From bfd6a79fe67f747f00bf81577ef261691fb36d41 Mon Sep 17 00:00:00 2001 From: sjplimp Date: Tue, 26 Oct 2010 16:14:31 +0000 Subject: [PATCH] git-svn-id: svn://svn.icms.temple.edu/lammps-ro/trunk@5143 f3b2605a-c512-4ea7-a41b-209d697bcdaa --- src/USER-REAXC/Install.sh | 115 ++ src/USER-REAXC/README | 61 + src/USER-REAXC/fix_qeq_reax.cpp | 851 +++++++++++ src/USER-REAXC/fix_qeq_reax.h | 134 ++ src/USER-REAXC/fix_reax_c.cpp | 156 +++ src/USER-REAXC/fix_reax_c.h | 53 + src/USER-REAXC/pair_reax_c.cpp | 664 +++++++++ src/USER-REAXC/pair_reax_c.h | 66 + src/USER-REAXC/reaxc_allocate.cpp | 1011 +++++++++++++ src/USER-REAXC/reaxc_allocate.h | 49 + src/USER-REAXC/reaxc_basic_comm.cpp | 312 +++++ src/USER-REAXC/reaxc_basic_comm.h | 47 + src/USER-REAXC/reaxc_bond_orders.cpp | 1219 ++++++++++++++++ src/USER-REAXC/reaxc_bond_orders.h | 58 + src/USER-REAXC/reaxc_bonds.cpp | 148 ++ src/USER-REAXC/reaxc_bonds.h | 29 + src/USER-REAXC/reaxc_control.cpp | 395 ++++++ src/USER-REAXC/reaxc_control.h | 29 + src/USER-REAXC/reaxc_defs.h | 141 ++ src/USER-REAXC/reaxc_ffield.cpp | 715 ++++++++++ src/USER-REAXC/reaxc_ffield.h | 29 + src/USER-REAXC/reaxc_forces.cpp | 929 ++++++++++++ src/USER-REAXC/reaxc_forces.h | 35 + src/USER-REAXC/reaxc_hydrogen_bonds.cpp | 220 +++ src/USER-REAXC/reaxc_hydrogen_bonds.h | 30 + src/USER-REAXC/reaxc_init_md.cpp | 916 ++++++++++++ src/USER-REAXC/reaxc_init_md.h | 35 + src/USER-REAXC/reaxc_io_tools.cpp | 1712 +++++++++++++++++++++++ src/USER-REAXC/reaxc_io_tools.h | 107 ++ src/USER-REAXC/reaxc_list.cpp | 157 +++ src/USER-REAXC/reaxc_list.h | 63 + src/USER-REAXC/reaxc_lookup.cpp | 339 +++++ src/USER-REAXC/reaxc_lookup.h | 32 + src/USER-REAXC/reaxc_multi_body.cpp | 311 ++++ src/USER-REAXC/reaxc_multi_body.h | 31 + src/USER-REAXC/reaxc_nonbonded.cpp | 424 ++++++ src/USER-REAXC/reaxc_nonbonded.h | 37 + src/USER-REAXC/reaxc_reset_tools.cpp | 254 ++++ src/USER-REAXC/reaxc_reset_tools.h | 40 + src/USER-REAXC/reaxc_system_props.cpp | 411 ++++++ src/USER-REAXC/reaxc_system_props.h | 41 + src/USER-REAXC/reaxc_tool_box.cpp | 467 +++++++ src/USER-REAXC/reaxc_tool_box.h | 69 + src/USER-REAXC/reaxc_torsion_angles.cpp | 590 ++++++++ src/USER-REAXC/reaxc_torsion_angles.h | 30 + src/USER-REAXC/reaxc_traj.cpp | 1072 ++++++++++++++ src/USER-REAXC/reaxc_traj.h | 77 + src/USER-REAXC/reaxc_types.h | 977 +++++++++++++ src/USER-REAXC/reaxc_valence_angles.cpp | 535 +++++++ src/USER-REAXC/reaxc_valence_angles.h | 34 + src/USER-REAXC/reaxc_vector.cpp | 518 +++++++ src/USER-REAXC/reaxc_vector.h | 89 ++ 52 files changed, 16864 insertions(+) create mode 100755 src/USER-REAXC/Install.sh create mode 100644 src/USER-REAXC/README create mode 100644 src/USER-REAXC/fix_qeq_reax.cpp create mode 100644 src/USER-REAXC/fix_qeq_reax.h create mode 100644 src/USER-REAXC/fix_reax_c.cpp create mode 100644 src/USER-REAXC/fix_reax_c.h create mode 100644 src/USER-REAXC/pair_reax_c.cpp create mode 100644 src/USER-REAXC/pair_reax_c.h create mode 100644 src/USER-REAXC/reaxc_allocate.cpp create mode 100644 src/USER-REAXC/reaxc_allocate.h create mode 100644 src/USER-REAXC/reaxc_basic_comm.cpp create mode 100644 src/USER-REAXC/reaxc_basic_comm.h create mode 100644 src/USER-REAXC/reaxc_bond_orders.cpp create mode 100644 src/USER-REAXC/reaxc_bond_orders.h create mode 100644 src/USER-REAXC/reaxc_bonds.cpp create mode 100644 src/USER-REAXC/reaxc_bonds.h create mode 100644 src/USER-REAXC/reaxc_control.cpp create mode 100644 src/USER-REAXC/reaxc_control.h create mode 100644 src/USER-REAXC/reaxc_defs.h create mode 100644 src/USER-REAXC/reaxc_ffield.cpp create mode 100644 src/USER-REAXC/reaxc_ffield.h create mode 100644 src/USER-REAXC/reaxc_forces.cpp create mode 100644 src/USER-REAXC/reaxc_forces.h create mode 100644 src/USER-REAXC/reaxc_hydrogen_bonds.cpp create mode 100644 src/USER-REAXC/reaxc_hydrogen_bonds.h create mode 100644 src/USER-REAXC/reaxc_init_md.cpp create mode 100644 src/USER-REAXC/reaxc_init_md.h create mode 100644 src/USER-REAXC/reaxc_io_tools.cpp create mode 100644 src/USER-REAXC/reaxc_io_tools.h create mode 100644 src/USER-REAXC/reaxc_list.cpp create mode 100644 src/USER-REAXC/reaxc_list.h create mode 100644 src/USER-REAXC/reaxc_lookup.cpp create mode 100644 src/USER-REAXC/reaxc_lookup.h create mode 100644 src/USER-REAXC/reaxc_multi_body.cpp create mode 100644 src/USER-REAXC/reaxc_multi_body.h create mode 100644 src/USER-REAXC/reaxc_nonbonded.cpp create mode 100644 src/USER-REAXC/reaxc_nonbonded.h create mode 100644 src/USER-REAXC/reaxc_reset_tools.cpp create mode 100644 src/USER-REAXC/reaxc_reset_tools.h create mode 100644 src/USER-REAXC/reaxc_system_props.cpp create mode 100644 src/USER-REAXC/reaxc_system_props.h create mode 100644 src/USER-REAXC/reaxc_tool_box.cpp create mode 100644 src/USER-REAXC/reaxc_tool_box.h create mode 100644 src/USER-REAXC/reaxc_torsion_angles.cpp create mode 100644 src/USER-REAXC/reaxc_torsion_angles.h create mode 100644 src/USER-REAXC/reaxc_traj.cpp create mode 100644 src/USER-REAXC/reaxc_traj.h create mode 100644 src/USER-REAXC/reaxc_types.h create mode 100644 src/USER-REAXC/reaxc_valence_angles.cpp create mode 100644 src/USER-REAXC/reaxc_valence_angles.h create mode 100644 src/USER-REAXC/reaxc_vector.cpp create mode 100644 src/USER-REAXC/reaxc_vector.h diff --git a/src/USER-REAXC/Install.sh b/src/USER-REAXC/Install.sh new file mode 100755 index 0000000000..a19874fb51 --- /dev/null +++ b/src/USER-REAXC/Install.sh @@ -0,0 +1,115 @@ +# Install/unInstall package classes in LAMMPS + +if (test $1 = 1) then + + cp -p pair_reax_c.cpp .. + cp -p fix_qeq_reax.cpp .. + cp -p fix_reax_c.cpp .. + + cp -p pair_reax_c.h .. + cp -p fix_qeq_reax.h .. + cp -p fix_reax_c.h .. + + cp -p reaxc_allocate.cpp .. + cp -p reaxc_basic_comm.cpp .. + cp -p reaxc_bond_orders.cpp .. + cp -p reaxc_bonds.cpp .. + cp -p reaxc_control.cpp .. + cp -p reaxc_ffield.cpp .. + cp -p reaxc_forces.cpp .. + cp -p reaxc_hydrogen_bonds.cpp .. + cp -p reaxc_init_md.cpp .. + cp -p reaxc_io_tools.cpp .. + cp -p reaxc_list.cpp .. + cp -p reaxc_lookup.cpp .. + cp -p reaxc_multi_body.cpp .. + cp -p reaxc_nonbonded.cpp .. + cp -p reaxc_reset_tools.cpp .. + cp -p reaxc_system_props.cpp .. + cp -p reaxc_tool_box.cpp .. + cp -p reaxc_torsion_angles.cpp .. + cp -p reaxc_traj.cpp .. + cp -p reaxc_valence_angles.cpp .. + cp -p reaxc_vector.cpp .. + + cp -p reaxc_allocate.h .. + cp -p reaxc_basic_comm.h .. + cp -p reaxc_bond_orders.h .. + cp -p reaxc_bonds.h .. + cp -p reaxc_control.h .. + cp -p reaxc_defs.h .. + cp -p reaxc_ffield.h .. + cp -p reaxc_forces.h .. + cp -p reaxc_hydrogen_bonds.h .. + cp -p reaxc_init_md.h .. + cp -p reaxc_io_tools.h .. + cp -p reaxc_list.h .. + cp -p reaxc_lookup.h .. + cp -p reaxc_multi_body.h .. + cp -p reaxc_nonbonded.h .. + cp -p reaxc_reset_tools.h .. + cp -p reaxc_system_props.h .. + cp -p reaxc_tool_box.h .. + cp -p reaxc_torsion_angles.h .. + cp -p reaxc_traj.h .. + cp -p reaxc_types.h .. + cp -p reaxc_valence_angles.h .. + cp -p reaxc_vector.h .. + +elif (test $1 = 0) then + + rm ../pair_reax_c.cpp + rm ../fix_qeq_reax.cpp + rm ../fix_reax_c.cpp + + rm ../pair_reax_c.h + rm ../fix_qeq_reax.h + rm ../fix_reax_c.h + + rm ../reaxc_allocate.cpp + rm ../reaxc_basic_comm.cpp + rm ../reaxc_bond_orders.cpp + rm ../reaxc_bonds.cpp + rm ../reaxc_control.cpp + rm ../reaxc_ffield.cpp + rm ../reaxc_forces.cpp + rm ../reaxc_hydrogen_bonds.cpp + rm ../reaxc_init_md.cpp + rm ../reaxc_io_tools.cpp + rm ../reaxc_list.cpp + rm ../reaxc_lookup.cpp + rm ../reaxc_multi_body.cpp + rm ../reaxc_nonbonded.cpp + rm ../reaxc_reset_tools.cpp + rm ../reaxc_system_props.cpp + rm ../reaxc_tool_box.cpp + rm ../reaxc_torsion_angles.cpp + rm ../reaxc_traj.cpp + rm ../reaxc_valence_angles.cpp + rm ../reaxc_vector.cpp + + rm ../reaxc_allocate.h + rm ../reaxc_basic_comm.h + rm ../reaxc_bond_orders.h + rm ../reaxc_bonds.h + rm ../reaxc_control.h + rm ../reaxc_defs.h + rm ../reaxc_ffield.h + rm ../reaxc_forces.h + rm ../reaxc_hydrogen_bonds.h + rm ../reaxc_init_md.h + rm ../reaxc_io_tools.h + rm ../reaxc_list.h + rm ../reaxc_lookup.h + rm ../reaxc_multi_body.h + rm ../reaxc_nonbonded.h + rm ../reaxc_reset_tools.h + rm ../reaxc_system_props.h + rm ../reaxc_tool_box.h + rm ../reaxc_torsion_angles.h + rm ../reaxc_traj.h + rm ../reaxc_types.h + rm ../reaxc_valence_angles.h + rm ../reaxc_vector.h + +fi diff --git a/src/USER-REAXC/README b/src/USER-REAXC/README new file mode 100644 index 0000000000..7830147200 --- /dev/null +++ b/src/USER-REAXC/README @@ -0,0 +1,61 @@ +The files in this directory are a user-contributed package for LAMMPS. + +The person who created this package is Hasan Metin Aktulga, haktulga +at cs.purdue.edu, while at Purdue University. Contact him directly, +or Aidan Thompson (Sandia) at athomps at sandia.gov, if you have +questions. + +-------------------------------------- + +Note that the files with names starting with "reaxc" in this package +are from PuReMD, the Purdue ReaxFF Molecular Dynamics Program. Its +copyright info and authorship info are listed below. + +PACKAGE DESCRIPTION: + +Contains a implementation for LAMMPS of the ReaxFF force field. +ReaxFF uses distance-dependent bond-order functions to represent the +contributions of chemical bonding to the potential energy. It was +originally developed by Adri van Duin and the Goddard group at +CalTech. + +The USER-REAXC version of ReaxFF (pair_style reax/c), implemented in +C++, should give identical or very similar results to pair_style reax, +which is a ReaxFF implementation on top of a Fortran library, a +version of which was originally authored by Adri van Duin. + +The reax/c version should be somewhat faster and more scalable, +particularly with respect to the charge equilibration calculation. It +should also be easier to build and use since there are no complicating +issues due to linking to a Fortran library. + +OTHERS FILES INCLUDED: + +User examples for pair_style reax/c are in examples/reax. + +Thanks to Steve Plimpton and Aidan Thompson for their input on the +LAMMPS architecture and for their help in understanding and +customizing some of the required LAMMPS interfaces. + +-------------------------------------- + +The reaxc files in this directory have the following header: + + 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: + . diff --git a/src/USER-REAXC/fix_qeq_reax.cpp b/src/USER-REAXC/fix_qeq_reax.cpp new file mode 100644 index 0000000000..640f102459 --- /dev/null +++ b/src/USER-REAXC/fix_qeq_reax.cpp @@ -0,0 +1,851 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Hasan Metin Aktulga, Purdue University +------------------------------------------------------------------------- */ + +#include "math.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "fix_qeq_reax.h" +#include "atom.h" +#include "comm.h" +#include "domain.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "update.h" +#include "force.h" +#include "pair.h" +#include "respa.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; + +#define EV_TO_KCAL_PER_MOL 14.4 +#define SAFE_ZONE 1.2 +#define DANGER_ZONE 0.95 +#define LOOSE_ZONE 0.7 +#define SQR(x) ((x)*(x)) +#define CUBE(x) ((x)*(x)*(x)) +#define MIN_CAP 50 +#define MIN_NBRS 100 + +#define MIN(A,B) ((A) < (B)) ? (A) : (B) +#define MAX(A,B) ((A) > (B)) ? (A) : (B) + +/* ---------------------------------------------------------------------- */ + +FixQEqReax::FixQEqReax(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg) +{ + if (narg != 8) error->all("Illegal fix qeq/reax command"); + + nevery = atoi(arg[3]); + swa = atof(arg[4]); + swb = atof(arg[5]); + tolerance = atof(arg[6]); + pertype_parameters(arg[7]); + + shld = NULL; + + n = n_cap = 0; + N = nmax = 0; + m_fill = m_cap = 0; + pack_flag = 0; + s = NULL; + t = NULL; + nprev = 5; + + Hdia_inv = NULL; + b_s = NULL; + b_t = NULL; + b_prc = NULL; + b_prm = NULL; + + // CG + p = NULL; + q = NULL; + r = NULL; + d = NULL; + + // GMRES + //g = NULL; + //y = NULL; + //hstr = NULL; + //v = NULL; + //h = NULL; + //hc = NULL; + //hs = NULL; + + // perform initial allocation of atom-based arrays + // register with Atom class + + s_hist = t_hist = NULL; + grow_arrays(atom->nmax); + atom->add_callback(0); + for( int i = 0; i < atom->nmax; i++ ) + for (int j = 0; j < nprev; ++j ) + s_hist[i][j] = t_hist[i][j] = 0; +} + +/* ---------------------------------------------------------------------- */ + +FixQEqReax::~FixQEqReax() +{ + // unregister callbacks to this fix from Atom class + + atom->delete_callback(id,0); + + memory->destroy_2d_double_array(s_hist); + memory->destroy_2d_double_array(t_hist); + + deallocate_storage(); + deallocate_matrix(); + + memory->destroy_2d_double_array(shld); + + if (!reaxflag) { + memory->sfree(chi); + memory->sfree(eta); + memory->sfree(gamma); + } +} + +/* ---------------------------------------------------------------------- */ + +int FixQEqReax::setmask() +{ + int mask = 0; + mask |= PRE_FORCE; + mask |= MIN_PRE_FORCE; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::pertype_parameters(char *arg) +{ + if (strcmp(arg,"reax/c") == 0) { + reaxflag = 1; + Pair *pair = force->pair_match("reax/c",1); + if (pair == NULL) error->all("No pair reax/c for fix qeq/reax"); + int tmp; + chi = (double *) pair->extract("chi",tmp); + eta = (double *) pair->extract("eta",tmp); + gamma = (double *) pair->extract("gamma",tmp); + if (chi == NULL || eta == NULL || gamma == NULL) + error->all("Fix qeq/reax could not extract params from pair reax/c"); + return; + } + + int i,itype,ntypes; + double v1,v2,v3; + FILE *pf; + + reaxflag = 0; + ntypes = atom->ntypes; + + chi = (double*) memory->smalloc(sizeof(double)*(ntypes+1),"qeq/reax:chi"); + eta = (double*) memory->smalloc(sizeof(double)*(ntypes+1),"qeq/reax:eta"); + gamma = (double*) memory->smalloc(sizeof(double)*(ntypes+1), + "qeq/reax:gamma"); + + if (comm->me == 0) { + if ((pf = fopen(arg,"r")) == NULL) + error->one("Fix qeq/reax parameter file could not be found"); + + for (i = 1; i <= ntypes && !feof(pf); i++) { + fscanf(pf,"%d %lg %lg %lg",&itype,&v1,&v2,&v3); + if (itype < 1 || itype > ntypes) + error->one("Fix qeq/reax invalid atom type in param file"); + chi[itype] = v1; + eta[itype] = v2; + gamma[itype] = v3; + } + if (i <= ntypes) error->one("Invalid param file for fix qeq/reax"); + fclose(pf); + } + + MPI_Bcast(&chi[1],ntypes,MPI_DOUBLE,0,world); + MPI_Bcast(&eta[1],ntypes,MPI_DOUBLE,0,world); + MPI_Bcast(&gamma[1],ntypes,MPI_DOUBLE,0,world); +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::allocate_storage() +{ + nmax = atom->nmax; + + s = (double*) memory->smalloc( nmax * sizeof(double), "qeq:s" ); + t = (double*) memory->smalloc( nmax * sizeof(double), "qeq:t" ); + + Hdia_inv = (double*) memory->smalloc(nmax * sizeof(double), "qeq:Hdia_inv"); + b_s = (double*) memory->smalloc( nmax * sizeof(double), "qeq:b_s" ); + b_t = (double*) memory->smalloc( nmax * sizeof(double), "qeq:b_t" ); + b_prc = (double*) memory->smalloc( nmax * sizeof(double), "qeq:b_prc" ); + b_prm = (double*) memory->smalloc( nmax * sizeof(double), "qeq:b_prm" ); + + // CG + p = (double*) memory->smalloc( nmax * sizeof(double), "qeq:p" ); + q = (double*) memory->smalloc( nmax * sizeof(double), "qeq:q" ); + r = (double*) memory->smalloc( nmax * sizeof(double), "qeq:r" ); + d = (double*) memory->smalloc( nmax * sizeof(double), "qeq:d" ); +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::deallocate_storage() +{ + memory->sfree(s); + memory->sfree(t); + + memory->sfree( Hdia_inv ); + memory->sfree( b_s ); + memory->sfree( b_t ); + memory->sfree( b_prc ); + memory->sfree( b_prm ); + + memory->sfree( p ); + memory->sfree( q ); + memory->sfree( r ); + memory->sfree( d ); +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::reallocate_storage() +{ + deallocate_storage(); + allocate_storage(); + init_storage(); +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::allocate_matrix() +{ + int i,ii; + + n = atom->nlocal; + n_cap = MAX( (int)(n * SAFE_ZONE), MIN_CAP ); + + // determine the total space for the H matrix + + int m = 0; + for( ii = 0; ii < list->inum; ii++ ) { + i = list->ilist[ii]; + m += list->numneigh[i]; + } + m_cap = MAX( (int)(m * SAFE_ZONE), MIN_CAP * MIN_NBRS ); + + H.n = n_cap; + H.m = m_cap; + H.firstnbr = (int*) memory->smalloc( n_cap * sizeof(int), "qeq:H.firstnbr" ); + H.numnbrs = (int*) memory->smalloc( n_cap * sizeof(int), "qeq:H.numnbrs" ); + H.jlist = (int*) memory->smalloc( m_cap * sizeof(int), "qeq:H.jlist" ); + H.val = (double*) memory->smalloc( m_cap * sizeof(double), "qeq:H.val" ); +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::deallocate_matrix() +{ + memory->sfree( H.firstnbr ); + memory->sfree( H.numnbrs ); + memory->sfree( H.jlist ); + memory->sfree( H.val ); +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::reallocate_matrix() +{ + deallocate_matrix(); + allocate_matrix(); +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::init() +{ + if (!atom->q_flag) error->all("Fix qeq/reax requires atom attribute q"); + + // need a half neighbor list w/ Newton off + // built whenever re-neighboring occurs + + int irequest = neighbor->request(this); + neighbor->requests[irequest]->pair = 0; + neighbor->requests[irequest]->fix = 1; + neighbor->requests[irequest]->newton = 2; + + init_shielding(); + init_taper(); + + if (strcmp(update->integrate_style,"respa") == 0) + nlevels_respa = ((Respa *) update->integrate)->nlevels; +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::init_list(int id, NeighList *ptr) +{ + list = ptr; +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::init_shielding() +{ + int i,j; + int ntypes; + + ntypes = atom->ntypes; + shld = memory->create_2d_double_array(ntypes+1, ntypes+1, "qeq:shileding"); + + for( i = 1; i <= ntypes; ++i ) + for( j = 1; j <= ntypes; ++j ) + shld[i][j] = pow( gamma[i] * gamma[j], -1.5 ); +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::init_taper() +{ + double d7, swa2, swa3, swb2, swb3; + + if (fabs(swa) > 0.01 && comm->me == 0) + error->warning("Fix qeq/reax has non-zero lower Taper radius cutoff"); + if (swb < 0) + error->all( "Fix qeq/reax has negative upper Taper radius cutoff"); + else if (swb < 5 && comm->me == 0) + error->warning("Fix qeq/reax has very low Taper radius cutoff"); + + d7 = pow( swb - swa, 7 ); + swa2 = SQR( swa ); + swa3 = CUBE( swa ); + swb2 = SQR( swb ); + swb3 = CUBE( swb ); + + Tap[7] = 20.0 / d7; + Tap[6] = -70.0 * (swa + swb) / d7; + Tap[5] = 84.0 * (swa2 + 3.0*swa*swb + swb2) / d7; + Tap[4] = -35.0 * (swa3 + 9.0*swa2*swb + 9.0*swa*swb2 + swb3 ) / d7; + Tap[3] = 140.0 * (swa3*swb + 3.0*swa2*swb2 + swa*swb3 ) / d7; + Tap[2] =-210.0 * (swa3*swb2 + swa2*swb3) / d7; + Tap[1] = 140.0 * swa3 * swb3 / d7; + Tap[0] = (-35.0*swa3*swb2*swb2 + 21.0*swa2*swb3*swb2 + + 7.0*swa*swb3*swb3 + swb3*swb3*swb ) / d7; +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::setup_pre_force(int vflag) +{ + neighbor->build_one(list->index); + allocate_storage(); + init_storage(); + allocate_matrix(); + + pre_force(vflag); +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::setup_pre_force_respa(int vflag, int ilevel) +{ + if (ilevel < nlevels_respa-1) return; + setup_pre_force(vflag); +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::min_setup_pre_force(int vflag) +{ + setup_pre_force(vflag); +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::init_storage() +{ + N = atom->nlocal + atom->nghost; + for( int i = 0; i < N; i++ ) { + Hdia_inv[i] = 1. / eta[atom->type[i]]; + b_s[i] = -chi[atom->type[i]]; + b_t[i] = -1.0; + b_prc[i] = 0; + b_prm[i] = 0; + s[i] = t[i] = 0; + } +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::pre_force(int vflag) +{ + double t_start, t_end; + + if (update->ntimestep % nevery) return; + if( comm->me == 0 ) t_start = MPI_Wtime(); + + n = atom->nlocal; + N = atom->nlocal + atom->nghost; + // grow arrays if necessary + // need to be atom->nmax in length + if( atom->nmax > nmax ) reallocate_storage(); + if( n > n_cap*DANGER_ZONE || m_fill > m_cap*DANGER_ZONE ) + reallocate_matrix(); + + init_matvec(); + matvecs = CG(b_s, s); // CG on s - parallel + matvecs += CG(b_t, t); // CG on t - parallel + calculate_Q(); + + if( comm->me == 0 ) { + t_end = MPI_Wtime(); + qeq_time = t_end - t_start; + } +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::pre_force_respa(int vflag, int ilevel, int iloop) +{ + if (ilevel == nlevels_respa-1) pre_force(vflag); +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::min_pre_force(int vflag) +{ + pre_force(vflag); +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::init_matvec() +{ + /* fill-in H matrix */ + compute_H(); + + for( int i = 0; i < n; ++i ) { + /* init pre-conditioner for H and init solution vectors */ + Hdia_inv[i] = 1. / eta[ atom->type[i] ]; + b_s[i] = -chi[ atom->type[i] ]; + b_t[i] = -1.0; + + /* linear extrapolation for s & t from previous solutions */ + //s[i] = 2 * s_hist[i][0] - s_hist[i][1]; + //t[i] = 2 * t_hist[i][0] - t_hist[i][1]; + + /* quadratic extrapolation for s & t from previous solutions */ + //s[i] = s_hist[i][2] + 3 * ( s_hist[i][0] - s_hist[i][1] ); + t[i] = t_hist[i][2] + 3 * ( t_hist[i][0] - t_hist[i][1] ); + + /* cubic extrapolation for s & t from previous solutions */ + s[i] = 4*(s_hist[i][0]+s_hist[i][2])-(6*s_hist[i][1]+s_hist[i][3]); + //t[i] = 4*(t_hist[i][0]+t_hist[i][2])-(6*t_hist[i][1]+t_hist[i][3]); + } + + pack_flag = 2; + comm->forward_comm_fix(this); //Dist_vector( s ); + pack_flag = 3; + comm->forward_comm_fix(this); //Dist_vector( t ); +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::compute_H() +{ + int inum, jnum, *ilist, *jlist, *numneigh, **firstneigh; + int i, j, ii, jj, temp, newnbr; + int *type; + double **x; + double dx, dy, dz, r_sqr; + + type = atom->type; + x = atom->x; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + // fill in the H matrix + m_fill = 0; + r_sqr = 0; + for( ii = 0; ii < inum; ii++ ) { + i = ilist[ii]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + H.firstnbr[i] = m_fill; + + for( jj = 0; jj < jnum; jj++ ) { + j = jlist[jj]; + + dx = x[i][0] - x[j][0]; + dy = x[i][1] - x[j][1]; + dz = x[i][2] - x[j][2]; + r_sqr = SQR(dx) + SQR(dy) + SQR(dz); + + if( r_sqr <= SQR(swb) && (j < n || atom->tag[i] <= atom->tag[j]) ) { + H.jlist[m_fill] = j; + H.val[m_fill] = calculate_H( sqrt(r_sqr), shld[type[i]][type[j]] ); + m_fill++; + } + } + + H.numnbrs[i] = m_fill - H.firstnbr[i]; + } + + if (m_fill >= H.m) { + char str[128]; + sprintf(str,"H matrix size has been exceeded: m_fill=%d H.m=%d\n", + m_fill, H.m ); + error->warning(str); + error->all("Fix qeq/reax has insufficient QEq matrix size"); + } +} + +/* ---------------------------------------------------------------------- */ + +double FixQEqReax::calculate_H( double r, double gamma ) +{ + double Taper, denom; + + Taper = Tap[7] * r + Tap[6]; + Taper = Taper * r + Tap[5]; + Taper = Taper * r + Tap[4]; + Taper = Taper * r + Tap[3]; + Taper = Taper * r + Tap[2]; + Taper = Taper * r + Tap[1]; + Taper = Taper * r + Tap[0]; + + denom = r * r * r + gamma; + denom = pow(denom,0.3333333333333); + + return Taper * EV_TO_KCAL_PER_MOL / denom; +} + +/* ---------------------------------------------------------------------- */ + +int FixQEqReax::CG( double *b, double *x ) +{ + int i, j; + double tmp, alpha, beta, b_norm; + double sig_old, sig_new, sig0; + + pack_flag = 1; + sparse_matvec( &H, x, q ); + comm->reverse_comm_fix( this ); //Coll_Vector( q ); + + vector_sum( r , 1., b, -1., q, n ); + for( j = 0; j < n; ++j ) + d[j] = r[j] * Hdia_inv[j]; //pre-condition + + b_norm = parallel_norm( b, n ); + sig_new = parallel_dot( r, d, n ); + sig0 = sig_new; + + for( i = 1; i < 100 && sqrt(sig_new) / b_norm > tolerance; ++i ) { + comm->forward_comm_fix(this); //Dist_vector( d ); + sparse_matvec( &H, d, q ); + comm->reverse_comm_fix(this); //Coll_vector( q ); + + tmp = parallel_dot( d, q, n ); + alpha = sig_new / tmp; + // comm->me, i, parallel_norm( d, n ), parallel_norm( q, n ), tmp ); + + vector_add( x, alpha, d, n ); + vector_add( r, -alpha, q, n ); + + // pre-conditioning + for( j = 0; j < n; ++j ) + p[j] = r[j] * Hdia_inv[j]; + + sig_old = sig_new; + sig_new = parallel_dot( r, p, n ); + + + beta = sig_new / sig_old; + vector_sum( d, 1., p, beta, d, n ); + } + + if (i >= 100 && comm->me == 0) + error->warning("Fix qeq/reax CG convergence failed"); + + return i; +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::sparse_matvec( sparse_matrix *A, double *x, double *b ) +{ + int i, j, itr_j; + + for( i = 0; i < n; ++i ) + b[i] = eta[ atom->type[i] ] * x[i]; + for( i = n; i < N; ++i ) + b[i] = 0; + + for( i = 0; i < n; ++i ) { + for( itr_j=A->firstnbr[i]; itr_jfirstnbr[i]+A->numnbrs[i]; itr_j++) { + j = A->jlist[itr_j]; + b[i] += A->val[itr_j] * x[j]; + b[j] += A->val[itr_j] * x[i]; + } + } +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::calculate_Q() +{ + int i, k; + double u, s_sum, t_sum; + double *q = atom->q; + + s_sum = parallel_vector_acc( s, n ); + t_sum = parallel_vector_acc( t, n); + u = s_sum / t_sum; + + for( i = 0; i < n; ++i ) { + q[i] = s[i] - u * t[i]; + + /* backup s & t */ + for( k = 4; k > 0; --k ) { + s_hist[i][k] = s_hist[i][k-1]; + t_hist[i][k] = t_hist[i][k-1]; + } + s_hist[i][0] = s[i]; + t_hist[i][0] = t[i]; + } + + pack_flag = 4; + comm->forward_comm_fix( this ); //Dist_vector( atom->q ); +} + +/* ---------------------------------------------------------------------- */ + +int FixQEqReax::pack_comm(int n, int *list, double *buf, + int pbc_flag, int *pbc) +{ + int m; + + if( pack_flag == 1) + for(m = 0; m < n; m++) buf[m] = d[list[m]]; + else if( pack_flag == 2 ) + for(m = 0; m < n; m++) buf[m] = s[list[m]]; + else if( pack_flag == 3 ) + for(m = 0; m < n; m++) buf[m] = t[list[m]]; + else if( pack_flag == 4 ) + for(m = 0; m < n; m++) buf[m] = atom->q[list[m]]; + + return 1; +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::unpack_comm(int n, int first, double *buf) +{ + int i, m; + + if( pack_flag == 1) + for(m = 0, i = first; m < n; m++, i++) d[i] = buf[m]; + else if( pack_flag == 2) + for(m = 0, i = first; m < n; m++, i++) s[i] = buf[m]; + else if( pack_flag == 3) + for(m = 0, i = first; m < n; m++, i++) t[i] = buf[m]; + else if( pack_flag == 4) + for(m = 0, i = first; m < n; m++, i++) atom->q[i] = buf[m]; +} + +/* ---------------------------------------------------------------------- */ + +int FixQEqReax::pack_reverse_comm(int n, int first, double *buf) +{ + int i, m; + for(m = 0, i = first; m < n; m++, i++) buf[m] = q[i]; + return 1; +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::unpack_reverse_comm(int n, int *list, double *buf) +{ + for(int m = 0; m < n; m++) q[list[m]] += buf[m]; +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based arrays +------------------------------------------------------------------------- */ + +double FixQEqReax::memory_usage() +{ + double bytes; + + bytes = atom->nmax*nprev*2 * sizeof(double); // s_hist & t_hist + bytes += atom->nmax*11 * sizeof(double); // storage + bytes += n_cap*2 * sizeof(int); // matrix... + bytes += m_cap * sizeof(int); + bytes += m_cap * sizeof(double); + + return bytes; +} + +/* ---------------------------------------------------------------------- + allocate fictitious charge arrays +------------------------------------------------------------------------- */ + +void FixQEqReax::grow_arrays(int nmax) +{ + s_hist = memory->grow_2d_double_array(s_hist,nmax,nprev,"qeq:s_hist"); + t_hist = memory->grow_2d_double_array(t_hist,nmax,nprev,"qeq:t_hist"); +} + +/* ---------------------------------------------------------------------- + copy values within fictitious charge arrays +------------------------------------------------------------------------- */ + +void FixQEqReax::copy_arrays(int i, int j) +{ + for (int m = 0; m < nprev; m++) { + s_hist[j][m] = s_hist[i][m]; + t_hist[j][m] = t_hist[i][m]; + } +} + +/* ---------------------------------------------------------------------- + pack values in local atom-based array for exchange with another proc +------------------------------------------------------------------------- */ + +int FixQEqReax::pack_exchange(int i, double *buf) +{ + for (int m = 0; m < nprev; m++) buf[m] = s_hist[i][m]; + for (int m = 0; m < nprev; m++) buf[nprev+m] = t_hist[i][m]; + return nprev*2; +} + +/* ---------------------------------------------------------------------- + unpack values in local atom-based array from exchange with another proc +------------------------------------------------------------------------- */ + +int FixQEqReax::unpack_exchange(int nlocal, double *buf) +{ + for (int m = 0; m < nprev; m++) s_hist[nlocal][m] = buf[m]; + for (int m = 0; m < nprev; m++) t_hist[nlocal][m] = buf[nprev+m]; + return nprev*2; +} + +/* ---------------------------------------------------------------------- */ + +double FixQEqReax::parallel_norm( double *v, int n ) +{ + int i; + double my_sum, norm_sqr; + + my_sum = 0; + for( i = 0; i < n; ++i ) + my_sum += SQR( v[i] ); + + MPI_Allreduce( &my_sum, &norm_sqr, 1, MPI_DOUBLE, MPI_SUM, world ); + + return sqrt( norm_sqr ); +} + +/* ---------------------------------------------------------------------- */ + +double FixQEqReax::parallel_dot( double *v1, double *v2, int n ) +{ + int i; + double my_dot, res; + + my_dot = 0; + res = 0; + for( i = 0; i < n; ++i ) + my_dot += v1[i] * v2[i]; + + MPI_Allreduce( &my_dot, &res, 1, MPI_DOUBLE, MPI_SUM, world ); + + return res; +} + +/* ---------------------------------------------------------------------- */ + +double FixQEqReax::parallel_vector_acc( double *v, int n ) +{ + int i; + double my_acc, res; + + my_acc = 0; + for( i = 0; i < n; ++i ) + my_acc += v[i]; + + MPI_Allreduce( &my_acc, &res, 1, MPI_DOUBLE, MPI_SUM, world ); + + return res; +} + +/* ---------------------------------------------------------------------- */ + +double FixQEqReax::norm( double* v1, int k ) +{ + double ret = 0; + + for( --k; k>=0; --k ) + ret += ( v1[k] * v1[k] ); + + return sqrt( ret ); +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::vector_sum( double* dest, double c, double* v, + double d, double* y, int k ) +{ + for( --k; k>=0; --k ) + dest[k] = c * v[k] + d * y[k]; +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::vector_scale( double* dest, double c, double* v, int k ) +{ + for( --k; k>=0; --k ) + dest[k] = c * v[k]; +} + +/* ---------------------------------------------------------------------- */ + +double FixQEqReax::dot( double* v1, double* v2, int k ) +{ + double ret = 0; + + for( --k; k>=0; --k ) + ret += v1[k] * v2[k]; + + return ret; +} + +/* ---------------------------------------------------------------------- */ + +void FixQEqReax::vector_add( double* dest, double c, double* v, int k ) +{ + for( --k; k>=0; --k ) + dest[k] += c * v[k]; +} diff --git a/src/USER-REAXC/fix_qeq_reax.h b/src/USER-REAXC/fix_qeq_reax.h new file mode 100644 index 0000000000..ceb3814304 --- /dev/null +++ b/src/USER-REAXC/fix_qeq_reax.h @@ -0,0 +1,134 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS + +FixStyle(qeq/reax,FixQEqReax) + +#else + +#ifndef LMP_FIX_QEQ_REAX_H +#define LMP_FIX_QEQ_REAX_H + +#include "fix.h" + +namespace LAMMPS_NS { + +class FixQEqReax : public Fix { + public: + FixQEqReax(class LAMMPS *, int, char **); + ~FixQEqReax(); + int setmask(); + void init(); + void init_list(int,class NeighList *); + void init_storage(); + void setup_pre_force(int); + void pre_force(int); + + void setup_pre_force_respa(int, int); + void pre_force_respa(int, int, int); + + void min_setup_pre_force(int); + void min_pre_force(int); + + int matvecs; + double qeq_time; + + private: + int nevery,reaxflag; + int n, N, m_fill; + int n_cap, nmax, m_cap; + int pack_flag; + int nlevels_respa; + class NeighList *list; + + double swa, swb; // lower/upper Taper cutoff radius + double Tap[8]; // Taper function + double tolerance; // tolerance for the norm of the rel residual in CG + + double *chi,*eta,*gamma; // qeq parameters + double **shld; + + // fictitious charges + + double *s, *t; + double **s_hist, **t_hist; + int nprev; + + typedef struct{ + int n, m; + int *firstnbr; + int *numnbrs; + int *jlist; + double *val; + } sparse_matrix; + + sparse_matrix H; + double *Hdia_inv; + double *b_s, *b_t; + double *b_prc, *b_prm; + + //CG storage + double *p, *q, *r, *d; + + //GMRES storage + //double *g,*y; + //double **v; + //double **h; + //double *hc, *hs; + + void pertype_parameters(char*); + void init_shielding(); + void init_taper(); + void allocate_storage(); + void deallocate_storage(); + void reallocate_storage(); + void allocate_matrix(); + void deallocate_matrix(); + void reallocate_matrix(); + + void init_matvec(); + void init_H(); + void compute_H(); + double calculate_H(double,double); + void calculate_Q(); + + int CG(double*,double*); + //int GMRES(double*,double*); + void sparse_matvec(sparse_matrix*,double*,double*); + + int pack_comm(int, int *, double *, int, int *); + void unpack_comm(int, int, double *); + int pack_reverse_comm(int, int, double *); + void unpack_reverse_comm(int, int *, double *); + double memory_usage(); + void grow_arrays(int); + void copy_arrays(int, int); + int pack_exchange(int, double *); + int unpack_exchange(int, double *); + + double parallel_norm( double*, int ); + double parallel_dot( double*, double*, int ); + double parallel_vector_acc( double*, int ); + + double norm(double*,int); + void vector_sum(double*,double,double*,double,double*,int); + void vector_scale(double*,double,double*,int); + double dot(double*,double*,int); + void vector_add(double*, double, double*,int); +}; + +} + +#endif +#endif diff --git a/src/USER-REAXC/fix_reax_c.cpp b/src/USER-REAXC/fix_reax_c.cpp new file mode 100644 index 0000000000..1e440dd765 --- /dev/null +++ b/src/USER-REAXC/fix_reax_c.cpp @@ -0,0 +1,156 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Hasan Metin Aktulga, Purdue University +------------------------------------------------------------------------- */ + +#include "fix_reax_c.h" +#include "atom.h" +#include "pair.h" +#include "comm.h" +#include "memory.h" + +using namespace LAMMPS_NS; + +#define MAX_REAX_BONDS 30 +#define MIN_REAX_BONDS 15 +#define MIN_REAX_HBONDS 25 + +/* ---------------------------------------------------------------------- */ + +FixReaxC::FixReaxC(LAMMPS *lmp,int narg, char **arg) : + Fix(lmp, narg, arg) +{ + // perform initial allocation of atom-based arrays + // register with atom class + + num_bonds = NULL; + num_hbonds = NULL; + grow_arrays(atom->nmax); + atom->add_callback(0); + + // initialize arrays to MIN so atom migration is OK the 1st time + + int nlocal = atom->nlocal; + for (int i = 0; i < nlocal; i++) + num_bonds[i] = num_hbonds[i] = MIN_REAX_BONDS; + + // set comm sizes needed by this fix + + comm_forward = 1; +} + +/* ---------------------------------------------------------------------- */ + +FixReaxC::~FixReaxC() +{ + // unregister this fix so atom class doesn't invoke it any more + + atom->delete_callback(id,0); + + // delete locally stored arrays + + memory->sfree(num_bonds); + memory->sfree(num_hbonds); +} + +/* ---------------------------------------------------------------------- */ + +int FixReaxC::setmask() +{ + int mask = 0; + return mask; +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based arrays +------------------------------------------------------------------------- */ + +double FixReaxC::memory_usage() +{ + int nmax = atom->nmax; + double bytes = nmax * 2 * sizeof(int); + return bytes; +} + +/* ---------------------------------------------------------------------- + allocate local atom-based arrays +------------------------------------------------------------------------- */ + +void FixReaxC::grow_arrays(int nmax) +{ + num_bonds = (int *) memory->srealloc(num_bonds,nmax*sizeof(int), + "reaxc:num_bonds"); + num_hbonds = (int *) memory->srealloc(num_hbonds,nmax*sizeof(int), + "reaxc:num_hbonds"); +} + +/* ---------------------------------------------------------------------- + copy values within local atom-based arrays +------------------------------------------------------------------------- */ + +void FixReaxC::copy_arrays(int i, int j) +{ + num_bonds[j] = num_bonds[i]; + num_hbonds[j] = num_hbonds[i]; +} + +/* ---------------------------------------------------------------------- + pack values in local atom-based arrays for exchange with another proc +------------------------------------------------------------------------- */ + +int FixReaxC::pack_exchange(int i, double *buf) +{ + buf[0] = num_bonds[i]; + buf[1] = num_hbonds[i]; + return 2; +} + +/* ---------------------------------------------------------------------- + unpack values in local atom-based arrays from exchange with another proc +------------------------------------------------------------------------- */ + +int FixReaxC::unpack_exchange(int nlocal, double *buf) +{ + num_bonds[nlocal] = static_cast (buf[0]); + num_hbonds[nlocal] = static_cast (buf[1]); + return 2; +} + +/* ---------------------------------------------------------------------- */ + +int FixReaxC::pack_comm(int n, int *list, double *buf, + int pbc_flag, int *pbc) +{ + int i,j,m; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = num_bonds[j]; + } + return 1; +} + +/* ---------------------------------------------------------------------- */ + +void FixReaxC::unpack_comm(int n, int first, double *buf) +{ + int i,m,last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) + num_bonds[i] = buf[m++]; +} diff --git a/src/USER-REAXC/fix_reax_c.h b/src/USER-REAXC/fix_reax_c.h new file mode 100644 index 0000000000..8f663f7327 --- /dev/null +++ b/src/USER-REAXC/fix_reax_c.h @@ -0,0 +1,53 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS + +FixStyle(REAXC,FixReaxC) + +#else + +#ifndef LMP_FIX_REAXC_H +#define LMP_FIX_REAXC_H + +#include "fix.h" + +namespace LAMMPS_NS { + +class FixReaxC : public Fix { + friend class PairReaxC; + + public: + FixReaxC(class LAMMPS *,int, char **); + ~FixReaxC(); + int setmask(); + + double memory_usage(); + void grow_arrays(int); + void copy_arrays(int, int); + int pack_exchange(int, double *); + int unpack_exchange(int, double *); + int pack_comm(int, int *, double *, int, int *); + void unpack_comm(int, int, double *); + + private: + int maxbonds; // max # of bonds for any atom + int maxhbonds; // max # of Hbonds for any atom + int *num_bonds; // # of bonds for each atom + int *num_hbonds; // # of Hbonds for each atom +}; + +} + +#endif +#endif diff --git a/src/USER-REAXC/pair_reax_c.cpp b/src/USER-REAXC/pair_reax_c.cpp new file mode 100644 index 0000000000..2f7b393a65 --- /dev/null +++ b/src/USER-REAXC/pair_reax_c.cpp @@ -0,0 +1,664 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Hasan Metin Aktulga, Purdue University +------------------------------------------------------------------------- */ + +#include "pair_reax_c.h" +#include "atom.h" +#include "update.h" +#include "force.h" +#include "comm.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "modify.h" +#include "fix.h" +#include "fix_reax_c.h" +#include "memory.h" +#include "error.h" + +#include "reaxc_types.h" +#include "reaxc_allocate.h" +#include "reaxc_control.h" +#include "reaxc_ffield.h" +#include "reaxc_forces.h" +#include "reaxc_init_md.h" +#include "reaxc_io_tools.h" +#include "reaxc_list.h" +#include "reaxc_lookup.h" +#include "reaxc_reset_tools.h" +#include "reaxc_traj.h" +#include "reaxc_vector.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +PairReaxC::PairReaxC(LAMMPS *lmp) : Pair(lmp) +{ + system = (reax_system *) + memory->smalloc( sizeof(reax_system), "reax:system" ); + control = (control_params *) + memory->smalloc( sizeof(control_params), "reax:control" ); + data = (simulation_data *) + memory->smalloc( sizeof(simulation_data), "reax:data" ); + workspace = (storage *) + memory->smalloc( sizeof(storage), "reax:storage" ); + lists = (reax_list *) + memory->smalloc( LIST_N * sizeof(reax_list), "reax:lists" ); + out_control = (output_controls *) + memory->smalloc( sizeof(output_controls), "reax:out_control" ); + mpi_data = (mpi_datatypes *) + memory->smalloc( sizeof(mpi_datatypes), "reax:mpi"); + + MPI_Comm_rank(world, &system->my_rank); + + system->my_coords[0] = 0; + system->my_coords[1] = 0; + system->my_coords[2] = 0; + system->num_nbrs = 0; + system->n = 0; // my atoms + system->N = 0; // mine + ghosts + system->bigN = 0; // all atoms in the system + system->local_cap = 0; + system->total_cap = 0; + system->gcell_cap = 0; + system->bndry_cuts.ghost_nonb = 0; + system->bndry_cuts.ghost_hbond = 0; + system->bndry_cuts.ghost_bond = 0; + system->bndry_cuts.ghost_cutoff = 0; + system->my_atoms = NULL; + + fix_reax = NULL; +} + +/* ---------------------------------------------------------------------- */ + +PairReaxC::~PairReaxC() +{ + if (fix_reax) modify->delete_fix("REAXC"); + + Close_Output_Files( system, control, out_control, mpi_data ); + + // deallocate reax data-structures + + if( control->tabulate ) Deallocate_Lookup_Tables( system ); + + if( control->hbond_cut > 0 ) Delete_List( lists+HBONDS, world ); + Delete_List( lists+BONDS, world ); + Delete_List( lists+THREE_BODIES, world ); + Delete_List( lists+FAR_NBRS, world ); + // fprintf( stderr, "3\n" ); + + DeAllocate_Workspace( control, workspace ); + DeAllocate_System( system ); + //fprintf( stderr, "4\n" ); + + memory->sfree( system ); + memory->sfree( control ); + memory->sfree( data ); + memory->sfree( workspace ); + memory->sfree( lists ); + memory->sfree( out_control ); + memory->sfree( mpi_data ); + //fprintf( stderr, "5\n" ); + + // deallocate interface storage + if( allocated ) { + memory->destroy_2d_int_array(setflag); + memory->destroy_2d_double_array(cutsq); + delete [] map; + + delete [] chi; + delete [] eta; + delete [] gamma; + } + //fprintf( stderr, "6\n" ); +} + +/* ---------------------------------------------------------------------- */ + +void PairReaxC::allocate( ) +{ + allocated = 1; + int n = atom->ntypes; + + setflag = memory->create_2d_int_array(n+1,n+1,"pair:setflag"); + cutsq = memory->create_2d_double_array(n+1,n+1,"pair:cutsq"); + map = new int[n+1]; + + chi = new double[n+1]; + eta = new double[n+1]; + gamma = new double[n+1]; +} + +/* ---------------------------------------------------------------------- */ + +void PairReaxC::settings(int narg, char **arg) +{ + if (narg != 1) error->all("Illegal pair_style command"); + + if (strcmp(arg[0],"NULL") == 0) { + strcpy( control->sim_name, "simulate" ); + control->ensemble = 0; + out_control->energy_update_freq = 0; + control->tabulate = 0; + + control->reneighbor = 1; + control->vlist_cut = control->nonb_cut; + control->bond_cut = 5.; + control->hbond_cut = 7.50; + control->thb_cut = 0.001; + + out_control->write_steps = 0; + out_control->traj_method = 0; + strcpy( out_control->traj_title, "default_title" ); + out_control->atom_info = 0; + out_control->bond_info = 0; + out_control->angle_info = 0; + } else Read_Control_File(arg[0], control, out_control); + + // LAMMPS is responsible for generating nbrs + + control->reneighbor = 1; +} + +/* ---------------------------------------------------------------------- */ + +void PairReaxC::coeff( int nargs, char **args ) +{ + if (!allocated) allocate(); + + if (nargs != 3 + atom->ntypes) + error->all("Incorrect args for pair coefficients"); + + // insure I,J args are * * + + if (strcmp(args[0],"*") != 0 || strcmp(args[1],"*") != 0) + error->all("Incorrect args for pair coefficients"); + + // read ffield file + + Read_Force_Field(args[2], &(system->reax_param), control); + + // read args that map atom types to elements in potential file + // map[i] = which element the Ith atom type is, -1 if NULL + + for (int i = 3; i < nargs; i++) { + if (strcmp(args[i],"NULL") == 0) { + map[i-2] = -1; + continue; + } + map[i-2] = atoi(args[i]) - 1; + } + + int n = atom->ntypes; + + int count = 0; + for (int i = 1; i <= n; i++) + for (int j = i; j <= n; j++) { + setflag[i][j] = 1; + count++; + } + + if (count == 0) error->all("Incorrect args for pair coefficients"); +} + +/* ---------------------------------------------------------------------- */ + +void PairReaxC::init_style( ) +{ + if (!atom->q_flag) error->all("Pair reax/c requires atom attribute q"); + + system->n = atom->nlocal; + system->N = atom->nlocal + atom->nghost; + system->bigN = static_cast (atom->natoms); + system->wsize = comm->nprocs; + + system->big_box.V = 0; + system->big_box.box_norms[0] = 0; + system->big_box.box_norms[1] = 0; + system->big_box.box_norms[2] = 0; + + if (atom->tag_enable == 0) + error->all("Pair style reax/c requires atom IDs"); + if (force->newton_pair == 0) + error->all("Pair style reax/c requires newton pair on"); + + // need a half neighbor list w/ Newton off + // built whenever re-neighboring occurs + + int irequest = neighbor->request(this); + neighbor->requests[irequest]->newton = 2; + + cutmax = MAX3(control->nonb_cut, control->hbond_cut, 2*control->bond_cut); + + for( int i = 0; i < LIST_N; ++i ) + lists[i].allocated = 0; + + if (fix_reax == NULL) { + char **fixarg = new char*[3]; + fixarg[0] = (char *) "REAXC"; + fixarg[1] = (char *) "all"; + fixarg[2] = (char *) "REAXC"; + modify->add_fix(3,fixarg); + delete [] fixarg; + fix_reax = (FixReaxC *) modify->fix[modify->nfix-1]; + } +} + +/* ---------------------------------------------------------------------- */ + +double PairReaxC::init_one(int i, int j) +{ + return cutmax; +} + +/* ---------------------------------------------------------------------- */ + +void PairReaxC::compute(int eflag, int vflag) +{ + int k, oldN; + double evdwl,ecoul; + double t_start, t_end; + + // communicate num_bonds once every reneighboring + // 2 num arrays stored by fix, grab ptr to them + + if (neighbor->ago == 0) comm->forward_comm_fix(fix_reax); + int *num_bonds = fix_reax->num_bonds; + int *num_hbonds = fix_reax->num_hbonds; + + evdwl = ecoul = 0.0; + if (eflag || vflag) ev_setup(eflag,vflag); + else evflag = vflag_fdotr = eflag_global = vflag_global = 0; + + if (vflag_global) control->virial = 1; + else control->virial = 0; + + system->n = atom->nlocal; // my atoms + oldN = system->N; + system->N = atom->nlocal + atom->nghost; // mine + ghosts + system->bigN = static_cast (atom->natoms); // all atoms in the system + + system->big_box.V = 0; + system->big_box.box_norms[0] = 0; + system->big_box.box_norms[1] = 0; + system->big_box.box_norms[2] = 0; + if( comm->me == 0 ) t_start = MPI_Wtime(); + + if( update->ntimestep == 0 ) { + control->vlist_cut = neighbor->cutneighmax; + + // determine the local and total capacity + + system->local_cap = MAX( (int)(system->n * SAFE_ZONE), MIN_CAP ); + system->total_cap = MAX( (int)(system->N * SAFE_ZONE), MIN_CAP ); + + // initialize my data structures + + PreAllocate_Space( system, control, workspace, world ); + write_reax_atoms(); + + int num_nbrs = estimate_reax_lists(); + if(!Make_List(system->total_cap, num_nbrs, TYP_FAR_NEIGHBOR, + lists+FAR_NBRS, world)) + error->all("Pair reax/c problem in far neighbor list"); + + write_reax_lists(); + Initialize( system, control, data, workspace, &lists, out_control, + mpi_data, world ); + for( k = 0; k < system->N; ++k ) { + num_bonds[k] = system->my_atoms[k].num_bonds; + num_hbonds[k] = system->my_atoms[k].num_hbonds; + } + + // locate the qeq/reax fix - for outputting log info + // if( comm->me == 0 ) { + // int qeq_id = modify->find_fix( "qeq/reax" ); + // if (qeq_id < 0) fprintf(stderr, "WARNING: no qeq/reax fix applied\n"); + // else fix_qeq = (FixQEqReax *) modify->fix[qeq_id]; + // } + } else { + // fill in reax datastructures + write_reax_atoms(); + + // reset the bond list info for new atoms + for( k = oldN; k < system->N; ++k ) + Set_End_Index( k, Start_Index( k, lists+BONDS ), lists+BONDS ); + + // check if I need to shrink/extend my data-structs + ReAllocate( system, control, data, workspace, &lists, mpi_data ); + } + + Reset( system, control, data, workspace, &lists, world ); + workspace->realloc.num_far = write_reax_lists(); + // timing for filling in the reax lists + if( comm->me == 0 ) { + t_end = MPI_Wtime(); + data->timing.nbrs = t_end - t_start; + } + + // forces + + Compute_Forces(system,control,data,workspace,&lists,out_control,mpi_data); + read_reax_forces(); + + for( k = 0; k < system->N; ++k ) { + num_bonds[k] = system->my_atoms[k].num_bonds; + num_hbonds[k] = system->my_atoms[k].num_hbonds; + } + + // energies and pressure + + if (eflag_global) { + evdwl += data->my_en.e_bond; + evdwl += data->my_en.e_ov; + evdwl += data->my_en.e_un; + evdwl += data->my_en.e_lp; + evdwl += data->my_en.e_ang; + evdwl += data->my_en.e_pen; + evdwl += data->my_en.e_coa; + evdwl += data->my_en.e_hb; + evdwl += data->my_en.e_tor; + evdwl += data->my_en.e_con; + evdwl += data->my_en.e_vdW; + + ecoul += data->my_en.e_ele; + ecoul += data->my_en.e_pol; + + eng_vdwl += evdwl; + eng_coul += ecoul; + } + + if (vflag_fdotr) virial_compute(); + +// #if defined(LOG_PERFORMANCE) +// if( comm->me == 0 && fix_qeq != NULL ) { +// data->timing.s_matvecs += fix_qeq->matvecs; +// data->timing.qEq += fix_qeq->qeq_time; +// } +// #endif + + Output_Results( system, control, data, &lists, out_control, mpi_data ); + + ++data->step; +} + +/* ---------------------------------------------------------------------- */ + +void PairReaxC::write_reax_atoms() +{ + int *num_bonds = fix_reax->num_bonds; + int *num_hbonds = fix_reax->num_hbonds; + + for( int i = 0; i < system->N; ++i ){ + system->my_atoms[i].orig_id = atom->tag[i]; + system->my_atoms[i].type = map[atom->type[i]]; + system->my_atoms[i].x[0] = atom->x[i][0]; + system->my_atoms[i].x[1] = atom->x[i][1]; + system->my_atoms[i].x[2] = atom->x[i][2]; + system->my_atoms[i].q = atom->q[i]; + system->my_atoms[i].num_bonds = num_bonds[i]; + system->my_atoms[i].num_hbonds = num_hbonds[i]; + } +} + +/* ---------------------------------------------------------------------- */ + +void PairReaxC::get_distance( rvec xj, rvec xi, double *d_sqr, rvec *dvec ) +{ + (*dvec)[0] = xj[0] - xi[0]; + (*dvec)[1] = xj[1] - xi[1]; + (*dvec)[2] = xj[2] - xi[2]; + *d_sqr = SQR((*dvec)[0]) + SQR((*dvec)[1]) + SQR((*dvec)[2]); +} + +/* ---------------------------------------------------------------------- */ + +void PairReaxC::set_far_nbr( far_neighbor_data *fdest, + int j, double d, rvec dvec ) +{ + fdest->nbr = j; + fdest->d = d; + rvec_Copy( fdest->dvec, dvec ); + ivec_MakeZero( fdest->rel_box ); +} + +/* ---------------------------------------------------------------------- */ + +int PairReaxC::estimate_reax_lists() +{ + int itr_i, itr_j, itr_g, i, j, g; + int nlocal, nghost, num_nbrs, num_marked; + int *ilist, *jlist, *numneigh, **firstneigh, *marked; + double d_sqr, g_d_sqr; + rvec dvec, g_dvec; + double *dist, **x; + reax_list *far_nbrs; + far_neighbor_data *far_list; + + x = atom->x; + nlocal = atom->nlocal; + nghost = atom->nghost; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + far_nbrs = lists + FAR_NBRS; + far_list = far_nbrs->select.far_nbr_list; + + num_nbrs = 0; + num_marked = 0; + marked = (int*) calloc( system->N, sizeof(int) ); + dist = (double*) calloc( system->N, sizeof(double) ); + + for( itr_i = 0; itr_i < list->inum; ++itr_i ){ + i = ilist[itr_i]; + marked[i] = 1; + ++num_marked; + jlist = firstneigh[i]; + + for( itr_j = 0; itr_j < numneigh[i]; ++itr_j ){ + j = jlist[itr_j]; + get_distance( x[j], x[i], &d_sqr, &dvec ); + dist[j] = sqrt(d_sqr); + + if( dist[j] <= control->nonb_cut ) + ++num_nbrs; + } + + // compute the nbrs among ghost atoms + for( itr_j = 0; itr_j < numneigh[i]; ++itr_j ){ + j = jlist[itr_j]; + + if( j >= nlocal && !marked[j] && + dist[j] <= (control->vlist_cut - control->bond_cut) ){ + marked[j] = 1; + ++num_marked; + + for( itr_g = 0; itr_g < numneigh[i]; ++itr_g ){ + g = jlist[itr_g]; + + if( g >= nlocal && !marked[g] ){ + get_distance( x[g], x[j], &g_d_sqr, &g_dvec ); + //g_dvec[0] = x[g][0] - x[j][0]; + //g_dvec[1] = x[g][1] - x[j][1]; + //g_dvec[2] = x[g][2] - x[j][2]; + //g_d_sqr = SQR(g_dvec[0]) + SQR(g_dvec[1]) + SQR(g_dvec[2]); + + if( g_d_sqr <= SQR(control->bond_cut) ) + ++num_nbrs; + } + } + } + } + } + + for( i = 0; i < system->N; ++i ) + if( !marked[i] ) { + marked[i] = 1; + ++num_marked; + + for( j = i+1; j < system->N; ++j ) + if( !marked[j] ) { + get_distance( x[j], x[i], &d_sqr, &dvec ); + if( d_sqr <= SQR(control->bond_cut) ) + ++num_nbrs; + } + } + + free( marked ); + free( dist ); + + return static_cast (MAX( num_nbrs*SAFE_ZONE, MIN_CAP*MIN_NBRS )); +} + +/* ---------------------------------------------------------------------- */ + +int PairReaxC::write_reax_lists() +{ + int itr_i, itr_j, itr_g, i, j, g; + int nlocal, nghost, num_nbrs; + int *ilist, *jlist, *numneigh, **firstneigh, *marked; + double d_sqr, g_d, g_d_sqr; + rvec dvec, g_dvec; + double *dist, **x; + reax_list *far_nbrs; + far_neighbor_data *far_list; + + x = atom->x; + nlocal = atom->nlocal; + nghost = atom->nghost; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + far_nbrs = lists + FAR_NBRS; + far_list = far_nbrs->select.far_nbr_list; + + num_nbrs = 0; + marked = (int*) calloc( system->N, sizeof(int) ); + dist = (double*) calloc( system->N, sizeof(double) ); + + for( itr_i = 0; itr_i < list->inum; ++itr_i ){ + i = ilist[itr_i]; + marked[i] = 1; + jlist = firstneigh[i]; + Set_Start_Index( i, num_nbrs, far_nbrs ); + + for( itr_j = 0; itr_j < numneigh[i]; ++itr_j ){ + j = jlist[itr_j]; + get_distance( x[j], x[i], &d_sqr, &dvec ); + dist[j] = sqrt( d_sqr ); + + if( dist[j] <= control->nonb_cut ){ + set_far_nbr( &far_list[num_nbrs], j, dist[j], dvec ); + ++num_nbrs; + } + } + Set_End_Index( i, num_nbrs, far_nbrs ); + + // compute the nbrs among ghost atoms + for( itr_j = 0; itr_j < numneigh[i]; ++itr_j ){ + j = jlist[itr_j]; + + if( j >= nlocal && !marked[j] && + dist[j] <= (control->vlist_cut - control->bond_cut) ){ + marked[j] = 1; + Set_Start_Index( j, num_nbrs, far_nbrs ); + + for( itr_g = 0; itr_g < numneigh[i]; ++itr_g ){ + g = jlist[itr_g]; + + if( g >= nlocal && !marked[g] ){ + get_distance( x[g], x[j], &g_d_sqr, &g_dvec ); + + if( g_d_sqr <= SQR(control->bond_cut) ){ + g_d = sqrt( g_d_sqr ); + + set_far_nbr( &far_list[num_nbrs], g, g_d, g_dvec ); + ++num_nbrs; + } + } + } + Set_End_Index( j, num_nbrs, far_nbrs ); + } + } + } + + for( i = 0; i < system->N; ++i ) + if( !marked[i] ) { + marked[i] = 1; + Set_Start_Index( i, num_nbrs, far_nbrs ); + + for( j = i+1; j < system->N; ++j ) + if( !marked[j] ) { + get_distance( x[j], x[i], &d_sqr, &dvec ); + if( d_sqr <= SQR(control->bond_cut) ) { + set_far_nbr( &far_list[num_nbrs], j, sqrt(d_sqr), dvec ); + ++num_nbrs; + } + } + + Set_End_Index( i, num_nbrs, far_nbrs ); + } + + free( marked ); + free( dist ); + + return num_nbrs; +} + +/* ---------------------------------------------------------------------- */ + +void PairReaxC::read_reax_forces() +{ + for( int i = 0; i < system->N; ++i ) { + system->my_atoms[i].f[0] = workspace->f[i][0]; + system->my_atoms[i].f[1] = workspace->f[i][1]; + system->my_atoms[i].f[2] = workspace->f[i][2]; + + atom->f[i][0] = -workspace->f[i][0]; + atom->f[i][1] = -workspace->f[i][1]; + atom->f[i][2] = -workspace->f[i][2]; + } +} + +/* ---------------------------------------------------------------------- */ + +void *PairReaxC::extract(char *str, int &dim) +{ + dim = 1; + if (strcmp(str,"chi") == 0 && chi) { + for (int i = 1; i <= atom->ntypes; i++) + if (map[i] >= 0) chi[i] = system->reax_param.sbp[map[i]].chi; + else chi[i] = 0.0; + return (void *) chi; + } + if (strcmp(str,"eta") == 0 && eta) { + for (int i = 1; i <= atom->ntypes; i++) + if (map[i] >= 0) eta[i] = system->reax_param.sbp[map[i]].eta; + else eta[i] = 0.0; + return (void *) eta; + } + if (strcmp(str,"gamma") == 0 && gamma) { + for (int i = 1; i <= atom->ntypes; i++) + if (map[i] >= 0) gamma[i] = system->reax_param.sbp[map[i]].gamma; + else gamma[i] = 0.0; + return (void *) gamma; + } + return NULL; +} diff --git a/src/USER-REAXC/pair_reax_c.h b/src/USER-REAXC/pair_reax_c.h new file mode 100644 index 0000000000..a556adf42f --- /dev/null +++ b/src/USER-REAXC/pair_reax_c.h @@ -0,0 +1,66 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS + +PairStyle(reax/c,PairReaxC) + +#else + +#ifndef LMP_PAIR_REAXC_H +#define LMP_PAIR_REAXC_H + +#include "pair.h" +#include "reaxc_types.h" + +namespace LAMMPS_NS { + +class PairReaxC : public Pair { + public: + PairReaxC(class LAMMPS *); + ~PairReaxC(); + void compute(int, int); + void settings(int, char **); + void coeff(int, char **); + void init_style(); + double init_one(int, int); + void *extract(char *, int &); + + private: + reax_system *system; + control_params *control; + simulation_data *data; + storage *workspace; + reax_list *lists; + output_controls *out_control; + mpi_datatypes *mpi_data; + + double cutmax; + int *map; + class FixReaxC *fix_reax; + + double *chi,*eta,*gamma; + + void allocate(); + void write_reax_atoms(); + void get_distance(rvec, rvec, double *, rvec *); + void set_far_nbr(far_neighbor_data *, int, double, rvec); + int estimate_reax_lists(); + int write_reax_lists(); + void read_reax_forces(); +}; + +} + +#endif +#endif diff --git a/src/USER-REAXC/reaxc_allocate.cpp b/src/USER-REAXC/reaxc_allocate.cpp new file mode 100644 index 0000000000..1851ac5bd9 --- /dev/null +++ b/src/USER-REAXC/reaxc_allocate.cpp @@ -0,0 +1,1011 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "allocate.h" +#include "list.h" +#include "reset_tools.h" +#include "tool_box.h" +#include "vector.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_allocate.h" +#include "reaxc_list.h" +#include "reaxc_reset_tools.h" +#include "reaxc_tool_box.h" +#include "reaxc_vector.h" +#endif + + +/* allocate space for my_atoms + important: we cannot know the exact number of atoms that will fall into a + process's box throughout the whole simulation. therefore + we need to make upper bound estimates for various data structures */ +int PreAllocate_Space( reax_system *system, control_params *control, + storage *workspace, MPI_Comm comm ) +{ + int i; + + /* determine the local and total capacity */ + system->local_cap = MAX( (int)(system->n * SAFE_ZONE), MIN_CAP ); + system->total_cap = MAX( (int)(system->N * SAFE_ZONE), MIN_CAP ); +#if defined(DEBUG) + fprintf( stderr, "p%d: local_cap=%d total_cap=%d\n", + system->my_rank, system->local_cap, system->total_cap ); +#endif + + system->my_atoms = (reax_atom*) + scalloc( system->total_cap, sizeof(reax_atom), "my_atoms", comm ); + + /* space for keeping restriction info, if any */ + // not yet implemented in the parallel version!!! + // if( control->restrict_bonds ) { + // workspace->restricted = (int*) + // scalloc( system->local_cap, sizeof(int), "restricted_atoms", comm ); + + // workspace->restricted_list = (int**) + // scalloc( system->local_cap, sizeof(int*), "restricted_list", comm ); + + // for( i = 0; i < system->local_cap; ++i ) + // workspace->restricted_list[i] = (int*) + // scalloc( MAX_RESTRICT, sizeof(int), "restricted_list[i]", comm ); + // } + + return SUCCESS; +} + + +/************* system *************/ +inline void reax_atom_Copy( reax_atom *dest, reax_atom *src ) +{ + dest->orig_id = src->orig_id; + dest->type = src->type; + strcpy( dest->name, src->name ); + rvec_Copy( dest->x, src->x ); + rvec_Copy( dest->v, src->v ); + rvec_Copy( dest->f_old, src->f_old ); + rvec_Copy( dest->s, src->s ); + rvec_Copy( dest->t, src->t ); + dest->Hindex = src->Hindex; + dest->num_bonds = src->num_bonds; + dest->num_hbonds = src->num_hbonds; +} + + +void Copy_Atom_List( reax_atom *dest, reax_atom *src, int n ) +{ + int i; + + for( i = 0; i < n; ++i ) + memcpy( dest+i, src+i, sizeof(reax_atom) ); +} + + +int Allocate_System( reax_system *system, int local_cap, int total_cap, + char *msg ) +{ + system->my_atoms = (reax_atom*) + realloc( system->my_atoms, total_cap*sizeof(reax_atom) ); + + return SUCCESS; +} + + +void DeAllocate_System( reax_system *system ) +{ + int i, j, k; + int ntypes; + reax_interaction *ff_params; + + // dealloocate the atom list + sfree( system->my_atoms, "system->my_atoms" ); + + // deallocate the ffield parameters storage + ff_params = &(system->reax_param); + ntypes = ff_params->num_atom_types; + + sfree( ff_params->gp.l, "ff:globals" ); + + for( i = 0; i < ntypes; ++i ) { + for( j = 0; j < ntypes; ++j ) { + for( k = 0; k < ntypes; ++k ) { + sfree( ff_params->fbp[i][j][k], "ff:fbp[i,j,k]" ); + } + sfree( ff_params->fbp[i][j], "ff:fbp[i,j]" ); + sfree( ff_params->thbp[i][j], "ff:thbp[i,j]" ); + sfree( ff_params->hbp[i][j], "ff:hbp[i,j]" ); + } + sfree( ff_params->fbp[i], "ff:fbp[i]" ); + sfree( ff_params->thbp[i], "ff:thbp[i]" ); + sfree( ff_params->hbp[i], "ff:hbp[i]" ); + sfree( ff_params->tbp[i], "ff:tbp[i]" ); + } + sfree( ff_params->fbp, "ff:fbp" ); + sfree( ff_params->thbp, "ff:thbp" ); + sfree( ff_params->hbp, "ff:hbp" ); + sfree( ff_params->tbp, "ff:tbp" ); + sfree( ff_params->sbp, "ff:sbp" ); +} + + +/************* workspace *************/ +void DeAllocate_Workspace( control_params *control, storage *workspace ) +{ + int i; + + if( !workspace->allocated ) + return; + + workspace->allocated = 0; + + /* communication storage */ + for( i = 0; i < MAX_NBRS; ++i ) { + sfree( workspace->tmp_dbl[i], "tmp_dbl[i]" ); + sfree( workspace->tmp_rvec[i], "tmp_rvec[i]" ); + sfree( workspace->tmp_rvec2[i], "tmp_rvec2[i]" ); + } + + /* bond order storage */ + sfree( workspace->within_bond_box, "skin" ); + sfree( workspace->total_bond_order, "total_bo" ); + sfree( workspace->Deltap, "Deltap" ); + sfree( workspace->Deltap_boc, "Deltap_boc" ); + sfree( workspace->dDeltap_self, "dDeltap_self" ); + sfree( workspace->Delta, "Delta" ); + sfree( workspace->Delta_lp, "Delta_lp" ); + sfree( workspace->Delta_lp_temp, "Delta_lp_temp" ); + sfree( workspace->dDelta_lp, "dDelta_lp" ); + sfree( workspace->dDelta_lp_temp, "dDelta_lp_temp" ); + sfree( workspace->Delta_e, "Delta_e" ); + sfree( workspace->Delta_boc, "Delta_boc" ); + sfree( workspace->nlp, "nlp" ); + sfree( workspace->nlp_temp, "nlp_temp" ); + sfree( workspace->Clp, "Clp" ); + sfree( workspace->vlpex, "vlpex" ); + sfree( workspace->bond_mark, "bond_mark" ); + sfree( workspace->done_after, "done_after" ); + + /* QEq storage */ + sfree( workspace->Hdia_inv, "Hdia_inv" ); + sfree( workspace->b_s, "b_s" ); + sfree( workspace->b_t, "b_t" ); + sfree( workspace->b_prc, "b_prc" ); + sfree( workspace->b_prm, "b_prm" ); + sfree( workspace->s, "s" ); + sfree( workspace->t, "t" ); + sfree( workspace->droptol, "droptol" ); + sfree( workspace->b, "b" ); + sfree( workspace->x, "x" ); + + /* GMRES storage */ + for( i = 0; i < RESTART+1; ++i ) { + sfree( workspace->h[i], "h[i]" ); + sfree( workspace->v[i], "v[i]" ); + } + sfree( workspace->h, "h" ); + sfree( workspace->v, "v" ); + sfree( workspace->y, "y" ); + sfree( workspace->z, "z" ); + sfree( workspace->g, "g" ); + sfree( workspace->hs, "hs" ); + sfree( workspace->hc, "hc" ); + /* CG storage */ + sfree( workspace->r, "r" ); + sfree( workspace->d, "d" ); + sfree( workspace->q, "q" ); + sfree( workspace->p, "p" ); + sfree( workspace->r2, "r2" ); + sfree( workspace->d2, "d2" ); + sfree( workspace->q2, "q2" ); + sfree( workspace->p2, "p2" ); + + /* integrator */ + // sfree( workspace->f_old ); + sfree( workspace->v_const, "v_const" ); + + /*workspace->realloc.num_far = -1; + workspace->realloc.Htop = -1; + workspace->realloc.hbonds = -1; + workspace->realloc.bonds = -1; + workspace->realloc.num_3body = -1; + workspace->realloc.gcell_atoms = -1;*/ + + /* storage for analysis */ + // if( control->molecular_analysis || control->diffusion_coef ) { + // sfree( workspace->mark, "mark" ); + // sfree( workspace->old_mark, "old_mark" ); + // } + + // if( control->diffusion_coef ) + // sfree( workspace->x_old, "x_old" ); + + /* force related storage */ + sfree( workspace->f, "f" ); + sfree( workspace->CdDelta, "CdDelta" ); +#ifdef TEST_FORCES + sfree(workspace->dDelta, "dDelta" ); + sfree( workspace->f_ele, "f_ele" ); + sfree( workspace->f_vdw, "f_vdw" ); + sfree( workspace->f_bo, "f_bo" ); + sfree( workspace->f_be, "f_be" ); + sfree( workspace->f_lp, "f_lp" ); + sfree( workspace->f_ov, "f_ov" ); + sfree( workspace->f_un, "f_un" ); + sfree( workspace->f_ang, "f_ang" ); + sfree( workspace->f_coa, "f_coa" ); + sfree( workspace->f_pen, "f_pen" ); + sfree( workspace->f_hb, "f_hb" ); + sfree( workspace->f_tor, "f_tor" ); + sfree( workspace->f_con, "f_con" ); + sfree( workspace->f_tot, "f_tot" ); + + sfree( workspace->rcounts, "rcounts" ); + sfree( workspace->displs, "displs" ); + sfree( workspace->id_all, "id_all" ); + sfree( workspace->f_all, "f_all" ); +#endif + + /* hbond storage */ + //sfree( workspace->Hindex, "Hindex" ); + //sfree( workspace->num_bonds ); + //sfree( workspace->num_hbonds ); + //sfree( workspace->hash, "hash" ); + //sfree( workspace->rev_hash, "rev_hash" ); +} + + +int Allocate_Workspace( reax_system *system, control_params *control, + storage *workspace, int local_cap, int total_cap, + MPI_Comm comm, char *msg ) +{ + int i, total_real, total_rvec, local_int, local_real, local_rvec; + + workspace->allocated = 1; + total_real = total_cap * sizeof(real); + total_rvec = total_cap * sizeof(rvec); + local_int = local_cap * sizeof(int); + local_real = local_cap * sizeof(real); + local_rvec = local_cap * sizeof(rvec); + + /* communication storage */ + for( i = 0; i < MAX_NBRS; ++i ) { + workspace->tmp_dbl[i] = (real*) + scalloc( total_cap, sizeof(real), "tmp_dbl", comm ); + workspace->tmp_rvec[i] = (rvec*) + scalloc( total_cap, sizeof(rvec), "tmp_rvec", comm ); + workspace->tmp_rvec2[i] = (rvec2*) + scalloc( total_cap, sizeof(rvec2), "tmp_rvec2", comm ); + } + + /* bond order related storage */ + workspace->within_bond_box = (int*) + scalloc( total_cap, sizeof(int), "skin", comm ); + workspace->total_bond_order = (real*) smalloc( total_real, "total_bo", comm ); + workspace->Deltap = (real*) smalloc( total_real, "Deltap", comm ); + workspace->Deltap_boc = (real*) smalloc( total_real, "Deltap_boc", comm ); + workspace->dDeltap_self = (rvec*) smalloc( total_rvec, "dDeltap_self", comm ); + workspace->Delta = (real*) smalloc( total_real, "Delta", comm ); + workspace->Delta_lp = (real*) smalloc( total_real, "Delta_lp", comm ); + workspace->Delta_lp_temp = (real*) + smalloc( total_real, "Delta_lp_temp", comm ); + workspace->dDelta_lp = (real*) smalloc( total_real, "dDelta_lp", comm ); + workspace->dDelta_lp_temp = (real*) + smalloc( total_real, "dDelta_lp_temp", comm ); + workspace->Delta_e = (real*) smalloc( total_real, "Delta_e", comm ); + workspace->Delta_boc = (real*) smalloc( total_real, "Delta_boc", comm ); + workspace->nlp = (real*) smalloc( total_real, "nlp", comm ); + workspace->nlp_temp = (real*) smalloc( total_real, "nlp_temp", comm ); + workspace->Clp = (real*) smalloc( total_real, "Clp", comm ); + workspace->vlpex = (real*) smalloc( total_real, "vlpex", comm ); + workspace->bond_mark = (int*) + scalloc( total_cap, sizeof(int), "bond_mark", comm ); + workspace->done_after = (int*) + scalloc( total_cap, sizeof(int), "done_after", comm ); + // fprintf( stderr, "p%d: bond order storage\n", system->my_rank ); + + /* QEq storage */ + workspace->Hdia_inv = (real*) + scalloc( total_cap, sizeof(real), "Hdia_inv", comm ); + workspace->b_s = (real*) scalloc( total_cap, sizeof(real), "b_s", comm ); + workspace->b_t = (real*) scalloc( total_cap, sizeof(real), "b_t", comm ); + workspace->b_prc = (real*) scalloc( total_cap, sizeof(real), "b_prc", comm ); + workspace->b_prm = (real*) scalloc( total_cap, sizeof(real), "b_prm", comm ); + workspace->s = (real*) scalloc( total_cap, sizeof(real), "s", comm ); + workspace->t = (real*) scalloc( total_cap, sizeof(real), "t", comm ); + workspace->droptol = (real*) + scalloc( total_cap, sizeof(real), "droptol", comm ); + workspace->b = (rvec2*) scalloc( total_cap, sizeof(rvec2), "b", comm ); + workspace->x = (rvec2*) scalloc( total_cap, sizeof(rvec2), "x", comm ); + + /* GMRES storage */ + workspace->y = (real*) scalloc( RESTART+1, sizeof(real), "y", comm ); + workspace->z = (real*) scalloc( RESTART+1, sizeof(real), "z", comm ); + workspace->g = (real*) scalloc( RESTART+1, sizeof(real), "g", comm ); + workspace->h = (real**) scalloc( RESTART+1, sizeof(real*), "h", comm ); + workspace->hs = (real*) scalloc( RESTART+1, sizeof(real), "hs", comm ); + workspace->hc = (real*) scalloc( RESTART+1, sizeof(real), "hc", comm ); + workspace->v = (real**) scalloc( RESTART+1, sizeof(real*), "v", comm ); + + for( i = 0; i < RESTART+1; ++i ) { + workspace->h[i] = (real*) scalloc( RESTART+1, sizeof(real), "h[i]", comm ); + workspace->v[i] = (real*) scalloc( total_cap, sizeof(real), "v[i]", comm ); + } + + /* CG storage */ + workspace->r = (real*) scalloc( total_cap, sizeof(real), "r", comm ); + workspace->d = (real*) scalloc( total_cap, sizeof(real), "d", comm ); + workspace->q = (real*) scalloc( total_cap, sizeof(real), "q", comm ); + workspace->p = (real*) scalloc( total_cap, sizeof(real), "p", comm ); + workspace->r2 = (rvec2*) scalloc( total_cap, sizeof(rvec2), "r2", comm ); + workspace->d2 = (rvec2*) scalloc( total_cap, sizeof(rvec2), "d2", comm ); + workspace->q2 = (rvec2*) scalloc( total_cap, sizeof(rvec2), "q2", comm ); + workspace->p2 = (rvec2*) scalloc( total_cap, sizeof(rvec2), "p2", comm ); + + /* integrator storage */ + workspace->v_const = (rvec*) smalloc( local_rvec, "v_const", comm ); + + /* storage for analysis */ + // not yet implemented in the parallel version!!! + // if( control->molecular_analysis || control->diffusion_coef ) { + // workspace->mark = (int*) scalloc( local_cap, sizeof(int), "mark", comm ); + // workspace->old_mark = (int*) + // scalloc( local_cap, sizeof(int), "old_mark", comm ); + // } + // else + // workspace->mark = workspace->old_mark = NULL; + + // if( control->diffusion_coef ) + // workspace->x_old = (rvec*) + // scalloc( local_cap, sizeof(rvec), "x_old", comm ); + // else workspace->x_old = NULL; + + // /* force related storage */ + workspace->f = (rvec*) scalloc( total_cap, sizeof(rvec), "f", comm ); + workspace->CdDelta = (real*) + scalloc( total_cap, sizeof(real), "CdDelta", comm ); + +#ifdef TEST_FORCES + workspace->dDelta=(rvec*) smalloc( total_rvec, "dDelta", comm ); + workspace->f_ele =(rvec*) smalloc( total_rvec, "f_ele", comm ); + workspace->f_vdw =(rvec*) smalloc( total_rvec, "f_vdw", comm ); + workspace->f_bo =(rvec*) smalloc( total_rvec, "f_bo", comm ); + workspace->f_be =(rvec*) smalloc( total_rvec, "f_be", comm ); + workspace->f_lp =(rvec*) smalloc( total_rvec, "f_lp", comm ); + workspace->f_ov =(rvec*) smalloc( total_rvec, "f_ov", comm ); + workspace->f_un =(rvec*) smalloc( total_rvec, "f_un", comm ); + workspace->f_ang =(rvec*) smalloc( total_rvec, "f_ang", comm ); + workspace->f_coa =(rvec*) smalloc( total_rvec, "f_coa", comm ); + workspace->f_pen =(rvec*) smalloc( total_rvec, "f_pen", comm ); + workspace->f_hb =(rvec*) smalloc( total_rvec, "f_hb", comm ); + workspace->f_tor =(rvec*) smalloc( total_rvec, "f_tor", comm ); + workspace->f_con =(rvec*) smalloc( total_rvec, "f_con", comm ); + workspace->f_tot =(rvec*) smalloc( total_rvec, "f_tot", comm ); + + if( system->my_rank == MASTER_NODE ) { + workspace->rcounts = (int*) + smalloc( system->wsize*sizeof(int), "rcount", comm ); + workspace->displs = (int*) + smalloc( system->wsize*sizeof(int), "displs", comm ); + workspace->id_all = (int*) + smalloc( system->bigN*sizeof(int), "id_all", comm ); + workspace->f_all = (rvec*) + smalloc( system->bigN*sizeof(rvec), "f_all", comm ); + } + else{ + workspace->rcounts = NULL; + workspace->displs = NULL; + workspace->id_all = NULL; + workspace->f_all = NULL; + } +#endif + + return SUCCESS; +} + + +void Reallocate_Neighbor_List( reax_list *far_nbrs, int n, int num_intrs, + MPI_Comm comm ) +{ + Delete_List( far_nbrs, comm ); + if(!Make_List( n, num_intrs, TYP_FAR_NEIGHBOR, far_nbrs, comm )){ + fprintf(stderr, "Problem in initializing far nbrs list. Terminating!\n"); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } +} + + +int Allocate_Matrix( sparse_matrix **pH, int cap, int m, MPI_Comm comm ) +{ + sparse_matrix *H; + + *pH = (sparse_matrix*) + smalloc( sizeof(sparse_matrix), "sparse_matrix", comm ); + H = *pH; + H->cap = cap; + H->m = m; + H->start = (int*) smalloc( sizeof(int) * cap, "matrix_start", comm ); + H->end = (int*) smalloc( sizeof(int) * cap, "matrix_end", comm ); + H->entries = (sparse_matrix_entry*) + smalloc( sizeof(sparse_matrix_entry)*m, "matrix_entries", comm ); + + return SUCCESS; +} + + +void Deallocate_Matrix( sparse_matrix *H ) +{ + sfree(H->start, "H->start"); + sfree(H->end, "H->end"); + sfree(H->entries, "H->entries"); + sfree(H, "H"); +} + + +int Reallocate_Matrix( sparse_matrix **H, int n, int m, char *name, + MPI_Comm comm ) +{ + Deallocate_Matrix( *H ); + if( !Allocate_Matrix( H, n, m, comm ) ) { + fprintf(stderr, "not enough space for %s matrix. terminating!\n", name); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } + +#if defined(DEBUG_FOCUS) + fprintf( stderr, "reallocating %s matrix, n = %d, m = %d\n", name, n, m ); + fprintf( stderr, "memory allocated: %s = %dMB\n", + name, (int)(m * sizeof(sparse_matrix_entry) / (1024*1024)) ); +#endif + return SUCCESS; +} + + +int Reallocate_HBonds_List( reax_system *system, reax_list *hbonds, + MPI_Comm comm ) +{ + int i, id, total_hbonds; + + total_hbonds = 0; + for( i = 0; i < system->n; ++i ) + if( (id = system->my_atoms[i].Hindex) >= 0 ) { + // commented out - already updated in validate_lists in forces.c + // system->my_atoms[i].num_hbonds = MAX(Num_Entries(id,hbonds)*SAFER_ZONE, + // MIN_HBONDS); + total_hbonds += system->my_atoms[i].num_hbonds; + } + total_hbonds = (int)(MAX( total_hbonds*SAFER_ZONE, MIN_CAP*MIN_HBONDS )); + + Delete_List( hbonds, comm ); + if( !Make_List( system->Hcap, total_hbonds, TYP_HBOND, hbonds, comm ) ) { + fprintf( stderr, "not enough space for hbonds list. terminating!\n" ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } + + return total_hbonds; +} + + +int Reallocate_Bonds_List( reax_system *system, reax_list *bonds, + int *total_bonds, int *est_3body, MPI_Comm comm ) +{ + int i; + + *total_bonds = 0; + *est_3body = 0; + for( i = 0; i < system->N; ++i ){ + *est_3body += SQR( Num_Entries( i, bonds ) ); + // commented out - already updated in validate_lists in forces.c + // system->my_atoms[i].num_bonds = MAX( Num_Entries(i,bonds)*2, MIN_BONDS ); + *total_bonds += system->my_atoms[i].num_bonds; + } + *total_bonds = (int)(MAX( *total_bonds * SAFE_ZONE, MIN_CAP*MIN_BONDS )); + + Delete_List( bonds, comm ); + if(!Make_List(system->total_cap, *total_bonds, TYP_BOND, bonds, comm)) { + fprintf( stderr, "not enough space for bonds list. terminating!\n" ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } + + return SUCCESS; +} + + +/************* grid *************/ +int Estimate_GCell_Population( reax_system* system, MPI_Comm comm ) +{ + int d, i, j, k, l, max_atoms, my_max, all_max; + ivec c; + grid *g; + grid_cell *gc; + simulation_box *big_box, *my_ext_box; + reax_atom *atoms; + + big_box = &(system->big_box); + my_ext_box = &(system->my_ext_box); + g = &(system->my_grid); + atoms = system->my_atoms; + Reset_Grid( g ); + + for( l = 0; l < system->n; l++ ) { + for( d = 0; d < 3; ++d ) { + //if( atoms[l].x[d] < big_box->min[d] ) + // atoms[l].x[d] += big_box->box_norms[d]; + //else if( atoms[l].x[d] >= big_box->max[d] ) + // atoms[l].x[d] -= big_box->box_norms[d]; + + c[d] = (int)((atoms[l].x[d]-my_ext_box->min[d])*g->inv_len[d]); + + if( c[d] >= g->native_end[d] ) + c[d] = g->native_end[d] - 1; + else if( c[d] < g->native_str[d] ) + c[d] = g->native_str[d]; + } +#if defined(DEBUG) + fprintf( stderr, "p%d bin_my_atoms: l:%d - atom%d @ %.5f %.5f %.5f" \ + "--> cell: %d %d %d\n", + system->my_rank, l, atoms[l].orig_id, + atoms[l].x[0], atoms[l].x[1], atoms[l].x[2], + c[0], c[1], c[2] ); +#endif + gc = &( g->cells[c[0]][c[1]][c[2]] ); + gc->top++; + } + + max_atoms = 0; + for( i = 0; i < g->ncells[0]; i++ ) + for( j = 0; j < g->ncells[1]; j++ ) + for( k = 0; k < g->ncells[2]; k++ ) { + gc = &(g->cells[i][j][k]); + if( max_atoms < gc->top ) + max_atoms = gc->top; +#if defined(DEBUG) + fprintf( stderr, "p%d gc[%d,%d,%d]->top=%d\n", + system->my_rank, i, j, k, gc->top ); +#endif + } + + my_max = (int)(MAX(max_atoms*SAFE_ZONE, MIN_GCELL_POPL)); + MPI_Allreduce( &my_max, &all_max, 1, MPI_INT, MPI_MAX, comm ); +#if defined(DEBUG) + fprintf( stderr, "p%d max_atoms=%d, my_max=%d, all_max=%d\n", + system->my_rank, max_atoms, my_max, all_max ); +#endif + + return all_max; +} + + +void Allocate_Grid( reax_system *system, MPI_Comm comm ) +{ + int i, j, k, l; + grid *g; + grid_cell *gc; + + g = &( system->my_grid ); + + /* allocate gcell reordering space */ + g->order = (ivec*) scalloc( g->total+1, sizeof(ivec), "g:order", comm ); + + /* allocate the gcells for the new grid */ + g->max_nbrs = (2*g->vlist_span[0]+1)*(2*g->vlist_span[1]+1)* + (2*g->vlist_span[2]+1)+3; + + g->cells = (grid_cell***) + scalloc( g->ncells[0], sizeof(grid_cell**), "gcells", comm ); + for( i = 0; i < g->ncells[0]; i++ ) { + g->cells[i] = (grid_cell**) + scalloc( g->ncells[1], sizeof(grid_cell*),"gcells[i]", comm ); + + for( j = 0; j < g->ncells[1]; ++j ) { + g->cells[i][j] = (grid_cell*) + scalloc( g->ncells[2], sizeof(grid_cell), "gcells[i][j]", comm ); + + for( k = 0; k < g->ncells[2]; k++ ) { + gc = &(g->cells[i][j][k]); + gc->top = gc->mark = gc->str = gc->end = 0; + gc->nbrs = (grid_cell**) + scalloc( g->max_nbrs, sizeof(grid_cell*), "g:nbrs", comm ); + gc->nbrs_x = (ivec*) + scalloc( g->max_nbrs, sizeof(ivec), "g:nbrs_x", comm ); + gc->nbrs_cp = (rvec*) + scalloc( g->max_nbrs, sizeof(rvec), "g:nbrs_cp", comm ); + for( l = 0; l < g->max_nbrs; ++l ) + gc->nbrs[l] = NULL; + } + } + } + + /* allocate atom id storage in gcells */ + g->max_atoms = Estimate_GCell_Population( system, comm ); + /* space for storing atom id's is required only for native cells */ + for( i = g->native_str[0]; i < g->native_end[0]; ++i ) + for( j = g->native_str[1]; j < g->native_end[1]; ++j ) + for( k = g->native_str[2]; k < g->native_end[2]; ++k ) + g->cells[i][j][k].atoms = (int*) scalloc( g->max_atoms, sizeof(int), + "g:atoms", comm ); +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d-allocated %dx%dx%d grid: nbrs=%d atoms=%d space=%dMB\n", + system->my_rank, g->ncells[0], g->ncells[1], g->ncells[2], + g->max_nbrs, g->max_atoms, + (int) + ((g->total*sizeof(grid_cell)+g->total*g->max_nbrs*sizeof(int*) + + g->total*g->max_nbrs*sizeof(rvec) + + (g->native_end[0]-g->native_str[0])* + (g->native_end[1]-g->native_str[1])* + (g->native_end[2]-g->native_str[2])*g->max_atoms*sizeof(int))/ + (1024*1024)) ); +#endif +} + + +void Deallocate_Grid( grid *g ) +{ + int i, j, k; + grid_cell *gc; + + sfree( g->order, "g:order" ); + + /* deallocate the grid cells */ + for( i = 0; i < g->ncells[0]; i++ ) { + for( j = 0; j < g->ncells[1]; j++ ) { + for( k = 0; k < g->ncells[2]; k++ ) { + gc = &(g->cells[i][j][k]); + sfree( gc->nbrs, "g:nbrs" ); + sfree( gc->nbrs_x, "g:nbrs_x" ); + sfree( gc->nbrs_cp, "g:nbrs_cp" ); + if(gc->atoms != NULL ) + sfree( gc->atoms, "g:atoms" ); + } + sfree( g->cells[i][j], "g:cells[i][j]" ); + } + sfree( g->cells[i], "g:cells[i]" ); + } + sfree( g->cells, "g:cells" ); +} + + +/************ mpi buffers ********************/ + /* make the allocations based on the largest need by the three comms: + 1- transfer an atom who has moved into other proc's domain (mpi_atom) + 2- exchange boundary atoms (boundary_atom) + 3- update position info for boundary atoms (mpi_rvec) + + the largest space by far is required for the 2nd comm operation above. + buffers are void*, type cast to the correct pointer type to access + the allocated buffers */ +int Allocate_MPI_Buffers( mpi_datatypes *mpi_data, int est_recv, + neighbor_proc *my_nbrs, char *msg ) +{ + int i; + mpi_out_data *mpi_buf; + MPI_Comm comm; + + comm = mpi_data->world; + + /* in buffers */ + mpi_data->in1_buffer = (void*) + scalloc( est_recv, sizeof(boundary_atom), "in1_buffer", comm ); + mpi_data->in2_buffer = (void*) + scalloc( est_recv, sizeof(boundary_atom), "in2_buffer", comm ); + + /* out buffers */ + for( i = 0; i < MAX_NBRS; ++i ) { + mpi_buf = &( mpi_data->out_buffers[i] ); + /* allocate storage for the neighbor processor i */ + mpi_buf->index = (int*) + scalloc( my_nbrs[i].est_send, sizeof(int), "mpibuf:index", comm ); + mpi_buf->out_atoms = (void*) + scalloc( my_nbrs[i].est_send, sizeof(boundary_atom), "mpibuf:out_atoms", + comm ); + } + + return SUCCESS; +} + + +void Deallocate_MPI_Buffers( mpi_datatypes *mpi_data ) +{ + int i; + mpi_out_data *mpi_buf; + + sfree( mpi_data->in1_buffer, "in1_buffer" ); + sfree( mpi_data->in2_buffer, "in2_buffer" ); + + for( i = 0; i < MAX_NBRS; ++i ) { + mpi_buf = &( mpi_data->out_buffers[i] ); + sfree( mpi_buf->index, "mpibuf:index" ); + sfree( mpi_buf->out_atoms, "mpibuf:out_atoms" ); + } +} + + +void ReAllocate( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, reax_list **lists, + mpi_datatypes *mpi_data ) +{ + int i, j, k, p; + int num_bonds, est_3body, nflag, Nflag, Hflag, mpi_flag, ret, total_send; + int renbr; + reallocate_data *realloc; + reax_list *far_nbrs; + sparse_matrix *H; + grid *g; + neighbor_proc *nbr_pr; + mpi_out_data *nbr_data; + MPI_Comm comm; + char msg[200]; + + realloc = &(workspace->realloc); + g = &(system->my_grid); + comm = mpi_data->world; + +#if defined(DEBUG) + fprintf( stderr, "p%d@reallocate: n: %d, N: %d, numH: %d\n", + system->my_rank, system->n, system->N, system->numH ); + fprintf( stderr, "p%d@reallocate: local_cap: %d, total_cap: %d, Hcap: %d\n", + system->my_rank, system->local_cap, system->total_cap, + system->Hcap); + fprintf( stderr, "p%d: realloc.num_far: %d\n", + system->my_rank, realloc->num_far ); + fprintf( stderr, "p%d: realloc.H: %d, realloc.Htop: %d\n", + system->my_rank, realloc->H, realloc->Htop ); + fprintf( stderr, "p%d: realloc.Hbonds: %d, realloc.num_hbonds: %d\n", + system->my_rank, realloc->hbonds, realloc->num_hbonds ); + fprintf( stderr, "p%d: realloc.bonds: %d, num_bonds: %d\n", + system->my_rank, realloc->bonds, realloc->num_bonds ); + fprintf( stderr, "p%d: realloc.num_3body: %d\n", + system->my_rank, realloc->num_3body ); +#endif + + // IMPORTANT: LOOSE ZONES CHECKS ARE DISABLED FOR NOW BY &&'ing with 0!!! + nflag = 0; + if( system->n >= DANGER_ZONE * system->local_cap || + (0 && system->n <= LOOSE_ZONE * system->local_cap) ) { + nflag = 1; + system->local_cap = (int)(system->n * SAFE_ZONE); + } + + Nflag = 0; + if( system->N >= DANGER_ZONE * system->total_cap || + (0 && system->N <= LOOSE_ZONE * system->total_cap) ) { + Nflag = 1; + system->total_cap = (int)(system->N * SAFE_ZONE); + } + + if( Nflag ) { + /* system */ +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: reallocating system and workspace -"\ + "n=%d N=%d local_cap=%d total_cap=%d\n", + system->my_rank, system->n, system->N, + system->local_cap, system->total_cap ); +#endif + ret = Allocate_System( system, system->local_cap, system->total_cap, msg ); + if( ret != SUCCESS ) { + fprintf( stderr, "not enough space for atom_list: total_cap=%d", + system->total_cap ); + fprintf( stderr, "terminating...\n" ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } + + /* workspace */ + DeAllocate_Workspace( control, workspace ); + ret = Allocate_Workspace( system, control, workspace, system->local_cap, + system->total_cap, comm, msg ); + if( ret != SUCCESS ) { + fprintf( stderr, "no space for workspace: local_cap=%d total_cap=%d", + system->local_cap, system->total_cap ); + fprintf( stderr, "terminating...\n" ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } + } + + + renbr = (data->step - data->prev_steps) % control->reneighbor == 0; + /* far neighbors */ + if( renbr ) { + far_nbrs = *lists + FAR_NBRS; + + if( Nflag || realloc->num_far >= far_nbrs->num_intrs * DANGER_ZONE ) { + if( realloc->num_far > far_nbrs->num_intrs ) { + fprintf( stderr, "step%d-ran out of space on far_nbrs: top=%d, max=%d", + data->step, realloc->num_far, far_nbrs->num_intrs ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: reallocating far_nbrs: num_fars=%d, space=%dMB\n", + system->my_rank, (int)(realloc->num_far*SAFE_ZONE), + (int)(realloc->num_far*SAFE_ZONE*sizeof(far_neighbor_data)/ + (1024*1024)) ); +#endif + Reallocate_Neighbor_List( far_nbrs, system->total_cap, + (int)(realloc->num_far*SAFE_ZONE), + comm ); + realloc->num_far = 0; + } + } + +#if defined(PURE_REAX) + /* qeq coef matrix */ + H = workspace->H; + if( nflag || realloc->Htop >= H->m * DANGER_ZONE ) { + if( realloc->Htop > H->m ) { + fprintf( stderr, + "step%d - ran out of space on H matrix: Htop=%d, max = %d", + data->step, realloc->Htop, H->m ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: reallocating H matrix: Htop=%d, space=%dMB\n", + system->my_rank, (int)(realloc->Htop*SAFE_ZONE), + (int)(realloc->Htop * SAFE_ZONE * sizeof(sparse_matrix_entry) / + (1024*1024)) ); +#endif + Reallocate_Matrix( &(workspace->H), system->local_cap, + realloc->Htop*SAFE_ZONE, "H", comm ); + //Deallocate_Matrix( workspace->L ); + //Deallocate_Matrix( workspace->U ); + workspace->L = NULL; + workspace->U = NULL; + realloc->Htop = 0; + } +#endif /*PURE_REAX*/ + + /* hydrogen bonds list */ + if( control->hbond_cut > 0 ) { + Hflag = 0; + if( system->numH >= DANGER_ZONE * system->Hcap || + (0 && system->numH <= LOOSE_ZONE * system->Hcap) ) { + Hflag = 1; + system->Hcap = (int)(system->numH * SAFE_ZONE); + } + + if( Hflag || realloc->hbonds ) { + ret = Reallocate_HBonds_List( system, (*lists)+HBONDS, comm ); + realloc->hbonds = 0; +#if defined(DEBUG_FOCUS) + fprintf(stderr, "p%d: reallocating hbonds: total_hbonds=%d space=%dMB\n", + system->my_rank, ret, (int)(ret*sizeof(hbond_data)/(1024*1024))); +#endif + } + } + + /* bonds list */ + num_bonds = est_3body = -1; + if( Nflag || realloc->bonds ){ + Reallocate_Bonds_List( system, (*lists)+BONDS, &num_bonds, + &est_3body, comm ); + realloc->bonds = 0; + realloc->num_3body = MAX( realloc->num_3body, est_3body ); +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: reallocating bonds: total_bonds=%d, space=%dMB\n", + system->my_rank, num_bonds, + (int)(num_bonds*sizeof(bond_data)/(1024*1024)) ); +#endif + } + + /* 3-body list */ + if( realloc->num_3body > 0 ) { +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: reallocating 3body list: num_3body=%d, space=%dMB\n", + system->my_rank, realloc->num_3body, + (int)(realloc->num_3body * sizeof(three_body_interaction_data) / + (1024*1024)) ); +#endif + Delete_List( (*lists)+THREE_BODIES, comm ); + + if( num_bonds == -1 ) + num_bonds = ((*lists)+BONDS)->num_intrs; + + realloc->num_3body = (int)(MAX(realloc->num_3body*SAFE_ZONE, MIN_3BODIES)); + + if( !Make_List( num_bonds, realloc->num_3body, TYP_THREE_BODY, + (*lists)+THREE_BODIES, comm ) ) { + fprintf( stderr, "Problem in initializing angles list. Terminating!\n" ); + MPI_Abort( comm, CANNOT_INITIALIZE ); + } + realloc->num_3body = -1; + } + +#if defined(PURE_REAX) + /* grid */ + if( renbr && realloc->gcell_atoms > -1 ) { +#if defined(DEBUG_FOCUS) + fprintf(stderr, "reallocating gcell: g->max_atoms: %d\n", g->max_atoms); +#endif + for( i = g->native_str[0]; i < g->native_end[0]; i++ ) + for( j = g->native_str[1]; j < g->native_end[1]; j++ ) + for( k = g->native_str[2]; k < g->native_end[2]; k++ ) { + // reallocate g->atoms + sfree( g->cells[i][j][k].atoms, "g:atoms" ); + g->cells[i][j][k].atoms = (int*) + scalloc( realloc->gcell_atoms, sizeof(int), "g:atoms", comm); + } + realloc->gcell_atoms = -1; + } + + /* mpi buffers */ + // we have to be at a renbring step - + // to ensure correct values at mpi_buffers for update_boundary_positions + if( !renbr ) + mpi_flag = 0; + // check whether in_buffer capacity is enough + else if( system->max_recved >= system->est_recv * 0.90 ) + mpi_flag = 1; + else { + // otherwise check individual outgoing buffers + mpi_flag = 0; + for( p = 0; p < MAX_NBRS; ++p ) { + nbr_pr = &( system->my_nbrs[p] ); + nbr_data = &( mpi_data->out_buffers[p] ); + if( nbr_data->cnt >= nbr_pr->est_send * 0.90 ) { + mpi_flag = 1; + break; + } + } + } + + if( mpi_flag ) { +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: reallocating mpi_buf: old_recv=%d\n", + system->my_rank, system->est_recv ); + for( p = 0; p < MAX_NBRS; ++p ) + fprintf( stderr, "p%d: nbr%d old_send=%d\n", + system->my_rank, p, system->my_nbrs[p].est_send ); +#endif + /* update mpi buffer estimates based on last comm */ + system->est_recv = MAX( system->max_recved*SAFER_ZONE, MIN_SEND ); + system->est_trans = + (system->est_recv * sizeof(boundary_atom)) / sizeof(mpi_atom); + total_send = 0; + for( p = 0; p < MAX_NBRS; ++p ) { + nbr_pr = &( system->my_nbrs[p] ); + nbr_data = &( mpi_data->out_buffers[p] ); + nbr_pr->est_send = MAX( nbr_data->cnt*SAFER_ZONE, MIN_SEND ); + total_send += nbr_pr->est_send; + } +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: reallocating mpi_buf: recv=%d send=%d total=%dMB\n", + system->my_rank, system->est_recv, total_send, + (int)((system->est_recv+total_send)*sizeof(boundary_atom)/ + (1024*1024))); + for( p = 0; p < MAX_NBRS; ++p ) + fprintf( stderr, "p%d: nbr%d new_send=%d\n", + system->my_rank, p, system->my_nbrs[p].est_send ); +#endif + + /* reallocate mpi buffers */ + Deallocate_MPI_Buffers( mpi_data ); + ret = Allocate_MPI_Buffers( mpi_data, system->est_recv, + system->my_nbrs, msg ); + if( ret != SUCCESS ) { + fprintf( stderr, "%s", msg ); + fprintf( stderr, "terminating...\n" ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } + } +#endif /*PURE_REAX*/ + +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d @ step%d: reallocate done\n", + system->my_rank, data->step ); + MPI_Barrier( comm ); +#endif +} diff --git a/src/USER-REAXC/reaxc_allocate.h b/src/USER-REAXC/reaxc_allocate.h new file mode 100644 index 0000000000..04e24c67ec --- /dev/null +++ b/src/USER-REAXC/reaxc_allocate.h @@ -0,0 +1,49 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __ALLOCATE_H_ +#define __ALLOCATE_H_ + +#include "reaxc_types.h" +int PreAllocate_Space( reax_system*, control_params*, storage*, MPI_Comm ); + +void reax_atom_Copy( reax_atom*, reax_atom* ); +int Allocate_System( reax_system*, int, int, char* ); +void DeAllocate_System( reax_system* ); + +int Allocate_Workspace( reax_system*, control_params*, storage*, + int, int, MPI_Comm, char* ); +void DeAllocate_Workspace( control_params*, storage* ); + +void Allocate_Grid( reax_system*, MPI_Comm ); +void Deallocate_Grid( grid* ); + +int Allocate_MPI_Buffers( mpi_datatypes*, int, neighbor_proc*, char* ); + +int Allocate_Matrix( sparse_matrix**, int, int, MPI_Comm ); + +int Allocate_HBond_List( int, int, int*, int*, reax_list* ); + +int Allocate_Bond_List( int, int*, reax_list* ); + +void ReAllocate( reax_system*, control_params*, simulation_data*, storage*, + reax_list**, mpi_datatypes* ); +#endif diff --git a/src/USER-REAXC/reaxc_basic_comm.cpp b/src/USER-REAXC/reaxc_basic_comm.cpp new file mode 100644 index 0000000000..16a46a03d8 --- /dev/null +++ b/src/USER-REAXC/reaxc_basic_comm.cpp @@ -0,0 +1,312 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "basic_comm.h" +#include "vector.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_basic_comm.h" +#include "reaxc_vector.h" +#endif + +#if defined(PURE_REAX) +void real_packer( void *dummy, mpi_out_data *out_buf ) +{ + int i; + real *buf = (real*) dummy; + real *out = (real*) out_buf->out_atoms; + + for( i = 0; i < out_buf->cnt; ++i ) + out[i] = buf[ out_buf->index[i] ]; +} + + +void rvec_packer( void *dummy, mpi_out_data *out_buf ) +{ + int i; + rvec *buf = (rvec*) dummy; + rvec *out = (rvec*)out_buf->out_atoms; + + for( i = 0; i < out_buf->cnt; ++i ) + memcpy( out[i], buf[ out_buf->index[i] ], sizeof(rvec) ); +} + + +void rvec2_packer( void *dummy, mpi_out_data *out_buf ) +{ + int i; + rvec2 *buf = (rvec2*) dummy; + rvec2 *out = (rvec2*) out_buf->out_atoms; + + for( i = 0; i < out_buf->cnt; ++i ) + memcpy( out[i], buf[ out_buf->index[i] ], sizeof(rvec2) ); +} + + +void Dist( reax_system* system, mpi_datatypes *mpi_data, + void *buf, MPI_Datatype type, int scale, dist_packer pack ) +{ + int d; + mpi_out_data *out_bufs; + MPI_Comm comm; + MPI_Request req1, req2; + MPI_Status stat1, stat2; + neighbor_proc *nbr1, *nbr2; + +#if defined(DEBUG) + fprintf( stderr, "p%d dist: entered\n", system->my_rank ); +#endif + comm = mpi_data->comm_mesh3D; + out_bufs = mpi_data->out_buffers; + + for( d = 0; d < 3; ++d ) { + /* initiate recvs */ + nbr1 = &(system->my_nbrs[2*d]); + if( nbr1->atoms_cnt ) + MPI_Irecv( buf + nbr1->atoms_str*scale, nbr1->atoms_cnt, type, + nbr1->rank, 2*d+1,comm, &req1 ); + + nbr2 = &(system->my_nbrs[2*d+1]); + if( nbr2->atoms_cnt ) + MPI_Irecv( buf + nbr2->atoms_str*scale, nbr2->atoms_cnt, type, + nbr2->rank, 2*d, comm, &req2 ); + + /* send both messages in dimension d */ + if( out_bufs[2*d].cnt ) { + pack( buf, out_bufs + (2*d) ); + MPI_Send( out_bufs[2*d].out_atoms, out_bufs[2*d].cnt, type, + nbr1->rank, 2*d, comm ); + } + + if( out_bufs[2*d+1].cnt ) { + pack( buf, out_bufs + (2*d+1) ); + MPI_Send( out_bufs[2*d+1].out_atoms, out_bufs[2*d+1].cnt, type, + nbr2->rank, 2*d+1, comm ); + } + + if( nbr1->atoms_cnt ) MPI_Wait( &req1, &stat1 ); + if( nbr2->atoms_cnt ) MPI_Wait( &req2, &stat2 ); + } + +#if defined(DEBUG) + fprintf( stderr, "p%d dist: done\n", system->my_rank ); +#endif +} + + +void real_unpacker( void *dummy_in, void *dummy_buf, mpi_out_data *out_buf ) +{ + int i; + real *in = (real*) dummy_in; + real *buf = (real*) dummy_buf; + + for( i = 0; i < out_buf->cnt; ++i ) + buf[ out_buf->index[i] ] += in[i]; +} + + +void rvec_unpacker( void *dummy_in, void *dummy_buf, mpi_out_data *out_buf ) +{ + int i; + rvec *in = (rvec*) dummy_in; + rvec *buf = (rvec*) dummy_buf; + + for( i = 0; i < out_buf->cnt; ++i ) { + rvec_Add( buf[ out_buf->index[i] ], in[i] ); +#if defined(DEBUG) + fprintf( stderr, "rvec_unpacker: cnt=%d i =%d index[i]=%d\n", + out_buf->cnt, i, out_buf->index[i] ); +#endif + } +} + + +void rvec2_unpacker( void *dummy_in, void *dummy_buf, mpi_out_data *out_buf ) +{ + int i; + rvec2 *in = (rvec2*) dummy_in; + rvec2 *buf = (rvec2*) dummy_buf; + + for( i = 0; i < out_buf->cnt; ++i ) { + buf[ out_buf->index[i] ][0] += in[i][0]; + buf[ out_buf->index[i] ][1] += in[i][1]; + } +} + + +void Coll( reax_system* system, mpi_datatypes *mpi_data, + void *buf, MPI_Datatype type, int scale, coll_unpacker unpack ) +{ + int d; + void *in1, *in2; + mpi_out_data *out_bufs; + MPI_Comm comm; + MPI_Request req1, req2; + MPI_Status stat1, stat2; + neighbor_proc *nbr1, *nbr2; + +#if defined(DEBUG) + fprintf( stderr, "p%d coll: entered\n", system->my_rank ); +#endif + comm = mpi_data->comm_mesh3D; + in1 = mpi_data->in1_buffer; + in2 = mpi_data->in2_buffer; + out_bufs = mpi_data->out_buffers; + + for( d = 2; d >= 0; --d ) { + /* initiate recvs */ + nbr1 = &(system->my_nbrs[2*d]); + if( out_bufs[2*d].cnt ) + MPI_Irecv(in1, out_bufs[2*d].cnt, type, nbr1->rank, 2*d+1, comm, &req1); + + nbr2 = &(system->my_nbrs[2*d+1]); + if( out_bufs[2*d+1].cnt ) + MPI_Irecv(in2, out_bufs[2*d+1].cnt, type, nbr2->rank, 2*d, comm, &req2); + + /* send both messages in dimension d */ + if( nbr1->atoms_cnt ) + MPI_Send( buf + nbr1->atoms_str*scale, nbr1->atoms_cnt, type, + nbr1->rank, 2*d, comm ); + + if( nbr2->atoms_cnt ) + MPI_Send( buf + nbr2->atoms_str*scale, nbr2->atoms_cnt, type, + nbr2->rank, 2*d+1, comm ); + +#if defined(DEBUG) + fprintf( stderr, "p%d coll[%d] nbr1: str=%d cnt=%d recv=%d\n", + system->my_rank, d, nbr1->atoms_str, nbr1->atoms_cnt, + out_bufs[2*d].cnt ); + fprintf( stderr, "p%d coll[%d] nbr2: str=%d cnt=%d recv=%d\n", + system->my_rank, d, nbr2->atoms_str, nbr2->atoms_cnt, + out_bufs[2*d+1].cnt ); +#endif + + if( out_bufs[2*d].cnt ) { + MPI_Wait( &req1, &stat1 ); + unpack( in1, buf, out_bufs + (2*d) ); + } + + if( out_bufs[2*d+1].cnt ) { + MPI_Wait( &req2, &stat2 ); + unpack( in2, buf, out_bufs + (2*d+1) ); + } + } + +#if defined(DEBUG) + fprintf( stderr, "p%d coll: done\n", system->my_rank ); +#endif +} +#endif /*PURE_REAX*/ + +/*****************************************************************************/ +real Parallel_Norm( real *v, int n, MPI_Comm comm ) +{ + int i; + real my_sum, norm_sqr; + + my_sum = 0; + for( i = 0; i < n; ++i ) + my_sum += SQR( v[i] ); + + MPI_Allreduce( &my_sum, &norm_sqr, 1, MPI_DOUBLE, MPI_SUM, comm ); + + return sqrt( norm_sqr ); +} + + + +real Parallel_Dot( real *v1, real *v2, int n, MPI_Comm comm ) +{ + int i; + real my_dot, res; + + my_dot = 0; + for( i = 0; i < n; ++i ) + my_dot += v1[i] * v2[i]; + + MPI_Allreduce( &my_dot, &res, 1, MPI_DOUBLE, MPI_SUM, comm ); + + return res; +} + + + +real Parallel_Vector_Acc( real *v, int n, MPI_Comm comm ) +{ + int i; + real my_acc, res; + + my_acc = 0; + for( i = 0; i < n; ++i ) + my_acc += v[i]; + + MPI_Allreduce( &my_acc, &res, 1, MPI_DOUBLE, MPI_SUM, comm ); + + return res; +} + + +/*****************************************************************************/ +#if defined(TEST_FORCES) +void Coll_ids_at_Master( reax_system *system, storage *workspace, + mpi_datatypes *mpi_data ) +{ + int i; + int *id_list; + + MPI_Gather( &system->n, 1, MPI_INT, workspace->rcounts, 1, MPI_INT, + MASTER_NODE, mpi_data->world ); + + if( system->my_rank == MASTER_NODE ){ + workspace->displs[0] = 0; + for( i = 1; i < system->wsize; ++i ) + workspace->displs[i] = workspace->displs[i-1] + workspace->rcounts[i-1]; + } + + id_list = (int*) malloc( system->n * sizeof(int) ); + for( i = 0; i < system->n; ++i ) + id_list[i] = system->my_atoms[i].orig_id; + + MPI_Gatherv( id_list, system->n, MPI_INT, + workspace->id_all, workspace->rcounts, workspace->displs, + MPI_INT, MASTER_NODE, mpi_data->world ); + + free( id_list ); + +#if defined(DEBUG) + if( system->my_rank == MASTER_NODE ) { + for( i = 0 ; i < system->bigN; ++i ) + fprintf( stderr, "id_all[%d]: %d\n", i, workspace->id_all[i] ); + } +#endif +} + + +void Coll_rvecs_at_Master( reax_system *system, storage *workspace, + mpi_datatypes *mpi_data, rvec* v ) +{ + MPI_Gatherv( v, system->n, mpi_data->mpi_rvec, + workspace->f_all, workspace->rcounts, workspace->displs, + mpi_data->mpi_rvec, MASTER_NODE, mpi_data->world ); +} + +#endif diff --git a/src/USER-REAXC/reaxc_basic_comm.h b/src/USER-REAXC/reaxc_basic_comm.h new file mode 100644 index 0000000000..986f95a175 --- /dev/null +++ b/src/USER-REAXC/reaxc_basic_comm.h @@ -0,0 +1,47 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __BASIC_COMM_H_ +#define __BASIC_COMM_H_ + +#include "reaxc_types.h" + +void real_packer( void*, mpi_out_data* ); +void rvec_packer( void*, mpi_out_data* ); +void rvec2_packer( void*, mpi_out_data* ); +void Dist(reax_system*, mpi_datatypes*, void*, MPI_Datatype, int, dist_packer); + +void real_unpacker( void*, void*, mpi_out_data* ); +void rvec_unpacker( void*, void*, mpi_out_data* ); +void rvec2_unpacker( void*, void*, mpi_out_data* ); +void Coll( reax_system*, mpi_datatypes*, void*, MPI_Datatype, + int, coll_unpacker ); + +real Parallel_Norm( real*, int, MPI_Comm ); +real Parallel_Dot( real*, real*, int, MPI_Comm ); +real Parallel_Vector_Acc( real*, int, MPI_Comm ); + +#if defined(TEST_FORCES) +void Coll_ids_at_Master( reax_system*, storage*, mpi_datatypes* ); +void Coll_rvecs_at_Master( reax_system*, storage*, mpi_datatypes*, rvec* ); +#endif + +#endif diff --git a/src/USER-REAXC/reaxc_bond_orders.cpp b/src/USER-REAXC/reaxc_bond_orders.cpp new file mode 100644 index 0000000000..02cee90d16 --- /dev/null +++ b/src/USER-REAXC/reaxc_bond_orders.cpp @@ -0,0 +1,1219 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "bond_orders.h" +#include "list.h" +#include "vector.h" +#include "io_tools.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_bond_orders.h" +#include "reaxc_list.h" +#include "reaxc_vector.h" +#endif + +#ifdef TEST_FORCES +void Get_dBO( reax_system *system, reax_list **lists, + int i, int pj, real C, rvec *v ) +{ + reax_list *bonds = (*lists) + BONDS; + reax_list *dBOs = (*lists) + DBOS; + int start_pj, end_pj, k; + + pj = bonds->select.bond_list[pj].dbond_index; + start_pj = Start_Index(pj, dBOs); + end_pj = End_Index(pj, dBOs); + + for( k = start_pj; k < end_pj; ++k ) + rvec_Scale( v[dBOs->select.dbo_list[k].wrt], + C, dBOs->select.dbo_list[k].dBO ); +} + + +void Get_dBOpinpi2( reax_system *system, reax_list **lists, + int i, int pj, real Cpi, real Cpi2, rvec *vpi, rvec *vpi2 ) +{ + reax_list *bonds = (*lists) + BONDS; + reax_list *dBOs = (*lists) + DBOS; + dbond_data *dbo_k; + int start_pj, end_pj, k; + + pj = bonds->select.bond_list[pj].dbond_index; + start_pj = Start_Index(pj, dBOs); + end_pj = End_Index(pj, dBOs); + + for( k = start_pj; k < end_pj; ++k ) + { + dbo_k = &(dBOs->select.dbo_list[k]); + rvec_Scale( vpi[dbo_k->wrt], Cpi, dbo_k->dBOpi ); + rvec_Scale( vpi2[dbo_k->wrt], Cpi2, dbo_k->dBOpi2 ); + } +} + + +void Add_dBO( reax_system *system, reax_list **lists, + int i, int pj, real C, rvec *v ) +{ + reax_list *bonds = (*lists) + BONDS; + reax_list *dBOs = (*lists) + DBOS; + int start_pj, end_pj, k; + + pj = bonds->select.bond_list[pj].dbond_index; + start_pj = Start_Index(pj, dBOs); + end_pj = End_Index(pj, dBOs); + //fprintf( stderr, "i=%d j=%d start=%d end=%d\n", i, pj, start_pj, end_pj ); + + for( k = start_pj; k < end_pj; ++k ) + rvec_ScaledAdd( v[dBOs->select.dbo_list[k].wrt], + C, dBOs->select.dbo_list[k].dBO ); + +} + + +void Add_dBOpinpi2( reax_system *system, reax_list **lists, + int i, int pj, real Cpi, real Cpi2, rvec *vpi, rvec *vpi2 ) +{ + reax_list *bonds = (*lists) + BONDS; + reax_list *dBOs = (*lists) + DBOS; + dbond_data *dbo_k; + int start_pj, end_pj, k; + + pj = bonds->select.bond_list[pj].dbond_index; + start_pj = Start_Index(pj, dBOs); + end_pj = End_Index(pj, dBOs); + + for( k = start_pj; k < end_pj; ++k ) + { + dbo_k = &(dBOs->select.dbo_list[k]); + rvec_ScaledAdd( vpi[dbo_k->wrt], Cpi, dbo_k->dBOpi ); + rvec_ScaledAdd( vpi2[dbo_k->wrt], Cpi2, dbo_k->dBOpi2 ); + } +} + + +void Add_dBO_to_Forces( reax_system *system, reax_list **lists, + int i, int pj, real C ) +{ + reax_list *bonds = (*lists) + BONDS; + reax_list *dBOs = (*lists) + DBOS; + int start_pj, end_pj, k; + + pj = bonds->select.bond_list[pj].dbond_index; + start_pj = Start_Index(pj, dBOs); + end_pj = End_Index(pj, dBOs); + + for( k = start_pj; k < end_pj; ++k ) + rvec_ScaledAdd( system->my_atoms[dBOs->select.dbo_list[k].wrt].f, + C, dBOs->select.dbo_list[k].dBO ); +} + + +void Add_dBOpinpi2_to_Forces( reax_system *system, reax_list **lists, + int i, int pj, real Cpi, real Cpi2 ) +{ + reax_list *bonds = (*lists) + BONDS; + reax_list *dBOs = (*lists) + DBOS; + dbond_data *dbo_k; + int start_pj, end_pj, k; + + pj = bonds->select.bond_list[pj].dbond_index; + start_pj = Start_Index(pj, dBOs); + end_pj = End_Index(pj, dBOs); + + for( k = start_pj; k < end_pj; ++k ) + { + dbo_k = &(dBOs->select.dbo_list[k]); + rvec_ScaledAdd( system->my_atoms[dbo_k->wrt].f, Cpi, dbo_k->dBOpi ); + rvec_ScaledAdd( system->my_atoms[dbo_k->wrt].f, Cpi2, dbo_k->dBOpi2 ); + } +} + + +void Add_dDelta( reax_system *system, reax_list **lists, int i, real C, rvec *v ) +{ + reax_list *dDeltas = &((*lists)[DDELTAS]); + int start = Start_Index(i, dDeltas); + int end = End_Index(i, dDeltas); + int k; + + for( k = start; k < end; ++k ) + rvec_ScaledAdd( v[dDeltas->select.dDelta_list[k].wrt], + C, dDeltas->select.dDelta_list[k].dVal ); +} + + +void Add_dDelta_to_Forces( reax_system *system, reax_list **lists, + int i, real C ) +{ + reax_list *dDeltas = &((*lists)[DDELTAS]); + int start = Start_Index(i, dDeltas); + int end = End_Index(i, dDeltas); + int k; + + for( k = start; k < end; ++k ) + rvec_ScaledAdd( system->my_atoms[dDeltas->select.dDelta_list[k].wrt].f, + C, dDeltas->select.dDelta_list[k].dVal ); +} + + + +void Calculate_dBO( int i, int pj, + storage *workspace, reax_list **lists, int *top ) +{ + /* Initializations */ + reax_list *bonds, *dBOs; + int j, k, l, start_i, end_i, end_j; + bond_data *nbr_l, *nbr_k; + bond_order_data *bo_ij; + dbond_data *top_dbo; + + // rvec due_j[1000], due_i[1000]; + // rvec due_j_pi[1000], due_i_pi[1000]; + + // memset(due_j, 0, sizeof(rvec)*1000 ); + // memset(due_i, 0, sizeof(rvec)*1000 ); + // memset(due_j_pi, 0, sizeof(rvec)*1000 ); + // memset(due_i_pi, 0, sizeof(rvec)*1000 ); + + bonds = *lists + BONDS; + dBOs = *lists + DBOS; + + start_i = Start_Index(i, bonds); + end_i = End_Index(i, bonds); + + j = bonds->select.bond_list[pj].nbr; + l = Start_Index(j, bonds); + end_j = End_Index(j, bonds); + + bo_ij = &(bonds->select.bond_list[pj].bo_data); + top_dbo = &(dBOs->select.dbo_list[ (*top) ]); + + for( k = start_i; k < end_i; ++k ) { + nbr_k = &(bonds->select.bond_list[k]); + + for( ; l < end_j && bonds->select.bond_list[l].nbr < nbr_k->nbr; ++l ) { + /* These are the neighbors of j which are not in the nbr_list of i + Note that they might also include i! */ + nbr_l = &(bonds->select.bond_list[l]); + top_dbo->wrt = nbr_l->nbr; + + //rvec_ScaledAdd( due_j[top_dbo->wrt], + // -bo_ij->BO * bo_ij->A2_ji, nbr_l->bo_data.dBOp ); + + /*3rd, dBO*/ + rvec_Scale( top_dbo->dBO, -bo_ij->C3dbo, nbr_l->bo_data.dBOp ); + /*4th, dBOpi*/ + rvec_Scale( top_dbo->dBOpi, -bo_ij->C4dbopi, nbr_l->bo_data.dBOp ); + /*4th, dBOpp*/ + rvec_Scale( top_dbo->dBOpi2, -bo_ij->C4dbopi2, nbr_l->bo_data.dBOp ); + + if( nbr_l->nbr == i ) { + /* do the adjustments on i */ + //rvec_ScaledAdd( due_i[i], bo_ij->A0_ij+bo_ij->BO*bo_ij->A1_ij, + // bo_ij->dBOp ); /*1st, dBO*/ + //rvec_ScaledAdd( due_i[i], bo_ij->BO * bo_ij->A2_ij, + // workspace->dDeltap_self[i] ); /*2nd, dBO*/ + + /*1st, dBO*/ + rvec_ScaledAdd( top_dbo->dBO, bo_ij->C1dbo, bo_ij->dBOp ); + /*2nd, dBO*/ + rvec_ScaledAdd( top_dbo->dBO, + bo_ij->C2dbo, workspace->dDeltap_self[i] ); + + /*1st, dBOpi*/ + rvec_ScaledAdd(top_dbo->dBOpi,bo_ij->C1dbopi,bo_ij->dln_BOp_pi ); + /*2nd, dBOpi*/ + rvec_ScaledAdd( top_dbo->dBOpi, bo_ij->C2dbopi, bo_ij->dBOp ); + /*3rd, dBOpi*/ + rvec_ScaledAdd( top_dbo->dBOpi, + bo_ij->C3dbopi, workspace->dDeltap_self[i] ); + + /*1st, dBO_p*/ + rvec_ScaledAdd( top_dbo->dBOpi2, + bo_ij->C1dbopi2, bo_ij->dln_BOp_pi2 ); + /*2nd, dBO_p*/ + rvec_ScaledAdd( top_dbo->dBOpi2, bo_ij->C2dbopi2, bo_ij->dBOp ); + /*3rd, dBO_p*/ + rvec_ScaledAdd( top_dbo->dBOpi2, + bo_ij->C3dbopi2, workspace->dDeltap_self[i] ); + } + + //rvec_Add( workspace->dDelta[nbr_l->nbr], top_dbo->dBO ); + ++(*top), ++top_dbo; + } + + /* Now we are processing neighbor k of i. */ + top_dbo->wrt = nbr_k->nbr; + + //2nd, dBO + //rvec_ScaledAdd( due_i[top_dbo->wrt], + // -bo_ij->BO * bo_ij->A2_ij, nbr_k->bo_data.dBOp ); + + /*2nd, dBO*/ + rvec_Scale( top_dbo->dBO, -bo_ij->C2dbo, nbr_k->bo_data.dBOp ); + /*3rd, dBOpi*/ + rvec_Scale( top_dbo->dBOpi, -bo_ij->C3dbopi, nbr_k->bo_data.dBOp ); + /*3rd, dBOpp*/ + rvec_Scale( top_dbo->dBOpi2, -bo_ij->C3dbopi2, nbr_k->bo_data.dBOp ); + + if( l < end_j && bonds->select.bond_list[l].nbr == nbr_k->nbr ) { + /* This is a common neighbor of i and j. */ + nbr_l = &(bonds->select.bond_list[l]); + + /*3rd, dBO*/ + //rvec_ScaledAdd( due_j[top_dbo->wrt], + // -bo_ij->BO * bo_ij->A2_ji, nbr_l->bo_data.dBOp ); + + /*3rd, dBO*/ + rvec_ScaledAdd( top_dbo->dBO, -bo_ij->C3dbo, nbr_l->bo_data.dBOp ); + /*4th, dBOpi*/ + rvec_ScaledAdd(top_dbo->dBOpi, -bo_ij->C4dbopi, nbr_l->bo_data.dBOp); + /*4th, dBOpp*/ + rvec_ScaledAdd(top_dbo->dBOpi2,-bo_ij->C4dbopi2,nbr_l->bo_data.dBOp); + ++l; + } + else if( k == pj ) { + /* This negihbor is j. */ + //rvec_ScaledAdd( due_j[j], -(bo_ij->A0_ij+bo_ij->BO*bo_ij->A1_ij), + // bo_ij->dBOp ); /*1st, dBO*/ + //rvec_ScaledAdd( due_j[j], bo_ij->BO * bo_ij->A2_ji, + // workspace->dDeltap_self[j] ); /*3rd, dBO*/ + + /*1st, dBO*/ + rvec_ScaledAdd( top_dbo->dBO, -bo_ij->C1dbo, bo_ij->dBOp ); + /*3rd, dBO*/ + rvec_ScaledAdd(top_dbo->dBO,bo_ij->C3dbo,workspace->dDeltap_self[j]); + + /*1st, dBOpi*/ + rvec_ScaledAdd( top_dbo->dBOpi, -bo_ij->C1dbopi, bo_ij->dln_BOp_pi ); + /*2nd, dBOpi*/ + rvec_ScaledAdd( top_dbo->dBOpi, -bo_ij->C2dbopi, bo_ij->dBOp ); + /*4th, dBOpi*/ + rvec_ScaledAdd( top_dbo->dBOpi, + bo_ij->C4dbopi, workspace->dDeltap_self[j] ); + + /*1st, dBOpi2*/ + rvec_ScaledAdd(top_dbo->dBOpi2,-bo_ij->C1dbopi2,bo_ij->dln_BOp_pi2); + /*2nd, dBOpi2*/ + rvec_ScaledAdd(top_dbo->dBOpi2,-bo_ij->C2dbopi2,bo_ij->dBOp ); + /*4th, dBOpi2*/ + rvec_ScaledAdd(top_dbo->dBOpi2, bo_ij->C4dbopi2, + workspace->dDeltap_self[j] ); + } + + // rvec_Add( workspace->dDelta[nbr_k->nbr], top_dbo->dBO ); + ++(*top), ++top_dbo; + } + + for( ; l < end_j; ++l ) { + /* These are the remaining neighbors of j which are not in the + neighbor_list of i. Note that they might also include i!*/ + nbr_l = &(bonds->select.bond_list[l]); + top_dbo->wrt = nbr_l->nbr; + + // fprintf( stdout, "\tl: %d nbr:%d\n", l, nbr_l->nbr+1 ); + + // rvec_ScaledAdd( due_j[top_dbo->wrt], + // -bo_ij->BO * bo_ij->A2_ji, nbr_l->bo_data.dBOp ); + + /*3rd, dBO*/ + rvec_Scale( top_dbo->dBO, -bo_ij->C3dbo, nbr_l->bo_data.dBOp ); + /*4th, dBOpi*/ + rvec_Scale( top_dbo->dBOpi, -bo_ij->C4dbopi, nbr_l->bo_data.dBOp ); + /*4th, dBOpp*/ + rvec_Scale( top_dbo->dBOpi2, -bo_ij->C4dbopi2, nbr_l->bo_data.dBOp ); + + if( nbr_l->nbr == i ) + { + /* do the adjustments on i */ + //rvec_ScaledAdd( due_i[i], bo_ij->A0_ij + bo_ij->BO * bo_ij->A1_ij, + // bo_ij->dBOp ); /*1st, dBO*/ + //rvec_ScaledAdd( due_i[i], bo_ij->BO * bo_ij->A2_ij, + // workspace->dDeltap_self[i] ); /*2nd, dBO*/ + + /*1st, dBO*/ + rvec_ScaledAdd( top_dbo->dBO, bo_ij->C1dbo, bo_ij->dBOp ); + /*2nd, dBO*/ + rvec_ScaledAdd(top_dbo->dBO,bo_ij->C2dbo,workspace->dDeltap_self[i]); + + /*1st, dBO_p*/ + rvec_ScaledAdd( top_dbo->dBOpi, bo_ij->C1dbopi, bo_ij->dln_BOp_pi ); + /*2nd, dBOpi*/ + rvec_ScaledAdd( top_dbo->dBOpi, bo_ij->C2dbopi, bo_ij->dBOp ); + /*3rd,dBOpi*/ + rvec_ScaledAdd( top_dbo->dBOpi, + bo_ij->C3dbopi, workspace->dDeltap_self[i] ); + + /*1st, dBO_p*/ + rvec_ScaledAdd(top_dbo->dBOpi2, bo_ij->C1dbopi2, bo_ij->dln_BOp_pi2); + /*2nd, dBO_p*/ + rvec_ScaledAdd(top_dbo->dBOpi2, bo_ij->C2dbopi2, bo_ij->dBOp); + /*3rd,dBO_p*/ + rvec_ScaledAdd(top_dbo->dBOpi2, + bo_ij->C3dbopi2, workspace->dDeltap_self[i]); + } + + // rvec_Add( workspace->dDelta[nbr_l->nbr], top_dbo->dBO ); + ++(*top), ++top_dbo; + } + + // for( k = 0; k < 21; ++k ){ + // fprintf( stderr, "%d %d %d, due_i:[%g %g %g]\n", + // i+1, j+1, k+1, due_i[k][0], due_i[k][1], due_i[k][2] ); + // fprintf( stderr, "%d %d %d, due_j:[%g %g %g]\n", + // i+1, j+1, k+1, due_j[k][0], due_j[k][1], due_j[k][2] ); +} +#endif + + + +void Add_dBond_to_Forces_NPT( int i, int pj, simulation_data *data, + storage *workspace, reax_list **lists ) +{ + reax_list *bonds = (*lists) + BONDS; + bond_data *nbr_j, *nbr_k; + bond_order_data *bo_ij, *bo_ji; + dbond_coefficients coef; + rvec temp, ext_press; + ivec rel_box; + int pk, k, j; + + /* Initializations */ + nbr_j = &(bonds->select.bond_list[pj]); + j = nbr_j->nbr; + bo_ij = &(nbr_j->bo_data); + bo_ji = &(bonds->select.bond_list[ nbr_j->sym_index ].bo_data); + + coef.C1dbo = bo_ij->C1dbo * (bo_ij->Cdbo + bo_ji->Cdbo); + coef.C2dbo = bo_ij->C2dbo * (bo_ij->Cdbo + bo_ji->Cdbo); + coef.C3dbo = bo_ij->C3dbo * (bo_ij->Cdbo + bo_ji->Cdbo); + + coef.C1dbopi = bo_ij->C1dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi); + coef.C2dbopi = bo_ij->C2dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi); + coef.C3dbopi = bo_ij->C3dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi); + coef.C4dbopi = bo_ij->C4dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi); + + coef.C1dbopi2 = bo_ij->C1dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2); + coef.C2dbopi2 = bo_ij->C2dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2); + coef.C3dbopi2 = bo_ij->C3dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2); + coef.C4dbopi2 = bo_ij->C4dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2); + + coef.C1dDelta = bo_ij->C1dbo * (workspace->CdDelta[i]+workspace->CdDelta[j]); + coef.C2dDelta = bo_ij->C2dbo * (workspace->CdDelta[i]+workspace->CdDelta[j]); + coef.C3dDelta = bo_ij->C3dbo * (workspace->CdDelta[i]+workspace->CdDelta[j]); + + + /************************************ + * forces related to atom i * + * first neighbors of atom i * + ************************************/ + for( pk = Start_Index(i, bonds); pk < End_Index(i, bonds); ++pk ) { + nbr_k = &(bonds->select.bond_list[pk]); + k = nbr_k->nbr; + + rvec_Scale(temp, -coef.C2dbo, nbr_k->bo_data.dBOp); /*2nd, dBO*/ + rvec_ScaledAdd(temp, -coef.C2dDelta, nbr_k->bo_data.dBOp);/*dDelta*/ + rvec_ScaledAdd(temp, -coef.C3dbopi, nbr_k->bo_data.dBOp); /*3rd, dBOpi*/ + rvec_ScaledAdd(temp, -coef.C3dbopi2, nbr_k->bo_data.dBOp);/*3rd, dBOpi2*/ + + /* force */ + rvec_Add( workspace->f[k], temp ); + /* pressure */ + rvec_iMultiply( ext_press, nbr_k->rel_box, temp ); + rvec_Add( data->my_ext_press, ext_press ); + + /* if( !ivec_isZero( nbr_k->rel_box ) ) + fprintf( stderr, "%3d %3d %3d: dvec[%10.6f %10.6f %10.6f]" + "ext[%3d %3d %3d] f[%10.6f %10.6f %10.6f]\n", + i+1, system->my_atoms[i].x[0], + system->my_atoms[i].x[1], system->my_atoms[i].x[2], + j+1, k+1, system->my_atoms[k].x[0], + system->my_atoms[k].x[1], system->my_atoms[k].x[2], + nbr_k->dvec[0], nbr_k->dvec[1], nbr_k->dvec[2], + nbr_k->rel_box[0], nbr_k->rel_box[1], nbr_k->rel_box[2], + temp[0], temp[1], temp[2] ); */ + } + + /* then atom i itself */ + rvec_Scale( temp, coef.C1dbo, bo_ij->dBOp ); /*1st,dBO*/ + rvec_ScaledAdd( temp, coef.C2dbo, workspace->dDeltap_self[i] ); /*2nd,dBO*/ + rvec_ScaledAdd( temp, coef.C1dDelta, bo_ij->dBOp ); /*1st,dBO*/ + rvec_ScaledAdd( temp, coef.C2dDelta, workspace->dDeltap_self[i] );/*2nd,dBO*/ + rvec_ScaledAdd( temp, coef.C1dbopi, bo_ij->dln_BOp_pi ); /*1st,dBOpi*/ + rvec_ScaledAdd( temp, coef.C2dbopi, bo_ij->dBOp ); /*2nd,dBOpi*/ + rvec_ScaledAdd( temp, coef.C3dbopi, workspace->dDeltap_self[i]);/*3rd,dBOpi*/ + + rvec_ScaledAdd( temp, coef.C1dbopi2, bo_ij->dln_BOp_pi2 ); /*1st,dBO_pi2*/ + rvec_ScaledAdd( temp, coef.C2dbopi2, bo_ij->dBOp ); /*2nd,dBO_pi2*/ + rvec_ScaledAdd( temp, coef.C3dbopi2, workspace->dDeltap_self[i] );/*3rd*/ + + /* force */ + rvec_Add( workspace->f[i], temp ); + /* ext pressure due to i is dropped, counting force on j will be enough */ + + + /****************************************************** + * forces and pressure related to atom j * + * first neighbors of atom j * + ******************************************************/ + for( pk = Start_Index(j, bonds); pk < End_Index(j, bonds); ++pk ) { + nbr_k = &(bonds->select.bond_list[pk]); + k = nbr_k->nbr; + + rvec_Scale( temp, -coef.C3dbo, nbr_k->bo_data.dBOp ); /*3rd,dBO*/ + rvec_ScaledAdd( temp, -coef.C3dDelta, nbr_k->bo_data.dBOp);/*dDelta*/ + rvec_ScaledAdd( temp, -coef.C4dbopi, nbr_k->bo_data.dBOp); /*4th,dBOpi*/ + rvec_ScaledAdd( temp, -coef.C4dbopi2, nbr_k->bo_data.dBOp);/*4th,dBOpi2*/ + + /* force */ + rvec_Add( workspace->f[k], temp ); + /* pressure */ + if( k != i ) { + ivec_Sum( rel_box, nbr_k->rel_box, nbr_j->rel_box ); //rel_box(k, i) + rvec_iMultiply( ext_press, rel_box, temp ); + rvec_Add( data->my_ext_press, ext_press ); + + /* if( !ivec_isZero( rel_box ) ) + fprintf( stderr, "%3d %3d %3d: dvec[%10.6f %10.6f %10.6f]" + "ext[%3d %3d %3d] f[%10.6f %10.6f %10.6f]\n", + i+1, j+1, system->my_atoms[j].x[0], + system->my_atoms[j].x[1], system->my_atoms[j].x[2], + k+1, system->my_atoms[k].x[0], + system->my_atoms[k].x[1], system->my_atoms[k].x[2], + nbr_k->dvec[0], nbr_k->dvec[1], nbr_k->dvec[2], + rel_box[0], rel_box[1], rel_box[2], + temp[0], temp[1], temp[2] ); */ + } + } + + /* then atom j itself */ + rvec_Scale( temp, -coef.C1dbo, bo_ij->dBOp ); /*1st, dBO*/ + rvec_ScaledAdd( temp, coef.C3dbo, workspace->dDeltap_self[j] ); /*2nd, dBO*/ + rvec_ScaledAdd( temp, -coef.C1dDelta, bo_ij->dBOp ); /*1st, dBO*/ + rvec_ScaledAdd( temp, coef.C3dDelta, workspace->dDeltap_self[j]);/*2nd, dBO*/ + + rvec_ScaledAdd( temp, -coef.C1dbopi, bo_ij->dln_BOp_pi ); /*1st,dBOpi*/ + rvec_ScaledAdd( temp, -coef.C2dbopi, bo_ij->dBOp ); /*2nd,dBOpi*/ + rvec_ScaledAdd( temp, coef.C4dbopi, workspace->dDeltap_self[j]);/*3rd,dBOpi*/ + + rvec_ScaledAdd( temp, -coef.C1dbopi2, bo_ij->dln_BOp_pi2 ); /*1st,dBOpi2*/ + rvec_ScaledAdd( temp, -coef.C2dbopi2, bo_ij->dBOp ); /*2nd,dBOpi2*/ + rvec_ScaledAdd( temp,coef.C4dbopi2,workspace->dDeltap_self[j]);/*3rd,dBOpi2*/ + + /* force */ + rvec_Add( workspace->f[j], temp ); + /* pressure */ + rvec_iMultiply( ext_press, nbr_j->rel_box, temp ); + rvec_Add( data->my_ext_press, ext_press ); + + /* if( !ivec_isZero( nbr_j->rel_box ) ) + fprintf( stderr, "%3d %3d %3d: dvec[%10.6f %10.6f %10.6f]" + "ext[%3d %3d %3d] f[%10.6f %10.6f %10.6f]\n", + i+1, system->my_atoms[i].x[0], system->my_atoms[i].x[1], + system->my_atoms[i].x[2], + j+1,system->my_atoms[j].x[0], system->my_atoms[j].x[1], + system->my_atoms[j].x[2], + j+1, nbr_j->dvec[0], nbr_j->dvec[1], nbr_j->dvec[2], + nbr_j->rel_box[0], nbr_j->rel_box[1], nbr_j->rel_box[2], + temp[0], temp[1], temp[2] ); */ +} + + + +void Add_dBond_to_Forces( int i, int pj, + storage *workspace, reax_list **lists ) +{ + reax_list *bonds = (*lists) + BONDS; + bond_data *nbr_j, *nbr_k; + bond_order_data *bo_ij, *bo_ji; + dbond_coefficients coef; + int pk, k, j; + + /* Initializations */ + nbr_j = &(bonds->select.bond_list[pj]); + j = nbr_j->nbr; + bo_ij = &(nbr_j->bo_data); + bo_ji = &(bonds->select.bond_list[ nbr_j->sym_index ].bo_data); + + coef.C1dbo = bo_ij->C1dbo * (bo_ij->Cdbo + bo_ji->Cdbo); + coef.C2dbo = bo_ij->C2dbo * (bo_ij->Cdbo + bo_ji->Cdbo); + coef.C3dbo = bo_ij->C3dbo * (bo_ij->Cdbo + bo_ji->Cdbo); + + coef.C1dbopi = bo_ij->C1dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi); + coef.C2dbopi = bo_ij->C2dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi); + coef.C3dbopi = bo_ij->C3dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi); + coef.C4dbopi = bo_ij->C4dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi); + + coef.C1dbopi2 = bo_ij->C1dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2); + coef.C2dbopi2 = bo_ij->C2dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2); + coef.C3dbopi2 = bo_ij->C3dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2); + coef.C4dbopi2 = bo_ij->C4dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2); + + coef.C1dDelta = bo_ij->C1dbo * (workspace->CdDelta[i]+workspace->CdDelta[j]); + coef.C2dDelta = bo_ij->C2dbo * (workspace->CdDelta[i]+workspace->CdDelta[j]); + coef.C3dDelta = bo_ij->C3dbo * (workspace->CdDelta[i]+workspace->CdDelta[j]); + + for( pk = Start_Index(i, bonds); pk < End_Index(i, bonds); ++pk ) { + nbr_k = &(bonds->select.bond_list[pk]); + k = nbr_k->nbr; + + /*2nd,dBO*/ + rvec_ScaledAdd( workspace->f[k], -coef.C2dbo, nbr_k->bo_data.dBOp ); + /*dDelta*/ + rvec_ScaledAdd( workspace->f[k], -coef.C2dDelta, nbr_k->bo_data.dBOp ); + /*3rd, dBOpi*/ + rvec_ScaledAdd( workspace->f[k], -coef.C3dbopi, nbr_k->bo_data.dBOp ); + /*3rd, dBOpi2*/ + rvec_ScaledAdd( workspace->f[k], -coef.C3dbopi2, nbr_k->bo_data.dBOp ); + } + + /*1st, dBO*/ + rvec_ScaledAdd( workspace->f[i], coef.C1dbo, bo_ij->dBOp ); + /*2nd, dBO*/ + rvec_ScaledAdd( workspace->f[i], coef.C2dbo, workspace->dDeltap_self[i] ); + + /*1st, dBO*/ + rvec_ScaledAdd( workspace->f[i], coef.C1dDelta, bo_ij->dBOp ); + /*2nd, dBO*/ + rvec_ScaledAdd( workspace->f[i], coef.C2dDelta, workspace->dDeltap_self[i] ); + + /*1st, dBOpi*/ + rvec_ScaledAdd( workspace->f[i], coef.C1dbopi, bo_ij->dln_BOp_pi ); + /*2nd, dBOpi*/ + rvec_ScaledAdd( workspace->f[i], coef.C2dbopi, bo_ij->dBOp ); + /*3rd, dBOpi*/ + rvec_ScaledAdd( workspace->f[i], coef.C3dbopi, workspace->dDeltap_self[i] ); + + /*1st, dBO_pi2*/ + rvec_ScaledAdd( workspace->f[i], coef.C1dbopi2, bo_ij->dln_BOp_pi2 ); + /*2nd, dBO_pi2*/ + rvec_ScaledAdd( workspace->f[i], coef.C2dbopi2, bo_ij->dBOp ); + /*3rd, dBO_pi2*/ + rvec_ScaledAdd( workspace->f[i], coef.C3dbopi2, workspace->dDeltap_self[i] ); + + + for( pk = Start_Index(j, bonds); pk < End_Index(j, bonds); ++pk ) { + nbr_k = &(bonds->select.bond_list[pk]); + k = nbr_k->nbr; + + /*3rd, dBO*/ + rvec_ScaledAdd( workspace->f[k], -coef.C3dbo, nbr_k->bo_data.dBOp ); + /*dDelta*/ + rvec_ScaledAdd( workspace->f[k], -coef.C3dDelta, nbr_k->bo_data.dBOp ); + /*4th, dBOpi*/ + rvec_ScaledAdd( workspace->f[k], -coef.C4dbopi, nbr_k->bo_data.dBOp ); + /*4th, dBOpi2*/ + rvec_ScaledAdd( workspace->f[k], -coef.C4dbopi2, nbr_k->bo_data.dBOp ); + } + + /*1st,dBO*/ + rvec_ScaledAdd( workspace->f[j], -coef.C1dbo, bo_ij->dBOp ); + /*2nd,dBO*/ + rvec_ScaledAdd( workspace->f[j], coef.C3dbo, workspace->dDeltap_self[j] ); + + /*1st, dBO*/ + rvec_ScaledAdd( workspace->f[j], -coef.C1dDelta, bo_ij->dBOp ); + /*2nd, dBO*/ + rvec_ScaledAdd( workspace->f[j], coef.C3dDelta, workspace->dDeltap_self[j] ); + + /*1st, dBOpi*/ + rvec_ScaledAdd( workspace->f[j], -coef.C1dbopi, bo_ij->dln_BOp_pi ); + /*2nd, dBOpi*/ + rvec_ScaledAdd( workspace->f[j], -coef.C2dbopi, bo_ij->dBOp ); + /*3rd, dBOpi*/ + rvec_ScaledAdd( workspace->f[j], coef.C4dbopi, workspace->dDeltap_self[j] ); + + /*1st, dBOpi2*/ + rvec_ScaledAdd( workspace->f[j], -coef.C1dbopi2, bo_ij->dln_BOp_pi2 ); + /*2nd, dBOpi2*/ + rvec_ScaledAdd( workspace->f[j], -coef.C2dbopi2, bo_ij->dBOp ); + /*3rd, dBOpi2*/ + rvec_ScaledAdd( workspace->f[j], coef.C4dbopi2, workspace->dDeltap_self[j] ); +} + + +int BOp( storage *workspace, reax_list *bonds, real bo_cut, + int i, int btop_i, far_neighbor_data *nbr_pj, + single_body_parameters *sbp_i, single_body_parameters *sbp_j, + two_body_parameters *twbp ) { + int j, btop_j; + real r2, C12, C34, C56; + real Cln_BOp_s, Cln_BOp_pi, Cln_BOp_pi2; + real BO, BO_s, BO_pi, BO_pi2; + bond_data *ibond, *jbond; + bond_order_data *bo_ij, *bo_ji; + + j = nbr_pj->nbr; + r2 = SQR(nbr_pj->d); + + if( sbp_i->r_s > 0.0 && sbp_j->r_s > 0.0 ) { + C12 = twbp->p_bo1 * pow( nbr_pj->d / twbp->r_s, twbp->p_bo2 ); + BO_s = (1.0 + bo_cut) * exp( C12 ); + } + else BO_s = C12 = 0.0; + + if( sbp_i->r_pi > 0.0 && sbp_j->r_pi > 0.0 ) { + C34 = twbp->p_bo3 * pow( nbr_pj->d / twbp->r_p, twbp->p_bo4 ); + BO_pi = exp( C34 ); + } + else BO_pi = C34 = 0.0; + + if( sbp_i->r_pi_pi > 0.0 && sbp_j->r_pi_pi > 0.0 ) { + C56 = twbp->p_bo5 * pow( nbr_pj->d / twbp->r_pp, twbp->p_bo6 ); + BO_pi2= exp( C56 ); + } + else BO_pi2 = C56 = 0.0; + + /* Initially BO values are the uncorrected ones, page 1 */ + BO = BO_s + BO_pi + BO_pi2; + + if( BO >= bo_cut ) { + /****** bonds i-j and j-i ******/ + ibond = &( bonds->select.bond_list[btop_i] ); + btop_j = End_Index( j, bonds ); + jbond = &(bonds->select.bond_list[btop_j]); + + ibond->nbr = j; + jbond->nbr = i; + ibond->d = nbr_pj->d; + jbond->d = nbr_pj->d; + rvec_Copy( ibond->dvec, nbr_pj->dvec ); + rvec_Scale( jbond->dvec, -1, nbr_pj->dvec ); + ivec_Copy( ibond->rel_box, nbr_pj->rel_box ); + ivec_Scale( jbond->rel_box, -1, nbr_pj->rel_box ); + ibond->dbond_index = btop_i; + jbond->dbond_index = btop_i; + ibond->sym_index = btop_j; + jbond->sym_index = btop_i; + Set_End_Index( j, btop_j+1, bonds ); + + bo_ij = &( ibond->bo_data ); + bo_ji = &( jbond->bo_data ); + bo_ji->BO = bo_ij->BO = BO; + bo_ji->BO_s = bo_ij->BO_s = BO_s; + bo_ji->BO_pi = bo_ij->BO_pi = BO_pi; + bo_ji->BO_pi2 = bo_ij->BO_pi2 = BO_pi2; + + /* Bond Order page2-3, derivative of total bond order prime */ + Cln_BOp_s = twbp->p_bo2 * C12 / r2; + Cln_BOp_pi = twbp->p_bo4 * C34 / r2; + Cln_BOp_pi2 = twbp->p_bo6 * C56 / r2; + + /* Only dln_BOp_xx wrt. dr_i is stored here, note that + dln_BOp_xx/dr_i = -dln_BOp_xx/dr_j and all others are 0 */ + rvec_Scale(bo_ij->dln_BOp_s,-bo_ij->BO_s*Cln_BOp_s,ibond->dvec); + rvec_Scale(bo_ij->dln_BOp_pi,-bo_ij->BO_pi*Cln_BOp_pi,ibond->dvec); + rvec_Scale(bo_ij->dln_BOp_pi2, + -bo_ij->BO_pi2*Cln_BOp_pi2,ibond->dvec); + rvec_Scale(bo_ji->dln_BOp_s, -1., bo_ij->dln_BOp_s); + rvec_Scale(bo_ji->dln_BOp_pi, -1., bo_ij->dln_BOp_pi ); + rvec_Scale(bo_ji->dln_BOp_pi2, -1., bo_ij->dln_BOp_pi2 ); + + /* Only dBOp wrt. dr_i is stored here, note that + dBOp/dr_i = -dBOp/dr_j and all others are 0 */ + rvec_Scale( bo_ij->dBOp, + -(bo_ij->BO_s * Cln_BOp_s + + bo_ij->BO_pi * Cln_BOp_pi + + bo_ij->BO_pi2 * Cln_BOp_pi2), ibond->dvec ); + rvec_Scale( bo_ji->dBOp, -1., bo_ij->dBOp ); + + rvec_Add( workspace->dDeltap_self[i], bo_ij->dBOp ); + rvec_Add( workspace->dDeltap_self[j], bo_ji->dBOp ); + + bo_ij->BO_s -= bo_cut; + bo_ij->BO -= bo_cut; + bo_ji->BO_s -= bo_cut; + bo_ji->BO -= bo_cut; + workspace->total_bond_order[i] += bo_ij->BO; //currently total_BOp + workspace->total_bond_order[j] += bo_ji->BO; //currently total_BOp + bo_ij->Cdbo = bo_ij->Cdbopi = bo_ij->Cdbopi2 = 0.0; + bo_ji->Cdbo = bo_ji->Cdbopi = bo_ji->Cdbopi2 = 0.0; + + /*fprintf( stderr, "%d %d %g %g %g\n", + i+1, j+1, bo_ij->BO, bo_ij->BO_pi, bo_ij->BO_pi2 );*/ + + /*fprintf( stderr, "Cln_BOp_s: %f, pbo2: %f, C12:%f\n", + Cln_BOp_s, twbp->p_bo2, C12 ); + fprintf( stderr, "Cln_BOp_pi: %f, pbo4: %f, C34:%f\n", + Cln_BOp_pi, twbp->p_bo4, C34 ); + fprintf( stderr, "Cln_BOp_pi2: %f, pbo6: %f, C56:%f\n", + Cln_BOp_pi2, twbp->p_bo6, C56 );*/ + /*fprintf(stderr, "pbo1: %f, pbo2:%f\n", twbp->p_bo1, twbp->p_bo2); + fprintf(stderr, "pbo3: %f, pbo4:%f\n", twbp->p_bo3, twbp->p_bo4); + fprintf(stderr, "pbo5: %f, pbo6:%f\n", twbp->p_bo5, twbp->p_bo6); + fprintf( stderr, "r_s: %f, r_p: %f, r_pp: %f\n", + twbp->r_s, twbp->r_p, twbp->r_pp ); + fprintf( stderr, "C12: %g, C34:%g, C56:%g\n", C12, C34, C56 );*/ + + /*fprintf( stderr, "\tfactors: %g %g %g\n", + -(bo_ij->BO_s * Cln_BOp_s + bo_ij->BO_pi * Cln_BOp_pi + + bo_ij->BO_pi2 * Cln_BOp_pp), + -bo_ij->BO_pi * Cln_BOp_pi, -bo_ij->BO_pi2 * Cln_BOp_pi2 );*/ + /*fprintf( stderr, "dBOpi:\t[%g, %g, %g]\n", + bo_ij->dBOp[0], bo_ij->dBOp[1], bo_ij->dBOp[2] ); + fprintf( stderr, "dBOpi:\t[%g, %g, %g]\n", + bo_ij->dln_BOp_pi[0], bo_ij->dln_BOp_pi[1], + bo_ij->dln_BOp_pi[2] ); + fprintf( stderr, "dBOpi2:\t[%g, %g, %g]\n\n", + bo_ij->dln_BOp_pi2[0], bo_ij->dln_BOp_pi2[1], + bo_ij->dln_BOp_pi2[2] );*/ + + return 1; + } + + return 0; +} + + +int compare_bonds( const void *p1, const void *p2 ) +{ + return ((bond_data *)p1)->nbr - ((bond_data *)p2)->nbr; +} + + +void BO( reax_system *system, control_params *control, simulation_data *data, + storage *workspace, reax_list **lists, output_controls *out_control ) +{ + int i, j, pj, type_i, type_j; + int start_i, end_i, sym_index, num_bonds; + real val_i, Deltap_i, Deltap_boc_i; + real val_j, Deltap_j, Deltap_boc_j; + real f1, f2, f3, f4, f5, f4f5, exp_f4, exp_f5; + real exp_p1i, exp_p2i, exp_p1j, exp_p2j; + real temp, u1_ij, u1_ji, Cf1A_ij, Cf1B_ij, Cf1_ij, Cf1_ji; + real Cf45_ij, Cf45_ji, p_lp1; //u_ij, u_ji + real A0_ij, A1_ij, A2_ij, A2_ji, A3_ij, A3_ji; + real explp1, p_boc1, p_boc2; + single_body_parameters *sbp_i, *sbp_j; + two_body_parameters *twbp; + bond_order_data *bo_ij, *bo_ji; + reax_list *bonds = (*lists) + BONDS; +#ifdef TEST_FORCES + int k, pk, start_j, end_j; + int top_dbo, top_dDelta; + dbond_data *pdbo; + dDelta_data *ptop_dDelta; + reax_list *dDeltas, *dBOs; + top_dbo=0; + top_dDelta=0; + dDeltas = (*lists) + DDELTAS; + dBOs = (*lists) + DBOS; + + //for( i = 0; i < system->N; ++i ) + // qsort( &(bonds->select.bond_list[Start_Index(i, bonds)]), + // Num_Entries(i, bonds), sizeof(bond_data), compare_bonds ); +#endif + + num_bonds = 0; + p_boc1 = system->reax_param.gp.l[0]; + p_boc2 = system->reax_param.gp.l[1]; + + /* Calculate Deltaprime, Deltaprime_boc values */ + for( i = 0; i < system->N; ++i ) { + type_i = system->my_atoms[i].type; + sbp_i = &(system->reax_param.sbp[type_i]); + workspace->Deltap[i] = workspace->total_bond_order[i] - sbp_i->valency; + workspace->Deltap_boc[i] = + workspace->total_bond_order[i] - sbp_i->valency_val; + + //fprintf( stdout, "%d(%d) %24.15f\n", + // i, workspace->bond_mark[i], workspace->total_bond_order[i] ); + workspace->total_bond_order[i] = 0; + } + // fprintf( stderr, "done with uncorrected bond orders\n" ); + + /* Corrected Bond Order calculations */ + for( i = 0; i < system->N; ++i ) { + type_i = system->my_atoms[i].type; + sbp_i = &(system->reax_param.sbp[type_i]); + val_i = sbp_i->valency; + Deltap_i = workspace->Deltap[i]; + Deltap_boc_i = workspace->Deltap_boc[i]; + start_i = Start_Index(i, bonds); + end_i = End_Index(i, bonds); + // fprintf( stderr, "i:%d Dp:%g Dbocp:%g s:%d e:%d\n", + // i+1, Deltap_i, Deltap_boc_i, start_i, end_i ); + + for( pj = start_i; pj < end_i; ++pj ) { + j = bonds->select.bond_list[pj].nbr; + type_j = system->my_atoms[j].type; + bo_ij = &( bonds->select.bond_list[pj].bo_data ); + // fprintf( stderr, "\tj:%d - ubo: %8.3f\n", j+1, bo_ij->BO ); + + if( i < j || workspace->bond_mark[j] > 3 ) { + twbp = &( system->reax_param.tbp[type_i][type_j] ); +#ifdef TEST_FORCES + Set_Start_Index( pj, top_dbo, dBOs ); + /* fprintf( stderr, "%6d%6d%12.6f%12.6f%12.6f\n", + workspace->reverse_map[i], workspace->reverse_map[j], + twbp->ovc, twbp->v13cor, bo_ij->BO ); */ +#endif + + if( twbp->ovc < 0.001 && twbp->v13cor < 0.001 ) { + /* There is no correction to bond orders nor to derivatives + of bond order prime! So we leave bond orders unchanged and + set derivative of bond order coefficients such that + dBO = dBOp & dBOxx = dBOxxp in Add_dBO_to_Forces */ + bo_ij->C1dbo = 1.000000; + bo_ij->C2dbo = 0.000000; + bo_ij->C3dbo = 0.000000; + + bo_ij->C1dbopi = bo_ij->BO_pi; + bo_ij->C2dbopi = 0.000000; + bo_ij->C3dbopi = 0.000000; + bo_ij->C4dbopi = 0.000000; + + bo_ij->C1dbopi2 = bo_ij->BO_pi2; + bo_ij->C2dbopi2 = 0.000000; + bo_ij->C3dbopi2 = 0.000000; + bo_ij->C4dbopi2 = 0.000000; + +#ifdef TEST_FORCES + pdbo = &(dBOs->select.dbo_list[ top_dbo ]); + + // compute dBO_ij/dr_i + pdbo->wrt = i; + rvec_Copy( pdbo->dBO, bo_ij->dBOp ); + rvec_Scale( pdbo->dBOpi, bo_ij->BO_pi, bo_ij->dln_BOp_pi ); + rvec_Scale( pdbo->dBOpi2, bo_ij->BO_pi2, bo_ij->dln_BOp_pi2); + + // compute dBO_ij/dr_j + pdbo++; + pdbo->wrt = j; + rvec_Scale( pdbo->dBO, -1.0, bo_ij->dBOp ); + rvec_Scale( pdbo->dBOpi, -bo_ij->BO_pi, bo_ij->dln_BOp_pi ); + rvec_Scale(pdbo->dBOpi2, -bo_ij->BO_pi2, bo_ij->dln_BOp_pi2); + + top_dbo += 2; +#endif + } + else { + val_j = system->reax_param.sbp[type_j].valency; + Deltap_j = workspace->Deltap[j]; + Deltap_boc_j = workspace->Deltap_boc[j]; + + /* on page 1 */ + if( twbp->ovc >= 0.001 ) { + /* Correction for overcoordination */ + exp_p1i = exp( -p_boc1 * Deltap_i ); + exp_p2i = exp( -p_boc2 * Deltap_i ); + exp_p1j = exp( -p_boc1 * Deltap_j ); + exp_p2j = exp( -p_boc2 * Deltap_j ); + + f2 = exp_p1i + exp_p1j; + f3 = -1.0 / p_boc2 * log( 0.5 * ( exp_p2i + exp_p2j ) ); + f1 = 0.5 * ( ( val_i + f2 )/( val_i + f2 + f3 ) + + ( val_j + f2 )/( val_j + f2 + f3 ) ); + + /*fprintf( stderr,"%d %d\t%g %g j:%g %g p_boc:%g %g\n" + "\tf:%g %g %g, exp:%g %g %g %g\n", + i+1, j+1, + val_i, Deltap_i, val_j, Deltap_j, p_boc1, p_boc2, + f1, f2, f3, exp_p1i, exp_p2i, exp_p1j, exp_p2j );*/ + + /* Now come the derivates */ + /* Bond Order pages 5-7, derivative of f1 */ + temp = f2 + f3; + u1_ij = val_i + temp; + u1_ji = val_j + temp; + Cf1A_ij = 0.5 * f3 * (1.0 / SQR( u1_ij ) + + 1.0 / SQR( u1_ji )); + Cf1B_ij = -0.5 * (( u1_ij - f3 ) / SQR( u1_ij ) + + ( u1_ji - f3 ) / SQR( u1_ji )); + + //Cf1_ij = -Cf1A_ij * p_boc1 * exp_p1i + + // Cf1B_ij * exp_p2i / ( exp_p2i + exp_p2j ); + Cf1_ij = 0.50 * ( -p_boc1 * exp_p1i / u1_ij - + ((val_i+f2) / SQR(u1_ij)) * + ( -p_boc1 * exp_p1i + + exp_p2i / ( exp_p2i + exp_p2j ) ) + + -p_boc1 * exp_p1i / u1_ji - + ((val_j+f2) / SQR(u1_ji)) * + ( -p_boc1 * exp_p1i + + exp_p2i / ( exp_p2i + exp_p2j ) )); + + + Cf1_ji = -Cf1A_ij * p_boc1 * exp_p1j + + Cf1B_ij * exp_p2j / ( exp_p2i + exp_p2j ); + + //fprintf( stderr, "\tCf1:%g %g\n", Cf1_ij, Cf1_ji ); + } + else { + /* No overcoordination correction! */ + f1 = 1.0; + Cf1_ij = Cf1_ji = 0.0; + } + + if( twbp->v13cor >= 0.001 ) { + /* Correction for 1-3 bond orders */ + exp_f4 =exp(-(twbp->p_boc4 * SQR( bo_ij->BO ) - + Deltap_boc_i) * twbp->p_boc3 + twbp->p_boc5); + exp_f5 =exp(-(twbp->p_boc4 * SQR( bo_ij->BO ) - + Deltap_boc_j) * twbp->p_boc3 + twbp->p_boc5); + + f4 = 1. / (1. + exp_f4); + f5 = 1. / (1. + exp_f5); + f4f5 = f4 * f5; + + /* Bond Order pages 8-9, derivative of f4 and f5 */ + /*temp = twbp->p_boc5 - + twbp->p_boc3 * twbp->p_boc4 * SQR( bo_ij->BO ); + u_ij = temp + twbp->p_boc3 * Deltap_boc_i; + u_ji = temp + twbp->p_boc3 * Deltap_boc_j; + Cf45_ij = Cf45( u_ij, u_ji ) / f4f5; + Cf45_ji = Cf45( u_ji, u_ij ) / f4f5;*/ + Cf45_ij = -f4 * exp_f4; + Cf45_ji = -f5 * exp_f5; + } + else { + f4 = f5 = f4f5 = 1.0; + Cf45_ij = Cf45_ji = 0.0; + } + + /* Bond Order page 10, derivative of total bond order */ + A0_ij = f1 * f4f5; + A1_ij = -2 * twbp->p_boc3 * twbp->p_boc4 * bo_ij->BO * + (Cf45_ij + Cf45_ji); + A2_ij = Cf1_ij / f1 + twbp->p_boc3 * Cf45_ij; + A2_ji = Cf1_ji / f1 + twbp->p_boc3 * Cf45_ji; + A3_ij = A2_ij + Cf1_ij / f1; + A3_ji = A2_ji + Cf1_ji / f1; + + /*fprintf( stderr, "\tBO: %f, A0: %f, A1: %f" + "A2_ij: %f A2_ji: %f, A3_ij: %f, A3_ji: %f\n", + bo_ij->BO, + A0_ij, A1_ij, A2_ij, A2_ji, A3_ij, A3_ji );*/ + + + /* find corrected bond orders and their derivative coef */ + bo_ij->BO = bo_ij->BO * A0_ij; + bo_ij->BO_pi = bo_ij->BO_pi * A0_ij *f1; + bo_ij->BO_pi2= bo_ij->BO_pi2* A0_ij *f1; + bo_ij->BO_s = bo_ij->BO - ( bo_ij->BO_pi + bo_ij->BO_pi2 ); + + bo_ij->C1dbo = A0_ij + bo_ij->BO * A1_ij; + bo_ij->C2dbo = bo_ij->BO * A2_ij; + bo_ij->C3dbo = bo_ij->BO * A2_ji; + + bo_ij->C1dbopi = f1*f1*f4*f5; + bo_ij->C2dbopi = bo_ij->BO_pi * A1_ij; + bo_ij->C3dbopi = bo_ij->BO_pi * A3_ij; + bo_ij->C4dbopi = bo_ij->BO_pi * A3_ji; + + bo_ij->C1dbopi2 = f1*f1*f4*f5; + bo_ij->C2dbopi2 = bo_ij->BO_pi2 * A1_ij; + bo_ij->C3dbopi2 = bo_ij->BO_pi2 * A3_ij; + bo_ij->C4dbopi2 = bo_ij->BO_pi2 * A3_ji; + +#ifdef TEST_FORCES + Calculate_dBO( i, pj, workspace, lists, &top_dbo ); +#endif + } + + /* neglect bonds that are < 1e-10 */ + if( bo_ij->BO < 1e-10 ) + bo_ij->BO = 0.0; + if( bo_ij->BO_s < 1e-10 ) + bo_ij->BO_s = 0.0; + if( bo_ij->BO_pi < 1e-10 ) + bo_ij->BO_pi = 0.0; + if( bo_ij->BO_pi2 < 1e-10 ) + bo_ij->BO_pi2 = 0.0; + + workspace->total_bond_order[i] += bo_ij->BO; //now keeps total_BO + + + /* fprintf( stderr, "%d %d\t%g %g %g %g\n" + "Cdbo:\t%g %g %g\n" + "Cdbopi:\t%g %g %g %g\n" + "Cdbopi2:%g %g %g %g\n\n", + i+1, j+1, + bonds->select.bond_list[ pj ].d, + bo_ij->BO,bo_ij->BO_pi, bo_ij->BO_pi2, + bo_ij->C1dbo, bo_ij->C2dbo, bo_ij->C3dbo, + bo_ij->C1dbopi, bo_ij->C2dbopi, + bo_ij->C3dbopi, bo_ij->C4dbopi, + bo_ij->C1dbopi2,bo_ij->C2dbopi2, + bo_ij->C3dbopi2, bo_ij->C4dbopi2 ); */ + + /* fprintf( stderr, "%d %d BO:%f BO_s:%f BO_pi:%f BO_pi2:%f\n", + i+1,j+1,bo_ij->BO,bo_ij->BO_s,bo_ij->BO_pi,bo_ij->BO_pi2 );*/ + +#ifdef TEST_FORCES + Set_End_Index( pj, top_dbo, dBOs ); + Add_dBO( system, lists, i, pj, 1.0, workspace->dDelta ); +#endif + } + else { + /* We only need to update bond orders from bo_ji + everything else is set in uncorrected_bo calculations */ + sym_index = bonds->select.bond_list[pj].sym_index; + bo_ji = &(bonds->select.bond_list[ sym_index ].bo_data); + bo_ij->BO = bo_ji->BO; + bo_ij->BO_s = bo_ji->BO_s; + bo_ij->BO_pi = bo_ji->BO_pi; + bo_ij->BO_pi2 = bo_ji->BO_pi2; + + workspace->total_bond_order[i] += bo_ij->BO;// now keeps total_BO +#ifdef TEST_FORCES + Add_dBO( system, lists, j, sym_index, 1.0, workspace->dDelta ); +#endif + } + } + +#ifdef TEST_FORCES + // fprintf( stderr, "dDelta computations\nj:" ); + Set_Start_Index( i, top_dDelta, dDeltas ); + ptop_dDelta = &( dDeltas->select.dDelta_list[top_dDelta] ); + + for( pj = start_i; pj < end_i; ++pj ) { + j = bonds->select.bond_list[pj].nbr; + // fprintf( stderr, "%d ", j ); + + if( !rvec_isZero( workspace->dDelta[j] ) ) { + ptop_dDelta->wrt = j; + rvec_Copy( ptop_dDelta->dVal, workspace->dDelta[j] ); + rvec_MakeZero( workspace->dDelta[j] ); + ++top_dDelta, ++ptop_dDelta; + } + + start_j = Start_Index(j, bonds); + end_j = End_Index(j, bonds); + for( pk = start_j; pk < end_j; ++pk ) { + k = bonds->select.bond_list[pk].nbr; + if( !rvec_isZero( workspace->dDelta[k] ) ) { + ptop_dDelta->wrt = k; + rvec_Copy( ptop_dDelta->dVal, workspace->dDelta[k] ); + rvec_MakeZero( workspace->dDelta[k] ); + ++top_dDelta, ++ptop_dDelta; + } + } + } + + Set_End_Index( i, top_dDelta, dDeltas ); + + /*for(pj = Start_Index(i,dDeltas); pj < End_Index(i,dDeltas); ++pj) + fprintf( stdout, "dDel: %d %d [%g %g %g]\n", + i+1, dDeltas->select.dDelta_list[pj].wrt+1, + dDeltas->select.dDelta_list[pj].dVal[0], + dDeltas->select.dDelta_list[pj].dVal[1], + dDeltas->select.dDelta_list[pj].dVal[2] );*/ +#endif + } + + /* fprintf( stderr, "\tCalculated actual bond orders ...\n" ); + fprintf( stderr, "j\tDelta\tDelta_e\tDelta_boc\tnlp" + "\tDelta_lp\tClp\tdDelta_lp\n" ); + fprintf( stderr, "Atom\tDelta\t\tDelta_e\t\tDelta_boc\tnlp" + "\t\tnlp_opt\t\tDelta_lp\tClp\t\tdDelta_lp\n" );*/ + + p_lp1 = system->reax_param.gp.l[15]; + /* Calculate some helper variables that are used at many places + throughout force calculations */ + for( j = 0; j < system->N; ++j ){ + type_j = system->my_atoms[j].type; + sbp_j = &(system->reax_param.sbp[ type_j ]); + + workspace->Delta[j] = workspace->total_bond_order[j] - sbp_j->valency; + workspace->Delta_e[j] = workspace->total_bond_order[j] - sbp_j->valency_e; + workspace->Delta_boc[j] = workspace->total_bond_order[j] - + sbp_j->valency_boc; + + workspace->vlpex[j] = workspace->Delta_e[j] - + 2.0 * (int)(workspace->Delta_e[j]/2.0); + explp1 = exp(-p_lp1 * SQR(2.0 + workspace->vlpex[j])); + workspace->nlp[j] = explp1 - (int)(workspace->Delta_e[j] / 2.0); + workspace->Delta_lp[j] = sbp_j->nlp_opt - workspace->nlp[j]; + workspace->Clp[j] = 2.0 * p_lp1 * explp1 * (2.0 + workspace->vlpex[j]); + /* Adri uses different dDelta_lp values than the ones in notes... */ + workspace->dDelta_lp[j] = workspace->Clp[j]; + //workspace->dDelta_lp[j] = workspace->Clp[j] + (0.5-workspace->Clp[j]) * + //((fabs(workspace->Delta_e[j]/2.0 - + // (int)(workspace->Delta_e[j]/2.0)) < 0.1) ? 1 : 0 ); + + if( sbp_j->mass > 21.0 ) { + workspace->nlp_temp[j] = 0.5 * (sbp_j->valency_e - sbp_j->valency); + workspace->Delta_lp_temp[j] = sbp_j->nlp_opt - workspace->nlp_temp[j]; + workspace->dDelta_lp_temp[j] = 0.; + } + else { + workspace->nlp_temp[j] = workspace->nlp[j]; + workspace->Delta_lp_temp[j] = sbp_j->nlp_opt - workspace->nlp_temp[j]; + workspace->dDelta_lp_temp[j] = workspace->Clp[j]; + } + + //fprintf( stderr, "%d\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\n", + //j, workspace->Delta[j], workspace->Delta_e[j], workspace->Delta_boc[j], + //workspace->nlp[j], system->reaxprm.sbp[type_j].nlp_opt, + //workspace->Delta_lp[j], workspace->Clp[j], workspace->dDelta_lp[j] ); + + //fprintf( stdout, "%d(%d) %24.15f\n", + // j, workspace->bond_mark[j], workspace->total_bond_order[j] ); + } + + //Print_Bonds( system, bonds, "pbonds.out" ); + +#if defined(TEST_ENERGIES) || defined(TEST_FORCES) + fprintf( stderr, "Number of bonds: %d\n", num_bonds ); + Print_Bond_List( system, control, data, lists, out_control); +#endif +} + + +#if defined(DEPRECATED) +/* Locate j on i's list. + This function assumes that j is there for sure! + And this is the case given our method of neighbor generation*/ +int Locate_Symmetric_Bond( reax_list *bonds, int i, int j ) +{ + int start = Start_Index(i, bonds); + int end = End_Index(i, bonds); + int mid = (start + end) / 2; + int mid_nbr; + + while( (mid_nbr = bonds->select.bond_list[mid].nbr) != j ) { + /*fprintf( stderr, "\tstart: %d end: %d mid: %d\n", + start, end, mid );*/ + if( mid_nbr < j ) + start = mid+1; + else end = mid - 1; + + mid = (start + end) / 2; + } + + return mid; +} + + +inline void Copy_Bond_Order_Data( bond_order_data *dest, bond_order_data *src ) +{ + dest->BO = src->BO; + dest->BO_s = src->BO_s; + dest->BO_pi = src->BO_pi; + dest->BO_pi2 = src->BO_pi2; + + rvec_Scale( dest->dBOp, -1.0, src->dBOp ); + rvec_Scale( dest->dln_BOp_s, -1.0, src->dln_BOp_s ); + rvec_Scale( dest->dln_BOp_pi, -1.0, src->dln_BOp_pi ); + rvec_Scale( dest->dln_BOp_pi2, -1.0, src->dln_BOp_pi2 ); +} +#endif diff --git a/src/USER-REAXC/reaxc_bond_orders.h b/src/USER-REAXC/reaxc_bond_orders.h new file mode 100644 index 0000000000..0ad8e3b836 --- /dev/null +++ b/src/USER-REAXC/reaxc_bond_orders.h @@ -0,0 +1,58 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __BOND_ORDERS_H_ +#define __BOND_ORDERS_H_ + +#include "reaxc_types.h" + +typedef struct{ + real C1dbo, C2dbo, C3dbo; + real C1dbopi, C2dbopi, C3dbopi, C4dbopi; + real C1dbopi2, C2dbopi2, C3dbopi2, C4dbopi2; + real C1dDelta, C2dDelta, C3dDelta; +}dbond_coefficients; + +#ifdef TEST_FORCES +void Get_dBO( reax_system*, reax_list**, int, int, real, rvec* ); +void Get_dBOpinpi2( reax_system*, reax_list**, + int, int, real, real, rvec*, rvec* ); + +void Add_dBO( reax_system*, reax_list**, int, int, real, rvec* ); +void Add_dBOpinpi2( reax_system*, reax_list**, + int, int, real, real, rvec*, rvec* ); + +void Add_dBO_to_Forces( reax_system*, reax_list**, int, int, real ); +void Add_dBOpinpi2_to_Forces( reax_system*, reax_list**, + int, int, real, real ); + +void Add_dDelta( reax_system*, reax_list**, int, real, rvec* ); +void Add_dDelta_to_Forces( reax_system *, reax_list**, int, real ); +#endif + +void Add_dBond_to_Forces( int, int, storage*, reax_list** ); +void Add_dBond_to_Forces_NPT( int, int, simulation_data*, + storage*, reax_list** ); +int BOp(storage*, reax_list*, real, int, int, far_neighbor_data*, + single_body_parameters*, single_body_parameters*, two_body_parameters*); +void BO( reax_system*, control_params*, simulation_data*, + storage*, reax_list**, output_controls* ); +#endif diff --git a/src/USER-REAXC/reaxc_bonds.cpp b/src/USER-REAXC/reaxc_bonds.cpp new file mode 100644 index 0000000000..70e0b644f2 --- /dev/null +++ b/src/USER-REAXC/reaxc_bonds.cpp @@ -0,0 +1,148 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "bonds.h" +#include "bond_orders.h" +#include "list.h" +#include "tool_box.h" +#include "vector.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_bonds.h" +#include "reaxc_bond_orders.h" +#include "reaxc_list.h" +#include "reaxc_tool_box.h" +#include "reaxc_vector.h" +#endif + + +void Bonds( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, reax_list **lists, + output_controls *out_control ) +{ + int i, j, pj, natoms; + int start_i, end_i; + int type_i, type_j; + real ebond, pow_BOs_be2, exp_be12, CEbo; + real gp3, gp4, gp7, gp10, gp37; + real exphu, exphua1, exphub1, exphuov, hulpov, estriph; + real decobdbo, decobdboua, decobdboub; + single_body_parameters *sbp_i, *sbp_j; + two_body_parameters *twbp; + bond_order_data *bo_ij; + reax_list *bonds; + + bonds = (*lists) + BONDS; + gp3 = system->reax_param.gp.l[3]; + gp4 = system->reax_param.gp.l[4]; + gp7 = system->reax_param.gp.l[7]; + gp10 = system->reax_param.gp.l[10]; + gp37 = (int) system->reax_param.gp.l[37]; + natoms = system->n; + + for( i = 0; i < natoms; ++i ) { + start_i = Start_Index(i, bonds); + end_i = End_Index(i, bonds); + + for( pj = start_i; pj < end_i; ++pj ) { + j = bonds->select.bond_list[pj].nbr; + + if( system->my_atoms[i].orig_id <= system->my_atoms[j].orig_id ) { + /* set the pointers */ + type_i = system->my_atoms[i].type; + type_j = system->my_atoms[j].type; + sbp_i = &( system->reax_param.sbp[type_i] ); + sbp_j = &( system->reax_param.sbp[type_j] ); + twbp = &( system->reax_param.tbp[type_i][type_j] ); + bo_ij = &( bonds->select.bond_list[pj].bo_data ); + + /* calculate the constants */ + pow_BOs_be2 = pow( bo_ij->BO_s, twbp->p_be2 ); + exp_be12 = exp( twbp->p_be1 * ( 1.0 - pow_BOs_be2 ) ); + CEbo = -twbp->De_s * exp_be12 * + ( 1.0 - twbp->p_be1 * twbp->p_be2 * pow_BOs_be2 ); + + /* calculate the Bond Energy */ + data->my_en.e_bond += ebond = + -twbp->De_s * bo_ij->BO_s * exp_be12 + -twbp->De_p * bo_ij->BO_pi + -twbp->De_pp * bo_ij->BO_pi2; + + /* calculate derivatives of Bond Orders */ + bo_ij->Cdbo += CEbo; + bo_ij->Cdbopi -= (CEbo + twbp->De_p); + bo_ij->Cdbopi2 -= (CEbo + twbp->De_pp); + +#ifdef TEST_ENERGY + //fprintf( out_control->ebond, "%6d%6d%24.15e%24.15e%24.15e\n", + fprintf( out_control->ebond, "%6d%6d%12.4f%12.4f%12.4f\n", + system->my_atoms[i].orig_id, + system->my_atoms[j].orig_id, + bo_ij->BO, ebond, data->my_en.e_bond ); +#endif +#ifdef TEST_FORCES + Add_dBO( system, lists, i, pj, CEbo, workspace->f_be ); + Add_dBOpinpi2( system, lists, i, pj, + -(CEbo + twbp->De_p), -(CEbo + twbp->De_pp), + workspace->f_be, workspace->f_be ); +#endif + /* Stabilisation terminal triple bond */ + if( bo_ij->BO >= 1.00 ) { + if( gp37 == 2 || + (sbp_i->mass == 12.0000 && sbp_j->mass == 15.9990) || + (sbp_j->mass == 12.0000 && sbp_i->mass == 15.9990) ) { + exphu = exp( -gp7 * SQR(bo_ij->BO - 2.50) ); + exphua1 = exp(-gp3 * (workspace->total_bond_order[i]-bo_ij->BO)); + exphub1 = exp(-gp3 * (workspace->total_bond_order[j]-bo_ij->BO)); + exphuov = exp(gp4 * (workspace->Delta[i] + workspace->Delta[j])); + hulpov = 1.0 / (1.0 + 25.0 * exphuov); + + estriph = gp10 * exphu * hulpov * (exphua1 + exphub1); + data->my_en.e_bond += estriph; + + decobdbo = gp10 * exphu * hulpov * (exphua1 + exphub1) * + ( gp3 - 2.0 * gp7 * (bo_ij->BO-2.50) ); + decobdboua = -gp10 * exphu * hulpov * + (gp3*exphua1 + 25.0*gp4*exphuov*hulpov*(exphua1+exphub1)); + decobdboub = -gp10 * exphu * hulpov * + (gp3*exphub1 + 25.0*gp4*exphuov*hulpov*(exphua1+exphub1)); + + bo_ij->Cdbo += decobdbo; + workspace->CdDelta[i] += decobdboua; + workspace->CdDelta[j] += decobdboub; +#ifdef TEST_ENERGY + //fprintf( out_control->ebond, + // "%6d%6d%24.15e%24.15e%24.15e%24.15e\n", + // system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, + // estriph, decobdbo, decobdboua, decobdboub ); +#endif +#ifdef TEST_FORCES + Add_dBO( system, lists, i, pj, decobdbo, workspace->f_be ); + Add_dDelta( system, lists, i, decobdboua, workspace->f_be ); + Add_dDelta( system, lists, j, decobdboub, workspace->f_be ); +#endif + } + } + } + } + } +} diff --git a/src/USER-REAXC/reaxc_bonds.h b/src/USER-REAXC/reaxc_bonds.h new file mode 100644 index 0000000000..bf8c111775 --- /dev/null +++ b/src/USER-REAXC/reaxc_bonds.h @@ -0,0 +1,29 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __BONDS_H_ +#define __BONDS_H_ + +#include "reaxc_types.h" + +void Bonds( reax_system*, control_params*, simulation_data*, + storage*, reax_list**, output_controls* ); +#endif diff --git a/src/USER-REAXC/reaxc_control.cpp b/src/USER-REAXC/reaxc_control.cpp new file mode 100644 index 0000000000..7a72a1ee6f --- /dev/null +++ b/src/USER-REAXC/reaxc_control.cpp @@ -0,0 +1,395 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "control.h" +#include "tool_box.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_control.h" +#include "reaxc_tool_box.h" +#endif + + +char Read_Control_File( char *control_file, control_params* control, + output_controls *out_control ) +{ + FILE *fp; + char *s, **tmp; + int c,i,ival; + real val; + + /* open control file */ + if ( (fp = fopen( control_file, "r" ) ) == NULL ) { + fprintf( stderr, "error opening the control file! terminating...\n" ); + MPI_Abort( MPI_COMM_WORLD, FILE_NOT_FOUND ); + } + + /* assign default values */ + strcpy( control->sim_name, "simulate" ); + control->ensemble = NVE; + control->nsteps = 0; + control->dt = 0.25; + control->nprocs = 1; + control->procs_by_dim[0] = 1; + control->procs_by_dim[1] = 1; + control->procs_by_dim[2] = 1; + control->geo_format = 1; + + control->restart = 0; + out_control->restart_format = WRITE_BINARY; + out_control->restart_freq = 0; + control->reposition_atoms = 0; + control->restrict_bonds = 0; + control->remove_CoM_vel = 25; + out_control->debug_level = 0; + out_control->energy_update_freq = 0; + + control->reneighbor = 1; + control->vlist_cut = control->nonb_cut; + control->bond_cut = 5.0; + control->bg_cut = 0.3; + control->thb_cut = 0.001; + control->hbond_cut = 0.0; + + control->tabulate = 0; + + control->qeq_freq = 1; + control->q_err = 1e-6; + control->refactor = 100; + control->droptol = 1e-2;; + + control->T_init = 0.; + control->T_final = 300.; + control->Tau_T = 500.0; + control->T_mode = 0; + control->T_rate = 1.; + control->T_freq = 1.; + + control->P[0] = control->P[1] = control->P[2] = 0.000101325; + control->Tau_P[0] = control->Tau_P[1] = control->Tau_P[2] = 500.0; + control->Tau_PT[0] = control->Tau_PT[1] = control->Tau_PT[2] = 500.0; + control->compressibility = 1.0; + control->press_mode = 0; + control->virial = 0; + + out_control->write_steps = 0; + out_control->traj_compress = 0; + out_control->traj_method = REG_TRAJ; + strcpy( out_control->traj_title, "default_title" ); + out_control->atom_info = 0; + out_control->bond_info = 0; + out_control->angle_info = 0; + + control->molecular_analysis = 0; + control->dipole_anal = 0; + control->freq_dipole_anal = 0; + control->diffusion_coef = 0; + control->freq_diffusion_coef = 0; + control->restrict_type = 0; + + /* memory allocations */ + s = (char*) malloc(sizeof(char)*MAX_LINE); + tmp = (char**) malloc(sizeof(char*)*MAX_TOKENS); + for (i=0; i < MAX_TOKENS; i++) + tmp[i] = (char*) malloc(sizeof(char)*MAX_LINE); + + /* read control parameters file */ + while (!feof(fp)) { + fgets( s, MAX_LINE, fp ); + c = Tokenize( s, &tmp ); + //fprintf( stderr, "%s\n", s ); + + if( strcmp(tmp[0], "simulation_name") == 0 ) { + strcpy( control->sim_name, tmp[1] ); + } + else if( strcmp(tmp[0], "ensemble_type") == 0 ) { + ival = atoi(tmp[1]); + control->ensemble = ival; + if( ival == iNPT || ival ==sNPT || ival == NPT ) + control->virial = 1; + } + else if( strcmp(tmp[0], "nsteps") == 0 ) { + ival = atoi(tmp[1]); + control->nsteps = ival; + } + else if( strcmp(tmp[0], "dt") == 0) { + val = atof(tmp[1]); + control->dt = val * 1.e-3; // convert dt from fs to ps! + } + else if( strcmp(tmp[0], "proc_by_dim") == 0 ) { + ival = atoi(tmp[1]); + control->procs_by_dim[0] = ival; + ival = atoi(tmp[2]); + control->procs_by_dim[1] = ival; + ival = atoi(tmp[3]); + control->procs_by_dim[2] = ival; + + control->nprocs = control->procs_by_dim[0]*control->procs_by_dim[1]* + control->procs_by_dim[2]; + } + //else if( strcmp(tmp[0], "restart") == 0 ) { + // ival = atoi(tmp[1]); + // control->restart = ival; + //} + //else if( strcmp(tmp[0], "restart_from") == 0 ) { + // strcpy( control->restart_from, tmp[1] ); + //} + else if( strcmp(tmp[0], "random_vel") == 0 ) { + ival = atoi(tmp[1]); + control->random_vel = ival; + } + else if( strcmp(tmp[0], "restart_format") == 0 ) { + ival = atoi(tmp[1]); + out_control->restart_format = ival; + } + else if( strcmp(tmp[0], "restart_freq") == 0 ) { + ival = atoi(tmp[1]); + out_control->restart_freq = ival; + } + else if( strcmp(tmp[0], "reposition_atoms") == 0 ) { + ival = atoi(tmp[1]); + control->reposition_atoms = ival; + } + else if( strcmp(tmp[0], "restrict_bonds") == 0 ) { + ival = atoi( tmp[1] ); + control->restrict_bonds = ival; + } + else if( strcmp(tmp[0], "remove_CoM_vel") == 0 ) { + ival = atoi(tmp[1]); + control->remove_CoM_vel = ival; + } + else if( strcmp(tmp[0], "debug_level") == 0 ) { + ival = atoi(tmp[1]); + out_control->debug_level = ival; + } + else if( strcmp(tmp[0], "energy_update_freq") == 0 ) { + ival = atoi(tmp[1]); + out_control->energy_update_freq = ival; + } + else if( strcmp(tmp[0], "reneighbor") == 0 ) { + ival = atoi( tmp[1] ); + control->reneighbor = ival; + } + else if( strcmp(tmp[0], "vlist_buffer") == 0 ) { + val = atof(tmp[1]); + control->vlist_cut= val + control->nonb_cut; + } + else if( strcmp(tmp[0], "nbrhood_cutoff") == 0 ) { + val = atof(tmp[1]); + control->bond_cut = val; + } + else if( strcmp(tmp[0], "bond_graph_cutoff") == 0 ) { + val = atof(tmp[1]); + control->bg_cut = val; + } + else if( strcmp(tmp[0], "thb_cutoff") == 0 ) { + val = atof(tmp[1]); + control->thb_cut = val; + } + else if( strcmp(tmp[0], "hbond_cutoff") == 0 ) { + val = atof( tmp[1] ); + control->hbond_cut = val; + } + else if( strcmp(tmp[0], "ghost_cutoff") == 0 ) { + val = atof(tmp[1]); + control->user_ghost_cut = val; + } + else if( strcmp(tmp[0], "tabulate_long_range") == 0 ) { + ival = atoi( tmp[1] ); + control->tabulate = ival; + } + else if( strcmp(tmp[0], "qeq_freq") == 0 ) { + ival = atoi( tmp[1] ); + control->qeq_freq = ival; + } + else if( strcmp(tmp[0], "q_err") == 0 ) { + val = atof( tmp[1] ); + control->q_err = val; + } + else if( strcmp(tmp[0], "ilu_refactor") == 0 ) { + ival = atoi( tmp[1] ); + control->refactor = ival; + } + else if( strcmp(tmp[0], "ilu_droptol") == 0 ) { + val = atof( tmp[1] ); + control->droptol = val; + } + else if( strcmp(tmp[0], "temp_init") == 0 ) { + val = atof(tmp[1]); + control->T_init = val; + + if( control->T_init < 0.1 ) + control->T_init = 0.1; + } + else if( strcmp(tmp[0], "temp_final") == 0 ) { + val = atof(tmp[1]); + control->T_final = val; + + if( control->T_final < 0.1 ) + control->T_final = 0.1; + } + else if( strcmp(tmp[0], "t_mass") == 0 ) { + val = atof(tmp[1]); + control->Tau_T = val * 1.e-3; // convert t_mass from fs to ps + } + else if( strcmp(tmp[0], "t_mode") == 0 ) { + ival = atoi(tmp[1]); + control->T_mode = ival; + } + else if( strcmp(tmp[0], "t_rate") == 0 ) { + val = atof(tmp[1]); + control->T_rate = val; + } + else if( strcmp(tmp[0], "t_freq") == 0 ) { + val = atof(tmp[1]); + control->T_freq = val; + } + else if( strcmp(tmp[0], "pressure") == 0 ) { + if( control->ensemble == iNPT ) { + control->P[0] = control->P[1] = control->P[2] = atof(tmp[1]); + } + else if( control->ensemble == sNPT ) { + control->P[0] = atof(tmp[1]); + control->P[1] = atof(tmp[2]); + control->P[2] = atof(tmp[3]); + } + } + else if( strcmp(tmp[0], "p_mass") == 0 ) { + // convert p_mass from fs to ps + if( control->ensemble == iNPT ) { + control->Tau_P[0] = control->Tau_P[1] = control->Tau_P[2] = + atof(tmp[1]) * 1.e-3; + } + else if( control->ensemble == sNPT ) { + control->Tau_P[0] = atof(tmp[1]) * 1.e-3; + control->Tau_P[1] = atof(tmp[2]) * 1.e-3; + control->Tau_P[2] = atof(tmp[3]) * 1.e-3; + } + } + else if( strcmp(tmp[0], "pt_mass") == 0 ) { + val = atof(tmp[1]); + control->Tau_PT[0] = control->Tau_PT[1] = control->Tau_PT[2] = + val * 1.e-3; // convert pt_mass from fs to ps + } + else if( strcmp(tmp[0], "compress") == 0 ) { + val = atof(tmp[1]); + control->compressibility = val; + } + else if( strcmp(tmp[0], "press_mode") == 0 ) { + ival = atoi(tmp[1]); + control->press_mode = ival; + } + else if( strcmp(tmp[0], "geo_format") == 0 ) { + ival = atoi( tmp[1] ); + control->geo_format = ival; + } + else if( strcmp(tmp[0], "write_freq") == 0 ) { + ival = atoi(tmp[1]); + out_control->write_steps = ival; + } + else if( strcmp(tmp[0], "traj_compress") == 0 ) { + ival = atoi(tmp[1]); + out_control->traj_compress = ival; + } + else if( strcmp(tmp[0], "traj_method") == 0 ) { + ival = atoi(tmp[1]); + out_control->traj_method = ival; + } + else if( strcmp(tmp[0], "traj_title") == 0 ) { + strcpy( out_control->traj_title, tmp[1] ); + } + else if( strcmp(tmp[0], "atom_info") == 0 ) { + ival = atoi(tmp[1]); + out_control->atom_info += ival * 4; + } + else if( strcmp(tmp[0], "atom_velocities") == 0 ) { + ival = atoi(tmp[1]); + out_control->atom_info += ival * 2; + } + else if( strcmp(tmp[0], "atom_forces") == 0 ) { + ival = atoi(tmp[1]); + out_control->atom_info += ival * 1; + } + else if( strcmp(tmp[0], "bond_info") == 0 ) { + ival = atoi(tmp[1]); + out_control->bond_info = ival; + } + else if( strcmp(tmp[0], "angle_info") == 0 ) { + ival = atoi(tmp[1]); + out_control->angle_info = ival; + } + else if( strcmp(tmp[0], "molecular_analysis") == 0 ) { + ival = atoi(tmp[1]); + control->molecular_analysis = ival; + } + else if( strcmp(tmp[0], "ignore") == 0 ) { + control->num_ignored = atoi(tmp[1]); + for( i = 0; i < control->num_ignored; ++i ) + control->ignore[atoi(tmp[i+2])] = 1; + } + else if( strcmp(tmp[0], "dipole_anal") == 0 ) { + ival = atoi(tmp[1]); + control->dipole_anal = ival; + } + else if( strcmp(tmp[0], "freq_dipole_anal") == 0 ) { + ival = atoi(tmp[1]); + control->freq_dipole_anal = ival; + } + else if( strcmp(tmp[0], "diffusion_coef") == 0 ) { + ival = atoi(tmp[1]); + control->diffusion_coef = ival; + } + else if( strcmp(tmp[0], "freq_diffusion_coef") == 0 ) { + ival = atoi(tmp[1]); + control->freq_diffusion_coef = ival; + } + else if( strcmp(tmp[0], "restrict_type") == 0 ) { + ival = atoi(tmp[1]); + control->restrict_type = ival; + } + else { + fprintf( stderr, "WARNING: unknown parameter %s\n", tmp[0] ); + MPI_Abort( MPI_COMM_WORLD, 15 ); + } + } + + /* determine target T */ + if( control->T_mode == 0 ) + control->T = control->T_final; + else control->T = control->T_init; + + /* free memory allocations at the top */ + for( i = 0; i < MAX_TOKENS; i++ ) + free( tmp[i] ); + free( tmp ); + free( s ); + + // fprintf( stderr,"%d %d %10.5f %d %10.5f %10.5f\n", + // control->ensemble, control->nsteps, control->dt, + // control->tabulate, control->T, control->P ); + +#if defined(DEBUG_FOCUS) + fprintf( stderr, "control file read\n" ); +#endif + + return SUCCESS; +} diff --git a/src/USER-REAXC/reaxc_control.h b/src/USER-REAXC/reaxc_control.h new file mode 100644 index 0000000000..68fd33c95d --- /dev/null +++ b/src/USER-REAXC/reaxc_control.h @@ -0,0 +1,29 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __CONTROL_H_ +#define __CONTROL_H_ + +#include "reaxc_types.h" + +char Read_Control_File( char*, control_params*, output_controls* ); + +#endif diff --git a/src/USER-REAXC/reaxc_defs.h b/src/USER-REAXC/reaxc_defs.h new file mode 100644 index 0000000000..957816d38a --- /dev/null +++ b/src/USER-REAXC/reaxc_defs.h @@ -0,0 +1,141 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef REAX_DEFS_H +#define REAX_DEFS_H + +#if defined(__IBMC__) +#define inline __inline__ +#endif /*IBMC*/ + +#define SUCCESS 1 +#define FAILURE 0 +#define TRUE 1 +#define FALSE 0 + +#define SQR(x) ((x)*(x)) +#define CUBE(x) ((x)*(x)*(x)) +#define DEG2RAD(a) ((a)*constPI/180.0) +#define RAD2DEG(a) ((a)*180.0/constPI) +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#define MAX3(x,y,z) MAX( MAX(x,y), z) + +#define constPI 3.14159265 +#define C_ele 332.06371 +//#define K_B 503.398008 // kcal/mol/K +#define K_B 0.831687 // amu A^2 / ps^2 / K +#define F_CONV 1e6 / 48.88821291 / 48.88821291 // --> amu A / ps^2 +#define E_CONV 0.002391 // amu A^2 / ps^2 --> kcal/mol +#define EV_to_KCALpMOL 14.400000 // ElectronVolt --> KCAL per MOLe +#define KCALpMOL_to_EV 23.02 // 23.060549 //KCAL per MOLe --> ElectronVolt +#define ECxA_to_DEBYE 4.803204 // elem. charge * Ang -> debye +#define CAL_to_JOULES 4.184000 // CALories --> JOULES +#define JOULES_to_CAL 1/4.184000 // JOULES --> CALories +#define AMU_to_GRAM 1.6605e-24 +#define ANG_to_CM 1e-8 +#define AVOGNR 6.0221367e23 +#define P_CONV 1e-24 * AVOGNR * JOULES_to_CAL + +#define MAX_STR 1024 +#define MAX_LINE 1024 +#define MAX_TOKENS 1024 +#define MAX_TOKEN_LEN 1024 + +#define MAX_ATOM_ID 100000 +#define MAX_RESTRICT 15 +#define MAX_MOLECULE_SIZE 20 +#define MAX_ATOM_TYPES 25 + +#define NUM_INTRS 10 +#define ALMOST_ZERO 1e-10 +#define NEG_INF -1e10 +#define NO_BOND 1e-3 // 0.001 +#define HB_THRESHOLD 1e-2 // 0.01 + +#define MIN_CAP 50 +#define MIN_NBRS 100 +#define MIN_HENTRIES 100 +#define MAX_BONDS 30 +#define MIN_BONDS 15 +#define MIN_HBONDS 25 +#define MIN_3BODIES 1000 +#define MIN_GCELL_POPL 50 +#define MIN_SEND 100 +#define SAFE_ZONE 1.2 +#define SAFER_ZONE 1.4 +#define DANGER_ZONE 0.90 +#define LOOSE_ZONE 0.75 +#define MAX_3BODY_PARAM 5 +#define MAX_4BODY_PARAM 5 + +#define MAX_dV 1.01 +#define MIN_dV 0.99 +#define MAX_dT 4.00 +#define MIN_dT 0.00 + +#define MASTER_NODE 0 +#define MAX_NBRS 6 //27 +#define MYSELF 13 // encoding of relative coordinate (0,0,0) + +#define MAX_ITR 10 +#define RESTART 30 + + + +/******************* ENUMERATIONS *************************/ +enum geo_formats { CUSTOM, PDB, ASCII_RESTART, BINARY_RESTART, GF_N }; + +enum restart_formats { WRITE_ASCII, WRITE_BINARY, RF_N }; + +enum ensembles { NVE, bNVT, nhNVT, sNPT, iNPT, NPT, ens_N }; + +enum lists { BONDS, OLD_BONDS, THREE_BODIES, + HBONDS, FAR_NBRS, DBOS, DDELTAS, LIST_N }; + +enum interactions { TYP_VOID, TYP_BOND, TYP_THREE_BODY, + TYP_HBOND, TYP_FAR_NEIGHBOR, TYP_DBO, TYP_DDELTA, TYP_N }; + +enum message_tags { INIT, UPDATE, BNDRY, UPDATE_BNDRY, + EXC_VEC1, EXC_VEC2, DIST_RVEC2, COLL_RVEC2, + DIST_RVECS, COLL_RVECS, INIT_DESCS, ATOM_LINES, + BOND_LINES, ANGLE_LINES, RESTART_ATOMS, TAGS_N }; + +enum errors { FILE_NOT_FOUND = -10, UNKNOWN_ATOM_TYPE = -11, + CANNOT_OPEN_FILE = -12, CANNOT_INITIALIZE = -13, + INSUFFICIENT_MEMORY = -14, UNKNOWN_OPTION = -15, + INVALID_INPUT = -16, INVALID_GEO = -17 }; + +enum exchanges { NONE, NEAR_EXCH, FULL_EXCH }; + +enum gcell_types { NO_NBRS=0, NEAR_ONLY=1, HBOND_ONLY=2, FAR_ONLY=4, + NEAR_HBOND=3, NEAR_FAR=5, HBOND_FAR=6, FULL_NBRS=7, + NATIVE=8 }; + +enum atoms { C_ATOM = 0, H_ATOM = 1, O_ATOM = 2, N_ATOM = 3, + S_ATOM = 4, SI_ATOM = 5, GE_ATOM = 6, X_ATOM = 7 }; + +enum traj_methods { REG_TRAJ, MPI_TRAJ, TF_N }; + +enum molecules { UNKNOWN, WATER }; + + +#endif diff --git a/src/USER-REAXC/reaxc_ffield.cpp b/src/USER-REAXC/reaxc_ffield.cpp new file mode 100644 index 0000000000..2d0f37123d --- /dev/null +++ b/src/USER-REAXC/reaxc_ffield.cpp @@ -0,0 +1,715 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "ffield.h" +#include "tool_box.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_ffield.h" +#include "reaxc_tool_box.h" +#endif + + +char Read_Force_Field( char *ffield_file, reax_interaction *reax, + control_params *control ) +{ + FILE *fp; + char *s; + char **tmp; + char ****tor_flag; + int c, i, j, k, l, m, n, o, p, cnt; + real val; + MPI_Comm comm; + + comm = MPI_COMM_WORLD; + + /* open force field file */ + if ( (fp = fopen( ffield_file, "r" ) ) == NULL ) { + fprintf( stderr, "error opening the force filed file! terminating...\n" ); + MPI_Abort( comm, FILE_NOT_FOUND ); + } + + s = (char*) malloc(sizeof(char)*MAX_LINE); + tmp = (char**) malloc(sizeof(char*)*MAX_TOKENS); + for (i=0; i < MAX_TOKENS; i++) + tmp[i] = (char*) malloc(sizeof(char)*MAX_TOKEN_LEN); + + + /* reading first header comment */ + fgets( s, MAX_LINE, fp ); + + /* line 2 is number of global parameters */ + fgets( s, MAX_LINE, fp ); + c = Tokenize( s, &tmp ); + + /* reading the number of global parameters */ + n = atoi(tmp[0]); + if (n < 1) { + fprintf( stderr, "WARNING: number of globals in ffield file is 0!\n" ); + fclose(fp); + return 1; + } + + reax->gp.n_global = n; + reax->gp.l = (real*) malloc(sizeof(real)*n); + + /* see reax_types.h for mapping between l[i] and the lambdas used in ff */ + for (i=0; i < n; i++) { + fgets(s,MAX_LINE,fp); + c = Tokenize(s,&tmp); + + val = (real) atof(tmp[0]); + reax->gp.l[i] = val; + } + + control->bo_cut = 0.01 * reax->gp.l[29]; + control->nonb_low = reax->gp.l[11]; + control->nonb_cut = reax->gp.l[12]; + + /* next line is number of atom types and some comments */ + fgets( s, MAX_LINE, fp ); + c = Tokenize( s, &tmp ); + reax->num_atom_types = atoi(tmp[0]); + + /* 3 lines of comments */ + fgets(s,MAX_LINE,fp); + fgets(s,MAX_LINE,fp); + fgets(s,MAX_LINE,fp); + + /* Allocating structures in reax_interaction */ + reax->sbp = (single_body_parameters*) + scalloc( reax->num_atom_types, sizeof(single_body_parameters), "sbp", + comm ); + reax->tbp = (two_body_parameters**) + scalloc( reax->num_atom_types, sizeof(two_body_parameters*), "tbp", comm ); + reax->thbp= (three_body_header***) + scalloc( reax->num_atom_types, sizeof(three_body_header**), "thbp", comm ); + reax->hbp = (hbond_parameters***) + scalloc( reax->num_atom_types, sizeof(hbond_parameters**), "hbp", comm ); + reax->fbp = (four_body_header****) + scalloc( reax->num_atom_types, sizeof(four_body_header***), "fbp", comm ); + tor_flag = (char****) + scalloc( reax->num_atom_types, sizeof(char***), "tor_flag", comm ); + + for( i = 0; i < reax->num_atom_types; i++ ) { + reax->tbp[i] = (two_body_parameters*) + scalloc( reax->num_atom_types, sizeof(two_body_parameters), "tbp[i]", + comm ); + reax->thbp[i]= (three_body_header**) + scalloc( reax->num_atom_types, sizeof(three_body_header*), "thbp[i]", + comm ); + reax->hbp[i] = (hbond_parameters**) + scalloc( reax->num_atom_types, sizeof(hbond_parameters*), "hbp[i]", + comm ); + reax->fbp[i] = (four_body_header***) + scalloc( reax->num_atom_types, sizeof(four_body_header**), "fbp[i]", + comm ); + tor_flag[i] = (char***) + scalloc( reax->num_atom_types, sizeof(char**), "tor_flag[i]", comm ); + + for( j = 0; j < reax->num_atom_types; j++ ) { + reax->thbp[i][j]= (three_body_header*) + scalloc( reax->num_atom_types, sizeof(three_body_header), "thbp[i,j]", + comm ); + reax->hbp[i][j] = (hbond_parameters*) + scalloc( reax->num_atom_types, sizeof(hbond_parameters), "hbp[i,j]", + comm ); + reax->fbp[i][j] = (four_body_header**) + scalloc( reax->num_atom_types, sizeof(four_body_header*), "fbp[i,j]", + comm ); + tor_flag[i][j] = (char**) + scalloc( reax->num_atom_types, sizeof(char*), "tor_flag[i,j]", comm ); + + for (k=0; k < reax->num_atom_types; k++) { + reax->fbp[i][j][k] = (four_body_header*) + scalloc( reax->num_atom_types, sizeof(four_body_header), "fbp[i,j,k]", + comm ); + tor_flag[i][j][k] = (char*) + scalloc( reax->num_atom_types, sizeof(char), "tor_flag[i,j,k]", + comm ); + } + } + } + + // vdWaals type: 1: Shielded Morse, no inner-wall + // 2: inner wall, no shielding + // 3: inner wall+shielding + reax->gp.vdw_type = 0; + + /* reading single atom parameters */ + /* there are 4 lines of each single atom parameters in ff files. these + parameters later determine some of the pair and triplet parameters using + combination rules. */ + for( i = 0; i < reax->num_atom_types; i++ ) { + /* line one */ + fgets( s, MAX_LINE, fp ); + c = Tokenize( s, &tmp ); + + for( j = 0; j < (int)(strlen(tmp[0])); ++j ) + reax->sbp[i].name[j] = toupper( tmp[0][j] ); + + val = atof(tmp[1]); reax->sbp[i].r_s = val; + val = atof(tmp[2]); reax->sbp[i].valency = val; + val = atof(tmp[3]); reax->sbp[i].mass = val; + val = atof(tmp[4]); reax->sbp[i].r_vdw = val; + val = atof(tmp[5]); reax->sbp[i].epsilon = val; + val = atof(tmp[6]); reax->sbp[i].gamma = val; + val = atof(tmp[7]); reax->sbp[i].r_pi = val; + val = atof(tmp[8]); reax->sbp[i].valency_e = val; + reax->sbp[i].nlp_opt = 0.5 * (reax->sbp[i].valency_e-reax->sbp[i].valency); + + /* line two */ + fgets( s, MAX_LINE, fp ); + c = Tokenize( s, &tmp ); + + val = atof(tmp[0]); reax->sbp[i].alpha = val; + val = atof(tmp[1]); reax->sbp[i].gamma_w = val; + val = atof(tmp[2]); reax->sbp[i].valency_boc= val; + val = atof(tmp[3]); reax->sbp[i].p_ovun5 = val; + val = atof(tmp[4]); + val = atof(tmp[5]); reax->sbp[i].chi = val; + val = atof(tmp[6]); reax->sbp[i].eta = 2.0 * val; + val = atof(tmp[7]); reax->sbp[i].p_hbond = (int) val; + + /* line 3 */ + fgets( s, MAX_LINE, fp ); + c = Tokenize( s, &tmp ); + + val = atof(tmp[0]); reax->sbp[i].r_pi_pi = val; + val = atof(tmp[1]); reax->sbp[i].p_lp2 = val; + val = atof(tmp[2]); + val = atof(tmp[3]); reax->sbp[i].b_o_131 = val; + val = atof(tmp[4]); reax->sbp[i].b_o_132 = val; + val = atof(tmp[5]); reax->sbp[i].b_o_133 = val; + val = atof(tmp[6]); + val = atof(tmp[7]); + + /* line 4 */ + fgets( s, MAX_LINE, fp ); + c = Tokenize( s, &tmp ); + + val = atof(tmp[0]); reax->sbp[i].p_ovun2 = val; + val = atof(tmp[1]); reax->sbp[i].p_val3 = val; + val = atof(tmp[2]); + val = atof(tmp[3]); reax->sbp[i].valency_val= val; + val = atof(tmp[4]); reax->sbp[i].p_val5 = val; + val = atof(tmp[5]); reax->sbp[i].rcore2 = val; + val = atof(tmp[6]); reax->sbp[i].ecore2 = val; + val = atof(tmp[7]); reax->sbp[i].acore2 = val; + + + if( reax->sbp[i].rcore2>0.01 && reax->sbp[i].acore2>0.01 ){ // Inner-wall + if( reax->sbp[i].gamma_w>0.5 ){ // Shielding vdWaals + if( reax->gp.vdw_type != 0 && reax->gp.vdw_type != 3 ) + fprintf( stderr, "Warning: inconsistent vdWaals-parameters\n" \ + "Force field parameters for element %s\n" \ + "indicate inner wall+shielding, but earlier\n" \ + "atoms indicate different vdWaals-method.\n" \ + "This may cause division-by-zero errors.\n" \ + "Keeping vdWaals-setting for earlier atoms.\n", + reax->sbp[i].name ); + else{ + reax->gp.vdw_type = 3; +#if defined(DEBUG) + fprintf( stderr, "vdWaals type for element %s: Shielding+inner-wall", + reax->sbp[i].name ); +#endif + } + } + else { // No shielding vdWaals parameters present + if( reax->gp.vdw_type != 0 && reax->gp.vdw_type != 2 ) + fprintf( stderr, "Warning: inconsistent vdWaals-parameters\n" \ + "Force field parameters for element %s\n" \ + "indicate inner wall without shielding, but earlier\n" \ + "atoms indicate different vdWaals-method.\n" \ + "This may cause division-by-zero errors.\n" \ + "Keeping vdWaals-setting for earlier atoms.\n", + reax->sbp[i].name ); + else{ + reax->gp.vdw_type = 2; +#if defined(DEBUG) + fprintf( stderr,"vdWaals type for element%s: No Shielding,inner-wall", + reax->sbp[i].name ); +#endif + } + } + } + else{ // No Inner wall parameters present + if( reax->sbp[i].gamma_w>0.5 ){ // Shielding vdWaals + if( reax->gp.vdw_type != 0 && reax->gp.vdw_type != 1 ) + fprintf( stderr, "Warning: inconsistent vdWaals-parameters\n" \ + "Force field parameters for element %s\n" \ + "indicate shielding without inner wall, but earlier\n" \ + "atoms indicate different vdWaals-method.\n" \ + "This may cause division-by-zero errors.\n" \ + "Keeping vdWaals-setting for earlier atoms.\n", + reax->sbp[i].name ); + else{ + reax->gp.vdw_type = 1; +#if defined(DEBUG) + fprintf( stderr,"vdWaals type for element%s: Shielding,no inner-wall", + reax->sbp[i].name ); +#endif + } + } + else{ + fprintf( stderr, "Error: inconsistent vdWaals-parameters\n"\ + "No shielding or inner-wall set for element %s\n", + reax->sbp[i].name ); + MPI_Abort( comm, INVALID_INPUT ); + } + } + } + +#if defined(DEBUG) + fprintf( stderr, "vdWaals type: %d\n", reax->gp.vdw_type ); +#endif + + /* Equate vval3 to valf for first-row elements (25/10/2004) */ + for( i = 0; i < reax->num_atom_types; i++ ) + if( reax->sbp[i].mass < 21 && + reax->sbp[i].valency_val != reax->sbp[i].valency_boc ){ + fprintf( stderr, "Warning: changed valency_val to valency_boc for %s\n", + reax->sbp[i].name ); + reax->sbp[i].valency_val = reax->sbp[i].valency_boc; + } + + + /* next line is number of two body combination and some comments */ + fgets(s,MAX_LINE,fp); + c=Tokenize(s,&tmp); + l = atoi(tmp[0]); + + /* a line of comments */ + fgets(s,MAX_LINE,fp); + + for (i=0; i < l; i++) { + /* line 1 */ + fgets(s,MAX_LINE,fp); + c=Tokenize(s,&tmp); + + j = atoi(tmp[0]) - 1; + k = atoi(tmp[1]) - 1; + + if (j < reax->num_atom_types && k < reax->num_atom_types) { + + val = atof(tmp[2]); reax->tbp[j][k].De_s = val; + reax->tbp[k][j].De_s = val; + val = atof(tmp[3]); reax->tbp[j][k].De_p = val; + reax->tbp[k][j].De_p = val; + val = atof(tmp[4]); reax->tbp[j][k].De_pp = val; + reax->tbp[k][j].De_pp = val; + val = atof(tmp[5]); reax->tbp[j][k].p_be1 = val; + reax->tbp[k][j].p_be1 = val; + val = atof(tmp[6]); reax->tbp[j][k].p_bo5 = val; + reax->tbp[k][j].p_bo5 = val; + val = atof(tmp[7]); reax->tbp[j][k].v13cor = val; + reax->tbp[k][j].v13cor = val; + + val = atof(tmp[8]); reax->tbp[j][k].p_bo6 = val; + reax->tbp[k][j].p_bo6 = val; + val = atof(tmp[9]); reax->tbp[j][k].p_ovun1 = val; + reax->tbp[k][j].p_ovun1 = val; + + /* line 2 */ + fgets(s,MAX_LINE,fp); + c=Tokenize(s,&tmp); + + val = atof(tmp[0]); reax->tbp[j][k].p_be2 = val; + reax->tbp[k][j].p_be2 = val; + val = atof(tmp[1]); reax->tbp[j][k].p_bo3 = val; + reax->tbp[k][j].p_bo3 = val; + val = atof(tmp[2]); reax->tbp[j][k].p_bo4 = val; + reax->tbp[k][j].p_bo4 = val; + val = atof(tmp[3]); + + val = atof(tmp[4]); reax->tbp[j][k].p_bo1 = val; + reax->tbp[k][j].p_bo1 = val; + val = atof(tmp[5]); reax->tbp[j][k].p_bo2 = val; + reax->tbp[k][j].p_bo2 = val; + val = atof(tmp[6]); reax->tbp[j][k].ovc = val; + reax->tbp[k][j].ovc = val; + + val = atof(tmp[7]); + } + } + + /* calculating combination rules and filling up remaining fields. */ + + for (i=0; i < reax->num_atom_types; i++) + for (j=i; j < reax->num_atom_types; j++) { + reax->tbp[i][j].r_s = 0.5 * + (reax->sbp[i].r_s + reax->sbp[j].r_s); + reax->tbp[j][i].r_s = 0.5 * + (reax->sbp[j].r_s + reax->sbp[i].r_s); + + reax->tbp[i][j].r_p = 0.5 * + (reax->sbp[i].r_pi + reax->sbp[j].r_pi); + reax->tbp[j][i].r_p = 0.5 * + (reax->sbp[j].r_pi + reax->sbp[i].r_pi); + + reax->tbp[i][j].r_pp = 0.5 * + (reax->sbp[i].r_pi_pi + reax->sbp[j].r_pi_pi); + reax->tbp[j][i].r_pp = 0.5 * + (reax->sbp[j].r_pi_pi + reax->sbp[i].r_pi_pi); + + + reax->tbp[i][j].p_boc3 = + sqrt(reax->sbp[i].b_o_132 * + reax->sbp[j].b_o_132); + reax->tbp[j][i].p_boc3 = + sqrt(reax->sbp[j].b_o_132 * + reax->sbp[i].b_o_132); + + reax->tbp[i][j].p_boc4 = + sqrt(reax->sbp[i].b_o_131 * + reax->sbp[j].b_o_131); + reax->tbp[j][i].p_boc4 = + sqrt(reax->sbp[j].b_o_131 * + reax->sbp[i].b_o_131); + + reax->tbp[i][j].p_boc5 = + sqrt(reax->sbp[i].b_o_133 * + reax->sbp[j].b_o_133); + reax->tbp[j][i].p_boc5 = + sqrt(reax->sbp[j].b_o_133 * + reax->sbp[i].b_o_133); + + + reax->tbp[i][j].D = + sqrt(reax->sbp[i].epsilon * + reax->sbp[j].epsilon); + + reax->tbp[j][i].D = + sqrt(reax->sbp[j].epsilon * + reax->sbp[i].epsilon); + + reax->tbp[i][j].alpha = + sqrt(reax->sbp[i].alpha * + reax->sbp[j].alpha); + + reax->tbp[j][i].alpha = + sqrt(reax->sbp[j].alpha * + reax->sbp[i].alpha); + + reax->tbp[i][j].r_vdW = + 2.0 * sqrt(reax->sbp[i].r_vdw * reax->sbp[j].r_vdw); + + reax->tbp[j][i].r_vdW = + 2.0 * sqrt(reax->sbp[j].r_vdw * reax->sbp[i].r_vdw); + + reax->tbp[i][j].gamma_w = + sqrt(reax->sbp[i].gamma_w * + reax->sbp[j].gamma_w); + + reax->tbp[j][i].gamma_w = + sqrt(reax->sbp[j].gamma_w * + reax->sbp[i].gamma_w); + + reax->tbp[i][j].gamma = + pow(reax->sbp[i].gamma * + reax->sbp[j].gamma,-1.5); + + reax->tbp[j][i].gamma = + pow(reax->sbp[j].gamma * + reax->sbp[i].gamma,-1.5); + + // additions for additional vdWaals interaction types - inner core + reax->tbp[i][j].rcore = reax->tbp[j][i].rcore = + sqrt( reax->sbp[i].rcore2 * reax->sbp[j].rcore2 ); + + reax->tbp[i][j].ecore = reax->tbp[j][i].ecore = + sqrt( reax->sbp[i].ecore2 * reax->sbp[j].ecore2 ); + + reax->tbp[i][j].acore = reax->tbp[j][i].acore = + sqrt( reax->sbp[i].acore2 * reax->sbp[j].acore2 ); + } + + + /* next line is number of two body offdiagonal combinations and comments */ + /* these are two body offdiagonal terms that are different from the + combination rules defined above */ + fgets(s,MAX_LINE,fp); + c=Tokenize(s,&tmp); + l = atoi(tmp[0]); + + for (i=0; i < l; i++) { + fgets(s,MAX_LINE,fp); + c=Tokenize(s,&tmp); + + j = atoi(tmp[0]) - 1; + k = atoi(tmp[1]) - 1; + + if (j < reax->num_atom_types && k < reax->num_atom_types) { + val = atof(tmp[2]); + if (val > 0.0) { + reax->tbp[j][k].D = val; + reax->tbp[k][j].D = val; + } + + val = atof(tmp[3]); + if (val > 0.0) { + reax->tbp[j][k].r_vdW = 2 * val; + reax->tbp[k][j].r_vdW = 2 * val; + } + + val = atof(tmp[4]); + if (val > 0.0) { + reax->tbp[j][k].alpha = val; + reax->tbp[k][j].alpha = val; + } + + val = atof(tmp[5]); + if (val > 0.0) { + reax->tbp[j][k].r_s = val; + reax->tbp[k][j].r_s = val; + } + + val = atof(tmp[6]); + if (val > 0.0) { + reax->tbp[j][k].r_p = val; + reax->tbp[k][j].r_p = val; + } + + val = atof(tmp[7]); + if (val > 0.0) { + reax->tbp[j][k].r_pp = val; + reax->tbp[k][j].r_pp = val; + } + } + } + + + /* 3-body parameters - + supports multi-well potentials (upto MAX_3BODY_PARAM in mytypes.h) */ + /* clear entries first */ + for( i = 0; i < reax->num_atom_types; ++i ) + for( j = 0; j < reax->num_atom_types; ++j ) + for( k = 0; k < reax->num_atom_types; ++k ) + reax->thbp[i][j][k].cnt = 0; + + /* next line is number of 3-body params and some comments */ + fgets( s, MAX_LINE, fp ); + c = Tokenize( s, &tmp ); + l = atoi( tmp[0] ); + + for( i = 0; i < l; i++ ) { + fgets(s,MAX_LINE,fp); + c=Tokenize(s,&tmp); + + j = atoi(tmp[0]) - 1; + k = atoi(tmp[1]) - 1; + m = atoi(tmp[2]) - 1; + + if (j < reax->num_atom_types && k < reax->num_atom_types && + m < reax->num_atom_types) { + cnt = reax->thbp[j][k][m].cnt; + reax->thbp[j][k][m].cnt++; + reax->thbp[m][k][j].cnt++; + + val = atof(tmp[3]); + reax->thbp[j][k][m].prm[cnt].theta_00 = val; + reax->thbp[m][k][j].prm[cnt].theta_00 = val; + + val = atof(tmp[4]); + reax->thbp[j][k][m].prm[cnt].p_val1 = val; + reax->thbp[m][k][j].prm[cnt].p_val1 = val; + + val = atof(tmp[5]); + reax->thbp[j][k][m].prm[cnt].p_val2 = val; + reax->thbp[m][k][j].prm[cnt].p_val2 = val; + + val = atof(tmp[6]); + reax->thbp[j][k][m].prm[cnt].p_coa1 = val; + reax->thbp[m][k][j].prm[cnt].p_coa1 = val; + + val = atof(tmp[7]); + reax->thbp[j][k][m].prm[cnt].p_val7 = val; + reax->thbp[m][k][j].prm[cnt].p_val7 = val; + + val = atof(tmp[8]); + reax->thbp[j][k][m].prm[cnt].p_pen1 = val; + reax->thbp[m][k][j].prm[cnt].p_pen1 = val; + + val = atof(tmp[9]); + reax->thbp[j][k][m].prm[cnt].p_val4 = val; + reax->thbp[m][k][j].prm[cnt].p_val4 = val; + } + } + + + /* 4-body parameters are entered in compact form. i.e. 0-X-Y-0 + correspond to any type of pair of atoms in 1 and 4 + position. However, explicit X-Y-Z-W takes precedence over the + default description. + supports multi-well potentials (upto MAX_4BODY_PARAM in mytypes.h) + IMPORTANT: for now, directions on how to read multi-entries from ffield + is not clear */ + + /* clear all entries first */ + for( i = 0; i < reax->num_atom_types; ++i ) + for( j = 0; j < reax->num_atom_types; ++j ) + for( k = 0; k < reax->num_atom_types; ++k ) + for( m = 0; m < reax->num_atom_types; ++m ) { + reax->fbp[i][j][k][m].cnt = 0; + tor_flag[i][j][k][m] = 0; + } + + /* next line is number of 4-body params and some comments */ + fgets( s, MAX_LINE, fp ); + c = Tokenize( s, &tmp ); + l = atoi( tmp[0] ); + + for( i = 0; i < l; i++ ) { + fgets( s, MAX_LINE, fp ); + c = Tokenize( s, &tmp ); + + j = atoi(tmp[0]) - 1; + k = atoi(tmp[1]) - 1; + m = atoi(tmp[2]) - 1; + n = atoi(tmp[3]) - 1; + + if (j >= 0 && n >= 0) { // this means the entry is not in compact form + if (j < reax->num_atom_types && k < reax->num_atom_types && + m < reax->num_atom_types && n < reax->num_atom_types) { + /* these flags ensure that this entry take precedence + over the compact form entries */ + tor_flag[j][k][m][n] = 1; + tor_flag[n][m][k][j] = 1; + + reax->fbp[j][k][m][n].cnt = 1; + reax->fbp[n][m][k][j].cnt = 1; + /* cnt = reax->fbp[j][k][m][n].cnt; + reax->fbp[j][k][m][n].cnt++; + reax->fbp[n][m][k][j].cnt++; */ + + val = atof(tmp[4]); + reax->fbp[j][k][m][n].prm[0].V1 = val; + reax->fbp[n][m][k][j].prm[0].V1 = val; + + val = atof(tmp[5]); + reax->fbp[j][k][m][n].prm[0].V2 = val; + reax->fbp[n][m][k][j].prm[0].V2 = val; + + val = atof(tmp[6]); + reax->fbp[j][k][m][n].prm[0].V3 = val; + reax->fbp[n][m][k][j].prm[0].V3 = val; + + val = atof(tmp[7]); + reax->fbp[j][k][m][n].prm[0].p_tor1 = val; + reax->fbp[n][m][k][j].prm[0].p_tor1 = val; + + val = atof(tmp[8]); + reax->fbp[j][k][m][n].prm[0].p_cot1 = val; + reax->fbp[n][m][k][j].prm[0].p_cot1 = val; + } + } + else { /* This means the entry is of the form 0-X-Y-0 */ + if( k < reax->num_atom_types && m < reax->num_atom_types ) + for( p = 0; p < reax->num_atom_types; p++ ) + for( o = 0; o < reax->num_atom_types; o++ ) { + reax->fbp[p][k][m][o].cnt = 1; + reax->fbp[o][m][k][p].cnt = 1; + /* cnt = reax->fbp[p][k][m][o].cnt; + reax->fbp[p][k][m][o].cnt++; + reax->fbp[o][m][k][p].cnt++; */ + + if (tor_flag[p][k][m][o] == 0) { + reax->fbp[p][k][m][o].prm[0].V1 = atof(tmp[4]); + reax->fbp[p][k][m][o].prm[0].V2 = atof(tmp[5]); + reax->fbp[p][k][m][o].prm[0].V3 = atof(tmp[6]); + reax->fbp[p][k][m][o].prm[0].p_tor1 = atof(tmp[7]); + reax->fbp[p][k][m][o].prm[0].p_cot1 = atof(tmp[8]); + } + + if (tor_flag[o][m][k][p] == 0) { + reax->fbp[o][m][k][p].prm[0].V1 = atof(tmp[4]); + reax->fbp[o][m][k][p].prm[0].V2 = atof(tmp[5]); + reax->fbp[o][m][k][p].prm[0].V3 = atof(tmp[6]); + reax->fbp[o][m][k][p].prm[0].p_tor1 = atof(tmp[7]); + reax->fbp[o][m][k][p].prm[0].p_cot1 = atof(tmp[8]); + } + } + } + } + + + + /* next line is number of hydrogen bond params and some comments */ + fgets( s, MAX_LINE, fp ); + c = Tokenize( s, &tmp ); + l = atoi( tmp[0] ); + + for( i = 0; i < l; i++ ) { + fgets( s, MAX_LINE, fp ); + c = Tokenize( s, &tmp ); + + j = atoi(tmp[0]) - 1; + k = atoi(tmp[1]) - 1; + m = atoi(tmp[2]) - 1; + + + if( j < reax->num_atom_types && m < reax->num_atom_types ) { + val = atof(tmp[3]); + reax->hbp[j][k][m].r0_hb = val; + + val = atof(tmp[4]); + reax->hbp[j][k][m].p_hb1 = val; + + val = atof(tmp[5]); + reax->hbp[j][k][m].p_hb2 = val; + + val = atof(tmp[6]); + reax->hbp[j][k][m].p_hb3 = val; + } + } + + + /* deallocate helper storage */ + for( i = 0; i < MAX_TOKENS; i++ ) + free( tmp[i] ); + free( tmp ); + free( s ); + + + /* deallocate tor_flag */ + for( i = 0; i < reax->num_atom_types; i++ ) { + for( j = 0; j < reax->num_atom_types; j++ ) { + for( k = 0; k < reax->num_atom_types; k++ ) { + free( tor_flag[i][j][k] ); + } + free( tor_flag[i][j] ); + } + free( tor_flag[i] ); + } + free( tor_flag ); + + // close file + + fclose(fp); + +#if defined(DEBUG_FOCUS) + fprintf( stderr, "force field read\n" ); +#endif + + return SUCCESS; +} diff --git a/src/USER-REAXC/reaxc_ffield.h b/src/USER-REAXC/reaxc_ffield.h new file mode 100644 index 0000000000..22a580f7f8 --- /dev/null +++ b/src/USER-REAXC/reaxc_ffield.h @@ -0,0 +1,29 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __FFIELD_H_ +#define __FFIELD_H_ + +#include "reaxc_types.h" + +char Read_Force_Field( char*, reax_interaction*, control_params* ); + +#endif diff --git a/src/USER-REAXC/reaxc_forces.cpp b/src/USER-REAXC/reaxc_forces.cpp new file mode 100644 index 0000000000..b1d5874683 --- /dev/null +++ b/src/USER-REAXC/reaxc_forces.cpp @@ -0,0 +1,929 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "forces.h" +#include "bond_orders.h" +#include "bonds.h" +#include "basic_comm.h" +#include "hydrogen_bonds.h" +#include "io_tools.h" +#include "list.h" +#include "lookup.h" +#include "multi_body.h" +#include "nonbonded.h" +#include "qEq.h" +#include "tool_box.h" +#include "torsion_angles.h" +#include "valence_angles.h" +#include "vector.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_forces.h" +#include "reaxc_bond_orders.h" +#include "reaxc_bonds.h" +#include "reaxc_basic_comm.h" +#include "reaxc_hydrogen_bonds.h" +#include "reaxc_io_tools.h" +#include "reaxc_list.h" +#include "reaxc_lookup.h" +#include "reaxc_multi_body.h" +#include "reaxc_nonbonded.h" +#include "reaxc_tool_box.h" +#include "reaxc_torsion_angles.h" +#include "reaxc_valence_angles.h" +#include "reaxc_vector.h" +#endif + +interaction_function Interaction_Functions[NUM_INTRS]; + +void Dummy_Interaction( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control ) +{ +} + + +void Init_Force_Functions( control_params *control ) +{ + Interaction_Functions[0] = BO; + Interaction_Functions[1] = Bonds; //Dummy_Interaction; + Interaction_Functions[2] = Atom_Energy; //Dummy_Interaction; + Interaction_Functions[3] = Valence_Angles; //Dummy_Interaction; + Interaction_Functions[4] = Torsion_Angles; //Dummy_Interaction; + if( control->hbond_cut > 0 ) + Interaction_Functions[5] = Hydrogen_Bonds; + else Interaction_Functions[5] = Dummy_Interaction; + Interaction_Functions[6] = Dummy_Interaction; //empty + Interaction_Functions[7] = Dummy_Interaction; //empty + Interaction_Functions[8] = Dummy_Interaction; //empty + Interaction_Functions[9] = Dummy_Interaction; //empty +} + + +void Compute_Bonded_Forces( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control, + MPI_Comm comm ) +{ + int i; + + /* Mark beginning of a new timestep in bonded energy files */ +#if defined(TEST_ENERGY) + Debug_Marker_Bonded( out_control, data->step ); +#endif + + /* Implement all force calls as function pointers */ + for( i = 0; i < NUM_INTRS; i++ ) { +#if defined(DEBUG) + fprintf( stderr, "p%d: starting f%d\n", system->my_rank, i ); + MPI_Barrier( comm ); +#endif + (Interaction_Functions[i])( system, control, data, workspace, + lists, out_control ); +#if defined(DEBUG) + fprintf( stderr, "p%d: f%d done\n", system->my_rank, i ); + MPI_Barrier( comm ); +#endif + } +} + + +void Compute_NonBonded_Forces( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control, + MPI_Comm comm ) +{ + /* Mark beginning of a new timestep in nonbonded energy files */ +#if defined(TEST_ENERGY) + Debug_Marker_Nonbonded( out_control, data->step ); +#endif + + /* van der Waals and Coulomb interactions */ + if( control->tabulate == 0 ) + vdW_Coulomb_Energy( system, control, data, workspace, + lists, out_control ); + else + Tabulated_vdW_Coulomb_Energy( system, control, data, workspace, + lists, out_control ); + +#if defined(DEBUG) + fprintf( stderr, "p%d: nonbonded forces done\n", system->my_rank ); + MPI_Barrier( comm ); +#endif +} + + + +/* this version of Compute_Total_Force computes forces from + coefficients accumulated by all interaction functions. + Saves enormous time & space! */ +void Compute_Total_Force( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, mpi_datatypes *mpi_data ) +{ + int i, pj; + reax_list *bonds = (*lists) + BONDS; + + for( i = 0; i < system->N; ++i ) + for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) + if( i < bonds->select.bond_list[pj].nbr ) { + if( control->virial == 0 ) + Add_dBond_to_Forces( i, pj, workspace, lists ); + else + Add_dBond_to_Forces_NPT( i, pj, data, workspace, lists ); + } + + //Print_Total_Force( system, data, workspace ); +#if defined(PURE_REAX) + /* now all forces are computed to their partially-final values + based on the neighbors information each processor has had. + final values of force on each atom needs to be computed by adding up + all partially-final pieces */ + Coll( system, mpi_data, workspace->f, mpi_data->mpi_rvec, + sizeof(rvec)/sizeof(void), rvec_unpacker ); + for( i = 0; i < system->n; ++i ) + rvec_Copy( system->my_atoms[i].f, workspace->f[i] ); + +#if defined(TEST_FORCES) + Coll( system, mpi_data, workspace->f_ele, mpi_data->mpi_rvec, rvec_unpacker); + Coll( system, mpi_data, workspace->f_vdw, mpi_data->mpi_rvec, rvec_unpacker); + Coll( system, mpi_data, workspace->f_be, mpi_data->mpi_rvec, rvec_unpacker ); + Coll( system, mpi_data, workspace->f_lp, mpi_data->mpi_rvec, rvec_unpacker ); + Coll( system, mpi_data, workspace->f_ov, mpi_data->mpi_rvec, rvec_unpacker ); + Coll( system, mpi_data, workspace->f_un, mpi_data->mpi_rvec, rvec_unpacker ); + Coll( system, mpi_data, workspace->f_ang, mpi_data->mpi_rvec, rvec_unpacker); + Coll( system, mpi_data, workspace->f_coa, mpi_data->mpi_rvec, rvec_unpacker); + Coll( system, mpi_data, workspace->f_pen, mpi_data->mpi_rvec, rvec_unpacker); + Coll( system, mpi_data, workspace->f_hb, mpi_data->mpi_rvec, rvec_unpacker ); + Coll( system, mpi_data, workspace->f_tor, mpi_data->mpi_rvec, rvec_unpacker); + Coll( system, mpi_data, workspace->f_con, mpi_data->mpi_rvec, rvec_unpacker); +#endif + +#endif +} + +void Validate_Lists( reax_system *system, storage *workspace, reax_list **lists, + int step, int n, int N, int numH, MPI_Comm comm ) +{ + int i, comp, Hindex; + reax_list *bonds, *hbonds; + reallocate_data *realloc; + realloc = &(workspace->realloc); + + /* bond list */ + if( N > 0 ) { + bonds = *lists + BONDS; + + for( i = 0; i < N; ++i ) { + // if( i < n ) - we need to update ghost estimates for delayed nbrings + system->my_atoms[i].num_bonds = MAX(Num_Entries(i,bonds)*2, MIN_BONDS); + + //if( End_Index(i, bonds) >= Start_Index(i+1, bonds)-2 ) + //workspace->realloc.bonds = 1; + + if( i < N-1 ) + comp = Start_Index(i+1, bonds); + else comp = bonds->num_intrs; + + if( End_Index(i, bonds) > comp ) { + fprintf( stderr, "step%d-bondchk failed: i=%d end(i)=%d str(i+1)=%d\n", + step, i, End_Index(i,bonds), comp ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } + } + } + + + /* hbonds list */ + if( numH > 0 ) { + hbonds = *lists + HBONDS; + + for( i = 0; i < n; ++i ) { + Hindex = system->my_atoms[i].Hindex; + if( Hindex > -1 ) { + system->my_atoms[i].num_hbonds = + (int)(MAX( Num_Entries(Hindex, hbonds)*SAFER_ZONE, MIN_HBONDS )); + + //if( Num_Entries(i, hbonds) >= + //(Start_Index(i+1,hbonds)-Start_Index(i,hbonds))*0.90/*DANGER_ZONE*/){ + // workspace->realloc.hbonds = 1; + + if( Hindex < numH-1 ) + comp = Start_Index(Hindex+1, hbonds); + else comp = hbonds->num_intrs; + + if( End_Index(Hindex, hbonds) > comp ) { + fprintf(stderr,"step%d-hbondchk failed: H=%d end(H)=%d str(H+1)=%d\n", + step, Hindex, End_Index(Hindex,hbonds), comp ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } + } + } + } +} + + +real Compute_H( real r, real gamma, real *ctap ) +{ + real taper, dr3gamij_1, dr3gamij_3; + + taper = ctap[7] * r + ctap[6]; + taper = taper * r + ctap[5]; + taper = taper * r + ctap[4]; + taper = taper * r + ctap[3]; + taper = taper * r + ctap[2]; + taper = taper * r + ctap[1]; + taper = taper * r + ctap[0]; + + dr3gamij_1 = ( r*r*r + gamma ); + dr3gamij_3 = pow( dr3gamij_1 , 0.33333333333333 ); + return taper * EV_to_KCALpMOL / dr3gamij_3; +} + + +real Compute_tabH( real r_ij, int ti, int tj ) +{ + int r, tmin, tmax; + real val, dif, base; + LR_lookup_table *t; + + tmin = MIN( ti, tj ); + tmax = MAX( ti, tj ); + t = &( LR[tmin][tmax] ); + + /* cubic spline interpolation */ + r = (int)(r_ij * t->inv_dx); + if( r == 0 ) ++r; + base = (real)(r+1) * t->dx; + dif = r_ij - base; + val = ((t->ele[r].d*dif + t->ele[r].c)*dif + t->ele[r].b)*dif + + t->ele[r].a; + val *= EV_to_KCALpMOL / C_ele; + + return val; +} + + +void Init_Forces( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, reax_list **lists, + output_controls *out_control, MPI_Comm comm ) { + int i, j, pj; + int start_i, end_i; + int type_i, type_j; + int Htop, btop_i, btop_j, num_bonds, num_hbonds; + int ihb, jhb, ihb_top, jhb_top; + int local, flag, renbr; + real r_ij, cutoff; + sparse_matrix *H; + reax_list *far_nbrs, *bonds, *hbonds; + single_body_parameters *sbp_i, *sbp_j; + two_body_parameters *twbp; + far_neighbor_data *nbr_pj; + reax_atom *atom_i, *atom_j; + + far_nbrs = *lists + FAR_NBRS; + bonds = *lists + BONDS; + hbonds = *lists + HBONDS; + + for( i = 0; i < system->n; ++i ) + workspace->bond_mark[i] = 0; + for( i = system->n; i < system->N; ++i ) { + workspace->bond_mark[i] = 1000; // put ghost atoms to an infinite distance + //workspace->done_after[i] = Start_Index( i, far_nbrs ); + } + + H = workspace->H; + H->n = system->n; + Htop = 0; + num_bonds = 0; + num_hbonds = 0; + btop_i = btop_j = 0; + renbr = (data->step-data->prev_steps) % control->reneighbor == 0; + + for( i = 0; i < system->N; ++i ) { + atom_i = &(system->my_atoms[i]); + type_i = atom_i->type; + start_i = Start_Index(i, far_nbrs); + end_i = End_Index(i, far_nbrs); + btop_i = End_Index( i, bonds ); + sbp_i = &(system->reax_param.sbp[type_i]); + + if( i < system->n ) { + local = 1; + cutoff = control->nonb_cut; + } + else { + local = 0; + cutoff = control->bond_cut; + } + + ihb = -1; + ihb_top = -1; + if( local ) { + H->start[i] = Htop; + H->entries[Htop].j = i; + H->entries[Htop].val = sbp_i->eta; + ++Htop; + + if( control->hbond_cut > 0 ) { + ihb = sbp_i->p_hbond; + if( ihb == 1 ) + ihb_top = End_Index( atom_i->Hindex, hbonds ); + else ihb_top = -1; + } + } + + /* update i-j distance - check if j is within cutoff */ + for( pj = start_i; pj < end_i; ++pj ) { + nbr_pj = &( far_nbrs->select.far_nbr_list[pj] ); + j = nbr_pj->nbr; + atom_j = &(system->my_atoms[j]); + //fprintf( stderr, "%d%d i=%d x_i: %f %f %f,j=%d x_j: %f %f %f, d=%f\n", + // MIN(atom_i->orig_id, atom_j->orig_id), + // MAX(atom_i->orig_id, atom_j->orig_id), + // i, atom_i->x[0], atom_i->x[1], atom_i->x[2], + // j, atom_j->x[0], atom_j->x[1], atom_j->x[2], nbr_pj->d ); + if( renbr ) { + if(nbr_pj->d <= cutoff) + flag = 1; + else flag = 0; + } + else{ + nbr_pj->dvec[0] = atom_j->x[0] - atom_i->x[0]; + nbr_pj->dvec[1] = atom_j->x[1] - atom_i->x[1]; + nbr_pj->dvec[2] = atom_j->x[2] - atom_i->x[2]; + nbr_pj->d = rvec_Norm_Sqr( nbr_pj->dvec ); + if( nbr_pj->d <= SQR(cutoff) ) { + nbr_pj->d = sqrt(nbr_pj->d); + flag = 1; + } + else { + flag = 0; + } + } + + if( flag ){ + type_j = atom_j->type; + r_ij = nbr_pj->d; + sbp_j = &(system->reax_param.sbp[type_j]); + twbp = &(system->reax_param.tbp[type_i][type_j]); + + if( local ) { + /* H matrix entry */ + if( j < system->n || atom_i->orig_id < atom_j->orig_id ) {//tryQEq||1 + H->entries[Htop].j = j; + //fprintf( stdout, "%d%d %d %d\n", + // MIN(atom_i->orig_id, atom_j->orig_id), + // MAX(atom_i->orig_id, atom_j->orig_id), + // MIN(atom_i->orig_id, atom_j->orig_id), + // MAX(atom_i->orig_id, atom_j->orig_id) ); + if( control->tabulate == 0 ) + H->entries[Htop].val = Compute_H(r_ij,twbp->gamma,workspace->Tap); + else H->entries[Htop].val = Compute_tabH(r_ij, type_i, type_j); + ++Htop; + } + + /* hydrogen bond lists */ + if( control->hbond_cut > 0 && (ihb==1 || ihb==2) && + nbr_pj->d <= control->hbond_cut ) { + // fprintf( stderr, "%d %d\n", atom1, atom2 ); + jhb = sbp_j->p_hbond; + if( ihb == 1 && jhb == 2 ) { + hbonds->select.hbond_list[ihb_top].nbr = j; + hbonds->select.hbond_list[ihb_top].scl = 1; + hbonds->select.hbond_list[ihb_top].ptr = nbr_pj; + ++ihb_top; + ++num_hbonds; + } + else if( j < system->n && ihb == 2 && jhb == 1 ) { + jhb_top = End_Index( atom_j->Hindex, hbonds ); + hbonds->select.hbond_list[jhb_top].nbr = i; + hbonds->select.hbond_list[jhb_top].scl = -1; + hbonds->select.hbond_list[jhb_top].ptr = nbr_pj; + Set_End_Index( atom_j->Hindex, jhb_top+1, hbonds ); + ++num_hbonds; + } + } + } + + /* uncorrected bond orders */ + if( //(workspace->bond_mark[i] < 3 || workspace->bond_mark[j] < 3) && + nbr_pj->d <= control->bond_cut && + BOp( workspace, bonds, control->bo_cut, + i , btop_i, nbr_pj, sbp_i, sbp_j, twbp ) ) { + num_bonds += 2; + ++btop_i; + + if( workspace->bond_mark[j] > workspace->bond_mark[i] + 1 ) + workspace->bond_mark[j] = workspace->bond_mark[i] + 1; + else if( workspace->bond_mark[i] > workspace->bond_mark[j] + 1 ) { + workspace->bond_mark[i] = workspace->bond_mark[j] + 1; + //if( workspace->bond_mark[i] == 1000 ) + // workspace->done_after[i] = pj; + } + //fprintf( stdout, "%d%d - %d(%d) %d(%d)\n", + // i , j, i, workspace->bond_mark[i], j, workspace->bond_mark[j] ); + } + } + } + + Set_End_Index( i, btop_i, bonds ); + if( local ) { + H->end[i] = Htop; + if( ihb == 1 ) + Set_End_Index( atom_i->Hindex, ihb_top, hbonds ); + } + } + + //fprintf( stderr, "after the first init loop\n" ); + /*for( i = system->n; i < system->N; ++i ) + if( workspace->bond_mark[i] > 3 ) { + start_i = Start_Index(i, bonds); + end_i = End_Index(i, bonds); + num_bonds -= (end_i - start_i); + Set_End_Index(i, start_i, bonds ); + }*/ + + /*for( i = system->n; i < system->N; ++i ) { + start_i = Start_Index(i, far_nbrs); + end_i = workspace->done_after[i]; + + if( workspace->bond_mark[i] >= 2 && start_i < end_i ) { + atom_i = &(system->my_atoms[i]); + type_i = atom_i->type; + btop_i = End_Index( i, bonds ); + sbp_i = &(system->reax_param.sbp[type_i]); + + for( pj = start_i; pj < end_i; ++pj ) { + nbr_pj = &( far_nbrs->select.far_nbr_list[pj] ); + j = nbr_pj->nbr; + + if( workspace->bond_mark[j] >= 2 && nbr_pj->d <= control->bond_cut ) { + atom_j = &(system->my_atoms[j]); + type_j = atom_j->type; + sbp_j = &(system->reax_param.sbp[type_j]); + twbp = &(system->reax_param.tbp[type_i][type_j]); + + if( BOp( workspace, bonds, control->bo_cut, + i , btop_i, nbr_pj, sbp_i, sbp_j, twbp ) ) { + num_bonds += 2; + ++btop_i; + + if( workspace->bond_mark[j] > workspace->bond_mark[i] + 1 ) + workspace->bond_mark[j] = workspace->bond_mark[i] + 1; + else if( workspace->bond_mark[i] > workspace->bond_mark[j] + 1 ) + workspace->bond_mark[i] = workspace->bond_mark[j] + 1; + + //fprintf( stdout, "%d%d - %d(%d) %d(%d) new\n", + // i , j, i, workspace->bond_mark[i], j, workspace->bond_mark[j] ); + } + } + } + Set_End_Index( i, btop_i, bonds ); + } + }*/ + + workspace->realloc.Htop = Htop; + workspace->realloc.num_bonds = num_bonds; + workspace->realloc.num_hbonds = num_hbonds; + +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d @ step%d: Htop = %d num_bonds = %d num_hbonds = %d\n", + system->my_rank, data->step, Htop, num_bonds, num_hbonds ); + MPI_Barrier( comm ); +#endif +#if defined( DEBUG ) + Print_Bonds( system, bonds, "debugbonds.out" ); + Print_Bond_List2( system, bonds, "pbonds.out" ); + Print_Sparse_Matrix( system, H ); + for( i = 0; i < H->n; ++i ) + for( j = H->start[i]; j < H->end[i]; ++j ) + fprintf( stderr, "%d %d %.15e\n", + MIN(system->my_atoms[i].orig_id, + system->my_atoms[H->entries[j].j].orig_id), + MAX(system->my_atoms[i].orig_id, + system->my_atoms[H->entries[j].j].orig_id), + H->entries[j].val ); +#endif + + Validate_Lists( system, workspace, lists, data->step, + system->n, system->N, system->numH, comm ); +} + + +void Init_Forces_noQEq( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control, + MPI_Comm comm ) { + int i, j, pj; + int start_i, end_i; + int type_i, type_j; + int btop_i, btop_j, num_bonds, num_hbonds; + int ihb, jhb, ihb_top, jhb_top; + int local, flag, renbr; + real r_ij, cutoff; + reax_list *far_nbrs, *bonds, *hbonds; + single_body_parameters *sbp_i, *sbp_j; + two_body_parameters *twbp; + far_neighbor_data *nbr_pj; + reax_atom *atom_i, *atom_j; + + far_nbrs = *lists + FAR_NBRS; + bonds = *lists + BONDS; + hbonds = *lists + HBONDS; + + for( i = 0; i < system->n; ++i ) + workspace->bond_mark[i] = 0; + for( i = system->n; i < system->N; ++i ) { + workspace->bond_mark[i] = 1000; // put ghost atoms to an infinite distance + //workspace->done_after[i] = Start_Index( i, far_nbrs ); + } + + num_bonds = 0; + num_hbonds = 0; + btop_i = btop_j = 0; + renbr = (data->step-data->prev_steps) % control->reneighbor == 0; + + for( i = 0; i < system->N; ++i ) { + atom_i = &(system->my_atoms[i]); + type_i = atom_i->type; + start_i = Start_Index(i, far_nbrs); + end_i = End_Index(i, far_nbrs); + btop_i = End_Index( i, bonds ); + sbp_i = &(system->reax_param.sbp[type_i]); + + if( i < system->n ) { + local = 1; + cutoff = MAX( control->hbond_cut, control->bond_cut ); + } + else { + local = 0; + cutoff = control->bond_cut; + } + + ihb = -1; + ihb_top = -1; + if( local && control->hbond_cut > 0 ) { + ihb = sbp_i->p_hbond; + if( ihb == 1 ) + ihb_top = End_Index( atom_i->Hindex, hbonds ); + else ihb_top = -1; + } + + /* update i-j distance - check if j is within cutoff */ + for( pj = start_i; pj < end_i; ++pj ) { + nbr_pj = &( far_nbrs->select.far_nbr_list[pj] ); + j = nbr_pj->nbr; + atom_j = &(system->my_atoms[j]); + + if( renbr ) { + if( nbr_pj->d <= cutoff ) + flag = 1; + else flag = 0; + } + else{ + nbr_pj->dvec[0] = atom_j->x[0] - atom_i->x[0]; + nbr_pj->dvec[1] = atom_j->x[1] - atom_i->x[1]; + nbr_pj->dvec[2] = atom_j->x[2] - atom_i->x[2]; + nbr_pj->d = rvec_Norm_Sqr( nbr_pj->dvec ); + if( nbr_pj->d <= SQR(cutoff) ) { + nbr_pj->d = sqrt(nbr_pj->d); + flag = 1; + } + else { + flag = 0; + } + } + + if( flag ) { + type_j = atom_j->type; + r_ij = nbr_pj->d; + sbp_j = &(system->reax_param.sbp[type_j]); + twbp = &(system->reax_param.tbp[type_i][type_j]); + + if( local ) { + /* hydrogen bond lists */ + if( control->hbond_cut > 0 && (ihb==1 || ihb==2) && + nbr_pj->d <= control->hbond_cut ) { + // fprintf( stderr, "%d %d\n", atom1, atom2 ); + jhb = sbp_j->p_hbond; + if( ihb == 1 && jhb == 2 ) { + hbonds->select.hbond_list[ihb_top].nbr = j; + hbonds->select.hbond_list[ihb_top].scl = 1; + hbonds->select.hbond_list[ihb_top].ptr = nbr_pj; + ++ihb_top; + ++num_hbonds; + } + else if( j < system->n && ihb == 2 && jhb == 1 ) { + jhb_top = End_Index( atom_j->Hindex, hbonds ); + hbonds->select.hbond_list[jhb_top].nbr = i; + hbonds->select.hbond_list[jhb_top].scl = -1; + hbonds->select.hbond_list[jhb_top].ptr = nbr_pj; + Set_End_Index( atom_j->Hindex, jhb_top+1, hbonds ); + ++num_hbonds; + } + } + } + + + /* uncorrected bond orders */ + if( //(workspace->bond_mark[i] < 3 || workspace->bond_mark[j] < 3) && + nbr_pj->d <= control->bond_cut && + BOp( workspace, bonds, control->bo_cut, + i , btop_i, nbr_pj, sbp_i, sbp_j, twbp ) ) { + num_bonds += 2; + ++btop_i; + + if( workspace->bond_mark[j] > workspace->bond_mark[i] + 1 ) + workspace->bond_mark[j] = workspace->bond_mark[i] + 1; + else if( workspace->bond_mark[i] > workspace->bond_mark[j] + 1 ) { + workspace->bond_mark[i] = workspace->bond_mark[j] + 1; + //if( workspace->bond_mark[i] == 1000 ) + // workspace->done_after[i] = pj; + } + //fprintf( stdout, "%d%d - %d(%d) %d(%d)\n", + // i , j, i, workspace->bond_mark[i], j, workspace->bond_mark[j] ); + } + } + } + + Set_End_Index( i, btop_i, bonds ); + if( local && ihb == 1 ) + Set_End_Index( atom_i->Hindex, ihb_top, hbonds ); + } + + /*for( i = system->n; i < system->N; ++i ) + if( workspace->bond_mark[i] > 3 ) { + start_i = Start_Index(i, bonds); + end_i = End_Index(i, bonds); + num_bonds -= (end_i - start_i); + Set_End_Index(i, start_i, bonds ); + }*/ + + workspace->realloc.num_bonds = num_bonds; + workspace->realloc.num_hbonds = num_hbonds; + +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d @ step%d: num_bonds = %d num_hbonds = %d\n", + system->my_rank, data->step, num_bonds, num_hbonds ); + MPI_Barrier( comm ); +#endif +#if defined( DEBUG ) + Print_Bonds( system, bonds, "debugbonds.out" ); + Print_Bond_List2( system, bonds, "pbonds.out" ); +#endif + + Validate_Lists( system, workspace, lists, data->step, + system->n, system->N, system->numH, comm ); +} + + +void Estimate_Storages( reax_system *system, control_params *control, + reax_list **lists, int *Htop, int *hb_top, + int *bond_top, int *num_3body, MPI_Comm comm ) +{ + int i, j, pj; + int start_i, end_i; + int type_i, type_j; + int ihb, jhb; + int local; + real cutoff; + real r_ij, r2; + real C12, C34, C56; + real BO, BO_s, BO_pi, BO_pi2; + reax_list *far_nbrs; + single_body_parameters *sbp_i, *sbp_j; + two_body_parameters *twbp; + far_neighbor_data *nbr_pj; + reax_atom *atom_i, *atom_j; + + far_nbrs = *lists + FAR_NBRS; + *Htop = 0; + memset( hb_top, 0, sizeof(int) * system->local_cap ); + memset( bond_top, 0, sizeof(int) * system->total_cap ); + *num_3body = 0; + + for( i = 0; i < system->N; ++i ) { + atom_i = &(system->my_atoms[i]); + type_i = atom_i->type; + start_i = Start_Index(i, far_nbrs); + end_i = End_Index(i, far_nbrs); + sbp_i = &(system->reax_param.sbp[type_i]); + + if( i < system->n ) { + local = 1; + cutoff = control->nonb_cut; + ++(*Htop); + ihb = sbp_i->p_hbond; + } + else { + local = 0; + cutoff = control->bond_cut; + ihb = -1; + } + + for( pj = start_i; pj < end_i; ++pj ) { + nbr_pj = &( far_nbrs->select.far_nbr_list[pj] ); + j = nbr_pj->nbr; + atom_j = &(system->my_atoms[j]); + + if(nbr_pj->d <= cutoff) { + type_j = system->my_atoms[j].type; + r_ij = nbr_pj->d; + sbp_j = &(system->reax_param.sbp[type_j]); + twbp = &(system->reax_param.tbp[type_i][type_j]); + + if( local ) { + if( j < system->n || atom_i->orig_id < atom_j->orig_id ) //tryQEq ||1 + ++(*Htop); + + /* hydrogen bond lists */ + if( control->hbond_cut > 0.1 && (ihb==1 || ihb==2) && + nbr_pj->d <= control->hbond_cut ) { + jhb = sbp_j->p_hbond; + if( ihb == 1 && jhb == 2 ) + ++hb_top[i]; + else if( j < system->n && ihb == 2 && jhb == 1 ) + ++hb_top[j]; + } + } + + /* uncorrected bond orders */ + if( nbr_pj->d <= control->bond_cut ) { + r2 = SQR(r_ij); + + if( sbp_i->r_s > 0.0 && sbp_j->r_s > 0.0) { + C12 = twbp->p_bo1 * pow( r_ij / twbp->r_s, twbp->p_bo2 ); + BO_s = (1.0 + control->bo_cut) * exp( C12 ); + } + else BO_s = C12 = 0.0; + + if( sbp_i->r_pi > 0.0 && sbp_j->r_pi > 0.0) { + C34 = twbp->p_bo3 * pow( r_ij / twbp->r_p, twbp->p_bo4 ); + BO_pi = exp( C34 ); + } + else BO_pi = C34 = 0.0; + + if( sbp_i->r_pi_pi > 0.0 && sbp_j->r_pi_pi > 0.0) { + C56 = twbp->p_bo5 * pow( r_ij / twbp->r_pp, twbp->p_bo6 ); + BO_pi2= exp( C56 ); + } + else BO_pi2 = C56 = 0.0; + + /* Initially BO values are the uncorrected ones, page 1 */ + BO = BO_s + BO_pi + BO_pi2; + + if( BO >= control->bo_cut ) { + ++bond_top[i]; + ++bond_top[j]; + } + } + } + } + } + + *Htop = (int)(MAX( *Htop * SAFE_ZONE, MIN_CAP * MIN_HENTRIES )); + for( i = 0; i < system->n; ++i ) + hb_top[i] = (int)(MAX( hb_top[i] * SAFER_ZONE, MIN_HBONDS )); + + for( i = 0; i < system->N; ++i ) { + *num_3body += SQR(bond_top[i]); + //if( i < system->n ) + bond_top[i] = MAX( bond_top[i] * 2, MIN_BONDS ); + //else bond_top[i] = MAX_BONDS; + } + +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d @ estimate storages: Htop = %d, num_3body = %d\n", + system->my_rank, *Htop, *num_3body ); + MPI_Barrier( comm ); +#endif +} + + +void Compute_Forces( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control, + mpi_datatypes *mpi_data ) +{ + MPI_Comm comm; + int qeq_flag; +#if defined(LOG_PERFORMANCE) + real t_start = 0; + + //MPI_Barrier( mpi_data->world ); + if( system->my_rank == MASTER_NODE ) + t_start = Get_Time( ); +#endif + + comm = mpi_data->world; + /********* init forces ************/ +#if defined(PURE_REAX) + if( control->qeq_freq && (data->step-data->prev_steps)%control->qeq_freq==0 ) + qeq_flag = 1; + else qeq_flag = 0; +#elif defined(LAMMPS_REAX) + qeq_flag = 0; +#endif + + if( qeq_flag ) + Init_Forces( system, control, data, workspace, lists, out_control, comm ); + else + Init_Forces_noQEq( system, control, data, workspace, + lists, out_control, comm ); + +#if defined(LOG_PERFORMANCE) + //MPI_Barrier( mpi_data->world ); + if( system->my_rank == MASTER_NODE ) + Update_Timing_Info( &t_start, &(data->timing.init_forces) ); +#endif + + + /********* bonded interactions ************/ + Compute_Bonded_Forces( system, control, data, workspace, + lists, out_control, mpi_data->world ); + +#if defined(LOG_PERFORMANCE) + //MPI_Barrier( mpi_data->world ); + if( system->my_rank == MASTER_NODE ) + Update_Timing_Info( &t_start, &(data->timing.bonded) ); +#endif +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d @ step%d: completed bonded\n", + system->my_rank, data->step ); + MPI_Barrier( mpi_data->world ); +#endif + + + /**************** qeq ************************/ +#if defined(PURE_REAX) + if( qeq_flag ) + QEq( system, control, data, workspace, out_control, mpi_data ); + +#if defined(LOG_PERFORMANCE) + //MPI_Barrier( mpi_data->world ); + if( system->my_rank == MASTER_NODE ) + Update_Timing_Info( &t_start, &(data->timing.qEq) ); +#endif +#if defined(DEBUG_FOCUS) + fprintf(stderr, "p%d @ step%d: qeq completed\n", system->my_rank, data->step); + MPI_Barrier( mpi_data->world ); +#endif +#endif //PURE_REAX + + + /********* nonbonded interactions ************/ + Compute_NonBonded_Forces( system, control, data, workspace, + lists, out_control, mpi_data->world ); + +#if defined(LOG_PERFORMANCE) + //MPI_Barrier( mpi_data->world ); + if( system->my_rank == MASTER_NODE ) + Update_Timing_Info( &t_start, &(data->timing.nonb) ); +#endif +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d @ step%d: nonbonded forces completed\n", + system->my_rank, data->step ); + MPI_Barrier( mpi_data->world ); +#endif + + + /*********** total force ***************/ + Compute_Total_Force( system, control, data, workspace, lists, mpi_data ); + +#if defined(LOG_PERFORMANCE) + //MPI_Barrier( mpi_data->world ); + if( system->my_rank == MASTER_NODE ) + Update_Timing_Info( &t_start, &(data->timing.bonded) ); +#endif +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d @ step%d: total forces computed\n", + system->my_rank, data->step ); + //Print_Total_Force( system, data, workspace ); + MPI_Barrier( mpi_data->world ); +#endif + +#if defined(TEST_FORCES) + Print_Force_Files( system, control, data, workspace, + lists, out_control, mpi_data ); +#endif +} diff --git a/src/USER-REAXC/reaxc_forces.h b/src/USER-REAXC/reaxc_forces.h new file mode 100644 index 0000000000..6723bc9660 --- /dev/null +++ b/src/USER-REAXC/reaxc_forces.h @@ -0,0 +1,35 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __FORCES_H_ +#define __FORCES_H_ + +#include "reaxc_types.h" +#include "reaxc_defs.h" + +extern interaction_function Interaction_Functions[NUM_INTRS]; + +void Init_Force_Functions( control_params* ); +void Compute_Forces( reax_system*, control_params*, simulation_data*, + storage*, reax_list**, output_controls*, mpi_datatypes* ); +void Estimate_Storages( reax_system*, control_params*, reax_list**, + int*, int*, int*, int*, MPI_Comm ); +#endif diff --git a/src/USER-REAXC/reaxc_hydrogen_bonds.cpp b/src/USER-REAXC/reaxc_hydrogen_bonds.cpp new file mode 100644 index 0000000000..86013abcbd --- /dev/null +++ b/src/USER-REAXC/reaxc_hydrogen_bonds.cpp @@ -0,0 +1,220 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "hydrogen_bonds.h" +#include "bond_orders.h" +#include "list.h" +#include "valence_angles.h" +#include "vector.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_hydrogen_bonds.h" +#include "reaxc_bond_orders.h" +#include "reaxc_list.h" +#include "reaxc_valence_angles.h" +#include "reaxc_vector.h" +#endif + + +void Hydrogen_Bonds( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control ) +{ + int i, j, k, pi, pk; + int type_i, type_j, type_k; + int start_j, end_j, hb_start_j, hb_end_j; + int hblist[MAX_BONDS]; + int itr, top; + int num_hb_intrs = 0; + ivec rel_jk; + real r_ij, r_jk, theta, cos_theta, sin_xhz4, cos_xhz1, sin_theta2; + real e_hb, exp_hb2, exp_hb3, CEhb1, CEhb2, CEhb3; + rvec dcos_theta_di, dcos_theta_dj, dcos_theta_dk; + rvec dvec_jk, force, ext_press; + // rtensor temp_rtensor, total_rtensor; + hbond_parameters *hbp; + bond_order_data *bo_ij; + bond_data *pbond_ij; + far_neighbor_data *nbr_jk; + reax_list *bonds, *hbonds; + bond_data *bond_list; + hbond_data *hbond_list; + + bonds = (*lists) + BONDS; + bond_list = bonds->select.bond_list; + hbonds = (*lists) + HBONDS; + hbond_list = hbonds->select.hbond_list; + + /* loops below discover the Hydrogen bonds between i-j-k triplets. + here j is H atom and there has to be some bond between i and j. + Hydrogen bond is between j and k. + so in this function i->X, j->H, k->Z when we map + variables onto the ones in the handout.*/ + for( j = 0; j < system->n; ++j ) + /* j has to be of type H */ + if( system->reax_param.sbp[system->my_atoms[j].type].p_hbond == 1 ) { + /*set j's variables */ + type_j = system->my_atoms[j].type; + start_j = Start_Index(j, bonds); + end_j = End_Index(j, bonds); + hb_start_j = Start_Index( system->my_atoms[j].Hindex, hbonds ); + hb_end_j = End_Index( system->my_atoms[j].Hindex, hbonds ); + + top = 0; + for( pi = start_j; pi < end_j; ++pi ) { + pbond_ij = &( bond_list[pi] ); + i = pbond_ij->nbr; + bo_ij = &(pbond_ij->bo_data); + type_i = system->my_atoms[i].type; + + if( system->reax_param.sbp[type_i].p_hbond == 2 && + bo_ij->BO >= HB_THRESHOLD ) + hblist[top++] = pi; + } + + // fprintf( stderr, "j: %d, top: %d, hb_start_j: %d, hb_end_j:%d\n", + // j, top, hb_start_j, hb_end_j ); + + for( pk = hb_start_j; pk < hb_end_j; ++pk ) { + /* set k's varibles */ + k = hbond_list[pk].nbr; + type_k = system->my_atoms[k].type; + nbr_jk = hbond_list[pk].ptr; + r_jk = nbr_jk->d; + rvec_Scale( dvec_jk, hbond_list[pk].scl, nbr_jk->dvec ); + + for( itr = 0; itr < top; ++itr ) { + pi = hblist[itr]; + pbond_ij = &( bonds->select.bond_list[pi] ); + i = pbond_ij->nbr; + + if( system->my_atoms[i].orig_id != system->my_atoms[k].orig_id ) { + bo_ij = &(pbond_ij->bo_data); + type_i = system->my_atoms[i].type; + r_ij = pbond_ij->d; + hbp = &(system->reax_param.hbp[ type_i ][ type_j ][ type_k ]); + ++num_hb_intrs; + + Calculate_Theta( pbond_ij->dvec, pbond_ij->d, dvec_jk, r_jk, + &theta, &cos_theta ); + /* the derivative of cos(theta) */ + Calculate_dCos_Theta( pbond_ij->dvec, pbond_ij->d, dvec_jk, r_jk, + &dcos_theta_di, &dcos_theta_dj, + &dcos_theta_dk ); + + /* hyrogen bond energy*/ + sin_theta2 = sin( theta/2.0 ); + sin_xhz4 = SQR(sin_theta2); + sin_xhz4 *= sin_xhz4; + cos_xhz1 = ( 1.0 - cos_theta ); + exp_hb2 = exp( -hbp->p_hb2 * bo_ij->BO ); + exp_hb3 = exp( -hbp->p_hb3 * ( hbp->r0_hb / r_jk + + r_jk / hbp->r0_hb - 2.0 ) ); + + data->my_en.e_hb += e_hb = + hbp->p_hb1 * (1.0 - exp_hb2) * exp_hb3 * sin_xhz4; + + CEhb1 = hbp->p_hb1 * hbp->p_hb2 * exp_hb2 * exp_hb3 * sin_xhz4; + CEhb2 = -hbp->p_hb1/2.0 * (1.0 - exp_hb2) * exp_hb3 * cos_xhz1; + CEhb3 = -hbp->p_hb3 * + (-hbp->r0_hb / SQR(r_jk) + 1.0 / hbp->r0_hb) * e_hb; + + /*fprintf( stdout, + "%6d%6d%6d%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f\n", + system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, + system->my_atoms[k].orig_id, + r_jk, theta, hbp->p_hb1, exp_hb2, hbp->p_hb3, hbp->r0_hb, + exp_hb3, sin_xhz4, e_hb ); */ + + /* hydrogen bond forces */ + bo_ij->Cdbo += CEhb1; // dbo term + + if( control->virial == 0 ) { + // dcos terms + rvec_ScaledAdd( workspace->f[i], +CEhb2, dcos_theta_di ); + rvec_ScaledAdd( workspace->f[j], +CEhb2, dcos_theta_dj ); + rvec_ScaledAdd( workspace->f[k], +CEhb2, dcos_theta_dk ); + // dr terms + rvec_ScaledAdd( workspace->f[j], -CEhb3/r_jk, dvec_jk ); + rvec_ScaledAdd( workspace->f[k], +CEhb3/r_jk, dvec_jk ); + } + else { + /* for pressure coupling, terms that are not related to bond order + derivatives are added directly into pressure vector/tensor */ + rvec_Scale( force, +CEhb2, dcos_theta_di ); // dcos terms + rvec_Add( workspace->f[i], force ); + rvec_iMultiply( ext_press, pbond_ij->rel_box, force ); + rvec_ScaledAdd( data->my_ext_press, 1.0, ext_press ); + + rvec_ScaledAdd( workspace->f[j], +CEhb2, dcos_theta_dj ); + + ivec_Scale( rel_jk, hbond_list[pk].scl, nbr_jk->rel_box ); + rvec_Scale( force, +CEhb2, dcos_theta_dk ); + rvec_Add( workspace->f[k], force ); + rvec_iMultiply( ext_press, rel_jk, force ); + rvec_ScaledAdd( data->my_ext_press, 1.0, ext_press ); + // dr terms + rvec_ScaledAdd( workspace->f[j], -CEhb3/r_jk, dvec_jk ); + + rvec_Scale( force, CEhb3/r_jk, dvec_jk ); + rvec_Add( workspace->f[k], force ); + rvec_iMultiply( ext_press, rel_jk, force ); + rvec_ScaledAdd( data->my_ext_press, 1.0, ext_press ); + } + +#ifdef TEST_ENERGY + /* fprintf( out_control->ehb, + "%24.15e%24.15e%24.15e\n%24.15e%24.15e%24.15e\n%24.15e%24.15e%24.15e\n", + dcos_theta_di[0], dcos_theta_di[1], dcos_theta_di[2], + dcos_theta_dj[0], dcos_theta_dj[1], dcos_theta_dj[2], + dcos_theta_dk[0], dcos_theta_dk[1], dcos_theta_dk[2]); + fprintf( out_control->ehb, "%24.15e%24.15e%24.15e\n", + CEhb1, CEhb2, CEhb3 ); */ + fprintf( out_control->ehb, + //"%6d%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e\n", + "%6d%6d%6d%12.4f%12.4f%12.4f%12.4f%12.4f\n", + system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, + system->my_atoms[k].orig_id, + r_jk, theta, bo_ij->BO, e_hb, data->my_en.e_hb ); +#endif +#ifdef TEST_FORCES + Add_dBO( system, lists, j, pi, +CEhb1, workspace->f_hb ); //dbo term + // dcos terms + rvec_ScaledAdd( workspace->f_hb[i], +CEhb2, dcos_theta_di ); + rvec_ScaledAdd( workspace->f_hb[j], +CEhb2, dcos_theta_dj ); + rvec_ScaledAdd( workspace->f_hb[k], +CEhb2, dcos_theta_dk ); + // dr terms + rvec_ScaledAdd( workspace->f_hb[j], -CEhb3/r_jk, dvec_jk ); + rvec_ScaledAdd( workspace->f_hb[k], +CEhb3/r_jk, dvec_jk ); +#endif + } + } + } + } + +#if defined(DEBUG) + fprintf( stderr, "Number of hydrogen bonds: %d\n", num_hb_intrs ); + fprintf( stderr, "Hydrogen Bond Energy: %g\n", data->my_en.e_hb ); + fprintf( stderr, "hydbonds: ext_press (%24.15e %24.15e %24.15e)\n", + data->ext_press[0], data->ext_press[1], data->ext_press[2] ); +#endif +} diff --git a/src/USER-REAXC/reaxc_hydrogen_bonds.h b/src/USER-REAXC/reaxc_hydrogen_bonds.h new file mode 100644 index 0000000000..bb26928d62 --- /dev/null +++ b/src/USER-REAXC/reaxc_hydrogen_bonds.h @@ -0,0 +1,30 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __HBONDS_H_ +#define __HBONDS_H_ + +#include "reaxc_types.h" + +void Hydrogen_Bonds( reax_system*, control_params*, simulation_data*, + storage*, reax_list**, output_controls* ); + +#endif diff --git a/src/USER-REAXC/reaxc_init_md.cpp b/src/USER-REAXC/reaxc_init_md.cpp new file mode 100644 index 0000000000..52466eaec9 --- /dev/null +++ b/src/USER-REAXC/reaxc_init_md.cpp @@ -0,0 +1,916 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "init_md.h" +#include "allocate.h" +#include "box.h" +#include "comm_tools.h" +#include "forces.h" +#include "grid.h" +#include "integrate.h" +#include "io_tools.h" +#include "list.h" +#include "lookup.h" +#include "neighbors.h" +#include "random.h" +#include "reset_tools.h" +#include "system_props.h" +#include "tool_box.h" +#include "vector.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_init_md.h" +#include "reaxc_allocate.h" +#include "reaxc_forces.h" +#include "reaxc_io_tools.h" +#include "reaxc_list.h" +#include "reaxc_lookup.h" +#include "reaxc_reset_tools.h" +#include "reaxc_system_props.h" +#include "reaxc_tool_box.h" +#include "reaxc_vector.h" +#endif + + +#if defined(PURE_REAX) +/************************ initialize system ************************/ +int Reposition_Atoms( reax_system *system, control_params *control, + simulation_data *data, mpi_datatypes *mpi_data, + char *msg ) +{ + int i; + rvec dx; + + /* reposition atoms */ + if( control->reposition_atoms == 0 ) { //fit atoms to periodic box + rvec_MakeZero( dx ); + } + else if( control->reposition_atoms == 1 ) { //put center of mass to center + rvec_Scale( dx, 0.5, system->big_box.box_norms ); + rvec_ScaledAdd( dx, -1., data->xcm ); + } + else if( control->reposition_atoms == 2 ) { //put center of mass to origin + rvec_Scale( dx, -1., data->xcm ); + } + else { + strcpy( msg, "reposition_atoms: invalid option" ); + return FAILURE; + } + + for( i = 0; i < system->n; ++i ) + // Inc_on_T3_Gen( system->my_atoms[i].x, dx, &(system->big_box) ); + rvec_Add( system->my_atoms[i].x, dx ); + + return SUCCESS; +} + + + +void Generate_Initial_Velocities( reax_system *system, real T ) +{ + int i; + real m, scale, norm; + + + if( T <= 0.1 ) { + for( i = 0; i < system->n; i++ ) + rvec_MakeZero( system->my_atoms[i].v ); + } + else { + Randomize(); + + for( i = 0; i < system->n; i++ ) { + rvec_Random( system->my_atoms[i].v ); + + norm = rvec_Norm_Sqr( system->my_atoms[i].v ); + m = system->reax_param.sbp[ system->my_atoms[i].type ].mass; + scale = sqrt( m * norm / (3.0 * K_B * T) ); + + rvec_Scale( system->my_atoms[i].v, 1./scale, system->my_atoms[i].v ); + + // fprintf( stderr, "v = %f %f %f\n", + // system->my_atoms[i].v[0], + // system->my_atoms[i].v[1], + // system->my_atoms[i].v[2] ); + + // fprintf( stderr, "scale = %f\n", scale ); + // fprintf( stderr, "v = %f %f %f\n", + // system->my_atoms[i].v[0], + // system->my_atoms[i].v[1], + // system->my_atoms[i].v[2] ); + } + } +} + + +int Init_System( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + mpi_datatypes *mpi_data, char *msg ) +{ + int i; + reax_atom *atom; + int nrecv[MAX_NBRS]; + + Setup_New_Grid( system, control, mpi_data->world ); +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d GRID:\n", system->my_rank ); + Print_Grid( &(system->my_grid), stderr ); +#endif + Bin_My_Atoms( system, &(workspace->realloc) ); + Reorder_My_Atoms( system, workspace ); + + /* estimate N and total capacity */ + for( i = 0; i < MAX_NBRS; ++i ) nrecv[i] = 0; + system->max_recved = 0; + system->N = SendRecv( system, mpi_data, mpi_data->boundary_atom_type, nrecv, + Estimate_Boundary_Atoms, Unpack_Estimate_Message, 1 ); + system->total_cap = MAX( (int)(system->N * SAFE_ZONE), MIN_CAP ); + Bin_Boundary_Atoms( system ); + + /* estimate numH and Hcap */ + system->numH = 0; + if( control->hbond_cut > 0 ) + for( i = 0; i < system->n; ++i ) { + atom = &(system->my_atoms[i]); + if( system->reax_param.sbp[ atom->type ].p_hbond == 1 ) + atom->Hindex = system->numH++; + else atom->Hindex = -1; + } + system->Hcap = MAX( system->numH * SAFER_ZONE, MIN_CAP ); + + //Allocate_System( system, system->local_cap, system->total_cap, msg ); +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: n=%d local_cap=%d\n", + system->my_rank, system->n, system->local_cap ); + fprintf( stderr, "p%d: N=%d total_cap=%d\n", + system->my_rank, system->N, system->total_cap ); + fprintf( stderr, "p%d: numH=%d H_cap=%d\n", + system->my_rank, system->numH, system->Hcap ); +#endif + + // if( Reposition_Atoms( system, control, data, mpi_data, msg ) == FAILURE ) + // return FAILURE; + + /* initialize velocities so that desired init T can be attained */ + if( !control->restart || (control->restart && control->random_vel) ) + Generate_Initial_Velocities( system, control->T_init ); + + return SUCCESS; +} + + +/************************ initialize simulation data ************************/ +int Init_Simulation_Data( reax_system *system, control_params *control, + simulation_data *data, mpi_datatypes *mpi_data, + char *msg ) +{ + Reset_Simulation_Data( data, control->virial ); + + if( !control->restart ) + data->step = data->prev_steps = 0; + + Compute_Total_Mass( system, data, mpi_data->comm_mesh3D ); + Compute_Center_of_Mass( system, data, mpi_data, mpi_data->comm_mesh3D ); + Compute_Kinetic_Energy( system, data, mpi_data->comm_mesh3D ); + + switch( control->ensemble ){ + case NVE: + data->N_f = 3 * system->bigN; + Evolve = Velocity_Verlet_NVE; + break; + + case bNVT: + data->N_f = 3 * system->bigN + 1; + Evolve = Velocity_Verlet_Berendsen_NVT; + break; + + case nhNVT: + fprintf( stderr, "WARNING: Nose-Hoover NVT is still under testing.\n" ); + //return FAILURE; + data->N_f = 3 * system->bigN + 1; + Evolve = Velocity_Verlet_Nose_Hoover_NVT_Klein; + if( !control->restart || (control->restart && control->random_vel) ) { + data->therm.G_xi = control->Tau_T * + (2.0 * data->sys_en.e_kin - data->N_f * K_B * control->T ); + data->therm.v_xi = data->therm.G_xi * control->dt; + data->therm.v_xi_old = 0; + data->therm.xi = 0; + } + break; + + case sNPT: /* Semi-Isotropic NPT */ + data->N_f = 3 * system->bigN + 4; + Evolve = Velocity_Verlet_Berendsen_NPT; + if( !control->restart ) + Reset_Pressures( data ); + break; + + case iNPT: /* Isotropic NPT */ + data->N_f = 3 * system->bigN + 2; + Evolve = Velocity_Verlet_Berendsen_NPT; + if( !control->restart ) + Reset_Pressures( data ); + break; + + case NPT: /* Anisotropic NPT */ + strcpy( msg, "init_simulation_data: option not yet implemented" ); + return FAILURE; + + data->N_f = 3 * system->bigN + 9; + Evolve = Velocity_Verlet_Berendsen_NPT; + /*if( !control->restart ) { + data->therm.G_xi = control->Tau_T * + (2.0 * data->my_en.e_Kin - data->N_f * K_B * control->T ); + data->therm.v_xi = data->therm.G_xi * control->dt; + data->iso_bar.eps = 0.33333 * log(system->box.volume); + data->inv_W = 1.0 / + ( data->N_f * K_B * control->T * SQR(control->Tau_P) ); + Compute_Pressure( system, control, data, out_control ); + }*/ + break; + + default: + strcpy( msg, "init_simulation_data: ensemble not recognized" ); + return FAILURE; + } + + /* initialize the timer(s) */ + MPI_Barrier( mpi_data->world ); // wait for everyone to come here + if( system->my_rank == MASTER_NODE ) { + data->timing.start = Get_Time( ); +#if defined(LOG_PERFORMANCE) + Reset_Timing( &data->timing ); +#endif + } + + +#if defined(DEBUG) + fprintf( stderr, "data->N_f: %8.3f\n", data->N_f ); +#endif + return SUCCESS; +} + +#elif defined(LAMMPS_REAX) +int Init_System( reax_system *system, control_params *control, char *msg ) +{ + int i; + reax_atom *atom; + + /* determine the local and total capacity */ + system->local_cap = MAX( (int)(system->n * SAFE_ZONE), MIN_CAP ); + system->total_cap = MAX( (int)(system->N * SAFE_ZONE), MIN_CAP ); + + /* estimate numH and Hcap */ + system->numH = 0; + if( control->hbond_cut > 0 ) + for( i = 0; i < system->n; ++i ) { + atom = &(system->my_atoms[i]); + if( system->reax_param.sbp[ atom->type ].p_hbond == 1 ) + atom->Hindex = system->numH++; + else atom->Hindex = -1; + } + system->Hcap = (int)(MAX( system->numH * SAFER_ZONE, MIN_CAP )); + +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: n=%d local_cap=%d\n", + system->my_rank, system->n, system->local_cap ); + fprintf( stderr, "p%d: N=%d total_cap=%d\n", + system->my_rank, system->N, system->total_cap ); + fprintf( stderr, "p%d: numH=%d H_cap=%d\n", + system->my_rank, system->numH, system->Hcap ); +#endif + + return SUCCESS; +} + + +int Init_Simulation_Data( reax_system *system, control_params *control, + simulation_data *data, char *msg ) +{ + Reset_Simulation_Data( data, control->virial ); + + /* initialize the timer(s) */ + if( system->my_rank == MASTER_NODE ) { + data->timing.start = Get_Time( ); +#if defined(LOG_PERFORMANCE) + Reset_Timing( &data->timing ); +#endif + } + + //if( !control->restart ) + data->step = data->prev_steps = 0; + + return SUCCESS; +} +#endif + + + +/************************ initialize workspace ************************/ +/* Initialize Taper params */ +void Init_Taper( control_params *control, storage *workspace, MPI_Comm comm ) +{ + real d1, d7; + real swa, swa2, swa3; + real swb, swb2, swb3; + + swa = control->nonb_low; + swb = control->nonb_cut; + + if( fabs( swa ) > 0.01 ) + fprintf( stderr, "Warning: non-zero lower Taper-radius cutoff\n" ); + + if( swb < 0 ) { + fprintf( stderr, "Negative upper Taper-radius cutoff\n" ); + MPI_Abort( comm, INVALID_INPUT ); + } + else if( swb < 5 ) + fprintf( stderr, "Warning: very low Taper-radius cutoff: %f\n", swb ); + + d1 = swb - swa; + d7 = pow( d1, 7.0 ); + swa2 = SQR( swa ); + swa3 = CUBE( swa ); + swb2 = SQR( swb ); + swb3 = CUBE( swb ); + + workspace->Tap[7] = 20.0 / d7; + workspace->Tap[6] = -70.0 * (swa + swb) / d7; + workspace->Tap[5] = 84.0 * (swa2 + 3.0*swa*swb + swb2) / d7; + workspace->Tap[4] = -35.0 * (swa3 + 9.0*swa2*swb + 9.0*swa*swb2 + swb3 ) / d7; + workspace->Tap[3] = 140.0 * (swa3*swb + 3.0*swa2*swb2 + swa*swb3 ) / d7; + workspace->Tap[2] =-210.0 * (swa3*swb2 + swa2*swb3) / d7; + workspace->Tap[1] = 140.0 * swa3 * swb3 / d7; + workspace->Tap[0] = (-35.0*swa3*swb2*swb2 + 21.0*swa2*swb3*swb2 + + 7.0*swa*swb3*swb3 + swb3*swb3*swb ) / d7; +} + + +int Init_Workspace( reax_system *system, control_params *control, + storage *workspace, MPI_Comm comm, char *msg ) +{ + int ret; + + ret = Allocate_Workspace( system, control, workspace, + system->local_cap, system->total_cap, comm, msg ); + if( ret != SUCCESS ) + return ret; + + memset( &(workspace->realloc), 0, sizeof(reallocate_data) ); + Reset_Workspace( system, workspace ); + + /* Initialize the Taper function */ + Init_Taper( control, workspace, comm ); + + return SUCCESS; +} + + +/************** setup communication data structures **************/ +int Init_MPI_Datatypes( reax_system *system, storage *workspace, + mpi_datatypes *mpi_data, MPI_Comm comm, char *msg ) +{ +#if defined(PURE_REAX) + int i, block[11]; + MPI_Aint base, disp[11]; + MPI_Datatype type[11]; + mpi_atom sample; + boundary_atom b_sample; + restart_atom r_sample; + rvec rvec_sample; + rvec2 rvec2_sample; +#endif + + /* setup the world */ + mpi_data->world = comm; + MPI_Comm_size( comm, &(system->wsize) ); + +#if defined(PURE_REAX) + /* init mpi buffers */ + mpi_data->in1_buffer = NULL; + mpi_data->in2_buffer = NULL; + + /* mpi_atom - [orig_id, imprt_id, type, num_bonds, num_hbonds, name, + x, v, f_old, s, t] */ + block[0] = block[1] = block[2] = block[3] = block[4] = 1; + block[5] = 8; + block[6] = block[7] = block[8] = 3; + block[9] = block[10] = 4; + + MPI_Address( &(sample.orig_id), disp + 0 ); + MPI_Address( &(sample.imprt_id), disp + 1 ); + MPI_Address( &(sample.type), disp + 2 ); + MPI_Address( &(sample.num_bonds), disp + 3 ); + MPI_Address( &(sample.num_hbonds), disp + 4 ); + MPI_Address( &(sample.name), disp + 5 ); + MPI_Address( &(sample.x[0]), disp + 6 ); + MPI_Address( &(sample.v[0]), disp + 7 ); + MPI_Address( &(sample.f_old[0]), disp + 8 ); + MPI_Address( &(sample.s[0]), disp + 9 ); + MPI_Address( &(sample.t[0]), disp + 10 ); + + base = (MPI_Aint)(&(sample)); + for( i = 0; i < 11; ++i ) disp[i] -= base; + + type[0] = type[1] = type[2] = type[3] = type[4] = MPI_INT; + type[5] = MPI_CHAR; + type[6] = type[7] = type[8] = type[9] = type[10] = MPI_DOUBLE; + + MPI_Type_struct( 11, block, disp, type, &(mpi_data->mpi_atom_type) ); + MPI_Type_commit( &(mpi_data->mpi_atom_type) ); + + /* boundary_atom - [orig_id, imprt_id, type, num_bonds, num_hbonds, x] */ + block[0] = block[1] = block[2] = block[3] = block[4] = 1; + block[5] = 3; + + MPI_Address( &(b_sample.orig_id), disp + 0 ); + MPI_Address( &(b_sample.imprt_id), disp + 1 ); + MPI_Address( &(b_sample.type), disp + 2 ); + MPI_Address( &(b_sample.num_bonds), disp + 3 ); + MPI_Address( &(b_sample.num_hbonds), disp + 4 ); + MPI_Address( &(b_sample.x[0]), disp + 5 ); + + base = (MPI_Aint)(&(b_sample)); + for( i = 0; i < 6; ++i ) disp[i] -= base; + + type[0] = type[1] = type[2] = type[3] = type[4] = MPI_INT; + type[5] = MPI_DOUBLE; + + MPI_Type_struct( 6, block, disp, type, &(mpi_data->boundary_atom_type) ); + MPI_Type_commit( &(mpi_data->boundary_atom_type) ); + + /* mpi_rvec */ + block[0] = 3; + MPI_Address( &(rvec_sample[0]), disp + 0 ); + base = disp[0]; + for( i = 0; i < 1; ++i ) disp[i] -= base; + type[0] = MPI_DOUBLE; + MPI_Type_struct( 1, block, disp, type, &(mpi_data->mpi_rvec) ); + MPI_Type_commit( &(mpi_data->mpi_rvec) ); + + /* mpi_rvec2 */ + block[0] = 2; + MPI_Address( &(rvec2_sample[0]), disp + 0 ); + base = disp[0]; + for( i = 0; i < 1; ++i ) disp[i] -= base; + type[0] = MPI_DOUBLE; + MPI_Type_struct( 1, block, disp, type, &(mpi_data->mpi_rvec2) ); + MPI_Type_commit( &(mpi_data->mpi_rvec2) ); + + /* restart_atom - [orig_id, type, name[8], x, v] */ + block[0] = block[1] = 1 ; + block[2] = 8; + block[3] = block[4] = 3; + + MPI_Address( &(r_sample.orig_id), disp + 0 ); + MPI_Address( &(r_sample.type), disp + 1 ); + MPI_Address( &(r_sample.name), disp + 2 ); + MPI_Address( &(r_sample.x[0]), disp + 3 ); + MPI_Address( &(r_sample.v[0]), disp + 4 ); + + base = (MPI_Aint)(&(r_sample)); + for( i = 0; i < 5; ++i ) disp[i] -= base; + + type[0] = type[1] = MPI_INT; + type[2] = MPI_CHAR; + type[3] = type[4] = MPI_DOUBLE; + + MPI_Type_struct( 5, block, disp, type, &(mpi_data->restart_atom_type) ); + MPI_Type_commit( &(mpi_data->restart_atom_type) ); +#endif + + return SUCCESS; +} + + +/********************** allocate lists *************************/ +#if defined(PURE_REAX) +int Init_Lists( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, reax_list **lists, + mpi_datatypes *mpi_data, char *msg ) +{ + int i, num_nbrs; + int total_hbonds, total_bonds, bond_cap, num_3body, cap_3body, Htop; + int *hb_top, *bond_top; + MPI_Comm comm; + + comm = mpi_data->world; + //for( i = 0; i < MAX_NBRS; ++i ) nrecv[i] = system->my_nbrs[i].est_recv; + //system->N = SendRecv( system, mpi_data, mpi_data->boundary_atom_type, nrecv, + // Sort_Boundary_Atoms, Unpack_Exchange_Message, 1 ); + num_nbrs = Estimate_NumNeighbors( system, lists ); + if(!Make_List( system->total_cap, num_nbrs, TYP_FAR_NEIGHBOR, + *lists+FAR_NBRS, comm )){ + fprintf(stderr, "Problem in initializing far nbrs list. Terminating!\n"); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: allocated far_nbrs: num_far=%d, space=%dMB\n", + system->my_rank, num_nbrs, + (int)(num_nbrs*sizeof(far_neighbor_data)/(1024*1024)) ); +#endif + + Generate_Neighbor_Lists( system, data, workspace, lists ); + bond_top = (int*) calloc( system->total_cap, sizeof(int) ); + hb_top = (int*) calloc( system->local_cap, sizeof(int) ); + Estimate_Storages( system, control, lists, + &Htop, hb_top, bond_top, &num_3body, comm ); + + Allocate_Matrix( &(workspace->H), system->local_cap, Htop, comm ); + workspace->L = NULL; + workspace->U = NULL; +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: allocated H matrix: Htop=%d, space=%dMB\n", + system->my_rank, Htop, + (int)(Htop * sizeof(sparse_matrix_entry) / (1024*1024)) ); +#endif + + if( control->hbond_cut > 0 ) { + /* init H indexes */ + total_hbonds = 0; + for( i = 0; i < system->n; ++i ) { + system->my_atoms[i].num_hbonds = hb_top[i]; + total_hbonds += hb_top[i]; + } + total_hbonds = MAX( total_hbonds*SAFER_ZONE, MIN_CAP*MIN_HBONDS ); + + if( !Make_List( system->Hcap, total_hbonds, TYP_HBOND, + *lists+HBONDS, comm ) ) { + fprintf( stderr, "not enough space for hbonds list. terminating!\n" ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: allocated hbonds: total_hbonds=%d, space=%dMB\n", + system->my_rank, total_hbonds, + (int)(total_hbonds*sizeof(hbond_data)/(1024*1024)) ); +#endif + } + + /* bonds list */ + //Allocate_Bond_List( system->N, bond_top, (*lists)+BONDS ); + //num_bonds = bond_top[system->N-1]; + total_bonds = 0; + for( i = 0; i < system->N; ++i ) { + system->my_atoms[i].num_bonds = bond_top[i]; + total_bonds += bond_top[i]; + } + bond_cap = MAX( total_bonds*SAFE_ZONE, MIN_CAP*MIN_BONDS ); + + if( !Make_List( system->total_cap, bond_cap, TYP_BOND, + *lists+BONDS, comm ) ) { + fprintf( stderr, "not enough space for bonds list. terminating!\n" ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: allocated bonds: total_bonds=%d, space=%dMB\n", + system->my_rank, bond_cap, + (int)(bond_cap*sizeof(bond_data)/(1024*1024)) ); +#endif + + /* 3bodies list */ + cap_3body = MAX( num_3body*SAFE_ZONE, MIN_3BODIES ); + if( !Make_List( bond_cap, cap_3body, TYP_THREE_BODY, + *lists+THREE_BODIES, comm ) ){ + fprintf( stderr, "Problem in initializing angles list. Terminating!\n" ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: allocated 3-body list: num_3body=%d, space=%dMB\n", + system->my_rank, cap_3body, + (int)(cap_3body*sizeof(three_body_interaction_data)/(1024*1024)) ); +#endif + +#if defined(TEST_FORCES) + if( !Make_List( system->total_cap, bond_cap*8, TYP_DDELTA, + *lists+DDELTAS, comm ) ) { + fprintf( stderr, "Problem in initializing dDelta list. Terminating!\n" ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } + fprintf( stderr, "p%d: allocated dDelta list: num_ddelta=%d space=%ldMB\n", + system->my_rank, bond_cap*30, + bond_cap*8*sizeof(dDelta_data)/(1024*1024) ); + + if( !Make_List( bond_cap, bond_cap*50, TYP_DBO, *lists+DBOS, comm ) ) { + fprintf( stderr, "Problem in initializing dBO list. Terminating!\n" ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } + fprintf( stderr, "p%d: allocated dbond list: num_dbonds=%d space=%ldMB\n", + system->my_rank, bond_cap*MAX_BONDS*3, + bond_cap*MAX_BONDS*3*sizeof(dbond_data)/(1024*1024) ); +#endif + + free( hb_top ); + free( bond_top ); + + return SUCCESS; +} +#elif defined(LAMMPS_REAX) +int Init_Lists( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, reax_list **lists, + mpi_datatypes *mpi_data, char *msg ) +{ + int i, num_nbrs; + int total_hbonds, total_bonds, bond_cap, num_3body, cap_3body, Htop; + int *hb_top, *bond_top; + int nrecv[MAX_NBRS]; + MPI_Comm comm; + + comm = mpi_data->world; + bond_top = (int*) calloc( system->total_cap, sizeof(int) ); + hb_top = (int*) calloc( system->local_cap, sizeof(int) ); + Estimate_Storages( system, control, lists, + &Htop, hb_top, bond_top, &num_3body, comm ); + + if( control->hbond_cut > 0 ) { + /* init H indexes */ + total_hbonds = 0; + for( i = 0; i < system->n; ++i ) { + system->my_atoms[i].num_hbonds = hb_top[i]; + total_hbonds += hb_top[i]; + } + total_hbonds = (int)(MAX( total_hbonds*SAFER_ZONE, MIN_CAP*MIN_HBONDS )); + + if( !Make_List( system->Hcap, total_hbonds, TYP_HBOND, + *lists+HBONDS, comm ) ) { + fprintf( stderr, "not enough space for hbonds list. terminating!\n" ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: allocated hbonds: total_hbonds=%d, space=%dMB\n", + system->my_rank, total_hbonds, + (int)(total_hbonds*sizeof(hbond_data)/(1024*1024)) ); +#endif + } + + /* bonds list */ + //Allocate_Bond_List( system->N, bond_top, (*lists)+BONDS ); + //num_bonds = bond_top[system->N-1]; + total_bonds = 0; + for( i = 0; i < system->N; ++i ) { + system->my_atoms[i].num_bonds = bond_top[i]; + total_bonds += bond_top[i]; + } + bond_cap = (int)(MAX( total_bonds*SAFE_ZONE, MIN_CAP*MIN_BONDS )); + + if( !Make_List( system->total_cap, bond_cap, TYP_BOND, + *lists+BONDS, comm ) ) { + fprintf( stderr, "not enough space for bonds list. terminating!\n" ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: allocated bonds: total_bonds=%d, space=%dMB\n", + system->my_rank, bond_cap, + (int)(bond_cap*sizeof(bond_data)/(1024*1024)) ); +#endif + + /* 3bodies list */ + cap_3body = (int)(MAX( num_3body*SAFE_ZONE, MIN_3BODIES )); + if( !Make_List( bond_cap, cap_3body, TYP_THREE_BODY, + *lists+THREE_BODIES, comm ) ){ + fprintf( stderr, "Problem in initializing angles list. Terminating!\n" ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: allocated 3-body list: num_3body=%d, space=%dMB\n", + system->my_rank, cap_3body, + (int)(cap_3body*sizeof(three_body_interaction_data)/(1024*1024)) ); +#endif + +#if defined(TEST_FORCES) + if( !Make_List( system->total_cap, bond_cap*8, TYP_DDELTA, + *lists+DDELTAS, comm ) ) { + fprintf( stderr, "Problem in initializing dDelta list. Terminating!\n" ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } + fprintf( stderr, "p%d: allocated dDelta list: num_ddelta=%d space=%ldMB\n", + system->my_rank, bond_cap*30, + bond_cap*8*sizeof(dDelta_data)/(1024*1024) ); + + if( !Make_List( bond_cap, bond_cap*50, TYP_DBO, (*lists)+DBOS, comm ) ) { + fprintf( stderr, "Problem in initializing dBO list. Terminating!\n" ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } + fprintf( stderr, "p%d: allocated dbond list: num_dbonds=%d space=%ldMB\n", + system->my_rank, bond_cap*MAX_BONDS*3, + bond_cap*MAX_BONDS*3*sizeof(dbond_data)/(1024*1024) ); +#endif + + free( hb_top ); + free( bond_top ); + + return SUCCESS; +} +#endif + + + +#if defined(PURE_REAX) +void Initialize( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control, + mpi_datatypes *mpi_data ) +{ + char msg[MAX_STR]; + + if( Init_MPI_Datatypes( system, workspace, mpi_data, MPI_COMM_WORLD, msg ) == + FAILURE ) { + fprintf( stderr, "p%d: init_mpi_datatypes: could not create datatypes\n", + system->my_rank ); + fprintf( stderr, "p%d: mpi_data couldn't be initialized! terminating.\n", + system->my_rank ); + MPI_Abort( mpi_data->world, CANNOT_INITIALIZE ); + } +#if defined(DEBUG) + fprintf( stderr, "p%d: initialized mpi datatypes\n", system->my_rank ); +#endif + + if( Init_System(system, control, data, workspace, mpi_data, msg) == FAILURE ){ + fprintf( stderr, "p%d: %s\n", system->my_rank, msg ); + fprintf( stderr, "p%d: system could not be initialized! terminating.\n", + system->my_rank ); + MPI_Abort( mpi_data->world, CANNOT_INITIALIZE ); + } +#if defined(DEBUG) + fprintf( stderr, "p%d: system initialized\n", system->my_rank ); +#endif + + if( Init_Simulation_Data(system, control, data, mpi_data, msg) == FAILURE ) { + fprintf( stderr, "p%d: %s\n", system->my_rank, msg ); + fprintf( stderr, "p%d: sim_data couldn't be initialized! terminating.\n", + system->my_rank ); + MPI_Abort( mpi_data->world, CANNOT_INITIALIZE ); + } +#if defined(DEBUG) + fprintf( stderr, "p%d: initialized simulation data\n", system->my_rank ); +#endif + + if( Init_Workspace( system, control, workspace, mpi_data->world, msg ) == + FAILURE ) { + fprintf( stderr, "p%d:init_workspace: not enough memory\n", + system->my_rank ); + fprintf( stderr, "p%d:workspace couldn't be initialized! terminating.\n", + system->my_rank ); + MPI_Abort( mpi_data->world, CANNOT_INITIALIZE ); + } +#if defined(DEBUG) + fprintf( stderr, "p%d: initialized workspace\n", system->my_rank ); +#endif + + if( Init_Lists( system, control, data, workspace, lists, mpi_data, msg ) == + FAILURE ) { + fprintf( stderr, "p%d: %s\n", system->my_rank, msg ); + fprintf( stderr, "p%d: system could not be initialized! terminating.\n", + system->my_rank ); + MPI_Abort( mpi_data->world, CANNOT_INITIALIZE ); + } +#if defined(DEBUG) + fprintf( stderr, "p%d: initialized lists\n", system->my_rank ); +#endif + + if(Init_Output_Files(system,control,out_control,mpi_data,msg) == FAILURE) { + fprintf( stderr, "p%d: %s\n", system->my_rank, msg ); + fprintf( stderr, "p%d: could not open output files! terminating...\n", + system->my_rank ); + MPI_Abort( mpi_data->world, CANNOT_INITIALIZE ); + } +#if defined(DEBUG) + fprintf( stderr, "p%d: output files opened\n", system->my_rank ); +#endif + + if( control->tabulate ) { + if( Init_Lookup_Tables(system,control,workspace,mpi_data,msg) == FAILURE ) { + fprintf( stderr, "p%d: %s\n", system->my_rank, msg ); + fprintf( stderr, "p%d: couldn't create lookup table! terminating.\n", + system->my_rank ); + MPI_Abort( mpi_data->world, CANNOT_INITIALIZE ); + } +#if defined(DEBUG) + fprintf( stderr, "p%d: initialized lookup tables\n", system->my_rank ); +#endif + } + + Init_Force_Functions( control ); +#if defined(DEBUG) + fprintf( stderr, "p%d: initialized force functions\n", system->my_rank ); +#endif + /*#ifdef TEST_FORCES + Init_Force_Test_Functions(); + fprintf(stderr,"p%d: initialized force test functions\n",system->my_rank); + #endif */ +} + +#elif defined(LAMMPS_REAX) +void Initialize( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control, + mpi_datatypes *mpi_data, MPI_Comm comm ) +{ + char msg[MAX_STR]; + + + if( Init_MPI_Datatypes(system, workspace, mpi_data, comm, msg) == FAILURE ) { + fprintf( stderr, "p%d: init_mpi_datatypes: could not create datatypes\n", + system->my_rank ); + fprintf( stderr, "p%d: mpi_data couldn't be initialized! terminating.\n", + system->my_rank ); + MPI_Abort( mpi_data->world, CANNOT_INITIALIZE ); + } +#if defined(DEBUG) + fprintf( stderr, "p%d: initialized mpi datatypes\n", system->my_rank ); +#endif + + if( Init_System(system, control, msg) == FAILURE ){ + fprintf( stderr, "p%d: %s\n", system->my_rank, msg ); + fprintf( stderr, "p%d: system could not be initialized! terminating.\n", + system->my_rank ); + MPI_Abort( mpi_data->world, CANNOT_INITIALIZE ); + } +#if defined(DEBUG) + fprintf( stderr, "p%d: system initialized\n", system->my_rank ); +#endif + + if( Init_Simulation_Data( system, control, data, msg ) == FAILURE ) { + fprintf( stderr, "p%d: %s\n", system->my_rank, msg ); + fprintf( stderr, "p%d: sim_data couldn't be initialized! terminating.\n", + system->my_rank ); + MPI_Abort( mpi_data->world, CANNOT_INITIALIZE ); + } +#if defined(DEBUG) + fprintf( stderr, "p%d: initialized simulation data\n", system->my_rank ); +#endif + + if( Init_Workspace( system, control, workspace, mpi_data->world, msg ) == + FAILURE ) { + fprintf( stderr, "p%d:init_workspace: not enough memory\n", + system->my_rank ); + fprintf( stderr, "p%d:workspace couldn't be initialized! terminating.\n", + system->my_rank ); + MPI_Abort( mpi_data->world, CANNOT_INITIALIZE ); + } +#if defined(DEBUG) + fprintf( stderr, "p%d: initialized workspace\n", system->my_rank ); +#endif + + if( Init_Lists( system, control, data, workspace, lists, mpi_data, msg ) == + FAILURE ) { + fprintf( stderr, "p%d: %s\n", system->my_rank, msg ); + fprintf( stderr, "p%d: system could not be initialized! terminating.\n", + system->my_rank ); + MPI_Abort( mpi_data->world, CANNOT_INITIALIZE ); + } +#if defined(DEBUG) + fprintf( stderr, "p%d: initialized lists\n", system->my_rank ); +#endif + + if( Init_Output_Files(system,control,out_control,mpi_data,msg)== FAILURE) { + fprintf( stderr, "p%d: %s\n", system->my_rank, msg ); + fprintf( stderr, "p%d: could not open output files! terminating...\n", + system->my_rank ); + MPI_Abort( mpi_data->world, CANNOT_INITIALIZE ); + } +#if defined(DEBUG) + fprintf( stderr, "p%d: output files opened\n", system->my_rank ); +#endif + + if( control->tabulate ) { + if( Init_Lookup_Tables( system, control, workspace, mpi_data, msg ) == FAILURE ) { + fprintf( stderr, "p%d: %s\n", system->my_rank, msg ); + fprintf( stderr, "p%d: couldn't create lookup table! terminating.\n", + system->my_rank ); + MPI_Abort( mpi_data->world, CANNOT_INITIALIZE ); + } +#if defined(DEBUG) + fprintf( stderr, "p%d: initialized lookup tables\n", system->my_rank ); +#endif + } + + + Init_Force_Functions( control ); +#if defined(DEBUG) + fprintf( stderr, "p%d: initialized force functions\n", system->my_rank ); +#endif + /*#if defined(TEST_FORCES) + Init_Force_Test_Functions(); + fprintf(stderr,"p%d: initialized force test functions\n",system->my_rank); + #endif*/ +} +#endif diff --git a/src/USER-REAXC/reaxc_init_md.h b/src/USER-REAXC/reaxc_init_md.h new file mode 100644 index 0000000000..c7896f6821 --- /dev/null +++ b/src/USER-REAXC/reaxc_init_md.h @@ -0,0 +1,35 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __INIT_MD_H_ +#define __INIT_MD_H_ + +#include "reaxc_types.h" + +#if defined(PURE_REAX) +void Initialize( reax_system*, control_params*, simulation_data*, + storage*, reax_list**, output_controls*, mpi_datatypes* ); +#elif defined(LAMMPS_REAX) +void Initialize( reax_system*, control_params*, simulation_data*, storage*, + reax_list**, output_controls*, mpi_datatypes*, MPI_Comm ); +#endif + +#endif diff --git a/src/USER-REAXC/reaxc_io_tools.cpp b/src/USER-REAXC/reaxc_io_tools.cpp new file mode 100644 index 0000000000..4020a3785e --- /dev/null +++ b/src/USER-REAXC/reaxc_io_tools.cpp @@ -0,0 +1,1712 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "io_tools.h" +#include "basic_comm.h" +#include "list.h" +#include "reset_tools.h" +#include "system_props.h" +#include "tool_box.h" +#include "traj.h" +#include "vector.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_io_tools.h" +#include "reaxc_basic_comm.h" +#include "reaxc_list.h" +#include "reaxc_reset_tools.h" +#include "reaxc_system_props.h" +#include "reaxc_tool_box.h" +#include "reaxc_traj.h" +#include "reaxc_vector.h" +#endif + +print_interaction Print_Interactions[NUM_INTRS]; + +/************************ initialize output controls ************************/ +int Init_Output_Files( reax_system *system, control_params *control, + output_controls *out_control, mpi_datatypes *mpi_data, + char *msg ) +{ + char temp[MAX_STR]; + int ret; + + if( out_control->write_steps > 0 ){ + ret = Init_Traj( system, control, out_control, mpi_data, msg ); + if( ret == FAILURE ) + return ret; + } + + if( system->my_rank == MASTER_NODE ) { + /* These files are written only by the master node */ + if( out_control->energy_update_freq > 0 ) { +#if defined(PURE_REAX) + /* init out file */ + sprintf( temp, "%s.out", control->sim_name ); + if( (out_control->out = fopen( temp, "w" )) != NULL ) { +#if !defined(DEBUG) && !defined(DEBUG_FOCUS) + fprintf( out_control->out, "%-6s%14s%14s%14s%11s%13s%13s\n", + "step", "total energy", "potential", "kinetic", + "T(K)", "V(A^3)", "P(Gpa)" ); +#else + fprintf( out_control->out, "%-6s%24s%24s%24s%13s%16s%13s\n", + "step", "total energy", "potential", "kinetic", + "T(K)", "V(A^3)", "P(GPa)" ); +#endif + fflush( out_control->out ); + } + else { + strcpy( msg, "init_out_controls: .out file could not be opened\n" ); + return FAILURE; + } +#endif + + /* init potentials file */ + sprintf( temp, "%s.pot", control->sim_name ); + if( (out_control->pot = fopen( temp, "w" )) != NULL ) { +#if !defined(DEBUG) && !defined(DEBUG_FOCUS) + fprintf( out_control->pot, + "%-6s%14s%14s%14s%14s%14s%14s%14s%14s%14s%14s%14s\n", + "step", "ebond", "eatom", "elp", + "eang", "ecoa", "ehb", "etor", "econj", + "evdw","ecoul", "epol" ); +#else + fprintf( out_control->pot, + "%-6s%24s%24s%24s%24s%24s%24s%24s%24s%24s%24s%24s\n", + "step", "ebond", "eatom", "elp", + "eang", "ecoa", "ehb", "etor", "econj", + "evdw","ecoul", "epol" ); +#endif + fflush( out_control->pot ); + } + else { + strcpy( msg, "init_out_controls: .pot file could not be opened\n" ); + return FAILURE; + } + + /* init log file */ +#if defined(LOG_PERFORMANCE) + sprintf( temp, "%s.log", control->sim_name ); + if( (out_control->log = fopen( temp, "w" )) != NULL ) { + fprintf( out_control->log, "%6s%8s%8s%8s%8s%8s%8s%8s%8s\n", + "step", "total", "comm", "nbrs", "init", "bonded", "nonb", + "qeq", "matvecs" ); + fflush( out_control->log ); + } + else { + strcpy( msg, "init_out_controls: .log file could not be opened\n" ); + return FAILURE; + } +#endif + } + + /* init pressure file */ + if( control->ensemble == NPT || + control->ensemble == iNPT || + control->ensemble == sNPT ) { + sprintf( temp, "%s.prs", control->sim_name ); + if( (out_control->prs = fopen( temp, "w" )) != NULL ) { + fprintf(out_control->prs,"%8s%13s%13s%13s%13s%13s%13s%13s\n", + "step", "Pint/norm[x]", "Pint/norm[y]", "Pint/norm[z]", + "Pext/Ptot[x]", "Pext/Ptot[y]", "Pext/Ptot[z]", "Pkin/V" ); + fflush( out_control->prs ); + } + else { + strcpy(msg,"init_out_controls: .prs file couldn't be opened\n"); + return FAILURE; + } + } + + /* init electric dipole moment analysis file */ + // not yet implemented in the parallel version!!! + // if( control->dipole_anal ) { + // sprintf( temp, "%s.dpl", control->sim_name ); + // if( (out_control->dpl = fopen( temp, "w" )) != NULL ) { + // fprintf( out_control->dpl, "%6s%20s%30s", + // "step", "molecule count", "avg dipole moment norm" ); + // fflush( out_control->dpl ); + // } + // else { + // strcpy(msg, "init_out_controls: .dpl file couldn't be opened\n"); + // return FAILURE; + // } + // } + + /* init diffusion coef analysis file */ + // not yet implemented in the parallel version!!! + // if( control->diffusion_coef ) { + // sprintf( temp, "%s.drft", control->sim_name ); + // if( (out_control->drft = fopen( temp, "w" )) != NULL ) { + // fprintf( out_control->drft, "%7s%20s%20s\n", + // "step", "type count", "avg disp^2" ); + // fflush( out_control->drft ); + // } + // else { + // strcpy(msg,"init_out_controls: .drft file couldn't be opened\n"); + // return FAILURE; + // } + // } + } + + + /* init molecular analysis file */ + /* proc0 opens this file and shares it with everyone. + then all processors write into it in a round-robin + fashion controlled by their rank */ + /*if( control->molecular_analysis ) { + if( system->my_rank == MASTER_NODE ) { + sprintf( temp, "%s.mol", control->sim_name ); + if( (out_control->mol = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"init_out_controls: .mol file could not be opened\n"); + return FAILURE; + } + } + + MPI_Bcast( &(out_control->mol), 1, MPI_LONG, 0, MPI_COMM_WORLD ); + }*/ + + +#ifdef TEST_ENERGY + /* open bond energy file */ + sprintf( temp, "%s.ebond.%d", control->sim_name, system->my_rank ); + if( (out_control->ebond = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .ebond file couldn't be opened\n"); + return FAILURE; + } + + /* open lone-pair energy file */ + sprintf( temp, "%s.elp.%d", control->sim_name, system->my_rank ); + if( (out_control->elp = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .elp file couldn't be opened\n"); + return FAILURE; + } + + /* open overcoordination energy file */ + sprintf( temp, "%s.eov.%d", control->sim_name, system->my_rank ); + if( (out_control->eov = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .eov file couldn't be opened\n"); + return FAILURE; + } + + /* open undercoordination energy file */ + sprintf( temp, "%s.eun.%d", control->sim_name, system->my_rank ); + if( (out_control->eun = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .eun file couldn't be opened\n"); + return FAILURE; + } + + /* open angle energy file */ + sprintf( temp, "%s.eval.%d", control->sim_name, system->my_rank ); + if( (out_control->eval = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .eval file couldn't be opened\n"); + return FAILURE; + } + + /* open coalition energy file */ + sprintf( temp, "%s.ecoa.%d", control->sim_name, system->my_rank ); + if( (out_control->ecoa = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .ecoa file couldn't be opened\n"); + return FAILURE; + } + + /* open penalty energy file */ + sprintf( temp, "%s.epen.%d", control->sim_name, system->my_rank ); + if( (out_control->epen = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .epen file couldn't be opened\n"); + return FAILURE; + } + + /* open torsion energy file */ + sprintf( temp, "%s.etor.%d", control->sim_name, system->my_rank ); + if( (out_control->etor = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .etor file couldn't be opened\n"); + return FAILURE; + } + + /* open conjugation energy file */ + sprintf( temp, "%s.econ.%d", control->sim_name, system->my_rank ); + if( (out_control->econ = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .econ file couldn't be opened\n"); + return FAILURE; + } + + /* open hydrogen bond energy file */ + sprintf( temp, "%s.ehb.%d", control->sim_name, system->my_rank ); + if( (out_control->ehb = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .ehb file couldn't be opened\n"); + return FAILURE; + } + + /* open vdWaals energy file */ + sprintf( temp, "%s.evdw.%d", control->sim_name, system->my_rank ); + if( (out_control->evdw = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .evdw file couldn't be opened\n"); + return FAILURE; + } + + /* open coulomb energy file */ + sprintf( temp, "%s.ecou.%d", control->sim_name, system->my_rank ); + if( (out_control->ecou = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .ecou file couldn't be opened\n"); + return FAILURE; + } +#endif + + +#ifdef TEST_FORCES + /* open bond orders file */ + sprintf( temp, "%s.fbo.%d", control->sim_name, system->my_rank ); + if( (out_control->fbo = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .fbo file couldn't be opened\n"); + return FAILURE; + } + + /* open bond orders derivatives file */ + sprintf( temp, "%s.fdbo.%d", control->sim_name, system->my_rank ); + if( (out_control->fdbo = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .fdbo file couldn't be opened\n"); + return FAILURE; + } + + /* produce a single force file - to be written by p0 */ + if( system->my_rank == MASTER_NODE ) { + /* open bond forces file */ + sprintf( temp, "%s.fbond", control->sim_name ); + if( (out_control->fbond = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .fbond file couldn't be opened\n"); + return FAILURE; + } + + /* open lone-pair forces file */ + sprintf( temp, "%s.flp", control->sim_name ); + if( (out_control->flp = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .flp file couldn't be opened\n"); + return FAILURE; + } + + /* open overcoordination forces file */ + sprintf( temp, "%s.fov", control->sim_name ); + if( (out_control->fov = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .fov file couldn't be opened\n"); + return FAILURE; + } + + /* open undercoordination forces file */ + sprintf( temp, "%s.fun", control->sim_name ); + if( (out_control->fun = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .fun file couldn't be opened\n"); + return FAILURE; + } + + /* open angle forces file */ + sprintf( temp, "%s.fang", control->sim_name ); + if( (out_control->fang = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .fang file couldn't be opened\n"); + return FAILURE; + } + + /* open coalition forces file */ + sprintf( temp, "%s.fcoa", control->sim_name ); + if( (out_control->fcoa = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .fcoa file couldn't be opened\n"); + return FAILURE; + } + + /* open penalty forces file */ + sprintf( temp, "%s.fpen", control->sim_name ); + if( (out_control->fpen = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .fpen file couldn't be opened\n"); + return FAILURE; + } + + /* open torsion forces file */ + sprintf( temp, "%s.ftor", control->sim_name ); + if( (out_control->ftor = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .ftor file couldn't be opened\n"); + return FAILURE; + } + + /* open conjugation forces file */ + sprintf( temp, "%s.fcon", control->sim_name ); + if( (out_control->fcon = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .fcon file couldn't be opened\n"); + return FAILURE; + } + + /* open hydrogen bond forces file */ + sprintf( temp, "%s.fhb", control->sim_name ); + if( (out_control->fhb = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .fhb file couldn't be opened\n"); + return FAILURE; + } + + /* open vdw forces file */ + sprintf( temp, "%s.fvdw", control->sim_name ); + if( (out_control->fvdw = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .fvdw file couldn't be opened\n"); + return FAILURE; + } + + /* open nonbonded forces file */ + sprintf( temp, "%s.fele", control->sim_name ); + if( (out_control->fele = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .fele file couldn't be opened\n"); + return FAILURE; + } + + /* open total force file */ + sprintf( temp, "%s.ftot", control->sim_name ); + if( (out_control->ftot = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .ftot file couldn't be opened\n"); + return FAILURE; + } + + /* open force comprison file */ + sprintf( temp, "%s.fcomp", control->sim_name ); + if( (out_control->fcomp = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .fcomp file couldn't be opened\n"); + return FAILURE; + } + } +#endif + +#if defined(PURE_REAX) +#if defined(TEST_FORCES) || defined(TEST_ENERGY) + /* open far neighbor list file */ + sprintf( temp, "%s.far_nbrs_list.%d", control->sim_name, system->my_rank ); + if( (out_control->flist = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .far_nbrs_list file couldn't be opened\n"); + return FAILURE; + } + + /* open bond list file */ + sprintf( temp, "%s.bond_list.%d", control->sim_name, system->my_rank ); + if( (out_control->blist = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .bond_list file couldn't be opened\n"); + return FAILURE; + } + + /* open near neighbor list file */ + sprintf( temp, "%s.near_nbrs_list.%d", control->sim_name, system->my_rank ); + if( (out_control->nlist = fopen( temp, "w" )) == NULL ) { + strcpy(msg,"Init_Out_Files: .near_nbrs_list file couldn't be opened\n"); + return FAILURE; + } +#endif +#endif + + return SUCCESS; +} + + +/************************ close output files ************************/ +int Close_Output_Files( reax_system *system, control_params *control, + output_controls *out_control, mpi_datatypes *mpi_data ) +{ + if( out_control->write_steps > 0 ) + End_Traj( system->my_rank, out_control ); + + if( system->my_rank == MASTER_NODE ) { + if( out_control->energy_update_freq > 0 ) { +#if defined(PURE_REAX) + fclose( out_control->out ); +#endif + fclose( out_control->pot ); +#if defined(LOG_PERFORMANCE) + fclose( out_control->log ); +#endif + } + + if( control->ensemble == NPT || control->ensemble == iNPT || + control->ensemble == sNPT ) + fclose( out_control->prs ); + + // not yet implemented in the parallel version + //if( control->dipole_anal ) fclose( out_control->dpl ); + //if( control->diffusion_coef ) fclose( out_control->drft ); + //if( control->molecular_analysis ) fclose( out_control->mol ); + } + +#ifdef TEST_ENERGY + fclose( out_control->ebond ); + fclose( out_control->elp ); + fclose( out_control->eov ); + fclose( out_control->eun ); + fclose( out_control->eval ); + fclose( out_control->epen ); + fclose( out_control->ecoa ); + fclose( out_control->ehb ); + fclose( out_control->etor ); + fclose( out_control->econ ); + fclose( out_control->evdw ); + fclose( out_control->ecou ); +#endif + +#ifdef TEST_FORCES + fclose( out_control->fbo ); + fclose( out_control->fdbo ); + + if( system->my_rank == MASTER_NODE ) { + fclose( out_control->fbond ); + fclose( out_control->flp ); + fclose( out_control->fov ); + fclose( out_control->fun ); + fclose( out_control->fang ); + fclose( out_control->fcoa ); + fclose( out_control->fpen ); + fclose( out_control->ftor ); + fclose( out_control->fcon ); + fclose( out_control->fhb ); + fclose( out_control->fvdw ); + fclose( out_control->fele ); + fclose( out_control->ftot ); + fclose( out_control->fcomp ); + } +#endif + +#if defined(PURE_REAX) +#if defined(TEST_FORCES) || defined(TEST_ENERGY) + fclose( out_control->flist ); + fclose( out_control->blist ); + fclose( out_control->nlist ); +#endif +#endif + + return SUCCESS; +} + + + +void Print_Box( simulation_box* box, char *name, FILE *out ) +{ + // int i, j; + + fprintf( out, "%s:\n", name ); + fprintf( out, "\tmin[%8.3f %8.3f %8.3f]\n", + box->min[0], box->min[1], box->min[2] ); + fprintf( out, "\tmax[%8.3f %8.3f %8.3f]\n", + box->max[0], box->max[1], box->max[2] ); + fprintf( out, "\tdims[%8.3f%8.3f%8.3f]\n", + box->box_norms[0], box->box_norms[1], box->box_norms[2] ); + + // fprintf( out, "box: {" ); + // for( i = 0; i < 3; ++i ) + // { + // fprintf( out, "{" ); + // for( j = 0; j < 3; ++j ) + // fprintf( out, "%8.3f ", box->box[i][j] ); + // fprintf( out, "}" ); + // } + // fprintf( out, "}\n" ); + + // fprintf( out, "box_trans: {" ); + // for( i = 0; i < 3; ++i ) + // { + // fprintf( out, "{" ); + // for( j = 0; j < 3; ++j ) + // fprintf( out, "%8.3f ", box->trans[i][j] ); + // fprintf( out, "}" ); + // } + // fprintf( out, "}\n" ); + + // fprintf( out, "box_trinv: {" ); + // for( i = 0; i < 3; ++i ) + // { + // fprintf( out, "{" ); + // for( j = 0; j < 3; ++j ) + // fprintf( out, "%8.3f ", box->trans_inv[i][j] ); + // fprintf( out, "}" ); + // } + // fprintf( out, "}\n" ); +} + + + +void Print_Grid( grid* g, FILE *out ) +{ + int x, y, z, gc_type; + ivec gc_str; + char gcell_type_text[10][12] = + { "NO_NBRS", "NEAR_ONLY", "HBOND_ONLY", "FAR_ONLY", + "NEAR_HBOND", "NEAR_FAR", "HBOND_FAR", "FULL_NBRS", "NATIVE" }; + + fprintf( out, "\tnumber of grid cells: %d %d %d\n", + g->ncells[0], g->ncells[1], g->ncells[2] ); + fprintf( out, "\tgcell lengths: %8.3f %8.3f %8.3f\n", + g->cell_len[0], g->cell_len[1], g->cell_len[2] ); + fprintf( out, "\tinverses of gcell lengths: %8.3f %8.3f %8.3f\n", + g->inv_len[0], g->inv_len[1], g->inv_len[2] ); + fprintf( out, "\t---------------------------------\n" ); + fprintf( out, "\tnumber of native gcells: %d %d %d\n", + g->native_cells[0], g->native_cells[1], g->native_cells[2] ); + fprintf( out, "\tnative gcell span: %d-%d %d-%d %d-%d\n", + g->native_str[0], g->native_end[0], + g->native_str[1], g->native_end[1], + g->native_str[2], g->native_end[2] ); + fprintf( out, "\t---------------------------------\n" ); + fprintf( out, "\tvlist gcell stretch: %d %d %d\n", + g->vlist_span[0], g->vlist_span[1], g->vlist_span[2] ); + fprintf( out, "\tnonbonded nbrs gcell stretch: %d %d %d\n", + g->nonb_span[0], g->nonb_span[1], g->nonb_span[2] ); + fprintf( out, "\tbonded nbrs gcell stretch: %d %d %d\n", + g->bond_span[0], g->bond_span[1], g->bond_span[2] ); + fprintf( out, "\t---------------------------------\n" ); + fprintf( out, "\tghost gcell span: %d %d %d\n", + g->ghost_span[0], g->ghost_span[1], g->ghost_span[2] ); + fprintf( out, "\tnonbonded ghost gcell span: %d %d %d\n", + g->ghost_nonb_span[0],g->ghost_nonb_span[1],g->ghost_nonb_span[2]); + fprintf(out, "\thbonded ghost gcell span: %d %d %d\n", + g->ghost_hbond_span[0],g->ghost_hbond_span[1],g->ghost_hbond_span[2]); + fprintf( out, "\tbonded ghost gcell span: %d %d %d\n", + g->ghost_bond_span[0],g->ghost_bond_span[1],g->ghost_bond_span[2]); + //fprintf(out, "\t---------------------------------\n" ); + //fprintf(out, "\tmax number of gcells at the boundary: %d\n", g->gcell_cap); + fprintf( out, "\t---------------------------------\n" ); + + fprintf( stderr, "GCELL MARKS:\n" ); + gc_type = g->cells[0][0][0].type; + ivec_MakeZero( gc_str ); + + x = y = z = 0; + for( x = 0; x < g->ncells[0]; ++x ) + for( y = 0; y < g->ncells[1]; ++y ) + for( z = 0; z < g->ncells[2]; ++z ) + if( g->cells[x][y][z].type != gc_type ){ + fprintf( stderr, + "\tgcells from(%2d %2d %2d) to (%2d %2d %2d): %d - %s\n", + gc_str[0], gc_str[1], gc_str[2], x, y, z, + gc_type, gcell_type_text[gc_type] ); + gc_type = g->cells[x][y][z].type; + gc_str[0] = x; + gc_str[1] = y; + gc_str[2] = z; + } + fprintf( stderr, "\tgcells from(%2d %2d %2d) to (%2d %2d %2d): %d - %s\n", + gc_str[0], gc_str[1], gc_str[2], x, y, z, + gc_type, gcell_type_text[gc_type] ); + fprintf( out, "-------------------------------------\n" ); +} + + + +void Print_GCell_Exchange_Bounds( int my_rank, neighbor_proc *my_nbrs ) +{ + ivec r; + int nbr; + neighbor_proc *nbr_pr; + char fname[100]; + FILE *f; + char exch[3][10] = { "NONE", "NEAR_EXCH", "FULL_EXCH" }; + + sprintf( fname, "gcell_exchange_bounds%d", my_rank ); + f = fopen( fname, "w" ); + + /* loop over neighbor processes */ + for( r[0] = -1; r[0] <= 1; ++r[0]) + for( r[1] = -1; r[1] <= 1; ++r[1] ) + for( r[2] = -1; r[2] <= 1; ++r[2] ) + if( r[0]!=0 || r[1]!=0 || r[2]!=0 ) { + nbr_pr = &(my_nbrs[nbr]); + + fprintf( f, "p%-2d GCELL BOUNDARIES with r(%2d %2d %2d):\n", + my_rank, r[0], r[1], r[2] ); + + fprintf( f, "\tsend_type %s: send(%d %d %d) to (%d %d %d)\n", + exch[nbr_pr->send_type], + nbr_pr->str_send[0], nbr_pr->str_send[1], + nbr_pr->str_send[2], + nbr_pr->end_send[0], nbr_pr->end_send[1], + nbr_pr->end_send[2] ); + + fprintf( f, "\trecv_type %s: recv(%d %d %d) to (%d %d %d)\n", + exch[nbr_pr->recv_type], + nbr_pr->str_recv[0], nbr_pr->str_recv[1], + nbr_pr->str_recv[2], + nbr_pr->end_recv[0], nbr_pr->end_recv[1], + nbr_pr->end_recv[2] ); + } + + fclose(f); +} + + + +void Print_Native_GCells( reax_system *system ) +{ + int i, j, k, l; + char fname[100]; + FILE *f; + grid *g; + grid_cell *gc; + char gcell_type_text[10][12] = + { "NO_NBRS", "NEAR_ONLY", "HBOND_ONLY", "FAR_ONLY", + "NEAR_HBOND", "NEAR_FAR", "HBOND_FAR", "FULL_NBRS", "NATIVE" }; + + sprintf( fname, "native_gcells.%d", system->my_rank ); + f = fopen( fname, "w" ); + g = &(system->my_grid); + + for( i = g->native_str[0]; i < g->native_end[0]; i++ ) + for( j = g->native_str[1]; j < g->native_end[1]; j++ ) + for( k = g->native_str[2]; k < g->native_end[2]; k++ ) + { + gc = &( g->cells[i][j][k] ); + + fprintf( f, "p%d gcell(%2d %2d %2d) of type %d(%s)\n", + system->my_rank, i, j, k, + gc->type, gcell_type_text[gc->type] ); + + fprintf( f, "\tatom list start: %d, end: %d\n\t", gc->str, gc->end ); + + for( l = gc->str; l < gc->end; ++l ) + fprintf( f, "%5d", system->my_atoms[l].orig_id ); + fprintf( f, "\n" ); + } + + fclose(f); +} + + + +void Print_All_GCells( reax_system *system ) +{ + int i, j, k, l; + char fname[100]; + FILE *f; + grid *g; + grid_cell *gc; + char gcell_type_text[10][12] = + { "NO_NBRS", "NEAR_ONLY", "HBOND_ONLY", "FAR_ONLY", + "NEAR_HBOND", "NEAR_FAR", "HBOND_FAR", "FULL_NBRS", "NATIVE" }; + + sprintf( fname, "all_gcells.%d", system->my_rank ); + f = fopen( fname, "w" ); + g = &(system->my_grid); + + for( i = 0; i < g->ncells[0]; i++ ) + for( j = 0; j < g->ncells[1]; j++ ) + for( k = 0; k < g->ncells[2]; k++ ) + { + gc = &( g->cells[i][j][k] ); + + fprintf( f, "p%d gcell(%2d %2d %2d) of type %d(%s)\n", + system->my_rank, i, j, k, + gc->type, gcell_type_text[gc->type] ); + + fprintf( f, "\tatom list start: %d, end: %d\n\t", gc->str, gc->end ); + + for( l = gc->str; l < gc->end; ++l ) + fprintf( f, "%5d", system->my_atoms[l].orig_id ); + fprintf( f, "\n" ); + } + + fclose(f); +} + + + +void Print_My_Atoms( reax_system *system ) +{ + int i; + char fname[100]; + FILE *fh; + + sprintf( fname, "my_atoms.%d", system->my_rank ); + if( (fh = fopen( fname, "w" )) == NULL ) + { + fprintf( stderr, "error in opening my_atoms file" ); + MPI_Abort( MPI_COMM_WORLD, FILE_NOT_FOUND ); + } + + // fprintf( stderr, "p%d had %d atoms\n", + // system->my_rank, system->n ); + + for( i = 0; i < system->n; ++i ) + fprintf( fh, "p%-2d %-5d %2d %24.15e%24.15e%24.15e\n", + system->my_rank, + system->my_atoms[i].orig_id, system->my_atoms[i].type, + system->my_atoms[i].x[0], + system->my_atoms[i].x[1], + system->my_atoms[i].x[2] ); + + fclose( fh ); +} + + +void Print_My_Ext_Atoms( reax_system *system ) +{ + int i; + char fname[100]; + FILE *fh; + + sprintf( fname, "my_ext_atoms.%d", system->my_rank ); + if( (fh = fopen( fname, "w" )) == NULL ) + { + fprintf( stderr, "error in opening my_ext_atoms file" ); + MPI_Abort( MPI_COMM_WORLD, FILE_NOT_FOUND ); + } + + // fprintf( stderr, "p%d had %d atoms\n", + // system->my_rank, system->n ); + + for( i = 0; i < system->N; ++i ) + fprintf( fh, "p%-2d %-5d imprt%-5d %2d %24.15e%24.15e%24.15e\n", + system->my_rank, system->my_atoms[i].orig_id, + system->my_atoms[i].imprt_id, system->my_atoms[i].type, + system->my_atoms[i].x[0], + system->my_atoms[i].x[1], + system->my_atoms[i].x[2] ); + + fclose( fh ); +} + + +void Print_Far_Neighbors( reax_system *system, reax_list **lists, + control_params *control ) +{ + char fname[100]; + int i, j, id_i, id_j, nbr, natoms; + FILE *fout; + reax_list *far_nbrs; + + sprintf( fname, "%s.far_nbrs.%d", control->sim_name, system->my_rank ); + fout = fopen( fname, "w" ); + far_nbrs = (*lists) + FAR_NBRS; + natoms = system->N; + + for( i = 0; i < natoms; ++i ) { + id_i = system->my_atoms[i].orig_id; + + for( j = Start_Index(i,far_nbrs); j < End_Index(i,far_nbrs); ++j ) { + nbr = far_nbrs->select.far_nbr_list[j].nbr; + id_j = system->my_atoms[nbr].orig_id; + + fprintf( fout, "%6d%6d%24.15e%24.15e%24.15e%24.15e\n", + id_i, id_j, far_nbrs->select.far_nbr_list[j].d, + far_nbrs->select.far_nbr_list[j].dvec[0], + far_nbrs->select.far_nbr_list[j].dvec[1], + far_nbrs->select.far_nbr_list[j].dvec[2] ); + + fprintf( fout, "%6d%6d%24.15e%24.15e%24.15e%24.15e\n", + id_j, id_i, far_nbrs->select.far_nbr_list[j].d, + -far_nbrs->select.far_nbr_list[j].dvec[0], + -far_nbrs->select.far_nbr_list[j].dvec[1], + -far_nbrs->select.far_nbr_list[j].dvec[2] ); + } + } + + fclose( fout ); +} + + +void Print_Sparse_Matrix( reax_system *system, sparse_matrix *A ) +{ + int i, j; + + for( i = 0; i < A->n; ++i ) + for( j = A->start[i]; j < A->end[i]; ++j ) + fprintf( stderr, "%d %d %.15e\n", + system->my_atoms[i].orig_id, + system->my_atoms[A->entries[j].j].orig_id, + A->entries[j].val ); +} + + +void Print_Sparse_Matrix2( reax_system *system, sparse_matrix *A, char *fname ) +{ + int i, j; + FILE *f = fopen( fname, "w" ); + + for( i = 0; i < A->n; ++i ) + for( j = A->start[i]; j < A->end[i]; ++j ) + fprintf( f, "%d %d %.15e\n", + system->my_atoms[i].orig_id, + system->my_atoms[A->entries[j].j].orig_id, + A->entries[j].val ); + + fclose(f); +} + + +void Print_Symmetric_Sparse(reax_system *system, sparse_matrix *A, char *fname) +{ + int i, j; + reax_atom *ai, *aj; + FILE *f = fopen( fname, "w" ); + + for( i = 0; i < A->n; ++i ) { + ai = &(system->my_atoms[i]); + for( j = A->start[i]; j < A->end[i]; ++j ) { + aj = &(system->my_atoms[A->entries[j].j]); + fprintf( f, "%d %d %.15e\n", + ai->renumber, aj->renumber, A->entries[j].val ); + if( A->entries[j].j < system->n && ai->renumber != aj->renumber ) + fprintf( f, "%d %d %.15e\n", + aj->renumber, ai->renumber, A->entries[j].val ); + } + } + + fclose(f); +} + + +void Print_Linear_System( reax_system *system, control_params *control, + storage *workspace, int step ) +{ + int i, j; + char fname[100]; + reax_atom *ai, *aj; + sparse_matrix *H; + FILE *out; + + // print rhs and init guesses for QEq + sprintf( fname, "%s.p%dstate%d", control->sim_name, system->my_rank, step ); + out = fopen( fname, "w" ); + for( i = 0; i < system->n; i++ ) { + ai = &(system->my_atoms[i]); + fprintf( out, "%6d%2d%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e\n", + ai->renumber, ai->type, ai->x[0], ai->x[1], ai->x[2], + workspace->s[i], workspace->b_s[i], + workspace->t[i], workspace->b_t[i] ); + } + fclose( out ); + + // print QEq coef matrix + sprintf( fname, "%s.p%dH%d", control->sim_name, system->my_rank, step ); + Print_Symmetric_Sparse( system, workspace->H, fname ); + + // print the incomplete H matrix + /*sprintf( fname, "%s.p%dHinc%d", control->sim_name, system->my_rank, step ); + out = fopen( fname, "w" ); + H = workspace->H; + for( i = 0; i < H->n; ++i ) { + ai = &(system->my_atoms[i]); + for( j = H->start[i]; j < H->end[i]; ++j ) + if( H->entries[j].j < system->n ) { + aj = &(system->my_atoms[H->entries[j].j]); + fprintf( out, "%d %d %.15e\n", + ai->orig_id, aj->orig_id, H->entries[j].val ); + if( ai->orig_id != aj->orig_id ) + fprintf( out, "%d %d %.15e\n", + aj->orig_id, ai->orig_id, H->entries[j].val ); + } + } + fclose( out );*/ + + // print the L from incomplete cholesky decomposition + /*sprintf( fname, "%s.p%dL%d", control->sim_name, system->my_rank, step ); + Print_Sparse_Matrix2( system, workspace->L, fname );*/ +} + + +void Print_LinSys_Soln( reax_system *system, real *x, real *b_prm, real *b ) +{ + int i; + char fname[100]; + FILE *fout; + + sprintf( fname, "qeq.%d.out", system->my_rank ); + fout = fopen( fname, "w" ); + + for( i = 0; i < system->n; ++i ) + fprintf( fout, "%6d%10.4f%10.4f%10.4f\n", + system->my_atoms[i].orig_id, x[i], b_prm[i], b[i] ); + + fclose( fout ); +} + + +void Print_Charges( reax_system *system ) +{ + int i; + char fname[100]; + FILE *fout; + + sprintf( fname, "q.%d.out", system->my_rank ); + fout = fopen( fname, "w" ); + + for( i = 0; i < system->n; ++i ) + fprintf( fout, "%6d %10.7f %10.7f %10.7f\n", + system->my_atoms[i].orig_id, + system->my_atoms[i].s[0], + system->my_atoms[i].t[0], + system->my_atoms[i].q ); + + fclose( fout ); +} + + +void Print_Bonds( reax_system *system, reax_list *bonds, char *fname ) +{ + int i, j, pj; + bond_data *pbond; + bond_order_data *bo_ij; + FILE *f = fopen( fname, "w" ); + + for( i = 0; i < system->N; ++i ) + for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) { + pbond = &(bonds->select.bond_list[pj]); + bo_ij = &(pbond->bo_data); + j = pbond->nbr; + //fprintf( f, "%6d%6d%23.15e%23.15e%23.15e%23.15e%23.15e\n", + // system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, + // pbond->d, bo_ij->BO, bo_ij->BO_s, bo_ij->BO_pi, bo_ij->BO_pi2 ); + fprintf( f, "%8d%8d %24.15f %24.15f\n", + i, j,//system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, + pbond->d, bo_ij->BO ); + } + + fclose(f); +} + + +int fn_qsort_intcmp( const void *a, const void *b ) +{ + return( *(int *)a - *(int *)b ); +} + +void Print_Bond_List2( reax_system *system, reax_list *bonds, char *fname ) +{ + int i,j, id_i, id_j, nbr, pj; + FILE *f = fopen( fname, "w" ); + int temp[500]; + int num=0; + + for( i = 0; i < system->n; ++i ) { + num=0; + id_i = system->my_atoms[i].orig_id; + fprintf( f, "%6d:", id_i); + for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) { + nbr = bonds->select.bond_list[pj].nbr; + id_j = system->my_atoms[nbr].orig_id; + if( id_i < id_j ) + temp[num++] = id_j; + } + + qsort(&temp, num, sizeof(int), fn_qsort_intcmp); + for(j=0; j < num; j++) + fprintf(f, "%6d", temp[j] ); + fprintf(f, "\n"); + } +} + + +void Print_Total_Force( reax_system *system, simulation_data *data, + storage *workspace ) +{ + int i; + + fprintf( stderr, "step: %d\n", data->step ); + fprintf( stderr, "%6s\t%-38s\n", "atom", "atom.f[0,1,2]"); + + for( i = 0; i < system->N; ++i ) + fprintf( stderr, "%6d %f %f %f\n", + //"%6d%24.15e%24.15e%24.15e\n", + system->my_atoms[i].orig_id, + workspace->f[i][0], workspace->f[i][1], workspace->f[i][2] ); +} + +void Output_Results( reax_system *system, control_params *control, + simulation_data *data, reax_list **lists, + output_controls *out_control, mpi_datatypes *mpi_data ) +{ +#if defined(LOG_PERFORMANCE) + real t_elapsed, denom; +#endif + + if((out_control->energy_update_freq > 0 && + data->step%out_control->energy_update_freq == 0) || + (out_control->write_steps > 0 && + data->step%out_control->write_steps == 0)){ + /* update system-wide energies */ + Compute_System_Energy( system, data, mpi_data->world ); + + /* output energies */ + if( system->my_rank == MASTER_NODE && + out_control->energy_update_freq > 0 && + data->step % out_control->energy_update_freq == 0 ) { +#if !defined(DEBUG) && !defined(DEBUG_FOCUS) +#if defined(PURE_REAX) + fprintf( out_control->out, + "%-6d%14.2f%14.2f%14.2f%11.2f%13.2f%13.5f\n", + data->step, data->sys_en.e_tot, data->sys_en.e_pot, + E_CONV * data->sys_en.e_kin, data->therm.T, + system->big_box.V, data->iso_bar.P ); + fflush( out_control->out ); +#endif + + fprintf( out_control->pot, + "%-6d%14.2f%14.2f%14.2f%14.2f%14.2f%14.2f%14.2f%14.2f%14.2f%14.2f%14.2f\n", + data->step, + 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); + fflush( out_control->pot ); +#else +#if defined(PURE_REAX) + fprintf( out_control->out, + "%-6d%24.15e%24.15e%24.15e%13.5f%16.5f%13.5f\n", + data->step, data->sys_en.e_tot, data->sys_en.e_pot, + E_CONV * data->sys_en.e_kin, data->therm.T, + system->big_box.V, data->iso_bar.P ); + fflush( out_control->out ); +#endif + + fprintf( out_control->pot, + "%-6d%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e\n", + data->step, + 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); + fflush( out_control->pot ); +#endif //DEBUG + +#if defined(LOG_PERFORMANCE) + t_elapsed = Get_Timing_Info( data->timing.total ); + if( data->step - data->prev_steps > 0 ) + denom = 1.0 / out_control->energy_update_freq; + else denom = 1; + + fprintf( out_control->log, "%6d%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f%6d\n", + data->step, + t_elapsed * denom, + data->timing.comm * denom, + data->timing.nbrs * denom, + data->timing.init_forces * denom, + data->timing.bonded * denom, + data->timing.nonb * denom, + data->timing.qEq * denom, + (int)((data->timing.s_matvecs+data->timing.t_matvecs)*denom) ); + + Reset_Timing( &(data->timing) ); + fflush( out_control->log ); +#endif //LOG_PERFORMANCE + + if( control->virial ){ + fprintf( out_control->prs, + "%8d%13.6f%13.6f%13.6f%13.6f%13.6f%13.6f%13.6f\n", + data->step, + data->int_press[0], data->int_press[1], data->int_press[2], + data->ext_press[0], data->ext_press[1], data->ext_press[2], + data->kin_press ); + + fprintf( out_control->prs, + "%8s%13.6f%13.6f%13.6f%13.6f%13.6f%13.6f%13.6f\n", + "",system->big_box.box_norms[0], system->big_box.box_norms[1], + system->big_box.box_norms[2], + data->tot_press[0], data->tot_press[1], data->tot_press[2], + system->big_box.V ); + + fflush( out_control->prs); + } + } + + /* write current frame */ + if( out_control->write_steps > 0 && + (data->step-data->prev_steps) % out_control->write_steps == 0 ) { + Append_Frame( system, control, data, lists, out_control, mpi_data ); + } + } + +#if defined(DEBUG) + fprintf( stderr, "output_results... done\n" ); +#endif +} + + +#ifdef TEST_ENERGY +void Debug_Marker_Bonded( output_controls *out_control, int step ) +{ + fprintf( out_control->ebond, "step: %d\n%6s%6s%12s%12s%12s\n", + step, "atom1", "atom2", "bo", "ebond", "total" ); + fprintf( out_control->elp, "step: %d\n%6s%12s%12s%12s\n", + step, "atom", "nlp", "elp", "total" ); + fprintf( out_control->eov, "step: %d\n%6s%12s%12s\n", + step, "atom", "eov", "total" ); + fprintf( out_control->eun, "step: %d\n%6s%12s%12s\n", + step, "atom", "eun", "total" ); + fprintf( out_control->eval, "step: %d\n%6s%6s%6s%12s%12s%12s%12s%12s%12s\n", + step, "atom1", "atom2", "atom3", "angle", "theta0", + "bo(12)", "bo(23)", "eval", "total" ); + fprintf( out_control->epen, "step: %d\n%6s%6s%6s%12s%12s%12s%12s%12s\n", + step, "atom1", "atom2", "atom3", "angle", "bo(12)", "bo(23)", + "epen", "total" ); + fprintf( out_control->ecoa, "step: %d\n%6s%6s%6s%12s%12s%12s%12s%12s\n", + step, "atom1", "atom2", "atom3", "angle", "bo(12)", "bo(23)", + "ecoa", "total" ); + fprintf( out_control->ehb, "step: %d\n%6s%6s%6s%12s%12s%12s%12s%12s\n", + step, "atom1", "atom2", "atom3", "r(23)", "angle", "bo(12)", + "ehb", "total" ); + fprintf( out_control->etor, "step: %d\n%6s%6s%6s%6s%12s%12s%12s%12s\n", + step, "atom1", "atom2", "atom3", "atom4", "phi", "bo(23)", + "etor", "total" ); + fprintf( out_control->econ,"step:%d\n%6s%6s%6s%6s%12s%12s%12s%12s%12s%12s\n", + step, "atom1", "atom2", "atom3", "atom4", + "phi", "bo(12)", "bo(23)", "bo(34)", "econ", "total" ); +} + +void Debug_Marker_Nonbonded( output_controls *out_control, int step ) +{ + fprintf( out_control->evdw, "step: %d\n%6s%6s%12s%12s%12s\n", + step, "atom1", "atom2", "r12", "evdw", "total" ); + fprintf( out_control->ecou, "step: %d\n%6s%6s%12s%12s%12s%12s%12s\n", + step, "atom1", "atom2", "r12", "q1", "q2", "ecou", "total" ); +} + +#endif + + +#ifdef TEST_FORCES +void Dummy_Printer( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control ) +{ +} + + + +void Print_Bond_Orders( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control ) +{ + int i, pj, pk; + bond_order_data *bo_ij; + dbond_data *dbo_k; + reax_list *bonds = (*lists) + BONDS; + reax_list *dBOs = (*lists) + DBOS; + + /* bond orders */ + fprintf( out_control->fbo, "step: %d\n", data->step ); + fprintf( out_control->fbo, "%6s%6s%12s%12s%12s%12s%12s\n", + "atom1", "atom2", "r_ij", "total_bo", "bo_s", "bo_p", "bo_pp" ); + + for( i = 0; i < system->N; ++i ) + for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) { + bo_ij = &(bonds->select.bond_list[pj].bo_data); + fprintf( out_control->fbo, + "%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e\n", + system->my_atoms[i].orig_id, + system->my_atoms[bonds->select.bond_list[pj].nbr].orig_id, + bonds->select.bond_list[pj].d, + bo_ij->BO, bo_ij->BO_s, bo_ij->BO_pi, bo_ij->BO_pi2 ); + } + + + /* derivatives of bond orders */ + fprintf( out_control->fdbo, "step: %d\n", data->step ); + fprintf( out_control->fdbo, "%6s%6s%6s%24s%24s%24s\n", + "atom1", "atom2", "atom2", "dBO", "dBOpi", "dBOpi2" ); + for( i = 0; i < system->N; ++i ) + for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) { + /* fprintf( out_control->fdbo, "%6d %6d\tstart: %6d\tend: %6d\n", + system->my_atoms[i].orig_id, + system->my_atoms[bonds->select.bond_list[pj].nbr].orig_id, + Start_Index( pj, dBOs ), End_Index( pj, dBOs ) ); */ + for( pk = Start_Index(pj, dBOs); pk < End_Index(pj, dBOs); ++pk ) { + dbo_k = &(dBOs->select.dbo_list[pk]); + fprintf( out_control->fdbo, "%6d%6d%6d%24.15e%24.15e%24.15e\n", + system->my_atoms[i].orig_id, + system->my_atoms[bonds->select.bond_list[pj].nbr].orig_id, + system->my_atoms[dbo_k->wrt].orig_id, + dbo_k->dBO[0], dbo_k->dBO[1], dbo_k->dBO[2] ); + + fprintf( out_control->fdbo, "%6d%6d%6d%24.15e%24.15e%24.15e\n", + system->my_atoms[i].orig_id, + system->my_atoms[bonds->select.bond_list[pj].nbr].orig_id, + system->my_atoms[dbo_k->wrt].orig_id, + dbo_k->dBOpi[0], dbo_k->dBOpi[1], dbo_k->dBOpi[2] ); + + fprintf( out_control->fdbo, "%6d%6d%6d%24.15e%24.15e%24.15e\n", + system->my_atoms[i].orig_id, + system->my_atoms[bonds->select.bond_list[pj].nbr].orig_id, + system->my_atoms[dbo_k->wrt].orig_id, + dbo_k->dBOpi2[0], dbo_k->dBOpi2[1], dbo_k->dBOpi2[2] ); + } + } +} + + +void Print_Forces( FILE *f, storage *workspace, int N, int step ) +{ + int i; + + fprintf( f, "step: %d\n", step ); + for( i = 0; i < N; ++i ) + //fprintf( f, "%6d %23.15e %23.15e %23.15e\n", + //fprintf( f, "%6d%12.6f%12.6f%12.6f\n", + fprintf( f, "%6d %19.9e %19.9e %19.9e\n", + workspace->id_all[i], workspace->f_all[i][0], + workspace->f_all[i][1], workspace->f_all[i][2] ); +} + + +void Print_Force_Files( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control, + mpi_datatypes *mpi_data ) +{ + int i, d; + + Coll_ids_at_Master( system, workspace, mpi_data ); + + Print_Bond_Orders( system, control, data, workspace, lists, out_control ); + + Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_be ); + if( system->my_rank == MASTER_NODE ) + Print_Forces( out_control->fbond, workspace, system->bigN, data->step ); + + Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_lp ); + if( system->my_rank == MASTER_NODE ) + Print_Forces( out_control->flp, workspace, system->bigN, data->step ); + + Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_ov ); + if( system->my_rank == MASTER_NODE ) + Print_Forces( out_control->fov, workspace, system->bigN, data->step ); + + Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_un ); + if( system->my_rank == MASTER_NODE ) + Print_Forces( out_control->fun, workspace, system->bigN, data->step ); + + Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_ang ); + if( system->my_rank == MASTER_NODE ) + Print_Forces( out_control->fang, workspace, system->bigN, data->step ); + + Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_coa ); + if( system->my_rank == MASTER_NODE ) + Print_Forces( out_control->fcoa, workspace, system->bigN, data->step ); + + Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_pen ); + if( system->my_rank == MASTER_NODE ) + Print_Forces( out_control->fpen, workspace, system->bigN, data->step ); + + Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_tor ); + if( system->my_rank == MASTER_NODE ) + Print_Forces( out_control->ftor, workspace, system->bigN, data->step ); + + Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_con ); + if( system->my_rank == MASTER_NODE ) + Print_Forces( out_control->fcon, workspace, system->bigN, data->step ); + + Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_hb ); + if( system->my_rank == MASTER_NODE ) + Print_Forces( out_control->fhb, workspace, system->bigN, data->step ); + + Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_vdw ); + if( system->my_rank == MASTER_NODE ) + Print_Forces( out_control->fvdw, workspace, system->bigN, data->step ); + + Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_ele ); + if( system->my_rank == MASTER_NODE ) + Print_Forces( out_control->fele, workspace, system->bigN, data->step ); + + Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f ); + if( system->my_rank == MASTER_NODE ) + Print_Forces( out_control->ftot, workspace, system->bigN, data->step ); + + for( i = 0; i < system->n; ++i ) { + for( d = 0; d < 3; ++d ) + workspace->f_tot[i][d] = workspace->f_be[i][d] + + workspace->f_lp[i][d]+workspace->f_ov[i][d]+workspace->f_un[i][d] + + workspace->f_ang[i][d]+workspace->f_pen[i][d]+workspace->f_coa[i][d] + + workspace->f_tor[i][d]+workspace->f_con[i][d] + + workspace->f_vdw[i][d]+workspace->f_ele[i][d] + + workspace->f_hb[i][d]; + } + + Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_tot ); + if( system->my_rank == MASTER_NODE ) + Print_Forces( out_control->fcomp, workspace, system->bigN, data->step ); +} +#endif + + +#if defined(TEST_FORCES) || defined(TEST_ENERGY) + +void Print_Far_Neighbors_List( reax_system *system, reax_list **lists, + control_params *control, simulation_data *data, + output_controls *out_control ) +{ + int i, j, id_i, id_j, nbr, natoms; + int num=0; + int temp[500]; + reax_list *far_nbrs; + + far_nbrs = (*lists) + FAR_NBRS; + fprintf( out_control->flist, "step: %d\n", data->step ); + fprintf( out_control->flist, "%6s\t%-38s\n", "atom", "Far_nbrs_list"); + + + natoms = system->n; + for( i = 0; i < natoms; ++i ) { + id_i = system->my_atoms[i].orig_id; + fprintf( out_control->flist, "%6d:",id_i); + num=0; + + for( j = Start_Index(i,far_nbrs); j < End_Index(i,far_nbrs); ++j ) { + nbr = far_nbrs->select.far_nbr_list[j].nbr; + id_j = system->my_atoms[nbr].orig_id; + temp[num++] = id_j; + } + + qsort(&temp, num, sizeof(int), fn_qsort_intcmp); + for(j=0; j < num; j++) + fprintf(out_control->flist, "%6d",temp[j]); + fprintf( out_control->flist, "\n"); + } +} + +void Print_Bond_List( reax_system *system, control_params *control, + simulation_data *data, reax_list **lists, + output_controls *out_control) +{ + int i,j, id_i, id_j, nbr, pj; + reax_list *bonds = (*lists) + BONDS; + + int temp[500]; + int num=0; + + fprintf( out_control->blist, "step: %d\n", data->step ); + fprintf( out_control->blist, "%6s\t%-38s\n", "atom", "Bond_list"); + + /* bond list */ + for( i = 0; i < system->n; ++i ) { + num=0; + id_i = system->my_atoms[i].orig_id; + fprintf( out_control->blist, "%6d:", id_i); + for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) { + nbr = bonds->select.bond_list[pj].nbr; + id_j = system->my_atoms[nbr].orig_id; + if( id_i < id_j ) + temp[num++] = id_j; + } + + qsort(&temp, num, sizeof(int), fn_qsort_intcmp); + for(j=0; j < num; j++) + fprintf(out_control->blist, "%6d",temp[j]); + fprintf(out_control->blist, "\n"); + } +} + + +#endif + + +#ifdef OLD_VERSION +void Print_Init_Atoms( reax_system *system, storage *workspace ) +{ + int i; + + fprintf( stderr, "p%d had %d atoms\n", + system->my_rank, workspace->init_cnt ); + + for( i = 0; i < workspace->init_cnt; ++i ) + fprintf( stderr, "p%d, atom%d: %d %s %8.3f %8.3f %8.3f\n", + system->my_rank, i, + workspace->init_atoms[i].type, workspace->init_atoms[i].name, + workspace->init_atoms[i].x[0], + workspace->init_atoms[i].x[1], + workspace->init_atoms[i].x[2] ); +} +#endif //OLD_VERSION + + +/*void Print_Bond_Forces( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control ) +{ + int i; + + fprintf( out_control->fbond, "step: %d\n", data->step ); + fprintf( out_control->fbond, "%6s%24s%24s%24s\n", + "atom", "f_be[0]", "f_be[1]", "f_be[2]" ); + + for( i = 0; i < system->bigN; ++i ) + fprintf(out_control->fbond, "%6d%24.15e%24.15e%24.15e\n", + system->my_atoms[i].orig_id, + workspace->f_all[i][0], workspace->f_all[i][1], + workspace->f_all[i][2]); +} + +void Print_LonePair_Forces( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control ) +{ + int i; + + fprintf( out_control->flp, "step: %d\n", data->step ); + fprintf( out_control->flp, "%6s%24s\n", "atom", "f_lonepair" ); + + for( i = 0; i < system->bigN; ++i ) + fprintf(out_control->flp, "%6d%24.15e%24.15e%24.15e\n", + system->my_atoms[i].orig_id, + workspace->f_all[i][0], workspace->f_all[i][1], + workspace->f_all[i][2]); +} + + +void Print_OverCoor_Forces( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control ) +{ + int i; + + fprintf( out_control->fov, "step: %d\n", data->step ); + fprintf( out_control->fov, "%6s%-38s%-38s%-38s\n", + "atom","f_over[0]", "f_over[1]", "f_over[2]" ); + + for( i = 0; i < system->bigN; ++i ) + fprintf( out_control->fov, + "%6d %24.15e%24.15e%24.15e 0 0 0\n", + system->my_atoms[i].orig_id, + workspace->f_all[i][0], workspace->f_all[i][1], + workspace->f_all[i][2] ); +} + + +void Print_UnderCoor_Forces( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control ) +{ + int i; + + fprintf( out_control->fun, "step: %d\n", data->step ); + fprintf( out_control->fun, "%6s%-38s%-38s%-38s\n", + "atom","f_under[0]", "f_under[1]", "f_under[2]" ); + + for( i = 0; i < system->bigN; ++i ) + fprintf( out_control->fun, + "%6d %24.15e%24.15e%24.15e 0 0 0\n", + system->my_atoms[i].orig_id, + workspace->f_all[i][0], workspace->f_all[i][1], + workspace->f_all[i][2] ); +} + + +void Print_ValAngle_Forces( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control ) +{ + int j; + + fprintf( out_control->f3body, "step: %d\n", data->step ); + fprintf( out_control->f3body, "%6s%-37s%-37s%-37s%-38s\n", + "atom", "3-body total", "f_ang", "f_pen", "f_coa" ); + + for( j = 0; j < system->N; ++j ){ + if( rvec_isZero(workspace->f_pen[j]) && rvec_isZero(workspace->f_coa[j]) ) + fprintf( out_control->f3body, + "%6d %24.15e%24.15e%24.15e 0 0 0 0 0 0\n", + system->my_atoms[j].orig_id, + workspace->f_ang[j][0], workspace->f_ang[j][1], + workspace->f_ang[j][2] ); + else if( rvec_isZero(workspace->f_coa[j]) ) + fprintf( out_control->f3body, + "%6d %24.15e%24.15e%24.15e %24.15e%24.15e%24.15e " \ + "%24.15e%24.15e%24.15e\n", + system->my_atoms[j].orig_id, + workspace->f_ang[j][0] + workspace->f_pen[j][0], + workspace->f_ang[j][1] + workspace->f_pen[j][1], + workspace->f_ang[j][2] + workspace->f_pen[j][2], + workspace->f_ang[j][0], workspace->f_ang[j][1], + workspace->f_ang[j][2], + workspace->f_pen[j][0], workspace->f_pen[j][1], + workspace->f_pen[j][2] ); + else{ + fprintf( out_control->f3body, "%6d %24.15e%24.15e%24.15e ", + system->my_atoms[j].orig_id, + workspace->f_ang[j][0] + workspace->f_pen[j][0] + + workspace->f_coa[j][0], + workspace->f_ang[j][1] + workspace->f_pen[j][1] + + workspace->f_coa[j][1], + workspace->f_ang[j][2] + workspace->f_pen[j][2] + + workspace->f_coa[j][2] ); + + fprintf( out_control->f3body, + "%24.15e%24.15e%24.15e %24.15e%24.15e%24.15e "\ + "%24.15e%24.15e%24.15e\n", + workspace->f_ang[j][0], workspace->f_ang[j][1], + workspace->f_ang[j][2], + workspace->f_pen[j][0], workspace->f_pen[j][1], + workspace->f_pen[j][2], + workspace->f_coa[j][0], workspace->f_coa[j][1], + workspace->f_coa[j][2] ); + } + } +} + + +void Print_Hydrogen_Bond_Forces( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control) +{ + int j; + + fprintf( out_control->fhb, "step: %d\n", data->step ); + fprintf( out_control->fhb, "%6s\t%-38s\n", "atom", "f_hb[0,1,2]" ); + + for( j = 0; j < system->N; ++j ) + fprintf(out_control->fhb, "%6d%24.15e%24.15e%24.15e\n", + system->my_atoms[j].orig_id, + workspace->f_hb[j][0], + workspace->f_hb[j][1], + workspace->f_hb[j][2] ); +} + + +void Print_Four_Body_Forces( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control ) +{ + int j; + + fprintf( out_control->f4body, "step: %d\n", data->step ); + fprintf( out_control->f4body, "%6s\t%-38s%-38s%-38s\n", + "atom", "4-body total", "f_tor", "f_con" ); + + for( j = 0; j < system->N; ++j ){ + if( !rvec_isZero( workspace->f_con[j] ) ) + fprintf( out_control->f4body, + "%6d %24.15e%24.15e%24.15e %24.15e%24.15e%24.15e "\ + "%24.15e%24.15e%24.15e\n", + system->my_atoms[j].orig_id, + workspace->f_tor[j][0] + workspace->f_con[j][0], + workspace->f_tor[j][1] + workspace->f_con[j][1], + workspace->f_tor[j][2] + workspace->f_con[j][2], + workspace->f_tor[j][0], workspace->f_tor[j][1], + workspace->f_tor[j][2], + workspace->f_con[j][0], workspace->f_con[j][1], + workspace->f_con[j][2] ); + else + fprintf( out_control->f4body, + "%6d %24.15e%24.15e%24.15e 0 0 0\n", + system->my_atoms[j].orig_id, workspace->f_tor[j][0], + workspace->f_tor[j][1], workspace->f_tor[j][2] ); + } + +} + + +void Print_vdW_Coulomb_Forces( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control ) +{ + int i; + + return; + + fprintf( out_control->fnonb, "step: %d\n", data->step ); + fprintf( out_control->fnonb, "%6s\t%-38s%-38s%-38s\n", + "atom", "nonbonded_total[0,1,2]", "f_vdw[0,1,2]", "f_ele[0,1,2]" ); + + for( i = 0; i < system->N; ++i ) + fprintf( out_control->fnonb, + "%6d%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e\n", + system->my_atoms[i].orig_id, + workspace->f_vdw[i][0] + workspace->f_ele[i][0], + workspace->f_vdw[i][1] + workspace->f_ele[i][1], + workspace->f_vdw[i][2] + workspace->f_ele[i][2], + workspace->f_vdw[i][0], + workspace->f_vdw[i][1], + workspace->f_vdw[i][2], + workspace->f_ele[i][0], + workspace->f_ele[i][1], + workspace->f_ele[i][2] ); +} + + +void Print_Total_Force( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control ) +{ + int i; + + return; + + fprintf( out_control->ftot, "step: %d\n", data->step ); + fprintf( out_control->ftot, "%6s\t%-38s\n", "atom", "atom.f[0,1,2]"); + + for( i = 0; i < system->n; ++i ) + fprintf( out_control->ftot, "%6d%24.15e%24.15e%24.15e\n", + system->my_atoms[i].orig_id, + system->my_atoms[i].f[0], + system->my_atoms[i].f[1], + system->my_atoms[i].f[2] ); +} + + +void Compare_Total_Forces( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control ) +{ + int i; + + return; + + fprintf( out_control->ftot2, "step: %d\n", data->step ); + fprintf( out_control->ftot2, "%6s\t%-38s%-38s\n", + "atom", "f_total[0,1,2]", "test_force_total[0,1,2]" ); + + for( i = 0; i < system->N; ++i ) + fprintf( out_control->ftot2, "%6d%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e\n", + system->my_atoms[i].orig_id, + system->my_atoms[i].f[0], + system->my_atoms[i].f[1], + system->my_atoms[i].f[2], + workspace->f_be[i][0] + workspace->f_lp[i][0] + + workspace->f_ov[i][0] + workspace->f_un[i][0] + + workspace->f_ang[i][0]+ workspace->f_pen[i][0]+ + workspace->f_coa[i][0]+ + workspace->f_hb[i][0] + + workspace->f_tor[i][0] + workspace->f_con[i][0] + + workspace->f_vdw[i][0] + workspace->f_ele[i][0], + workspace->f_be[i][1] + workspace->f_lp[i][1] + + workspace->f_ov[i][1] + workspace->f_un[i][1] + + workspace->f_ang[i][1]+ workspace->f_pen[i][1]+ + workspace->f_coa[i][1]+ + workspace->f_hb[i][1] + + workspace->f_tor[i][1] + workspace->f_con[i][1] + + workspace->f_vdw[i][1] + workspace->f_ele[i][1], + workspace->f_be[i][2] + workspace->f_lp[i][2] + + workspace->f_ov[i][2] + workspace->f_un[i][2] + + workspace->f_ang[i][2]+ workspace->f_pen[i][2] + + workspace->f_coa[i][2]+ + workspace->f_hb[i][2] + + workspace->f_tor[i][2] + workspace->f_con[i][2] + + workspace->f_vdw[i][2] + workspace->f_ele[i][2] ); +}*/ + +/*void Init_Force_Test_Functions( ) +{ + Print_Interactions[0] = Print_Bond_Orders; + Print_Interactions[1] = Print_Bond_Forces; + Print_Interactions[2] = Print_LonePair_Forces; + Print_Interactions[3] = Print_OverUnderCoor_Forces; + Print_Interactions[4] = Print_Three_Body_Forces; + Print_Interactions[5] = Print_Four_Body_Forces; + Print_Interactions[6] = Print_Hydrogen_Bond_Forces; + Print_Interactions[7] = Print_vdW_Coulomb_Forces; + Print_Interactions[8] = Print_Total_Force; + Print_Interactions[9] = Compare_Total_Forces; + }*/ diff --git a/src/USER-REAXC/reaxc_io_tools.h b/src/USER-REAXC/reaxc_io_tools.h new file mode 100644 index 0000000000..c009f14df7 --- /dev/null +++ b/src/USER-REAXC/reaxc_io_tools.h @@ -0,0 +1,107 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __IO_TOOLS_H_ +#define __IO_TOOLS_H_ + +#include "reaxc_types.h" + +int Init_Output_Files( reax_system*, control_params*, + output_controls*, mpi_datatypes*, char* ); +int Close_Output_Files( reax_system*, control_params*, + output_controls*, mpi_datatypes* ); + +void Print_Box( simulation_box*, char*, FILE* ); + +void Print_Grid( grid*, FILE* ); +void Print_GCell_Exchange_Bounds( int, neighbor_proc* ); +void Print_Native_GCells( reax_system* ); +void Print_All_GCells( reax_system*); + +void Print_Init_Atoms( reax_system*, storage* ); +void Print_My_Atoms( reax_system* ); +void Print_My_Ext_Atoms( reax_system* ); + +void Print_Far_Neighbors( reax_system*, reax_list**, control_params *); +void Print_Sparse_Matrix( reax_system*, sparse_matrix* ); +void Print_Sparse_Matrix2( reax_system*, sparse_matrix*, char* ); +void Print_Linear_System( reax_system*, control_params*, storage*, int ); +void Print_LinSys_Soln( reax_system*, real*, real*, real* ); +void Print_Charges( reax_system* ); +void Print_Bonds( reax_system*, reax_list*, char* ); +void Print_Bond_List2( reax_system*, reax_list*, char* ); +void Print_Total_Force( reax_system*, simulation_data*, storage* ); +void Output_Results( reax_system*, control_params*, simulation_data*, + reax_list**, output_controls*, mpi_datatypes* ); + +#if defined(DEBUG_FOCUS) || defined(TEST_FORCES) || defined(TEST_ENERGY) +void Debug_Marker_Bonded( output_controls*, int ); +void Debug_Marker_Nonbonded( output_controls*, int ); +void Print_Near_Neighbors_List( reax_system*, reax_list**, control_params*, + simulation_data*, output_controls* ); +void Print_Far_Neighbors_List( reax_system*, reax_list**, control_params*, + simulation_data*, output_controls* ); +void Print_Bond_List( reax_system*, control_params*, simulation_data*, + reax_list**, output_controls* ); +/*void Dummy_Printer( reax_system*, control_params*, simulation_data*, + storage*, reax_list**, output_controls* ); +void Print_Bond_Orders( reax_system*, control_params*, simulation_data*, + storage*, reax_list**, output_controls* ); +void Print_Bond_Forces( reax_system*, control_params*, simulation_data*, + storage*, reax_list**, output_controls* ); +void Print_LonePair_Forces( reax_system*, control_params*, simulation_data*, + storage*, reax_list**, output_controls* ); +void Print_OverUnderCoor_Forces( reax_system*, control_params*, + simulation_data*, storage*, reax_list**, + output_controls* ); +void Print_Three_Body_Forces( reax_system*, control_params*, simulation_data*, + storage*, reax_list**, output_controls* ); +void Print_Hydrogen_Bond_Forces( reax_system*, control_params*, + simulation_data*, storage*, reax_list**, + output_controls* ); +void Print_Four_Body_Forces( reax_system*, control_params*, simulation_data*, + storage*, reax_list**, output_controls* ); +void Print_vdW_Coulomb_Forces( reax_system*, control_params*, + simulation_data*, storage*, reax_list**, + output_controls* ); +void Print_Total_Force( reax_system*, control_params*, simulation_data*, + storage*, reax_list**, output_controls* ); +void Compare_Total_Forces( reax_system*, control_params*, simulation_data*, +storage*, reax_list**, output_controls* );*/ +//void Print_Total_Force( reax_system*, control_params* ); +void Print_Force_Files( reax_system*, control_params*, simulation_data*, + storage*, reax_list**, output_controls*, + mpi_datatypes * ); +//void Init_Force_Test_Functions( ); + +int fn_qsort_intcmp( const void *, const void * ); + +void Print_Far_Neighbors_List( reax_system*, reax_list**, control_params*, + simulation_data*, output_controls* ); + +void Print_Near_Neighbors_List( reax_system*, reax_list**, control_params*, + simulation_data*, output_controls* ); + +void Print_Bond_List( reax_system*, control_params*, simulation_data*, + reax_list**, output_controls*); + +#endif +#endif diff --git a/src/USER-REAXC/reaxc_list.cpp b/src/USER-REAXC/reaxc_list.cpp new file mode 100644 index 0000000000..0ea3d7d875 --- /dev/null +++ b/src/USER-REAXC/reaxc_list.cpp @@ -0,0 +1,157 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "list.h" +#include "tool_box.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_list.h" +#include "reaxc_tool_box.h" +#endif + + +/************* allocate list space ******************/ +int Make_List(int n, int num_intrs, int type, reax_list *l, MPI_Comm comm) +{ + l->allocated = 1; + + l->n = n; + l->num_intrs = num_intrs; + + l->index = (int*) smalloc( n * sizeof(int), "list:index", comm ); + l->end_index = (int*) smalloc( n * sizeof(int), "list:end_index", comm ); + + l->type = type; +#if defined(DEBUG_FOCUS) + fprintf( stderr, "list: n=%d num_intrs=%d type=%d\n", n, num_intrs, type ); +#endif + + switch(l->type) { + case TYP_VOID: + l->select.v = (void*) smalloc(l->num_intrs * sizeof(void*), "list:v", comm); + break; + + case TYP_THREE_BODY: + l->select.three_body_list = (three_body_interaction_data*) + smalloc( l->num_intrs * sizeof(three_body_interaction_data), + "list:three_bodies", comm ); + break; + + case TYP_BOND: + l->select.bond_list = (bond_data*) + smalloc( l->num_intrs * sizeof(bond_data), "list:bonds", comm ); + break; + + case TYP_DBO: + l->select.dbo_list = (dbond_data*) + smalloc( l->num_intrs * sizeof(dbond_data), "list:dbonds", comm ); + break; + + case TYP_DDELTA: + l->select.dDelta_list = (dDelta_data*) + smalloc( l->num_intrs * sizeof(dDelta_data), "list:dDeltas", comm ); + break; + + case TYP_FAR_NEIGHBOR: + l->select.far_nbr_list = (far_neighbor_data*) + smalloc(l->num_intrs * sizeof(far_neighbor_data), "list:far_nbrs", comm); + break; + + case TYP_HBOND: + l->select.hbond_list = (hbond_data*) + smalloc( l->num_intrs * sizeof(hbond_data), "list:hbonds", comm ); + break; + + default: + fprintf( stderr, "ERROR: no %d list type defined!\n", l->type ); + MPI_Abort( comm, INVALID_INPUT ); + } + + return SUCCESS; +} + + +void Delete_List( reax_list *l, MPI_Comm comm ) +{ + if( l->allocated == 0 ) + return; + l->allocated = 0; + + sfree( l->index, "list:index" ); + sfree( l->end_index, "list:end_index" ); + + switch(l->type) { + case TYP_VOID: + sfree( l->select.v, "list:v" ); + break; + case TYP_HBOND: + sfree( l->select.hbond_list, "list:hbonds" ); + break; + case TYP_FAR_NEIGHBOR: + sfree( l->select.far_nbr_list, "list:far_nbrs" ); + break; + case TYP_BOND: + sfree( l->select.bond_list, "list:bonds" ); + break; + case TYP_DBO: + sfree( l->select.dbo_list, "list:dbos" ); + break; + case TYP_DDELTA: + sfree( l->select.dDelta_list, "list:dDeltas" ); + break; + case TYP_THREE_BODY: + sfree( l->select.three_body_list, "list:three_bodies" ); + break; + + default: + fprintf( stderr, "ERROR: no %d list type defined!\n", l->type ); + MPI_Abort( comm, INVALID_INPUT ); + } +} + + +#if defined(PURE_REAX) +inline int Num_Entries( int i, reax_list *l ) +{ + return l->end_index[i] - l->index[i]; +} + +inline int Start_Index( int i, reax_list *l ) +{ + return l->index[i]; +} + +inline int End_Index( int i, reax_list *l ) +{ + return l->end_index[i]; +} + +inline void Set_Start_Index( int i, int val, reax_list *l ) +{ + l->index[i] = val; +} + +inline void Set_End_Index( int i, int val, reax_list *l ) +{ + l->end_index[i] = val; +} +#endif diff --git a/src/USER-REAXC/reaxc_list.h b/src/USER-REAXC/reaxc_list.h new file mode 100644 index 0000000000..cca217dbf7 --- /dev/null +++ b/src/USER-REAXC/reaxc_list.h @@ -0,0 +1,63 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __LIST_H_ +#define __LIST_H_ + +#include "reaxc_types.h" + +int Make_List( int, int, int, reax_list*, MPI_Comm ); +void Delete_List( reax_list*, MPI_Comm ); + +inline int Num_Entries(int,reax_list*); +inline int Start_Index( int, reax_list* ); +inline int End_Index( int, reax_list* ); +inline void Set_Start_Index(int,int,reax_list*); +inline void Set_End_Index(int,int,reax_list*); + +#if defined(LAMMPS_REAX) +inline int Num_Entries( int i, reax_list *l ) +{ + return l->end_index[i] - l->index[i]; +} + +inline int Start_Index( int i, reax_list *l ) +{ + return l->index[i]; +} + +inline int End_Index( int i, reax_list *l ) +{ + return l->end_index[i]; +} + +inline void Set_Start_Index( int i, int val, reax_list *l ) +{ + l->index[i] = val; +} + +inline void Set_End_Index( int i, int val, reax_list *l ) +{ + l->end_index[i] = val; +} +#endif // LAMMPS_REAX + +#endif diff --git a/src/USER-REAXC/reaxc_lookup.cpp b/src/USER-REAXC/reaxc_lookup.cpp new file mode 100644 index 0000000000..a4b851b9d8 --- /dev/null +++ b/src/USER-REAXC/reaxc_lookup.cpp @@ -0,0 +1,339 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "lookup.h" +#include "nonbonded.h" +#include "tool_box.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_lookup.h" +#include "reaxc_nonbonded.h" +#include "reaxc_tool_box.h" +#endif + +LR_lookup_table **LR; + +/* Fills solution into x. Warning: will modify c and d! */ +void Tridiagonal_Solve( const real *a, const real *b, + real *c, real *d, real *x, unsigned int n){ + int i; + real id; + + /* Modify the coefficients. */ + c[0] /= b[0]; /* Division by zero risk. */ + d[0] /= b[0]; /* Division by zero would imply a singular matrix. */ + for(i = 1; i < n; i++){ + id = (b[i] - c[i-1] * a[i]); /* Division by zero risk. */ + c[i] /= id; /* Last value calculated is redundant. */ + d[i] = (d[i] - d[i-1] * a[i])/id; + } + + /* Now back substitute. */ + x[n - 1] = d[n - 1]; + for(i = n - 2; i >= 0; i--) + x[i] = d[i] - c[i] * x[i + 1]; +} + + +void Natural_Cubic_Spline( const real *h, const real *f, + cubic_spline_coef *coef, unsigned int n, + MPI_Comm comm ) +{ + int i; + real *a, *b, *c, *d, *v; + + /* allocate space for the linear system */ + a = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm ); + b = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm ); + c = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm ); + d = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm ); + v = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm ); + + /* build the linear system */ + a[0] = a[1] = a[n-1] = 0; + for( i = 2; i < n-1; ++i ) + a[i] = h[i-1]; + + b[0] = b[n-1] = 0; + for( i = 1; i < n-1; ++i ) + b[i] = 2 * (h[i-1] + h[i]); + + c[0] = c[n-2] = c[n-1] = 0; + for( i = 1; i < n-2; ++i ) + c[i] = h[i]; + + d[0] = d[n-1] = 0; + for( i = 1; i < n-1; ++i ) + d[i] = 6 * ((f[i+1]-f[i])/h[i] - (f[i]-f[i-1])/h[i-1]); + + v[0] = 0; + v[n-1] = 0; + Tridiagonal_Solve( &(a[1]), &(b[1]), &(c[1]), &(d[1]), &(v[1]), n-2 ); + + for( i = 1; i < n; ++i ){ + coef[i-1].d = (v[i] - v[i-1]) / (6*h[i-1]); + coef[i-1].c = v[i]/2; + coef[i-1].b = (f[i]-f[i-1])/h[i-1] + h[i-1]*(2*v[i] + v[i-1])/6; + coef[i-1].a = f[i]; + } + + sfree( a, "cubic_spline:a" ); + sfree( b, "cubic_spline:b" ); + sfree( c, "cubic_spline:c" ); + sfree( d, "cubic_spline:d" ); + sfree( v, "cubic_spline:v" ); +} + + + +void Complete_Cubic_Spline( const real *h, const real *f, real v0, real vlast, + cubic_spline_coef *coef, unsigned int n, + MPI_Comm comm ) +{ + int i; + real *a, *b, *c, *d, *v; + + /* allocate space for the linear system */ + a = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm ); + b = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm ); + c = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm ); + d = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm ); + v = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm ); + + /* build the linear system */ + a[0] = 0; + for( i = 1; i < n; ++i ) + a[i] = h[i-1]; + + b[0] = 2*h[0]; + for( i = 1; i < n; ++i ) + b[i] = 2 * (h[i-1] + h[i]); + + c[n-1] = 0; + for( i = 0; i < n-1; ++i ) + c[i] = h[i]; + + d[0] = 6 * (f[1]-f[0])/h[0] - 6 * v0; + d[n-1] = 6 * vlast - 6 * (f[n-1]-f[n-2]/h[n-2]); + for( i = 1; i < n-1; ++i ) + d[i] = 6 * ((f[i+1]-f[i])/h[i] - (f[i]-f[i-1])/h[i-1]); + + Tridiagonal_Solve( &(a[0]), &(b[0]), &(c[0]), &(d[0]), &(v[0]), n ); + + for( i = 1; i < n; ++i ){ + coef[i-1].d = (v[i] - v[i-1]) / (6*h[i-1]); + coef[i-1].c = v[i]/2; + coef[i-1].b = (f[i]-f[i-1])/h[i-1] + h[i-1]*(2*v[i] + v[i-1])/6; + coef[i-1].a = f[i]; + } + + sfree( a, "cubic_spline:a" ); + sfree( b, "cubic_spline:b" ); + sfree( c, "cubic_spline:c" ); + sfree( d, "cubic_spline:d" ); + sfree( v, "cubic_spline:v" ); +} + + +void LR_Lookup( LR_lookup_table *t, real r, LR_data *y ) +{ + int i; + real base, dif; + + i = (int)(r * t->inv_dx); + if( i == 0 ) ++i; + base = (real)(i+1) * t->dx; + dif = r - base; + + y->e_vdW = ((t->vdW[i].d*dif + t->vdW[i].c)*dif + t->vdW[i].b)*dif + + t->vdW[i].a; + y->CEvd = ((t->CEvd[i].d*dif + t->CEvd[i].c)*dif + + t->CEvd[i].b)*dif + t->CEvd[i].a; + + y->e_ele = ((t->ele[i].d*dif + t->ele[i].c)*dif + t->ele[i].b)*dif + + t->ele[i].a; + y->CEclmb = ((t->CEclmb[i].d*dif + t->CEclmb[i].c)*dif + t->CEclmb[i].b)*dif + + t->CEclmb[i].a; + + y->H = y->e_ele * EV_to_KCALpMOL / C_ele; +} + + +int Init_Lookup_Tables( reax_system *system, control_params *control, + storage *workspace, mpi_datatypes *mpi_data, char *msg ) +{ + int i, j, r; + int num_atom_types; + int existing_types[MAX_ATOM_TYPES], aggregated[MAX_ATOM_TYPES]; + real dr; + real *h, *fh, *fvdw, *fele, *fCEvd, *fCEclmb; + real v0_vdw, v0_ele, vlast_vdw, vlast_ele; + MPI_Comm comm; + + /* initializations */ + v0_vdw = 0; + v0_ele = 0; + vlast_vdw = 0; + vlast_ele = 0; + comm = mpi_data->world; + + num_atom_types = system->reax_param.num_atom_types; + dr = control->nonb_cut / control->tabulate; + h = (real*) + smalloc( (control->tabulate+2) * sizeof(real), "lookup:h", comm ); + fh = (real*) + smalloc( (control->tabulate+2) * sizeof(real), "lookup:fh", comm ); + fvdw = (real*) + smalloc( (control->tabulate+2) * sizeof(real), "lookup:fvdw", comm ); + fCEvd = (real*) + smalloc( (control->tabulate+2) * sizeof(real), "lookup:fCEvd", comm ); + fele = (real*) + smalloc( (control->tabulate+2) * sizeof(real), "lookup:fele", comm ); + fCEclmb = (real*) + smalloc( (control->tabulate+2) * sizeof(real), "lookup:fCEclmb", comm ); + + /* allocate Long-Range LookUp Table space based on + number of atom types in the ffield file */ + LR = (LR_lookup_table**) + scalloc( num_atom_types, sizeof(LR_lookup_table*), "lookup:LR", comm ); + for( i = 0; i < num_atom_types; ++i ) + LR[i] = (LR_lookup_table*) + scalloc( num_atom_types, sizeof(LR_lookup_table), "lookup:LR[i]", comm ); + + /* most atom types in ffield file will not exist in the current + simulation. to avoid unnecessary lookup table space, determine + the atom types that exist in the current simulation */ + for( i = 0; i < MAX_ATOM_TYPES; ++i ) + existing_types[i] = 0; + for( i = 0; i < system->n; ++i ) + existing_types[ system->my_atoms[i].type ] = 1; + + MPI_Allreduce( existing_types, aggregated, MAX_ATOM_TYPES, + MPI_INT, MPI_SUM, mpi_data->world ); + + /* fill in the lookup table entries for existing atom types. + only lower half should be enough. */ + for( i = 0; i < num_atom_types; ++i ) + if( aggregated[i] ) + //for( j = 0; j < num_atom_types; ++j ) + for( j = i; j < num_atom_types; ++j ) + if( aggregated[j] ) { + LR[i][j].xmin = 0; + LR[i][j].xmax = control->nonb_cut; + LR[i][j].n = control->tabulate + 2; + LR[i][j].dx = dr; + LR[i][j].inv_dx = control->tabulate / control->nonb_cut; + LR[i][j].y = (LR_data*) + smalloc( LR[i][j].n * sizeof(LR_data), "lookup:LR[i,j].y", comm ); + LR[i][j].H = (cubic_spline_coef*) + smalloc( LR[i][j].n*sizeof(cubic_spline_coef),"lookup:LR[i,j].H" , + comm ); + LR[i][j].vdW = (cubic_spline_coef*) + smalloc( LR[i][j].n*sizeof(cubic_spline_coef),"lookup:LR[i,j].vdW", + comm); + LR[i][j].CEvd = (cubic_spline_coef*) + smalloc( LR[i][j].n*sizeof(cubic_spline_coef),"lookup:LR[i,j].CEvd", + comm); + LR[i][j].ele = (cubic_spline_coef*) + smalloc( LR[i][j].n*sizeof(cubic_spline_coef),"lookup:LR[i,j].ele", + comm ); + LR[i][j].CEclmb = (cubic_spline_coef*) + smalloc( LR[i][j].n*sizeof(cubic_spline_coef), + "lookup:LR[i,j].CEclmb", comm ); + + for( r = 1; r <= control->tabulate; ++r ) { + LR_vdW_Coulomb( system, workspace, i, j, r * dr, &(LR[i][j].y[r]) ); + h[r] = LR[i][j].dx; + fh[r] = LR[i][j].y[r].H; + fvdw[r] = LR[i][j].y[r].e_vdW; + fCEvd[r] = LR[i][j].y[r].CEvd; + fele[r] = LR[i][j].y[r].e_ele; + fCEclmb[r] = LR[i][j].y[r].CEclmb; + } + + // init the start-end points + h[r] = LR[i][j].dx; + v0_vdw = LR[i][j].y[1].CEvd; + v0_ele = LR[i][j].y[1].CEclmb; + fh[r] = fh[r-1]; + fvdw[r] = fvdw[r-1]; + fCEvd[r] = fCEvd[r-1]; + fele[r] = fele[r-1]; + fCEclmb[r] = fCEclmb[r-1]; + vlast_vdw = fCEvd[r-1]; + vlast_ele = fele[r-1]; + + Natural_Cubic_Spline( &h[1], &fh[1], + &(LR[i][j].H[1]), control->tabulate+1, comm ); + + Complete_Cubic_Spline( &h[1], &fvdw[1], v0_vdw, vlast_vdw, + &(LR[i][j].vdW[1]), control->tabulate+1, + comm ); + + Natural_Cubic_Spline( &h[1], &fCEvd[1], + &(LR[i][j].CEvd[1]), control->tabulate+1, + comm ); + + Complete_Cubic_Spline( &h[1], &fele[1], v0_ele, vlast_ele, + &(LR[i][j].ele[1]), control->tabulate+1, + comm ); + + Natural_Cubic_Spline( &h[1], &fCEclmb[1], + &(LR[i][j].CEclmb[1]), control->tabulate+1, + comm ); + } + else{ + LR[i][j].n = 0; + } + + free(h); + free(fh); + free(fvdw); + free(fCEvd); + free(fele); + free(fCEclmb); + + return 1; +} + + +void Deallocate_Lookup_Tables( reax_system *system ) +{ + int i, j; + int ntypes; + + ntypes = system->reax_param.num_atom_types; + + for( i = 0; i < ntypes; ++i ) { + for( j = i; j < ntypes; ++j ) + if( LR[i][j].n ) { + sfree( LR[i][j].y, "LR[i,j].y" ); + sfree( LR[i][j].H, "LR[i,j].H" ); + sfree( LR[i][j].vdW, "LR[i,j].vdW" ); + sfree( LR[i][j].CEvd, "LR[i,j].CEvd" ); + sfree( LR[i][j].ele, "LR[i,j].ele" ); + sfree( LR[i][j].CEclmb, "LR[i,j].CEclmb" ); + } + sfree( LR[i], "LR[i]" ); + } + sfree( LR, "LR" ); +} diff --git a/src/USER-REAXC/reaxc_lookup.h b/src/USER-REAXC/reaxc_lookup.h new file mode 100644 index 0000000000..28658386b4 --- /dev/null +++ b/src/USER-REAXC/reaxc_lookup.h @@ -0,0 +1,32 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __LOOKUP_H_ +#define __LOOKUP_H_ + +#include "reaxc_types.h" + +int Init_Lookup_Tables( reax_system*, control_params*, storage*, + mpi_datatypes*, char* ); + +void Deallocate_Lookup_Tables( reax_system* ); + +#endif diff --git a/src/USER-REAXC/reaxc_multi_body.cpp b/src/USER-REAXC/reaxc_multi_body.cpp new file mode 100644 index 0000000000..88b671e24a --- /dev/null +++ b/src/USER-REAXC/reaxc_multi_body.cpp @@ -0,0 +1,311 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "multi_body.h" +#include "bond_orders.h" +#include "list.h" +#include "vector.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_multi_body.h" +#include "reaxc_bond_orders.h" +#include "reaxc_list.h" +#include "reaxc_vector.h" +#endif + + +void Atom_Energy( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, reax_list **lists, + output_controls *out_control ) +{ + int i, j, pj, type_i, type_j; + real Delta_lpcorr, dfvl; + real e_lp, expvd2, inv_expvd2, dElp, CElp, DlpVi; + real e_lph, Di, vov3, deahu2dbo, deahu2dsbo; + real e_ov, CEover1, CEover2, CEover3, CEover4; + real exp_ovun1, exp_ovun2, sum_ovun1, sum_ovun2; + real exp_ovun2n, exp_ovun6, exp_ovun8; + real inv_exp_ovun1, inv_exp_ovun2, inv_exp_ovun2n, inv_exp_ovun8; + real e_un, CEunder1, CEunder2, CEunder3, CEunder4; + real p_lp1, p_lp2, p_lp3; + real p_ovun2, p_ovun3, p_ovun4, p_ovun5, p_ovun6, p_ovun7, p_ovun8; + + single_body_parameters *sbp_i, *sbp_j; + two_body_parameters *twbp; + bond_data *pbond; + bond_order_data *bo_ij; + reax_list *bonds = (*lists) + BONDS; + + /* Initialize parameters */ + p_lp1 = system->reax_param.gp.l[15]; + p_lp3 = system->reax_param.gp.l[5]; + p_ovun3 = system->reax_param.gp.l[32]; + p_ovun4 = system->reax_param.gp.l[31]; + p_ovun6 = system->reax_param.gp.l[6]; + p_ovun7 = system->reax_param.gp.l[8]; + p_ovun8 = system->reax_param.gp.l[9]; + + for( i = 0; i < system->n; ++i ) { + /* set the parameter pointer */ + type_i = system->my_atoms[i].type; + sbp_i = &(system->reax_param.sbp[ type_i ]); + + /* lone-pair Energy */ + p_lp2 = sbp_i->p_lp2; + expvd2 = exp( -75 * workspace->Delta_lp[i] ); + inv_expvd2 = 1. / (1. + expvd2 ); + + /* calculate the energy */ + data->my_en.e_lp += e_lp = + p_lp2 * workspace->Delta_lp[i] * inv_expvd2; + + dElp = p_lp2 * inv_expvd2 + + 75 * p_lp2 * workspace->Delta_lp[i] * expvd2 * SQR(inv_expvd2); + CElp = dElp * workspace->dDelta_lp[i]; + + workspace->CdDelta[i] += CElp; // lp - 1st term + +#ifdef TEST_ENERGY +// fprintf( out_control->elp, "%24.15e%24.15e%24.15e%24.15e\n", +// p_lp2, workspace->Delta_lp_temp[i], expvd2, dElp ); +// fprintf( out_control->elp, "%6d%24.15e%24.15e%24.15e\n", + fprintf( out_control->elp, "%6d%12.4f%12.4f%12.4f\n", + system->my_atoms[i].orig_id, workspace->nlp[i], + e_lp, data->my_en.e_lp ); +#endif +#ifdef TEST_FORCES + Add_dDelta( system, lists, i, CElp, workspace->f_lp ); // lp - 1st term +#endif + + /* correction for C2 */ + if( system->reax_param.gp.l[5] > 0.001 && + !strcmp( system->reax_param.sbp[type_i].name, "C" ) ) + for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) + if( system->my_atoms[i].orig_id < + system->my_atoms[bonds->select.bond_list[pj].nbr].orig_id ) { + j = bonds->select.bond_list[pj].nbr; + type_j = system->my_atoms[j].type; + + if( !strcmp( system->reax_param.sbp[type_j].name, "C" ) ) { + twbp = &( system->reax_param.tbp[type_i][type_j]); + bo_ij = &( bonds->select.bond_list[pj].bo_data ); + Di = workspace->Delta[i]; + vov3 = bo_ij->BO - Di - 0.040*pow(Di, 4.); + + if( vov3 > 3. ) { + data->my_en.e_lp += e_lph = p_lp3 * SQR(vov3-3.0); + + deahu2dbo = 2.*p_lp3*(vov3 - 3.); + deahu2dsbo = 2.*p_lp3*(vov3 - 3.)*(-1. - 0.16*pow(Di, 3.)); + + bo_ij->Cdbo += deahu2dbo; + workspace->CdDelta[i] += deahu2dsbo; +#ifdef TEST_ENERGY + fprintf(out_control->elp,"C2cor%6d%6d%12.6f%12.6f%12.6f\n", + system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, + e_lph, deahu2dbo, deahu2dsbo ); +#endif +#ifdef TEST_FORCES + Add_dBO(system, lists, i, pj, deahu2dbo, workspace->f_lp); + Add_dDelta(system, lists, i, deahu2dsbo, workspace->f_lp); +#endif + } + } + } + } + + + for( i = 0; i < system->n; ++i ) { + type_i = system->my_atoms[i].type; + sbp_i = &(system->reax_param.sbp[ type_i ]); + + /* over-coordination energy */ + if( sbp_i->mass > 21.0 ) + dfvl = 0.0; + else dfvl = 1.0; // only for 1st-row elements + + p_ovun2 = sbp_i->p_ovun2; + sum_ovun1 = sum_ovun2 = 0; + for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) { + j = bonds->select.bond_list[pj].nbr; + type_j = system->my_atoms[j].type; + bo_ij = &(bonds->select.bond_list[pj].bo_data); + sbp_j = &(system->reax_param.sbp[ type_j ]); + twbp = &(system->reax_param.tbp[ type_i ][ type_j ]); + + sum_ovun1 += twbp->p_ovun1 * twbp->De_s * bo_ij->BO; + sum_ovun2 += (workspace->Delta[j] - dfvl*workspace->Delta_lp_temp[j])* + ( bo_ij->BO_pi + bo_ij->BO_pi2 ); + + /*fprintf( stdout, "%4d%4d%12.6f%12.6f%12.6f\n", + i+1, j+1, + dfvl * workspace->Delta_lp_temp[j], + sbp_j->nlp_opt, + workspace->nlp_temp[j] );*/ + } + + exp_ovun1 = p_ovun3 * exp( p_ovun4 * sum_ovun2 ); + inv_exp_ovun1 = 1.0 / (1 + exp_ovun1); + Delta_lpcorr = workspace->Delta[i] - + (dfvl * workspace->Delta_lp_temp[i]) * inv_exp_ovun1; + + exp_ovun2 = exp( p_ovun2 * Delta_lpcorr ); + inv_exp_ovun2 = 1.0 / (1.0 + exp_ovun2); + + DlpVi = 1.0 / (Delta_lpcorr + sbp_i->valency + 1e-8); + CEover1 = Delta_lpcorr * DlpVi * inv_exp_ovun2; + + data->my_en.e_ov += e_ov = sum_ovun1 * CEover1; + + CEover2 = sum_ovun1 * DlpVi * inv_exp_ovun2 * + (1.0 - Delta_lpcorr * ( DlpVi + p_ovun2 * exp_ovun2 * inv_exp_ovun2 )); + + CEover3 = CEover2 * (1.0 - dfvl * workspace->dDelta_lp[i] * inv_exp_ovun1 ); + + CEover4 = CEover2 * (dfvl * workspace->Delta_lp_temp[i]) * + p_ovun4 * exp_ovun1 * SQR(inv_exp_ovun1); + + + /* under-coordination potential */ + p_ovun2 = sbp_i->p_ovun2; + p_ovun5 = sbp_i->p_ovun5; + + exp_ovun2n = 1.0 / exp_ovun2; + exp_ovun6 = exp( p_ovun6 * Delta_lpcorr ); + exp_ovun8 = p_ovun7 * exp(p_ovun8 * sum_ovun2); + inv_exp_ovun2n = 1.0 / (1.0 + exp_ovun2n); + inv_exp_ovun8 = 1.0 / (1.0 + exp_ovun8); + + data->my_en.e_un += e_un = + -p_ovun5 * (1.0 - exp_ovun6) * inv_exp_ovun2n * inv_exp_ovun8; + + CEunder1 = inv_exp_ovun2n * + ( p_ovun5 * p_ovun6 * exp_ovun6 * inv_exp_ovun8 + + p_ovun2 * e_un * exp_ovun2n ); + CEunder2 = -e_un * p_ovun8 * exp_ovun8 * inv_exp_ovun8; + CEunder3 = CEunder1 * (1.0 - dfvl*workspace->dDelta_lp[i]*inv_exp_ovun1); + CEunder4 = CEunder1 * (dfvl*workspace->Delta_lp_temp[i]) * + p_ovun4 * exp_ovun1 * SQR(inv_exp_ovun1) + CEunder2; + + + /* forces */ + workspace->CdDelta[i] += CEover3; // OvCoor - 2nd term + workspace->CdDelta[i] += CEunder3; // UnCoor - 1st term + +#ifdef TEST_FORCES + Add_dDelta( system, lists, i, CEover3, workspace->f_ov ); // OvCoor 2nd + Add_dDelta( system, lists, i, CEunder3, workspace->f_un ); // UnCoor 1st +#endif + + for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) { + pbond = &(bonds->select.bond_list[pj]); + j = pbond->nbr; + bo_ij = &(pbond->bo_data); + twbp = &(system->reax_param.tbp[ system->my_atoms[i].type ] + [system->my_atoms[pbond->nbr].type]); + + + bo_ij->Cdbo += CEover1 * twbp->p_ovun1 * twbp->De_s;// OvCoor-1st + workspace->CdDelta[j] += CEover4 * (1.0 - dfvl*workspace->dDelta_lp[j]) * + (bo_ij->BO_pi + bo_ij->BO_pi2); // OvCoor-3a + bo_ij->Cdbopi += CEover4 * + (workspace->Delta[j] - dfvl*workspace->Delta_lp_temp[j]); // OvCoor-3b + bo_ij->Cdbopi2 += CEover4 * + (workspace->Delta[j] - dfvl*workspace->Delta_lp_temp[j]); // OvCoor-3b + + + workspace->CdDelta[j] += CEunder4 * (1.0 - dfvl*workspace->dDelta_lp[j]) * + (bo_ij->BO_pi + bo_ij->BO_pi2); // UnCoor - 2a + bo_ij->Cdbopi += CEunder4 * + (workspace->Delta[j] - dfvl*workspace->Delta_lp_temp[j]); // UnCoor-2b + bo_ij->Cdbopi2 += CEunder4 * + (workspace->Delta[j] - dfvl*workspace->Delta_lp_temp[j]); // UnCoor-2b + + +#ifdef TEST_ENERGY +/* fprintf( out_control->eov, "%6d%12.6f\n", + workspace->reverse_map[j], + // CEover1 * twbp->p_ovun1 * twbp->De_s, CEover3, + CEover4 * (1.0 - workspace->dDelta_lp[j]) * + (bo_ij->BO_pi + bo_ij->BO_pi2) +*/// /*CEover4 * (workspace->Delta[j]-workspace->Delta_lp[j])*/); +// fprintf( out_control->eov, "%6d%12.6f\n", +// fprintf( out_control->eov, "%6d%24.15e\n", +// system->my_atoms[j].orig_id, + // CEover1 * twbp->p_ovun1 * twbp->De_s, CEover3, +// CEover4 * (1.0 - workspace->dDelta_lp[j]) * +// (bo_ij->BO_pi + bo_ij->BO_pi2) +// /*CEover4 * (workspace->Delta[j]-workspace->Delta_lp[j])*/); + + // CEunder4 * (1.0 - workspace->dDelta_lp[j]) * + // (bo_ij->BO_pi + bo_ij->BO_pi2), + // CEunder4 * (workspace->Delta[j] - workspace->Delta_lp[j]) ); +#endif + +#ifdef TEST_FORCES + Add_dBO( system, lists, i, pj, CEover1 * twbp->p_ovun1 * twbp->De_s, + workspace->f_ov ); // OvCoor - 1st term + + Add_dDelta( system, lists, j, + CEover4 * (1.0 - dfvl*workspace->dDelta_lp[j]) * + (bo_ij->BO_pi + bo_ij->BO_pi2), + workspace->f_ov ); // OvCoor - 3a + + Add_dBOpinpi2( system, lists, i, pj, + CEover4 * (workspace->Delta[j] - + dfvl * workspace->Delta_lp_temp[j]), + CEover4 * (workspace->Delta[j] - + dfvl * workspace->Delta_lp_temp[j]), + workspace->f_ov, workspace->f_ov ); // OvCoor - 3b + + Add_dDelta( system, lists, j, + CEunder4 * (1.0 - dfvl*workspace->dDelta_lp[j]) * + (bo_ij->BO_pi + bo_ij->BO_pi2), + workspace->f_un ); // UnCoor - 2a + + Add_dBOpinpi2( system, lists, i, pj, + CEunder4 * (workspace->Delta[j] - + dfvl * workspace->Delta_lp_temp[j]), + CEunder4 * (workspace->Delta[j] - + dfvl * workspace->Delta_lp_temp[j]), + workspace->f_un, workspace->f_un ); // UnCoor - 2b +#endif + } + +#ifdef TEST_ENERGY + //fprintf( out_control->elp, "%6d%24.15e%24.15e%24.15e\n", + //fprintf( out_control->elp, "%6d%12.4f%12.4f%12.4f\n", + // system->my_atoms[i].orig_id, workspace->nlp[i], + // e_lp, data->my_en.e_lp ); + + //fprintf( out_control->eov, "%6d%24.15e%24.15e\n", + fprintf( out_control->eov, "%6d%12.4f%12.4f\n", + system->my_atoms[i].orig_id, + e_ov, data->my_en.e_ov + data->my_en.e_un ); + + //fprintf( out_control->eun, "%6d%24.15e%24.15e\n", + fprintf( out_control->eun, "%6d%12.4f%12.4f\n", + system->my_atoms[i].orig_id, + e_un, data->my_en.e_ov + data->my_en.e_un ); +#endif + } +} diff --git a/src/USER-REAXC/reaxc_multi_body.h b/src/USER-REAXC/reaxc_multi_body.h new file mode 100644 index 0000000000..dcd11fc7e7 --- /dev/null +++ b/src/USER-REAXC/reaxc_multi_body.h @@ -0,0 +1,31 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __MULTI_BODY_H_ +#define __MULTI_BODY_H_ + +#include "reaxc_types.h" + +void Atom_Energy( reax_system*, control_params*, simulation_data*, + storage*, reax_list**, output_controls* ); + +#endif + diff --git a/src/USER-REAXC/reaxc_nonbonded.cpp b/src/USER-REAXC/reaxc_nonbonded.cpp new file mode 100644 index 0000000000..419779a68f --- /dev/null +++ b/src/USER-REAXC/reaxc_nonbonded.cpp @@ -0,0 +1,424 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "nonbonded.h" +#include "bond_orders.h" +#include "list.h" +#include "vector.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_nonbonded.h" +#include "reaxc_bond_orders.h" +#include "reaxc_list.h" +#include "reaxc_vector.h" +#endif + + +void vdW_Coulomb_Energy( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control ) +{ + int i, j, pj, natoms; + int start_i, end_i, orig_i, orig_j; + real p_vdW1, p_vdW1i; + real powr_vdW1, powgi_vdW1; + real tmp, r_ij, fn13, exp1, exp2; + real Tap, dTap, dfn13, CEvd, CEclmb, de_core; + real dr3gamij_1, dr3gamij_3; + real e_ele, e_vdW, e_core; + rvec temp, ext_press; + two_body_parameters *twbp; + far_neighbor_data *nbr_pj; + reax_list *far_nbrs; + // rtensor temp_rtensor, total_rtensor; + + natoms = system->n; + far_nbrs = (*lists) + FAR_NBRS; + p_vdW1 = system->reax_param.gp.l[28]; + p_vdW1i = 1.0 / p_vdW1; + e_core = 0; + e_vdW = 0; + + for( i = 0; i < natoms; ++i ) { + start_i = Start_Index(i, far_nbrs); + end_i = End_Index(i, far_nbrs); + orig_i = system->my_atoms[i].orig_id; + //fprintf( stderr, "i:%d, start_i: %d, end_i: %d\n", i, start_i, end_i ); + + for( pj = start_i; pj < end_i; ++pj ) { + nbr_pj = &(far_nbrs->select.far_nbr_list[pj]); + j = nbr_pj->nbr; + orig_j = system->my_atoms[j].orig_id; + + if( nbr_pj->d <= control->nonb_cut && (j < natoms || orig_i < orig_j) ) { + r_ij = nbr_pj->d; + twbp = &(system->reax_param.tbp[ system->my_atoms[i].type ] + [ system->my_atoms[j].type ]); + + /* Calculate Taper and its derivative */ + // Tap = nbr_pj->Tap; -- precomputed during compte_H + Tap = workspace->Tap[7] * r_ij + workspace->Tap[6]; + Tap = Tap * r_ij + workspace->Tap[5]; + Tap = Tap * r_ij + workspace->Tap[4]; + Tap = Tap * r_ij + workspace->Tap[3]; + Tap = Tap * r_ij + workspace->Tap[2]; + Tap = Tap * r_ij + workspace->Tap[1]; + Tap = Tap * r_ij + workspace->Tap[0]; + + dTap = 7*workspace->Tap[7] * r_ij + 6*workspace->Tap[6]; + dTap = dTap * r_ij + 5*workspace->Tap[5]; + dTap = dTap * r_ij + 4*workspace->Tap[4]; + dTap = dTap * r_ij + 3*workspace->Tap[3]; + dTap = dTap * r_ij + 2*workspace->Tap[2]; + dTap += workspace->Tap[1]/r_ij; + + /*vdWaals Calculations*/ + if(system->reax_param.gp.vdw_type==1 || system->reax_param.gp.vdw_type==3) + { // shielding + powr_vdW1 = pow(r_ij, p_vdW1); + powgi_vdW1 = pow( 1.0 / twbp->gamma_w, p_vdW1); + + fn13 = pow( powr_vdW1 + powgi_vdW1, p_vdW1i ); + exp1 = exp( twbp->alpha * (1.0 - fn13 / twbp->r_vdW) ); + exp2 = exp( 0.5 * twbp->alpha * (1.0 - fn13 / twbp->r_vdW) ); + + e_vdW = twbp->D * (exp1 - 2.0 * exp2); + data->my_en.e_vdW += Tap * e_vdW; + + dfn13 = pow( powr_vdW1 + powgi_vdW1, p_vdW1i - 1.0) * + pow(r_ij, p_vdW1 - 2.0); + + CEvd = dTap * e_vdW - + Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2) * dfn13; + } + else{ // no shielding + exp1 = exp( twbp->alpha * (1.0 - r_ij / twbp->r_vdW) ); + exp2 = exp( 0.5 * twbp->alpha * (1.0 - r_ij / twbp->r_vdW) ); + + e_vdW = twbp->D * (exp1 - 2.0 * exp2); + data->my_en.e_vdW += Tap * e_vdW; + + CEvd = dTap * e_vdW - + Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2); + } + + if(system->reax_param.gp.vdw_type==2 || system->reax_param.gp.vdw_type==3) + { // innner wall + e_core = twbp->ecore * exp(twbp->acore * (1.0-(r_ij/twbp->rcore))); + data->my_en.e_vdW += Tap * e_core; + + de_core = -(twbp->acore/twbp->rcore) * e_core; + CEvd += dTap * e_core + Tap * de_core; + } + + /*Coulomb Calculations*/ + dr3gamij_1 = ( r_ij * r_ij * r_ij + twbp->gamma ); + dr3gamij_3 = pow( dr3gamij_1 , 0.33333333333333 ); + + tmp = Tap / dr3gamij_3; + data->my_en.e_ele += e_ele = + C_ele * system->my_atoms[i].q * system->my_atoms[j].q * tmp; + + + CEclmb = C_ele * system->my_atoms[i].q * system->my_atoms[j].q * + ( dTap - Tap * r_ij / dr3gamij_1 ) / dr3gamij_3; + // fprintf( fout, "%5d %5d %10.6f %10.6f\n", + // MIN( system->my_atoms[i].orig_id, system->my_atoms[j].orig_id ), + // MAX( system->my_atoms[i].orig_id, system->my_atoms[j].orig_id ), + // CEvd, CEclmb ); + + if( control->virial == 0 ) { + rvec_ScaledAdd( workspace->f[i], -(CEvd + CEclmb), nbr_pj->dvec ); + rvec_ScaledAdd( workspace->f[j], +(CEvd + CEclmb), nbr_pj->dvec ); + } + else { /* NPT, iNPT or sNPT */ + /* for pressure coupling, terms not related to bond order + derivatives are added directly into pressure vector/tensor */ + rvec_Scale( temp, CEvd + CEclmb, nbr_pj->dvec ); + + rvec_ScaledAdd( workspace->f[i], -1., temp ); + rvec_Add( workspace->f[j], temp ); + + rvec_iMultiply( ext_press, nbr_pj->rel_box, temp ); + rvec_Add( data->my_ext_press, ext_press ); + + // fprintf( stderr, "nonbonded(%d,%d): rel_box (%f %f %f) + // force(%f %f %f) ext_press (%12.6f %12.6f %12.6f)\n", + // i, j, nbr_pj->rel_box[0], nbr_pj->rel_box[1], nbr_pj->rel_box[2], + // temp[0], temp[1], temp[2], + // data->ext_press[0], data->ext_press[1], data->ext_press[2] ); + } + +#ifdef TEST_ENERGY + // fprintf( out_control->evdw, + // "%12.9f%12.9f%12.9f%12.9f%12.9f%12.9f%12.9f%12.9f\n", + // workspace->Tap[7],workspace->Tap[6],workspace->Tap[5], + // workspace->Tap[4],workspace->Tap[3],workspace->Tap[2], + // workspace->Tap[1], Tap ); + //fprintf( out_control->evdw, "%6d%6d%24.15e%24.15e%24.15e\n", + fprintf( out_control->evdw, "%6d%6d%12.4f%12.4f%12.4f\n", + system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, + r_ij, e_vdW, data->my_en.e_vdW ); + //fprintf(out_control->ecou,"%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e\n", + fprintf( out_control->ecou, "%6d%6d%12.4f%12.4f%12.4f%12.4f%12.4f\n", + system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, + r_ij, system->my_atoms[i].q, system->my_atoms[j].q, + e_ele, data->my_en.e_ele ); +#endif +#ifdef TEST_FORCES + rvec_ScaledAdd( workspace->f_vdw[i], -CEvd, nbr_pj->dvec ); + rvec_ScaledAdd( workspace->f_vdw[j], +CEvd, nbr_pj->dvec ); + rvec_ScaledAdd( workspace->f_ele[i], -CEclmb, nbr_pj->dvec ); + rvec_ScaledAdd( workspace->f_ele[j], +CEclmb, nbr_pj->dvec ); +#endif + } + } + } + +#if defined(DEBUG) + fprintf( stderr, "nonbonded: ext_press (%12.6f %12.6f %12.6f)\n", + data->ext_press[0], data->ext_press[1], data->ext_press[2] ); + MPI_Barrier( MPI_COMM_WORLD ); +#endif + + Compute_Polarization_Energy( system, data ); +} + + + +void Tabulated_vdW_Coulomb_Energy( reax_system *system,control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, + output_controls *out_control ) +{ + int i, j, pj, r, natoms, steps, update_freq, update_energies; + int type_i, type_j, tmin, tmax; + int start_i, end_i, orig_i, orig_j; + real r_ij, base, dif; + real e_vdW, e_ele; + real CEvd, CEclmb; + rvec temp, ext_press; + far_neighbor_data *nbr_pj; + reax_list *far_nbrs; + LR_lookup_table *t; + + natoms = system->n; + far_nbrs = (*lists) + FAR_NBRS; + steps = data->step - data->prev_steps; + update_freq = out_control->energy_update_freq; + update_energies = update_freq > 0 && steps % update_freq == 0; + e_ele = e_vdW = 0; + + for( i = 0; i < natoms; ++i ) { + type_i = system->my_atoms[i].type; + start_i = Start_Index(i,far_nbrs); + end_i = End_Index(i,far_nbrs); + orig_i = system->my_atoms[i].orig_id; + + for( pj = start_i; pj < end_i; ++pj ) { + nbr_pj = &(far_nbrs->select.far_nbr_list[pj]); + j = nbr_pj->nbr; + orig_j = system->my_atoms[j].orig_id; + + if( nbr_pj->d <= control->nonb_cut && (j < natoms || orig_i < orig_j) ) { + j = nbr_pj->nbr; + type_j = system->my_atoms[j].type; + r_ij = nbr_pj->d; + tmin = MIN( type_i, type_j ); + tmax = MAX( type_i, type_j ); + t = &( LR[tmin][tmax] ); + //t = &( LR[type_i][type_j] ); + + /* Cubic Spline Interpolation */ + r = (int)(r_ij * t->inv_dx); + if( r == 0 ) ++r; + base = (real)(r+1) * t->dx; + dif = r_ij - base; + //fprintf(stderr, "r: %f, i: %d, base: %f, dif: %f\n", r, i, base, dif); + + if( update_energies ) { + e_vdW = ((t->vdW[r].d*dif + t->vdW[r].c)*dif + t->vdW[r].b)*dif + + t->vdW[r].a; + + e_ele = ((t->ele[r].d*dif + t->ele[r].c)*dif + t->ele[r].b)*dif + + t->ele[r].a; + e_ele *= system->my_atoms[i].q * system->my_atoms[j].q; + + data->my_en.e_vdW += e_vdW; + data->my_en.e_ele += e_ele; + } + + CEvd = ((t->CEvd[r].d*dif + t->CEvd[r].c)*dif + t->CEvd[r].b)*dif + + t->CEvd[r].a; + + CEclmb = ((t->CEclmb[r].d*dif+t->CEclmb[r].c)*dif+t->CEclmb[r].b)*dif + + t->CEclmb[r].a; + CEclmb *= system->my_atoms[i].q * system->my_atoms[j].q; + + if( control->virial == 0 ) { + rvec_ScaledAdd( workspace->f[i], -(CEvd + CEclmb), nbr_pj->dvec ); + rvec_ScaledAdd( workspace->f[j], +(CEvd + CEclmb), nbr_pj->dvec ); + } + else { // NPT, iNPT or sNPT + /* for pressure coupling, terms not related to bond order derivatives + are added directly into pressure vector/tensor */ + rvec_Scale( temp, CEvd + CEclmb, nbr_pj->dvec ); + + rvec_ScaledAdd( workspace->f[i], -1., temp ); + rvec_Add( workspace->f[j], temp ); + + rvec_iMultiply( ext_press, nbr_pj->rel_box, temp ); + rvec_Add( data->my_ext_press, ext_press ); + } + +#ifdef TEST_ENERGY + //fprintf( out_control->evdw, "%6d%6d%24.15e%24.15e%24.15e\n", + fprintf( out_control->evdw, "%6d%6d%12.4f%12.4f%12.4f\n", + system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, + r_ij, e_vdW, data->my_en.e_vdW ); + //fprintf(out_control->ecou,"%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e\n", + fprintf( out_control->ecou, "%6d%6d%12.4f%12.4f%12.4f%12.4f%12.4f\n", + system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, + r_ij, system->my_atoms[i].q, system->my_atoms[j].q, + e_ele, data->my_en.e_ele ); +#endif +#ifdef TEST_FORCES + rvec_ScaledAdd( workspace->f_vdw[i], -CEvd, nbr_pj->dvec ); + rvec_ScaledAdd( workspace->f_vdw[j], +CEvd, nbr_pj->dvec ); + rvec_ScaledAdd( workspace->f_ele[i], -CEclmb, nbr_pj->dvec ); + rvec_ScaledAdd( workspace->f_ele[j], +CEclmb, nbr_pj->dvec ); +#endif + } + } + } + + Compute_Polarization_Energy( system, data ); +} + + + +void Compute_Polarization_Energy( reax_system *system, simulation_data *data ) +{ + int i, type_i; + real q; + + data->my_en.e_pol = 0.0; + for( i = 0; i < system->n; i++ ) { + q = system->my_atoms[i].q; + type_i = system->my_atoms[i].type; + + data->my_en.e_pol += + KCALpMOL_to_EV * (system->reax_param.sbp[type_i].chi * q + + (system->reax_param.sbp[type_i].eta / 2.) * SQR(q)); + } +} + + +void LR_vdW_Coulomb( reax_system *system, storage *workspace, + int i, int j, real r_ij, LR_data *lr ) +{ + real p_vdW1 = system->reax_param.gp.l[28]; + real p_vdW1i = 1.0 / p_vdW1; + real powr_vdW1, powgi_vdW1; + real tmp, fn13, exp1, exp2; + real Tap, dTap, dfn13; + real dr3gamij_1, dr3gamij_3; + real e_core, de_core; + two_body_parameters *twbp; + + twbp = &(system->reax_param.tbp[i][j]); + e_core = 0; + de_core = 0; + + /* calculate taper and its derivative */ + Tap = workspace->Tap[7] * r_ij + workspace->Tap[6]; + Tap = Tap * r_ij + workspace->Tap[5]; + Tap = Tap * r_ij + workspace->Tap[4]; + Tap = Tap * r_ij + workspace->Tap[3]; + Tap = Tap * r_ij + workspace->Tap[2]; + Tap = Tap * r_ij + workspace->Tap[1]; + Tap = Tap * r_ij + workspace->Tap[0]; + + dTap = 7*workspace->Tap[7] * r_ij + 6*workspace->Tap[6]; + dTap = dTap * r_ij + 5*workspace->Tap[5]; + dTap = dTap * r_ij + 4*workspace->Tap[4]; + dTap = dTap * r_ij + 3*workspace->Tap[3]; + dTap = dTap * r_ij + 2*workspace->Tap[2]; + dTap += workspace->Tap[1]/r_ij; + + /*vdWaals Calculations*/ + if(system->reax_param.gp.vdw_type==1 || system->reax_param.gp.vdw_type==3) + { // shielding + powr_vdW1 = pow(r_ij, p_vdW1); + powgi_vdW1 = pow( 1.0 / twbp->gamma_w, p_vdW1); + + fn13 = pow( powr_vdW1 + powgi_vdW1, p_vdW1i ); + exp1 = exp( twbp->alpha * (1.0 - fn13 / twbp->r_vdW) ); + exp2 = exp( 0.5 * twbp->alpha * (1.0 - fn13 / twbp->r_vdW) ); + + lr->e_vdW = Tap * twbp->D * (exp1 - 2.0 * exp2); + + dfn13 = pow( powr_vdW1 + powgi_vdW1, p_vdW1i-1.0) * pow(r_ij, p_vdW1-2.0); + + lr->CEvd = dTap * twbp->D * (exp1 - 2.0 * exp2) - + Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2) * dfn13; + } + else{ // no shielding + exp1 = exp( twbp->alpha * (1.0 - r_ij / twbp->r_vdW) ); + exp2 = exp( 0.5 * twbp->alpha * (1.0 - r_ij / twbp->r_vdW) ); + + lr->e_vdW = Tap * twbp->D * (exp1 - 2.0 * exp2); + lr->CEvd = dTap * twbp->D * (exp1 - 2.0 * exp2) - + Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2); + } + + if(system->reax_param.gp.vdw_type==2 || system->reax_param.gp.vdw_type==3) + { // innner wall + e_core = twbp->ecore * exp(twbp->acore * (1.0-(r_ij/twbp->rcore))); + lr->e_vdW += Tap * e_core; + + de_core = -(twbp->acore/twbp->rcore) * e_core; + lr->CEvd += dTap * e_core + Tap * de_core; + } + + + /* Coulomb calculations */ + dr3gamij_1 = ( r_ij * r_ij * r_ij + twbp->gamma ); + dr3gamij_3 = pow( dr3gamij_1 , 0.33333333333333 ); + + tmp = Tap / dr3gamij_3; + lr->H = EV_to_KCALpMOL * tmp; + lr->e_ele = C_ele * tmp; + // fprintf( stderr, + // "i:%d(%d), j:%d(%d), gamma:%f, Tap:%f, dr3gamij_3:%f, qi: %f, qj: %f\n", + // i, system->my_atoms[i].type, j, system->my_atoms[j].type, + // twbp->gamma, Tap, dr3gamij_3, + // system->my_atoms[i].q, system->my_atoms[j].q ); + + lr->CEclmb = C_ele * ( dTap - Tap * r_ij / dr3gamij_1 ) / dr3gamij_3; + // fprintf( stdout, "%d %d\t%g\t%g %g\t%g %g\t%g %g\n", + // i+1, j+1, r_ij, e_vdW, CEvd * r_ij, + // system->my_atoms[i].q, system->my_atoms[j].q, e_ele, CEclmb * r_ij ); + + // fprintf(stderr,"LR_Lookup: %3d %3d %5.3f-%8.5f %8.5f %8.5f %8.5f %8.5f\n", + // i, j, r_ij, lr->H, lr->e_vdW, lr->CEvd, lr->e_ele, lr->CEclmb ); */ +} diff --git a/src/USER-REAXC/reaxc_nonbonded.h b/src/USER-REAXC/reaxc_nonbonded.h new file mode 100644 index 0000000000..7e418d43e1 --- /dev/null +++ b/src/USER-REAXC/reaxc_nonbonded.h @@ -0,0 +1,37 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __NONBONDED_H_ +#define __NONBONDED_H_ + +#include "reaxc_types.h" + +void vdW_Coulomb_Energy( reax_system*, control_params*, simulation_data*, + storage*, reax_list**, output_controls* ); + +void Tabulated_vdW_Coulomb_Energy( reax_system*, control_params*, + simulation_data*, storage*, + reax_list**, output_controls* ); + +void Compute_Polarization_Energy( reax_system*, simulation_data* ); + +void LR_vdW_Coulomb( reax_system*, storage*, int, int, real, LR_data* ); +#endif diff --git a/src/USER-REAXC/reaxc_reset_tools.cpp b/src/USER-REAXC/reaxc_reset_tools.cpp new file mode 100644 index 0000000000..7b7141f5a5 --- /dev/null +++ b/src/USER-REAXC/reaxc_reset_tools.cpp @@ -0,0 +1,254 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "reset_tools.h" +#include "list.h" +#include "tool_box.h" +#include "vector.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_reset_tools.h" +#include "reaxc_list.h" +#include "reaxc_tool_box.h" +#include "reaxc_vector.h" +#endif + + +void Reset_Atoms( reax_system* system, control_params *control ) +{ + int i; + reax_atom *atom; + + system->numH = 0; + if( control->hbond_cut > 0 ) + for( i = 0; i < system->n; ++i ) { + atom = &(system->my_atoms[i]); + if( system->reax_param.sbp[ atom->type ].p_hbond == 1 ) + atom->Hindex = system->numH++; + else atom->Hindex = -1; + } +} + + +void Reset_Energies( energy_data *en ) +{ + en->e_bond = 0; + en->e_ov = 0; + en->e_un = 0; + en->e_lp = 0; + en->e_ang = 0; + en->e_pen = 0; + en->e_coa = 0; + en->e_hb = 0; + en->e_tor = 0; + en->e_con = 0; + en->e_vdW = 0; + en->e_ele = 0; + en->e_pol = 0; + + en->e_pot = 0; + en->e_kin = 0; + en->e_tot = 0; +} + + +void Reset_Temperatures( simulation_data *data ) +{ + data->therm.T = 0; +} + + +void Reset_Pressures( simulation_data *data ) +{ + data->flex_bar.P_scalar = 0; + rtensor_MakeZero( data->flex_bar.P ); + + data->iso_bar.P = 0; + rvec_MakeZero( data->int_press ); + rvec_MakeZero( data->my_ext_press ); + rvec_MakeZero( data->ext_press ); +} + + +void Reset_Simulation_Data( simulation_data* data, int virial ) +{ + Reset_Energies( &data->my_en ); + Reset_Energies( &data->sys_en ); + Reset_Temperatures( data ); + //if( virial ) + Reset_Pressures( data ); +} + + +void Reset_Timing( reax_timing *rt ) +{ + rt->total = Get_Time(); + rt->comm = 0; + rt->nbrs = 0; + rt->init_forces = 0; + rt->bonded = 0; + rt->nonb = 0; + rt->qEq = 0; + rt->s_matvecs = 0; + rt->t_matvecs = 0; +} + +#ifdef TEST_FORCES +void Reset_Test_Forces( reax_system *system, storage *workspace ) +{ + memset( workspace->f_ele, 0, system->total_cap * sizeof(rvec) ); + memset( workspace->f_vdw, 0, system->total_cap * sizeof(rvec) ); + memset( workspace->f_bo, 0, system->total_cap * sizeof(rvec) ); + memset( workspace->f_be, 0, system->total_cap * sizeof(rvec) ); + memset( workspace->f_lp, 0, system->total_cap * sizeof(rvec) ); + memset( workspace->f_ov, 0, system->total_cap * sizeof(rvec) ); + memset( workspace->f_un, 0, system->total_cap * sizeof(rvec) ); + memset( workspace->f_ang, 0, system->total_cap * sizeof(rvec) ); + memset( workspace->f_coa, 0, system->total_cap * sizeof(rvec) ); + memset( workspace->f_pen, 0, system->total_cap * sizeof(rvec) ); + memset( workspace->f_hb, 0, system->total_cap * sizeof(rvec) ); + memset( workspace->f_tor, 0, system->total_cap * sizeof(rvec) ); + memset( workspace->f_con, 0, system->total_cap * sizeof(rvec) ); +} +#endif + + +void Reset_Workspace( reax_system *system, storage *workspace ) +{ + memset( workspace->total_bond_order, 0, system->total_cap * sizeof( real ) ); + memset( workspace->dDeltap_self, 0, system->total_cap * sizeof( rvec ) ); + memset( workspace->CdDelta, 0, system->total_cap * sizeof( real ) ); + memset( workspace->f, 0, system->total_cap * sizeof( rvec ) ); + +#ifdef TEST_FORCES + memset( workspace->dDelta, 0, sizeof(rvec) * system->total_cap ); + Reset_Test_Forces( system, workspace ); +#endif +} + + +void Reset_Grid( grid *g ) +{ + int i, j, k; + + for( i = 0; i < g->ncells[0]; i++ ) + for( j = 0; j < g->ncells[1]; j++ ) + for( k = 0; k < g->ncells[2]; k++ ) { + g->cells[i][j][k].top = 0; + g->cells[i][j][k].str = 0; + g->cells[i][j][k].end = 0; + } +} + + +void Reset_Out_Buffers( mpi_out_data *out_buf, int n ) +{ + int i; + + for( i = 0; i < n; ++i ) + out_buf[i].cnt = 0; +} + + +void Reset_Neighbor_Lists( reax_system *system, control_params *control, + storage *workspace, reax_list **lists, + MPI_Comm comm ) +{ + int i, total_bonds, Hindex, total_hbonds; + reax_list *bonds, *hbonds; + + /* bonds list */ + if( system->N > 0 ){ + bonds = (*lists) + BONDS; + total_bonds = 0; + + /* reset start-end indexes */ + for( i = 0; i < system->N; ++i ) { + Set_Start_Index( i, total_bonds, bonds ); + Set_End_Index( i, total_bonds, bonds ); + total_bonds += system->my_atoms[i].num_bonds; + } + + /* is reallocation needed? */ + if( total_bonds >= bonds->num_intrs * DANGER_ZONE ) { + workspace->realloc.bonds = 1; + if( total_bonds >= bonds->num_intrs ) { + fprintf(stderr, + "p%d: not enough space for bonds! total=%d allocated=%d\n", + system->my_rank, total_bonds, bonds->num_intrs ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } + } + } + + // fprintf( stderr, "p%d: n:%d num_intrs:%d num_H:%d\n", + // system->my_rank, hbonds->n, hbonds->num_intrs, workspace->num_H ); + // MPI_Barrier( comm ); + /* hbonds list */ + if( control->hbond_cut > 0 && system->numH > 0 ) { + hbonds = (*lists) + HBONDS; + total_hbonds = 0; + + /* reset start-end indexes */ + for( i = 0; i < system->n; ++i ) { + Hindex = system->my_atoms[i].Hindex; + if( Hindex > -1 ) { + Set_Start_Index( Hindex, total_hbonds, hbonds ); + Set_End_Index( Hindex, total_hbonds, hbonds ); + total_hbonds += system->my_atoms[i].num_hbonds; + } + } + + /* is reallocation needed? */ + if( total_hbonds >= hbonds->num_intrs * 0.90/*DANGER_ZONE*/ ) { + workspace->realloc.hbonds = 1; + if( total_hbonds >= hbonds->num_intrs ) { + fprintf(stderr, + "p%d: not enough space for hbonds! total=%d allocated=%d\n", + system->my_rank, total_hbonds, hbonds->num_intrs ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } + } + } + // fprintf( stderr, "p%d: cleared hbonds\n", system->my_rank ); + // MPI_Barrier( comm ); +} + + +void Reset( reax_system *system, control_params *control, simulation_data *data, + storage *workspace, reax_list **lists, MPI_Comm comm ) +{ + Reset_Atoms( system, control ); + + Reset_Simulation_Data( data, control->virial ); + + Reset_Workspace( system, workspace ); + + Reset_Neighbor_Lists( system, control, workspace, lists, comm ); + +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d @ step%d: reset done\n", system->my_rank, data->step ); + MPI_Barrier( comm ); +#endif + +} + diff --git a/src/USER-REAXC/reaxc_reset_tools.h b/src/USER-REAXC/reaxc_reset_tools.h new file mode 100644 index 0000000000..988883dfe7 --- /dev/null +++ b/src/USER-REAXC/reaxc_reset_tools.h @@ -0,0 +1,40 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __RESET_TOOLS_H_ +#define __RESET_TOOLS_H_ + +#include "reaxc_types.h" + +void Reset_Pressures( simulation_data* ); +void Reset_Simulation_Data( simulation_data*, int ); +void Reset_Timing( reax_timing* ); +void Reset_Workspace( reax_system*, storage* ); +void Reset_Grid( grid* ); +void Reset_Out_Buffers( mpi_out_data*, int ); +void Reset_Neighbor_Lists( reax_system*, control_params*, storage*, + reax_list**, MPI_Comm ); +void Reset( reax_system*, control_params*, simulation_data*, storage*, + reax_list**, MPI_Comm ); +#ifdef TEST_FORCES +void Reset_Test_Forces( reax_system*, storage* ); +#endif +#endif diff --git a/src/USER-REAXC/reaxc_system_props.cpp b/src/USER-REAXC/reaxc_system_props.cpp new file mode 100644 index 0000000000..9997394afa --- /dev/null +++ b/src/USER-REAXC/reaxc_system_props.cpp @@ -0,0 +1,411 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "system_props.h" +#include "tool_box.h" +#include "vector.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_system_props.h" +#include "reaxc_tool_box.h" +#include "reaxc_vector.h" +#endif + + +void Temperature_Control( control_params *control, simulation_data *data ) +{ + real tmp; + + if( control->T_mode == 1 ) {// step-wise temperature control + 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; + } + } + else if( control->T_mode == 2 ) { // constant slope control + 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; + rvec p; + real m; + + data->my_en.e_kin = 0.0; + data->sys_en.e_kin = 0.0; + data->therm.T = 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 += 0.5 * rvec_Dot( p, system->my_atoms[i].v ); + } + + MPI_Allreduce( &data->my_en.e_kin, &data->sys_en.e_kin, + 1, MPI_DOUBLE, MPI_SUM, comm ); + + data->therm.T = (2. * 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_System_Energy( reax_system *system, simulation_data *data, + MPI_Comm comm ) +{ + real my_en[15], sys_en[15]; + + 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; + MPI_Reduce( my_en, sys_en, 14, MPI_DOUBLE, MPI_SUM, MASTER_NODE, comm ); + + 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; + real tmp; + + tmp = 0; + for( i = 0; i < system->n; i++ ) + tmp += system->reax_param.sbp[ system->my_atoms[i].type ].mass; + + MPI_Allreduce( &tmp, &data->M, 1, MPI_DOUBLE, MPI_SUM, comm ); + + data->inv_M = 1. / data->M; +} + + + +void Compute_Center_of_Mass( reax_system *system, simulation_data *data, + mpi_datatypes *mpi_data, MPI_Comm comm ) +{ + int i; + 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 ); + } + + MPI_Allreduce( my_xcm, data->xcm, 3, MPI_DOUBLE, MPI_SUM, comm ); + MPI_Allreduce( my_vcm, data->vcm, 3, MPI_DOUBLE, MPI_SUM, comm ); + MPI_Allreduce( my_amcm, data->amcm, 3, MPI_DOUBLE, MPI_SUM, comm ); + + 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; + //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., system->my_atoms[i].x, -1., 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; + } + + MPI_Reduce( tmp_mat, tot_mat, 6, MPI_DOUBLE, MPI_SUM, MASTER_NODE, comm ); + + 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./det, inv ); + else rtensor_MakeZero( inv ); + + /* Compute the angular velocity about the centre of mass */ + rtensor_MatVec( data->avcm, inv, data->amcm ); + } + + MPI_Bcast( data->avcm, 3, MPI_DOUBLE, MASTER_NODE, comm ); + + /* Compute the rotational energy */ + data->erot_cm = 0.5 * E_CONV * rvec_Dot( data->avcm, data->amcm ); + +#if defined(DEBUG) + 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 +} + + + +/* 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; + reax_atom *p_atom; + rvec tmp, tx, int_press; + simulation_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) + 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 + } + } + + /* sum up internal and external pressure */ +#if defined(DEBUG) + 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 + MPI_Allreduce( int_press, data->int_press, + 3, MPI_DOUBLE, MPI_SUM, mpi_data->comm_mesh3D ); + MPI_Allreduce( data->my_ext_press, data->ext_press, + 3, MPI_DOUBLE, MPI_SUM, mpi_data->comm_mesh3D ); +#if defined(DEBUG) + 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.*(E_CONV*data->sys_en.e_kin) / (3.*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; +} +*/ diff --git a/src/USER-REAXC/reaxc_system_props.h b/src/USER-REAXC/reaxc_system_props.h new file mode 100644 index 0000000000..712a6f679f --- /dev/null +++ b/src/USER-REAXC/reaxc_system_props.h @@ -0,0 +1,41 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __SYSTEM_PROP_H_ +#define __SYSTEM_PROP_H_ + +#include "reaxc_types.h" + +void Temperature_Control( control_params*, simulation_data* ); + +void Compute_Kinetic_Energy( reax_system*, simulation_data*, MPI_Comm ); + +void Compute_System_Energy( reax_system*, simulation_data*, MPI_Comm ); + +void Compute_Total_Mass( reax_system*, simulation_data*, MPI_Comm ); + +void Compute_Center_of_Mass( reax_system*, simulation_data*, + mpi_datatypes*, MPI_Comm ); + +void Compute_Pressure( reax_system*, control_params*, + simulation_data*, mpi_datatypes* ); +//void Compute_Pressure( reax_system*, simulation_data* ); +#endif diff --git a/src/USER-REAXC/reaxc_tool_box.cpp b/src/USER-REAXC/reaxc_tool_box.cpp new file mode 100644 index 0000000000..074921248c --- /dev/null +++ b/src/USER-REAXC/reaxc_tool_box.cpp @@ -0,0 +1,467 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "tool_box.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_tool_box.h" +#endif + + +#if defined(PURE_REAX) +/************** taken from comm_tools.c **************/ +int SumScan( int n, int me, int root, MPI_Comm comm ) +{ + int i, my_order, wsize;; + int *nbuf = NULL; + + if( me == root ) { + MPI_Comm_size( comm, &wsize ); + nbuf = (int *) calloc( wsize, sizeof(int) ); + + MPI_Gather( &n, 1, MPI_INT, nbuf, 1, MPI_INT, root, comm ); + + for( i = 0; i < wsize-1; ++i ) { + nbuf[i+1] += nbuf[i]; + } + + MPI_Scatter( nbuf, 1, MPI_INT, &my_order, 1, MPI_INT, root, comm ); + + free( nbuf ); + } + else { + MPI_Gather( &n, 1, MPI_INT, nbuf, 1, MPI_INT, root, comm ); + MPI_Scatter( nbuf, 1, MPI_INT, &my_order, 1, MPI_INT, root, comm ); + } + + return my_order; +} + + +void SumScanB( int n, int me, int wsize, int root, MPI_Comm comm, int *nbuf ) +{ + int i; + + MPI_Gather( &n, 1, MPI_INT, nbuf, 1, MPI_INT, root, comm ); + + if( me == root ) { + for( i = 0; i < wsize-1; ++i ) + nbuf[i+1] += nbuf[i]; + } + + MPI_Bcast( nbuf, wsize, MPI_INT, root, comm ); +} +#endif + + +/************** taken from box.c **************/ +void Transform( rvec x1, simulation_box *box, char flag, rvec x2 ) +{ + int i, j; + real tmp; + + // printf(">x1: (%lf, %lf, %lf)\n",x1[0],x1[1],x1[2]); + + if (flag > 0) { + for (i=0; i < 3; i++) { + tmp = 0.0; + for (j=0; j < 3; j++) + tmp += box->trans[i][j]*x1[j]; + x2[i] = tmp; + } + } + else { + for (i=0; i < 3; i++) { + tmp = 0.0; + for (j=0; j < 3; j++) + tmp += box->trans_inv[i][j]*x1[j]; + x2[i] = tmp; + } + } + // printf(">x2: (%lf, %lf, %lf)\n", x2[0], x2[1], x2[2]); +} + + +void Transform_to_UnitBox( rvec x1, simulation_box *box, char flag, rvec x2 ) +{ + Transform( x1, box, flag, x2 ); + + x2[0] /= box->box_norms[0]; + x2[1] /= box->box_norms[1]; + x2[2] /= box->box_norms[2]; +} + + +/* determine whether point p is inside the box */ +void Fit_to_Periodic_Box( simulation_box *box, rvec *p ) +{ + int i; + + for( i = 0; i < 3; ++i ) { + if( (*p)[i] < box->min[i] ) { + /* handle lower coords */ + while( (*p)[i] < box->min[i] ) + (*p)[i] += box->box_norms[i]; + } + else if( (*p)[i] >= box->max[i] ) { + /* handle higher coords */ + while( (*p)[i] >= box->max[i] ) + (*p)[i] -= box->box_norms[i]; + } + } +} + +#if defined(PURE_REAX) +/* determine the touch point, tp, of a box to + its neighbor denoted by the relative coordinate rl */ +inline void Box_Touch_Point( simulation_box *box, ivec rl, rvec tp ) +{ + int d; + + for( d = 0; d < 3; ++d ) + if( rl[d] == -1 ) + tp[d] = box->min[d]; + else if( rl[d] == 0 ) + tp[d] = NEG_INF - 1.; + else + tp[d] = box->max[d]; +} + + +/* determine whether point p is inside the box */ +/* assumes orthogonal box */ +inline int is_Inside_Box( simulation_box *box, rvec p ) +{ + if( p[0] < box->min[0] || p[0] >= box->max[0] || + p[1] < box->min[1] || p[1] >= box->max[1] || + p[2] < box->min[2] || p[2] >= box->max[2] ) + return 0; + + return 1; +} + + +inline int iown_midpoint( simulation_box *box, rvec p1, rvec p2 ) +{ + rvec midp; + + midp[0] = (p1[0] + p2[0]) / 2; + midp[1] = (p1[1] + p2[1]) / 2; + midp[2] = (p1[2] + p2[2]) / 2; + + if( midp[0] < box->min[0] || midp[0] >= box->max[0] || + midp[1] < box->min[1] || midp[1] >= box->max[1] || + midp[2] < box->min[2] || midp[2] >= box->max[2] ) + return 0; + + return 1; +} + + + +/**************** from grid.c ****************/ +/* finds the closest point of grid cell cj to ci. + no need to consider periodic boundary conditions as in the serial case + because the box of a process is not periodic in itself */ +inline void GridCell_Closest_Point( grid_cell *gci, grid_cell *gcj, + ivec ci, ivec cj, rvec cp ) +{ + int d; + + for( d = 0; d < 3; d++ ) + if( cj[d] > ci[d] ) + cp[d] = gcj->min[d]; + else if ( cj[d] == ci[d] ) + cp[d] = NEG_INF - 1.; + else + cp[d] = gcj->max[d]; +} + + + +inline void GridCell_to_Box_Points( grid_cell *gc, ivec rl, rvec cp, rvec fp ) +{ + int d; + + for( d = 0; d < 3; ++d ) + if( rl[d] == -1 ) { + cp[d] = gc->min[d]; + fp[d] = gc->max[d]; + } + else if( rl[d] == 0 ) { + cp[d] = fp[d] = NEG_INF - 1.; + } + else{ + cp[d] = gc->max[d]; + fp[d] = gc->min[d]; + } +} + + +inline real DistSqr_between_Special_Points( rvec sp1, rvec sp2 ) +{ + int i; + real d_sqr = 0; + + for( i = 0; i < 3; ++i ) + if( sp1[i] > NEG_INF && sp2[i] > NEG_INF ) + d_sqr += SQR( sp1[i] - sp2[i] ); + + return d_sqr; +} + + +inline real DistSqr_to_Special_Point( rvec cp, rvec x ) +{ + int i; + real d_sqr = 0; + + for( i = 0; i < 3; ++i ) + if( cp[i] > NEG_INF ) + d_sqr += SQR( cp[i] - x[i] ); + + return d_sqr; +} + + +inline int Relative_Coord_Encoding( ivec c ) +{ + return 9 * (c[0] + 1) + 3 * (c[1] + 1) + (c[2] + 1); +} +#endif + + +/************** from geo_tools.c *****************/ +void Make_Point( real x, real y, real z, rvec* p ) +{ + (*p)[0] = x; + (*p)[1] = y; + (*p)[2] = z; +} + + + +int is_Valid_Serial( storage *workspace, int serial ) +{ + // if( workspace->map_serials[ serial ] < 0 ) + // { + // fprintf( stderr, "CONECT line includes invalid pdb serial number %d.\n", + // serial ); + // fprintf( stderr, "Please correct the input file.Terminating...\n" ); + // MPI_Abort( MPI_COMM_WORLD, INVALID_INPUT ); + // } + + return SUCCESS; +} + + + +int Check_Input_Range( int val, int lo, int hi, char *message, MPI_Comm comm ) +{ + if( val < lo || val > hi ) { + fprintf( stderr, "%s\nInput %d - Out of range %d-%d. Terminating...\n", + message, val, lo, hi ); + MPI_Abort( comm, INVALID_INPUT ); + } + + return 1; +} + + +void Trim_Spaces( char *element ) +{ + int i, j; + + for( i = 0; element[i] == ' '; ++i ); // skip initial space chars + + for( j = i; j < (int)(strlen(element)) && element[j] != ' '; ++j ) + element[j-i] = toupper( element[j] ); // make uppercase, offset to 0 + element[j-i] = 0; // finalize the string +} + + +/************ from system_props.c *************/ +struct timeval tim; +real t_end; + +real Get_Time( ) +{ + gettimeofday(&tim, NULL ); + return( tim.tv_sec + (tim.tv_usec / 1000000.0) ); +} + + +real Get_Timing_Info( real t_start ) +{ + gettimeofday(&tim, NULL ); + t_end = tim.tv_sec + (tim.tv_usec / 1000000.0); + return (t_end - t_start); +} + + +void Update_Timing_Info( real *t_start, real *timing ) +{ + gettimeofday(&tim, NULL ); + t_end = tim.tv_sec + (tim.tv_usec / 1000000.0); + *timing += (t_end - *t_start); + *t_start = t_end; +} + + +/*********** from io_tools.c **************/ +int Get_Atom_Type( reax_interaction *reax_param, char *s, MPI_Comm comm ) +{ + int i; + + for( i = 0; i < reax_param->num_atom_types; ++i ) + if( !strcmp( reax_param->sbp[i].name, s ) ) + return i; + + fprintf( stderr, "Unknown atom type %s. Terminating...\n", s ); + MPI_Abort( comm, UNKNOWN_ATOM_TYPE ); + + return -1; +} + + + +char *Get_Element( reax_system *system, int i ) +{ + return &( system->reax_param.sbp[system->my_atoms[i].type].name[0] ); +} + + + +char *Get_Atom_Name( reax_system *system, int i ) +{ + return &(system->my_atoms[i].name[0]); +} + + + +int Allocate_Tokenizer_Space( char **line, char **backup, char ***tokens ) +{ + int i; + + if( (*line = (char*) malloc( sizeof(char) * MAX_LINE )) == NULL ) + return FAILURE; + + if( (*backup = (char*) malloc( sizeof(char) * MAX_LINE )) == NULL ) + return FAILURE; + + if( (*tokens = (char**) malloc( sizeof(char*) * MAX_TOKENS )) == NULL ) + return FAILURE; + + for( i = 0; i < MAX_TOKENS; i++ ) + if( ((*tokens)[i] = (char*) malloc(sizeof(char) * MAX_TOKEN_LEN)) == NULL ) + return FAILURE; + + return SUCCESS; +} + + + +int Tokenize( char* s, char*** tok ) +{ + char test[MAX_LINE]; + char *sep = "\t \n!="; + char *word; + int count=0; + + strncpy( test, s, MAX_LINE ); + + for( word = strtok(test, sep); word; word = strtok(NULL, sep) ) { + strncpy( (*tok)[count], word, MAX_LINE ); + count++; + } + + return count; +} + + +/***************** taken from lammps ************************/ +/* safe malloc */ +void *smalloc( long n, char *name, MPI_Comm comm ) +{ + void *ptr; + + if( n <= 0 ) { + fprintf( stderr, "WARNING: trying to allocate %ld bytes for array %s. ", + n, name ); + fprintf( stderr, "returning NULL.\n" ); + return NULL; + } + + ptr = malloc( n ); + if( ptr == NULL ) { + fprintf( stderr, "ERROR: failed to allocate %ld bytes for array %s", + n, name ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } + + return ptr; +} + + +/* safe calloc */ +void *scalloc( int n, int size, char *name, MPI_Comm comm ) +{ + void *ptr; + + if( n <= 0 ) { + fprintf( stderr, "WARNING: trying to allocate %d elements for array %s. ", + n, name ); + fprintf( stderr, "returning NULL.\n" ); + return NULL; + } + + if( size <= 0 ) { + fprintf( stderr, "WARNING: elements size for array %s is %d. ", + name, size ); + fprintf( stderr, "returning NULL.\n" ); + return NULL; + } + + ptr = calloc( n, size ); + if( ptr == NULL ) { + fprintf( stderr, "ERROR: failed to allocate %d bytes for array %s", + n*size, name ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } + + return ptr; +} + + +/* safe free */ +void sfree( void *ptr, char *name ) +{ + if( ptr == NULL ) { + fprintf( stderr, "WARNING: trying to free the already NULL pointer %s!\n", + name ); + return; + } + + free( ptr ); + ptr = NULL; +} + diff --git a/src/USER-REAXC/reaxc_tool_box.h b/src/USER-REAXC/reaxc_tool_box.h new file mode 100644 index 0000000000..9a0b60247b --- /dev/null +++ b/src/USER-REAXC/reaxc_tool_box.h @@ -0,0 +1,69 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __TOOL_BOX_H_ +#define __TOOL_BOX_H_ + +#include "reaxc_types.h" +#include "reaxc_defs.h" + +/* from comm_tools.h */ +int SumScan( int, int, int, MPI_Comm ); +void SumScanB( int, int, int, int, MPI_Comm, int* ); + +/* from box.h */ +void Transform_to_UnitBox( rvec, simulation_box*, char, rvec ); +void Fit_to_Periodic_Box( simulation_box*, rvec* ); +void Box_Touch_Point( simulation_box*, ivec, rvec ); +int is_Inside_Box( simulation_box*, rvec ); +int iown_midpoint( simulation_box*, rvec, rvec ); + +/* from grid.h */ +void GridCell_Closest_Point( grid_cell*, grid_cell*, ivec, ivec, rvec ); +void GridCell_to_Box_Points( grid_cell*, ivec, rvec, rvec ); +real DistSqr_between_Special_Points( rvec, rvec ); +real DistSqr_to_Special_Point( rvec, rvec ); +int Relative_Coord_Encoding( ivec ); + +/* from geo_tools.h */ +void Make_Point( real, real, real, rvec* ); +int is_Valid_Serial( storage*, int ); +int Check_Input_Range( int, int, int, char*, MPI_Comm ); +void Trim_Spaces( char* ); + +/* from system_props.h */ +real Get_Time( ); +real Get_Timing_Info( real ); +void Update_Timing_Info( real*, real* ); + +/* from io_tools.h */ +int Get_Atom_Type( reax_interaction*, char*, MPI_Comm ); +char *Get_Element( reax_system*, int ); +char *Get_Atom_Name( reax_system*, int ); +int Allocate_Tokenizer_Space( char**, char**, char*** ); +int Tokenize( char*, char*** ); + +/* from lammps */ +void *smalloc( long, char*, MPI_Comm ); +void *scalloc( int, int, char*, MPI_Comm ); +void sfree( void*, char* ); + +#endif diff --git a/src/USER-REAXC/reaxc_torsion_angles.cpp b/src/USER-REAXC/reaxc_torsion_angles.cpp new file mode 100644 index 0000000000..f1afe3c3a6 --- /dev/null +++ b/src/USER-REAXC/reaxc_torsion_angles.cpp @@ -0,0 +1,590 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "torsion_angles.h" +#include "bond_orders.h" +#include "list.h" +#include "tool_box.h" +#include "vector.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_torsion_angles.h" +#include "reaxc_bond_orders.h" +#include "reaxc_list.h" +#include "reaxc_tool_box.h" +#include "reaxc_vector.h" +#endif + +#define MIN_SINE 1e-10 + +real Calculate_Omega( rvec dvec_ij, real r_ij, + rvec dvec_jk, real r_jk, + rvec dvec_kl, real r_kl, + rvec dvec_li, real r_li, + three_body_interaction_data *p_ijk, + three_body_interaction_data *p_jkl, + rvec dcos_omega_di, rvec dcos_omega_dj, + rvec dcos_omega_dk, rvec dcos_omega_dl, + output_controls *out_control ) +{ + real unnorm_cos_omega, unnorm_sin_omega, omega; + real sin_ijk, cos_ijk, sin_jkl, cos_jkl; + real htra, htrb, htrc, hthd, hthe, hnra, hnrc, hnhd, hnhe; + real arg, poem, tel; + rvec cross_jk_kl; + + sin_ijk = sin( p_ijk->theta ); + cos_ijk = cos( p_ijk->theta ); + sin_jkl = sin( p_jkl->theta ); + cos_jkl = cos( p_jkl->theta ); + + /* omega */ + unnorm_cos_omega = -rvec_Dot(dvec_ij, dvec_jk) * rvec_Dot(dvec_jk, dvec_kl) + + SQR( r_jk ) * rvec_Dot( dvec_ij, dvec_kl ); + + rvec_Cross( cross_jk_kl, dvec_jk, dvec_kl ); + unnorm_sin_omega = -r_jk * rvec_Dot( dvec_ij, cross_jk_kl ); + + omega = atan2( unnorm_sin_omega, unnorm_cos_omega ); + + + /* derivatives */ + /* coef for adjusments to cos_theta's */ + /* rla = r_ij, rlb = r_jk, rlc = r_kl, r4 = r_li; + coshd = cos_ijk, coshe = cos_jkl; + sinhd = sin_ijk, sinhe = sin_jkl; */ + htra = r_ij + cos_ijk * ( r_kl * cos_jkl - r_jk ); + htrb = r_jk - r_ij * cos_ijk - r_kl * cos_jkl; + htrc = r_kl + cos_jkl * ( r_ij * cos_ijk - r_jk ); + hthd = r_ij * sin_ijk * ( r_jk - r_kl * cos_jkl ); + hthe = r_kl * sin_jkl * ( r_jk - r_ij * cos_ijk ); + hnra = r_kl * sin_ijk * sin_jkl; + hnrc = r_ij * sin_ijk * sin_jkl; + hnhd = r_ij * r_kl * cos_ijk * sin_jkl; + hnhe = r_ij * r_kl * sin_ijk * cos_jkl; + + + poem = 2.0 * r_ij * r_kl * sin_ijk * sin_jkl; + if( poem < 1e-20 ) poem = 1e-20; + + tel = SQR( r_ij ) + SQR( r_jk ) + SQR( r_kl ) - SQR( r_li ) - + 2.0 * ( r_ij * r_jk * cos_ijk - r_ij * r_kl * cos_ijk * cos_jkl + + r_jk * r_kl * cos_jkl ); + + arg = tel / poem; + if( arg > 1.0 ) arg = 1.0; + if( arg < -1.0 ) arg = -1.0; + + + /* fprintf( out_control->etor, + "%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f\n", + htra, htrb, htrc, hthd, hthe, hnra, hnrc, hnhd, hnhe ); + fprintf( out_control->etor, "%12.6f%12.6f%12.6f\n", + dvec_ij[0]/r_ij, dvec_ij[1]/r_ij, dvec_ij[2]/r_ij ); + fprintf( out_control->etor, "%12.6f%12.6f%12.6f\n", + -dvec_jk[0]/r_jk, -dvec_jk[1]/r_jk, -dvec_jk[2]/r_jk ); + fprintf( out_control->etor, "%12.6f%12.6f%12.6f\n", + -dvec_kl[0]/r_kl, -dvec_kl[1]/r_kl, -dvec_kl[2]/r_kl ); + fprintf( out_control->etor, "%12.6f%12.6f%12.6f%12.6f\n", + r_li, dvec_li[0], dvec_li[1], dvec_li[2] ); + fprintf( out_control->etor, "%12.6f%12.6f%12.6f\n", + poem, tel, arg ); */ + /* fprintf( out_control->etor, "%12.6f%12.6f%12.6f\n", + -p_ijk->dcos_dk[0]/sin_ijk, -p_ijk->dcos_dk[1]/sin_ijk, + -p_ijk->dcos_dk[2]/sin_ijk ); + fprintf( out_control->etor, "%12.6f%12.6f%12.6f\n", + -p_jkl->dcos_dk[0]/sin_jkl, -p_jkl->dcos_dk[1]/sin_jkl, + -p_jkl->dcos_dk[2]/sin_jkl );*/ + + if( sin_ijk >= 0 && sin_ijk <= MIN_SINE ) sin_ijk = MIN_SINE; + else if( sin_ijk <= 0 && sin_ijk >= -MIN_SINE ) sin_ijk = -MIN_SINE; + if( sin_jkl >= 0 && sin_jkl <= MIN_SINE ) sin_jkl = MIN_SINE; + else if( sin_jkl <= 0 && sin_jkl >= -MIN_SINE ) sin_jkl = -MIN_SINE; + + // dcos_omega_di + rvec_ScaledSum( dcos_omega_di, (htra-arg*hnra)/r_ij, dvec_ij, -1., dvec_li ); + rvec_ScaledAdd( dcos_omega_di,-(hthd-arg*hnhd)/sin_ijk, p_ijk->dcos_dk ); + rvec_Scale( dcos_omega_di, 2.0 / poem, dcos_omega_di ); + + // dcos_omega_dj + rvec_ScaledSum( dcos_omega_dj,-(htra-arg*hnra)/r_ij, dvec_ij, + -htrb / r_jk, dvec_jk ); + rvec_ScaledAdd( dcos_omega_dj,-(hthd-arg*hnhd)/sin_ijk, p_ijk->dcos_dj ); + rvec_ScaledAdd( dcos_omega_dj,-(hthe-arg*hnhe)/sin_jkl, p_jkl->dcos_di ); + rvec_Scale( dcos_omega_dj, 2.0 / poem, dcos_omega_dj ); + + // dcos_omega_dk + rvec_ScaledSum( dcos_omega_dk,-(htrc-arg*hnrc)/r_kl, dvec_kl, + htrb / r_jk, dvec_jk ); + rvec_ScaledAdd( dcos_omega_dk,-(hthd-arg*hnhd)/sin_ijk, p_ijk->dcos_di ); + rvec_ScaledAdd( dcos_omega_dk,-(hthe-arg*hnhe)/sin_jkl, p_jkl->dcos_dj ); + rvec_Scale( dcos_omega_dk, 2.0 / poem, dcos_omega_dk ); + + // dcos_omega_dl + rvec_ScaledSum( dcos_omega_dl, (htrc-arg*hnrc)/r_kl, dvec_kl, 1., dvec_li ); + rvec_ScaledAdd( dcos_omega_dl,-(hthe-arg*hnhe)/sin_jkl, p_jkl->dcos_dk ); + rvec_Scale( dcos_omega_dl, 2.0 / poem, dcos_omega_dl ); + + return omega; +} + + + +void Torsion_Angles( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control ) +{ + int i, j, k, l, pi, pj, pk, pl, pij, plk, natoms; + int type_i, type_j, type_k, type_l; + int start_j, end_j, start_k, end_k; + int start_pj, end_pj, start_pk, end_pk; + int num_frb_intrs = 0; + + real Delta_j, Delta_k; + real r_ij, r_jk, r_kl, r_li; + real BOA_ij, BOA_jk, BOA_kl; + + real exp_tor2_ij, exp_tor2_jk, exp_tor2_kl; + real exp_tor1, exp_tor3_DjDk, exp_tor4_DjDk, exp_tor34_inv; + real exp_cot2_jk, exp_cot2_ij, exp_cot2_kl; + real fn10, f11_DjDk, dfn11, fn12; + real theta_ijk, theta_jkl; + real sin_ijk, sin_jkl; + real cos_ijk, cos_jkl; + real tan_ijk_i, tan_jkl_i; + real omega, cos_omega, cos2omega, cos3omega; + rvec dcos_omega_di, dcos_omega_dj, dcos_omega_dk, dcos_omega_dl; + real CV, cmn, CEtors1, CEtors2, CEtors3, CEtors4; + real CEtors5, CEtors6, CEtors7, CEtors8, CEtors9; + real Cconj, CEconj1, CEconj2, CEconj3; + real CEconj4, CEconj5, CEconj6; + real e_tor, e_con; + rvec dvec_li; + rvec force, ext_press; + ivec rel_box_jl; + // rtensor total_rtensor, temp_rtensor; + four_body_header *fbh; + four_body_parameters *fbp; + bond_data *pbond_ij, *pbond_jk, *pbond_kl; + bond_order_data *bo_ij, *bo_jk, *bo_kl; + three_body_interaction_data *p_ijk, *p_jkl; + real p_tor2 = system->reax_param.gp.l[23]; + real p_tor3 = system->reax_param.gp.l[24]; + real p_tor4 = system->reax_param.gp.l[25]; + real p_cot2 = system->reax_param.gp.l[27]; + reax_list *bonds = (*lists) + BONDS; + reax_list *thb_intrs = (*lists) + THREE_BODIES; + // char fname[100]; + // FILE *ftor; + + // sprintf( fname, "tor%d.out", system->my_rank ); + // ftor = fopen( fname, "w" ); + + natoms = system->n; + + for( j = 0; j < natoms; ++j ) { + type_j = system->my_atoms[j].type; + Delta_j = workspace->Delta_boc[j]; + start_j = Start_Index(j, bonds); + end_j = End_Index(j, bonds); + + for( pk = start_j; pk < end_j; ++pk ) { + pbond_jk = &( bonds->select.bond_list[pk] ); + k = pbond_jk->nbr; + bo_jk = &( pbond_jk->bo_data ); + BOA_jk = bo_jk->BO - control->thb_cut; + + /* see if there are any 3-body interactions involving j&k + where j is the central atom. Otherwise there is no point in + trying to form a 4-body interaction out of this neighborhood */ + if( system->my_atoms[j].orig_id < system->my_atoms[k].orig_id && + bo_jk->BO > control->thb_cut/*0*/ && Num_Entries(pk, thb_intrs) ) { + start_k = Start_Index(k, bonds); + end_k = End_Index(k, bonds); + pj = pbond_jk->sym_index; // pj points to j on k's list + + /* do the same check as above: + are there any 3-body interactions involving k&j + where k is the central atom */ + if( Num_Entries(pj, thb_intrs) ) { + type_k = system->my_atoms[k].type; + Delta_k = workspace->Delta_boc[k]; + r_jk = pbond_jk->d; + + start_pk = Start_Index(pk, thb_intrs ); + end_pk = End_Index(pk, thb_intrs ); + start_pj = Start_Index(pj, thb_intrs ); + end_pj = End_Index(pj, thb_intrs ); + + exp_tor2_jk = exp( -p_tor2 * BOA_jk ); + exp_cot2_jk = exp( -p_cot2 * SQR(BOA_jk - 1.5) ); + exp_tor3_DjDk = exp( -p_tor3 * (Delta_j + Delta_k) ); + exp_tor4_DjDk = exp( p_tor4 * (Delta_j + Delta_k) ); + exp_tor34_inv = 1.0 / (1.0 + exp_tor3_DjDk + exp_tor4_DjDk); + f11_DjDk = (2.0 + exp_tor3_DjDk) * exp_tor34_inv; + + + /* pick i up from j-k interaction where j is the central atom */ + for( pi = start_pk; pi < end_pk; ++pi ) { + p_ijk = &( thb_intrs->select.three_body_list[pi] ); + pij = p_ijk->pthb; // pij is pointer to i on j's bond_list + pbond_ij = &( bonds->select.bond_list[pij] ); + bo_ij = &( pbond_ij->bo_data ); + + + if( bo_ij->BO > control->thb_cut/*0*/ ) { + i = p_ijk->thb; + type_i = system->my_atoms[i].type; + r_ij = pbond_ij->d; + BOA_ij = bo_ij->BO - control->thb_cut; + + theta_ijk = p_ijk->theta; + sin_ijk = sin( theta_ijk ); + cos_ijk = cos( theta_ijk ); + //tan_ijk_i = 1. / tan( theta_ijk ); + if( sin_ijk >= 0 && sin_ijk <= MIN_SINE ) + tan_ijk_i = cos_ijk / MIN_SINE; + else if( sin_ijk <= 0 && sin_ijk >= -MIN_SINE ) + tan_ijk_i = cos_ijk / -MIN_SINE; + else tan_ijk_i = cos_ijk / sin_ijk; + + exp_tor2_ij = exp( -p_tor2 * BOA_ij ); + exp_cot2_ij = exp( -p_cot2 * SQR(BOA_ij -1.5) ); + + + /* pick l up from j-k interaction where k is the central atom */ + for( pl = start_pj; pl < end_pj; ++pl ) { + p_jkl = &( thb_intrs->select.three_body_list[pl] ); + l = p_jkl->thb; + plk = p_jkl->pthb; //pointer to l on k's bond_list! + pbond_kl = &( bonds->select.bond_list[plk] ); + bo_kl = &( pbond_kl->bo_data ); + type_l = system->my_atoms[l].type; + fbh = &(system->reax_param.fbp[type_i][type_j] + [type_k][type_l]); + fbp = &(system->reax_param.fbp[type_i][type_j] + [type_k][type_l].prm[0]); + + + if( i != l && fbh->cnt && + bo_kl->BO > control->thb_cut/*0*/ && + bo_ij->BO * bo_jk->BO * bo_kl->BO > control->thb_cut/*0*/ ){ + ++num_frb_intrs; + r_kl = pbond_kl->d; + BOA_kl = bo_kl->BO - control->thb_cut; + + theta_jkl = p_jkl->theta; + sin_jkl = sin( theta_jkl ); + cos_jkl = cos( theta_jkl ); + //tan_jkl_i = 1. / tan( theta_jkl ); + if( sin_jkl >= 0 && sin_jkl <= MIN_SINE ) + tan_jkl_i = cos_jkl / MIN_SINE; + else if( sin_jkl <= 0 && sin_jkl >= -MIN_SINE ) + tan_jkl_i = cos_jkl / -MIN_SINE; + else tan_jkl_i = cos_jkl /sin_jkl; + + rvec_ScaledSum( dvec_li, 1., system->my_atoms[i].x, + -1., system->my_atoms[l].x ); + r_li = rvec_Norm( dvec_li ); + + + /* omega and its derivative */ + omega = Calculate_Omega( pbond_ij->dvec, r_ij, + pbond_jk->dvec, r_jk, + pbond_kl->dvec, r_kl, + dvec_li, r_li, + p_ijk, p_jkl, + dcos_omega_di, dcos_omega_dj, + dcos_omega_dk, dcos_omega_dl, + out_control ); + + cos_omega = cos( omega ); + cos2omega = cos( 2. * omega ); + cos3omega = cos( 3. * omega ); + /* end omega calculations */ + + /* torsion energy */ + exp_tor1 = exp( fbp->p_tor1 * + SQR(2.0 - bo_jk->BO_pi - f11_DjDk) ); + exp_tor2_kl = exp( -p_tor2 * BOA_kl ); + exp_cot2_kl = exp( -p_cot2 * SQR(BOA_kl - 1.5) ); + fn10 = (1.0 - exp_tor2_ij) * (1.0 - exp_tor2_jk) * + (1.0 - exp_tor2_kl); + + CV = 0.5 * ( fbp->V1 * (1.0 + cos_omega) + + fbp->V2 * exp_tor1 * (1.0 - cos2omega) + + fbp->V3 * (1.0 + cos3omega) ); + + data->my_en.e_tor += e_tor = fn10 * sin_ijk * sin_jkl * CV; + + dfn11 = (-p_tor3 * exp_tor3_DjDk + + (p_tor3 * exp_tor3_DjDk - p_tor4 * exp_tor4_DjDk) * + (2.0 + exp_tor3_DjDk) * exp_tor34_inv) * + exp_tor34_inv; + + CEtors1 = sin_ijk * sin_jkl * CV; + + CEtors2 = -fn10 * 2.0 * fbp->p_tor1 * fbp->V2 * exp_tor1 * + (2.0 - bo_jk->BO_pi - f11_DjDk) * (1.0 - SQR(cos_omega)) * + sin_ijk * sin_jkl; + CEtors3 = CEtors2 * dfn11; + + CEtors4 = CEtors1 * p_tor2 * exp_tor2_ij * + (1.0 - exp_tor2_jk) * (1.0 - exp_tor2_kl); + CEtors5 = CEtors1 * p_tor2 * + (1.0 - exp_tor2_ij) * exp_tor2_jk * (1.0 - exp_tor2_kl); + CEtors6 = CEtors1 * p_tor2 * + (1.0 - exp_tor2_ij) * (1.0 - exp_tor2_jk) * exp_tor2_kl; + + cmn = -fn10 * CV; + CEtors7 = cmn * sin_jkl * tan_ijk_i; + CEtors8 = cmn * sin_ijk * tan_jkl_i; + + CEtors9 = fn10 * sin_ijk * sin_jkl * + (0.5 * fbp->V1 - 2.0 * fbp->V2 * exp_tor1 * cos_omega + + 1.5 * fbp->V3 * (cos2omega + 2.0 * SQR(cos_omega))); + /* end of torsion energy */ + + + /* 4-body conjugation energy */ + fn12 = exp_cot2_ij * exp_cot2_jk * exp_cot2_kl; + data->my_en.e_con += e_con = + fbp->p_cot1 * fn12 * + (1.0 + (SQR(cos_omega) - 1.0) * sin_ijk * sin_jkl); + + Cconj = -2.0 * fn12 * fbp->p_cot1 * p_cot2 * + (1.0 + (SQR(cos_omega) - 1.0) * sin_ijk * sin_jkl); + + CEconj1 = Cconj * (BOA_ij - 1.5e0); + CEconj2 = Cconj * (BOA_jk - 1.5e0); + CEconj3 = Cconj * (BOA_kl - 1.5e0); + + CEconj4 = -fbp->p_cot1 * fn12 * + (SQR(cos_omega) - 1.0) * sin_jkl * tan_ijk_i; + CEconj5 = -fbp->p_cot1 * fn12 * + (SQR(cos_omega) - 1.0) * sin_ijk * tan_jkl_i; + CEconj6 = 2.0 * fbp->p_cot1 * fn12 * + cos_omega * sin_ijk * sin_jkl; + /* end 4-body conjugation energy */ + + /* forces */ + bo_jk->Cdbopi += CEtors2; + workspace->CdDelta[j] += CEtors3; + workspace->CdDelta[k] += CEtors3; + bo_ij->Cdbo += (CEtors4 + CEconj1); + bo_jk->Cdbo += (CEtors5 + CEconj2); + bo_kl->Cdbo += (CEtors6 + CEconj3); + + if( control->virial == 0 ) { + /* dcos_theta_ijk */ + rvec_ScaledAdd( workspace->f[i], + CEtors7 + CEconj4, p_ijk->dcos_dk ); + rvec_ScaledAdd( workspace->f[j], + CEtors7 + CEconj4, p_ijk->dcos_dj ); + rvec_ScaledAdd( workspace->f[k], + CEtors7 + CEconj4, p_ijk->dcos_di ); + + /* dcos_theta_jkl */ + rvec_ScaledAdd( workspace->f[j], + CEtors8 + CEconj5, p_jkl->dcos_di ); + rvec_ScaledAdd( workspace->f[k], + CEtors8 + CEconj5, p_jkl->dcos_dj ); + rvec_ScaledAdd( workspace->f[l], + CEtors8 + CEconj5, p_jkl->dcos_dk ); + + /* dcos_omega */ + rvec_ScaledAdd( workspace->f[i], + CEtors9 + CEconj6, dcos_omega_di ); + rvec_ScaledAdd( workspace->f[j], + CEtors9 + CEconj6, dcos_omega_dj ); + rvec_ScaledAdd( workspace->f[k], + CEtors9 + CEconj6, dcos_omega_dk ); + rvec_ScaledAdd( workspace->f[l], + CEtors9 + CEconj6, dcos_omega_dl ); + } + else { + ivec_Sum(rel_box_jl, pbond_jk->rel_box, pbond_kl->rel_box); + + /* dcos_theta_ijk */ + rvec_Scale( force, CEtors7 + CEconj4, p_ijk->dcos_dk ); + rvec_Add( workspace->f[i], force ); + rvec_iMultiply( ext_press, pbond_ij->rel_box, force ); + rvec_Add( data->my_ext_press, ext_press ); + + rvec_ScaledAdd( workspace->f[j], + CEtors7 + CEconj4, p_ijk->dcos_dj ); + + rvec_Scale( force, CEtors7 + CEconj4, p_ijk->dcos_di ); + rvec_Add( workspace->f[k], force ); + rvec_iMultiply( ext_press, pbond_jk->rel_box, force ); + rvec_Add( data->my_ext_press, ext_press ); + + + /* dcos_theta_jkl */ + rvec_ScaledAdd( workspace->f[j], + CEtors8 + CEconj5, p_jkl->dcos_di ); + + rvec_Scale( force, CEtors8 + CEconj5, p_jkl->dcos_dj ); + rvec_Add( workspace->f[k], force ); + rvec_iMultiply( ext_press, pbond_jk->rel_box, force ); + rvec_Add( data->my_ext_press, ext_press ); + + rvec_Scale( force, CEtors8 + CEconj5, p_jkl->dcos_dk ); + rvec_Add( workspace->f[l], force ); + rvec_iMultiply( ext_press, rel_box_jl, force ); + rvec_Add( data->my_ext_press, ext_press ); + + + /* dcos_omega */ + rvec_Scale( force, CEtors9 + CEconj6, dcos_omega_di ); + rvec_Add( workspace->f[i], force ); + rvec_iMultiply( ext_press, pbond_ij->rel_box, force ); + rvec_Add( data->my_ext_press, ext_press ); + + rvec_ScaledAdd( workspace->f[j], + CEtors9 + CEconj6, dcos_omega_dj ); + + rvec_Scale( force, CEtors9 + CEconj6, dcos_omega_dk ); + rvec_Add( workspace->f[k], force ); + rvec_iMultiply( ext_press, pbond_jk->rel_box, force ); + rvec_Add( data->my_ext_press, ext_press ); + + rvec_Scale( force, CEtors9 + CEconj6, dcos_omega_dl ); + rvec_Add( workspace->f[l], force ); + rvec_iMultiply( ext_press, rel_box_jl, force ); + rvec_Add( data->my_ext_press, ext_press ); + } + +#ifdef TEST_ENERGY + /* fprintf( out_control->etor, + "%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f\n", + r_ij, r_jk, r_kl, cos_ijk, cos_jkl, sin_ijk, sin_jkl ); + fprintf( out_control->etor, "%12.8f\n", dfn11 ); */ + /* fprintf( out_control->etor, + "%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f\n", + CEtors2, CEtors3, CEtors4, CEtors5, CEtors6, + CEtors7, CEtors8, CEtors9 ); */ + /* fprintf( out_control->etor, + "%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f\n", + htra, htrb, htrc, hthd, hthe, hnra, hnrc, hnhd, hnhe ); */ + /* fprintf( out_control->etor, + "%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f\n", + CEconj1, CEconj2, CEconj3, CEconj4, CEconj5, CEconj6 ); */ + + /* fprintf( out_control->etor, "%12.6f%12.6f%12.6f%12.6f\n", + fbp->V1, fbp->V2, fbp->V3, fbp->p_tor1 );*/ + + fprintf(out_control->etor, + //"%6d%6d%6d%6d%24.15e%24.15e%24.15e%24.15e\n", + "%6d%6d%6d%6d%12.4f%12.4f%12.4f%12.4f\n", + system->my_atoms[i].orig_id,system->my_atoms[j].orig_id, + system->my_atoms[k].orig_id,system->my_atoms[l].orig_id, + RAD2DEG(omega), BOA_jk, e_tor, data->my_en.e_tor ); + + fprintf(out_control->econ, + //"%6d%6d%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e\n", + "%6d%6d%6d%6d%12.4f%12.4f%12.4f%12.4f%12.4f%12.4f\n", + system->my_atoms[i].orig_id,system->my_atoms[j].orig_id, + system->my_atoms[k].orig_id,system->my_atoms[l].orig_id, + RAD2DEG(omega), BOA_ij, BOA_jk, BOA_kl, + e_con, data->my_en.e_con ); +#endif + +#ifdef TEST_FORCES + /* Torsion Forces */ + Add_dBOpinpi2( system, lists, j, pk, CEtors2, 0.0, + workspace->f_tor, workspace->f_tor ); + Add_dDelta( system, lists, j, CEtors3, workspace->f_tor ); + Add_dDelta( system, lists, k, CEtors3, workspace->f_tor ); + Add_dBO( system, lists, j, pij, CEtors4, workspace->f_tor ); + Add_dBO( system, lists, j, pk, CEtors5, workspace->f_tor ); + Add_dBO( system, lists, k, plk, CEtors6, workspace->f_tor ); + + rvec_ScaledAdd( workspace->f_tor[i], + CEtors7, p_ijk->dcos_dk ); + rvec_ScaledAdd( workspace->f_tor[j], + CEtors7, p_ijk->dcos_dj ); + rvec_ScaledAdd( workspace->f_tor[k], + CEtors7, p_ijk->dcos_di ); + + rvec_ScaledAdd( workspace->f_tor[j], + CEtors8, p_jkl->dcos_di ); + rvec_ScaledAdd( workspace->f_tor[k], + CEtors8, p_jkl->dcos_dj ); + rvec_ScaledAdd( workspace->f_tor[l], + CEtors8, p_jkl->dcos_dk ); + + rvec_ScaledAdd( workspace->f_tor[i], + CEtors9, dcos_omega_di ); + rvec_ScaledAdd( workspace->f_tor[j], + CEtors9, dcos_omega_dj ); + rvec_ScaledAdd( workspace->f_tor[k], + CEtors9, dcos_omega_dk ); + rvec_ScaledAdd( workspace->f_tor[l], + CEtors9, dcos_omega_dl ); + + /* Conjugation Forces */ + Add_dBO( system, lists, j, pij, CEconj1, workspace->f_con ); + Add_dBO( system, lists, j, pk, CEconj2, workspace->f_con ); + Add_dBO( system, lists, k, plk, CEconj3, workspace->f_con ); + + rvec_ScaledAdd( workspace->f_con[i], + CEconj4, p_ijk->dcos_dk ); + rvec_ScaledAdd( workspace->f_con[j], + CEconj4, p_ijk->dcos_dj ); + rvec_ScaledAdd( workspace->f_con[k], + CEconj4, p_ijk->dcos_di ); + + rvec_ScaledAdd( workspace->f_con[j], + CEconj5, p_jkl->dcos_di ); + rvec_ScaledAdd( workspace->f_con[k], + CEconj5, p_jkl->dcos_dj ); + rvec_ScaledAdd( workspace->f_con[l], + CEconj5, p_jkl->dcos_dk ); + + rvec_ScaledAdd( workspace->f_con[i], + CEconj6, dcos_omega_di ); + rvec_ScaledAdd( workspace->f_con[j], + CEconj6, dcos_omega_dj ); + rvec_ScaledAdd( workspace->f_con[k], + CEconj6, dcos_omega_dk ); + rvec_ScaledAdd( workspace->f_con[l], + CEconj6, dcos_omega_dl ); +#endif + } // pl check ends + } // pl loop ends + } // pi check ends + } // pi loop ends + } // k-j neighbor check ends + } // jmy_en.e_tor, data->my_en.e_con ); + + fprintf( stderr, "4body: ext_press (%12.6f %12.6f %12.6f)\n", + data->ext_press[0], data->ext_press[1], data->ext_press[2] ); +#endif +} diff --git a/src/USER-REAXC/reaxc_torsion_angles.h b/src/USER-REAXC/reaxc_torsion_angles.h new file mode 100644 index 0000000000..d3c25501e6 --- /dev/null +++ b/src/USER-REAXC/reaxc_torsion_angles.h @@ -0,0 +1,30 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __TORSION_ANGLES_H_ +#define __TORSION_ANGLES_H_ + +#include "reaxc_types.h" + +void Torsion_Angles( reax_system*, control_params*, simulation_data*, + storage*, reax_list**, output_controls* ); + +#endif diff --git a/src/USER-REAXC/reaxc_traj.cpp b/src/USER-REAXC/reaxc_traj.cpp new file mode 100644 index 0000000000..0aaa413156 --- /dev/null +++ b/src/USER-REAXC/reaxc_traj.cpp @@ -0,0 +1,1072 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "traj.h" +#include "list.h" +#include "tool_box.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_traj.h" +#include "reaxc_list.h" +#include "reaxc_tool_box.h" +#endif + + +#if defined(PURE_REAX) +int Set_My_Trajectory_View( MPI_File trj, int offset, MPI_Datatype etype, + MPI_Comm comm, int my_rank, int my_n, int big_n ) +{ + int my_disp; + int length[3]; + MPI_Aint line_len; + MPI_Aint disp[3]; + MPI_Datatype type[3]; + MPI_Datatype view; + + /* line length inferred from etype */ + MPI_Type_extent( etype, &line_len ); + line_len /= sizeof(char); + + /* determine where to start writing into the mpi file */ + my_disp = SumScan( my_n, my_rank, MASTER_NODE, comm ); + my_disp -= my_n; + + /* create atom_info_view */ + length[0] = 1; + length[1] = my_n; + length[2] = 1; + disp[0] = 0; + disp[1] = line_len * my_disp; + disp[2] = line_len * big_n; + type[0] = MPI_LB; + type[1] = etype; + type[2] = MPI_UB; + + MPI_Type_struct( 3, length, disp, type, &view ); + MPI_Type_commit( &view ); + + MPI_File_set_view( trj, offset, etype, view, "native", MPI_INFO_NULL ); + + return my_disp; +} +#endif + + +int Reallocate_Output_Buffer( output_controls *out_control, int req_space, + MPI_Comm comm ) +{ + if( out_control->buffer_len > 0 ) + free( out_control->buffer ); + + out_control->buffer_len = (int)(req_space*SAFE_ZONE); + out_control->buffer = (char*) malloc(out_control->buffer_len*sizeof(char)); + if( out_control->buffer == NULL ) { + fprintf( stderr, + "insufficient memory for required buffer size %d. terminating!\n", + (int) (req_space*SAFE_ZONE) ); + MPI_Abort( comm, INSUFFICIENT_MEMORY ); + } + + return SUCCESS; +} + + +void Write_Skip_Line( output_controls *out_control, mpi_datatypes *mpi_data, + int my_rank, int skip, int num_section ) +{ +#if defined(PURE_REAX) + MPI_Status status; + + if( out_control->traj_method == MPI_TRAJ ) { + MPI_File_set_view( out_control->trj, out_control->trj_offset, + mpi_data->header_line, mpi_data->header_line, + "native", MPI_INFO_NULL ); + if( my_rank == MASTER_NODE ) { + sprintf( out_control->line, INT2_LINE, "chars_to_skip_section:", + skip, num_section ); + MPI_File_write( out_control->trj, out_control->line, 1, + mpi_data->header_line, &status ); + } + out_control->trj_offset += HEADER_LINE_LEN; + } + else { + if( my_rank == MASTER_NODE ) + fprintf( out_control->strj, INT2_LINE, + "chars_to_skip_section:", skip, num_section ); + } +#elif defined(LAMMPS_REAX) + if( my_rank == MASTER_NODE ) + fprintf( out_control->strj, INT2_LINE, + "chars_to_skip_section:", skip, num_section ); +#endif + +} + + +int Write_Header( reax_system *system, control_params *control, + output_controls *out_control, mpi_datatypes *mpi_data ) +{ + int num_hdr_lines, my_hdr_lines, buffer_req; + MPI_Status status; + char ensembles[ens_N][25] = { "NVE", "NVT", "fully flexible NPT", + "semi isotropic NPT", "isotropic NPT" }; + char reposition[3][25] = { "fit to periodic box", "CoM to center of box", + "CoM to origin" }; + char t_regime[3][25] = { "T-coupling only", "step-wise", "constant slope" }; + + char traj_methods[TF_N][10] = { "custom", "xyz" }; + char atom_formats[8][40] = { "none", "invalid", "invalid", "invalid", + "xyz_q", + "xyz_q_fxfyfz", + "xyz_q_vxvyvz", + "detailed_atom_info" }; + char bond_formats[3][30] = { "none", + "basic_bond_info", + "detailed_bond_info" }; + char angle_formats[2][30] = { "none", "basic_angle_info" }; + + /* set header lengths */ + num_hdr_lines = NUM_HEADER_LINES; + my_hdr_lines = num_hdr_lines * ( system->my_rank == MASTER_NODE ); + buffer_req = my_hdr_lines * HEADER_LINE_LEN; + if( buffer_req > out_control->buffer_len * DANGER_ZONE ) + Reallocate_Output_Buffer( out_control, buffer_req, mpi_data->world ); + + /* only the master node writes into trajectory header */ + if( system->my_rank == MASTER_NODE ) { + /* clear the contents of line & buffer */ + out_control->line[0] = 0; + out_control->buffer[0] = 0; + + /* to skip the header */ + sprintf( out_control->line, INT_LINE, "chars_to_skip_header:", + (num_hdr_lines-1) * HEADER_LINE_LEN ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + /* general simulation info */ + sprintf( out_control->line, STR_LINE, "simulation_name:", + out_control->traj_title ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, INT_LINE, "number_of_atoms:", system->bigN ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, STR_LINE, "ensemble_type:", + ensembles[ control->ensemble ] ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, INT_LINE, "number_of_steps:", + control->nsteps ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "timestep_length_(in_fs):", + control->dt * 1000 ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + /* restart info */ + sprintf( out_control->line, STR_LINE, "is_this_a_restart?:", + (control->restart ? "yes" : "no") ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + //sprintf( out_control->line, STR_LINE, "restarted_from_file:", + // (control->restart ? control->restart_from : "NA") ); + //strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + //sprintf( out_control->line, STR_LINE, "kept_restart_velocities?:", + // (control->restart ? (control->random_vel ? "no":"yes"):"NA") ); + //strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, STR_LINE, "write_restart_files?:", + ((out_control->restart_freq > 0) ? "yes" : "no") ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, INT_LINE, "frequency_to_write_restarts:", + out_control->restart_freq ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + /* preferences */ + sprintf( out_control->line, STR_LINE, "tabulate_long_range_intrs?:", + (control->tabulate ? "yes" : "no") ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, INT_LINE, "table_size:", control->tabulate ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, STR_LINE, "restrict_bonds?:", + (control->restrict_bonds ? "yes" : "no") ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, INT_LINE, "bond_restriction_length:", + control->restrict_bonds ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, STR_LINE, "reposition_atoms?:", + reposition[control->reposition_atoms] ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, INT_LINE, "remove_CoM_velocity?:", + (control->ensemble==NVE) ? 0 : control->remove_CoM_vel); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + + /* cut-off values */ + sprintf( out_control->line, REAL_LINE, "bonded_intr_dist_cutoff:", + control->bond_cut ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "nonbonded_intr_dist_cutoff:", + control->nonb_cut ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "hbond_dist_cutoff:", + control->hbond_cut ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "reax_bond_threshold:", + control->bo_cut ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "physical_bond_threshold:", + control->bg_cut ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "valence_angle_threshold:", + control->thb_cut ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, SCI_LINE, "QEq_tolerance:", control->q_err ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + /* temperature controls */ + sprintf( out_control->line, REAL_LINE, "initial_temperature:", + control->T_init ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "target_temperature:", + control->T_final ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "thermal_inertia:", + control->Tau_T ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, STR_LINE, "temperature_regime:", + t_regime[ control->T_mode ] ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "temperature_change_rate_(K/ps):", + control->T_rate / control->T_freq ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + /* pressure controls */ + sprintf( out_control->line, REAL3_LINE, "target_pressure_(GPa):", + control->P[0], control->P[1], control->P[2] ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL3_LINE, "virial_inertia:", + control->Tau_P[0], control->Tau_P[1], control->Tau_P[2] ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + /* trajectory */ + sprintf( out_control->line, INT_LINE, "energy_dumping_freq:", + out_control->energy_update_freq ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, INT_LINE, "trajectory_dumping_freq:", + out_control->write_steps ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, STR_LINE, "compress_trajectory_output?:", + (out_control->traj_compress ? "yes" : "no") ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, STR_LINE, "trajectory_format:", + traj_methods[ out_control->traj_method ] ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, STR_LINE, "atom_info:", + atom_formats[ out_control->atom_info ] ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, STR_LINE, "bond_info:", + bond_formats[ out_control->bond_info ] ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, STR_LINE, "angle_info:", + angle_formats[ out_control->angle_info ] ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + /* analysis */ + //sprintf( out_control->line, STR_LINE, "molecular_analysis:", + // (control->molec_anal ? "yes" : "no") ); + //strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, INT_LINE, "molecular_analysis_frequency:", + control->molecular_analysis ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + } + + /* dump out the buffer */ +#if defined(PURE_REAX) + if( out_control->traj_method == MPI_TRAJ ) { + out_control->trj_offset = 0; + Set_My_Trajectory_View( out_control->trj, + out_control->trj_offset, mpi_data->header_line, + mpi_data->world, system->my_rank, + my_hdr_lines, num_hdr_lines ); + MPI_File_write_all( out_control->trj, out_control->buffer, + num_hdr_lines, mpi_data->header_line, &status ); + out_control->trj_offset = (num_hdr_lines) * HEADER_LINE_LEN; + } + else { + if( system->my_rank == MASTER_NODE ) + fprintf( out_control->strj, "%s", out_control->buffer ); + } +#elif defined(LAMMPS_REAX) + if( system->my_rank == MASTER_NODE ) + fprintf( out_control->strj, "%s", out_control->buffer ); +#endif + + return SUCCESS; +} + + +int Write_Init_Desc( reax_system *system, control_params *control, + output_controls *out_control, mpi_datatypes *mpi_data ) +{ + int i, me, np, cnt, buffer_len, buffer_req; + reax_atom *p_atom; + //MPI_Request request; + MPI_Status status; + + me = system->my_rank; + np = system->wsize; + + /* skip info */ + Write_Skip_Line( out_control, mpi_data, me, + system->bigN * INIT_DESC_LEN, system->bigN ); + + if( out_control->traj_method == REG_TRAJ && me == MASTER_NODE ) + buffer_req = system->bigN * INIT_DESC_LEN + 1; + else buffer_req = system->n * INIT_DESC_LEN + 1; + + if( buffer_req > out_control->buffer_len * DANGER_ZONE ) + Reallocate_Output_Buffer( out_control, buffer_req, mpi_data->world ); + + out_control->line[0] = 0; + out_control->buffer[0] = 0; + for( i = 0; i < system->n; ++i ) { + p_atom = &( system->my_atoms[i] ); + sprintf( out_control->line, INIT_DESC, + p_atom->orig_id, p_atom->type, p_atom->name, + system->reax_param.sbp[ p_atom->type ].mass ); + strncpy( out_control->buffer + i*INIT_DESC_LEN, + out_control->line, INIT_DESC_LEN+1 ); + } + +#if defined(PURE_REAX) + if( out_control->traj_method == MPI_TRAJ ) { + Set_My_Trajectory_View( out_control->trj, out_control->trj_offset, + mpi_data->init_desc_line, mpi_data->world, + me, system->n, system->bigN ); + MPI_File_write( out_control->trj, out_control->buffer, system->n, + mpi_data->init_desc_line, &status ); + out_control->trj_offset += system->bigN * INIT_DESC_LEN; + } + else{ + if( me != MASTER_NODE ) + MPI_Send( out_control->buffer, buffer_req-1, MPI_CHAR, MASTER_NODE, + np * INIT_DESCS + me, mpi_data->world ); + else{ + buffer_len = system->n * INIT_DESC_LEN; + for( i = 0; i < np; ++i ) + if( i != MASTER_NODE ) { + MPI_Recv( out_control->buffer + buffer_len, buffer_req - buffer_len, + MPI_CHAR, i, np*INIT_DESCS+i, mpi_data->world, &status ); + MPI_Get_count( &status, MPI_CHAR, &cnt ); + buffer_len += cnt; + } + out_control->buffer[buffer_len] = 0; + fprintf( out_control->strj, "%s", out_control->buffer ); + } + } +#elif defined(LAMMPS_REAX) + if( me != MASTER_NODE ) + MPI_Send( out_control->buffer, buffer_req-1, MPI_CHAR, MASTER_NODE, + np * INIT_DESCS + me, mpi_data->world ); + else{ + buffer_len = system->n * INIT_DESC_LEN; + for( i = 0; i < np; ++i ) + if( i != MASTER_NODE ) { + MPI_Recv( out_control->buffer + buffer_len, buffer_req - buffer_len, + MPI_CHAR, i, np*INIT_DESCS+i, mpi_data->world, &status ); + MPI_Get_count( &status, MPI_CHAR, &cnt ); + buffer_len += cnt; + } + out_control->buffer[buffer_len] = 0; + fprintf( out_control->strj, "%s", out_control->buffer ); + } +#endif + + return SUCCESS; +} + + +int Init_Traj( reax_system *system, control_params *control, + output_controls *out_control, mpi_datatypes *mpi_data, + char *msg ) +{ + char fname[MAX_STR]; + int atom_line_len[ NR_OPT_ATOM ] = { 0, 0, 0, 0, + ATOM_BASIC_LEN, ATOM_wV_LEN, + ATOM_wF_LEN, ATOM_FULL_LEN }; + int bond_line_len[ NR_OPT_BOND ] = { 0, BOND_BASIC_LEN, BOND_FULL_LEN }; + int angle_line_len[ NR_OPT_ANGLE ] = { 0, ANGLE_BASIC_LEN }; + + /* generate trajectory name */ + sprintf( fname, "%s.trj", control->sim_name ); + + /* how should I write atoms? */ + out_control->atom_line_len = atom_line_len[ out_control->atom_info ]; + out_control->write_atoms = ( out_control->atom_line_len ? 1 : 0 ); + /* bonds? */ + out_control->bond_line_len = bond_line_len[ out_control->bond_info ]; + out_control->write_bonds = ( out_control->bond_line_len ? 1 : 0 ); + /* angles? */ + out_control->angle_line_len = angle_line_len[ out_control->angle_info ]; + out_control->write_angles = ( out_control->angle_line_len ? 1 : 0 ); + + /* allocate line & buffer space */ + out_control->line = (char*) calloc( MAX_TRJ_LINE_LEN + 1, sizeof(char) ); + out_control->buffer_len = 0; + out_control->buffer = NULL; + + /* fprintf( stderr, "p%d: init_traj: atom_line_len = %d " \ + "bond_line_len = %d, angle_line_len = %d\n" \ + "max_line = %d, max_buffer_size = %d\n", + system->my_rank, out_control->atom_line_len, + out_control->bond_line_len, out_control->angle_line_len, + MAX_TRJ_LINE_LEN, MAX_TRJ_BUFFER_SIZE ); */ + + /* write trajectory header and atom info, if applicable */ +#if defined(PURE_REAX) + if( out_control->traj_method == MPI_TRAJ ) { + /* attemp to delete the file to get rid of remnants of previous runs */ + if( system->my_rank == MASTER_NODE ) { + MPI_File_delete( fname, MPI_INFO_NULL ); + } + + /* open a fresh trajectory file */ + if( MPI_File_open( mpi_data->world, fname, + MPI_MODE_CREATE | MPI_MODE_WRONLY, MPI_INFO_NULL, + &(out_control->trj) ) ) { + strcpy( msg, "init_traj: unable to open trajectory file" ); + return FAILURE; + } + + /* build the mpi structs for trajectory */ + /* header_line */ + MPI_Type_contiguous( HEADER_LINE_LEN, MPI_CHAR, &(mpi_data->header_line) ); + MPI_Type_commit( &(mpi_data->header_line) ); + /* init_desc_line */ + MPI_Type_contiguous( INIT_DESC_LEN, MPI_CHAR, &(mpi_data->init_desc_line) ); + MPI_Type_commit( &(mpi_data->init_desc_line) ); + /* atom */ + MPI_Type_contiguous( out_control->atom_line_len, MPI_CHAR, + &(mpi_data->atom_line) ); + MPI_Type_commit( &(mpi_data->atom_line) ); + /* bonds */ + MPI_Type_contiguous( out_control->bond_line_len, MPI_CHAR, + &(mpi_data->bond_line) ); + MPI_Type_commit( &(mpi_data->bond_line) ); + /* angles */ + MPI_Type_contiguous( out_control->angle_line_len, MPI_CHAR, + &(mpi_data->angle_line) ); + MPI_Type_commit( &(mpi_data->angle_line) ); + } + else if( out_control->traj_method == REG_TRAJ) { + if( system->my_rank == MASTER_NODE ) + out_control->strj = fopen( fname, "w" ); + } + else { + strcpy( msg, "init_traj: unknown trajectory option" ); + return FAILURE; + } +#elif defined(LAMMPS_REAX) + if( out_control->traj_method == REG_TRAJ) { + if( system->my_rank == MASTER_NODE ) + out_control->strj = fopen( fname, "w" ); + } + else { + strcpy( msg, "init_traj: unknown trajectory option" ); + return FAILURE; + } +#endif + + +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: initiated trajectory\n", system->my_rank ); +#endif + Write_Header( system, control, out_control, mpi_data ); +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: header written\n", system->my_rank ); +#endif + Write_Init_Desc( system, control, out_control, mpi_data ); +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: atom descriptions written\n", system->my_rank ); +#endif + + return SUCCESS; +} + + +int Write_Frame_Header( reax_system *system, control_params *control, + simulation_data *data, output_controls *out_control, + mpi_datatypes *mpi_data ) +{ + int me, num_frm_hdr_lines, my_frm_hdr_lines, buffer_req; + MPI_Status status; + + me = system->my_rank; + /* frame header lengths */ + num_frm_hdr_lines = 22; + my_frm_hdr_lines = num_frm_hdr_lines * ( me == MASTER_NODE ); + buffer_req = my_frm_hdr_lines * HEADER_LINE_LEN; + if( buffer_req > out_control->buffer_len * DANGER_ZONE ) + Reallocate_Output_Buffer( out_control, buffer_req, mpi_data->world ); + + /* only the master node writes into trajectory header */ + if( me == MASTER_NODE ) { + /* clear the contents of line & buffer */ + out_control->line[0] = 0; + out_control->buffer[0] = 0; + + /* skip info */ + sprintf( out_control->line, INT_LINE, "chars_to_skip_frame_header:", + (num_frm_hdr_lines - 1) * HEADER_LINE_LEN ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + /* step & time */ + sprintf( out_control->line, INT_LINE, "step:", data->step ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "time_in_ps:", + data->step * control->dt ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + + /* box info */ + sprintf( out_control->line, REAL_LINE, "volume:", system->big_box.V ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL3_LINE, "box_dimensions:", + system->big_box.box_norms[0], + system->big_box.box_norms[1], + system->big_box.box_norms[2] ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL3_LINE, + "coordinate_angles:", 90.0, 90.0, 90.0 ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + + /* system T and P */ + sprintf( out_control->line, REAL_LINE, "temperature:", data->therm.T ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "pressure:", + (control->ensemble==iNPT) ? + data->iso_bar.P : data->flex_bar.P_scalar ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + + /* energies */ + sprintf( out_control->line, REAL_LINE, "total_energy:", + data->sys_en.e_tot ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "total_kinetic:", + data->sys_en.e_kin ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "total_potential:", + data->sys_en.e_pot ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "bond_energy:", + data->sys_en.e_bond ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "atom_energy:", + data->sys_en.e_ov + data->sys_en.e_un ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "lone_pair_energy:", + data->sys_en.e_lp ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "valence_angle_energy:", + data->sys_en.e_ang + data->sys_en.e_pen ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "3-body_conjugation:", + data->sys_en.e_coa ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "hydrogen_bond_energy:", + data->sys_en.e_hb ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "torsion_angle_energy:", + data->sys_en.e_tor ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "4-body_conjugation:", + data->sys_en.e_con ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "vdWaals_energy:", + data->sys_en.e_vdW ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "electrostatics_energy:", + data->sys_en.e_ele ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + + sprintf( out_control->line, REAL_LINE, "polarization_energy:", + data->sys_en.e_pol ); + strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 ); + } + + /* dump out the buffer */ +#if defined(PURE_REAX) + if( out_control->traj_method == MPI_TRAJ ) { + Set_My_Trajectory_View( out_control->trj, out_control->trj_offset, + mpi_data->header_line, mpi_data->world, + me, my_frm_hdr_lines, num_frm_hdr_lines ); + + MPI_File_write_all(out_control->trj, out_control->buffer, my_frm_hdr_lines, + mpi_data->header_line, &status); + out_control->trj_offset += (num_frm_hdr_lines) * HEADER_LINE_LEN; + } + else { + if( system->my_rank == MASTER_NODE ) + fprintf( out_control->strj, "%s", out_control->buffer ); + } +#elif defined(LAMMPS_REAX) + if( system->my_rank == MASTER_NODE ) + fprintf( out_control->strj, "%s", out_control->buffer ); +#endif + + return SUCCESS; +} + + + +int Write_Atoms( reax_system *system, control_params *control, + output_controls *out_control, mpi_datatypes *mpi_data ) +{ + int i, me, np, line_len, buffer_len, buffer_req, cnt; + MPI_Status status; + reax_atom *p_atom; + + me = system->my_rank; + np = system->wsize; + line_len = out_control->atom_line_len; + + Write_Skip_Line( out_control, mpi_data, me, + system->bigN*line_len, system->bigN ); + + if( out_control->traj_method == REG_TRAJ && me == MASTER_NODE ) + buffer_req = system->bigN * line_len + 1; + else buffer_req = system->n * line_len + 1; + + if( buffer_req > out_control->buffer_len * DANGER_ZONE ) + Reallocate_Output_Buffer( out_control, buffer_req, mpi_data->world ); + + /* fill in buffer */ + out_control->line[0] = 0; + out_control->buffer[0] = 0; + for( i = 0; i < system->n; ++i ) { + p_atom = &( system->my_atoms[i] ); + + switch( out_control->atom_info ) { + case OPT_ATOM_BASIC: + sprintf( out_control->line, ATOM_BASIC, + p_atom->orig_id, p_atom->x[0], p_atom->x[1], p_atom->x[2], + p_atom->q ); + break; + case OPT_ATOM_wF: + sprintf( out_control->line, ATOM_wF, + p_atom->orig_id, p_atom->x[0], p_atom->x[1], p_atom->x[2], + p_atom->f[0], p_atom->f[1], p_atom->f[2], p_atom->q ); + break; + case OPT_ATOM_wV: + sprintf( out_control->line, ATOM_wV, + p_atom->orig_id, p_atom->x[0], p_atom->x[1], p_atom->x[2], + p_atom->v[0], p_atom->v[1], p_atom->v[2], p_atom->q ); + break; + case OPT_ATOM_FULL: + sprintf( out_control->line, ATOM_FULL, + p_atom->orig_id, p_atom->x[0], p_atom->x[1], p_atom->x[2], + p_atom->v[0], p_atom->v[1], p_atom->v[2], + p_atom->f[0], p_atom->f[1], p_atom->f[2], p_atom->q ); + break; + default: + fprintf( stderr, + "write_traj_atoms: unknown atom trajectroy format!\n"); + MPI_Abort( mpi_data->world, UNKNOWN_OPTION ); + } + + strncpy( out_control->buffer + i*line_len, out_control->line, line_len+1 ); + } + +#if defined(PURE_REAX) + if( out_control->traj_method == MPI_TRAJ ) { + Set_My_Trajectory_View( out_control->trj, out_control->trj_offset, + mpi_data->atom_line, mpi_data->world, + me, system->n, system->bigN ); + MPI_File_write( out_control->trj, out_control->buffer, system->n, + mpi_data->atom_line, &status ); + out_control->trj_offset += (system->bigN) * out_control->atom_line_len; + } + else{ + if( me != MASTER_NODE ) + MPI_Send( out_control->buffer, buffer_req-1, MPI_CHAR, MASTER_NODE, + np*ATOM_LINES+me, mpi_data->world ); + else{ + buffer_len = system->n * line_len; + for( i = 0; i < np; ++i ) + if( i != MASTER_NODE ) { + MPI_Recv( out_control->buffer + buffer_len, buffer_req - buffer_len, + MPI_CHAR, i, np*ATOM_LINES+i, mpi_data->world, &status ); + MPI_Get_count( &status, MPI_CHAR, &cnt ); + buffer_len += cnt; + } + out_control->buffer[buffer_len] = 0; + fprintf( out_control->strj, "%s", out_control->buffer ); + } + } +#elif defined(LAMMPS_REAX) + if( me != MASTER_NODE ) + MPI_Send( out_control->buffer, buffer_req-1, MPI_CHAR, MASTER_NODE, + np*ATOM_LINES+me, mpi_data->world ); + else{ + buffer_len = system->n * line_len; + for( i = 0; i < np; ++i ) + if( i != MASTER_NODE ) { + MPI_Recv( out_control->buffer + buffer_len, buffer_req - buffer_len, + MPI_CHAR, i, np*ATOM_LINES+i, mpi_data->world, &status ); + MPI_Get_count( &status, MPI_CHAR, &cnt ); + buffer_len += cnt; + } + out_control->buffer[buffer_len] = 0; + fprintf( out_control->strj, "%s", out_control->buffer ); + } +#endif + + return SUCCESS; +} + + +int Write_Bonds(reax_system *system, control_params *control, reax_list *bonds, + output_controls *out_control, mpi_datatypes *mpi_data) +{ + int i, j, pj, me, np; + int my_bonds, num_bonds; + int line_len, buffer_len, buffer_req, cnt; + MPI_Status status; + bond_data *bo_ij; + + me = system->my_rank; + np = system->wsize; + line_len = out_control->bond_line_len; + + /* count the number of bonds I will write */ + my_bonds = 0; + for( i=0; i < system->n; ++i ) + for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) { + j = bonds->select.bond_list[pj].nbr; + if( system->my_atoms[i].orig_id <= system->my_atoms[j].orig_id && + bonds->select.bond_list[pj].bo_data.BO >= control->bg_cut ) + ++my_bonds; + } + /* allreduce - total number of bonds */ + MPI_Allreduce( &my_bonds, &num_bonds, 1, MPI_INT, MPI_SUM, mpi_data->world ); + + Write_Skip_Line( out_control, mpi_data, me, num_bonds*line_len, num_bonds ); + + if( out_control->traj_method == REG_TRAJ && me == MASTER_NODE ) + buffer_req = num_bonds * line_len + 1; + else buffer_req = my_bonds * line_len + 1; + + if( buffer_req > out_control->buffer_len * DANGER_ZONE ) + Reallocate_Output_Buffer( out_control, buffer_req, mpi_data->world ); + + /* fill in the buffer */ + my_bonds = 0; + out_control->line[0] = 0; + out_control->buffer[0] = 0; + for( i=0; i < system->n; ++i ) + for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) { + bo_ij = &( bonds->select.bond_list[pj] ); + j = bo_ij->nbr; + + if( system->my_atoms[i].orig_id <= system->my_atoms[j].orig_id && + bo_ij->bo_data.BO >= control->bg_cut ) { + switch( out_control->bond_info ) { + case OPT_BOND_BASIC: + sprintf( out_control->line, BOND_BASIC, + system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, + bo_ij->d, bo_ij->bo_data.BO ); + break; + case OPT_BOND_FULL: + sprintf( out_control->line, BOND_FULL, + system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, + bo_ij->d, bo_ij->bo_data.BO, bo_ij->bo_data.BO_s, + bo_ij->bo_data.BO_pi, bo_ij->bo_data.BO_pi2 ); + break; + default: + fprintf(stderr, "write_traj_bonds: FATAL! invalid bond_info option"); + MPI_Abort( mpi_data->world, UNKNOWN_OPTION ); + } + + strncpy( out_control->buffer + my_bonds*line_len, + out_control->line, line_len+1 ); + ++my_bonds; + } + } + +#if defined(PURE_REAX) + if( out_control->traj_method == MPI_TRAJ ) { + Set_My_Trajectory_View( out_control->trj, out_control->trj_offset, + mpi_data->bond_line, mpi_data->world, + me, my_bonds, num_bonds ); + MPI_File_write( out_control->trj, out_control->buffer, my_bonds, + mpi_data->bond_line, &status ); + out_control->trj_offset += num_bonds * line_len; + } + else{ + if( me != MASTER_NODE ) + MPI_Send( out_control->buffer, buffer_req-1, MPI_CHAR, MASTER_NODE, + np*BOND_LINES+me, mpi_data->world ); + else{ + buffer_len = my_bonds * line_len; + for( i = 0; i < np; ++i ) + if( i != MASTER_NODE ) { + MPI_Recv( out_control->buffer + buffer_len, buffer_req - buffer_len, + MPI_CHAR, i, np*BOND_LINES+i, mpi_data->world, &status ); + MPI_Get_count( &status, MPI_CHAR, &cnt ); + buffer_len += cnt; + } + out_control->buffer[buffer_len] = 0; + fprintf( out_control->strj, "%s", out_control->buffer ); + } + } +#elif defined(LAMMPS_REAX) + if( me != MASTER_NODE ) + MPI_Send( out_control->buffer, buffer_req-1, MPI_CHAR, MASTER_NODE, + np*BOND_LINES+me, mpi_data->world ); + else{ + buffer_len = my_bonds * line_len; + for( i = 0; i < np; ++i ) + if( i != MASTER_NODE ) { + MPI_Recv( out_control->buffer + buffer_len, buffer_req - buffer_len, + MPI_CHAR, i, np*BOND_LINES+i, mpi_data->world, &status ); + MPI_Get_count( &status, MPI_CHAR, &cnt ); + buffer_len += cnt; + } + out_control->buffer[buffer_len] = 0; + fprintf( out_control->strj, "%s", out_control->buffer ); + } +#endif + + return SUCCESS; +} + + +int Write_Angles( reax_system *system, control_params *control, + reax_list *bonds, reax_list *thb_intrs, + output_controls *out_control, mpi_datatypes *mpi_data ) +{ + int i, j, k, pi, pk, me, np; + int my_angles, num_angles; + int line_len, buffer_len, buffer_req, cnt; + bond_data *bo_ij, *bo_jk; + three_body_interaction_data *angle_ijk; + MPI_Status status; + + me = system->my_rank; + np = system->wsize; + line_len = out_control->angle_line_len; + + /* count the number of valence angles I will output */ + my_angles = 0; + for( j = 0; j < system->n; ++j ) + for( pi = Start_Index(j, bonds); pi < End_Index(j, bonds); ++pi ) { + bo_ij = &(bonds->select.bond_list[pi]); + i = bo_ij->nbr; + + if( bo_ij->bo_data.BO >= control->bg_cut ) // physical j&i bond + for( pk = Start_Index( pi, thb_intrs ); + pk < End_Index( pi, thb_intrs ); ++pk ) { + angle_ijk = &(thb_intrs->select.three_body_list[pk]); + k = angle_ijk->thb; + bo_jk = &(bonds->select.bond_list[ angle_ijk->pthb ]); + + if( system->my_atoms[i].orig_id < system->my_atoms[k].orig_id && + bo_jk->bo_data.BO >= control->bg_cut ) // physical j&k bond + ++my_angles; + } + } + /* total number of valences */ + MPI_Allreduce(&my_angles, &num_angles, 1, MPI_INT, MPI_SUM, mpi_data->world); + + Write_Skip_Line( out_control, mpi_data, me, num_angles*line_len, num_angles ); + + if( out_control->traj_method == REG_TRAJ && me == MASTER_NODE ) + buffer_req = num_angles * line_len + 1; + else buffer_req = my_angles * line_len + 1; + + if( buffer_req > out_control->buffer_len * DANGER_ZONE ) + Reallocate_Output_Buffer( out_control, buffer_req, mpi_data->world ); + + /* fill in the buffer */ + my_angles = 0; + out_control->line[0] = 0; + out_control->buffer[0] = 0; + for( j = 0; j < system->n; ++j ) + for( pi = Start_Index(j, bonds); pi < End_Index(j, bonds); ++pi ) { + bo_ij = &(bonds->select.bond_list[pi]); + i = bo_ij->nbr; + + if( bo_ij->bo_data.BO >= control->bg_cut ) // physical j&i bond + for( pk = Start_Index( pi, thb_intrs ); + pk < End_Index( pi, thb_intrs ); ++pk ) { + angle_ijk = &(thb_intrs->select.three_body_list[pk]); + k = angle_ijk->thb; + bo_jk = &(bonds->select.bond_list[ angle_ijk->pthb ]); + + if( system->my_atoms[i].orig_id < system->my_atoms[k].orig_id && + bo_jk->bo_data.BO >= control->bg_cut ) { // physical j&k bond + sprintf( out_control->line, ANGLE_BASIC, + system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, + system->my_atoms[k].orig_id, RAD2DEG( angle_ijk->theta ) ); + + strncpy( out_control->buffer + my_angles*line_len, + out_control->line, line_len+1 ); + ++my_angles; + } + } + } + +#if defined(PURE_REAX) + if( out_control->traj_method == MPI_TRAJ ){ + Set_My_Trajectory_View( out_control->trj, out_control->trj_offset, + mpi_data->angle_line, mpi_data->world, + me, my_angles, num_angles ); + MPI_File_write( out_control->trj, out_control->buffer, my_angles, + mpi_data->angle_line, &status ); + out_control->trj_offset += num_angles * line_len; + } + else{ + if( me != MASTER_NODE ) + MPI_Send( out_control->buffer, buffer_req-1, MPI_CHAR, MASTER_NODE, + np*ANGLE_LINES+me, mpi_data->world ); + else{ + buffer_len = my_angles * line_len; + for( i = 0; i < np; ++i ) + if( i != MASTER_NODE ) { + MPI_Recv( out_control->buffer + buffer_len, buffer_req - buffer_len, + MPI_CHAR, i, np*ANGLE_LINES+i, mpi_data->world, &status ); + MPI_Get_count( &status, MPI_CHAR, &cnt ); + buffer_len += cnt; + } + out_control->buffer[buffer_len] = 0; + fprintf( out_control->strj, "%s", out_control->buffer ); + } + } +#elif defined(LAMMPS_REAX) + if( me != MASTER_NODE ) + MPI_Send( out_control->buffer, buffer_req-1, MPI_CHAR, MASTER_NODE, + np*ANGLE_LINES+me, mpi_data->world ); + else{ + buffer_len = my_angles * line_len; + for( i = 0; i < np; ++i ) + if( i != MASTER_NODE ) { + MPI_Recv( out_control->buffer + buffer_len, buffer_req - buffer_len, + MPI_CHAR, i, np*ANGLE_LINES+i, mpi_data->world, &status ); + MPI_Get_count( &status, MPI_CHAR, &cnt ); + buffer_len += cnt; + } + out_control->buffer[buffer_len] = 0; + fprintf( out_control->strj, "%s", out_control->buffer ); + } +#endif + + return SUCCESS; +} + + +int Append_Frame( reax_system *system, control_params *control, + simulation_data *data, reax_list **lists, + output_controls *out_control, mpi_datatypes *mpi_data ) +{ +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: appending frame %d\n", system->my_rank, data->step ); +#endif + Write_Frame_Header( system, control, data, out_control, mpi_data ); + + if( out_control->write_atoms ) + Write_Atoms( system, control, out_control, mpi_data ); + + if( out_control->write_bonds ) + Write_Bonds( system, control, (*lists + BONDS), out_control, mpi_data ); + + if( out_control->write_angles ) + Write_Angles( system, control, (*lists + BONDS), (*lists + THREE_BODIES), + out_control, mpi_data ); +#if defined(DEBUG_FOCUS) + fprintf( stderr, "p%d: appended frame %d\n", system->my_rank, data->step ); +#endif + + return SUCCESS; +} + + +int End_Traj( int my_rank, output_controls *out_control ) +{ +#if defined(PURE_REAX) + if( out_control->traj_method == MPI_TRAJ ) + MPI_File_close( &(out_control->trj) ); + else if( my_rank == MASTER_NODE ) + fclose( out_control->strj ); +#elif defined(LAMMPS_REAX) + if( my_rank == MASTER_NODE ) + fclose( out_control->strj ); +#endif + + free( out_control->buffer ); + free( out_control->line ); + + return SUCCESS; +} diff --git a/src/USER-REAXC/reaxc_traj.h b/src/USER-REAXC/reaxc_traj.h new file mode 100644 index 0000000000..99e0c5223a --- /dev/null +++ b/src/USER-REAXC/reaxc_traj.h @@ -0,0 +1,77 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __TRAJ_H__ +#define __TRAJ_H__ + +#include "reaxc_types.h" + +#define MAX_TRJ_LINE_LEN 120 +#define MAX_TRJ_BUFFER_SIZE (MAX_TRJ_LINE_LEN * 100) + +#define NUM_HEADER_LINES 37 +#define HEADER_LINE_LEN 62 +#define STR_LINE "%-37s%-24s\n" +#define INT_LINE "%-37s%-24d\n" +#define INT2_LINE "%-36s%-12d,%-12d\n" +#define REAL_LINE "%-37s%-24.3f\n" +#define SCI_LINE "%-37s%-24g\n" +#define REAL3_LINE "%-32s%9.3f,%9.3f,%9.3f\n" + +#define INIT_DESC "%9d%3d%9s%10.3f\n" //AtomID - AtomType, AtomName, AtomMass +#define INIT_DESC_LEN 32 + +#define SIZE_INFO_LINE2 "%-10d%-10d\n" +#define SIZE_INFO_LEN2 21 + +#define SIZE_INFO_LINE3 "%-10d%-10d%-10d\n" +#define SIZE_INFO_LEN3 31 + +#define ATOM_BASIC "%9d%10.3f%10.3f%10.3f%10.3f\n" //AtomID AtomType (X Y Z) Charge +#define ATOM_BASIC_LEN 50 +#define ATOM_wV "%9d%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f\n" //AtomID (X Y Z) (Vx Vy Vz) Charge +#define ATOM_wV_LEN 80 +#define ATOM_wF "%9d%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f\n" //AtomID (X Y Z) (Fx Fy Fz) Charge +#define ATOM_wF_LEN 80 +#define ATOM_FULL "%9d%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f\n" //AtomID (X Y Z) (Vx Vy Vz) (Fx Fy Fz) Charge +#define ATOM_FULL_LEN 110 + +#define BOND_BASIC "%9d%9d%10.3f%10.3f\n" // Atom1 Atom2 Dist Total_BO +#define BOND_BASIC_LEN 39 +#define BOND_FULL "%9d%9d%10.3f%10.3f%10.3f%10.3f%10.3f\n" // Atom1 Atom2 Dist Total_BO BOs BOpi BOpi2 +#define BOND_FULL_LEN 69 + +#define ANGLE_BASIC "%9d%9d%9d%10.3f\n" // Atom1 Atom2 Atom3 Theta +#define ANGLE_BASIC_LEN 38 + +enum ATOM_LINE_OPTS { OPT_NOATOM = 0, OPT_ATOM_BASIC = 4, OPT_ATOM_wF = 5, OPT_ATOM_wV = 6, OPT_ATOM_FULL = 7, NR_OPT_ATOM = 8 }; +enum BOND_LINE_OPTS { OPT_NOBOND, OPT_BOND_BASIC, OPT_BOND_FULL, NR_OPT_BOND }; +enum ANGLE_LINE_OPTS { OPT_NOANGLE, OPT_ANGLE_BASIC, NR_OPT_ANGLE }; + + +int Init_Traj( reax_system*, control_params*, output_controls*, + mpi_datatypes*, char* ); +int End_Traj( int, output_controls* ); + +int Append_Frame( reax_system*, control_params*, simulation_data*, + reax_list**, output_controls*, mpi_datatypes* ); + +#endif diff --git a/src/USER-REAXC/reaxc_types.h b/src/USER-REAXC/reaxc_types.h new file mode 100644 index 0000000000..7c4dfc3c5b --- /dev/null +++ b/src/USER-REAXC/reaxc_types.h @@ -0,0 +1,977 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __REAX_TYPES_H_ +#define __REAX_TYPES_H_ + +#include "ctype.h" +#include "math.h" +#include "mpi.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "sys/time.h" +#include "time.h" +#include "zlib.h" + +/************* SOME DEFS - crucial for reax_types.h *********/ + +//#define PURE_REAX +#define LAMMPS_REAX + +//#define DEBUG +//#define DEBUG_FOCUS +//#define TEST_ENERGY +//#define TEST_FORCES +//#define CG_PERFORMANCE +#define LOG_PERFORMANCE +#define STANDARD_BOUNDARIES +//#define OLD_BOUNDARIES +//#define MIDPOINT_BOUNDARIES + +#define REAX_MAX_STR 1024 +#define REAX_MAX_NBRS 6 +#define REAX_MAX_3BODY_PARAM 5 +#define REAX_MAX_4BODY_PARAM 5 +#define REAX_MAX_ATOM_TYPES 25 +#define REAX_MAX_MOLECULE_SIZE 20 + +/********************** TYPE DEFINITIONS ********************/ +typedef int ivec[3]; +typedef double real; +typedef real rvec[3]; +typedef real rtensor[3][3]; +typedef real rvec2[2]; +typedef real rvec4[4]; + + +typedef struct { + int step, bigN; + real T, xi, v_xi, v_xi_old, G_xi; + rtensor box; +} restart_header; + +typedef struct { + int orig_id, type; + char name[8]; + rvec x, v; +} restart_atom; + +typedef struct +{ + int orig_id; + int imprt_id; + int type; + int num_bonds; + int num_hbonds; + //int pad; // pad to 8-byte address boundary + char name[8]; + rvec x; // position + rvec v; // velocity + rvec f_old; // old force + rvec4 s, t; // for calculating q +} mpi_atom; + + +typedef struct +{ + int orig_id; + int imprt_id; + int type; + int num_bonds; + int num_hbonds; + //int pad; + rvec x; // position +} boundary_atom; + + +typedef struct +{ + //int ncells; + //int *cnt_by_gcell; + + int cnt; + //int *block; + int *index; + //MPI_Datatype out_dtype; + void *out_atoms; +} mpi_out_data; + + +typedef struct +{ + MPI_Comm world; + MPI_Comm comm_mesh3D; + + MPI_Datatype sys_info; + MPI_Datatype mpi_atom_type; + MPI_Datatype boundary_atom_type; + MPI_Datatype mpi_rvec, mpi_rvec2; + MPI_Datatype restart_atom_type; + + MPI_Datatype header_line; + MPI_Datatype header_view; + MPI_Datatype init_desc_line; + MPI_Datatype init_desc_view; + MPI_Datatype atom_line; + MPI_Datatype atom_view; + MPI_Datatype bond_line; + MPI_Datatype bond_view; + MPI_Datatype angle_line; + MPI_Datatype angle_view; + + //MPI_Request send_req1[REAX_MAX_NBRS]; + //MPI_Request send_req2[REAX_MAX_NBRS]; + //MPI_Status send_stat1[REAX_MAX_NBRS]; + //MPI_Status send_stat2[REAX_MAX_NBRS]; + //MPI_Status recv_stat1[REAX_MAX_NBRS]; + //MPI_Status recv_stat2[REAX_MAX_NBRS]; + + mpi_out_data out_buffers[REAX_MAX_NBRS]; + void *in1_buffer; + void *in2_buffer; +} mpi_datatypes; + + +/* Global params mapping */ +/* +l[0] = p_boc1 +l[1] = p_boc2 +l[2] = p_coa2 +l[3] = N/A +l[4] = N/A +l[5] = N/A +l[6] = p_ovun6 +l[7] = N/A +l[8] = p_ovun7 +l[9] = p_ovun8 +l[10] = N/A +l[11] = swa +l[12] = swb +l[13] = N/A +l[14] = p_val6 +l[15] = p_lp1 +l[16] = p_val9 +l[17] = p_val10 +l[18] = N/A +l[19] = p_pen2 +l[20] = p_pen3 +l[21] = p_pen4 +l[22] = N/A +l[23] = p_tor2 +l[24] = p_tor3 +l[25] = p_tor4 +l[26] = N/A +l[27] = p_cot2 +l[28] = p_vdW1 +l[29] = v_par30 +l[30] = p_coa4 +l[31] = p_ovun4 +l[32] = p_ovun3 +l[33] = p_val8 +l[34] = N/A +l[35] = N/A +l[36] = N/A +l[37] = version number +l[38] = p_coa3 +*/ + +typedef struct +{ + int n_global; + real* l; + int vdw_type; +} global_parameters; + + + +typedef struct +{ + /* Line one in field file */ + char name[15]; // Two character atom name + + real r_s; + real valency; // Valency of the atom + real mass; // Mass of atom + real r_vdw; + real epsilon; + real gamma; + real r_pi; + real valency_e; + real nlp_opt; + + /* Line two in field file */ + real alpha; + real gamma_w; + real valency_boc; + real p_ovun5; + real chi; + real eta; + int p_hbond; // 1 for H, 2 for hbonding atoms (O,S,P,N), 0 for others + + /* Line three in field file */ + real r_pi_pi; + real p_lp2; + real b_o_131; + real b_o_132; + real b_o_133; + + /* Line four in the field file */ + real p_ovun2; + real p_val3; + real valency_val; + real p_val5; + real rcore2; + real ecore2; + real acore2; +} single_body_parameters; + + + +/* Two Body Parameters */ +typedef struct { + /* Bond Order parameters */ + real p_bo1,p_bo2,p_bo3,p_bo4,p_bo5,p_bo6; + real r_s, r_p, r_pp; // r_o distances in BO formula + real p_boc3, p_boc4, p_boc5; + + /* Bond Energy parameters */ + real p_be1, p_be2; + real De_s, De_p, De_pp; + + /* Over/Under coordination parameters */ + real p_ovun1; + + /* Van der Waal interaction parameters */ + real D; + real alpha; + real r_vdW; + real gamma_w; + real rcore, ecore, acore; + + /* electrostatic parameters */ + real gamma; // note: this parameter is gamma^-3 and not gamma. + + real v13cor, ovc; +} two_body_parameters; + + + +/* 3-body parameters */ +typedef struct { + /* valence angle */ + real theta_00; + real p_val1, p_val2, p_val4, p_val7; + + /* penalty */ + real p_pen1; + + /* 3-body conjugation */ + real p_coa1; +} three_body_parameters; + + +typedef struct{ + int cnt; + three_body_parameters prm[REAX_MAX_3BODY_PARAM]; +} three_body_header; + + + +/* hydrogen-bond parameters */ +typedef struct{ + real r0_hb, p_hb1, p_hb2, p_hb3; +} hbond_parameters; + + + +/* 4-body parameters */ +typedef struct { + real V1, V2, V3; + + /* torsion angle */ + real p_tor1; + + /* 4-body conjugation */ + real p_cot1; +} four_body_parameters; + + +typedef struct +{ + int cnt; + four_body_parameters prm[REAX_MAX_4BODY_PARAM]; +} four_body_header; + + +typedef struct +{ + int num_atom_types; + global_parameters gp; + single_body_parameters *sbp; + two_body_parameters **tbp; + three_body_header ***thbp; + hbond_parameters ***hbp; + four_body_header ****fbp; +} reax_interaction; + + + +typedef struct +{ + int orig_id; + int imprt_id; + int type; + char name[8]; + + rvec x; // position + rvec v; // velocity + rvec f; // force + rvec f_old; + + real q; // charge + rvec4 s; // they take part in + rvec4 t; // computing q + + int Hindex; + int num_bonds; + int num_hbonds; + int renumber; +} reax_atom; + + + +typedef struct +{ + real V; + rvec min, max, box_norms; + + rtensor box, box_inv; + rtensor trans, trans_inv; + rtensor g; +} simulation_box; + + + +struct grid_cell +{ + real cutoff; + rvec min, max; + ivec rel_box; + + int mark; + int type; + int str; + int end; + int top; + int* atoms; + struct grid_cell** nbrs; + ivec* nbrs_x; + rvec* nbrs_cp; +}; + +typedef struct grid_cell grid_cell; + + +typedef struct +{ + int total, max_atoms, max_nbrs; + ivec ncells; + rvec cell_len; + rvec inv_len; + + ivec bond_span; + ivec nonb_span; + ivec vlist_span; + + ivec native_cells; + ivec native_str; + ivec native_end; + + real ghost_cut; + ivec ghost_span; + ivec ghost_nonb_span; + ivec ghost_hbond_span; + ivec ghost_bond_span; + + grid_cell*** cells; + ivec *order; +} grid; + + +typedef struct +{ + int rank; + int est_send, est_recv; + int atoms_str, atoms_cnt; + ivec rltv, prdc; + rvec bndry_min, bndry_max; + + int send_type; + int recv_type; + ivec str_send; + ivec end_send; + ivec str_recv; + ivec end_recv; +} neighbor_proc; + + + +typedef struct +{ + int N; + int exc_gcells; + int exc_atoms; +} bound_estimate; + + + +typedef struct +{ + real ghost_nonb; + real ghost_hbond; + real ghost_bond; + real ghost_cutoff; +} boundary_cutoff; + + + +typedef struct +{ + reax_interaction reax_param; + + int n, N, bigN, numH; + int local_cap, total_cap, gcell_cap, Hcap; + int est_recv, est_trans, max_recved; + int wsize, my_rank, num_nbrs; + ivec my_coords; + neighbor_proc my_nbrs[REAX_MAX_NBRS]; + int *global_offset; + simulation_box big_box, my_box, my_ext_box; + grid my_grid; + boundary_cutoff bndry_cuts; + + reax_atom *my_atoms; +} reax_system; + + + +/* system control parameters */ +typedef struct +{ + char sim_name[REAX_MAX_STR]; + int nprocs; + ivec procs_by_dim; + /* ensemble values: + 0 : NVE + 1 : bNVT (Berendsen) + 2 : nhNVT (Nose-Hoover) + 3 : sNPT (Parrinello-Rehman-Nose-Hoover) semiisotropic + 4 : iNPT (Parrinello-Rehman-Nose-Hoover) isotropic + 5 : NPT (Parrinello-Rehman-Nose-Hoover) Anisotropic*/ + int ensemble; + int nsteps; + real dt; + int geo_format; + int restart; + + int restrict_bonds; + int remove_CoM_vel; + int random_vel; + int reposition_atoms; + + int reneighbor; + real vlist_cut; + real bond_cut; + real nonb_cut, nonb_low; + real hbond_cut; + real user_ghost_cut; + + real bg_cut; + real bo_cut; + real thb_cut; + + int tabulate; + + int qeq_freq; + real q_err; + int refactor; + real droptol; + + real T_init, T_final, T; + real Tau_T; + int T_mode; + real T_rate, T_freq; + + int virial; + rvec P, Tau_P, Tau_PT; + int press_mode; + real compressibility; + + int molecular_analysis; + int num_ignored; + int ignore[REAX_MAX_ATOM_TYPES]; + + int dipole_anal; + int freq_dipole_anal; + int diffusion_coef; + int freq_diffusion_coef; + int restrict_type; +} control_params; + + +typedef struct +{ + real T; + real xi; + real v_xi; + real v_xi_old; + real G_xi; + +} thermostat; + + +typedef struct +{ + real P; + real eps; + real v_eps; + real v_eps_old; + real a_eps; + +} isotropic_barostat; + + +typedef struct +{ + rtensor P; + real P_scalar; + + real eps; + real v_eps; + real v_eps_old; + real a_eps; + + rtensor h0; + rtensor v_g0; + rtensor v_g0_old; + rtensor a_g0; + +} flexible_barostat; + + +typedef struct +{ + real start; + real end; + real elapsed; + + real total; + real comm; + real nbrs; + real init_forces; + real bonded; + real nonb; + real qEq; + int s_matvecs; + int t_matvecs; +} reax_timing; + + +typedef struct +{ + real e_tot; + real e_kin; // Total kinetic energy + real e_pot; + + real e_bond; // Total bond energy + real e_ov; // Total over coordination + real e_un; // Total under coordination energy + real e_lp; // Total under coordination energy + real e_ang; // Total valance angle energy + real e_pen; // Total penalty energy + real e_coa; // Total three body conjgation energy + real e_hb; // Total Hydrogen bond energy + real e_tor; // Total torsional energy + real e_con; // Total four body conjugation energy + real e_vdW; // Total van der Waals energy + real e_ele; // Total electrostatics energy + real e_pol; // Polarization energy +} energy_data; + +typedef struct +{ + int step; + int prev_steps; + real time; + + real M; // Total Mass + real inv_M; // 1 / Total Mass + + rvec xcm; // Center of mass + rvec vcm; // Center of mass velocity + rvec fcm; // Center of mass force + rvec amcm; // Angular momentum of CoM + rvec avcm; // Angular velocity of CoM + real etran_cm; // Translational kinetic energy of CoM + real erot_cm; // Rotational kinetic energy of CoM + + rtensor kinetic; // Kinetic energy tensor + rtensor virial; // Hydrodynamic virial + + energy_data my_en; + energy_data sys_en; + + real N_f; //Number of degrees of freedom + rvec t_scale; + rtensor p_scale; + thermostat therm; // Used in Nose_Hoover method + isotropic_barostat iso_bar; + flexible_barostat flex_bar; + real inv_W; + + real kin_press; + rvec int_press; + rvec my_ext_press; + rvec ext_press; + rvec tot_press; + + reax_timing timing; +} simulation_data; + + +typedef struct{ + int thb; + int pthb; // pointer to the third body on the central atom's nbrlist + real theta, cos_theta; + rvec dcos_di, dcos_dj, dcos_dk; +} three_body_interaction_data; + + +typedef struct { + int nbr; + ivec rel_box; + real d; + rvec dvec; +} far_neighbor_data; + + +typedef struct { + int nbr; + int scl; + far_neighbor_data *ptr; +} hbond_data; + + +typedef struct{ + int wrt; + rvec dVal; +} dDelta_data; + + +typedef struct{ + int wrt; + rvec dBO, dBOpi, dBOpi2; +} dbond_data; + +typedef struct{ + real BO, BO_s, BO_pi, BO_pi2; + real Cdbo, Cdbopi, Cdbopi2; + real C1dbo, C2dbo, C3dbo; + real C1dbopi, C2dbopi, C3dbopi, C4dbopi; + real C1dbopi2, C2dbopi2, C3dbopi2, C4dbopi2; + rvec dBOp, dln_BOp_s, dln_BOp_pi, dln_BOp_pi2; +} bond_order_data; + +typedef struct { + int nbr; + int sym_index; + int dbond_index; + ivec rel_box; + // rvec ext_factor; + real d; + rvec dvec; + bond_order_data bo_data; +} bond_data; + + +typedef struct { + int j; + real val; +} sparse_matrix_entry; + +typedef struct { + int cap, n, m; + int *start, *end; + sparse_matrix_entry *entries; +} sparse_matrix; + + +typedef struct { + int num_far; + int H, Htop; + int hbonds, num_hbonds; + int bonds, num_bonds; + int num_3body; + int gcell_atoms; +} reallocate_data; + + +typedef struct +{ + int allocated; + + /* communication storage */ + real *tmp_dbl[REAX_MAX_NBRS]; + rvec *tmp_rvec[REAX_MAX_NBRS]; + rvec2 *tmp_rvec2[REAX_MAX_NBRS]; + int *within_bond_box; + + /* bond order related storage */ + real *total_bond_order; + real *Deltap, *Deltap_boc; + real *Delta, *Delta_lp, *Delta_lp_temp, *Delta_e, *Delta_boc; + real *dDelta_lp, *dDelta_lp_temp; + real *nlp, *nlp_temp, *Clp, *vlpex; + rvec *dDeltap_self; + int *bond_mark, *done_after; + + /* QEq storage */ + sparse_matrix *H, *L, *U; + real *Hdia_inv, *b_s, *b_t, *b_prc, *b_prm, *s, *t; + real *droptol; + rvec2 *b, *x; + + /* GMRES storage */ + real *y, *z, *g; + real *hc, *hs; + real **h, **v; + /* CG storage */ + real *r, *d, *q, *p; + rvec2 *r2, *d2, *q2, *p2; + /* Taper */ + real Tap[8]; //Tap7, Tap6, Tap5, Tap4, Tap3, Tap2, Tap1, Tap0; + + /* storage for analysis */ + int *mark, *old_mark; + rvec *x_old; + + /* storage space for bond restrictions */ + int *restricted; + int **restricted_list; + + /* integrator */ + rvec *v_const; + + /* force calculations */ + real *CdDelta; // coefficient of dDelta + rvec *f; +#ifdef TEST_FORCES + rvec *f_ele; + rvec *f_vdw; + rvec *f_bo; + rvec *f_be; + rvec *f_lp; + rvec *f_ov; + rvec *f_un; + rvec *f_ang; + rvec *f_coa; + rvec *f_pen; + rvec *f_hb; + rvec *f_tor; + rvec *f_con; + rvec *f_tot; + rvec *dDelta; // calculated on the fly in bond_orders.c together with bo' + + int *rcounts; + int *displs; + int *id_all; + rvec *f_all; +#endif + + reallocate_data realloc; + //int *num_bonds; + /* hydrogen bonds */ + //int num_H, Hcap; + //int *Hindex; + //int *num_hbonds; + //int *hash; + //int *rev_hash; +} storage; + + +typedef union +{ + void *v; + three_body_interaction_data *three_body_list; + bond_data *bond_list; + dbond_data *dbo_list; + dDelta_data *dDelta_list; + far_neighbor_data *far_nbr_list; + hbond_data *hbond_list; +} list_type; + + +typedef struct +{ + int allocated; + + int n; + int num_intrs; + + int *index; + int *end_index; + + int type; + list_type select; +} reax_list; + + +typedef struct +{ +#if defined(PURE_REAX) + MPI_File trj; +#endif + FILE *strj; + int trj_offset; + int atom_line_len; + int bond_line_len; + int angle_line_len; + int write_atoms; + int write_bonds; + int write_angles; + char *line; + int buffer_len; + char *buffer; + + FILE *out; + FILE *pot; + FILE *log; + FILE *mol, *ign; + FILE *dpl; + FILE *drft; + FILE *pdb; + FILE *prs; + + int write_steps; + int traj_compress; + int traj_method; + char traj_title[81]; + int atom_info; + int bond_info; + int angle_info; + + int restart_format; + int restart_freq; + int debug_level; + int energy_update_freq; + +#ifdef TEST_ENERGY + FILE *ebond; + FILE *elp, *eov, *eun; + FILE *eval, *epen, *ecoa; + FILE *ehb; + FILE *etor, *econ; + FILE *evdw, *ecou; +#endif + +#ifdef TEST_FORCES + FILE *fbo, *fdbo; + FILE *fbond; + FILE *flp, *fov, *fun; + FILE *fang, *fcoa, *fpen; + FILE *fhb; + FILE *ftor, *fcon; + FILE *fvdw, *fele; + FILE *ftot, *fcomp; +#endif + +#if defined(TEST_ENERGY) || defined(TEST_FORCES) + FILE *flist; // far neighbor list + FILE *blist; // bond list + FILE *nlist; // near neighbor list +#endif +} output_controls; + + +typedef struct +{ + int atom_count; + int atom_list[REAX_MAX_MOLECULE_SIZE]; + int mtypes[REAX_MAX_ATOM_TYPES]; +} molecule; + + +typedef struct +{ + real H; + real e_vdW, CEvd; + real e_ele, CEclmb; +} LR_data; + + +typedef struct +{ + real a, b, c, d; +} cubic_spline_coef; + + + +typedef struct +{ + real xmin, xmax; + int n; + real dx, inv_dx; + real a; + real m; + real c; + + LR_data *y; + cubic_spline_coef *H; + cubic_spline_coef *vdW, *CEvd; + cubic_spline_coef *ele, *CEclmb; +} LR_lookup_table; +extern LR_lookup_table **LR; + +/* function pointer defs */ +typedef void (*evolve_function)(reax_system*, control_params*, + simulation_data*, storage*, reax_list**, + output_controls*, mpi_datatypes* ); +#if defined(PURE_REAX) +evolve_function Evolve; +#endif + +typedef void (*interaction_function) (reax_system*, control_params*, + simulation_data*, storage*, + reax_list**, output_controls*); + +typedef void (*print_interaction)(reax_system*, control_params*, + simulation_data*, storage*, + reax_list**, output_controls*); + +typedef real (*lookup_function)(real); + +typedef void (*message_sorter) (reax_system*, int, int, int, mpi_out_data*); +typedef void (*unpacker) ( reax_system*, int, void*, int, neighbor_proc*, int ); + +typedef void (*dist_packer) (void*, mpi_out_data*); +typedef void (*coll_unpacker) (void*, void*, mpi_out_data*); +#endif diff --git a/src/USER-REAXC/reaxc_valence_angles.cpp b/src/USER-REAXC/reaxc_valence_angles.cpp new file mode 100644 index 0000000000..84b41ba5fc --- /dev/null +++ b/src/USER-REAXC/reaxc_valence_angles.cpp @@ -0,0 +1,535 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "valence_angles.h" +#include "bond_orders.h" +#include "list.h" +#include "vector.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_valence_angles.h" +#include "reaxc_bond_orders.h" +#include "reaxc_list.h" +#include "reaxc_vector.h" +#endif + + +/* calculates the theta angle between i-j-k */ +void Calculate_Theta( rvec dvec_ji, real d_ji, rvec dvec_jk, real d_jk, + real *theta, real *cos_theta ) +{ + (*cos_theta) = Dot( dvec_ji, dvec_jk, 3 ) / ( d_ji * d_jk ); + if( *cos_theta > 1. ) *cos_theta = 1.0; + if( *cos_theta < -1. ) *cos_theta = -1.0; + + (*theta) = acos( *cos_theta ); +} + + +/* calculates the derivative of the cosine of the angle between i-j-k */ +void Calculate_dCos_Theta( rvec dvec_ji, real d_ji, rvec dvec_jk, real d_jk, + rvec* dcos_theta_di, + rvec* dcos_theta_dj, + rvec* dcos_theta_dk ) +{ + int t; + real sqr_d_ji = SQR(d_ji); + real sqr_d_jk = SQR(d_jk); + real inv_dists = 1.0 / (d_ji * d_jk); + real inv_dists3 = pow( inv_dists, 3 ); + real dot_dvecs = Dot( dvec_ji, dvec_jk, 3 ); + real Cdot_inv3 = dot_dvecs * inv_dists3; + + for( t = 0; t < 3; ++t ) { + (*dcos_theta_di)[t] = dvec_jk[t] * inv_dists - + Cdot_inv3 * sqr_d_jk * dvec_ji[t]; + (*dcos_theta_dj)[t] = -(dvec_jk[t] + dvec_ji[t]) * inv_dists + + Cdot_inv3 * ( sqr_d_jk * dvec_ji[t] + sqr_d_ji * dvec_jk[t] ); + (*dcos_theta_dk)[t] = dvec_ji[t] * inv_dists - + Cdot_inv3 * sqr_d_ji * dvec_jk[t]; + } +} + + +/* this is a 3-body interaction in which the main role is + played by j which sits in the middle of the other two. */ +void Valence_Angles( reax_system *system, control_params *control, + simulation_data *data, storage *workspace, + reax_list **lists, output_controls *out_control ) +{ + int i, j, pi, k, pk, t; + int type_i, type_j, type_k; + int start_j, end_j, start_pk, end_pk; + int cnt, num_thb_intrs; + + real temp, temp_bo_jt, pBOjt7; + real p_val1, p_val2, p_val3, p_val4, p_val5; + real p_val6, p_val7, p_val8, p_val9, p_val10; + real p_pen1, p_pen2, p_pen3, p_pen4; + real p_coa1, p_coa2, p_coa3, p_coa4; + real trm8, expval6, expval7, expval2theta, expval12theta, exp3ij, exp3jk; + real exp_pen2ij, exp_pen2jk, exp_pen3, exp_pen4, trm_pen34, exp_coa2; + real dSBO1, dSBO2, SBO, SBO2, CSBO2, SBOp, prod_SBO, vlpadj; + real CEval1, CEval2, CEval3, CEval4, CEval5, CEval6, CEval7, CEval8; + real CEpen1, CEpen2, CEpen3; + real e_ang, e_coa, e_pen; + real CEcoa1, CEcoa2, CEcoa3, CEcoa4, CEcoa5; + real Cf7ij, Cf7jk, Cf8j, Cf9j; + real f7_ij, f7_jk, f8_Dj, f9_Dj; + real Ctheta_0, theta_0, theta_00, theta, cos_theta, sin_theta; + real r_ij, r_jk; + real BOA_ij, BOA_jk; + rvec force, ext_press; + // rtensor temp_rtensor, total_rtensor; + + three_body_header *thbh; + three_body_parameters *thbp; + three_body_interaction_data *p_ijk, *p_kji; + bond_data *pbond_ij, *pbond_jk, *pbond_jt; + bond_order_data *bo_ij, *bo_jk, *bo_jt; + reax_list *bonds = (*lists) + BONDS; + reax_list *thb_intrs = (*lists) + THREE_BODIES; + + + /* global parameters used in these calculations */ + p_val6 = system->reax_param.gp.l[14]; + p_val8 = system->reax_param.gp.l[33]; + p_val9 = system->reax_param.gp.l[16]; + p_val10 = system->reax_param.gp.l[17]; + num_thb_intrs = 0; + + + for( j = 0; j < system->N; ++j ) { + // fprintf( out_control->eval, "j: %d\n", j ); + type_j = system->my_atoms[j].type; + start_j = Start_Index(j, bonds); + end_j = End_Index(j, bonds); + + p_val3 = system->reax_param.sbp[ type_j ].p_val3; + p_val5 = system->reax_param.sbp[ type_j ].p_val5; + + SBOp = 0, prod_SBO = 1; + for( t = start_j; t < end_j; ++t ) { + bo_jt = &(bonds->select.bond_list[t].bo_data); + SBOp += (bo_jt->BO_pi + bo_jt->BO_pi2); + temp = SQR( bo_jt->BO ); + temp *= temp; + temp *= temp; + prod_SBO *= exp( -temp ); + } + + /* modifications to match Adri's code - 09/01/09 */ + if( workspace->vlpex[j] >= 0 ){ + vlpadj = 0; + dSBO2 = prod_SBO - 1; + } + else{ + vlpadj = workspace->nlp[j]; + dSBO2 = (prod_SBO - 1) * (1 - p_val8 * workspace->dDelta_lp[j]); + } + + SBO = SBOp + (1 - prod_SBO) * (-workspace->Delta_boc[j] - p_val8 * vlpadj); + dSBO1 = -8 * prod_SBO * ( workspace->Delta_boc[j] + p_val8 * vlpadj ); + + if( SBO <= 0 ) + SBO2 = 0, CSBO2 = 0; + else if( SBO > 0 && SBO <= 1 ) { + SBO2 = pow( SBO, p_val9 ); + CSBO2 = p_val9 * pow( SBO, p_val9 - 1 ); + } + else if( SBO > 1 && SBO < 2 ) { + SBO2 = 2 - pow( 2-SBO, p_val9 ); + CSBO2 = p_val9 * pow( 2 - SBO, p_val9 - 1 ); + } + else + SBO2 = 2, CSBO2 = 0; + + expval6 = exp( p_val6 * workspace->Delta_boc[j] ); + + for( pi = start_j; pi < end_j; ++pi ) { + Set_Start_Index( pi, num_thb_intrs, thb_intrs ); + pbond_ij = &(bonds->select.bond_list[pi]); + bo_ij = &(pbond_ij->bo_data); + BOA_ij = bo_ij->BO - control->thb_cut; + + + if( BOA_ij/*bo_ij->BO*/ > 0.0 && + ( j < system->n || pbond_ij->nbr < system->n ) ) { + i = pbond_ij->nbr; + r_ij = pbond_ij->d; + type_i = system->my_atoms[i].type; + // fprintf( out_control->eval, "i: %d\n", i ); + + + /* first copy 3-body intrs from previously computed ones where i>k. + in the second for-loop below, + we compute only new 3-body intrs where i < k */ + for( pk = start_j; pk < pi; ++pk ) { + // fprintf( out_control->eval, "pk: %d\n", pk ); + start_pk = Start_Index( pk, thb_intrs ); + end_pk = End_Index( pk, thb_intrs ); + + for( t = start_pk; t < end_pk; ++t ) + if( thb_intrs->select.three_body_list[t].thb == i ) { + p_ijk = &(thb_intrs->select.three_body_list[num_thb_intrs] ); + p_kji = &(thb_intrs->select.three_body_list[t]); + + p_ijk->thb = bonds->select.bond_list[pk].nbr; + p_ijk->pthb = pk; + p_ijk->theta = p_kji->theta; + rvec_Copy( p_ijk->dcos_di, p_kji->dcos_dk ); + rvec_Copy( p_ijk->dcos_dj, p_kji->dcos_dj ); + rvec_Copy( p_ijk->dcos_dk, p_kji->dcos_di ); + + ++num_thb_intrs; + break; + } + } + + + /* and this is the second for loop mentioned above */ + for( pk = pi+1; pk < end_j; ++pk ) { + pbond_jk = &(bonds->select.bond_list[pk]); + bo_jk = &(pbond_jk->bo_data); + BOA_jk = bo_jk->BO - control->thb_cut; + k = pbond_jk->nbr; + type_k = system->my_atoms[k].type; + p_ijk = &( thb_intrs->select.three_body_list[num_thb_intrs] ); + + Calculate_Theta( pbond_ij->dvec, pbond_ij->d, + pbond_jk->dvec, pbond_jk->d, + &theta, &cos_theta ); + + Calculate_dCos_Theta( pbond_ij->dvec, pbond_ij->d, + pbond_jk->dvec, pbond_jk->d, + &(p_ijk->dcos_di), &(p_ijk->dcos_dj), + &(p_ijk->dcos_dk) ); + p_ijk->thb = k; + p_ijk->pthb = pk; + p_ijk->theta = theta; + + sin_theta = sin( theta ); + if( sin_theta < 1.0e-5 ) + sin_theta = 1.0e-5; + + ++num_thb_intrs; + + + if( (j < system->n) && (BOA_jk > 0.0) && + (bo_ij->BO * bo_jk->BO > SQR(control->thb_cut)/*0*/) ) { + r_jk = pbond_jk->d; + thbh = &( system->reax_param.thbp[ type_i ][ type_j ][ type_k ] ); + + /* if( system->my_atoms[i].orig_id < system->my_atoms[k].orig_id ) + fprintf( fval, "%6d %6d %6d %7.3f %7.3f %7.3f\n", + system->my_atoms[i].orig_id, + system->my_atoms[j].orig_id, + system->my_atoms[k].orig_id, + bo_ij->BO, bo_jk->BO, p_ijk->theta ); + else + fprintf( fval, "%6d %6d %6d %7.3f %7.3f %7.3f\n", + system->my_atoms[k].orig_id, + system->my_atoms[j].orig_id, + system->my_atoms[i].orig_id, + bo_jk->BO, bo_ij->BO, p_ijk->theta ); */ + + for( cnt = 0; cnt < thbh->cnt; ++cnt ) { + // fprintf( out_control->eval, "%6d%6d%6d -- exists in thbp\n", + // i+1, j+1, k+1 ); + + if( fabs(thbh->prm[cnt].p_val1) > 0.001 ) { + thbp = &( thbh->prm[cnt] ); + + /* ANGLE ENERGY */ + p_val1 = thbp->p_val1; + p_val2 = thbp->p_val2; + p_val4 = thbp->p_val4; + p_val7 = thbp->p_val7; + theta_00 = thbp->theta_00; + + exp3ij = exp( -p_val3 * pow( BOA_ij, p_val4 ) ); + f7_ij = 1.0 - exp3ij; + Cf7ij = p_val3 * p_val4 * pow( BOA_ij, p_val4 - 1.0 ) * exp3ij; + + exp3jk = exp( -p_val3 * pow( BOA_jk, p_val4 ) ); + f7_jk = 1.0 - exp3jk; + Cf7jk = p_val3 * p_val4 * pow( BOA_jk, p_val4 - 1.0 ) * exp3jk; + + expval7 = exp( -p_val7 * workspace->Delta_boc[j] ); + trm8 = 1.0 + expval6 + expval7; + f8_Dj = p_val5 - ( (p_val5 - 1.0) * (2.0 + expval6) / trm8 ); + Cf8j = ( (1.0 - p_val5) / SQR(trm8) ) * + ( p_val6 * expval6 * trm8 - + (2.0 + expval6) * ( p_val6*expval6 - p_val7*expval7 ) ); + + theta_0 = 180.0 - theta_00 * (1.0 - + exp(-p_val10 * (2.0 - SBO2))); + theta_0 = DEG2RAD( theta_0 ); + + expval2theta = exp( -p_val2 * SQR(theta_0 - theta) ); + if( p_val1 >= 0 ) + expval12theta = p_val1 * (1.0 - expval2theta); + else // To avoid linear Me-H-Me angles (6/6/06) + expval12theta = p_val1 * -expval2theta; + + CEval1 = Cf7ij * f7_jk * f8_Dj * expval12theta; + CEval2 = Cf7jk * f7_ij * f8_Dj * expval12theta; + CEval3 = Cf8j * f7_ij * f7_jk * expval12theta; + CEval4 = -2.0 * p_val1 * p_val2 * f7_ij * f7_jk * f8_Dj * + expval2theta * (theta_0 - theta); + + Ctheta_0 = p_val10 * DEG2RAD(theta_00) * + exp( -p_val10 * (2.0 - SBO2) ); + + CEval5 = -CEval4 * Ctheta_0 * CSBO2; + CEval6 = CEval5 * dSBO1; + CEval7 = CEval5 * dSBO2; + CEval8 = -CEval4 / sin_theta; + + data->my_en.e_ang += e_ang = + f7_ij * f7_jk * f8_Dj * expval12theta; + /* END ANGLE ENERGY*/ + + + /* PENALTY ENERGY */ + p_pen1 = thbp->p_pen1; + p_pen2 = system->reax_param.gp.l[19]; + p_pen3 = system->reax_param.gp.l[20]; + p_pen4 = system->reax_param.gp.l[21]; + + exp_pen2ij = exp( -p_pen2 * SQR( BOA_ij - 2.0 ) ); + exp_pen2jk = exp( -p_pen2 * SQR( BOA_jk - 2.0 ) ); + exp_pen3 = exp( -p_pen3 * workspace->Delta[j] ); + exp_pen4 = exp( p_pen4 * workspace->Delta[j] ); + trm_pen34 = 1.0 + exp_pen3 + exp_pen4; + f9_Dj = ( 2.0 + exp_pen3 ) / trm_pen34; + Cf9j = ( -p_pen3 * exp_pen3 * trm_pen34 - + (2.0 + exp_pen3) * ( -p_pen3 * exp_pen3 + + p_pen4 * exp_pen4 ) ) / + SQR( trm_pen34 ); + + data->my_en.e_pen += e_pen = + p_pen1 * f9_Dj * exp_pen2ij * exp_pen2jk; + + CEpen1 = e_pen * Cf9j / f9_Dj; + temp = -2.0 * p_pen2 * e_pen; + CEpen2 = temp * (BOA_ij - 2.0); + CEpen3 = temp * (BOA_jk - 2.0); + /* END PENALTY ENERGY */ + + + /* COALITION ENERGY */ + p_coa1 = thbp->p_coa1; + p_coa2 = system->reax_param.gp.l[2]; + p_coa3 = system->reax_param.gp.l[38]; + p_coa4 = system->reax_param.gp.l[30]; + + exp_coa2 = exp( p_coa2 * workspace->Delta_boc[j] ); + data->my_en.e_coa += e_coa = + p_coa1 / (1. + exp_coa2) * + exp( -p_coa3 * SQR(workspace->total_bond_order[i]-BOA_ij) ) * + exp( -p_coa3 * SQR(workspace->total_bond_order[k]-BOA_jk) ) * + exp( -p_coa4 * SQR(BOA_ij - 1.5) ) * + exp( -p_coa4 * SQR(BOA_jk - 1.5) ); + + CEcoa1 = -2 * p_coa4 * (BOA_ij - 1.5) * e_coa; + CEcoa2 = -2 * p_coa4 * (BOA_jk - 1.5) * e_coa; + CEcoa3 = -p_coa2 * exp_coa2 * e_coa / (1 + exp_coa2); + CEcoa4 = -2 * p_coa3 * + (workspace->total_bond_order[i]-BOA_ij) * e_coa; + CEcoa5 = -2 * p_coa3 * + (workspace->total_bond_order[k]-BOA_jk) * e_coa; + /* END COALITION ENERGY */ + + /* FORCES */ + bo_ij->Cdbo += (CEval1 + CEpen2 + (CEcoa1 - CEcoa4)); + bo_jk->Cdbo += (CEval2 + CEpen3 + (CEcoa2 - CEcoa5)); + workspace->CdDelta[j] += ((CEval3 + CEval7) + CEpen1 + CEcoa3); + workspace->CdDelta[i] += CEcoa4; + workspace->CdDelta[k] += CEcoa5; + + for( t = start_j; t < end_j; ++t ) { + pbond_jt = &( bonds->select.bond_list[t] ); + bo_jt = &(pbond_jt->bo_data); + temp_bo_jt = bo_jt->BO; + temp = CUBE( temp_bo_jt ); + pBOjt7 = temp * temp * temp_bo_jt; + + // fprintf( out_control->eval, "%6d%12.8f\n", + // workspace->reverse_map[bonds->select.bond_list[t].nbr], + // (CEval6 * pBOjt7) ); + + bo_jt->Cdbo += (CEval6 * pBOjt7); + bo_jt->Cdbopi += CEval5; + bo_jt->Cdbopi2 += CEval5; + } + + + if( control->virial == 0 ) { + rvec_ScaledAdd( workspace->f[i], CEval8, p_ijk->dcos_di ); + rvec_ScaledAdd( workspace->f[j], CEval8, p_ijk->dcos_dj ); + rvec_ScaledAdd( workspace->f[k], CEval8, p_ijk->dcos_dk ); + } + else { + /* terms not related to bond order derivatives are + added directly into forces and pressure vector/tensor */ + rvec_Scale( force, CEval8, p_ijk->dcos_di ); + rvec_Add( workspace->f[i], force ); + rvec_iMultiply( ext_press, pbond_ij->rel_box, force ); + rvec_Add( data->my_ext_press, ext_press ); + + rvec_ScaledAdd( workspace->f[j], CEval8, p_ijk->dcos_dj ); + + rvec_Scale( force, CEval8, p_ijk->dcos_dk ); + rvec_Add( workspace->f[k], force ); + rvec_iMultiply( ext_press, pbond_jk->rel_box, force ); + rvec_Add( data->my_ext_press, ext_press ); + } + +#ifdef TEST_ENERGY + /*fprintf( out_control->eval, "%12.8f%12.8f%12.8f%12.8f\n", + p_val3, p_val4, BOA_ij, BOA_jk ); + fprintf(out_control->eval, "%13.8f%13.8f%13.8f%13.8f%13.8f\n", + workspace->Delta_e[j], workspace->vlpex[j], + dSBO1, dSBO2, vlpadj ); + fprintf( out_control->eval, "%12.8f%12.8f%12.8f%12.8f\n", + f7_ij, f7_jk, f8_Dj, expval12theta ); + fprintf( out_control->eval, + "%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f\n", + CEval1, CEval2, CEval3, CEval4, + CEval5, CEval6, CEval7, CEval8 ); + + fprintf( out_control->eval, + "%12.8f%12.8f%12.8f\n%12.8f%12.8f%12.8f\n%12.8f%12.8f%12.8f\n", + p_ijk->dcos_di[0]/sin_theta, p_ijk->dcos_di[1]/sin_theta, + p_ijk->dcos_di[2]/sin_theta, + p_ijk->dcos_dj[0]/sin_theta, p_ijk->dcos_dj[1]/sin_theta, + p_ijk->dcos_dj[2]/sin_theta, + p_ijk->dcos_dk[0]/sin_theta, p_ijk->dcos_dk[1]/sin_theta, + p_ijk->dcos_dk[2]/sin_theta); + + fprintf( out_control->eval, + "%6d%6d%6d%15.8f%15.8f\n", + system->my_atoms[i].orig_id, + system->my_atoms[j].orig_id, + system->my_atoms[k].orig_id, + RAD2DEG(theta), e_ang );*/ + + fprintf( out_control->eval, + //"%6d%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e\n", + "%6d%6d%6d%12.4f%12.4f%12.4f%12.4f%12.4f%12.4f\n", + system->my_atoms[i].orig_id, + system->my_atoms[j].orig_id, + system->my_atoms[k].orig_id, + RAD2DEG(theta), theta_0, BOA_ij, BOA_jk, + e_ang, data->my_en.e_ang ); + + fprintf( out_control->epen, + //"%6d%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e\n", + "%6d%6d%6d%12.4f%12.4f%12.4f%12.4f%12.4f\n", + system->my_atoms[i].orig_id, + system->my_atoms[j].orig_id, + system->my_atoms[k].orig_id, + RAD2DEG(theta), BOA_ij, BOA_jk, e_pen, + data->my_en.e_pen ); + + fprintf( out_control->ecoa, + //"%6d%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e\n", + "%6d%6d%6d%12.4f%12.4f%12.4f%12.4f%12.4f\n", + system->my_atoms[i].orig_id, + system->my_atoms[j].orig_id, + system->my_atoms[k].orig_id, + RAD2DEG(theta), BOA_ij, BOA_jk, + e_coa, data->my_en.e_coa ); +#endif + +#ifdef TEST_FORCES /* angle forces */ + Add_dBO( system, lists, j, pi, CEval1, workspace->f_ang ); + Add_dBO( system, lists, j, pk, CEval2, workspace->f_ang ); + Add_dDelta( system, lists, j, + CEval3 + CEval7, workspace->f_ang ); + + for( t = start_j; t < end_j; ++t ) { + pbond_jt = &( bonds->select.bond_list[t] ); + bo_jt = &(pbond_jt->bo_data); + temp_bo_jt = bo_jt->BO; + temp = CUBE( temp_bo_jt ); + pBOjt7 = temp * temp * temp_bo_jt; + + Add_dBO( system, lists, j, t, pBOjt7 * CEval6, + workspace->f_ang ); + Add_dBOpinpi2( system, lists, j, t, CEval5, CEval5, + workspace->f_ang, workspace->f_ang ); + } + + rvec_ScaledAdd( workspace->f_ang[i], CEval8, p_ijk->dcos_di ); + rvec_ScaledAdd( workspace->f_ang[j], CEval8, p_ijk->dcos_dj ); + rvec_ScaledAdd( workspace->f_ang[k], CEval8, p_ijk->dcos_dk ); + /* end angle forces */ + + /* penalty forces */ + Add_dDelta( system, lists, j, CEpen1, workspace->f_pen ); + Add_dBO( system, lists, j, pi, CEpen2, workspace->f_pen ); + Add_dBO( system, lists, j, pk, CEpen3, workspace->f_pen ); + /* end penalty forces */ + + /* coalition forces */ + Add_dBO( system, lists, j, pi, CEcoa1 - CEcoa4, + workspace->f_coa ); + Add_dBO( system, lists, j, pk, CEcoa2 - CEcoa5, + workspace->f_coa ); + Add_dDelta( system, lists, j, CEcoa3, workspace->f_coa ); + Add_dDelta( system, lists, i, CEcoa4, workspace->f_coa ); + Add_dDelta( system, lists, k, CEcoa5, workspace->f_coa ); + /* end coalition forces */ +#endif + } + } + } + } + } + + Set_End_Index(pi, num_thb_intrs, thb_intrs ); + } + } + + if( num_thb_intrs >= thb_intrs->num_intrs * DANGER_ZONE ) { + workspace->realloc.num_3body = num_thb_intrs; + if( num_thb_intrs > thb_intrs->num_intrs ) { + fprintf( stderr, "step%d-ran out of space on angle_list: top=%d, max=%d", + data->step, num_thb_intrs, thb_intrs->num_intrs ); + MPI_Abort( MPI_COMM_WORLD, INSUFFICIENT_MEMORY ); + } + } + //fprintf( stderr,"%d: Number of angle interactions: %d\n", + // data->step, num_thb_intrs ); + +#if defined(DEBUG) + fprintf( stderr, "Number of angle interactions: %d\n", num_thb_intrs ); + fprintf( stderr, + "Angle Energy: %g\t Penalty Energy: %g\t Coalition Energy: %g\t\n", + data->my_en.e_ang, data->my_en.e_pen, data->my_en.e_coa ); + + fprintf( stderr, "3body: ext_press (%12.6f %12.6f %12.6f)\n", + data->ext_press[0], data->ext_press[1], data->ext_press[2] ); +#endif +} diff --git a/src/USER-REAXC/reaxc_valence_angles.h b/src/USER-REAXC/reaxc_valence_angles.h new file mode 100644 index 0000000000..ac27db483d --- /dev/null +++ b/src/USER-REAXC/reaxc_valence_angles.h @@ -0,0 +1,34 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __VALENCE_ANGLES_H_ +#define __VALENCE_ANGLES_H_ + +#include "reaxc_types.h" + +void Valence_Angles( reax_system*, control_params*, simulation_data*, + storage*, reax_list**, output_controls* ); + +void Calculate_Theta( rvec, real, rvec, real, real*, real* ); + +void Calculate_dCos_Theta( rvec, real, rvec, real, rvec*, rvec*, rvec* ); + +#endif diff --git a/src/USER-REAXC/reaxc_vector.cpp b/src/USER-REAXC/reaxc_vector.cpp new file mode 100644 index 0000000000..77feddf9dd --- /dev/null +++ b/src/USER-REAXC/reaxc_vector.cpp @@ -0,0 +1,518 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#include "reaxc_types.h" +#if defined(PURE_REAX) +#include "vector.h" +#include "random.h" +#elif defined(LAMMPS_REAX) +#include "reaxc_vector.h" +#endif + +int Vector_isZero( real* v, int k ) +{ + for( --k; k>=0; --k ) + if( fabs( v[k] ) > ALMOST_ZERO ) + return 0; + + return 1; +} + + +void Vector_MakeZero( real *v, int k ) +{ + for( --k; k>=0; --k ) + v[k] = 0; +} + + +void Vector_Copy( real* dest, real* v, int k ) +{ + for( --k; k>=0; --k ) + dest[k] = v[k]; +} + + +void Vector_Scale( real* dest, real c, real* v, int k ) +{ + for( --k; k>=0; --k ) + dest[k] = c * v[k]; +} + + +void Vector_Sum( real* dest, real c, real* v, real d, real* y, int k ) +{ + for( --k; k>=0; --k ) + dest[k] = c * v[k] + d * y[k]; +} + + +void Vector_Add( real* dest, real c, real* v, int k ) +{ + for( --k; k>=0; --k ) + dest[k] += c * v[k]; +} + + +real Dot( real* v1, real* v2, int k ) +{ + real ret = 0; + + for( --k; k>=0; --k ) + ret += v1[k] * v2[k]; + + return ret; +} + + +real Norm( real* v1, int k ) +{ + real ret = 0; + + for( --k; k>=0; --k ) + ret += SQR( v1[k] ); + + return sqrt( ret ); +} + + +void Vector_Print( FILE *fout, char *vname, real *v, int k ) +{ + int i; + + fprintf( fout, "%s:", vname ); + for( i = 0; i < k; ++i ) + fprintf( fout, "%24.15e\n", v[i] ); + fprintf( fout, "\n" ); +} + + +void rvec_Copy( rvec dest, rvec src ) +{ + dest[0] = src[0], dest[1] = src[1], dest[2] = src[2]; +} + +void rvec_Scale( rvec ret, real c, rvec v ) +{ + ret[0] = c * v[0], ret[1] = c * v[1], ret[2] = c * v[2]; +} + + +void rvec_Add( rvec ret, rvec v ) +{ + ret[0] += v[0], ret[1] += v[1], ret[2] += v[2]; +} + + +void rvec_ScaledAdd( rvec ret, real c, rvec v ) +{ + ret[0] += c * v[0], ret[1] += c * v[1], ret[2] += c * v[2]; +} + + +void rvec_Sum( rvec ret, rvec v1 ,rvec v2 ) +{ + ret[0] = v1[0] + v2[0]; + ret[1] = v1[1] + v2[1]; + ret[2] = v1[2] + v2[2]; +} + + +void rvec_ScaledSum( rvec ret, real c1, rvec v1 ,real c2, rvec v2 ) +{ + ret[0] = c1 * v1[0] + c2 * v2[0]; + ret[1] = c1 * v1[1] + c2 * v2[1]; + ret[2] = c1 * v1[2] + c2 * v2[2]; +} + + +real rvec_Dot( rvec v1, rvec v2 ) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + + +real rvec_ScaledDot( real c1, rvec v1, real c2, rvec v2 ) +{ + return (c1*c2) * (v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]); +} + + +void rvec_Multiply( rvec r, rvec v1, rvec v2 ) +{ + r[0] = v1[0] * v2[0]; + r[1] = v1[1] * v2[1]; + r[2] = v1[2] * v2[2]; +} + + +void rvec_iMultiply( rvec r, ivec v1, rvec v2 ) +{ + r[0] = v1[0] * v2[0]; + r[1] = v1[1] * v2[1]; + r[2] = v1[2] * v2[2]; +} + + +void rvec_Divide( rvec r, rvec v1, rvec v2 ) +{ + r[0] = v1[0] / v2[0]; + r[1] = v1[1] / v2[1]; + r[2] = v1[2] / v2[2]; +} + + +void rvec_iDivide( rvec r, rvec v1, ivec v2 ) +{ + r[0] = v1[0] / v2[0]; + r[1] = v1[1] / v2[1]; + r[2] = v1[2] / v2[2]; +} + + +void rvec_Invert( rvec r, rvec v ) +{ + r[0] = 1. / v[0]; + r[1] = 1. / v[1]; + r[2] = 1. / v[2]; +} + + +void rvec_Cross( rvec ret, rvec v1, rvec v2 ) +{ + ret[0] = v1[1] * v2[2] - v1[2] * v2[1]; + ret[1] = v1[2] * v2[0] - v1[0] * v2[2]; + ret[2] = v1[0] * v2[1] - v1[1] * v2[0]; +} + + +void rvec_OuterProduct( rtensor r, rvec v1, rvec v2 ) +{ + int i, j; + + for( i = 0; i < 3; ++i ) + for( j = 0; j < 3; ++j ) + r[i][j] = v1[i] * v2[j]; +} + + +real rvec_Norm_Sqr( rvec v ) +{ + return SQR(v[0]) + SQR(v[1]) + SQR(v[2]); +} + + +real rvec_Norm( rvec v ) +{ + return sqrt( SQR(v[0]) + SQR(v[1]) + SQR(v[2]) ); +} + + +int rvec_isZero( rvec v ) +{ + if( fabs(v[0]) > ALMOST_ZERO || + fabs(v[1]) > ALMOST_ZERO || + fabs(v[2]) > ALMOST_ZERO ) + return 0; + return 1; +} + + +void rvec_MakeZero( rvec v ) +{ +// v[0] = v[1] = v[2] = 0.0000000000000; + v[0] = v[1] = v[2] = 0.000000000000000e+00; +} + + +#if defined(PURE_REAX) +void rvec_Random( rvec v ) +{ + v[0] = Random(2.0)-1.0; + v[1] = Random(2.0)-1.0; + v[2] = Random(2.0)-1.0; +} +#endif + + +void rtensor_Multiply( rtensor ret, rtensor m1, rtensor m2 ) +{ + int i, j, k; + rtensor temp; + + // check if the result matrix is the same as one of m1, m2. + // if so, we cannot modify the contents of m1 or m2, so + // we have to use a temp matrix. + if( ret == m1 || ret == m2 ) + { + for( i = 0; i < 3; ++i ) + for( j = 0; j < 3; ++j ) + { + temp[i][j] = 0; + for( k = 0; k < 3; ++k ) + temp[i][j] += m1[i][k] * m2[k][j]; + } + + for( i = 0; i < 3; ++i ) + for( j = 0; j < 3; ++j ) + ret[i][j] = temp[i][j]; + } + else + { + for( i = 0; i < 3; ++i ) + for( j = 0; j < 3; ++j ) + { + ret[i][j] = 0; + for( k = 0; k < 3; ++k ) + ret[i][j] += m1[i][k] * m2[k][j]; + } + } +} + + +void rtensor_MatVec( rvec ret, rtensor m, rvec v ) +{ + int i; + rvec temp; + + // if ret is the same vector as v, we cannot modify the + // contents of v until all computation is finished. + if( ret == v ) + { + for( i = 0; i < 3; ++i ) + temp[i] = m[i][0] * v[0] + m[i][1] * v[1] + m[i][2] * v[2]; + + for( i = 0; i < 3; ++i ) + ret[i] = temp[i]; + } + else + { + for( i = 0; i < 3; ++i ) + ret[i] = m[i][0] * v[0] + m[i][1] * v[1] + m[i][2] * v[2]; + } +} + + +void rtensor_Scale( rtensor ret, real c, rtensor m ) +{ + int i, j; + + for( i = 0; i < 3; ++i ) + for( j = 0; j < 3; ++j ) + ret[i][j] = c * m[i][j]; +} + + +void rtensor_Add( rtensor ret, rtensor t ) +{ + int i, j; + + for( i = 0; i < 3; ++i ) + for( j = 0; j < 3; ++j ) + ret[i][j] += t[i][j]; +} + + +void rtensor_ScaledAdd( rtensor ret, real c, rtensor t ) +{ + int i, j; + + for( i = 0; i < 3; ++i ) + for( j = 0; j < 3; ++j ) + ret[i][j] += c * t[i][j]; +} + + +void rtensor_Sum( rtensor ret, rtensor t1, rtensor t2 ) +{ + int i, j; + + for( i = 0; i < 3; ++i ) + for( j = 0; j < 3; ++j ) + ret[i][j] = t1[i][j] + t2[i][j]; +} + + +void rtensor_ScaledSum( rtensor ret, real c1, rtensor t1, + real c2, rtensor t2 ) +{ + int i, j; + + for( i = 0; i < 3; ++i ) + for( j = 0; j < 3; ++j ) + ret[i][j] = c1 * t1[i][j] + c2 * t2[i][j]; +} + + +void rtensor_Copy( rtensor ret, rtensor t ) +{ + int i, j; + + for( i = 0; i < 3; ++i ) + for( j = 0; j < 3; ++j ) + ret[i][j] = t[i][j]; +} + + +void rtensor_Identity( rtensor t ) +{ + t[0][0] = t[1][1] = t[2][2] = 1; + t[0][1] = t[0][2] = t[1][0] = t[1][2] = t[2][0] = t[2][1] = 0; +} + + +void rtensor_MakeZero( rtensor t ) +{ + t[0][0] = t[0][1] = t[0][2] = 0; + t[1][0] = t[1][1] = t[1][2] = 0; + t[2][0] = t[2][1] = t[2][2] = 0; +} + + +void rtensor_Transpose( rtensor ret, rtensor t ) +{ + ret[0][0] = t[0][0], ret[1][1] = t[1][1], ret[2][2] = t[2][2]; + ret[0][1] = t[1][0], ret[0][2] = t[2][0]; + ret[1][0] = t[0][1], ret[1][2] = t[2][1]; + ret[2][0] = t[0][2], ret[2][1] = t[1][2]; +} + + +real rtensor_Det( rtensor t ) +{ + return ( t[0][0] * (t[1][1] * t[2][2] - t[1][2] * t[2][1] ) + + t[0][1] * (t[1][2] * t[2][0] - t[1][0] * t[2][2] ) + + t[0][2] * (t[1][0] * t[2][1] - t[1][1] * t[2][0] ) ); +} + + +real rtensor_Trace( rtensor t ) +{ + return (t[0][0] + t[1][1] + t[2][2]); +} + + +void Print_rTensor(FILE* fp, rtensor t) +{ + int i, j; + + for (i=0; i < 3; i++) + { + fprintf(fp,"["); + for (j=0; j < 3; j++) + fprintf(fp,"%8.3f,\t",t[i][j]); + fprintf(fp,"]\n"); + } +} + + +void ivec_MakeZero( ivec v ) +{ + v[0] = v[1] = v[2] = 0; +} + + +void ivec_Copy( ivec dest, ivec src ) +{ + dest[0] = src[0], dest[1] = src[1], dest[2] = src[2]; +} + + +void ivec_Scale( ivec dest, real C, ivec src ) +{ + dest[0] = (int)(C * src[0]); + dest[1] = (int)(C * src[1]); + dest[2] = (int)(C * src[2]); +} + + +void ivec_rScale( ivec dest, real C, rvec src ) +{ + dest[0] = (int)(C * src[0]); + dest[1] = (int)(C * src[1]); + dest[2] = (int)(C * src[2]); +} + + +int ivec_isZero( ivec v ) +{ + if( v[0]==0 && v[1]==0 && v[2]==0 ) + return 1; + return 0; +} + + +int ivec_isEqual( ivec v1, ivec v2 ) +{ + if( v1[0]==v2[0] && v1[1]==v2[1] && v1[2]==v2[2] ) + return 1; + return 0; +} + + +void ivec_Sum( ivec dest, ivec v1, ivec v2 ) +{ + dest[0] = v1[0] + v2[0]; + dest[1] = v1[1] + v2[1]; + dest[2] = v1[2] + v2[2]; +} + + +void ivec_ScaledSum( ivec dest, int k1, ivec v1, int k2, ivec v2 ) +{ + dest[0] = k1*v1[0] + k2*v2[0]; + dest[1] = k1*v1[1] + k2*v2[1]; + dest[2] = k1*v1[2] + k2*v2[2]; +} + + +void ivec_Add( ivec dest, ivec v ) +{ + dest[0] += v[0]; + dest[1] += v[1]; + dest[2] += v[2]; +} + + +void ivec_ScaledAdd( ivec dest, int k, ivec v ) +{ + dest[0] += k * v[0]; + dest[1] += k * v[1]; + dest[2] += k * v[2]; +} + + + +void ivec_Max( ivec res, ivec v1, ivec v2 ) +{ + res[0] = MAX( v1[0], v2[0] ); + res[1] = MAX( v1[1], v2[1] ); + res[2] = MAX( v1[2], v2[2] ); +} + + +void ivec_Max3( ivec res, ivec v1, ivec v2, ivec v3 ) +{ + res[0] = MAX3( v1[0], v2[0], v3[0] ); + res[1] = MAX3( v1[1], v2[1], v3[1] ); + res[2] = MAX3( v1[2], v2[2], v3[2] ); +} + diff --git a/src/USER-REAXC/reaxc_vector.h b/src/USER-REAXC/reaxc_vector.h new file mode 100644 index 0000000000..3771406478 --- /dev/null +++ b/src/USER-REAXC/reaxc_vector.h @@ -0,0 +1,89 @@ +/*---------------------------------------------------------------------- + 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: + . + ----------------------------------------------------------------------*/ + +#ifndef __VECTOR_H_ +#define __VECTOR_H_ + +#include "reaxc_types.h" +#include "reaxc_defs.h" + +int Vector_isZero( real*, int ); +void Vector_MakeZero( real*, int ); +void Vector_Copy( real*, real*, int ); +void Vector_Scale( real*, real, real*, int ); +void Vector_Sum( real*, real, real*, real, real*, int ); +void Vector_Add( real*, real, real*, int ); +real Dot( real*, real*, int ); +real Norm( real*, int ); +void Vector_Print( FILE*, char*, real*, int ); + +void rvec_Copy( rvec, rvec ); +void rvec_Scale( rvec, real, rvec ); +void rvec_Add( rvec, rvec ); +void rvec_ScaledAdd( rvec, real, rvec ); +void rvec_Sum( rvec, rvec, rvec ); +void rvec_ScaledSum( rvec, real, rvec, real, rvec ); +real rvec_Dot( rvec, rvec ); +real rvec_ScaledDot( real, rvec, real, rvec ); +void rvec_Multiply( rvec, rvec, rvec ); +void rvec_iMultiply( rvec, ivec, rvec ); +void rvec_Divide( rvec, rvec, rvec ); +void rvec_iDivide( rvec, rvec, ivec ); +void rvec_Invert( rvec, rvec ); +void rvec_Cross( rvec, rvec, rvec ); +void rvec_OuterProduct( rtensor, rvec, rvec ); +real rvec_Norm_Sqr( rvec ); +real rvec_Norm( rvec ); +int rvec_isZero( rvec ); +void rvec_MakeZero( rvec ); +void rvec_Random( rvec ); + +void rtensor_MakeZero( rtensor ); +void rtensor_Multiply( rtensor, rtensor, rtensor ); +void rtensor_MatVec( rvec, rtensor, rvec ); +void rtensor_Scale( rtensor, real, rtensor ); +void rtensor_Add( rtensor, rtensor ); +void rtensor_ScaledAdd( rtensor, real, rtensor ); +void rtensor_Sum( rtensor, rtensor, rtensor ); +void rtensor_ScaledSum( rtensor, real, rtensor, real, rtensor ); +void rtensor_Scale( rtensor, real, rtensor ); +void rtensor_Copy( rtensor, rtensor ); +void rtensor_Identity( rtensor ); +void rtensor_Transpose( rtensor, rtensor ); +real rtensor_Det( rtensor ); +real rtensor_Trace( rtensor ); + +void Print_rTensor(FILE*,rtensor); + +int ivec_isZero( ivec ); +int ivec_isEqual( ivec, ivec ); +void ivec_MakeZero( ivec ); +void ivec_Copy( ivec, ivec ); +void ivec_Scale( ivec, real, ivec ); +void ivec_rScale( ivec, real, rvec ); +void ivec_Sum( ivec, ivec, ivec ); +void ivec_ScaledSum( ivec, int, ivec, int, ivec ); +void ivec_Add( ivec, ivec ); +void ivec_ScaledAdd( ivec, int, ivec ); +void ivec_Max( ivec, ivec, ivec ); +void ivec_Max3( ivec, ivec, ivec, ivec ); + +#endif