Merge branch 'develop' into type-labels

This commit is contained in:
Jacob Gissinger
2022-08-08 17:16:50 -04:00
committed by GitHub
4100 changed files with 378596 additions and 127634 deletions

107
src/.gitignore vendored
View File

@ -37,6 +37,12 @@
/library_mdi.h
/mdi_engine.cpp
/mdi_engine.h
/fix_mdi_aimd.cpp
/fix_mdi_aimd.h
/mdi_command.cpp
/mdi_command.h
/mdi_plugin.cpp
/mdi_plugin.h
/fix_brownian*.cpp
/fix_brownian*.h
@ -167,12 +173,20 @@
/pair_tdpd.cpp
/pair_tdpd.h
/compute_grid.cpp
/compute_grid.h
/compute_grid_local.cpp
/compute_grid_local.h
/compute_sna_atom.cpp
/compute_sna_atom.h
/compute_snad_atom.cpp
/compute_snad_atom.h
/compute_snav_atom.cpp
/compute_snav_atom.h
/compute_sna_grid.cpp
/compute_sna_grid.h
/compute_sna_grid_local.cpp
/compute_sna_grid_local.h
/compute_snap.cpp
/compute_snap.h
/openmp_snap.h
@ -254,6 +268,47 @@
/pair_mesont_tpm.cpp
/pair_mesont_tpm.h
/atom_vec_bpm_sphere.cpp
/atom_vec_bpm_sphere.h
/bond_bpm.cpp
/bond_bpm.h
/bond_bpm_rotational.cpp
/bond_bpm_rotational.h
/bond_bpm_spring.cpp
/bond_bpm_spring.h
/compute_nbond_atom.cpp
/compute_nbond_atom.h
/fix_nve_bpm_sphere.cpp
/fix_nve_bpm_sphere.h
/pair_bpm_spring.cpp
/pair_bpm_spring.h
/boundary_correction.cpp
/boundary_correction.h
/electrode_accel_interface.h
/electrode_kspace.h
/electrode_math.h
/electrode_matrix.cpp
/electrode_matrix.h
/electrode_vector.cpp
/electrode_vector.h
/ewald_electrode.cpp
/ewald_electrode.h
/fix_electrode_conp.cpp
/fix_electrode_conp.h
/fix_electrode_conq.cpp
/fix_electrode_conq.h
/fix_electrode_thermo.cpp
/fix_electrode_thermo.h
/pppm_electrode.cpp
/pppm_electrode.h
/slab_2d.cpp
/slab_2d.h
/slab_dipole.cpp
/slab_dipole.h
/wire_dipole.cpp
/wire_dipole.h
/compute_adf.cpp
/compute_adf.h
/compute_contact_atom.cpp
@ -354,8 +409,8 @@
/angle_mm3.h
/angle_quartic.cpp
/angle_quartic.h
/angle_sdk.cpp
/angle_sdk.h
/angle_spica.cpp
/angle_spica.h
/angle_table.cpp
/angle_table.h
/atom_vec_angle.cpp
@ -438,6 +493,8 @@
/compute_basal_atom.h
/compute_body_local.cpp
/compute_body_local.h
/compute_born_matrix.cpp
/compute_born_matrix.h
/compute_cnp_atom.cpp
/compute_cnp_atom.h
/compute_damage_atom.cpp
@ -460,6 +517,8 @@
/compute_fabric.h
/compute_fep.cpp
/compute_fep.h
/compute_fep_ta.cpp
/compute_fep_ta.h
/compute_force_tally.cpp
/compute_force_tally.h
/compute_gyration_shape.cpp
@ -560,6 +619,7 @@
/dihedral_table_cut.h
/dump_atom_adios.cpp
/dump_atom_adios.h
/adios_common.h
/dump_atom_gz.cpp
/dump_atom_gz.h
/dump_atom_zstd.cpp
@ -600,12 +660,15 @@
/dump_xyz_mpiio.h
/dump_xyz_zstd.cpp
/dump_xyz_zstd.h
/dump_yaml.cpp
/dump_yaml.h
/dynamical_matrix.cpp
/dynamical_matrix.h
/ewald.cpp
/ewald.h
/ewald_cg.cpp
/ewald_cg.h
/ewald_const.h
/ewald_dipole.cpp
/ewald_dipole.h
/ewald_dipole_spin.cpp
@ -650,6 +713,8 @@
/fix_client_md.h
/fix_cmap.cpp
/fix_cmap.h
/fix_damping_cundall.cpp
/fix_damping_cundall.h
/fix_dpd_energy.cpp
/fix_dpd_energy.h
/fix_electron_stopping.cpp
@ -706,6 +771,7 @@
/fix_langevin_eff.h
/fix_latte.cpp
/fix_latte.h
/latboltz_const.h
/fix_lb_fluid.cpp
/fix_lb_fluid.h
/fix_lb_momentum.cpp
@ -788,8 +854,6 @@
/fix_orient_eco.h
/fix_orient_fcc.cpp
/fix_orient_fcc.h
/fix_pair_tracker.cpp
/fix_pair_tracker.h
/fix_peri_neigh.cpp
/fix_peri_neigh.h
/fix_phonon.cpp
@ -869,6 +933,8 @@
/fix_ti_spring.h
/fix_tune_kspace.cpp
/fix_tune_kspace.h
/fix_viscous_sphere.cpp
/fix_viscous_sphere.h
/fix_wall_body_polygon.cpp
/fix_wall_body_polygon.h
/fix_wall_body_polyhedron.cpp
@ -924,7 +990,7 @@
/improper_umbrella.h
/interlayer_taper.h
/kissfft.h
/lj_sdk_common.h
/lj_spica_common.h
/math_complex.h
/math_vector.h
/message.cpp
@ -939,6 +1005,8 @@
/neb.h
/netcdf_units.cpp
/netcdf_units.h
/pair_threebody_table.cpp
/pair_threebody_table.h
/pair_adp.cpp
/pair_adp.h
/pair_agni.cpp
@ -1074,8 +1142,12 @@
/pair_hdnnp.h
/pair_ilp_graphene_hbn.cpp
/pair_ilp_graphene_hbn.h
/pair_ilp_graphene_hbn_opt.cpp
/pair_ilp_graphene_hbn_opt.h
/pair_ilp_tmd.cpp
/pair_ilp_tmd.h
/pair_ilp_tmd_opt.cpp
/pair_ilp_tmd_opt.h
/pair_kolmogorov_crespi_full.cpp
/pair_kolmogorov_crespi_full.h
/pair_kolmogorov_crespi_z.cpp
@ -1146,12 +1218,12 @@
/pair_lj_long_tip4p_long.h
/pair_lj_cut_tgpu.cpp
/pair_lj_cut_tgpu.h
/pair_lj_sdk.cpp
/pair_lj_sdk.h
/pair_lj_sdk_coul_long.cpp
/pair_lj_sdk_coul_long.h
/pair_lj_sdk_coul_msm.cpp
/pair_lj_sdk_coul_msm.h
/pair_lj_spica.cpp
/pair_lj_spica.h
/pair_lj_spica_coul_long.cpp
/pair_lj_spica_coul_long.h
/pair_lj_spica_coul_msm.cpp
/pair_lj_spica_coul_msm.h
/pair_lj_sf_dipole_sf.cpp
/pair_lj_sf_dipole_sf.h
/pair_lj_switch3_coulgauss_long.cpp
@ -1211,6 +1283,8 @@
/pair_resquared.h
/pair_saip_metal.cpp
/pair_saip_metal.h
/pair_saip_metal_opt.cpp
/pair_saip_metal_opt.h
/pair_sdpd_taitwater_isothermal.cpp
/pair_sdpd_taitwater_isothermal.h
/pair_sph_heatconduction.cpp
@ -1227,6 +1301,8 @@
/pair_sph_taitwater_morris.h
/pair_sw.cpp
/pair_sw.h
/pair_sw_angle_table.cpp
/pair_sw_angle_table.h
/pair_sw_mod.cpp
/pair_sw_mod.h
/pair_tersoff.cpp
@ -1446,6 +1522,8 @@
/fix_smd_wall_surface.h
/fix_srp.cpp
/fix_srp.h
/fix_srp_react.cpp
/fix_srp_react.h
/fix_tfmc.cpp
/fix_tfmc.h
/fix_ttm.cpp
@ -1486,6 +1564,8 @@
/pair_smd_ulsph.h
/pair_srp.cpp
/pair_srp.h
/pair_srp_react.cpp
/pair_srp_react.h
/pair_thole.cpp
/pair_thole.h
/pair_buck_mdf.cpp
@ -1516,7 +1596,12 @@
/pair_mgpt.h
/pair_morse_smooth_linear.cpp
/pair_morse_smooth_linear.h
/pair_smatb.cpp
/pair_smatb.h
/pair_smatb_single.cpp
/pair_smatb_single.h
/pair_smtbq.cpp
/pair_smtbq.h
/pair_vashishta*.cpp
/pair_vashishta*.h

View File

@ -31,17 +31,17 @@ done
if (test $1 = 1) then
CONFIGSCRIPT=none
if ( test `which adios2-config 2>> /dev/null` ) then
if ( type adios2-config > /dev/null 2>&1 ) then
CONFIGSCRIPT=adios2-config
elif ( ! test -z "$ADIOS2_DIR" ) then
if ( test `which $ADIOS2_DIR/bin/adios2-config` ) then
if ( type $ADIOS2_DIR/bin/adios2-config > /dev/null 2>&1 ) then
CONFIGSCRIPT=$ADIOS2_DIR/bin/adios2-config
else
echo "ERROR: ADIOS2_DIR environment variable is set but" \
"\$ADIOS2_DIR/bin/adios2-config does not exist"
fi
elif ( ! test -z "$ADIOS_DIR" ) then
if ( test `which $ADIOS_DIR/bin/adios2-config` ) then
if ( type $ADIOS_DIR/bin/adios2-config > /dev/null 2>&1 ) then
CONFIGSCRIPT=$ADIOS_DIR/bin/adios2-config
else
echo "ERROR: ADIOS_DIR environment variable is set but" \

39
src/ADIOS/adios_common.h Normal file
View File

@ -0,0 +1,39 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, 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.
Contributed by Norbert Podhorszki (Oak Ridge National Laboratory)
------------------------------------------------------------------------- */
#ifndef LMP_ADIOS_COMMON_H
#define LMP_ADIOS_COMMON_H
// common definitions for all ADIOS package classes
static const char default_config[] = "<?xml version=\"1.0\"?>\n"
"<adios-config>\n"
" <io name=\"atom\">\n"
" <engine type=\"BP4\">\n"
" <parameter key=\"substreams\" value=\"1\"/>\n"
" </engine>\n"
" </io>\n"
" <io name=\"custom\">\n"
" <engine type=\"BP4\">\n"
" <parameter key=\"substreams\" value=\"1\"/>\n"
" </engine>\n"
" </io>\n"
" <io name=\"read_dump\">\n"
" <engine type=\"BP4\">\n"
" </engine>\n"
" </io>\n"
"</adios-config>\n";
#endif

View File

@ -1,4 +1,3 @@
// clang-format off
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, Sandia National Laboratories
@ -24,333 +23,294 @@
#include "memory.h"
#include "universe.h"
#include "update.h"
#include <cstring>
#include "adios2.h"
#include "adios_common.h"
using namespace LAMMPS_NS;
#define MAX_TEXT_HEADER_SIZE 4096
#define DUMP_BUF_CHUNK_SIZE 16384
#define DUMP_BUF_INCREMENT_SIZE 4096
namespace LAMMPS_NS {
class DumpAtomADIOSInternal {
namespace LAMMPS_NS
{
class DumpAtomADIOSInternal
{
public:
DumpAtomADIOSInternal() = default;
~DumpAtomADIOSInternal() = default;
public:
DumpAtomADIOSInternal() {};
~DumpAtomADIOSInternal() = default;
// name of adios group, referrable in adios2_config.xml
const std::string ioName = "atom";
adios2::ADIOS *ad = nullptr; // adios object
adios2::IO io; // adios group of variables and attributes in this dump
adios2::Engine fh; // adios file/stream handle object
// one ADIOS output variable we need to change every step
adios2::Variable<double> varAtoms;
// name of adios group, referrable in adios2_config.xml
const std::string ioName = "atom";
adios2::ADIOS *ad = nullptr; // adios object
adios2::IO io; // adios group of variables and attributes in this dump
adios2::Engine fh; // adios file/stream handle object
// one ADIOS output variable we need to change every step
adios2::Variable<double> varAtoms;
};
} // namespace LAMMPS_NS
} // namespace LAMMPS_NS
/* ---------------------------------------------------------------------- */
DumpAtomADIOS::DumpAtomADIOS(LAMMPS *lmp, int narg, char **arg)
: DumpAtom(lmp, narg, arg)
DumpAtomADIOS::DumpAtomADIOS(LAMMPS *lmp, int narg, char **arg) : DumpAtom(lmp, narg, arg)
{
internal = new DumpAtomADIOSInternal();
try {
internal->ad =
new adios2::ADIOS("adios2_config.xml", world, adios2::DebugON);
} catch (std::ios_base::failure &e) {
char str[256];
snprintf(str, sizeof(str), "ADIOS initialization failed with error: %s",
e.what());
error->one(FLERR, str);
}
// create a default adios2_config.xml if it doesn't exist yet.
FILE *cfgfp = fopen("adios2_config.xml", "r");
if (!cfgfp) {
cfgfp = fopen("adios2_config.xml", "w");
if (cfgfp) fputs(default_config, cfgfp);
}
if (cfgfp) fclose(cfgfp);
internal = new DumpAtomADIOSInternal();
try {
internal->ad = new adios2::ADIOS("adios2_config.xml", world, adios2::DebugON);
} catch (std::ios_base::failure &e) {
error->all(FLERR, "ADIOS initialization failed with error: {}", e.what());
}
}
/* ---------------------------------------------------------------------- */
DumpAtomADIOS::~DumpAtomADIOS()
{
if (internal->fh) {
internal->fh.Close();
}
delete internal->ad;
delete internal;
if (internal->fh) internal->fh.Close();
delete internal->ad;
delete internal;
}
/* ---------------------------------------------------------------------- */
void DumpAtomADIOS::openfile()
{
if (multifile) {
// if one file per timestep, replace '*' with current timestep
char *filestar = strdup(filename);
char *filecurrent = new char[strlen(filestar) + 16];
char *ptr = strchr(filestar, '*');
*ptr = '\0';
if (padflag == 0)
snprintf(filecurrent, sizeof(filecurrent), "%s" BIGINT_FORMAT "%s",
filestar, update->ntimestep, ptr + 1);
else {
char bif[8], pad[16];
strcpy(bif, BIGINT_FORMAT);
snprintf(pad, sizeof(pad), "%%s%%0%d%s%%s", padflag, &bif[1]);
snprintf(filecurrent, sizeof(filecurrent), pad, filestar,
update->ntimestep, ptr + 1);
}
internal->fh =
internal->io.Open(filecurrent, adios2::Mode::Write, world);
if (!internal->fh) {
char str[128];
snprintf(str, sizeof(str), "Cannot open dump file %s", filecurrent);
error->one(FLERR, str);
}
free(filestar);
delete[] filecurrent;
} else {
if (!singlefile_opened) {
internal->fh =
internal->io.Open(filename, adios2::Mode::Write, world);
if (!internal->fh) {
char str[128];
snprintf(str, sizeof(str), "Cannot open dump file %s",
filename);
error->one(FLERR, str);
}
singlefile_opened = 1;
}
if (multifile) {
// if one file per timestep, replace '*' with current timestep
auto filecurrent = utils::star_subst(filename, update->ntimestep, padflag);
internal->fh = internal->io.Open(filecurrent, adios2::Mode::Write, world);
if (!internal->fh) error->one(FLERR, "Cannot open dump file {}", filecurrent);
} else {
if (!singlefile_opened) {
internal->fh = internal->io.Open(filename, adios2::Mode::Write, world);
if (!internal->fh) error->one(FLERR, "Cannot open dump file {}", filename);
singlefile_opened = 1;
}
}
}
/* ---------------------------------------------------------------------- */
void DumpAtomADIOS::write()
{
if (domain->triclinic == 0) {
boxxlo = domain->boxlo[0];
boxxhi = domain->boxhi[0];
boxylo = domain->boxlo[1];
boxyhi = domain->boxhi[1];
boxzlo = domain->boxlo[2];
boxzhi = domain->boxhi[2];
} else {
boxxlo = domain->boxlo_bound[0];
boxxhi = domain->boxhi_bound[0];
boxylo = domain->boxlo_bound[1];
boxyhi = domain->boxhi_bound[1];
boxzlo = domain->boxlo_bound[2];
boxzhi = domain->boxhi_bound[2];
boxxy = domain->xy;
boxxz = domain->xz;
boxyz = domain->yz;
if (domain->triclinic == 0) {
boxxlo = domain->boxlo[0];
boxxhi = domain->boxhi[0];
boxylo = domain->boxlo[1];
boxyhi = domain->boxhi[1];
boxzlo = domain->boxlo[2];
boxzhi = domain->boxhi[2];
} else {
boxxlo = domain->boxlo_bound[0];
boxxhi = domain->boxhi_bound[0];
boxylo = domain->boxlo_bound[1];
boxyhi = domain->boxhi_bound[1];
boxzlo = domain->boxlo_bound[2];
boxzhi = domain->boxhi_bound[2];
boxxy = domain->xy;
boxxz = domain->xz;
boxyz = domain->yz;
}
// nme = # of dump lines this proc contributes to dump
nme = count();
// ntotal = total # of atoms in snapshot
// atomOffset = sum of # of atoms up to this proc (exclusive prefix sum)
bigint bnme = nme;
MPI_Allreduce(&bnme, &ntotal, 1, MPI_LMP_BIGINT, MPI_SUM, world);
bigint atomOffset; // sum of all atoms on processes 0..me-1
MPI_Scan(&bnme, &atomOffset, 1, MPI_LMP_BIGINT, MPI_SUM, world);
atomOffset -= nme; // exclusive prefix sum needed
// Now we know the global size and the local subset size and offset
// of the atoms table
auto nAtomsGlobal = static_cast<size_t>(ntotal);
auto startRow = static_cast<size_t>(atomOffset);
auto nAtomsLocal = static_cast<size_t>(nme);
auto nColumns = static_cast<size_t>(size_one);
internal->varAtoms.SetShape({nAtomsGlobal, nColumns});
internal->varAtoms.SetSelection({{startRow, 0}, {nAtomsLocal, nColumns}});
// insure buf is sized for packing
// adios does not limit per-process data size so nme*size_one is not
// constrained to int
// if sorting on IDs also request ID list from pack()
// sort buf as needed
if (nme > maxbuf) {
maxbuf = nme;
memory->destroy(buf);
memory->create(buf, (maxbuf * size_one), "dump:buf");
}
if (sort_flag && sortcol == 0 && nme > maxids) {
maxids = nme;
memory->destroy(ids);
memory->create(ids, maxids, "dump:ids");
}
if (sort_flag && sortcol == 0)
pack(ids);
else
pack(nullptr);
if (sort_flag) sort();
openfile();
internal->fh.BeginStep();
// write info on data as scalars (by me==0)
if (me == 0) {
internal->fh.Put<uint64_t>("ntimestep", update->ntimestep);
internal->fh.Put<int>("nprocs", nprocs);
internal->fh.Put<double>("boxxlo", boxxlo);
internal->fh.Put<double>("boxxhi", boxxhi);
internal->fh.Put<double>("boxylo", boxylo);
internal->fh.Put<double>("boxyhi", boxyhi);
internal->fh.Put<double>("boxzlo", boxzlo);
internal->fh.Put<double>("boxzhi", boxzhi);
if (domain->triclinic) {
internal->fh.Put<double>("boxxy", boxxy);
internal->fh.Put<double>("boxxz", boxxz);
internal->fh.Put<double>("boxyz", boxyz);
}
}
// Everyone needs to write scalar variables that are used as dimensions and
// offsets of arrays
internal->fh.Put<uint64_t>("natoms", ntotal);
internal->fh.Put<int>("ncolumns", size_one);
internal->fh.Put<uint64_t>("nme", bnme);
internal->fh.Put<uint64_t>("offset", atomOffset);
// now write the atoms
internal->fh.Put<double>(internal->varAtoms, buf);
internal->fh.EndStep(); // I/O will happen now...
// nme = # of dump lines this proc contributes to dump
nme = count();
// ntotal = total # of atoms in snapshot
// atomOffset = sum of # of atoms up to this proc (exclusive prefix sum)
bigint bnme = nme;
MPI_Allreduce(&bnme, &ntotal, 1, MPI_LMP_BIGINT, MPI_SUM, world);
bigint atomOffset; // sum of all atoms on processes 0..me-1
MPI_Scan(&bnme, &atomOffset, 1, MPI_LMP_BIGINT, MPI_SUM, world);
atomOffset -= nme; // exclusive prefix sum needed
// Now we know the global size and the local subset size and offset
// of the atoms table
size_t nAtomsGlobal = static_cast<size_t>(ntotal);
size_t startRow = static_cast<size_t>(atomOffset);
size_t nAtomsLocal = static_cast<size_t>(nme);
size_t nColumns = static_cast<size_t>(size_one);
internal->varAtoms.SetShape({nAtomsGlobal, nColumns});
internal->varAtoms.SetSelection({{startRow, 0}, {nAtomsLocal, nColumns}});
// insure buf is sized for packing
// adios does not limit per-process data size so nme*size_one is not
// constrained to int
// if sorting on IDs also request ID list from pack()
// sort buf as needed
if (nme > maxbuf) {
maxbuf = nme;
memory->destroy(buf);
memory->create(buf, (maxbuf * size_one), "dump:buf");
}
if (sort_flag && sortcol == 0 && nme > maxids) {
maxids = nme;
memory->destroy(ids);
memory->create(ids, maxids, "dump:ids");
}
if (sort_flag && sortcol == 0)
pack(ids);
else
pack(nullptr);
if (sort_flag)
sort();
openfile();
internal->fh.BeginStep();
// write info on data as scalars (by me==0)
if (me == 0) {
internal->fh.Put<uint64_t>("ntimestep", update->ntimestep);
internal->fh.Put<int>("nprocs", nprocs);
internal->fh.Put<double>("boxxlo", boxxlo);
internal->fh.Put<double>("boxxhi", boxxhi);
internal->fh.Put<double>("boxylo", boxylo);
internal->fh.Put<double>("boxyhi", boxyhi);
internal->fh.Put<double>("boxzlo", boxzlo);
internal->fh.Put<double>("boxzhi", boxzhi);
if (domain->triclinic) {
internal->fh.Put<double>("boxxy", boxxy);
internal->fh.Put<double>("boxxz", boxxz);
internal->fh.Put<double>("boxyz", boxyz);
}
}
// Everyone needs to write scalar variables that are used as dimensions and
// offsets of arrays
internal->fh.Put<uint64_t>("natoms", ntotal);
internal->fh.Put<int>("ncolumns", size_one);
internal->fh.Put<uint64_t>("nme", bnme);
internal->fh.Put<uint64_t>("offset", atomOffset);
// now write the atoms
internal->fh.Put<double>(internal->varAtoms, buf);
internal->fh.EndStep(); // I/O will happen now...
if (multifile) {
internal->fh.Close();
}
if (multifile) internal->fh.Close();
}
/* ---------------------------------------------------------------------- */
void DumpAtomADIOS::init_style()
{
if (image_flag == 0)
size_one = 5;
else
size_one = 8;
if (image_flag == 0)
size_one = 5;
else
size_one = 8;
// setup boundary string
// setup boundary string
domain->boundary_string(boundstr);
domain->boundary_string(boundstr);
// remove % from filename since ADIOS always writes a global file with
// data/metadata
int len = strlen(filename);
char *ptr = strchr(filename, '%');
if (ptr) {
*ptr = '\0';
char *s = new char[len - 1];
snprintf(s, sizeof(s), "%s%s", filename, ptr + 1);
strncpy(filename, s, len);
// remove % from filename since ADIOS always writes a global file with
// data/metadata.
char *ptr = strchr(filename, '%');
if (ptr) {
while (*ptr) {
ptr[0] = ptr[1];
++ptr;
}
}
// setup column string
// setup column string
std::vector<std::string> columnNames;
std::vector<std::string> columnNames;
if (scale_flag == 0 && image_flag == 0) {
columns = (char *)"id type x y z";
columnNames = {"id", "type", "x", "y", "z"};
} else if (scale_flag == 0 && image_flag == 1) {
columns = (char *)"id type x y z ix iy iz";
columnNames = {"id", "type", "x", "y", "z", "ix", "iy", "iz"};
} else if (scale_flag == 1 && image_flag == 0) {
columns = (char *)"id type xs ys zs";
columnNames = {"id", "type", "xs", "ys", "zs"};
} else if (scale_flag == 1 && image_flag == 1) {
columns = (char *)"id type xs ys zs ix iy iz";
columnNames = {"id", "type", "xs", "ys", "zs", "ix", "iy", "iz"};
}
if (scale_flag == 0 && image_flag == 0) {
columns = (char *) "id type x y z";
columnNames = {"id", "type", "x", "y", "z"};
} else if (scale_flag == 0 && image_flag == 1) {
columns = (char *) "id type x y z ix iy iz";
columnNames = {"id", "type", "x", "y", "z", "ix", "iy", "iz"};
} else if (scale_flag == 1 && image_flag == 0) {
columns = (char *) "id type xs ys zs";
columnNames = {"id", "type", "xs", "ys", "zs"};
} else if (scale_flag == 1 && image_flag == 1) {
columns = (char *) "id type xs ys zs ix iy iz";
columnNames = {"id", "type", "xs", "ys", "zs", "ix", "iy", "iz"};
}
// setup function ptrs
for (int icol = 0; icol < (int) columnNames.size(); ++icol)
if (keyword_user[icol].size()) columnNames[icol] = keyword_user[icol];
if (scale_flag == 1 && image_flag == 0 && domain->triclinic == 0)
pack_choice = &DumpAtomADIOS::pack_scale_noimage;
else if (scale_flag == 1 && image_flag == 1 && domain->triclinic == 0)
pack_choice = &DumpAtomADIOS::pack_scale_image;
else if (scale_flag == 1 && image_flag == 0 && domain->triclinic == 1)
pack_choice = &DumpAtomADIOS::pack_scale_noimage_triclinic;
else if (scale_flag == 1 && image_flag == 1 && domain->triclinic == 1)
pack_choice = &DumpAtomADIOS::pack_scale_image_triclinic;
else if (scale_flag == 0 && image_flag == 0)
pack_choice = &DumpAtomADIOS::pack_noscale_noimage;
else if (scale_flag == 0 && image_flag == 1)
pack_choice = &DumpAtomADIOS::pack_noscale_image;
// setup function ptrs
/* Define the group of variables for the atom style here since it's a fixed
if (scale_flag == 1 && image_flag == 0 && domain->triclinic == 0)
pack_choice = &DumpAtomADIOS::pack_scale_noimage;
else if (scale_flag == 1 && image_flag == 1 && domain->triclinic == 0)
pack_choice = &DumpAtomADIOS::pack_scale_image;
else if (scale_flag == 1 && image_flag == 0 && domain->triclinic == 1)
pack_choice = &DumpAtomADIOS::pack_scale_noimage_triclinic;
else if (scale_flag == 1 && image_flag == 1 && domain->triclinic == 1)
pack_choice = &DumpAtomADIOS::pack_scale_image_triclinic;
else if (scale_flag == 0 && image_flag == 0)
pack_choice = &DumpAtomADIOS::pack_noscale_noimage;
else if (scale_flag == 0 && image_flag == 1)
pack_choice = &DumpAtomADIOS::pack_noscale_image;
/* Define the group of variables for the atom style here since it's a fixed
* set */
internal->io = internal->ad->DeclareIO(internal->ioName);
if (!internal->io.InConfigFile()) {
// if not defined by user, we can change the default settings
// BPFile is the default writer
internal->io.SetEngine("BPFile");
int num_aggregators = multiproc;
if (num_aggregators == 0)
num_aggregators = 1;
char nstreams[128];
snprintf(nstreams, sizeof(nstreams), "%d", num_aggregators);
internal->io.SetParameters({{"substreams", nstreams}});
if (me == 0 && screen)
fprintf(
screen,
"ADIOS method for %s is n-to-m (aggregation with %s writers)\n",
filename, nstreams);
}
internal->io = internal->ad->DeclareIO(internal->ioName);
if (!internal->io.InConfigFile()) {
// if not defined by user, we can change the default settings
// BPFile is the default writer
internal->io.SetEngine("BPFile");
int num_aggregators = multiproc;
if (num_aggregators == 0) num_aggregators = 1;
auto nstreams = std::to_string(num_aggregators);
internal->io.SetParameters({{"substreams", nstreams}});
if (me == 0)
utils::logmesg(lmp, "ADIOS method for {} is n-to-m (aggregation with {} writers)\n", filename,
nstreams);
}
internal->io.DefineVariable<uint64_t>("ntimestep");
internal->io.DefineVariable<uint64_t>("natoms");
internal->io.DefineVariable<uint64_t>("ntimestep");
internal->io.DefineVariable<uint64_t>("natoms");
internal->io.DefineVariable<int>("nprocs");
internal->io.DefineVariable<int>("ncolumns");
internal->io.DefineVariable<int>("nprocs");
internal->io.DefineVariable<int>("ncolumns");
internal->io.DefineVariable<double>("boxxlo");
internal->io.DefineVariable<double>("boxxhi");
internal->io.DefineVariable<double>("boxylo");
internal->io.DefineVariable<double>("boxyhi");
internal->io.DefineVariable<double>("boxzlo");
internal->io.DefineVariable<double>("boxzhi");
internal->io.DefineVariable<double>("boxxlo");
internal->io.DefineVariable<double>("boxxhi");
internal->io.DefineVariable<double>("boxylo");
internal->io.DefineVariable<double>("boxyhi");
internal->io.DefineVariable<double>("boxzlo");
internal->io.DefineVariable<double>("boxzhi");
internal->io.DefineVariable<double>("boxxy");
internal->io.DefineVariable<double>("boxxz");
internal->io.DefineVariable<double>("boxyz");
internal->io.DefineVariable<double>("boxxy");
internal->io.DefineVariable<double>("boxxz");
internal->io.DefineVariable<double>("boxyz");
internal->io.DefineAttribute<int>("triclinic", domain->triclinic);
internal->io.DefineAttribute<int>("scaled", scale_flag);
internal->io.DefineAttribute<int>("image", image_flag);
internal->io.DefineAttribute<int>("triclinic", domain->triclinic);
internal->io.DefineAttribute<int>("scaled", scale_flag);
internal->io.DefineAttribute<int>("image", image_flag);
int *boundaryptr = reinterpret_cast<int *>(domain->boundary);
internal->io.DefineAttribute<int>("boundary", boundaryptr, 6);
int *boundaryptr = reinterpret_cast<int *>(domain->boundary);
internal->io.DefineAttribute<int>("boundary", boundaryptr, 6);
size_t nColumns = static_cast<size_t>(size_one);
internal->io.DefineAttribute<std::string>("columns", columnNames.data(),
nColumns);
internal->io.DefineAttribute<std::string>("columnstr", columns);
internal->io.DefineAttribute<std::string>("boundarystr", boundstr);
internal->io.DefineAttribute<std::string>("LAMMPS/dump_style", "atom");
internal->io.DefineAttribute<std::string>("LAMMPS/version",
lmp->version);
internal->io.DefineAttribute<std::string>("LAMMPS/num_ver",
std::to_string(lmp->num_ver));
auto nColumns = static_cast<size_t>(size_one);
internal->io.DefineAttribute<std::string>("columns", columnNames.data(), nColumns);
internal->io.DefineAttribute<std::string>("columnstr", columns);
internal->io.DefineAttribute<std::string>("boundarystr", boundstr);
internal->io.DefineAttribute<std::string>("LAMMPS/dump_style", "atom");
internal->io.DefineAttribute<std::string>("LAMMPS/version", lmp->version);
internal->io.DefineAttribute<std::string>("LAMMPS/num_ver", std::to_string(lmp->num_ver));
internal->io.DefineVariable<uint64_t>(
"nme", {adios2::LocalValueDim}); // local dimension variable
internal->io.DefineVariable<uint64_t>(
"offset", {adios2::LocalValueDim}); // local dimension variable
// local dimension variables
internal->io.DefineVariable<uint64_t>("nme", {adios2::LocalValueDim});
internal->io.DefineVariable<uint64_t>("offset", {adios2::LocalValueDim});
// atom table size is not known at the moment
// it will be correctly defined at the moment of write
size_t UnknownSizeYet = 1;
internal->varAtoms = internal->io.DefineVariable<double>(
"atoms", {UnknownSizeYet, nColumns}, {UnknownSizeYet, 0},
{UnknownSizeYet, nColumns});
// atom table size is not known at the moment
// it will be correctly defined at the moment of write
size_t UnknownSizeYet = 1;
internal->varAtoms = internal->io.DefineVariable<double>(
"atoms", {UnknownSizeYet, nColumns}, {UnknownSizeYet, 0}, {UnknownSizeYet, nColumns});
}

View File

@ -44,17 +44,3 @@ class DumpAtomADIOS : public DumpAtom {
#endif
#endif
/* ERROR/WARNING messages:
E: Cannot open dump file %s
The output file for the dump command cannot be opened. Check that the
path and name are correct.
E: Too much per-proc info for dump
Number of local atoms times number of columns must fit in a 32-bit
integer for dump.
*/

View File

@ -1,4 +1,3 @@
// clang-format off
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, Sandia National Laboratories
@ -17,427 +16,320 @@
------------------------------------------------------------------------- */
#include "dump_custom_adios.h"
#include "atom.h"
#include "compute.h"
#include "domain.h"
#include "error.h"
#include "fix.h"
#include "force.h"
#include "group.h"
#include "input.h"
#include "memory.h"
#include "modify.h"
#include "region.h"
#include "universe.h"
#include "update.h"
#include "variable.h"
#include <cmath>
#include <cstring>
#include "adios2.h"
#include "adios_common.h"
using namespace LAMMPS_NS;
#define MAX_TEXT_HEADER_SIZE 4096
#define DUMP_BUF_CHUNK_SIZE 16384
#define DUMP_BUF_INCREMENT_SIZE 4096
namespace LAMMPS_NS {
class DumpCustomADIOSInternal {
enum {
ID,
MOL,
TYPE,
ELEMENT,
MASS,
X,
Y,
Z,
XS,
YS,
ZS,
XSTRI,
YSTRI,
ZSTRI,
XU,
YU,
ZU,
XUTRI,
YUTRI,
ZUTRI,
XSU,
YSU,
ZSU,
XSUTRI,
YSUTRI,
ZSUTRI,
IX,
IY,
IZ,
VX,
VY,
VZ,
FX,
FY,
FZ,
Q,
MUX,
MUY,
MUZ,
MU,
RADIUS,
DIAMETER,
OMEGAX,
OMEGAY,
OMEGAZ,
ANGMOMX,
ANGMOMY,
ANGMOMZ,
TQX,
TQY,
TQZ,
SPIN,
ERADIUS,
ERVEL,
ERFORCE,
COMPUTE,
FIX,
VARIABLE
public:
DumpCustomADIOSInternal() = default;
~DumpCustomADIOSInternal() = default;
// name of adios group, referrable in adios2_config.xml
const std::string ioName = "custom";
adios2::ADIOS *ad = nullptr; // adios object
adios2::IO io; // adios group of variables and attributes in this dump
adios2::Engine fh; // adios file/stream handle object
// one ADIOS output variable we need to change every step
adios2::Variable<double> varAtoms;
// list of column names for the atom table
// (individual list of 'columns' string)
std::vector<std::string> columnNames;
};
enum { LT, LE, GT, GE, EQ, NEQ };
enum { INT, DOUBLE, STRING, BIGINT }; // same as in DumpCustom
namespace LAMMPS_NS
{
class DumpCustomADIOSInternal
{
public:
DumpCustomADIOSInternal() {};
~DumpCustomADIOSInternal() = default;
// name of adios group, referrable in adios2_config.xml
const std::string ioName = "custom";
adios2::ADIOS *ad = nullptr; // adios object
adios2::IO io; // adios group of variables and attributes in this dump
adios2::Engine fh; // adios file/stream handle object
// one ADIOS output variable we need to change every step
adios2::Variable<double> varAtoms;
// list of column names for the atom table
// (individual list of 'columns' string)
std::vector<std::string> columnNames;
};
} // namespace LAMMPS_NS
} // namespace LAMMPS_NS
/* ---------------------------------------------------------------------- */
DumpCustomADIOS::DumpCustomADIOS(LAMMPS *lmp, int narg, char **arg)
: DumpCustom(lmp, narg, arg)
DumpCustomADIOS::DumpCustomADIOS(LAMMPS *lmp, int narg, char **arg) : DumpCustom(lmp, narg, arg)
{
internal = new DumpCustomADIOSInternal();
try {
internal->ad =
new adios2::ADIOS("adios2_config.xml", world, adios2::DebugON);
} catch (std::ios_base::failure &e) {
char str[256];
snprintf(str, sizeof(str), "ADIOS initialization failed with error: %s",
e.what());
error->one(FLERR, str);
}
// create a default adios2_config.xml if it doesn't exist yet.
FILE *cfgfp = fopen("adios2_config.xml", "r");
if (!cfgfp) {
cfgfp = fopen("adios2_config.xml", "w");
if (cfgfp) fputs(default_config, cfgfp);
}
if (cfgfp) fclose(cfgfp);
// if (screen) fprintf(screen, "DumpCustomADIOS constructor: nvariable=%d
// id_variable=%p, variables=%p, nfield=%d, earg=%p\n", nvariable,
// id_variable, variable, nfield, earg);
internal->columnNames.reserve(nfield);
for (int i = 0; i < nfield; ++i) {
internal->columnNames.push_back(earg[i]);
// if (screen) fprintf(screen, "earg[%d] = '%s'\n", i, earg[i]);
}
internal = new DumpCustomADIOSInternal();
try {
internal->ad = new adios2::ADIOS("adios2_config.xml", world, adios2::DebugON);
} catch (std::ios_base::failure &e) {
error->all(FLERR, "ADIOS initialization failed with error: {}", e.what());
}
internal->columnNames.reserve(nfield);
for (int i = 0; i < nfield; ++i) { internal->columnNames.emplace_back(earg[i]); }
}
/* ---------------------------------------------------------------------- */
DumpCustomADIOS::~DumpCustomADIOS()
{
internal->columnNames.clear();
if (internal->fh) {
internal->fh.Close();
}
delete internal->ad;
delete internal;
internal->columnNames.clear();
if (internal->fh) { internal->fh.Close(); }
delete internal->ad;
delete internal;
}
/* ---------------------------------------------------------------------- */
void DumpCustomADIOS::openfile()
{
if (multifile) {
// if one file per timestep, replace '*' with current timestep
char *filestar = strdup(filename);
char *filecurrent = new char[strlen(filestar) + 16];
char *ptr = strchr(filestar, '*');
*ptr = '\0';
if (padflag == 0)
sprintf(filecurrent, "%s" BIGINT_FORMAT "%s", filestar,
update->ntimestep, ptr + 1);
else {
char bif[8], pad[16];
strcpy(bif, BIGINT_FORMAT);
sprintf(pad, "%%s%%0%d%s%%s", padflag, &bif[1]);
sprintf(filecurrent, pad, filestar, update->ntimestep, ptr + 1);
}
internal->fh =
internal->io.Open(filecurrent, adios2::Mode::Write, world);
if (!internal->fh) {
char str[128];
sprintf(str, "Cannot open dump file %s", filecurrent);
error->one(FLERR, str);
}
free(filestar);
delete[] filecurrent;
} else {
if (!singlefile_opened) {
internal->fh =
internal->io.Open(filename, adios2::Mode::Write, world);
if (!internal->fh) {
char str[128];
sprintf(str, "Cannot open dump file %s", filename);
error->one(FLERR, str);
}
singlefile_opened = 1;
}
if (multifile) {
// if one file per timestep, replace '*' with current timestep
auto filecurrent = utils::star_subst(filename, update->ntimestep, padflag);
internal->fh = internal->io.Open(filecurrent, adios2::Mode::Write, world);
if (!internal->fh) error->one(FLERR, "Cannot open dump file {}", filecurrent);
} else {
if (!singlefile_opened) {
internal->fh = internal->io.Open(filename, adios2::Mode::Write, world);
if (!internal->fh) error->one(FLERR, "Cannot open dump file {}", filename);
singlefile_opened = 1;
}
}
}
/* ---------------------------------------------------------------------- */
void DumpCustomADIOS::write()
{
if (domain->triclinic == 0) {
boxxlo = domain->boxlo[0];
boxxhi = domain->boxhi[0];
boxylo = domain->boxlo[1];
boxyhi = domain->boxhi[1];
boxzlo = domain->boxlo[2];
boxzhi = domain->boxhi[2];
} else {
boxxlo = domain->boxlo_bound[0];
boxxhi = domain->boxhi_bound[0];
boxylo = domain->boxlo_bound[1];
boxyhi = domain->boxhi_bound[1];
boxzlo = domain->boxlo_bound[2];
boxzhi = domain->boxhi_bound[2];
boxxy = domain->xy;
boxxz = domain->xz;
boxyz = domain->yz;
if (domain->triclinic == 0) {
boxxlo = domain->boxlo[0];
boxxhi = domain->boxhi[0];
boxylo = domain->boxlo[1];
boxyhi = domain->boxhi[1];
boxzlo = domain->boxlo[2];
boxzhi = domain->boxhi[2];
} else {
boxxlo = domain->boxlo_bound[0];
boxxhi = domain->boxhi_bound[0];
boxylo = domain->boxlo_bound[1];
boxyhi = domain->boxhi_bound[1];
boxzlo = domain->boxlo_bound[2];
boxzhi = domain->boxhi_bound[2];
boxxy = domain->xy;
boxxz = domain->xz;
boxyz = domain->yz;
}
// nme = # of dump lines this proc contributes to dump
nme = count();
// ntotal = total # of atoms in snapshot
// atomOffset = sum of # of atoms up to this proc (exclusive prefix sum)
bigint bnme = nme;
MPI_Allreduce(&bnme, &ntotal, 1, MPI_LMP_BIGINT, MPI_SUM, world);
bigint atomOffset; // sum of all atoms on processes 0..me-1
MPI_Scan(&bnme, &atomOffset, 1, MPI_LMP_BIGINT, MPI_SUM, world);
atomOffset -= nme; // exclusive prefix sum needed
// Now we know the global size and the local subset size and offset
// of the atoms table
auto nAtomsGlobal = static_cast<size_t>(ntotal);
auto startRow = static_cast<size_t>(atomOffset);
auto nAtomsLocal = static_cast<size_t>(nme);
auto nColumns = static_cast<size_t>(size_one);
internal->varAtoms.SetShape({nAtomsGlobal, nColumns});
internal->varAtoms.SetSelection({{startRow, 0}, {nAtomsLocal, nColumns}});
// insure filewriter proc can receive everyone's info
// limit nmax*size_one to int since used as arg in MPI_Rsend() below
// pack my data into buf
// if sorting on IDs also request ID list from pack()
// sort buf as needed
if (nme > maxbuf) {
if ((bigint) nme * size_one > MAXSMALLINT) error->all(FLERR, "Too much per-proc info for dump");
maxbuf = nme;
memory->destroy(buf);
memory->create(buf, (maxbuf * size_one), "dump:buf");
}
if (sort_flag && sortcol == 0 && nme > maxids) {
maxids = nme;
memory->destroy(ids);
memory->create(ids, maxids, "dump:ids");
}
if (sort_flag && sortcol == 0)
pack(ids);
else
pack(nullptr);
if (sort_flag) sort();
openfile();
internal->fh.BeginStep();
// write info on data as scalars (by me==0)
if (me == 0) {
internal->fh.Put<uint64_t>("ntimestep", update->ntimestep);
internal->fh.Put<int>("nprocs", nprocs);
internal->fh.Put<double>("boxxlo", boxxlo);
internal->fh.Put<double>("boxxhi", boxxhi);
internal->fh.Put<double>("boxylo", boxylo);
internal->fh.Put<double>("boxyhi", boxyhi);
internal->fh.Put<double>("boxzlo", boxzlo);
internal->fh.Put<double>("boxzhi", boxzhi);
if (domain->triclinic) {
internal->fh.Put<double>("boxxy", boxxy);
internal->fh.Put<double>("boxxz", boxxz);
internal->fh.Put<double>("boxyz", boxyz);
}
}
// Everyone needs to write scalar variables that are used as dimensions and
// offsets of arrays
internal->fh.Put<uint64_t>("natoms", ntotal);
internal->fh.Put<int>("ncolumns", size_one);
internal->fh.Put<uint64_t>("nme", bnme);
internal->fh.Put<uint64_t>("offset", atomOffset);
// now write the atoms
internal->fh.Put<double>("atoms", buf);
internal->fh.EndStep(); // I/O will happen now...
// nme = # of dump lines this proc contributes to dump
nme = count();
// ntotal = total # of atoms in snapshot
// atomOffset = sum of # of atoms up to this proc (exclusive prefix sum)
bigint bnme = nme;
MPI_Allreduce(&bnme, &ntotal, 1, MPI_LMP_BIGINT, MPI_SUM, world);
bigint atomOffset; // sum of all atoms on processes 0..me-1
MPI_Scan(&bnme, &atomOffset, 1, MPI_LMP_BIGINT, MPI_SUM, world);
atomOffset -= nme; // exclusive prefix sum needed
// Now we know the global size and the local subset size and offset
// of the atoms table
size_t nAtomsGlobal = static_cast<size_t>(ntotal);
size_t startRow = static_cast<size_t>(atomOffset);
size_t nAtomsLocal = static_cast<size_t>(nme);
size_t nColumns = static_cast<size_t>(size_one);
internal->varAtoms.SetShape({nAtomsGlobal, nColumns});
internal->varAtoms.SetSelection({{startRow, 0}, {nAtomsLocal, nColumns}});
// insure filewriter proc can receive everyone's info
// limit nmax*size_one to int since used as arg in MPI_Rsend() below
// pack my data into buf
// if sorting on IDs also request ID list from pack()
// sort buf as needed
if (nme > maxbuf) {
if ((bigint)nme * size_one > MAXSMALLINT)
error->all(FLERR, "Too much per-proc info for dump");
maxbuf = nme;
memory->destroy(buf);
memory->create(buf, (maxbuf * size_one), "dump:buf");
}
if (sort_flag && sortcol == 0 && nme > maxids) {
maxids = nme;
memory->destroy(ids);
memory->create(ids, maxids, "dump:ids");
}
if (sort_flag && sortcol == 0)
pack(ids);
else
pack(nullptr);
if (sort_flag)
sort();
openfile();
internal->fh.BeginStep();
// write info on data as scalars (by me==0)
if (me == 0) {
internal->fh.Put<uint64_t>("ntimestep", update->ntimestep);
internal->fh.Put<int>("nprocs", nprocs);
internal->fh.Put<double>("boxxlo", boxxlo);
internal->fh.Put<double>("boxxhi", boxxhi);
internal->fh.Put<double>("boxylo", boxylo);
internal->fh.Put<double>("boxyhi", boxyhi);
internal->fh.Put<double>("boxzlo", boxzlo);
internal->fh.Put<double>("boxzhi", boxzhi);
if (domain->triclinic) {
internal->fh.Put<double>("boxxy", boxxy);
internal->fh.Put<double>("boxxz", boxxz);
internal->fh.Put<double>("boxyz", boxyz);
}
}
// Everyone needs to write scalar variables that are used as dimensions and
// offsets of arrays
internal->fh.Put<uint64_t>("natoms", ntotal);
internal->fh.Put<int>("ncolumns", size_one);
internal->fh.Put<uint64_t>("nme", bnme);
internal->fh.Put<uint64_t>("offset", atomOffset);
// now write the atoms
internal->fh.Put<double>("atoms", buf);
internal->fh.EndStep(); // I/O will happen now...
if (multifile) {
internal->fh.Close();
}
if (multifile) { internal->fh.Close(); }
}
/* ---------------------------------------------------------------------- */
void DumpCustomADIOS::init_style()
{
// assemble column string from defaults and user values
// setup boundary string
delete[] columns;
std::string combined;
int icol = 0;
for (auto item : utils::split_words(columns_default)) {
if (combined.size()) combined += " ";
if (keyword_user[icol].size())
combined += keyword_user[icol];
else
combined += item;
++icol;
}
columns = utils::strdup(combined);
domain->boundary_string(boundstr);
// setup boundary string
// remove % from filename since ADIOS always writes a global file with
// data/metadata
int len = strlen(filename);
char *ptr = strchr(filename, '%');
if (ptr) {
*ptr = '\0';
char *s = new char[len - 1];
sprintf(s, "%s%s", filename, ptr + 1);
strncpy(filename, s, len);
domain->boundary_string(boundstr);
// remove % from filename since ADIOS always writes a global file with
// data/metadata
char *ptr = strchr(filename, '%');
if (ptr) {
while (*ptr) {
ptr[0] = ptr[1];
++ptr;
}
}
/* The next four loops are copied from dump_custom_mpiio, but nothing is
* done with them.
* It is unclear why we need them here.
* For metadata, variable[] will be written out as an ADIOS attribute if
* nvariable>0
*/
// find current ptr for each compute,fix,variable
// check that fix frequency is acceptable
int icompute;
for (int i = 0; i < ncompute; i++) {
icompute = modify->find_compute(id_compute[i]);
if (icompute < 0)
error->all(FLERR, "Could not find dump custom compute ID");
compute[i] = modify->compute[icompute];
}
/* The next four loops are copied from dump_custom_mpiio, but nothing is
* done with them.
* It is unclear why we need them here.
* For metadata, variable[] will be written out as an ADIOS attribute if
* nvariable>0
*/
// find current ptr for each compute,fix,variable
// check that fix frequency is acceptable
for (int i = 0; i < ncompute; i++) {
compute[i] = modify->get_compute_by_id(id_compute[i]);
if (!compute[i])
error->all(FLERR, "Could not find dump custom/adios compute ID {}", id_compute[i]);
}
int ifix;
for (int i = 0; i < nfix; i++) {
ifix = modify->find_fix(id_fix[i]);
if (ifix < 0)
error->all(FLERR, "Could not find dump custom fix ID");
fix[i] = modify->fix[ifix];
if (nevery % modify->fix[ifix]->peratom_freq)
error->all(FLERR,
"Dump custom and fix not computed at compatible times");
}
for (int i = 0; i < nfix; i++) {
fix[i] = modify->get_fix_by_id(id_fix[i]);
if (!fix[i]) error->all(FLERR, "Could not find dump custom/adios fix ID {}", id_fix[i]);
if (nevery % fix[i]->peratom_freq)
error->all(FLERR, "dump custom/adios and fix {} with ID {} not computed at compatible times",
fix[i]->style, id_fix[i]);
}
int ivariable;
for (int i = 0; i < nvariable; i++) {
ivariable = input->variable->find(id_variable[i]);
if (ivariable < 0)
error->all(FLERR, "Could not find dump custom variable name");
variable[i] = ivariable;
}
int ivariable;
for (int i = 0; i < nvariable; i++) {
ivariable = input->variable->find(id_variable[i]);
if (ivariable < 0) error->all(FLERR, "Could not find dump custom/adios variable name");
variable[i] = ivariable;
}
// set index and check validity of region
if (iregion >= 0) {
iregion = domain->find_region(idregion);
if (iregion == -1)
error->all(FLERR, "Region ID for dump custom does not exist");
}
// set index and check validity of region
if (idregion && !domain->get_region_by_id(idregion))
error->all(FLERR, "Region {} for dump custom/adios does not exist", idregion);
/* Define the group of variables for the atom style here since it's a fixed
* set */
internal->io = internal->ad->DeclareIO(internal->ioName);
if (!internal->io.InConfigFile()) {
// if not defined by user, we can change the default settings
// BPFile is the default writer
internal->io.SetEngine("BPFile");
int num_aggregators = multiproc;
if (num_aggregators == 0)
num_aggregators = 1;
char nstreams[128];
sprintf(nstreams, "%d", num_aggregators);
internal->io.SetParameters({{"substreams", nstreams}});
if (me == 0 && screen)
fprintf(
screen,
"ADIOS method for %s is n-to-m (aggregation with %s writers)\n",
filename, nstreams);
}
/* Define the group of variables for the atom style here since it's a fixed
* set */
internal->io = internal->ad->DeclareIO(internal->ioName);
if (!internal->io.InConfigFile()) {
// if not defined by user, we can change the default settings
// BPFile is the default writer
internal->io.SetEngine("BPFile");
int num_aggregators = multiproc;
if (num_aggregators == 0) num_aggregators = 1;
auto nstreams = std::to_string(num_aggregators);
internal->io.SetParameters({{"substreams", nstreams}});
if (me == 0)
utils::logmesg(lmp, "ADIOS method for {} is n-to-m (aggregation with {} writers)\n", filename,
nstreams);
}
internal->io.DefineVariable<uint64_t>("ntimestep");
internal->io.DefineVariable<uint64_t>("natoms");
internal->io.DefineVariable<uint64_t>("ntimestep");
internal->io.DefineVariable<uint64_t>("natoms");
internal->io.DefineVariable<int>("nprocs");
internal->io.DefineVariable<int>("ncolumns");
internal->io.DefineVariable<int>("nprocs");
internal->io.DefineVariable<int>("ncolumns");
internal->io.DefineVariable<double>("boxxlo");
internal->io.DefineVariable<double>("boxxhi");
internal->io.DefineVariable<double>("boxylo");
internal->io.DefineVariable<double>("boxyhi");
internal->io.DefineVariable<double>("boxzlo");
internal->io.DefineVariable<double>("boxzhi");
internal->io.DefineVariable<double>("boxxlo");
internal->io.DefineVariable<double>("boxxhi");
internal->io.DefineVariable<double>("boxylo");
internal->io.DefineVariable<double>("boxyhi");
internal->io.DefineVariable<double>("boxzlo");
internal->io.DefineVariable<double>("boxzhi");
internal->io.DefineVariable<double>("boxxy");
internal->io.DefineVariable<double>("boxxz");
internal->io.DefineVariable<double>("boxyz");
internal->io.DefineVariable<double>("boxxy");
internal->io.DefineVariable<double>("boxxz");
internal->io.DefineVariable<double>("boxyz");
internal->io.DefineAttribute<int>("triclinic", domain->triclinic);
internal->io.DefineAttribute<int>("triclinic", domain->triclinic);
int *boundaryptr = reinterpret_cast<int *>(domain->boundary);
internal->io.DefineAttribute<int>("boundary", boundaryptr, 6);
int *boundaryptr = reinterpret_cast<int *>(domain->boundary);
internal->io.DefineAttribute<int>("boundary", boundaryptr, 6);
size_t nColumns = static_cast<size_t>(size_one);
internal->io.DefineAttribute<std::string>(
"columns", internal->columnNames.data(), nColumns);
internal->io.DefineAttribute<std::string>("columnstr", columns);
internal->io.DefineAttribute<std::string>("boundarystr", boundstr);
internal->io.DefineAttribute<std::string>("LAMMPS/dump_style", "custom");
internal->io.DefineAttribute<std::string>("LAMMPS/version",
lmp->version);
internal->io.DefineAttribute<std::string>("LAMMPS/num_ver",
std::to_string(lmp->num_ver));
auto nColumns = static_cast<size_t>(size_one);
internal->io.DefineAttribute<std::string>("columns", internal->columnNames.data(), nColumns);
internal->io.DefineAttribute<std::string>("columnstr", columns);
internal->io.DefineAttribute<std::string>("boundarystr", boundstr);
internal->io.DefineAttribute<std::string>("LAMMPS/dump_style", "custom");
internal->io.DefineAttribute<std::string>("LAMMPS/version", lmp->version);
internal->io.DefineAttribute<std::string>("LAMMPS/num_ver", std::to_string(lmp->num_ver));
internal->io.DefineVariable<uint64_t>(
"nme", {adios2::LocalValueDim}); // local dimension variable
internal->io.DefineVariable<uint64_t>(
"offset", {adios2::LocalValueDim}); // local dimension variable
internal->io.DefineVariable<uint64_t>("nme",
{adios2::LocalValueDim}); // local dimension variable
internal->io.DefineVariable<uint64_t>("offset",
{adios2::LocalValueDim}); // local dimension variable
// atom table size is not known at the moment
// it will be correctly defined at the moment of write
size_t UnknownSizeYet = 1;
internal->varAtoms = internal->io.DefineVariable<double>(
"atoms", {UnknownSizeYet, nColumns}, {UnknownSizeYet, 0},
{UnknownSizeYet, nColumns});
// atom table size is not known at the moment
// it will be correctly defined at the moment of write
size_t UnknownSizeYet = 1;
internal->varAtoms = internal->io.DefineVariable<double>(
"atoms", {UnknownSizeYet, nColumns}, {UnknownSizeYet, 0}, {UnknownSizeYet, nColumns});
}

View File

@ -43,43 +43,3 @@ class DumpCustomADIOS : public DumpCustom {
#endif
#endif
/* ERROR/WARNING messages:
E: Cannot open dump file %s
The output file for the dump command cannot be opened. Check that the
path and name are correct.
E: Too much per-proc info for dump
Number of local atoms times number of columns must fit in a 32-bit
integer for dump.
E: Dump_modify format string is too short
There are more fields to be dumped in a line of output than your
format string specifies.
E: Could not find dump custom compute ID
Self-explanatory.
E: Could not find dump custom fix ID
Self-explanatory.
E: Dump custom and fix not computed at compatible times
The fix must produce per-atom quantities on timesteps that dump custom
needs them.
E: Could not find dump custom variable name
Self-explanatory.
E: Region ID for dump custom does not exist
Self-explanatory.
*/

View File

@ -1,4 +1,3 @@
// clang-format off
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, Sandia National Laboratories
@ -17,20 +16,20 @@
------------------------------------------------------------------------- */
#include "reader_adios.h"
#include "comm.h"
#include "error.h"
#include "memory.h"
#include <cmath>
#include <cstdlib>
#include <cstring>
#include "adios2.h"
#include "math_const.h"
#include "adios_common.h"
using namespace LAMMPS_NS;
using namespace MathConst;
// also in read_dump.cpp
enum { ID, TYPE, X, Y, Z, VX, VY, VZ, Q, IX, IY, IZ, FX, FY, FZ };
@ -38,78 +37,69 @@ enum { UNSET, NOSCALE_NOWRAP, NOSCALE_WRAP, SCALE_NOWRAP, SCALE_WRAP };
#define SMALL 1.0e-6
// true if the difference between two floats is "small".
// cannot use fabsf() since it is not fully portable.
static bool is_smalldiff(const float &val1, const float &val2)
{
return (fabs(static_cast<double>(val1 - val2)) < SMALL);
}
namespace LAMMPS_NS {
class ReadADIOSInternal {
namespace LAMMPS_NS
{
class ReadADIOSInternal
{
public:
ReadADIOSInternal() = default;
~ReadADIOSInternal() = default;
public:
ReadADIOSInternal() {};
~ReadADIOSInternal() = default;
// name of adios group, referrable in adios2_config.xml
const std::string ioName = "read_dump";
adios2::ADIOS *ad = nullptr; // adios object
adios2::IO io; // adios group of variables and attributes in this dump
adios2::Engine fh; // adios file/stream handle object
// ADIOS input variables we need to change every step
adios2::Variable<uint64_t> varNtimestep;
adios2::Variable<uint64_t> varNatoms;
adios2::Variable<double> varAtoms;
// list of column names for the atom table
// (individual list of 'columns' string)
std::vector<std::string> columnNames;
float timeout = 0.0;
// name of adios group, referrable in adios2_config.xml
const std::string ioName = "read_dump";
adios2::ADIOS *ad = nullptr; // adios object
adios2::IO io; // adios group of variables and attributes in this dump
adios2::Engine fh; // adios file/stream handle object
// ADIOS input variables we need to change every step
adios2::Variable<uint64_t> varNtimestep;
adios2::Variable<uint64_t> varNatoms;
adios2::Variable<double> varAtoms;
// list of column names for the atom table
// (individual list of 'columns' string)
std::vector<std::string> columnNames;
float timeout = 0.0;
};
} // namespace LAMMPS_NS
} // namespace LAMMPS_NS
/* ---------------------------------------------------------------------- */
ReaderADIOS::ReaderADIOS(LAMMPS *lmp) : Reader(lmp)
{
fieldindex = nullptr;
nAtoms = 0;
nAtomsTotal = 0;
atomOffset = 0;
nstep = 0;
nid = 0;
me = comm->me;
fieldindex = nullptr;
nAtoms = 0;
nAtomsTotal = 0;
atomOffset = 0;
nstep = 0;
nid = 0;
me = comm->me;
internal = new ReadADIOSInternal();
try {
internal->ad =
new adios2::ADIOS("adios2_config.xml", world, adios2::DebugON);
} catch (std::ios_base::failure &e) {
char str[256];
snprintf(str, sizeof(str), "ADIOS initialization failed with error: %s",
e.what());
error->one(FLERR, str);
}
// create a default adios2_config.xml if it doesn't exist yet.
FILE *cfgfp = fopen("adios2_config.xml", "r");
if (!cfgfp) {
cfgfp = fopen("adios2_config.xml", "w");
if (cfgfp) fputs(default_config, cfgfp);
}
if (cfgfp) fclose(cfgfp);
/* Define the group holding all variables and attributes */
internal->io = internal->ad->DeclareIO(internal->ioName);
internal = new ReadADIOSInternal();
try {
internal->ad = new adios2::ADIOS("adios2_config.xml", world, adios2::DebugON);
} catch (std::ios_base::failure &e) {
error->one(FLERR, "ADIOS initialization failed with error: {}", e.what());
}
/* Define the group holding all variables and attributes */
internal->io = internal->ad->DeclareIO(internal->ioName);
}
/* ---------------------------------------------------------------------- */
ReaderADIOS::~ReaderADIOS()
{
if (me == 0) {
memory->destroy(fieldindex);
}
internal->columnNames.clear();
if (internal->fh) {
internal->fh.Close();
}
delete internal->ad;
delete internal;
if (me == 0) memory->destroy(fieldindex);
internal->columnNames.clear();
if (internal->fh) internal->fh.Close();
delete internal->ad;
delete internal;
}
/* ----------------------------------------------------------------------
@ -118,23 +108,19 @@ ReaderADIOS::~ReaderADIOS()
------------------------------------------------------------------------- */
void ReaderADIOS::settings(int narg, char **arg)
{
int idx = 0;
while (idx < narg) {
if (!strcmp(arg[idx], "timeout")) {
if (idx + 1 < narg) {
internal->timeout = std::stof(arg[idx + 1]);
internal->io.SetParameter("OpenTimeoutSecs", arg[idx + 1]);
++idx;
} else {
char str[128];
snprintf(str, sizeof(str),
"Missing value for 'timeout' option for ADIOS "
"read_dump command");
error->one(FLERR, str);
}
}
int idx = 0;
while (idx < narg) {
if (!strcmp(arg[idx], "timeout")) {
if (idx + 1 < narg) {
internal->timeout = std::stof(arg[idx + 1]);
internal->io.SetParameter("OpenTimeoutSecs", arg[idx + 1]);
++idx;
} else {
error->one(FLERR, "Missing value for 'timeout' option for ADIOS read_dump command");
}
}
++idx;
}
}
/* ----------------------------------------------------------------------
@ -142,26 +128,17 @@ void ReaderADIOS::settings(int narg, char **arg)
Every process must call this Collective operation
------------------------------------------------------------------------- */
void ReaderADIOS::open_file(const char *file)
void ReaderADIOS::open_file(const std::string &file)
{
int rv;
char str[1024];
// close open file, if needed.
if (internal->fh) internal->fh.Close();
// close open file, if needed.
if (internal->fh)
internal->fh.Close();
try {
internal->fh = internal->io.Open(file, adios2::Mode::Read, world);
} catch (std::ios_base::failure &e) {
char str[256];
snprintf(str, sizeof(str), "%s", e.what());
error->one(FLERR, str);
}
if (!internal->fh) {
snprintf(str, sizeof(str), "Cannot open file %s using ADIOS", file);
error->one(FLERR, str);
}
try {
internal->fh = internal->io.Open(file, adios2::Mode::Read, world);
} catch (std::ios_base::failure &e) {
error->one(FLERR, "Error opening file {}: {}", file, e.what());
}
if (!internal->fh) error->one(FLERR, "Cannot open file {} using ADIOS", file);
}
/* ----------------------------------------------------------------------
@ -171,10 +148,8 @@ void ReaderADIOS::open_file(const char *file)
void ReaderADIOS::close_file()
{
// close open file, if needed.
if (internal->fh) {
internal->fh.Close();
}
// close open file, if needed.
if (internal->fh) { internal->fh.Close(); }
}
/* ----------------------------------------------------------------------
@ -185,34 +160,24 @@ void ReaderADIOS::close_file()
int ReaderADIOS::read_time(bigint &ntimestep)
{
char str[1024];
adios2::StepStatus status = internal->fh.BeginStep(adios2::StepMode::Read, internal->timeout);
adios2::StepStatus status =
internal->fh.BeginStep(adios2::StepMode::Read, internal->timeout);
switch (status) {
switch (status) {
case adios2::StepStatus::EndOfStream:
case adios2::StepStatus::NotReady:
case adios2::StepStatus::OtherError:
return 1;
return 1;
default:
break;
}
break;
}
internal->varNtimestep =
internal->io.InquireVariable<uint64_t>("ntimestep");
internal->varNtimestep = internal->io.InquireVariable<uint64_t>("ntimestep");
if (!internal->varNtimestep) {
snprintf(str, sizeof(str),
"Did not find 'ntimestep' variable in ADIOS file %s",
internal->fh.Name().c_str());
error->one(FLERR, str);
}
if (!internal->varNtimestep)
error->one(FLERR, "Did not find 'ntimestep' variable in ADIOS file {}", internal->fh.Name());
ntimestep = static_cast<bigint>(internal->varNtimestep.Max());
// std::cerr << " **** ReaderADIOS::read_time found step " << ntimestep
// << " **** " << std::endl;
return 0;
ntimestep = static_cast<bigint>(internal->varNtimestep.Max());
return 0;
}
/* ----------------------------------------------------------------------
@ -220,7 +185,10 @@ int ReaderADIOS::read_time(bigint &ntimestep)
Called by all processors.
------------------------------------------------------------------------- */
void ReaderADIOS::skip() { internal->fh.EndStep(); }
void ReaderADIOS::skip()
{
internal->fh.EndStep();
}
/* ----------------------------------------------------------------------
read remaining header info:
@ -236,234 +204,205 @@ void ReaderADIOS::skip() { internal->fh.EndStep(); }
only called by proc 0
------------------------------------------------------------------------- */
bigint ReaderADIOS::read_header(double box[3][3], int &boxinfo, int &triclinic,
int fieldinfo, int nfield, int *fieldtype,
char **fieldlabel, int scaleflag, int wrapflag,
int &fieldflag, int &xflag, int &yflag,
int &zflag)
bigint ReaderADIOS::read_header(double box[3][3], int &boxinfo, int &triclinic, int fieldinfo,
int nfield, int *fieldtype, char **fieldlabel, int scaleflag,
int wrapflag, int &fieldflag, int &xflag, int &yflag, int &zflag)
{
char str[1024];
nid = 0;
nid = 0;
// signal that we have no box info at all so far.
// signal that we have no box info at all so far.
internal->varNatoms = internal->io.InquireVariable<uint64_t>("natoms");
if (!internal->varNatoms) {
snprintf(str, sizeof(str),
"Did not find 'natoms' variable in ADIOS file %s",
internal->fh.Name().c_str());
error->one(FLERR, str);
internal->varNatoms = internal->io.InquireVariable<uint64_t>("natoms");
if (!internal->varNatoms)
error->one(FLERR, "Did not find 'natoms' variable in ADIOS file {}", internal->fh.Name());
/* nAtoms */
nAtomsTotal = internal->varNatoms.Max();
uint64_t rem = nAtomsTotal % comm->nprocs;
nAtoms = nAtomsTotal / comm->nprocs;
atomOffset = comm->me * nAtoms;
if (comm->me < (int) rem) {
++nAtoms;
atomOffset += comm->me;
} else {
atomOffset += rem;
}
/* triclinic */
adios2::Attribute<int32_t> attTriclinic = internal->io.InquireAttribute<int32_t>("triclinic");
if (!attTriclinic)
error->one(FLERR, "Did not find 'triclinic' attribute in ADIOS file {}", internal->fh.Name());
triclinic = attTriclinic.Data()[0];
/* read Box */
adios2::Variable<double> varBoxxlo = internal->io.InquireVariable<double>("boxxlo");
adios2::Variable<double> varBoxxhi = internal->io.InquireVariable<double>("boxxhi");
adios2::Variable<double> varBoxylo = internal->io.InquireVariable<double>("boxylo");
adios2::Variable<double> varBoxyhi = internal->io.InquireVariable<double>("boxyhi");
adios2::Variable<double> varBoxzlo = internal->io.InquireVariable<double>("boxzlo");
adios2::Variable<double> varBoxzhi = internal->io.InquireVariable<double>("boxzhi");
box[0][0] = varBoxxlo.Max();
box[0][1] = varBoxxhi.Max();
box[0][2] = 0.0;
box[1][0] = varBoxylo.Max();
box[1][1] = varBoxyhi.Max();
box[1][2] = 0.0;
box[2][0] = varBoxzlo.Max();
box[2][1] = varBoxzhi.Max();
box[2][2] = 0.0;
if (triclinic) {
adios2::Variable<double> varBoxxy = internal->io.InquireVariable<double>("boxxy");
adios2::Variable<double> varBoxxz = internal->io.InquireVariable<double>("boxxz");
adios2::Variable<double> varBoxyz = internal->io.InquireVariable<double>("boxyz");
box[0][2] = varBoxxy.Max();
box[1][2] = varBoxxz.Max();
box[2][2] = varBoxyz.Max();
}
boxinfo = 1;
// if no field info requested, just return
if (!fieldinfo) return nAtoms;
memory->create(fieldindex, nfield, "read_dump:fieldindex");
/* Columns */
adios2::Attribute<std::string> attColumns = internal->io.InquireAttribute<std::string>("columns");
std::vector<std::string> labelVector = attColumns.Data();
int nwords = labelVector.size();
std::map<std::string, int> labels;
for (int i = 0; i < nwords; ++i) { labels.emplace(labelVector[i], i); }
int s_index, u_index, su_index;
xflag = UNSET;
yflag = UNSET;
zflag = UNSET;
// copy fieldtype list for supported fields
for (int i = 0; i < nfield; i++) {
if (fieldlabel[i]) {
fieldindex[i] = find_label(fieldlabel[i], labels);
if (fieldtype[i] == X)
xflag = 2 * scaleflag + wrapflag + 1;
else if (fieldtype[i] == Y)
yflag = 2 * scaleflag + wrapflag + 1;
else if (fieldtype[i] == Z)
zflag = 2 * scaleflag + wrapflag + 1;
}
/* nAtoms */
nAtomsTotal = internal->varNatoms.Max();
uint64_t rem = nAtomsTotal % comm->nprocs;
nAtoms = nAtomsTotal / comm->nprocs;
atomOffset = comm->me * nAtoms;
if (comm->me < rem) {
++nAtoms;
atomOffset += comm->me;
} else {
atomOffset += rem;
}
else if (fieldtype[i] == ID)
fieldindex[i] = find_label("id", labels);
else if (fieldtype[i] == TYPE)
fieldindex[i] = find_label("type", labels);
/* triclinic */
adios2::Attribute<int32_t> attTriclinic =
internal->io.InquireAttribute<int32_t>("triclinic");
if (!attTriclinic) {
snprintf(str, sizeof(str),
"Did not find 'triclinic' attribute in ADIOS file %s",
internal->fh.Name().c_str());
error->one(FLERR, str);
}
triclinic = attTriclinic.Data()[0];
/* read Box */
adios2::Variable<double> varBoxxlo =
internal->io.InquireVariable<double>("boxxlo");
adios2::Variable<double> varBoxxhi =
internal->io.InquireVariable<double>("boxxhi");
adios2::Variable<double> varBoxylo =
internal->io.InquireVariable<double>("boxylo");
adios2::Variable<double> varBoxyhi =
internal->io.InquireVariable<double>("boxyhi");
adios2::Variable<double> varBoxzlo =
internal->io.InquireVariable<double>("boxzlo");
adios2::Variable<double> varBoxzhi =
internal->io.InquireVariable<double>("boxzhi");
box[0][0] = varBoxxlo.Max();
box[0][1] = varBoxxhi.Max();
box[0][2] = 0.0;
box[1][0] = varBoxylo.Max();
box[1][1] = varBoxyhi.Max();
box[1][2] = 0.0;
box[2][0] = varBoxzlo.Max();
box[2][1] = varBoxzhi.Max();
box[2][2] = 0.0;
if (triclinic) {
adios2::Variable<double> varBoxxy =
internal->io.InquireVariable<double>("boxxy");
adios2::Variable<double> varBoxxz =
internal->io.InquireVariable<double>("boxxz");
adios2::Variable<double> varBoxyz =
internal->io.InquireVariable<double>("boxyz");
box[0][2] = varBoxxy.Max();
box[1][2] = varBoxxz.Max();
box[2][2] = varBoxyz.Max();
}
boxinfo = 1;
// if no field info requested, just return
if (!fieldinfo)
return nAtoms;
memory->create(fieldindex, nfield, "read_dump:fieldindex");
/* Columns */
adios2::Attribute<std::string> attColumns =
internal->io.InquireAttribute<std::string>("columns");
std::vector<std::string> labelVector = attColumns.Data();
int nwords = labelVector.size();
std::map<std::string, int> labels;
for (int i = 0; i < nwords; ++i) {
labels.emplace(labelVector[i], i);
}
int s_index, u_index, su_index;
xflag = UNSET;
yflag = UNSET;
zflag = UNSET;
// copy fieldtype list for supported fields
for (int i = 0; i < nfield; i++) {
if (fieldlabel[i]) {
fieldindex[i] = find_label(fieldlabel[i], labels);
if (fieldtype[i] == X)
xflag = 2 * scaleflag + wrapflag + 1;
else if (fieldtype[i] == Y)
yflag = 2 * scaleflag + wrapflag + 1;
else if (fieldtype[i] == Z)
zflag = 2 * scaleflag + wrapflag + 1;
else if (fieldtype[i] == X) {
fieldindex[i] = find_label("x", labels);
xflag = NOSCALE_WRAP;
if (fieldindex[i] < 0) {
fieldindex[i] = nwords;
s_index = find_label("xs", labels);
u_index = find_label("xu", labels);
su_index = find_label("xsu", labels);
if (s_index >= 0 && s_index < fieldindex[i]) {
fieldindex[i] = s_index;
xflag = SCALE_WRAP;
}
if (u_index >= 0 && u_index < fieldindex[i]) {
fieldindex[i] = u_index;
xflag = NOSCALE_NOWRAP;
}
if (su_index >= 0 && su_index < fieldindex[i]) {
fieldindex[i] = su_index;
xflag = SCALE_NOWRAP;
}
}
if (fieldindex[i] == nwords) fieldindex[i] = -1;
else if (fieldtype[i] == ID)
fieldindex[i] = find_label("id", labels);
else if (fieldtype[i] == TYPE)
fieldindex[i] = find_label("type", labels);
} else if (fieldtype[i] == Y) {
fieldindex[i] = find_label("y", labels);
yflag = NOSCALE_WRAP;
if (fieldindex[i] < 0) {
fieldindex[i] = nwords;
s_index = find_label("ys", labels);
u_index = find_label("yu", labels);
su_index = find_label("ysu", labels);
if (s_index >= 0 && s_index < fieldindex[i]) {
fieldindex[i] = s_index;
yflag = SCALE_WRAP;
}
if (u_index >= 0 && u_index < fieldindex[i]) {
fieldindex[i] = u_index;
yflag = NOSCALE_NOWRAP;
}
if (su_index >= 0 && su_index < fieldindex[i]) {
fieldindex[i] = su_index;
yflag = SCALE_NOWRAP;
}
}
if (fieldindex[i] == nwords) fieldindex[i] = -1;
else if (fieldtype[i] == X) {
fieldindex[i] = find_label("x", labels);
xflag = NOSCALE_WRAP;
if (fieldindex[i] < 0) {
fieldindex[i] = nwords;
s_index = find_label("xs", labels);
u_index = find_label("xu", labels);
su_index = find_label("xsu", labels);
if (s_index >= 0 && s_index < fieldindex[i]) {
fieldindex[i] = s_index;
xflag = SCALE_WRAP;
}
if (u_index >= 0 && u_index < fieldindex[i]) {
fieldindex[i] = u_index;
xflag = NOSCALE_NOWRAP;
}
if (su_index >= 0 && su_index < fieldindex[i]) {
fieldindex[i] = su_index;
xflag = SCALE_NOWRAP;
}
}
if (fieldindex[i] == nwords)
fieldindex[i] = -1;
} else if (fieldtype[i] == Z) {
fieldindex[i] = find_label("z", labels);
zflag = NOSCALE_WRAP;
if (fieldindex[i] < 0) {
fieldindex[i] = nwords;
s_index = find_label("zs", labels);
u_index = find_label("zu", labels);
su_index = find_label("zsu", labels);
if (s_index >= 0 && s_index < fieldindex[i]) {
fieldindex[i] = s_index;
zflag = SCALE_WRAP;
}
if (u_index >= 0 && u_index < fieldindex[i]) {
fieldindex[i] = u_index;
zflag = NOSCALE_NOWRAP;
}
if (su_index >= 0 && su_index < fieldindex[i]) {
fieldindex[i] = su_index;
zflag = SCALE_NOWRAP;
}
}
if (fieldindex[i] == nwords) fieldindex[i] = -1;
} else if (fieldtype[i] == Y) {
fieldindex[i] = find_label("y", labels);
yflag = NOSCALE_WRAP;
if (fieldindex[i] < 0) {
fieldindex[i] = nwords;
s_index = find_label("ys", labels);
u_index = find_label("yu", labels);
su_index = find_label("ysu", labels);
if (s_index >= 0 && s_index < fieldindex[i]) {
fieldindex[i] = s_index;
yflag = SCALE_WRAP;
}
if (u_index >= 0 && u_index < fieldindex[i]) {
fieldindex[i] = u_index;
yflag = NOSCALE_NOWRAP;
}
if (su_index >= 0 && su_index < fieldindex[i]) {
fieldindex[i] = su_index;
yflag = SCALE_NOWRAP;
}
}
if (fieldindex[i] == nwords)
fieldindex[i] = -1;
} else if (fieldtype[i] == VX)
fieldindex[i] = find_label("vx", labels);
else if (fieldtype[i] == VY)
fieldindex[i] = find_label("vy", labels);
else if (fieldtype[i] == VZ)
fieldindex[i] = find_label("vz", labels);
} else if (fieldtype[i] == Z) {
fieldindex[i] = find_label("z", labels);
zflag = NOSCALE_WRAP;
if (fieldindex[i] < 0) {
fieldindex[i] = nwords;
s_index = find_label("zs", labels);
u_index = find_label("zu", labels);
su_index = find_label("zsu", labels);
if (s_index >= 0 && s_index < fieldindex[i]) {
fieldindex[i] = s_index;
zflag = SCALE_WRAP;
}
if (u_index >= 0 && u_index < fieldindex[i]) {
fieldindex[i] = u_index;
zflag = NOSCALE_NOWRAP;
}
if (su_index >= 0 && su_index < fieldindex[i]) {
fieldindex[i] = su_index;
zflag = SCALE_NOWRAP;
}
}
if (fieldindex[i] == nwords)
fieldindex[i] = -1;
else if (fieldtype[i] == FX)
fieldindex[i] = find_label("fx", labels);
else if (fieldtype[i] == FY)
fieldindex[i] = find_label("fy", labels);
else if (fieldtype[i] == FZ)
fieldindex[i] = find_label("fz", labels);
} else if (fieldtype[i] == VX)
fieldindex[i] = find_label("vx", labels);
else if (fieldtype[i] == VY)
fieldindex[i] = find_label("vy", labels);
else if (fieldtype[i] == VZ)
fieldindex[i] = find_label("vz", labels);
else if (fieldtype[i] == Q)
fieldindex[i] = find_label("q", labels);
else if (fieldtype[i] == FX)
fieldindex[i] = find_label("fx", labels);
else if (fieldtype[i] == FY)
fieldindex[i] = find_label("fy", labels);
else if (fieldtype[i] == FZ)
fieldindex[i] = find_label("fz", labels);
else if (fieldtype[i] == IX)
fieldindex[i] = find_label("ix", labels);
else if (fieldtype[i] == IY)
fieldindex[i] = find_label("iy", labels);
else if (fieldtype[i] == IZ)
fieldindex[i] = find_label("iz", labels);
}
else if (fieldtype[i] == Q)
fieldindex[i] = find_label("q", labels);
// set fieldflag = -1 if any unfound fields
else if (fieldtype[i] == IX)
fieldindex[i] = find_label("ix", labels);
else if (fieldtype[i] == IY)
fieldindex[i] = find_label("iy", labels);
else if (fieldtype[i] == IZ)
fieldindex[i] = find_label("iz", labels);
}
fieldflag = 0;
for (int i = 0; i < nfield; i++)
if (fieldindex[i] < 0) fieldflag = -1;
// set fieldflag = -1 if any unfound fields
fieldflag = 0;
for (int i = 0; i < nfield; i++)
if (fieldindex[i] < 0)
fieldflag = -1;
return nAtoms;
return nAtoms;
}
/* ----------------------------------------------------------------------
@ -475,41 +414,33 @@ bigint ReaderADIOS::read_header(double box[3][3], int &boxinfo, int &triclinic,
void ReaderADIOS::read_atoms(int n, int nfield, double **fields)
{
char str[1024];
/* Read Atoms */
/* This is the firsts (and last) read of array data, so we
* call EndStep() here instead of PerformGets()
*/
/* Read Atoms */
/* This is the firsts (and last) read of array data, so we
* call EndStep() here instead of PerformGets()
*/
adios2::Variable<double> varAtoms = internal->io.InquireVariable<double>("atoms");
adios2::Variable<double> varAtoms =
internal->io.InquireVariable<double>("atoms");
if ((uint64_t) n != nAtoms)
error->one(FLERR,
"ReaderADIOS::read_atoms() expects 'n={}' equal to the number of "
"atoms (={}) for process {} in ADIOS file {}.",
n, nAtoms, comm->me, internal->fh.Name());
if (n != nAtoms) {
snprintf(
str, sizeof(str),
"ReaderADIOS::read_atoms() expects 'n=%d' equal to the number of "
"atoms (=%" PRIu64 ") for process %d in ADIOS file %s.",
n, nAtoms, comm->me, internal->fh.Name().c_str());
error->one(FLERR, str);
}
size_t ncols = varAtoms.Count()[1];
varAtoms.SetSelection({{atomOffset, 0}, {nAtoms, ncols}});
size_t ncols = varAtoms.Count()[1];
varAtoms.SetSelection({{atomOffset, 0}, {nAtoms, ncols}});
std::vector<double> table;
std::vector<double> table;
internal->fh.Get<double>(varAtoms, table);
// EndStep or PerformGets required to make the read happen
internal->fh.EndStep();
internal->fh.Get<double>(varAtoms, table);
// EndStep or PerformGets required to make the read happen
internal->fh.EndStep();
size_t idx;
for (int i = 0; i < nAtoms; i++) {
idx = i * ncols;
for (int m = 0; m < nfield; m++) {
fields[i][m] = table[idx + fieldindex[m]];
}
}
size_t idx;
for (uint64_t i = 0; i < nAtoms; i++) {
idx = i * ncols;
for (int m = 0; m < nfield; m++) { fields[i][m] = table[idx + fieldindex[m]]; }
}
}
/* ----------------------------------------------------------------------
@ -517,12 +448,9 @@ void ReaderADIOS::read_atoms(int n, int nfield, double **fields)
return index of match or -1 if no match
------------------------------------------------------------------------- */
int ReaderADIOS::find_label(const std::string &label,
const std::map<std::string, int> &labels)
int ReaderADIOS::find_label(const std::string &label, const std::map<std::string, int> &labels)
{
std::map<std::string, int>::const_iterator it = labels.find(label);
if (it != labels.end()) {
return it->second;
}
return -1;
auto it = labels.find(label);
if (it != labels.end()) { return it->second; }
return -1;
}

View File

@ -40,11 +40,11 @@ class ReaderADIOS : public Reader {
int read_time(bigint &) override;
void skip() override;
bigint read_header(double[3][3], int &, int &, int, int, int *, char **, int, int, int &,
int &, int &, int &) override;
bigint read_header(double[3][3], int &, int &, int, int, int *, char **, int, int, int &, int &,
int &, int &) override;
void read_atoms(int, int, double **) override;
void open_file(const char *) override;
void open_file(const std::string &) override;
void close_file() override;
private:

40
src/AMOEBA/Install.sh Normal file
View File

@ -0,0 +1,40 @@
# Install/unInstall package files in LAMMPS
# mode = 0/1/2 for uninstall/install/update
mode=$1
# enforce using portable C locale
LC_ALL=C
export LC_ALL
# arg1 = file, arg2 = file it depends on
action () {
if (test $mode = 0) then
rm -f ../$1
elif (! cmp -s $1 ../$1) then
if (test -z "$2" || test -e ../$2) then
cp $1 ..
if (test $mode = 2) then
echo " updating src/$1"
fi
fi
elif (test -n "$2") then
if (test ! -e ../$2) then
rm -f ../$1
fi
fi
}
# pair style amoeba calls KSPACE functions and requires FFT grid.
if (test $1 = 1) then
if (test ! -e ../pppm.cpp) then
echo "Must install KSPACE package with AMOEBA package"
exit 1
fi
fi
for file in *.cpp *.h; do
action ${file}
done

View File

@ -0,0 +1,167 @@
// clang-format off
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/ 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.
------------------------------------------------------------------------- */
#include "pair_amoeba.h"
#include "atom.h"
#include "memory.h"
#include "neigh_list.h"
#include <cmath>
using namespace LAMMPS_NS;
enum{VDWL,REPULSE,QFER,DISP,MPOLE,POLAR,USOLV,DISP_LONG,MPOLE_LONG,POLAR_LONG};
/* ----------------------------------------------------------------------
charge_transfer = HIPPO charge transfer forces
adapted from Tinker echgtrn1b() routine
------------------------------------------------------------------------- */
void PairAmoeba::charge_transfer()
{
int i,j,ii,jj,itype,jtype,iclass,jclass;
double e,de,felec;
double rr1,r,r2;
double r3,r4,r5;
double xi,yi,zi;
double xr,yr,zr;
double chgi,chgj;
double alphai,alphaj;
double expi,expj;
double frcx,frcy,frcz;
double vxx,vyy,vzz;
double vxy,vxz,vyz;
double taper,dtaper;
double factor_mpole;
int inum,jnum;
int *ilist,*jlist,*numneigh,**firstneigh;
// set cutoffs and taper coeffs
choose(QFER);
// owned atoms
double **x = atom->x;
double **f = atom->f;
// neigh list
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// set the energy unit conversion factor
felec = electric / am_dielectric;
// find charge transfer energy and derivatives via neighbor list
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
itype = amtype[i];
iclass = amtype2class[itype];
jlist = firstneigh[i];
jnum = numneigh[i];
xi = x[i][0];
yi = x[i][1];
zi = x[i][2];
chgi = chgct[iclass];
alphai = dmpct[iclass];
if (alphai == 0.0) alphai = 100.0;
// evaluate all sites within the cutoff distance
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_mpole = special_mpole[sbmask15(j)];
if (factor_mpole == 0.0) continue;
j &= NEIGHMASK15;
xr = x[j][0] - xi;
yr = x[j][1] - yi;
zr = x[j][2] - zi;
r2 = xr*xr + yr* yr + zr*zr;
if (r2 > off2) continue;
jtype = amtype[j];
jclass = amtype2class[jtype];
r = sqrt(r2);
rr1 = 1.0 / r;
chgj = chgct[jclass];
alphaj = dmpct[jclass];
if (alphaj == 0.0) alphaj = 100.0;
expi = exp(-alphai*r);
expj = exp(-alphaj*r);
e = -chgi*expj - chgj*expi;
de = chgi*expj*alphaj + chgj*expi*alphai;
e = felec * e * factor_mpole;
de = felec * de * factor_mpole;
// use energy switching if near the cutoff distance
if (r2 > cut2) {
r3 = r2 * r;
r4 = r2 * r2;
r5 = r2 * r3;
taper = c5*r5 + c4*r4 + c3*r3 + c2*r2 + c1*r + c0;
dtaper = 5.0*c5*r4 + 4.0*c4*r3 + 3.0*c3*r2 + 2.0*c2*r + c1;
de = e*dtaper + de*taper;
e *= taper;
}
eqxfer += e;
// compute the force components for this interaction
frcx = de * xr * rr1;
frcy = de * yr * rr1;
frcz = de * zr * rr1;
// increment the total charge transfer energy and derivatives
f[i][0] += frcx;
f[i][1] += frcy;
f[i][2] += frcz;
f[j][0] -= frcx;
f[j][1] -= frcy;
f[j][2] -= frcz;
// increment the internal virial tensor components
if (vflag_global) {
vxx = xr * frcx;
vxy = yr * frcx;
vxz = zr * frcx;
vyy = yr * frcy;
vyz = zr * frcy;
vzz = zr * frcz;
virqxfer[0] -= vxx;
virqxfer[1] -= vyy;
virqxfer[2] -= vzz;
virqxfer[3] -= vxy;
virqxfer[4] -= vxz;
virqxfer[5] -= vyz;
}
}
}
}

View File

@ -0,0 +1,843 @@
// clang-format off
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/ 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.
------------------------------------------------------------------------- */
#include "amoeba_convolution.h"
#include "comm.h"
#include "domain.h"
#include "fft3d_wrap.h"
#include "gridcomm.h"
#include "memory.h"
#include "neighbor.h"
#include "remap_wrap.h"
#include "update.h"
using namespace LAMMPS_NS;
// DEBUG
#define DEBUG_AMOEBA 0
#if DEBUG_AMOEBA
char *labels[7] =
{(char *) "MPOLE_GRID", (char *) "POLAR_GRID",
(char *) "POLAR_GRIDC", (char *) "DISP_GRID",
(char *) "INDUCE_GRID", (char *) "INDUCE_GRIDC"};
enum{GRIDBRICK_OUT,GRIDBRICK_IN,FFT,CFFT1,CFFT2};
#endif
// END DEBUG
enum{MPOLE_GRID,POLAR_GRID,POLAR_GRIDC,DISP_GRID,INDUCE_GRID,INDUCE_GRIDC};
//#define SCALE 1
#define SCALE 0
#ifdef FFT_SINGLE
#define ZEROF 0.0f
#define ONEF 1.0f
#else
#define ZEROF 0.0
#define ONEF 1.0
#endif
/* ----------------------------------------------------------------------
partition an FFT grid across processors
both for a brick and FFT x pencil decomposition
nx,nz,nz = global FFT grid size
order = size of stencil in each dimension that maps atoms to grid
adapted from PPPM::set_grid_local()
------------------------------------------------------------------------- */
AmoebaConvolution::AmoebaConvolution(LAMMPS *lmp, Pair *pair,
int nx_caller, int ny_caller, int nz_caller,
int order_caller, int which_caller) :
Pointers(lmp)
{
amoeba = pair;
nx = nx_caller;
ny = ny_caller;
nz = nz_caller;
order = order_caller;
which = which_caller;
flag3d = 1;
if (which == POLAR_GRIDC || which == INDUCE_GRIDC) flag3d = 0;
nfft_global = (bigint) nx * ny * nz;
// global indices of grid range from 0 to N-1
// nlo_in,nhi_in = lower/upper limits of the 3d sub-brick of
// global grid that I own without ghost cells
// both non-tiled and tiled proc layouts use 0-1 fractional subdomain info
if (comm->layout != Comm::LAYOUT_TILED) {
nxlo_in = static_cast<int> (comm->xsplit[comm->myloc[0]] * nx);
nxhi_in = static_cast<int> (comm->xsplit[comm->myloc[0]+1] * nx) - 1;
nylo_in = static_cast<int> (comm->ysplit[comm->myloc[1]] * ny);
nyhi_in = static_cast<int> (comm->ysplit[comm->myloc[1]+1] * ny) - 1;
nzlo_in = static_cast<int> (comm->zsplit[comm->myloc[2]] * nz);
nzhi_in = static_cast<int> (comm->zsplit[comm->myloc[2]+1] * nz) - 1;
} else {
nxlo_in = static_cast<int> (comm->mysplit[0][0] * nx);
nxhi_in = static_cast<int> (comm->mysplit[0][1] * nx) - 1;
nylo_in = static_cast<int> (comm->mysplit[1][0] * ny);
nyhi_in = static_cast<int> (comm->mysplit[1][1] * ny) - 1;
nzlo_in = static_cast<int> (comm->mysplit[2][0] * nz);
nzhi_in = static_cast<int> (comm->mysplit[2][1] * nz) - 1;
}
// nlower,nupper = stencil size for mapping particles to FFT grid
int nlower = -(order-1)/2;
int nupper = order/2;
// nlo_out,nhi_out = lower/upper limits of the 3d sub-brick of
// global grid that my particles can contribute charge to
// effectively nlo_in,nhi_in + ghost cells
// nlo,nhi = global coords of grid pt to "lower left" of smallest/largest
// position a particle in my box can be at
// dist[3] = particle position bound = subbox + skin/2.0
// convert to triclinic if necessary
// nlo_out,nhi_out = nlo,nhi + stencil size for particle mapping
double *prd,*boxlo,*sublo,*subhi;
int triclinic = domain->triclinic;
if (triclinic == 0) {
prd = domain->prd;
boxlo = domain->boxlo;
sublo = domain->sublo;
subhi = domain->subhi;
} else {
prd = domain->prd_lamda;
boxlo = domain->boxlo_lamda;
sublo = domain->sublo_lamda;
subhi = domain->subhi_lamda;
}
double xprd = prd[0];
double yprd = prd[1];
double zprd = prd[2];
double dist[3] = {0.0,0.0,0.0};
double cuthalf = 0.5*neighbor->skin;
if (triclinic == 0) dist[0] = dist[1] = dist[2] = cuthalf;
else kspacebbox(cuthalf,&dist[0]);
int nlo,nhi;
nlo = static_cast<int> ((sublo[0]-dist[0]-boxlo[0]) * nx/xprd);
nhi = static_cast<int> ((subhi[0]+dist[0]-boxlo[0]) * nx/xprd);
nxlo_out = nlo + nlower;
nxhi_out = nhi + nupper;
nlo = static_cast<int> ((sublo[1]-dist[1]-boxlo[1]) * ny/yprd);
nhi = static_cast<int> ((subhi[1]+dist[1]-boxlo[1]) * ny/yprd);
nylo_out = nlo + nlower;
nyhi_out = nhi + nupper;
nlo = static_cast<int> ((sublo[2]-dist[2]-boxlo[2]) * nz/zprd);
nhi = static_cast<int> ((subhi[2]+dist[2]-boxlo[2]) * nz/zprd);
nzlo_out = nlo + nlower;
nzhi_out = nhi + nupper;
// x-pencil decomposition of FFT mesh
// global indices range from 0 to N-1
// each proc owns entire x-dimension, clumps of columns in y,z dimensions
// npey_fft,npez_fft = # of procs in y,z dims
// if nprocs is small enough, proc can own 1 or more entire xy planes,
// else proc owns 2d sub-blocks of yz plane
// me_y,me_z = which proc (0-npe_fft-1) I am in y,z dimensions
// nlo_fft,nhi_fft = lower/upper limit of the section
// of the global FFT mesh that I own in x-pencil decomposition
int me = comm->me;
int nprocs = comm->nprocs;
int npey_fft,npez_fft;
if (nz >= nprocs) {
npey_fft = 1;
npez_fft = nprocs;
} else procs2grid2d(nprocs,ny,nz,npey_fft,npez_fft);
int me_y = me % npey_fft;
int me_z = me / npey_fft;
nxlo_fft = 0;
nxhi_fft = nx - 1;
nylo_fft = me_y*ny/npey_fft;
nyhi_fft = (me_y+1)*ny/npey_fft - 1;
nzlo_fft = me_z*nz/npez_fft;
nzhi_fft = (me_z+1)*nz/npez_fft - 1;
// grid sizes
// nbrick_owned = owned grid points in brick decomp
// nbrick_ghosts = owned + ghost grid points in grid decomp
// nfft_owned = owned grid points in FFT decomp
// ngrid_either = max of nbrick_onwed and nfft_owned
// nfft = total FFT grid points
nbrick_owned = (nxhi_in-nxlo_in+1) * (nyhi_in-nylo_in+1) *
(nzhi_in-nzlo_in+1);
nbrick_ghosts = (nxhi_out-nxlo_out+1) * (nyhi_out-nylo_out+1) *
(nzhi_out-nzlo_out+1);
nfft_owned = (nxhi_fft-nxlo_fft+1) * (nyhi_fft-nylo_fft+1) *
(nzhi_fft-nzlo_fft+1);
ngrid_either = MAX(nbrick_owned,nfft_owned);
// instantiate FFT, GridComm, and Remap
int tmp;
fft1 = new FFT3d(lmp,world,nx,ny,nz,
nxlo_fft,nxhi_fft,nylo_fft,nyhi_fft,nzlo_fft,nzhi_fft,
nxlo_fft,nxhi_fft,nylo_fft,nyhi_fft,nzlo_fft,nzhi_fft,
1,0,&tmp,0);
// 0,0,&tmp,0);
fft2 = new FFT3d(lmp,world,nx,ny,nz,
nxlo_fft,nxhi_fft,nylo_fft,nyhi_fft,nzlo_fft,nzhi_fft,
nxlo_in,nxhi_in,nylo_in,nyhi_in,nzlo_in,nzhi_in,
//1,0,&tmp,0);
0,0,&tmp,0);
gc = new GridComm(lmp,world,nx,ny,nz,
nxlo_in,nxhi_in,nylo_in,nyhi_in,nzlo_in,nzhi_in,
nxlo_out,nxhi_out,nylo_out,nyhi_out,nzlo_out,nzhi_out);
int nqty = flag3d ? 1 : 2;
remap = new Remap(lmp,world,
nxlo_in,nxhi_in,nylo_in,nyhi_in,nzlo_in,nzhi_in,
nxlo_fft,nxhi_fft,nylo_fft,nyhi_fft,nzlo_fft,nzhi_fft,
nqty,0,0,FFT_PRECISION,0);
// memory allocations
if (flag3d) {
memory->create3d_offset(grid_brick,nzlo_out,nzhi_out,nylo_out,nyhi_out,
nxlo_out,nxhi_out,"amoeba:grid_brick");
grid_brick_start = &grid_brick[nzlo_out][nylo_out][nxlo_out];
cgrid_brick = nullptr;
} else {
memory->create4d_offset_last(cgrid_brick,nzlo_out,nzhi_out,nylo_out,nyhi_out,
nxlo_out,nxhi_out,2,"amoeba:cgrid_brick");
grid_brick_start = &cgrid_brick[nzlo_out][nylo_out][nxlo_out][0];
grid_brick = nullptr;
}
memory->create(grid_fft,ngrid_either,"amoeba:grid_fft");
memory->create(cfft,2*ngrid_either,"amoeba:cfft");
int ngc_buf1,ngc_buf2;
gc->setup(ngc_buf1,ngc_buf2);
memory->create(gc_buf1,nqty*ngc_buf1,"amoeba:gc_buf1");
memory->create(gc_buf2,nqty*ngc_buf2,"amoeba:gc_buf2");
memory->create(remap_buf,nqty*nfft_owned,"amoeba:remap_buf");
}
/* ----------------------------------------------------------------------
free all memory
------------------------------------------------------------------------- */
AmoebaConvolution::~AmoebaConvolution()
{
memory->destroy3d_offset(grid_brick,nzlo_out,nylo_out,nxlo_out);
memory->destroy4d_offset_last(cgrid_brick,nzlo_out,nylo_out,nxlo_out);
memory->destroy(grid_fft);
memory->destroy(cfft);
memory->destroy(gc_buf1);
memory->destroy(gc_buf2);
memory->destroy(remap_buf);
delete fft1;
delete fft2;
delete gc;
delete remap;
}
/* ----------------------------------------------------------------------
zero brick grid, including ghosts
can be 3d real or 4d complex array
return pointer to data in brick grid, caller casts to 3d or 4d
------------------------------------------------------------------------- */
void *AmoebaConvolution::zero()
{
if (flag3d) return zero_3d();
return zero_4d();
}
/* ---------------------------------------------------------------------- */
void *AmoebaConvolution::zero_3d()
{
if (!grid_brick) return nullptr;
memset(&(grid_brick[nzlo_out][nylo_out][nxlo_out]),0,
nbrick_ghosts*sizeof(FFT_SCALAR));
return (void *) grid_brick;
}
/* ---------------------------------------------------------------------- */
void *AmoebaConvolution::zero_4d()
{
if (!cgrid_brick) return nullptr;
memset(&(cgrid_brick[nzlo_out][nylo_out][nxlo_out][0]),0,
2*nbrick_ghosts*sizeof(FFT_SCALAR));
return (void *) cgrid_brick;
}
/* ----------------------------------------------------------------------
perform pre-convolution grid operations
can be 3d real or 4d complex array
return pointer to complex cfft vector
------------------------------------------------------------------------- */
FFT_SCALAR *AmoebaConvolution::pre_convolution()
{
if (flag3d) return pre_convolution_3d();
return pre_convolution_4d();
}
/* ----------------------------------------------------------------------
perform pre-convolution grid operations for 3d grid_brick array
------------------------------------------------------------------------- */
FFT_SCALAR *AmoebaConvolution::pre_convolution_3d()
{
int ix,iy,iz,n;
// reverse comm for 3d brick grid + ghosts
#if DEBUG_AMOEBA
debug_scalar(GRIDBRICK_OUT,"PRE Convo / PRE GridComm");
#endif
gc->reverse_comm(GridComm::PAIR,amoeba,1,sizeof(FFT_SCALAR),which,
gc_buf1,gc_buf2,MPI_FFT_SCALAR);
#if DEBUG_AMOEBA
debug_scalar(GRIDBRICK_IN,"PRE Convo / POST GridComm");
debug_file(GRIDBRICK_IN,"pre.convo.post.gridcomm");
#endif
// copy owned 3d brick grid values to FFT grid
n = 0;
for (iz = nzlo_in; iz <= nzhi_in; iz++)
for (iy = nylo_in; iy <= nyhi_in; iy++)
for (ix = nxlo_in; ix <= nxhi_in; ix++)
grid_fft[n++] = grid_brick[iz][iy][ix];
// remap FFT grid from brick to x pencil partitioning
remap->perform(grid_fft,grid_fft,remap_buf);
#if DEBUG_AMOEBA
debug_scalar(FFT,"PRE Convo / POST Remap");
debug_file(FFT,"pre.convo.post.remap");
#endif
// copy real values into complex grid
n = 0;
for (int i = 0; i < nfft_owned; i++) {
cfft[n++] = grid_fft[i];
cfft[n++] = ZEROF;
}
// perform forward FFT
fft1->compute(cfft,cfft,FFT3d::FORWARD);
if (SCALE) {
double scale = 1.0/nfft_global;
for (int i = 0; i < 2*nfft_owned; i++) cfft[i] *= scale;
}
#if DEBUG_AMOEBA
debug_scalar(CFFT1,"PRE Convo / POST FFT");
debug_file(CFFT1,"pre.convo.post.fft");
#endif
return cfft;
}
/* ----------------------------------------------------------------------
perform pre-convolution grid operations for 4d cgrid_brick array
------------------------------------------------------------------------- */
FFT_SCALAR *AmoebaConvolution::pre_convolution_4d()
{
int ix,iy,iz,n;
// reverse comm for 4d brick grid + ghosts
#if DEBUG_AMOEBA
debug_scalar(GRIDBRICK_OUT,"PRE Convo / PRE GridComm");
#endif
gc->reverse_comm(GridComm::PAIR,amoeba,2,sizeof(FFT_SCALAR),which,
gc_buf1,gc_buf2,MPI_FFT_SCALAR);
#if DEBUG_AMOEBA
debug_scalar(GRIDBRICK_IN,"PRE Convo / POST GridComm");
debug_file(GRIDBRICK_IN,"pre.convo.post.gridcomm");
#endif
// copy owned 4d brick grid values to FFT grid
n = 0;
for (iz = nzlo_in; iz <= nzhi_in; iz++)
for (iy = nylo_in; iy <= nyhi_in; iy++)
for (ix = nxlo_in; ix <= nxhi_in; ix++) {
cfft[n++] = cgrid_brick[iz][iy][ix][0];
cfft[n++] = cgrid_brick[iz][iy][ix][1];
}
// remap FFT grid from brick to x pencil partitioning
// NOTE: could just setup FFT to start from brick decomp and skip remap
remap->perform(cfft,cfft,remap_buf);
#if DEBUG_AMOEBA
debug_scalar(FFT,"PRE Convo / POST Remap");
debug_file(FFT,"pre.convo.post.remap");
#endif
// perform forward FFT
fft1->compute(cfft,cfft,FFT3d::FORWARD);
if (SCALE) {
double scale = 1.0/nfft_global;
for (int i = 0; i < 2*nfft_owned; i++) cfft[i] *= scale;
}
#if DEBUG_AMOEBA
debug_scalar(CFFT1,"PRE Convo / POST FFT");
debug_file(CFFT1,"pre.convo.post.fft");
#endif
return cfft;
}
/* ----------------------------------------------------------------------
perform post-convolution grid operations
can be 3d real or 4d complex array
return pointer to data in brick grid, caller casts to 3d or 4d
------------------------------------------------------------------------- */
void *AmoebaConvolution::post_convolution()
{
if (flag3d) return post_convolution_3d();
return post_convolution_4d();
}
/* ----------------------------------------------------------------------
perform post-convolution grid operations for 3d grid_brick array
------------------------------------------------------------------------- */
void *AmoebaConvolution::post_convolution_3d()
{
int ix,iy,iz,n;
// perform backward FFT
#if DEBUG_AMOEBA
debug_scalar(CFFT1,"POST Convo / PRE FFT");
debug_file(CFFT1,"post.convo.pre.fft");
#endif
fft2->compute(cfft,cfft,FFT3d::BACKWARD);
#if DEBUG_AMOEBA
debug_scalar(CFFT2,"POST Convo / POST FFT");
debug_file(CFFT2,"post.convo.post.fft");
#endif
// copy real portion of 1d complex values into 3d real grid
n = 0;
for (iz = nzlo_in; iz <= nzhi_in; iz++)
for (iy = nylo_in; iy <= nyhi_in; iy++)
for (ix = nxlo_in; ix <= nxhi_in; ix++) {
grid_brick[iz][iy][ix] = cfft[n];
n += 2;
}
// forward comm to populate ghost grid values
#if DEBUG_AMOEBA
debug_scalar(GRIDBRICK_IN,"POST Convo / PRE gridcomm");
debug_file(GRIDBRICK_IN,"post.convo.pre.gridcomm");
#endif
gc->forward_comm(GridComm::PAIR,amoeba,1,sizeof(FFT_SCALAR),which,
gc_buf1,gc_buf2,MPI_FFT_SCALAR);
return (void *) grid_brick;
}
/* ----------------------------------------------------------------------
perform post-convolution grid operations for 4d cgrid_brick array
------------------------------------------------------------------------- */
void *AmoebaConvolution::post_convolution_4d()
{
int ix,iy,iz,n;
// perform backward FFT
#if DEBUG_AMOEBA
debug_scalar(CFFT1,"POST Convo / PRE FFT");
debug_file(CFFT1,"post.convo.pre.fft");
#endif
fft2->compute(cfft,cfft,FFT3d::BACKWARD);
#if DEBUG_AMOEBA
debug_scalar(CFFT2,"POST Convo / POST FFT");
debug_file(CFFT2,"post.convo.post.fft");
#endif
// copy 1d complex values into 4d complex grid
n = 0;
for (iz = nzlo_in; iz <= nzhi_in; iz++)
for (iy = nylo_in; iy <= nyhi_in; iy++)
for (ix = nxlo_in; ix <= nxhi_in; ix++) {
cgrid_brick[iz][iy][ix][0] = cfft[n++];
cgrid_brick[iz][iy][ix][1] = cfft[n++];
}
// forward comm to populate ghost grid values
#if DEBUG_AMOEBA
debug_scalar(GRIDBRICK_IN,"POST Convo / PRE gridcomm");
debug_file(GRIDBRICK_IN,"post.convo.pre.gridcomm");
#endif
gc->forward_comm(GridComm::PAIR,amoeba,2,sizeof(FFT_SCALAR),which,
gc_buf1,gc_buf2,MPI_FFT_SCALAR);
return (void *) cgrid_brick;
}
/* ----------------------------------------------------------------------
convert a sphere in box coords to an ellipsoid in lamda (0-1)
coords and return the tight (axis-aligned) bounding box, does not
preserve vector magnitude
see http://www.loria.fr/~shornus/ellipsoid-bbox.html and
http://yiningkarlli.blogspot.com/2013/02/
bounding-boxes-for-ellipsoidsfigure.html
------------------------------------------------------------------------- */
void AmoebaConvolution::kspacebbox(double r, double *b)
{
double *h = domain->h;
double lx,ly,lz,xy,xz,yz;
lx = h[0]; ly = h[1]; lz = h[2];
yz = h[3]; xz = h[4]; xy = h[5];
b[0] = r*sqrt(ly*ly*lz*lz + ly*ly*xz*xz - 2.0*ly*xy*xz*yz + lz*lz*xy*xy +
xy*xy*yz*yz)/(lx*ly*lz);
b[1] = r*sqrt(lz*lz + yz*yz)/(ly*lz);
b[2] = r/lz;
}
/* ----------------------------------------------------------------------
map nprocs to NX by NY grid as PX by PY procs - return optimal px,py
copy of PPPM::procs2grid2d()
------------------------------------------------------------------------- */
void AmoebaConvolution::procs2grid2d(int nprocs, int nx, int ny, int &px, int &py)
{
// loop thru all possible factorizations of nprocs
// surf = surface area of largest proc sub-domain
// innermost if test minimizes surface area and surface/volume ratio
int bestsurf = 2 * (nx + ny);
int bestboxx = 0;
int bestboxy = 0;
int boxx,boxy,surf,ipx,ipy;
ipx = 1;
while (ipx <= nprocs) {
if (nprocs % ipx == 0) {
ipy = nprocs/ipx;
boxx = nx/ipx;
if (nx % ipx) boxx++;
boxy = ny/ipy;
if (ny % ipy) boxy++;
surf = boxx + boxy;
if (surf < bestsurf ||
(surf == bestsurf && boxx*boxy > bestboxx*bestboxy)) {
bestsurf = surf;
bestboxx = boxx;
bestboxy = boxy;
px = ipx;
py = ipy;
}
}
ipx++;
}
}
#if DEBUG_AMOEBA
/* ----------------------------------------------------------------------
output a scalar value to screen
array = which array is being summed over
---------------------------------------------------------------------- */
void AmoebaConvolution::debug_scalar(int array, const char *label)
{
double sum = 0.0;
if (array == GRIDBRICK_OUT) {
if (flag3d) {
for (int iz = nzlo_out; iz <= nzhi_out; iz++)
for (int iy = nylo_out; iy <= nyhi_out; iy++)
for (int ix = nxlo_out; ix <= nxhi_out; ix++)
sum += grid_brick[iz][iy][ix];
} else {
for (int iz = nzlo_out; iz <= nzhi_out; iz++)
for (int iy = nylo_out; iy <= nyhi_out; iy++)
for (int ix = nxlo_out; ix <= nxhi_out; ix++) {
sum += cgrid_brick[iz][iy][ix][0];
sum += cgrid_brick[iz][iy][ix][1];
}
}
}
if (array == GRIDBRICK_IN) {
if (flag3d) {
for (int iz = nzlo_in; iz <= nzhi_in; iz++)
for (int iy = nylo_in; iy <= nyhi_in; iy++)
for (int ix = nxlo_in; ix <= nxhi_in; ix++)
sum += grid_brick[iz][iy][ix];
} else {
for (int iz = nzlo_in; iz <= nzhi_in; iz++)
for (int iy = nylo_in; iy <= nyhi_in; iy++)
for (int ix = nxlo_in; ix <= nxhi_in; ix++) {
sum += cgrid_brick[iz][iy][ix][0];
sum += cgrid_brick[iz][iy][ix][1];
}
}
}
if (array == FFT) {
if (flag3d) {
for (int i = 0; i < nfft_owned; i++)
sum += grid_fft[i];
} else {
for (int i = 0; i < 2*nfft_owned; i++)
sum += cfft[i];
}
}
if (array == CFFT1) {
for (int i = 0; i < 2*nfft_owned; i++)
sum += cfft[i];
}
if (array == CFFT2) {
for (int i = 0; i < 2*nbrick_owned; i++)
sum += cfft[i];
}
/*
double sumall;
MPI_Allreduce(&sum,&sumall,1,MPI_DOUBLE,MPI_SUM,world);
if (comm->me == 0) printf("%s: %s: %12.8g\n",labels[which],label,sumall);
*/
}
/* ----------------------------------------------------------------------
dump grid values to a file
array = which array is being output
---------------------------------------------------------------------- */
void AmoebaConvolution::debug_file(int array, const char *label)
{
FILE *fp;
int me = comm->me;
int nprocs = comm->nprocs;
// open file
char fname[128];
sprintf(fname,"tmp.%s.%s",labels[which],label);
if (me == 0) fp = fopen(fname,"w");
// file header
// ncol = # of columns, including grid cell ID
bigint ntot = nx * ny * nz;
int ncol;
char *columns;
if (array == CFFT1 || array == CFFT2 || !flag3d) {
ncol = 3;
columns = (char *) "id real imag";
} else {
ncol = 2;
columns = (char *) "id value";
}
char boundstr[9]; // encoding of boundary flags
domain->boundary_string(boundstr);
if (me == 0) {
fprintf(fp,"ITEM: TIMESTEP\n");
fprintf(fp,BIGINT_FORMAT "\n",update->ntimestep);
fprintf(fp,"ITEM: NUMBER OF ATOMS\n");
fprintf(fp,BIGINT_FORMAT "\n",ntot);
fprintf(fp,"ITEM: BOX BOUNDS %s\n",boundstr);
fprintf(fp,"%-1.16e %-1.16e\n",domain->boxlo[0],domain->boxhi[0]);
fprintf(fp,"%-1.16e %-1.16e\n",domain->boxlo[1],domain->boxhi[1]);
fprintf(fp,"%-1.16e %-1.16e\n",domain->boxlo[2],domain->boxhi[2]);
fprintf(fp,"ITEM: ATOMS %s\n",columns);
}
// pack my values
// ngrid = # of grid cells I own
int ngrid;
if (array == GRIDBRICK_IN) ngrid = nbrick_owned;
else if (array == FFT) ngrid = nfft_owned;
else if (array == CFFT1) ngrid = nfft_owned;
else if (array == CFFT2) ngrid = nbrick_owned;
int ngridmax;
MPI_Allreduce(&ngrid,&ngridmax,1,MPI_INT,MPI_MAX,world);
double *buf,*buf2;
memory->create(buf,ncol*ngridmax,"amoeba:buf");
memory->create(buf2,ncol*ngridmax,"amoeba:buf2");
ngrid = 0;
if (array == GRIDBRICK_IN) {
if (flag3d) {
for (int iz = nzlo_in; iz <= nzhi_in; iz++)
for (int iy = nylo_in; iy <= nyhi_in; iy++)
for (int ix = nxlo_in; ix <= nxhi_in; ix++) {
int id = iz*ny*nx + iy*nx + ix + 1;
buf[ncol*ngrid] = id;
buf[ncol*ngrid+1] = grid_brick[iz][iy][ix];
ngrid++;
}
} else {
for (int iz = nzlo_in; iz <= nzhi_in; iz++)
for (int iy = nylo_in; iy <= nyhi_in; iy++)
for (int ix = nxlo_in; ix <= nxhi_in; ix++) {
int id = iz*ny*nx + iy*nx + ix + 1;
buf[ncol*ngrid] = id;
buf[ncol*ngrid+1] = cgrid_brick[iz][iy][ix][0];
buf[ncol*ngrid+2] = cgrid_brick[iz][iy][ix][1];
ngrid++;
}
}
}
if (array == FFT) {
if (flag3d) {
int m = 0;
for (int iz = nzlo_fft; iz <= nzhi_fft; iz++)
for (int iy = nylo_fft; iy <= nyhi_fft; iy++)
for (int ix = nxlo_fft; ix <= nxhi_fft; ix++) {
int id = iz*ny*nx + iy*nx + ix + 1;
buf[ncol*ngrid] = id;
buf[ncol*ngrid+1] = grid_fft[m++];
ngrid++;
}
} else {
int m = 0;
for (int iz = nzlo_fft; iz <= nzhi_fft; iz++)
for (int iy = nylo_fft; iy <= nyhi_fft; iy++)
for (int ix = nxlo_fft; ix <= nxhi_fft; ix++) {
int id = iz*ny*nx + iy*nx + ix + 1;
buf[ncol*ngrid] = id;
buf[ncol*ngrid+1] = cfft[m++];
buf[ncol*ngrid+2] = cfft[m++];
ngrid++;
}
}
}
if (array == CFFT1) {
int m = 0;
for (int iz = nzlo_fft; iz <= nzhi_fft; iz++)
for (int iy = nylo_fft; iy <= nyhi_fft; iy++)
for (int ix = nxlo_fft; ix <= nxhi_fft; ix++) {
int id = iz*ny*nx + iy*nx + ix + 1;
buf[ncol*ngrid] = id;
buf[ncol*ngrid+1] = cfft[m++];
buf[ncol*ngrid+2] = cfft[m++];
ngrid++;
}
}
if (array == CFFT2) {
int m = 0;
for (int iz = nzlo_in; iz <= nzhi_in; iz++)
for (int iy = nylo_in; iy <= nyhi_in; iy++)
for (int ix = nxlo_in; ix <= nxhi_in; ix++) {
int id = iz*ny*nx + iy*nx + ix + 1;
buf[ncol*ngrid] = id;
buf[ncol*ngrid+1] = cfft[m++];
buf[ncol*ngrid+2] = cfft[m++];
ngrid++;
}
}
// proc 0 outputs values
// pings other procs, send/recv of their values
int tmp,nlines;
MPI_Request request;
MPI_Status status;
if (me == 0) {
for (int iproc = 0; iproc < nprocs; iproc++) {
if (iproc) {
MPI_Irecv(buf,ngridmax*ncol,MPI_DOUBLE,iproc,0,world,&request);
MPI_Send(&tmp,0,MPI_INT,me+iproc,0,world);
MPI_Wait(&request,&status);
MPI_Get_count(&status,MPI_DOUBLE,&nlines);
nlines /= ncol;
} else nlines = ngrid;
int n = 0;
for (int m = 0; m < nlines; m++) {
if (ncol == 2)
fprintf(fp,"%d %12.8g\n",(int) buf[n],buf[n+1]);
else if (ncol == 3)
fprintf(fp,"%d %12.8g %12.8g\n",(int ) buf[n],buf[n+1],buf[n+2]);
n += ncol;
}
}
} else {
MPI_Recv(&tmp,0,MPI_INT,0,0,world,MPI_STATUS_IGNORE);
MPI_Rsend(buf,ngrid*ncol,MPI_DOUBLE,0,0,world);
}
// close file
if (me == 0) fclose(fp);
// clean up
memory->destroy(buf);
memory->destroy(buf2);
}
#endif

View File

@ -0,0 +1,85 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/ 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.
------------------------------------------------------------------------- */
#ifndef LMP_AMOEBA_CONVOLUTION_H
#define LMP_AMOEBA_CONVOLUTION_H
#include "pointers.h"
#ifdef FFT_SINGLE
typedef float FFT_SCALAR;
#define LMP_FFT_PREC "single"
#define MPI_FFT_SCALAR MPI_FLOAT
#else
typedef double FFT_SCALAR;
#define LMP_FFT_PREC "double"
#define MPI_FFT_SCALAR MPI_DOUBLE
#endif
namespace LAMMPS_NS {
class AmoebaConvolution : protected Pointers {
public:
int nx, ny, nz;
int order;
int nfft_owned; // owned grid points in FFT decomp
int nxlo_in, nxhi_in, nylo_in, nyhi_in, nzlo_in, nzhi_in;
int nxlo_out, nxhi_out, nylo_out, nyhi_out, nzlo_out, nzhi_out;
int nxlo_fft, nxhi_fft, nylo_fft, nyhi_fft, nzlo_fft, nzhi_fft;
bigint nfft_global; // nx * ny * nz
double *grid_brick_start; // lower left corner of (c)grid_brick data
AmoebaConvolution(class LAMMPS *, class Pair *, int, int, int, int, int);
~AmoebaConvolution();
void *zero();
FFT_SCALAR *pre_convolution();
void *post_convolution();
private:
int which; // caller name for convolution being performed
int flag3d; // 1 if using 3d grid_brick, 0 for 4d cgrid_brick
int nbrick_owned; // owned grid points in brick decomp
int nbrick_ghosts; // owned + ghost brick grid points
int ngrid_either; // max of nbrick_owned or nfft_owned
class Pair *amoeba;
class FFT3d *fft1, *fft2;
class GridComm *gc;
class Remap *remap;
double ***grid_brick; // 3d real brick grid with ghosts
double ****cgrid_brick; // 4d complex brick grid with ghosts
FFT_SCALAR *grid_fft; // 3d FFT grid as 1d vector
FFT_SCALAR *cfft; // 3d complex FFT grid as 1d vector
double *gc_buf1, *gc_buf2; // buffers for GridComm
double *remap_buf; // buffer for Remap
void *zero_3d();
void *zero_4d();
FFT_SCALAR *pre_convolution_3d();
FFT_SCALAR *pre_convolution_4d();
void *post_convolution_3d();
void *post_convolution_4d();
void kspacebbox(double, double *);
void procs2grid2d(int, int, int, int &, int &);
// DEBUG
void debug_scalar(int, const char *);
void debug_file(int, const char *);
};
} // namespace LAMMPS_NS
#endif

View File

@ -0,0 +1,422 @@
// clang-format off
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/ 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.
------------------------------------------------------------------------- */
#include "pair_amoeba.h"
#include "amoeba_convolution.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "fft3d_wrap.h"
#include "math_const.h"
#include "math_special.h"
#include "memory.h"
#include "neigh_list.h"
#include <cmath>
using namespace LAMMPS_NS;
using namespace MathConst;
using MathSpecial::cube;
using MathSpecial::powint;
enum{VDWL,REPULSE,QFER,DISP,MPOLE,POLAR,USOLV,DISP_LONG,MPOLE_LONG,POLAR_LONG};
/* ----------------------------------------------------------------------
dispersion = Ewald dispersion
adapted from Tinker edisp1d() routine
------------------------------------------------------------------------- */
void PairAmoeba::dispersion()
{
// set cutoffs, taper coeffs, and PME params
if (use_dewald) choose(DISP_LONG);
else choose(DISP);
// owned atoms
int nlocal = atom->nlocal;
// compute the real space portion of the Ewald summation
if (disp_rspace_flag) dispersion_real();
// compute the reciprocal space part of the Ewald summation
if (disp_kspace_flag) dispersion_kspace();
// compute the self-energy portion of the Ewald summation
int itype,iclass;
double term;
for (int i = 0; i < nlocal; i++) {
itype = amtype[i];
iclass = amtype2class[itype];
term = powint(aewald,6) / 12.0;
edisp += term*csix[iclass]*csix[iclass];
}
}
/* ----------------------------------------------------------------------
dispersion_real = real-space portion of Ewald dispersion
adapted from Tinker edreal1d() routine
------------------------------------------------------------------------- */
void PairAmoeba::dispersion_real()
{
int i,j,ii,jj,itype,jtype,iclass,jclass;
double xi,yi,zi;
double xr,yr,zr;
double e,de;
double ci,ck;
double r,r2,r6,r7;
double ai,ai2;
double ak,ak2;
double di,di2,di3,di4,di5;
double dk,dk2,dk3;
double ti,ti2;
double tk,tk2;
double expi,expk;
double damp3,damp5;
double damp,ddamp;
double ralpha2,scale;
double expterm,term;
double expa,rterm;
double dedx,dedy,dedz;
double vxx,vyx,vzx;
double vyy,vzy,vzz;
double factor_disp;
int inum,jnum;
int *ilist,*jlist,*numneigh,**firstneigh;
// owned atoms
double **x = atom->x;
double **f = atom->f;
// neigh list
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// compute the real space portion of the Ewald summation
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
itype = amtype[i];
iclass = amtype2class[itype];
jlist = firstneigh[i];
jnum = numneigh[i];
ci = csix[iclass];
ai = adisp[iclass];
xi = x[i][0];
yi = x[i][1];
zi = x[i][2];
// decide whether to compute the current interaction
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_disp = special_disp[sbmask15(j)];
j &= NEIGHMASK15;
xr = xi - x[j][0];
yr = yi - x[j][1];
zr = zi - x[j][2];
r2 = xr*xr + yr*yr + zr*zr;
if (r2 > off2) continue;
// compute the energy contribution for this interaction
jtype = amtype[j];
jclass = amtype2class[jtype];
ck = csix[jclass];
ak = adisp[jclass];
r6 = r2*r2*r2;
ralpha2 = r2 * aewald*aewald;
term = 1.0 + ralpha2 + 0.5*ralpha2*ralpha2;
expterm = exp(-ralpha2);
expa = expterm * term;
// find the damping factor for the dispersion interaction
r = sqrt(r2);
r7 = r6 * r;
di = ai * r;
di2 = di * di;
di3 = di * di2;
dk = ak * r;
expi = exp(-di);
expk = exp(-dk);
if (ai != ak) {
ai2 = ai * ai;
ak2 = ak * ak;
dk2 = dk * dk;
dk3 = dk * dk2;
ti = ak2 / (ak2-ai2);
ti2 = ti * ti;
tk = ai2 / (ai2-ak2);
tk2 = tk * tk;
damp3 = 1.0 - ti2*(1.0+di+0.5*di2)*expi - tk2*(1.0+dk+0.5*dk2)*expk -
2.0*ti2*tk*(1.0+di)*expi - 2.0*tk2*ti*(1.0+dk)*expk;
damp5 = 1.0 - ti2*(1.0+di+0.5*di2+di3/6.0)*expi -
tk2*(1.0+dk+0.5*dk2 + dk3/6.0)*expk -
2.0*ti2*tk*(1.0+di+di2/3.0)*expi - 2.0*tk2*ti*(1.0+dk+dk2/3.0)*expk;
ddamp = 0.25 * di2 * ti2 * ai * expi * (r*ai+4.0*tk-1.0) +
0.25 * dk2 * tk2 * ak * expk * (r*ak+4.0*ti-1.0);
} else {
di4 = di2 * di2;
di5 = di2 * di3;
damp3 = 1.0 - (1.0+di+0.5*di2 + 7.0*di3/48.0+di4/48.0)*expi;
damp5 = 1.0 - (1.0+di+0.5*di2 + di3/6.0+di4/24.0+di5/144.0)*expi;
ddamp = ai * expi * (di5-3.0*di3-3.0*di2) / 96.0;
}
damp = 1.5*damp5 - 0.5*damp3;
// apply damping and scaling factors for this interaction
scale = factor_disp * damp*damp;
scale = scale - 1.0;
e = -ci * ck * (expa+scale) / r6;
rterm = -cube(ralpha2) * expterm / r;
de = -6.0*e/r2 - ci*ck*rterm/r7 - 2.0*ci*ck*factor_disp*damp*ddamp/r7;
edisp += e;
// increment the damped dispersion derivative components
dedx = de * xr;
dedy = de * yr;
dedz = de * zr;
f[i][0] -= dedx;
f[i][1] -= dedy;
f[i][2] -= dedz;
f[j][0] += dedx;
f[j][1] += dedy;
f[j][2] += dedz;
// increment the internal virial tensor components
if (vflag_global) {
vxx = xr * dedx;
vyx = yr * dedx;
vzx = zr * dedx;
vyy = yr * dedy;
vzy = zr * dedy;
vzz = zr * dedz;
virdisp[0] -= vxx;
virdisp[1] -= vyy;
virdisp[2] -= vzz;
virdisp[3] -= vyx;
virdisp[4] -= vzx;
virdisp[5] -= vzy;
}
}
}
}
/* ----------------------------------------------------------------------
dispersion_kspace = KSpace portion of Ewald dispersion
adapted from Tinker edrecip1d() routine
------------------------------------------------------------------------- */
void PairAmoeba::dispersion_kspace()
{
int i,j,k,m,n,ib,jb,kb,itype,iclass;
int nhalf1,nhalf2,nhalf3;
int nxlo,nxhi,nylo,nyhi,nzlo,nzhi;
double e,fi,denom,scale;
double r1,r2,r3;
double h1,h2,h3;
double term,vterm;
double expterm;
double erfcterm;
double hsq,struc2;
double h,hhh,b,bfac;
double term1,denom0;
double fac1,fac2,fac3;
double de1,de2,de3;
double dt1,dt2,dt3;
double t1,t2,t3;
// return if the Ewald coefficient is zero
if (aewald < 1.0e-6) return;
// owned atoms
double **f = atom->f;
int nlocal = atom->nlocal;
double volbox = domain->prd[0] * domain->prd[1] * domain->prd[2];
// FFT moduli pre-computations
// set igrid for each atom and its B-spline coeffs
nfft1 = d_kspace->nx;
nfft2 = d_kspace->ny;
nfft3 = d_kspace->nz;
bsorder = d_kspace->order;
moduli();
bspline_fill();
// gridpre = my portion of 3d grid in brick decomp w/ ghost values
// zeroed by zero()
double ***gridpre = (double ***) d_kspace->zero();
// map atoms to grid
grid_disp(gridpre);
// pre-convolution operations including forward FFT
// gridfft = my portion of complex 3d grid in FFT decomposition
double *gridfft = d_kspace->pre_convolution();
// ---------------------
// convolution operation
// ---------------------
nhalf1 = (nfft1+1) / 2;
nhalf2 = (nfft2+1) / 2;
nhalf3 = (nfft3+1) / 2;
nxlo = d_kspace->nxlo_fft;
nxhi = d_kspace->nxhi_fft;
nylo = d_kspace->nylo_fft;
nyhi = d_kspace->nyhi_fft;
nzlo = d_kspace->nzlo_fft;
nzhi = d_kspace->nzhi_fft;
bfac = MY_PI / aewald;
fac1 = 2.0*pow(MY_PI,3.5);
fac2 = cube(aewald);
fac3 = -2.0*aewald*MY_PI*MY_PI;
denom0 = (6.0*volbox)/pow(MY_PI,1.5);
n = 0;
for (k = nzlo; k <= nzhi; k++) {
for (j = nylo; j <= nyhi; j++) {
for (i = nxlo; i <= nxhi; i++) {
r1 = (i >= nhalf1) ? i-nfft1 : i;
r2 = (j >= nhalf2) ? j-nfft2 : j;
r3 = (k >= nhalf3) ? k-nfft3 : k;
h1 = recip[0][0]*r1 + recip[0][1]*r2 + recip[0][2]*r3; // matvec
h2 = recip[1][0]*r1 + recip[1][1]*r2 + recip[1][2]*r3;
h3 = recip[2][0]*r1 + recip[2][1]*r2 + recip[2][2]*r3;
hsq = h1*h1 + h2*h2 + h3*h3;
h = sqrt(hsq);
b = h*bfac;
hhh = h*hsq;
term = -b*b;
expterm = 0.0;
erfcterm = erfc(b);
denom = denom0*bsmod1[i]*bsmod2[j]*bsmod3[k];
if (term > -50.0 && hsq != 0.0) {
expterm = exp(term);
erfcterm = erfc(b);
term1 = fac1*erfcterm*hhh + expterm*(fac2 + fac3*hsq);
struc2 = gridfft[n]*gridfft[n] + gridfft[n+1]*gridfft[n+1];
e = -(term1 / denom) * struc2;
edisp += e;
if (vflag_global) {
vterm = 3.0 * (fac1*erfcterm*h + fac3*expterm) * struc2/denom;
virdisp[0] -= h1*h1*vterm - e;
virdisp[1] -= h2*h2*vterm - e;
virdisp[2] -= h3*h3*vterm - e;
virdisp[3] -= h1*h2*vterm;
virdisp[4] -= h1*h3*vterm;
virdisp[5] -= h2*h3*vterm;
}
} else term1 = 0.0;
scale = -term1 / denom;
gridfft[n] *= scale;
gridfft[n+1] *= scale;
n += 2;
}
}
}
// post-convolution operations including backward FFT
// gridppost = my portion of 3d grid in brick decomp w/ ghost values
double ***gridpost = (double ***) d_kspace->post_convolution();
// get first derivatives of the reciprocal space energy
int nlpts = (bsorder-1) / 2;
for (m = 0; m < nlocal; m++) {
itype = amtype[m];
iclass = amtype2class[itype];
de1 = de2 = de3 = 0.0;
k = igrid[m][2] - nlpts;
for (kb = 0; kb < bsorder; kb++) {
t3 = thetai3[m][kb][0];
dt3 = nfft3 * thetai3[m][kb][1];
j = igrid[m][1] - nlpts;
for (jb = 0; jb < bsorder; jb++) {
t2 = thetai2[m][jb][0];
dt2 = nfft2 * thetai2[m][jb][1];
i = igrid[m][0] - nlpts;
for (ib = 0; ib < bsorder; ib++) {
t1 = thetai1[m][ib][0];
dt1 = nfft1 * thetai1[m][ib][1];
term = gridpost[k][j][i];
de1 += 2.0*term*dt1*t2*t3;
de2 += 2.0*term*dt2*t1*t3;
de3 += 2.0*term*dt3*t1*t2;
i++;
}
j++;
}
k++;
}
fi = csix[iclass];
f[m][0] -= fi * (recip[0][0]*de1 + recip[0][1]*de2 + recip[0][2]*de3);
f[m][1] -= fi * (recip[1][0]*de1 + recip[1][1]*de2 + recip[1][2]*de3);
f[m][2] -= fi * (recip[2][0]*de1 + recip[2][1]*de2 + recip[2][2]*de3);
}
// account for the energy and virial correction terms
term = csixpr * aewald*aewald*aewald / denom0;
if (comm->me == 0) {
edisp -= term;
if (vflag_global) {
virdisp[0] -= term;
virdisp[1] -= term;
virdisp[2] -= term;
}
}
}

1402
src/AMOEBA/amoeba_file.cpp Normal file

File diff suppressed because it is too large Load Diff

210
src/AMOEBA/amoeba_hal.cpp Normal file
View File

@ -0,0 +1,210 @@
// clang-format off
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/ 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.
------------------------------------------------------------------------- */
#include "pair_amoeba.h"
#include "atom.h"
#include "error.h"
#include "math_special.h"
#include "neigh_list.h"
#include <cmath>
using namespace LAMMPS_NS;
using MathSpecial::square;
using MathSpecial::cube;
using MathSpecial::powint;
enum{VDWL,REPULSE,QFER,DISP,MPOLE,POLAR,USOLV,DISP_LONG,MPOLE_LONG,POLAR_LONG};
/* ----------------------------------------------------------------------
hal = buffered 14-7 Vdwl interactions
adapted from Tinker ehal1c() routine
------------------------------------------------------------------------- */
void PairAmoeba::hal()
{
int i,j,ii,jj,itype,jtype,iclass,jclass,iv,jv;
int special_which;
double e,de,eps;
double rv,rv7;
double xi,yi,zi;
double xr,yr,zr;
double redi,rediv;
double redj,redjv;
double dedx,dedy,dedz;
double rho,tau,tau7;
double dtau,gtau;
double taper,dtaper;
double rik,rik2,rik3;
double rik4,rik5;
double rik6,rik7;
double vxx,vyy,vzz;
double vyx,vzx,vzy;
double factor_hal;
int inum,jnum;
int *ilist,*jlist,*numneigh,**firstneigh;
// set cutoffs and taper coeffs
choose(VDWL);
// owned atoms
double **f = atom->f;
// neigh list
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// find van der Waals energy and derivatives via neighbor list
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
itype = amtype[i];
iclass = amtype2class[itype];
jlist = firstneigh[i];
jnum = numneigh[i];
redi = kred[iclass];
rediv = 1.0 - redi;
xi = xred[i][0];
yi = xred[i][1];
zi = xred[i][2];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
special_which = sbmask15(j);
factor_hal = special_hal[special_which];
if (factor_hal == 0.0) continue;
j &= NEIGHMASK15;
xr = xi - xred[j][0];
yr = yi - xred[j][1];
zr = zi - xred[j][2];
rik2 = xr*xr + yr*yr + zr*zr;
if (rik2 > off2) continue;
// compute the energy contribution for this interaction
jtype = amtype[j];
jclass = amtype2class[jtype];
// check for an interaction distance less than the cutoff
// special_which = 3 is a 1-4 neighbor with its own sigma,epsilon
rik = sqrt(rik2);
rv = radmin[iclass][jclass];
eps = epsilon[iclass][jclass];
if (special_which == 3) {
rv = radmin4[iclass][jclass];
eps = epsilon4[iclass][jclass];
}
eps *= factor_hal;
rv7 = powint(rv,7);
rik6 = cube(rik2);
rik7 = rik6 * rik;
rho = rik7 + ghal*rv7;
tau = (dhal+1.0) / (rik + dhal*rv);
tau7 = powint(tau,7);
dtau = tau / (dhal+1.0);
gtau = eps*tau7*rik6*(ghal+1.0)*square(rv7/rho);
e = eps*tau7*rv7*((ghal+1.0)*rv7/rho-2.0);
de = -7.0 * (dtau*e+gtau);
// use energy switching if near the cutoff distance
if (rik2 > cut2) {
rik3 = rik2 * rik;
rik4 = rik2 * rik2;
rik5 = rik2 * rik3;
taper = c5*rik5 + c4*rik4 + c3*rik3 + c2*rik2 + c1*rik + c0;
dtaper = 5.0*c5*rik4 + 4.0*c4*rik3 + 3.0*c3*rik2 + 2.0*c2*rik + c1;
de = e*dtaper + de*taper;
e *= taper;
}
ehal += e;
// find the chain rule terms for derivative components
de = de / rik;
dedx = de * xr;
dedy = de * yr;
dedz = de * zr;
// increment the total van der Waals energy and derivatives
// if jv < 0, trigger an error, needed H-bond partner is missing
iv = red2local[i];
jv = red2local[j];
if (jv < 0)
error->one(FLERR,"AMOEBA hal cannot find H bond partner - "
"ghost comm is too short");
if (i == iv) {
f[i][0] -= dedx;
f[i][1] -= dedy;
f[i][2] -= dedz;
} else {
f[i][0] -= dedx*redi;
f[i][1] -= dedy*redi;
f[i][2] -= dedz*redi;
f[iv][0] -= dedx*rediv;
f[iv][1] -= dedy*rediv;
f[iv][2] -= dedz*rediv;
}
if (j == jv) {
f[j][0] += dedx;
f[j][1] += dedy;
f[j][2] += dedz;
} else {
redj = kred[jclass];
redjv = 1.0 - redj;
f[j][0] += dedx*redj;
f[j][1] += dedy*redj;
f[j][2] += dedz*redj;
f[jv][0] += dedx*redjv;
f[jv][1] += dedy*redjv;
f[jv][2] += dedz*redjv;
}
// increment the internal virial tensor components
if (vflag_global) {
vxx = xr * dedx;
vyx = yr * dedx;
vzx = zr * dedx;
vyy = yr * dedy;
vzy = zr * dedy;
vzz = zr * dedz;
virhal[0] -= vxx;
virhal[1] -= vyy;
virhal[2] -= vzz;
virhal[3] -= vyx;
virhal[4] -= vzx;
virhal[5] -= vzy;
}
}
}
}

1702
src/AMOEBA/amoeba_induce.cpp Normal file

File diff suppressed because it is too large Load Diff

1239
src/AMOEBA/amoeba_kspace.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,985 @@
// clang-format off
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/ 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.
------------------------------------------------------------------------- */
#include "pair_amoeba.h"
#include "amoeba_convolution.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "fft3d_wrap.h"
#include "math_const.h"
#include "math_special.h"
#include "memory.h"
#include "neigh_list.h"
#include <cmath>
#include <cstring>
using namespace LAMMPS_NS;
using namespace MathConst;
using MathSpecial::square;
enum{FIELD,ZRSD,TORQUE,UFLD}; // reverse comm
enum{VDWL,REPULSE,QFER,DISP,MPOLE,POLAR,USOLV,DISP_LONG,MPOLE_LONG,POLAR_LONG};
#ifdef FFT_SINGLE
#define ZEROF 0.0f
#define ONEF 1.0f
#else
#define ZEROF 0.0
#define ONEF 1.0
#endif
/* ----------------------------------------------------------------------
multipole = multipole interactions
adapted from Tinker empole1d() routine
------------------------------------------------------------------------- */
void PairAmoeba::multipole()
{
double e;
double felec;
double term,fterm;
double ci;
double dix,diy,diz;
double qixx,qixy,qixz,qiyy,qiyz,qizz;
double cii,dii,qii;
// set cutoffs, taper coeffs, and PME params
if (use_ewald) choose(MPOLE_LONG);
else choose(MPOLE);
// owned atoms
const int nlocal = atom->nlocal;
// zero repulsion torque on owned + ghost atoms
const int nall = nlocal + atom->nghost;
for (int i = 0; i < nall; i++) {
tq[i][0] = 0.0;
tq[i][1] = 0.0;
tq[i][2] = 0.0;
}
// set the energy unit conversion factor
felec = electric / am_dielectric;
// compute the real space part of the Ewald summation
if (mpole_rspace_flag) multipole_real();
// compute the reciprocal space part of the Ewald summation
if (mpole_kspace_flag) multipole_kspace();
// compute the Ewald self-energy term over all the atoms
term = 2.0 * aewald * aewald;
fterm = -felec * aewald / MY_PIS;
for (int i = 0; i < nlocal; i++) {
ci = rpole[i][0];
dix = rpole[i][1];
diy = rpole[i][2];
diz = rpole[i][3];
qixx = rpole[i][4];
qixy = rpole[i][5];
qixz = rpole[i][6];
qiyy = rpole[i][8];
qiyz = rpole[i][9];
qizz = rpole[i][12];
cii = ci*ci;
dii = dix*dix + diy*diy + diz*diz;
qii = 2.0*(qixy*qixy+qixz*qixz+qiyz*qiyz) +
qixx*qixx + qiyy*qiyy + qizz*qizz;
e = fterm * (cii + term*(dii/3.0+2.0*term*qii/5.0));
empole += e;
}
}
/* ----------------------------------------------------------------------
multipole_real = real-space portion of mulipole interactions
adapted from Tinker emreal1d() routine
------------------------------------------------------------------------- */
void PairAmoeba::multipole_real()
{
int i,j,k,itype,jtype,iclass,jclass;
int ii,jj;
int ix,iy,iz;
double e,de,felec;
double bfac;
double alsq2,alsq2n;
double exp2a,ralpha;
double scalek;
double xi,yi,zi;
double xr,yr,zr;
double xix,yix,zix;
double xiy,yiy,ziy;
double xiz,yiz,ziz;
double r,r2,rr1,rr3;
double rr5,rr7,rr9,rr11;
double rr1i,rr3i,rr5i,rr7i;
double rr1k,rr3k,rr5k,rr7k;
double rr1ik,rr3ik,rr5ik;
double rr7ik,rr9ik,rr11ik;
double ci,dix,diy,diz;
double qixx,qixy,qixz;
double qiyy,qiyz,qizz;
double ck,dkx,dky,dkz;
double qkxx,qkxy,qkxz;
double qkyy,qkyz,qkzz;
double dir,dkr,dik,qik;
double qix,qiy,qiz,qir;
double qkx,qky,qkz,qkr;
double diqk,dkqi,qiqk;
double dirx,diry,dirz;
double dkrx,dkry,dkrz;
double dikx,diky,dikz;
double qirx,qiry,qirz;
double qkrx,qkry,qkrz;
double qikx,qiky,qikz;
double qixk,qiyk,qizk;
double qkxi,qkyi,qkzi;
double qikrx,qikry,qikrz;
double qkirx,qkiry,qkirz;
double diqkx,diqky,diqkz;
double dkqix,dkqiy,dkqiz;
double diqkrx,diqkry,diqkrz;
double dkqirx,dkqiry,dkqirz;
double dqikx,dqiky,dqikz;
double corei,corek;
double vali,valk;
double alphai,alphak;
double term1,term2,term3;
double term4,term5,term6;
double term1i,term2i,term3i;
double term1k,term2k,term3k;
double term1ik,term2ik,term3ik;
double term4ik,term5ik;
double frcx,frcy,frcz;
double vxx,vyy,vzz;
double vxy,vxz,vyz;
double factor_mpole;
double ttmi[3],ttmk[3];
double fix[3],fiy[3],fiz[3];
double dmpi[9],dmpj[9];
double dmpij[11];
double bn[6];
int inum,jnum;
int *ilist,*jlist,*numneigh,**firstneigh;
// owned atoms
double *pval = atom->dvector[index_pval];
double **x = atom->x;
double **f = atom->f;
int nlocal = atom->nlocal;
// neigh list
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// set conversion factor, cutoff and switching coefficients
felec = electric / am_dielectric;
// DEBUG
//int count = 0;
//int imin,imax;
// compute the real space portion of the Ewald summation
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
itype = amtype[i];
iclass = amtype2class[itype];
jlist = firstneigh[i];
jnum = numneigh[i];
xi = x[i][0];
yi = x[i][1];
zi = x[i][2];
ci = rpole[i][0];
dix = rpole[i][1];
diy = rpole[i][2];
diz = rpole[i][3];
qixx = rpole[i][4];
qixy = rpole[i][5];
qixz = rpole[i][6];
qiyy = rpole[i][8];
qiyz = rpole[i][9];
qizz = rpole[i][12];
if (!amoeba) {
corei = pcore[iclass];
alphai = palpha[iclass];
vali = pval[i];
}
// evaluate all sites within the cutoff distance
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_mpole = special_mpole[sbmask15(j)];
j &= NEIGHMASK15;
xr = x[j][0] - xi;
yr = x[j][1] - yi;
zr = x[j][2] - zi;
r2 = xr*xr + yr*yr + zr*zr;
if (r2 > off2) continue;
// DEBUG
//imin = MIN(atom->tag[i],atom->tag[j]);
//imax = MAX(atom->tag[i],atom->tag[j]);
jtype = amtype[j];
jclass = amtype2class[jtype];
r = sqrt(r2);
ck = rpole[j][0];
dkx = rpole[j][1];
dky = rpole[j][2];
dkz = rpole[j][3];
qkxx = rpole[j][4];
qkxy = rpole[j][5];
qkxz = rpole[j][6];
qkyy = rpole[j][8];
qkyz = rpole[j][9];
qkzz = rpole[j][12];
// intermediates involving moments and separation distance
dir = dix*xr + diy*yr + diz*zr;
qix = qixx*xr + qixy*yr + qixz*zr;
qiy = qixy*xr + qiyy*yr + qiyz*zr;
qiz = qixz*xr + qiyz*yr + qizz*zr;
qir = qix*xr + qiy*yr + qiz*zr;
dkr = dkx*xr + dky*yr + dkz*zr;
qkx = qkxx*xr + qkxy*yr + qkxz*zr;
qky = qkxy*xr + qkyy*yr + qkyz*zr;
qkz = qkxz*xr + qkyz*yr + qkzz*zr;
qkr = qkx*xr + qky*yr + qkz*zr;
dik = dix*dkx + diy*dky + diz*dkz;
qik = qix*qkx + qiy*qky + qiz*qkz;
diqk = dix*qkx + diy*qky + diz*qkz;
dkqi = dkx*qix + dky*qiy + dkz*qiz;
qiqk = 2.0*(qixy*qkxy+qixz*qkxz+qiyz*qkyz) +
qixx*qkxx + qiyy*qkyy + qizz*qkzz;
// additional intermediates involving moments and distance
dirx = diy*zr - diz*yr;
diry = diz*xr - dix*zr;
dirz = dix*yr - diy*xr;
dkrx = dky*zr - dkz*yr;
dkry = dkz*xr - dkx*zr;
dkrz = dkx*yr - dky*xr;
dikx = diy*dkz - diz*dky;
diky = diz*dkx - dix*dkz;
dikz = dix*dky - diy*dkx;
qirx = qiz*yr - qiy*zr;
qiry = qix*zr - qiz*xr;
qirz = qiy*xr - qix*yr;
qkrx = qkz*yr - qky*zr;
qkry = qkx*zr - qkz*xr;
qkrz = qky*xr - qkx*yr;
qikx = qky*qiz - qkz*qiy;
qiky = qkz*qix - qkx*qiz;
qikz = qkx*qiy - qky*qix;
qixk = qixx*qkx + qixy*qky + qixz*qkz;
qiyk = qixy*qkx + qiyy*qky + qiyz*qkz;
qizk = qixz*qkx + qiyz*qky + qizz*qkz;
qkxi = qkxx*qix + qkxy*qiy + qkxz*qiz;
qkyi = qkxy*qix + qkyy*qiy + qkyz*qiz;
qkzi = qkxz*qix + qkyz*qiy + qkzz*qiz;
qikrx = qizk*yr - qiyk*zr;
qikry = qixk*zr - qizk*xr;
qikrz = qiyk*xr - qixk*yr;
qkirx = qkzi*yr - qkyi*zr;
qkiry = qkxi*zr - qkzi*xr;
qkirz = qkyi*xr - qkxi*yr;
diqkx = dix*qkxx + diy*qkxy + diz*qkxz;
diqky = dix*qkxy + diy*qkyy + diz*qkyz;
diqkz = dix*qkxz + diy*qkyz + diz*qkzz;
dkqix = dkx*qixx + dky*qixy + dkz*qixz;
dkqiy = dkx*qixy + dky*qiyy + dkz*qiyz;
dkqiz = dkx*qixz + dky*qiyz + dkz*qizz;
diqkrx = diqkz*yr - diqky*zr;
diqkry = diqkx*zr - diqkz*xr;
diqkrz = diqky*xr - diqkx*yr;
dkqirx = dkqiz*yr - dkqiy*zr;
dkqiry = dkqix*zr - dkqiz*xr;
dkqirz = dkqiy*xr - dkqix*yr;
dqikx = diy*qkz - diz*qky + dky*qiz - dkz*qiy -
2.0*(qixy*qkxz+qiyy*qkyz+qiyz*qkzz - qixz*qkxy-qiyz*qkyy-qizz*qkyz);
dqiky = diz*qkx - dix*qkz + dkz*qix - dkx*qiz -
2.0*(qixz*qkxx+qiyz*qkxy+qizz*qkxz - qixx*qkxz-qixy*qkyz-qixz*qkzz);
dqikz = dix*qky - diy*qkx + dkx*qiy - dky*qix -
2.0*(qixx*qkxy+qixy*qkyy+qixz*qkyz - qixy*qkxx-qiyy*qkxy-qiyz*qkxz);
// get reciprocal distance terms for this interaction
rr1 = felec / r;
rr3 = rr1 / r2;
rr5 = 3.0 * rr3 / r2;
rr7 = 5.0 * rr5 / r2;
rr9 = 7.0 * rr7 / r2;
rr11 = 9.0 * rr9 / r2;
// calculate the real space Ewald error function terms
ralpha = aewald * r;
bn[0] = erfc(ralpha) / r;
alsq2 = 2.0 * aewald*aewald;
alsq2n = 0.0;
if (aewald > 0.0) alsq2n = 1.0 / (MY_PIS*aewald);
exp2a = exp(-ralpha*ralpha);
for (k = 1; k < 6; k++) {
bfac = (double) (k+k-1);
alsq2n = alsq2 * alsq2n;
bn[k] = (bfac*bn[k-1]+alsq2n*exp2a) / r2;
}
for (k = 0; k < 6; k++) bn[k] *= felec;
// find damped multipole intermediates and energy value
if (!amoeba) {
corek = pcore[jclass];
alphak = palpha[jclass];
valk = pval[j];
term1 = corei*corek;
term1i = corek*vali;
term2i = corek*dir;
term3i = corek*qir;
term1k = corei*valk;
term2k = -corei*dkr;
term3k = corei*qkr;
term1ik = vali*valk;
term2ik = valk*dir - vali*dkr + dik;
term3ik = vali*qkr + valk*qir - dir*dkr + 2.0*(dkqi-diqk+qiqk);
term4ik = dir*qkr - dkr*qir - 4.0*qik;
term5ik = qir*qkr;
damppole(r,11,alphai,alphak,dmpi,dmpj,dmpij);
scalek = factor_mpole;
rr1i = bn[0] - (1.0-scalek*dmpi[0])*rr1;
rr3i = bn[1] - (1.0-scalek*dmpi[2])*rr3;
rr5i = bn[2] - (1.0-scalek*dmpi[4])*rr5;
rr7i = bn[3] - (1.0-scalek*dmpi[6])*rr7;
rr1k = bn[0] - (1.0-scalek*dmpj[0])*rr1;
rr3k = bn[1] - (1.0-scalek*dmpj[2])*rr3;
rr5k = bn[2] - (1.0-scalek*dmpj[4])*rr5;
rr7k = bn[3] - (1.0-scalek*dmpj[6])*rr7;
rr1ik = bn[0] - (1.0-scalek*dmpij[0])*rr1;
rr3ik = bn[1] - (1.0-scalek*dmpij[2])*rr3;
rr5ik = bn[2] - (1.0-scalek*dmpij[4])*rr5;
rr7ik = bn[3] - (1.0-scalek*dmpij[6])*rr7;
rr9ik = bn[4] - (1.0-scalek*dmpij[8])*rr9;
rr11ik = bn[5] - (1.0-scalek*dmpij[10])*rr11;
rr1 = bn[0] - (1.0-scalek)*rr1;
rr3 = bn[1] - (1.0-scalek)*rr3;
e = term1*rr1 + term4ik*rr7ik + term5ik*rr9ik +
term1i*rr1i + term1k*rr1k + term1ik*rr1ik +
term2i*rr3i + term2k*rr3k + term2ik*rr3ik +
term3i*rr5i + term3k*rr5k + term3ik*rr5ik;
// find damped multipole intermediates for force and torque
de = term1*rr3 + term4ik*rr9ik + term5ik*rr11ik +
term1i*rr3i + term1k*rr3k + term1ik*rr3ik +
term2i*rr5i + term2k*rr5k + term2ik*rr5ik +
term3i*rr7i + term3k*rr7k + term3ik*rr7ik;
term1 = -corek*rr3i - valk*rr3ik + dkr*rr5ik - qkr*rr7ik;
term2 = corei*rr3k + vali*rr3ik + dir*rr5ik + qir*rr7ik;
term3 = 2.0 * rr5ik;
term4 = -2.0 * (corek*rr5i+valk*rr5ik - dkr*rr7ik+qkr*rr9ik);
term5 = -2.0 * (corei*rr5k+vali*rr5ik + dir*rr7ik+qir*rr9ik);
term6 = 4.0 * rr7ik;
rr3 = rr3ik;
// find standard multipole intermediates and energy value
} else {
term1 = ci*ck;
term2 = ck*dir - ci*dkr + dik;
term3 = ci*qkr + ck*qir - dir*dkr + 2.0*(dkqi-diqk+qiqk);
term4 = dir*qkr - dkr*qir - 4.0*qik;
term5 = qir*qkr;
scalek = 1.0 - factor_mpole;
rr1 = bn[0] - scalek*rr1;
rr3 = bn[1] - scalek*rr3;
rr5 = bn[2] - scalek*rr5;
rr7 = bn[3] - scalek*rr7;
rr9 = bn[4] - scalek*rr9;
rr11 = bn[5] - scalek*rr11;
e = term1*rr1 + term2*rr3 + term3*rr5 + term4*rr7 + term5*rr9;
// find standard multipole intermediates for force and torque
de = term1*rr3 + term2*rr5 + term3*rr7 + term4*rr9 + term5*rr11;
term1 = -ck*rr3 + dkr*rr5 - qkr*rr7;
term2 = ci*rr3 + dir*rr5 + qir*rr7;
term3 = 2.0 * rr5;
term4 = 2.0 * (-ck*rr5+dkr*rr7-qkr*rr9);
term5 = 2.0 * (-ci*rr5-dir*rr7-qir*rr9);
term6 = 4.0 * rr7;
}
empole += e;
// compute the force components for this interaction
frcx = de*xr + term1*dix + term2*dkx + term3*(diqkx-dkqix) +
term4*qix + term5*qkx + term6*(qixk+qkxi);
frcy = de*yr + term1*diy + term2*dky + term3*(diqky-dkqiy) +
term4*qiy + term5*qky + term6*(qiyk+qkyi);
frcz = de*zr + term1*diz + term2*dkz + term3*(diqkz-dkqiz) +
term4*qiz + term5*qkz + term6*(qizk+qkzi);
// compute the torque components for this interaction
ttmi[0] = -rr3*dikx + term1*dirx + term3*(dqikx+dkqirx) -
term4*qirx - term6*(qikrx+qikx);
ttmi[1] = -rr3*diky + term1*diry + term3*(dqiky+dkqiry) -
term4*qiry - term6*(qikry+qiky);
ttmi[2] = -rr3*dikz + term1*dirz + term3*(dqikz+dkqirz) -
term4*qirz - term6*(qikrz+qikz);
ttmk[0] = rr3*dikx + term2*dkrx - term3*(dqikx+diqkrx) -
term5*qkrx - term6*(qkirx-qikx);
ttmk[1] = rr3*diky + term2*dkry - term3*(dqiky+diqkry) -
term5*qkry - term6*(qkiry-qiky);
ttmk[2] = rr3*dikz + term2*dkrz - term3*(dqikz+diqkrz) -
term5*qkrz - term6*(qkirz-qikz);
// increment force-based gradient and torque on first site
f[i][0] -= frcx;
f[i][1] -= frcy;
f[i][2] -= frcz;
tq[i][0] += ttmi[0];
tq[i][1] += ttmi[1];
tq[i][2] += ttmi[2];
// increment force-based gradient and torque on second site
f[j][0] += frcx;
f[j][1] += frcy;
f[j][2] += frcz;
tq[j][0] += ttmk[0];
tq[j][1] += ttmk[1];
tq[j][2] += ttmk[2];
// increment the virial due to pairwise Cartesian forces
if (vflag_global) {
vxx = -xr * frcx;
vxy = -0.5 * (yr*frcx+xr*frcy);
vxz = -0.5 * (zr*frcx+xr*frcz);
vyy = -yr * frcy;
vyz = -0.5 * (zr*frcy+yr*frcz);
vzz = -zr * frcz;
virmpole[0] -= vxx;
virmpole[1] -= vyy;
virmpole[2] -= vzz;
virmpole[3] -= vxy;
virmpole[4] -= vxz;
virmpole[5] -= vyz;
}
}
}
// reverse comm to sum torque from ghost atoms to owned atoms
crstyle = TORQUE;
comm->reverse_comm(this);
// resolve site torques then increment forces and virial
for (i = 0; i < nlocal; i++) {
torque2force(i,tq[i],fix,fiy,fiz,f);
if (!vflag_global) continue;
iz = zaxis2local[i];
ix = xaxis2local[i];
iy = yaxis2local[i];
xiz = x[iz][0] - x[i][0];
yiz = x[iz][1] - x[i][1];
ziz = x[iz][2] - x[i][2];
xix = x[ix][0] - x[i][0];
yix = x[ix][1] - x[i][1];
zix = x[ix][2] - x[i][2];
xiy = x[iy][0] - x[i][0];
yiy = x[iy][1] - x[i][1];
ziy = x[iy][2] - x[i][2];
vxx = xix*fix[0] + xiy*fiy[0] + xiz*fiz[0];
vxy = 0.5 * (yix*fix[0] + yiy*fiy[0] + yiz*fiz[0] +
xix*fix[1] + xiy*fiy[1] + xiz*fiz[1]);
vxz = 0.5 * (zix*fix[0] + ziy*fiy[0] + ziz*fiz[0] +
xix*fix[2] + xiy*fiy[2] + xiz*fiz[2]);
vyy = yix*fix[1] + yiy*fiy[1] + yiz*fiz[1];
vyz = 0.5 * (zix*fix[1] + ziy*fiy[1] + ziz*fiz[1] +
yix*fix[2] + yiy*fiy[2] + yiz*fiz[2]);
vzz = zix*fix[2] + ziy*fiy[2] + ziz*fiz[2];
virmpole[0] -= vxx;
virmpole[1] -= vyy;
virmpole[2] -= vzz;
virmpole[3] -= vxy;
virmpole[4] -= vxz;
virmpole[5] -= vyz;
}
}
/* ----------------------------------------------------------------------
multipole_kspace = KSpace portion of multipole interactions
adapted from Tinker emrecip1() routine
literature reference:
C. Sagui, L. G. Pedersen and T. A. Darden, "Towards an Accurate
Representation of Electrostatics in Classical Force Fields:
Efficient Implementation of Multipolar Interactions in
Biomolecular Simulations", Journal of Chemical Physics, 120,
73-87 (2004)
------------------------------------------------------------------------- */
void PairAmoeba::multipole_kspace()
{
int i,j,k,n,ix,iy,iz;
int nhalf1,nhalf2,nhalf3;
int nxlo,nxhi,nylo,nyhi,nzlo,nzhi;
double e,eterm,felec;
double r1,r2,r3;
double h1,h2,h3;
double f1,f2,f3;
double xix,yix,zix;
double xiy,yiy,ziy;
double xiz,yiz,ziz;
double vxx,vyy,vzz,vxy,vxz,vyz;
double volterm,denom;
double hsq,expterm;
double term,pterm;
double vterm,struc2;
double tem[3],fix[3],fiy[3],fiz[3];
// indices into the electrostatic field array
// decremented by 1 versus Fortran
int deriv1[10] = {1, 4, 7, 8, 10, 15, 17, 13, 14, 19};
int deriv2[10] = {2, 7, 5, 9, 13, 11, 18, 15, 19, 16};
int deriv3[10] = {3, 8, 9, 6, 14, 16, 12, 19, 17, 18};
// return if the Ewald coefficient is zero
if (aewald < 1.0e-6) return;
// owned atoms
double **x = atom->x;
double **f = atom->f;
int nlocal = atom->nlocal;
double volbox = domain->prd[0] * domain->prd[1] * domain->prd[2];
felec = electric / am_dielectric;
// FFT moduli pre-computations
// set igrid for each atom and its B-spline coeffs
nfft1 = m_kspace->nx;
nfft2 = m_kspace->ny;
nfft3 = m_kspace->nz;
bsorder = m_kspace->order;
moduli();
bspline_fill();
// copy multipole info to Cartesian cmp
for (i = 0; i < nlocal; i++) {
cmp[i][0] = rpole[i][0];
cmp[i][1] = rpole[i][1];
cmp[i][2] = rpole[i][2];
cmp[i][3] = rpole[i][3];
cmp[i][4] = rpole[i][4];
cmp[i][5] = rpole[i][8];
cmp[i][6] = rpole[i][12];
cmp[i][7] = 2.0 * rpole[i][5];
cmp[i][8] = 2.0 * rpole[i][6];
cmp[i][9] = 2.0 * rpole[i][9];
}
// convert Cartesian multipoles to fractional multipoles
cmp_to_fmp(cmp,fmp);
// gridpre = my portion of 3d grid in brick decomp w/ ghost values
double ***gridpre = (double ***) m_kspace->zero();
// map atoms to grid
grid_mpole(fmp,gridpre);
// pre-convolution operations including forward FFT
// gridfft = my portion of complex 3d grid in FFT decomp as 1d vector
double *gridfft = m_kspace->pre_convolution();
// ---------------------
// convolution operation
// ---------------------
// zero virial accumulation variables
vxx = vyy = vzz = vxy = vxz = vyz = 0.0;
// perform convolution on K-space points I own
nhalf1 = (nfft1+1) / 2;
nhalf2 = (nfft2+1) / 2;
nhalf3 = (nfft3+1) / 2;
nxlo = m_kspace->nxlo_fft;
nxhi = m_kspace->nxhi_fft;
nylo = m_kspace->nylo_fft;
nyhi = m_kspace->nyhi_fft;
nzlo = m_kspace->nzlo_fft;
nzhi = m_kspace->nzhi_fft;
pterm = square(MY_PI/aewald);
volterm = MY_PI * volbox;
n = 0;
for (k = nzlo; k <= nzhi; k++) {
for (j = nylo; j <= nyhi; j++) {
for (i = nxlo; i <= nxhi; i++) {
r1 = (i >= nhalf1) ? i-nfft1 : i;
r2 = (j >= nhalf2) ? j-nfft2 : j;
r3 = (k >= nhalf3) ? k-nfft3 : k;
h1 = recip[0][0]*r1 + recip[0][1]*r2 + recip[0][2]*r3; // matvec
h2 = recip[1][0]*r1 + recip[1][1]*r2 + recip[1][2]*r3;
h3 = recip[2][0]*r1 + recip[2][1]*r2 + recip[2][2]*r3;
hsq = h1*h1 + h2*h2 + h3*h3;
term = -pterm * hsq;
expterm = 0.0;
if (term > -50.0 && hsq != 0.0) {
denom = volterm*hsq*bsmod1[i]*bsmod2[j]*bsmod3[k];
expterm = exp(term) / denom;
struc2 = gridfft[n]*gridfft[n] + gridfft[n+1]*gridfft[n+1];
eterm = 0.5 * felec * expterm * struc2;
vterm = (2.0/hsq) * (1.0-term) * eterm;
vxx += h1*h1*vterm - eterm;
vyy += h2*h2*vterm - eterm;
vzz += h3*h3*vterm - eterm;
vxy += h1*h2*vterm;
vxz += h1*h3*vterm;
vyz += h2*h3*vterm;
}
gridfft[n] *= expterm;
gridfft[n+1] *= expterm;
n += 2;
}
}
}
// save multipole virial for use in polarization computation
vmsave[0] = vxx;
vmsave[1] = vyy;
vmsave[2] = vzz;
vmsave[3] = vxy;
vmsave[4] = vxz;
vmsave[5] = vyz;
// post-convolution operations including backward FFT
// gridppost = my portion of 3d grid in brick decomp w/ ghost values
double ***gridpost = (double ***) m_kspace->post_convolution();
// get potential
fphi_mpole(gridpost,fphi);
for (i = 0; i < nlocal; i++) {
for (k = 0; k < 20; k++)
fphi[i][k] *= felec;
}
// convert field from fractional to Cartesian
fphi_to_cphi(fphi,cphi);
// increment the permanent multipole energy and gradient
e = 0.0;
for (i = 0; i < nlocal; i++) {
f1 = 0.0;
f2 = 0.0;
f3 = 0.0;
for (k = 0; k < 10; k++) {
e += fmp[i][k]*fphi[i][k];
f1 += fmp[i][k]*fphi[i][deriv1[k]];
f2 += fmp[i][k]*fphi[i][deriv2[k]];
f3 += fmp[i][k]*fphi[i][deriv3[k]];
}
f1 *= nfft1;
f2 *= nfft2;
f3 *= nfft3;
h1 = recip[0][0]*f1 + recip[0][1]*f2 + recip[0][2]*f3; // matvec?
h2 = recip[1][0]*f1 + recip[1][1]*f2 + recip[1][2]*f3;
h3 = recip[2][0]*f1 + recip[2][1]*f2 + recip[2][2]*f3;
f[i][0] -= h1;
f[i][1] -= h2;
f[i][2] -= h3;
}
empole += 0.5*e;
// augment the permanent multipole virial contributions
if (vflag_global) {
for (i = 0; i < nlocal; i++) {
vxx = vxx - cmp[i][1]*cphi[i][1] - 2.0*cmp[i][4]*cphi[i][4] -
cmp[i][7]*cphi[i][7] - cmp[i][8]*cphi[i][8];
vxy = vxy - 0.5*(cmp[i][2]*cphi[i][1]+cmp[i][1]*cphi[i][2]) -
(cmp[i][4]+cmp[i][5])*cphi[i][7] - 0.5*cmp[i][7]*(cphi[i][4]+cphi[i][5]) -
0.5*(cmp[i][8]*cphi[i][9]+cmp[i][9]*cphi[i][8]);
vxz = vxz - 0.5*(cmp[i][3]*cphi[i][1]+cmp[i][1]*cphi[i][3]) -
(cmp[i][4]+cmp[i][6])*cphi[i][8] - 0.5*cmp[i][8]*(cphi[i][4]+cphi[i][6]) -
0.5*(cmp[i][7]*cphi[i][9]+cmp[i][9]*cphi[i][7]);
vyy = vyy - cmp[i][2]*cphi[i][2] - 2.0*cmp[i][5]*cphi[i][5] -
cmp[i][7]*cphi[i][7] - cmp[i][9]*cphi[i][9];
vyz = vyz - 0.5*(cmp[i][3]*cphi[i][2]+cmp[i][2]*cphi[i][3]) -
(cmp[i][5]+cmp[i][6])*cphi[i][9] - 0.5*cmp[i][9]*(cphi[i][5]+cphi[i][6]) -
0.5*(cmp[i][7]*cphi[i][8]+cmp[i][8]*cphi[i][7]);
vzz = vzz - cmp[i][3]*cphi[i][3] - 2.0*cmp[i][6]*cphi[i][6] -
cmp[i][8]*cphi[i][8] - cmp[i][9]*cphi[i][9];
}
}
// resolve site torques then increment forces and virial
for (i = 0; i < nlocal; i++) {
tem[0] = cmp[i][3]*cphi[i][2] - cmp[i][2]*cphi[i][3] +
2.0*(cmp[i][6]-cmp[i][5])*cphi[i][9] +
cmp[i][8]*cphi[i][7] + cmp[i][9]*cphi[i][5] -
cmp[i][7]*cphi[i][8] - cmp[i][9]*cphi[i][6];
tem[1] = cmp[i][1]*cphi[i][3] - cmp[i][3]*cphi[i][1] +
2.0*(cmp[i][4]-cmp[i][6])*cphi[i][8] +
cmp[i][7]*cphi[i][9] + cmp[i][8]*cphi[i][6] -
cmp[i][8]*cphi[i][4] - cmp[i][9]*cphi[i][7];
tem[2] = cmp[i][2]*cphi[i][1] - cmp[i][1]*cphi[i][2] +
2.0*(cmp[i][5]-cmp[i][4])*cphi[i][7] +
cmp[i][7]*cphi[i][4] + cmp[i][9]*cphi[i][8] -
cmp[i][7]*cphi[i][5] - cmp[i][8]*cphi[i][9];
torque2force(i,tem,fix,fiy,fiz,f);
if (vflag_global) {
iz = zaxis2local[i];
ix = xaxis2local[i];
iy = yaxis2local[i];
xiz = x[iz][0] - x[i][0];
yiz = x[iz][1] - x[i][1];
ziz = x[iz][2] - x[i][2];
xix = x[ix][0] - x[i][0];
yix = x[ix][1] - x[i][1];
zix = x[ix][2] - x[i][2];
xiy = x[iy][0] - x[i][0];
yiy = x[iy][1] - x[i][1];
ziy = x[iy][2] - x[i][2];
vxx += xix*fix[0] + xiy*fiy[0] + xiz*fiz[0];
vxy += 0.5*(yix*fix[0] + yiy*fiy[0] + yiz*fiz[0] +
xix*fix[1] + xiy*fiy[1] + xiz*fiz[1]);
vxz += 0.5*(zix*fix[0] + ziy*fiy[0] + ziz*fiz[0] +
xix*fix[2] + xiy*fiy[2] + xiz*fiz[2]);
vyy += yix*fix[1] + yiy*fiy[1] + yiz*fiz[1];
vyz += 0.5*(zix*fix[1] + ziy*fiy[1] + ziz*fiz[1] +
yix*fix[2] + yiy*fiy[2] + yiz*fiz[2]);
vzz += zix*fix[2] + ziy*fiy[2] + ziz*fiz[2];
}
}
// increment total internal virial tensor components
if (vflag_global) {
virmpole[0] -= vxx;
virmpole[1] -= vyy;
virmpole[2] -= vzz;
virmpole[3] -= vxy;
virmpole[4] -= vxz;
virmpole[5] -= vyz;
}
}
/* ----------------------------------------------------------------------
damppole generates coefficients for the charge penetration
damping function for powers of the interatomic distance
literature references:
L. V. Slipchenko and M. S. Gordon, "Electrostatic Energy in the
Effective Fragment Potential Method: Theory and Application to
the Benzene Dimer", Journal of Computational Chemistry, 28,
276-291 (2007) [Gordon f1 and f2 models]
J. A. Rackers, Q. Wang, C. Liu, J.-P. Piquemal, P. Ren and
J. W. Ponder, "An Optimized Charge Penetration Model for Use with
the AMOEBA Force Field", Physical Chemistry Chemical Physics, 19,
276-291 (2017)
------------------------------------------------------------------------- */
void PairAmoeba::damppole(double r, int rorder, double alphai, double alphak,
double *dmpi, double *dmpk, double *dmpik)
{
double termi,termk;
double termi2,termk2;
double alphai2,alphak2;
double eps,diff;
double expi,expk;
double dampi,dampk;
double dampi2,dampi3;
double dampi4,dampi5;
double dampi6,dampi7;
double dampi8;
double dampk2,dampk3;
double dampk4,dampk5;
double dampk6;
// compute tolerance and exponential damping factors
eps = 0.001;
diff = fabs(alphai-alphak);
dampi = alphai * r;
dampk = alphak * r;
expi = exp(-dampi);
expk = exp(-dampk);
// core-valence charge penetration damping for Gordon f1
dampi2 = dampi * dampi;
dampi3 = dampi * dampi2;
dampi4 = dampi2 * dampi2;
dampi5 = dampi2 * dampi3;
dmpi[0] = 1.0 - (1.0 + 0.5*dampi)*expi;
dmpi[2] = 1.0 - (1.0 + dampi + 0.5*dampi2)*expi;
dmpi[4] = 1.0 - (1.0 + dampi + 0.5*dampi2 + dampi3/6.0)*expi;
dmpi[6] = 1.0 - (1.0 + dampi + 0.5*dampi2 + dampi3/6.0 + dampi4/30.0)*expi;
dmpi[8] = 1.0 - (1.0 + dampi + 0.5*dampi2 + dampi3/6.0 +
4.0*dampi4/105.0 + dampi5/210.0)*expi;
if (diff < eps) {
dmpk[0] = dmpi[0];
dmpk[2] = dmpi[2];
dmpk[4] = dmpi[4];
dmpk[6] = dmpi[6];
dmpk[8] = dmpi[8];
} else {
dampk2 = dampk * dampk;
dampk3 = dampk * dampk2;
dampk4 = dampk2 * dampk2;
dampk5 = dampk2 * dampk3;
dmpk[0] = 1.0 - (1.0 + 0.5*dampk)*expk;
dmpk[2] = 1.0 - (1.0 + dampk + 0.5*dampk2)*expk;
dmpk[4] = 1.0 - (1.0 + dampk + 0.5*dampk2 + dampk3/6.0)*expk;
dmpk[6] = 1.0 - (1.0 + dampk + 0.5*dampk2 + dampk3/6.0 + dampk4/30.0)*expk;
dmpk[8] = 1.0 - (1.0 + dampk + 0.5*dampk2 + dampk3/6.0 +
4.0*dampk4/105.0 + dampk5/210.0)*expk;
}
// valence-valence charge penetration damping for Gordon f1
if (diff < eps) {
dampi6 = dampi3 * dampi3;
dampi7 = dampi3 * dampi4;
dmpik[0] = 1.0 - (1.0 + 11.0*dampi/16.0 + 3.0*dampi2/16.0 +
dampi3/48.0)*expi;
dmpik[2] = 1.0 - (1.0 + dampi + 0.5*dampi2 +
7.0*dampi3/48.0 + dampi4/48.0)*expi;
dmpik[4] = 1.0 - (1.0 + dampi + 0.5*dampi2 + dampi3/6.0 +
dampi4/24.0 + dampi5/144.0)*expi;
dmpik[6] = 1.0 - (1.0 + dampi + 0.5*dampi2 + dampi3/6.0 +
dampi4/24.0 + dampi5/120.0 + dampi6/720.0)*expi;
dmpik[8] = 1.0 - (1.0 + dampi + 0.5*dampi2 + dampi3/6.0 +
dampi4/24.0 + dampi5/120.0 + dampi6/720.0 +
dampi7/5040.0)*expi;
if (rorder >= 11) {
dampi8 = dampi4 * dampi4;
dmpik[10] = 1.0 - (1.0 + dampi + 0.5*dampi2 + dampi3/6.0 +
dampi4/24.0 + dampi5/120.0 + dampi6/720.0 +
dampi7/5040.0 + dampi8/45360.0)*expi;
}
} else {
alphai2 = alphai * alphai;
alphak2 = alphak * alphak;
termi = alphak2 / (alphak2-alphai2);
termk = alphai2 / (alphai2-alphak2);
termi2 = termi * termi;
termk2 = termk * termk;
dmpik[0] = 1.0 - termi2*(1.0 + 2.0*termk + 0.5*dampi)*expi -
termk2*(1.0 + 2.0*termi + 0.5*dampk)*expk;
dmpik[2] = 1.0 - termi2*(1.0+dampi+0.5*dampi2)*expi -
termk2*(1.0+dampk+0.5*dampk2)*expk -
2.0*termi2*termk*(1.0+dampi)*expi -
2.0*termk2*termi*(1.0+dampk)*expk;
dmpik[4] = 1.0 - termi2*(1.0 + dampi + 0.5*dampi2 + dampi3/6.0)*expi -
termk2*(1.0 + dampk + 0.5*dampk2 + dampk3/6.0)*expk -
2.0*termi2*termk*(1.0 + dampi + dampi2/3.0)*expi -
2.0*termk2*termi*(1.0 + dampk + dampk2/3.0)*expk;
dmpik[6] = 1.0 - termi2*(1.0 + dampi + 0.5*dampi2 +
dampi3/6.0 + dampi4/30.0)*expi -
termk2*(1.0 + dampk + 0.5*dampk2 + dampk3/6.0 + dampk4/30.0)*expk -
2.0*termi2*termk*(1.0 + dampi + 2.0*dampi2/5.0 + dampi3/15.0)*expi -
2.0*termk2*termi*(1.0 + dampk + 2.0*dampk2/5.0 + dampk3/15.0)*expk;
dmpik[8] = 1.0 - termi2*(1.0 + dampi + 0.5*dampi2 + dampi3/6.0 +
4.0*dampi4/105.0 + dampi5/210.0)*expi -
termk2*(1.0 + dampk + 0.5*dampk2 + dampk3/6.0 +
4.0*dampk4/105.0 + dampk5/210.0)*expk -
2.0*termi2*termk*(1.0 + dampi + 3.0*dampi2/7.0 +
2.0*dampi3/21.0 + dampi4/105.0)*expi -
2.0*termk2*termi*(1.0 + dampk + 3.0*dampk2/7.0 +
2.0*dampk3/21.0 + dampk4/105.0)*expk;
if (rorder >= 11) {
dampi6 = dampi3 * dampi3;
dampk6 = dampk3 * dampk3;
dmpik[10] = 1.0 - termi2*(1.0 + dampi + 0.5*dampi2 + dampi3/6.0 +
5.0*dampi4/126.0 + 2.0*dampi5/315.0 +
dampi6/1890.0)*expi -
termk2*(1.0 + dampk + 0.5*dampk2 + dampk3/6.0 + 5.0*dampk4/126.0 +
2.0*dampk5/315.0 + dampk6/1890.0)*expk -
2.0*termi2*termk*(1.0 + dampi + 4.0*dampi2/9.0 + dampi3/9.0 +
dampi4/63.0 + dampi5/945.0)*expi -
2.0*termk2*termi*(1.0 + dampk + 4.0*dampk2/9.0 + dampk3/9.0 +
dampk4/63.0 + dampk5/945.0)*expk;
}
}
}

2177
src/AMOEBA/amoeba_polar.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,569 @@
// clang-format off
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/ 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.
------------------------------------------------------------------------- */
#include "pair_amoeba.h"
#include "atom.h"
#include "comm.h"
#include "memory.h"
#include "neigh_list.h"
#include <cmath>
using namespace LAMMPS_NS;
enum{FIELD,ZRSD,TORQUE,UFLD}; // reverse comm
enum{VDWL,REPULSE,QFER,DISP,MPOLE,POLAR,USOLV,DISP_LONG,MPOLE_LONG,POLAR_LONG};
/* ----------------------------------------------------------------------
repulsion = Pauli repulsion interactions
adapted from Tinker erepel1b() routine
------------------------------------------------------------------------- */
void PairAmoeba::repulsion()
{
int i,j,k,ii,jj,itype,jtype;
int ix,iy,iz;
double e;
double eterm,de;
double xi,yi,zi;
double xr,yr,zr;
double xix,yix,zix;
double xiy,yiy,ziy;
double xiz,yiz,ziz;
double r,r2,r3,r4,r5;
double rr1,rr3,rr5;
double rr7,rr9,rr11;
double dix,diy,diz;
double qixx,qixy,qixz;
double qiyy,qiyz,qizz;
double dkx,dky,dkz;
double qkxx,qkxy,qkxz;
double qkyy,qkyz,qkzz;
double dir,dkr,dik,qik;
double qix,qiy,qiz,qir;
double qkx,qky,qkz,qkr;
double diqk,dkqi,qiqk;
double dirx,diry,dirz;
double dkrx,dkry,dkrz;
double dikx,diky,dikz;
double qirx,qiry,qirz;
double qkrx,qkry,qkrz;
double qikx,qiky,qikz;
double qixk,qiyk,qizk;
double qkxi,qkyi,qkzi;
double qikrx,qikry,qikrz;
double qkirx,qkiry,qkirz;
double diqkx,diqky,diqkz;
double dkqix,dkqiy,dkqiz;
double diqkrx,diqkry,diqkrz;
double dkqirx,dkqiry,dkqirz;
double dqikx,dqiky,dqikz;
double term1,term2,term3;
double term4,term5,term6;
double sizi,sizk,sizik;
double vali,valk;
double dmpi,dmpk;
double frcx,frcy,frcz;
double taper,dtaper;
double vxx,vyy,vzz;
double vxy,vxz,vyz;
double factor_repel;
double ttri[3],ttrk[3];
double fix[3],fiy[3],fiz[3];
double dmpik[11];
int inum,jnum;
int *ilist,*jlist,*numneigh,**firstneigh;
// set cutoffs and taper coeffs
choose(REPULSE);
// owned atoms
double **x = atom->x;
double **f = atom->f;
int nlocal = atom->nlocal;
// zero repulsion torque on owned + ghost atoms
int nall = nlocal + atom->nghost;
for (i = 0; i < nall; i++) {
tq[i][0] = 0.0;
tq[i][1] = 0.0;
tq[i][2] = 0.0;
}
// neigh list
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// double loop over owned atoms and neighbors
// DEBUG
//FILE *fp = fopen("lammps.dat","w");
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
itype = amtype[i];
jlist = firstneigh[i];
jnum = numneigh[i];
xi = x[i][0];
yi = x[i][1];
zi = x[i][2];
sizi = sizpr[itype];
dmpi = dmppr[itype];
vali = elepr[itype];
dix = rpole[i][1];
diy = rpole[i][2];
diz = rpole[i][3];
qixx = rpole[i][4];
qixy = rpole[i][5];
qixz = rpole[i][6];
qiyy = rpole[i][8];
qiyz = rpole[i][9];
qizz = rpole[i][12];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_repel = special_repel[sbmask15(j)];
if (factor_repel == 0.0) continue;
j &= NEIGHMASK15;
xr = x[j][0] - xi;
yr = x[j][1] - yi;
zr = x[j][2] - zi;
r2 = xr*xr + yr*yr + zr*zr;
if (r2 > off2) continue;
jtype = amtype[j];
r = sqrt(r2);
sizk = sizpr[jtype];
dmpk = dmppr[jtype];
valk = elepr[jtype];
dkx = rpole[j][1];
dky = rpole[j][2];
dkz = rpole[j][3];
qkxx = rpole[j][4];
qkxy = rpole[j][5];
qkxz = rpole[j][6];
qkyy = rpole[j][8];
qkyz = rpole[j][9];
qkzz = rpole[j][12];
// intermediates involving moments and separation distance
dir = dix*xr + diy*yr + diz*zr;
qix = qixx*xr + qixy*yr + qixz*zr;
qiy = qixy*xr + qiyy*yr + qiyz*zr;
qiz = qixz*xr + qiyz*yr + qizz*zr;
qir = qix*xr + qiy*yr + qiz*zr;
dkr = dkx*xr + dky*yr + dkz*zr;
qkx = qkxx*xr + qkxy*yr + qkxz*zr;
qky = qkxy*xr + qkyy*yr + qkyz*zr;
qkz = qkxz*xr + qkyz*yr + qkzz*zr;
qkr = qkx*xr + qky*yr + qkz*zr;
dik = dix*dkx + diy*dky + diz*dkz;
qik = qix*qkx + qiy*qky + qiz*qkz;
diqk = dix*qkx + diy*qky + diz*qkz;
dkqi = dkx*qix + dky*qiy + dkz*qiz;
qiqk = 2.0*(qixy*qkxy+qixz*qkxz+qiyz*qkyz) +
qixx*qkxx + qiyy*qkyy + qizz*qkzz;
// additional intermediates involving moments and distance
dirx = diy*zr - diz*yr;
diry = diz*xr - dix*zr;
dirz = dix*yr - diy*xr;
dkrx = dky*zr - dkz*yr;
dkry = dkz*xr - dkx*zr;
dkrz = dkx*yr - dky*xr;
dikx = diy*dkz - diz*dky;
diky = diz*dkx - dix*dkz;
dikz = dix*dky - diy*dkx;
qirx = qiz*yr - qiy*zr;
qiry = qix*zr - qiz*xr;
qirz = qiy*xr - qix*yr;
qkrx = qkz*yr - qky*zr;
qkry = qkx*zr - qkz*xr;
qkrz = qky*xr - qkx*yr;
qikx = qky*qiz - qkz*qiy;
qiky = qkz*qix - qkx*qiz;
qikz = qkx*qiy - qky*qix;
qixk = qixx*qkx + qixy*qky + qixz*qkz;
qiyk = qixy*qkx + qiyy*qky + qiyz*qkz;
qizk = qixz*qkx + qiyz*qky + qizz*qkz;
qkxi = qkxx*qix + qkxy*qiy + qkxz*qiz;
qkyi = qkxy*qix + qkyy*qiy + qkyz*qiz;
qkzi = qkxz*qix + qkyz*qiy + qkzz*qiz;
qikrx = qizk*yr - qiyk*zr;
qikry = qixk*zr - qizk*xr;
qikrz = qiyk*xr - qixk*yr;
qkirx = qkzi*yr - qkyi*zr;
qkiry = qkxi*zr - qkzi*xr;
qkirz = qkyi*xr - qkxi*yr;
diqkx = dix*qkxx + diy*qkxy + diz*qkxz;
diqky = dix*qkxy + diy*qkyy + diz*qkyz;
diqkz = dix*qkxz + diy*qkyz + diz*qkzz;
dkqix = dkx*qixx + dky*qixy + dkz*qixz;
dkqiy = dkx*qixy + dky*qiyy + dkz*qiyz;
dkqiz = dkx*qixz + dky*qiyz + dkz*qizz;
diqkrx = diqkz*yr - diqky*zr;
diqkry = diqkx*zr - diqkz*xr;
diqkrz = diqky*xr - diqkx*yr;
dkqirx = dkqiz*yr - dkqiy*zr;
dkqiry = dkqix*zr - dkqiz*xr;
dkqirz = dkqiy*xr - dkqix*yr;
dqikx = diy*qkz - diz*qky + dky*qiz - dkz*qiy -
2.0*(qixy*qkxz+qiyy*qkyz+qiyz*qkzz-qixz*qkxy-qiyz*qkyy-qizz*qkyz);
dqiky = diz*qkx - dix*qkz + dkz*qix - dkx*qiz -
2.0*(qixz*qkxx+qiyz*qkxy+qizz*qkxz-qixx*qkxz-qixy*qkyz-qixz*qkzz);
dqikz = dix*qky - diy*qkx + dkx*qiy - dky*qix -
2.0*(qixx*qkxy+qixy*qkyy+qixz*qkyz-qixy*qkxx-qiyy*qkxy-qiyz*qkxz);
// get reciprocal distance terms for this interaction
rr1 = 1.0 / r;
rr3 = rr1 / r2;
rr5 = 3.0 * rr3 / r2;
rr7 = 5.0 * rr5 / r2;
rr9 = 7.0 * rr7 / r2;
rr11 = 9.0 * rr9 / r2;
// get damping coefficients for the Pauli repulsion energy
damprep(r,r2,rr1,rr3,rr5,rr7,rr9,rr11,11,dmpi,dmpk,dmpik);
// calculate intermediate terms needed for the energy
term1 = vali*valk;
term2 = valk*dir - vali*dkr + dik;
term3 = vali*qkr + valk*qir - dir*dkr + 2.0*(dkqi-diqk+qiqk);
term4 = dir*qkr - dkr*qir - 4.0*qik;
term5 = qir*qkr;
eterm = term1*dmpik[0] + term2*dmpik[2] +
term3*dmpik[4] + term4*dmpik[6] + term5*dmpik[8];
// compute the Pauli repulsion energy for this interaction
sizik = sizi * sizk * factor_repel;
e = sizik * eterm * rr1;
// calculate intermediate terms for force and torque
de = term1*dmpik[2] + term2*dmpik[4] + term3*dmpik[6] +
term4*dmpik[8] + term5*dmpik[10];
term1 = -valk*dmpik[2] + dkr*dmpik[4] - qkr*dmpik[6];
term2 = vali*dmpik[2] + dir*dmpik[4] + qir*dmpik[6];
term3 = 2.0 * dmpik[4];
term4 = 2.0 * (-valk*dmpik[4] + dkr*dmpik[6] - qkr*dmpik[8]);
term5 = 2.0 * (-vali*dmpik[4] - dir*dmpik[6] - qir*dmpik[8]);
term6 = 4.0 * dmpik[6];
// compute the force components for this interaction
frcx = de*xr + term1*dix + term2*dkx + term3*(diqkx-dkqix) +
term4*qix + term5*qkx + term6*(qixk+qkxi);
frcy = de*yr + term1*diy + term2*dky + term3*(diqky-dkqiy) +
term4*qiy + term5*qky + term6*(qiyk+qkyi);
frcz = de*zr + term1*diz + term2*dkz + term3*(diqkz-dkqiz) +
term4*qiz + term5*qkz + term6*(qizk+qkzi);
frcx = frcx*rr1 + eterm*rr3*xr;
frcy = frcy*rr1 + eterm*rr3*yr;
frcz = frcz*rr1 + eterm*rr3*zr;
frcx = sizik * frcx;
frcy = sizik * frcy;
frcz = sizik * frcz;
// compute the torque components for this interaction
ttri[0] = -dmpik[2]*dikx + term1*dirx + term3*(dqikx+dkqirx) -
term4*qirx - term6*(qikrx+qikx);
ttri[1] = -dmpik[2]*diky + term1*diry + term3*(dqiky+dkqiry) -
term4*qiry - term6*(qikry+qiky);
ttri[2] = -dmpik[2]*dikz + term1*dirz + term3*(dqikz+dkqirz) -
term4*qirz - term6*(qikrz+qikz);
ttrk[0] = dmpik[2]*dikx + term2*dkrx - term3*(dqikx+diqkrx) -
term5*qkrx - term6*(qkirx-qikx);
ttrk[1] = dmpik[2]*diky + term2*dkry - term3*(dqiky+diqkry) -
term5*qkry - term6*(qkiry-qiky);
ttrk[2] = dmpik[2]*dikz + term2*dkrz - term3*(dqikz+diqkrz) -
term5*qkrz - term6*(qkirz-qikz);
ttri[0] = sizik * ttri[0] * rr1;
ttri[1] = sizik * ttri[1] * rr1;
ttri[2] = sizik * ttri[2] * rr1;
ttrk[0] = sizik * ttrk[0] * rr1;
ttrk[1] = sizik * ttrk[1] * rr1;
ttrk[2] = sizik * ttrk[2] * rr1;
// use energy switching if near the cutoff distance
if (r2 > cut2) {
r3 = r2 * r;
r4 = r2 * r2;
r5 = r2 * r3;
taper = c5*r5 + c4*r4 + c3*r3 + c2*r2 + c1*r + c0;
dtaper = 5.0*c5*r4 + 4.0*c4*r3 + 3.0*c3*r2 + 2.0*c2*r + c1;
dtaper *= e * rr1;
e *= taper;
frcx = frcx*taper - dtaper*xr;
frcy = frcy*taper - dtaper*yr;
frcz = frcz*taper - dtaper*zr;
for (k = 0; k < 3; k++) {
ttri[k] *= taper;
ttrk[k] *= taper;
}
}
erepulse += e;
// increment force-based gradient and torque on atom I
f[i][0] -= frcx;
f[i][1] -= frcy;
f[i][2] -= frcz;
tq[i][0] += ttri[0];
tq[i][1] += ttri[1];
tq[i][2] += ttri[2];
// increment force-based gradient and torque on atom J
f[j][0] += frcx;
f[j][1] += frcy;
f[j][2] += frcz;
tq[j][0] += ttrk[0];
tq[j][1] += ttrk[1];
tq[j][2] += ttrk[2];
// increment the virial due to pairwise Cartesian forces
if (vflag_global) {
vxx = -xr * frcx;
vxy = -0.5 * (yr*frcx+xr*frcy);
vxz = -0.5 * (zr*frcx+xr*frcz);
vyy = -yr * frcy;
vyz = -0.5 * (zr*frcy+yr*frcz);
vzz = -zr * frcz;
virrepulse[0] -= vxx;
virrepulse[1] -= vyy;
virrepulse[2] -= vzz;
virrepulse[3] -= vxy;
virrepulse[4] -= vxz;
virrepulse[5] -= vyz;
}
}
}
// reverse comm to sum torque from ghost atoms to owned atoms
crstyle = TORQUE;
comm->reverse_comm(this);
// resolve site torques then increment forces and virial
for (i = 0; i < nlocal; i++) {
torque2force(i,tq[i],fix,fiy,fiz,f);
if (!vflag_global) continue;
iz = zaxis2local[i];
ix = xaxis2local[i];
iy = yaxis2local[i];
xiz = x[iz][0] - x[i][0];
yiz = x[iz][1] - x[i][1];
ziz = x[iz][2] - x[i][2];
xix = x[ix][0] - x[i][0];
yix = x[ix][1] - x[i][1];
zix = x[ix][2] - x[i][2];
xiy = x[iy][0] - x[i][0];
yiy = x[iy][1] - x[i][1];
ziy = x[iy][2] - x[i][2];
vxx = xix*fix[0] + xiy*fiy[0] + xiz*fiz[0];
vyy = yix*fix[1] + yiy*fiy[1] + yiz*fiz[1];
vzz = zix*fix[2] + ziy*fiy[2] + ziz*fiz[2];
vxy = 0.5 * (yix*fix[0] + yiy*fiy[0] + yiz*fiz[0] +
xix*fix[1] + xiy*fiy[1] + xiz*fiz[1]);
vxz = 0.5 * (zix*fix[0] + ziy*fiy[0] + ziz*fiz[0] +
xix*fix[2] + xiy*fiy[2] + xiz*fiz[2]);
vyz = 0.5 * (zix*fix[1] + ziy*fiy[1] + ziz*fiz[1] +
yix*fix[2] + yiy*fiy[2] + yiz*fiz[2]);
virrepulse[0] -= vxx;
virrepulse[1] -= vyy;
virrepulse[2] -= vzz;
virrepulse[3] -= vxy;
virrepulse[4] -= vxz;
virrepulse[5] -= vyz;
}
}
/* ----------------------------------------------------------------------
damprep generates coefficients for the Pauli repulsion
damping function for powers of the interatomic distance
literature reference:
J. A. Rackers and J. W. Ponder, "Classical Pauli Repulsion: An
Anisotropic, Atomic Multipole Model", Journal of Chemical Physics,
150, 084104 (2019)
------------------------------------------------------------------------- */
void PairAmoeba::damprep(double r, double r2, double rr1, double rr3,
double rr5, double rr7, double rr9, double rr11,
int rorder, double dmpi, double dmpk, double *dmpik)
{
double r3,r4;
double r5,r6,r7,r8;
double s,ds,d2s;
double d3s,d4s,d5s;
double dmpi2,dmpk2;
double dmpi22,dmpi23;
double dmpi24,dmpi25;
double dmpi26,dmpi27;
double dmpk22,dmpk23;
double dmpk24,dmpk25;
double dmpk26;
double eps,diff;
double expi,expk;
double dampi,dampk;
double pre,term,tmp;
// compute tolerance value for damping exponents
eps = 0.001;
diff = fabs(dmpi-dmpk);
// treat the case where alpha damping exponents are equal
if (diff < eps) {
r3 = r2 * r;
r4 = r3 * r;
r5 = r4 * r;
r6 = r5 * r;
r7 = r6 * r;
dmpi2 = 0.5 * dmpi;
dampi = dmpi2 * r;
expi = exp(-dampi);
dmpi22 = dmpi2 * dmpi2;
dmpi23 = dmpi22 * dmpi2;
dmpi24 = dmpi23 * dmpi2;
dmpi25 = dmpi24 * dmpi2;
dmpi26 = dmpi25 * dmpi2;
pre = 128.0;
s = (r + dmpi2*r2 + dmpi22*r3/3.0) * expi;
ds = (dmpi22*r3 + dmpi23*r4) * expi / 3.0;
d2s = dmpi24 * expi * r5 / 9.0;
d3s = dmpi25 * expi * r6 / 45.0;
d4s = (dmpi25*r6 + dmpi26*r7) * expi / 315.0;
if (rorder >= 11) {
r8 = r7 * r;
dmpi27 = dmpi2 * dmpi26;
d5s = (dmpi25*r6 + dmpi26*r7 + dmpi27*r8/3.0) * expi / 945.0;
} else d5s = 0.0;
// treat the case where alpha damping exponents are unequal
} else {
r3 = r2 * r;
r4 = r3 * r;
r5 = r4 * r;
dmpi2 = 0.5 * dmpi;
dmpk2 = 0.5 * dmpk;
dampi = dmpi2 * r;
dampk = dmpk2 * r;
expi = exp(-dampi);
expk = exp(-dampk);
dmpi22 = dmpi2 * dmpi2;
dmpi23 = dmpi22 * dmpi2;
dmpi24 = dmpi23 * dmpi2;
dmpi25 = dmpi24 * dmpi2;
dmpk22 = dmpk2 * dmpk2;
dmpk23 = dmpk22 * dmpk2;
dmpk24 = dmpk23 * dmpk2;
dmpk25 = dmpk24 * dmpk2;
term = dmpi22 - dmpk22;
pre = 8192.0 * dmpi23 * dmpk23 / (term*term*term*term);
tmp = 4.0 * dmpi2 * dmpk2 / term;
s = (dampi-tmp)*expk + (dampk+tmp)*expi;
ds = (dmpi2*dmpk2*r2 - 4.0*dmpi2*dmpk22*r/term -
4.0*dmpi2*dmpk2/term) * expk +
(dmpi2*dmpk2*r2 + 4.0*dmpi22*dmpk2*r/term + 4.0*dmpi2*dmpk2/term) * expi;
d2s = (dmpi2*dmpk2*r2/3.0 + dmpi2*dmpk22*r3/3.0 -
(4.0/3.0)*dmpi2*dmpk23*r2/term - 4.0*dmpi2*dmpk22*r/term -
4.0*dmpi2*dmpk2/term) * expk +
(dmpi2*dmpk2*r2/3.0 + dmpi22*dmpk2*r3/3.0 +
(4.0/3.0)*dmpi23*dmpk2*r2/term + 4.0*dmpi22*dmpk2*r/term +
4.0*dmpi2*dmpk2/term) * expi;
d3s = (dmpi2*dmpk23*r4/15.0 + dmpi2*dmpk22*r3/5.0 + dmpi2*dmpk2*r2/5.0 -
(4.0/15.0)*dmpi2*dmpk24*r3/term - (8.0/5.0)*dmpi2*dmpk23*r2/term -
4.0*dmpi2*dmpk22*r/term - 4.0/term*dmpi2*dmpk2) * expk +
(dmpi23*dmpk2*r4/15.0 + dmpi22*dmpk2*r3/5.0 + dmpi2*dmpk2*r2/5.0 +
(4.0/15.0)*dmpi24*dmpk2*r3/term + (8.0/5.0)*dmpi23*dmpk2*r2/term +
4.0*dmpi22*dmpk2*r/term + 4.0/term*dmpi2*dmpk2) * expi;
d4s = (dmpi2*dmpk24*r5/105.0 + (2.0/35.0)*dmpi2*dmpk23*r4 +
dmpi2*dmpk22*r3/7.0 + dmpi2*dmpk2*r2/7.0 -
(4.0/105.0)*dmpi2*dmpk25*r4/term - (8.0/21.0)*dmpi2*dmpk24*r3/term -
(12.0/7.0)*dmpi2*dmpk23*r2/term - 4.0*dmpi2*dmpk22*r/term -
4.0*dmpi2*dmpk2/term) * expk +
(dmpi24*dmpk2*r5/105.0 + (2.0/35.0)*dmpi23*dmpk2*r4 +
dmpi22*dmpk2*r3/7.0 + dmpi2*dmpk2*r2/7.0 +
(4.0/105.0)*dmpi25*dmpk2*r4/term + (8.0/21.0)*dmpi24*dmpk2*r3/term +
(12.0/7.0)*dmpi23*dmpk2*r2/term + 4.0*dmpi22*dmpk2*r/term +
4.0*dmpi2*dmpk2/term) * expi;
if (rorder >= 11) {
r6 = r5 * r;
dmpi26 = dmpi25 * dmpi2;
dmpk26 = dmpk25 * dmpk2;
d5s = (dmpi2*dmpk25*r6/945.0 + (2.0/189.0)*dmpi2*dmpk24*r5 +
dmpi2*dmpk23*r4/21.0 + dmpi2*dmpk22*r3/9.0 + dmpi2*dmpk2*r2/9.0 -
(4.0/945.0)*dmpi2*dmpk26*r5/term -
(4.0/63.0)*dmpi2*dmpk25*r4/term - (4.0/9.0)*dmpi2*dmpk24*r3/term -
(16.0/9.0)*dmpi2*dmpk23*r2/term - 4.0*dmpi2*dmpk22*r/term -
4.0*dmpi2*dmpk2/term) * expk +
(dmpi25*dmpk2*r6/945.0 + (2.0/189.0)*dmpi24*dmpk2*r5 +
dmpi23*dmpk2*r4/21.0 + dmpi22*dmpk2*r3/9.0 + dmpi2*dmpk2*r2/9.0 +
(4.0/945.0)*dmpi26*dmpk2*r5/term + (4.0/63.0)*dmpi25*dmpk2*r4/term +
(4.0/9.0)*dmpi24*dmpk2*r3/term + (16.0/9.0)*dmpi23*dmpk2*r2/term +
4.0*dmpi22*dmpk2*r/term + 4.0*dmpi2*dmpk2/term) * expi;
} else d5s = 0.0;
}
// convert partial derivatives into full derivatives
s = s * rr1;
ds = ds * rr3;
d2s = d2s * rr5;
d3s = d3s * rr7;
d4s = d4s * rr9;
d5s = d5s * rr11;
dmpik[0] = 0.5 * pre * s * s;
dmpik[2] = pre * s * ds;
dmpik[4] = pre * (s*d2s + ds*ds);
dmpik[6] = pre * (s*d3s + 3.0*ds*d2s);
dmpik[8] = pre * (s*d4s + 4.0*ds*d3s + 3.0*d2s*d2s);
if (rorder >= 11) dmpik[10] = pre * (s*d5s + 5.0*ds*d4s + 10.0*d2s*d3s);
}

1135
src/AMOEBA/amoeba_utils.cpp Normal file

File diff suppressed because it is too large Load Diff

870
src/AMOEBA/angle_amoeba.cpp Normal file
View File

@ -0,0 +1,870 @@
// clang-format off
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, 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.
------------------------------------------------------------------------- */
#include "angle_amoeba.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "error.h"
#include "force.h"
#include "math_const.h"
#include "memory.h"
#include "neighbor.h"
#include "pair.h"
#include <cmath>
#include <cstring>
using namespace LAMMPS_NS;
using namespace MathConst;
#define SMALL 0.001
/* ---------------------------------------------------------------------- */
AngleAmoeba::AngleAmoeba(LAMMPS *lmp) : Angle(lmp)
{
pflag = nullptr;
ubflag = nullptr;
theta0 = nullptr;
k2 = nullptr;
k3 = nullptr;
k4 = nullptr;
k5 = nullptr;
k6 = nullptr;
ba_k1 = nullptr;
ba_k2 = nullptr;
ba_r1 = nullptr;
ba_r2 = nullptr;
ub_k = nullptr;
ub_r0 = nullptr;
setflag_a = setflag_ba = setflag_ub = nullptr;
enable_angle = enable_urey = 0;
}
/* ---------------------------------------------------------------------- */
AngleAmoeba::~AngleAmoeba()
{
if (copymode) return;
if (allocated) {
memory->destroy(setflag);
memory->destroy(setflag_a);
memory->destroy(setflag_ba);
memory->destroy(setflag_ub);
memory->destroy(pflag);
memory->destroy(ubflag);
memory->destroy(theta0);
memory->destroy(k2);
memory->destroy(k3);
memory->destroy(k4);
memory->destroy(k5);
memory->destroy(k6);
memory->destroy(ba_k1);
memory->destroy(ba_k2);
memory->destroy(ba_r1);
memory->destroy(ba_r2);
memory->destroy(ub_k);
memory->destroy(ub_r0);
}
}
/* ---------------------------------------------------------------------- */
void AngleAmoeba::compute(int eflag, int vflag)
{
int i1,i2,i3,n,type,tflag,uflag;
int **anglelist = neighbor->anglelist;
int **nspecial = atom->nspecial;
int nanglelist = neighbor->nanglelist;
ev_init(eflag,vflag);
for (n = 0; n < nanglelist; n++) {
i1 = anglelist[n][0];
i2 = anglelist[n][1];
i3 = anglelist[n][2];
type = anglelist[n][3];
// tflag = 0 for "angle", 1 for "anglep" in Tinker PRM file
// atom 2 must have exactly 3 bond partners to invoke anglep() variant
if (enable_angle) {
tflag = pflag[type];
if (tflag && nspecial[i2][0] == 3)
tinker_anglep(i1,i2,i3,type,eflag);
else
tinker_angle(i1,i2,i3,type,eflag);
// bondangle = bond-stretch cross term in Tinker
if (ba_k1[type] != 0.0)
tinker_bondangle(i1,i2,i3,type,eflag);
}
// Urey-Bradley H-H bond term within water molecules
if (enable_urey) {
uflag = ubflag[type];
if (uflag) tinker_urey_bradley(i1,i3,type,eflag);
}
}
}
/* ---------------------------------------------------------------------- */
void AngleAmoeba::tinker_angle(int i1, int i2, int i3, int type, int eflag)
{
double delx1,dely1,delz1,delx2,dely2,delz2;
double eangle,f1[3],f3[3];
double dtheta,dtheta2,dtheta3,dtheta4,dtheta5,dtheta6,de_angle;
double rsq1,rsq2,r1,r2,c,s,a;
double a11,a12,a22;
double **x = atom->x;
double **f = atom->f;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
// 1st bond
delx1 = x[i1][0] - x[i2][0];
dely1 = x[i1][1] - x[i2][1];
delz1 = x[i1][2] - x[i2][2];
rsq1 = delx1*delx1 + dely1*dely1 + delz1*delz1;
r1 = sqrt(rsq1);
// 2nd bond
delx2 = x[i3][0] - x[i2][0];
dely2 = x[i3][1] - x[i2][1];
delz2 = x[i3][2] - x[i2][2];
rsq2 = delx2*delx2 + dely2*dely2 + delz2*delz2;
r2 = sqrt(rsq2);
// angle (cos and sin)
c = delx1*delx2 + dely1*dely2 + delz1*delz2;
c /= r1*r2;
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
s = sqrt(1.0 - c*c);
if (s < SMALL) s = SMALL;
s = 1.0/s;
// force & energy for angle term
dtheta = acos(c) - theta0[type];
dtheta2 = dtheta*dtheta;
dtheta3 = dtheta2*dtheta;
dtheta4 = dtheta3*dtheta;
dtheta5 = dtheta4*dtheta;
dtheta6 = dtheta5*dtheta;
de_angle = 2.0*k2[type]*dtheta + 3.0*k3[type]*dtheta2 +
4.0*k4[type]*dtheta3 + 5.0*k5[type]*dtheta4 + 6.0*k6[type]*dtheta5;
a = -de_angle*s;
a11 = a*c / rsq1;
a12 = -a / (r1*r2);
a22 = a*c / rsq2;
f1[0] = a11*delx1 + a12*delx2;
f1[1] = a11*dely1 + a12*dely2;
f1[2] = a11*delz1 + a12*delz2;
f3[0] = a22*delx2 + a12*delx1;
f3[1] = a22*dely2 + a12*dely1;
f3[2] = a22*delz2 + a12*delz1;
eangle = 0.0;
if (eflag) eangle = k2[type]*dtheta2 + k3[type]*dtheta3 +
k4[type]*dtheta4 + k5[type]*dtheta5 + k6[type]*dtheta6;
// apply force to each of 3 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0];
f[i1][1] += f1[1];
f[i1][2] += f1[2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] -= f1[0] + f3[0];
f[i2][1] -= f1[1] + f3[1];
f[i2][2] -= f1[2] + f3[2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f3[0];
f[i3][1] += f3[1];
f[i3][2] += f3[2];
}
if (evflag) ev_tally(i1,i2,i3,nlocal,newton_bond,eangle,f1,f3,
delx1,dely1,delz1,delx2,dely2,delz2);
}
/* ---------------------------------------------------------------------- */
void AngleAmoeba::tinker_anglep(int i1, int i2, int i3, int type, int eflag)
{
int i4;
tagint i1tag,i3tag,i4tag;
double xia,yia,zia,xib,yib,zib,xic,yic,zic,xid,yid,zid;
double xad,yad,zad,xbd,ybd,zbd,xcd,ycd,zcd;
double xt,yt,zt,rt2;
double xip,yip,zip,xap,yap,zap,xcp,ycp,zcp;
double rap2,rcp2;
double dtheta,dtheta2,dtheta3,dtheta4,dtheta5,dtheta6;
double xm,ym,zm,rm,dot;
double cosine,eangle,deddt;
double dedxip,dedyip,dedzip,dpdxia,dpdyia,dpdzia,dpdxic,dpdyic,dpdzic;
double delta,delta2,ptrt2,term,terma,termc;
double f1[3],f2[3],f3[3],f4[3];
double **x = atom->x;
double **f = atom->f;
tagint **special = atom->special;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
// i4 = index of third atom that i2 is bonded to
i1tag = atom->tag[i1];
i3tag = atom->tag[i3];
for (int ibond = 0; ibond < 3; ibond++) {
i4tag = special[i2][ibond];
if (i4tag != i1tag && i4tag != i3tag) break;
}
i4 = atom->map(i4tag);
if (i4 < 0) error->one(FLERR,"Amoeba angle 4th atom {} out of range", i4tag);
i4 = domain->closest_image(i2,i4);
// anglep out-of-plane calculation from Tinker
xia = x[i1][0];
yia = x[i1][1];
zia = x[i1][2];
xib = x[i2][0];
yib = x[i2][1];
zib = x[i2][2];
xic = x[i3][0];
yic = x[i3][1];
zic = x[i3][2];
xid = x[i4][0];
yid = x[i4][1];
zid = x[i4][2];
xad = xia - xid;
yad = yia - yid;
zad = zia - zid;
xbd = xib - xid;
ybd = yib - yid;
zbd = zib - zid;
xcd = xic - xid;
ycd = yic - yid;
zcd = zic - zid;
xt = yad*zcd - zad*ycd;
yt = zad*xcd - xad*zcd;
zt = xad*ycd - yad*xcd;
rt2 = xt*xt + yt*yt + zt*zt;
delta = -(xt*xbd + yt*ybd + zt*zbd) / rt2;
xip = xib + xt*delta;
yip = yib + yt*delta;
zip = zib + zt*delta;
xap = xia - xip;
yap = yia - yip;
zap = zia - zip;
xcp = xic - xip;
ycp = yic - yip;
zcp = zic - zip;
rap2 = xap*xap + yap*yap + zap*zap;
rcp2 = xcp*xcp + ycp*ycp + zcp*zcp;
// Tinker just skips the computation in either is zero
if (rap2 == 0.0 || rcp2 == 0.0) return;
xm = ycp*zap - zcp*yap;
ym = zcp*xap - xcp*zap;
zm = xcp*yap - ycp*xap;
rm = sqrt(xm*xm + ym*ym + zm*zm);
rm = MAX(rm,0.0001);
dot = xap*xcp + yap*ycp + zap*zcp;
cosine = dot / sqrt(rap2*rcp2);
cosine = MIN(1.0,MAX(-1.0,cosine));
// force & energy for angle term
dtheta = acos(cosine) - theta0[type];
dtheta2 = dtheta*dtheta;
dtheta3 = dtheta2*dtheta;
dtheta4 = dtheta3*dtheta;
dtheta5 = dtheta4*dtheta;
dtheta6 = dtheta5*dtheta;
deddt = 2.0*k2[type]*dtheta + 3.0*k3[type]*dtheta2 +
4.0*k4[type]*dtheta3 + 5.0*k5[type]*dtheta4 + 6.0*k6[type]*dtheta5;
eangle = 0.0;
if (eflag) eangle = k2[type]*dtheta2 + k3[type]*dtheta3 +
k4[type]*dtheta4 + k5[type]*dtheta5 + k6[type]*dtheta6;
// chain rule terms for first derivative components
terma = -deddt / (rap2*rm);
termc = deddt / (rcp2*rm);
f1[0] = terma * (yap*zm-zap*ym);
f1[1] = terma * (zap*xm-xap*zm);
f1[2] = terma * (xap*ym-yap*xm);
f3[0] = termc * (ycp*zm-zcp*ym);
f3[1] = termc * (zcp*xm-xcp*zm);
f3[2] = termc * (xcp*ym-ycp*xm);
dedxip = -f1[0] - f3[0];
dedyip = -f1[1] - f3[1];
dedzip = -f1[2] - f3[2];
// chain rule components for the projection of the central atom
delta2 = 2.0 * delta;
ptrt2 = (dedxip*xt + dedyip*yt + dedzip*zt) / rt2;
term = (zcd*ybd-ycd*zbd) + delta2*(yt*zcd-zt*ycd);
dpdxia = delta*(ycd*dedzip-zcd*dedyip) + term*ptrt2;
term = (xcd*zbd-zcd*xbd) + delta2*(zt*xcd-xt*zcd);
dpdyia = delta*(zcd*dedxip-xcd*dedzip) + term*ptrt2;
term = (ycd*xbd-xcd*ybd) + delta2*(xt*ycd-yt*xcd);
dpdzia = delta*(xcd*dedyip-ycd*dedxip) + term*ptrt2;
term = (yad*zbd-zad*ybd) + delta2*(zt*yad-yt*zad);
dpdxic = delta*(zad*dedyip-yad*dedzip) + term*ptrt2;
term = (zad*xbd-xad*zbd) + delta2*(xt*zad-zt*xad);
dpdyic = delta*(xad*dedzip-zad*dedxip) + term*ptrt2;
term = (xad*ybd-yad*xbd) + delta2*(yt*xad-xt*yad);
dpdzic = delta*(yad*dedxip-xad*dedyip) + term*ptrt2;
// compute derivative components for this interaction
f1[0] += dpdxia;
f1[1] += dpdyia;
f1[2] += dpdzia;
f2[0] = dedxip;
f2[1] = dedyip;
f2[2] = dedzip;
f3[0] += dpdxic;
f3[1] += dpdyic;
f3[2] += dpdzic;
f4[0] = -f1[0] - f2[0] - f3[0];
f4[1] = -f1[1] - f2[1] - f3[1];
f4[2] = -f1[2] - f2[2] - f3[2];
// apply force to each of 4 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] -= f1[0];
f[i1][1] -= f1[1];
f[i1][2] -= f1[2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] -= f2[0];
f[i2][1] -= f2[1];
f[i2][2] -= f2[2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] -= f3[0];
f[i3][1] -= f3[1];
f[i3][2] -= f3[2];
}
if (newton_bond || i4 < nlocal) {
f[i4][0] -= f4[0];
f[i4][1] -= f4[1];
f[i4][2] -= f4[2];
}
if (evflag) {
f1[0] = -f1[0]; f1[1] = -f1[1]; f1[2] = -f1[2];
f2[0] = -f2[0]; f2[1] = -f2[1]; f2[2] = -f2[2];
f3[0] = -f3[0]; f3[1] = -f3[1]; f3[2] = -f3[2];
f4[0] = -f4[0]; f4[1] = -f4[1]; f4[2] = -f4[2];
ev_tally4(i1,i2,i3,i4,nlocal,newton_bond,eangle,f1,f2,f3,f4);
}
}
/* ---------------------------------------------------------------------- */
void AngleAmoeba::tinker_bondangle(int i1, int i2, int i3, int type, int eflag)
{
double delx1,dely1,delz1,delx2,dely2,delz2;
double rsq1,r1,rsq2,r2,c,s,dtheta;
double dr1,dr2,aa1,aa2,b1,b2;
double aa11,aa12,aa21,aa22;
double vx11,vx12,vy11,vy12,vz11,vz12,vx21,vx22,vy21,vy22,vz21,vz22;
double eangle,f1[3],f3[3];
double **x = atom->x;
double **f = atom->f;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
// 1st bond
delx1 = x[i1][0] - x[i2][0];
dely1 = x[i1][1] - x[i2][1];
delz1 = x[i1][2] - x[i2][2];
rsq1 = delx1*delx1 + dely1*dely1 + delz1*delz1;
r1 = sqrt(rsq1);
// 2nd bond
delx2 = x[i3][0] - x[i2][0];
dely2 = x[i3][1] - x[i2][1];
delz2 = x[i3][2] - x[i2][2];
rsq2 = delx2*delx2 + dely2*dely2 + delz2*delz2;
r2 = sqrt(rsq2);
// angle (cos and sin)
c = delx1*delx2 + dely1*dely2 + delz1*delz2;
c /= r1*r2;
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
s = sqrt(1.0 - c*c);
if (s < SMALL) s = SMALL;
s = 1.0/s;
dtheta = acos(c) - theta0[type];
// force & energy for bond-angle term
dr1 = r1 - ba_r1[type];
dr2 = r2 - ba_r2[type];
aa1 = s * dr1 * ba_k1[type];
aa2 = s * dr2 * ba_k2[type];
aa11 = aa1 * c / rsq1;
aa12 = -aa1 / (r1 * r2);
aa21 = aa2 * c / rsq1;
aa22 = -aa2 / (r1 * r2);
vx11 = (aa11 * delx1) + (aa12 * delx2);
vx12 = (aa21 * delx1) + (aa22 * delx2);
vy11 = (aa11 * dely1) + (aa12 * dely2);
vy12 = (aa21 * dely1) + (aa22 * dely2);
vz11 = (aa11 * delz1) + (aa12 * delz2);
vz12 = (aa21 * delz1) + (aa22 * delz2);
aa11 = aa1 * c / rsq2;
aa21 = aa2 * c / rsq2;
vx21 = (aa11 * delx2) + (aa12 * delx1);
vx22 = (aa21 * delx2) + (aa22 * delx1);
vy21 = (aa11 * dely2) + (aa12 * dely1);
vy22 = (aa21 * dely2) + (aa22 * dely1);
vz21 = (aa11 * delz2) + (aa12 * delz1);
vz22 = (aa21 * delz2) + (aa22 * delz1);
b1 = ba_k1[type] * dtheta / r1;
b2 = ba_k2[type] * dtheta / r2;
f1[0] = -(vx11 + b1*delx1 + vx12);
f1[1] = -(vy11 + b1*dely1 + vy12);
f1[2] = -(vz11 + b1*delz1 + vz12);
f3[0] = -(vx21 + b2*delx2 + vx22);
f3[1] = -(vy21 + b2*dely2 + vy22);
f3[2] = -(vz21 + b2*delz2 + vz22);
eangle = 0.0;
if (eflag) eangle = ba_k1[type]*dr1*dtheta + ba_k2[type]*dr2*dtheta;
// apply force to each of 3 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0];
f[i1][1] += f1[1];
f[i1][2] += f1[2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] -= f1[0] + f3[0];
f[i2][1] -= f1[1] + f3[1];
f[i2][2] -= f1[2] + f3[2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f3[0];
f[i3][1] += f3[1];
f[i3][2] += f3[2];
}
if (evflag) ev_tally(i1,i2,i3,nlocal,newton_bond,eangle,f1,f3,
delx1,dely1,delz1,delx2,dely2,delz2);
}
/* ---------------------------------------------------------------------- */
void AngleAmoeba::tinker_urey_bradley(int i1, int i2, int type, int eflag)
{
double delx,dely,delz;
double rsq,r,dr,rk;
double fbond,ebond;
double **x = atom->x;
double **f = atom->f;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
delx = x[i1][0] - x[i2][0];
dely = x[i1][1] - x[i2][1];
delz = x[i1][2] - x[i2][2];
rsq = delx*delx + dely*dely + delz*delz;
r = sqrt(rsq);
dr = r - ub_r0[type];
rk = ub_k[type] * dr;
// force & energy
if (r > 0.0) fbond = -2.0*rk/r;
else fbond = 0.0;
if (eflag) ebond = rk*dr;
// apply force to each of 2 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += delx*fbond;
f[i1][1] += dely*fbond;
f[i1][2] += delz*fbond;
}
if (newton_bond || i2 < nlocal) {
f[i2][0] -= delx*fbond;
f[i2][1] -= dely*fbond;
f[i2][2] -= delz*fbond;
}
if (evflag) ev_tally2(i1,i2,nlocal,newton_bond,ebond,fbond,delx,dely,delz);
}
/* ---------------------------------------------------------------------- */
void AngleAmoeba::allocate()
{
allocated = 1;
int n = atom->nangletypes;
memory->create(pflag,n+1,"angle:pflag");
memory->create(ubflag,n+1,"angle:ubflag");
memory->create(theta0,n+1,"angle:theta0");
memory->create(k2,n+1,"angle:k2");
memory->create(k3,n+1,"angle:k3");
memory->create(k4,n+1,"angle:k4");
memory->create(k5,n+1,"angle:k5");
memory->create(k6,n+1,"angle:k6");
memory->create(ba_k1,n+1,"angle:ba_k1");
memory->create(ba_k2,n+1,"angle:ba_k2");
memory->create(ba_r1,n+1,"angle:ba_r1");
memory->create(ba_r2,n+1,"angle:ba_r2");
memory->create(ub_k,n+1,"angle:ub_k");
memory->create(ub_r0,n+1,"angle:ub_r0");
memory->create(setflag,n+1,"angle:setflag");
memory->create(setflag_a,n+1,"angle:setflag_a");
memory->create(setflag_ba,n+1,"angle:setflag_ba");
memory->create(setflag_ub,n+1,"angle:setflag_ub");
for (int i = 1; i <= n; i++)
setflag[i] = setflag_a[i] = setflag_ba[i] = setflag_ub[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one or more types
------------------------------------------------------------------------- */
void AngleAmoeba::coeff(int narg, char **arg)
{
if (narg < 2) error->all(FLERR,"Incorrect args for angle coefficients");
if (!allocated) allocate();
int ilo,ihi;
utils::bounds(FLERR,arg[0],1,atom->nangletypes,ilo,ihi,error);
int count = 0;
if (strcmp(arg[1],"ba") == 0) {
if (narg != 6) error->all(FLERR,"Incorrect args for angle coefficients");
double ba_k1_one = utils::numeric(FLERR,arg[2],false,lmp);
double ba_k2_one = utils::numeric(FLERR,arg[3],false,lmp);
double ba_r1_one = utils::numeric(FLERR,arg[4],false,lmp);
double ba_r2_one = utils::numeric(FLERR,arg[5],false,lmp);
for (int i = ilo; i <= ihi; i++) {
ba_k1[i] = ba_k1_one;
ba_k2[i] = ba_k2_one;
ba_r1[i] = ba_r1_one;
ba_r2[i] = ba_r2_one;
setflag_ba[i] = 1;
count++;
}
} else if (strcmp(arg[1],"ub") == 0) {
if (narg != 4) error->all(FLERR,"Incorrect args for angle coefficients");
double ub_k_one = utils::numeric(FLERR,arg[2],false,lmp);
double ub_r0_one = utils::numeric(FLERR,arg[3],false,lmp);
for (int i = ilo; i <= ihi; i++) {
ub_k[i] = ub_k_one;
ub_r0[i] = ub_r0_one;
setflag_ub[i] = 1;
count++;
}
} else {
if (narg != 9) error->all(FLERR,"Incorrect args for angle coefficients");
int pflag_one = utils::inumeric(FLERR,arg[1],false,lmp);
int ubflag_one = utils::inumeric(FLERR,arg[2],false,lmp);
double theta0_one = utils::numeric(FLERR,arg[3],false,lmp);
double k2_one = utils::numeric(FLERR,arg[4],false,lmp);
double k3_one = utils::numeric(FLERR,arg[5],false,lmp);
double k4_one = utils::numeric(FLERR,arg[6],false,lmp);
double k5_one = utils::numeric(FLERR,arg[7],false,lmp);
double k6_one = utils::numeric(FLERR,arg[8],false,lmp);
// convert theta0 from degrees to radians
for (int i = ilo; i <= ihi; i++) {
pflag[i] = pflag_one;
ubflag[i] = ubflag_one;
theta0[i] = theta0_one/180.0 * MY_PI;
k2[i] = k2_one;
k3[i] = k3_one;
k4[i] = k4_one;
k5[i] = k5_one;
k6[i] = k6_one;
setflag_a[i] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for angle coefficients");
for (int i = ilo; i <= ihi; i++)
if (setflag_a[i] == 1 && setflag_ba[i] == 1 && setflag_ub[i])
setflag[i] = 1;
}
/* ---------------------------------------------------------------------- */
void AngleAmoeba::init_style()
{
// check if PairAmoeba or PairHippo disabled angle or Urey-Bradley terms
Pair *pair = nullptr;
pair = force->pair_match("amoeba",1,0);
if (!pair) pair = force->pair_match("hippo",1,0);
if (!pair) enable_angle = enable_urey = 1;
else {
int tmp;
enable_angle = *((int *) pair->extract("angle_flag",tmp));
enable_urey = *((int *) pair->extract("urey_flag",tmp));
}
}
/* ---------------------------------------------------------------------- */
double AngleAmoeba::equilibrium_angle(int i)
{
return theta0[i];
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void AngleAmoeba::write_restart(FILE *fp)
{
fwrite(&pflag[1],sizeof(int),atom->nangletypes,fp);
fwrite(&ubflag[1],sizeof(int),atom->nangletypes,fp);
fwrite(&theta0[1],sizeof(double),atom->nangletypes,fp);
fwrite(&k2[1],sizeof(double),atom->nangletypes,fp);
fwrite(&k3[1],sizeof(double),atom->nangletypes,fp);
fwrite(&k4[1],sizeof(double),atom->nangletypes,fp);
fwrite(&k5[1],sizeof(double),atom->nangletypes,fp);
fwrite(&k6[1],sizeof(double),atom->nangletypes,fp);
fwrite(&ba_k1[1],sizeof(double),atom->nangletypes,fp);
fwrite(&ba_k2[1],sizeof(double),atom->nangletypes,fp);
fwrite(&ba_r1[1],sizeof(double),atom->nangletypes,fp);
fwrite(&ba_r2[1],sizeof(double),atom->nangletypes,fp);
fwrite(&ub_k[1],sizeof(double),atom->nangletypes,fp);
fwrite(&ub_r0[1],sizeof(double),atom->nangletypes,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void AngleAmoeba::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
utils::sfread(FLERR,&pflag[1],sizeof(int),atom->nangletypes,fp,nullptr,error);
utils::sfread(FLERR,&ubflag[1],sizeof(int),atom->nangletypes,
fp,nullptr,error);
utils::sfread(FLERR,&theta0[1],sizeof(double),atom->nangletypes,
fp,nullptr,error);
utils::sfread(FLERR,&k2[1],sizeof(double),atom->nangletypes,fp,nullptr,error);
utils::sfread(FLERR,&k3[1],sizeof(double),atom->nangletypes,fp,nullptr,error);
utils::sfread(FLERR,&k4[1],sizeof(double),atom->nangletypes,fp,nullptr,error);
utils::sfread(FLERR,&k5[1],sizeof(double),atom->nangletypes,fp,nullptr,error);
utils::sfread(FLERR,&k6[1],sizeof(double),atom->nangletypes,fp,nullptr,error);
utils::sfread(FLERR,&ba_k1[1],sizeof(double),atom->nangletypes,
fp,nullptr,error);
utils::sfread(FLERR,&ba_k2[1],sizeof(double),atom->nangletypes,
fp,nullptr,error);
utils::sfread(FLERR,&ba_r1[1],sizeof(double),atom->nangletypes,
fp,nullptr,error);
utils::sfread(FLERR,&ba_r2[1],sizeof(double),atom->nangletypes,
fp,nullptr,error);
utils::sfread(FLERR,&ub_k[1],sizeof(double),atom->nangletypes,
fp,nullptr,error);
utils::sfread(FLERR,&ub_r0[1],sizeof(double),atom->nangletypes,
fp,nullptr,error);
}
MPI_Bcast(&pflag[1],atom->nangletypes,MPI_INT,0,world);
MPI_Bcast(&ubflag[1],atom->nangletypes,MPI_INT,0,world);
MPI_Bcast(&theta0[1],atom->nangletypes,MPI_DOUBLE,0,world);
MPI_Bcast(&k2[1],atom->nangletypes,MPI_DOUBLE,0,world);
MPI_Bcast(&k3[1],atom->nangletypes,MPI_DOUBLE,0,world);
MPI_Bcast(&k4[1],atom->nangletypes,MPI_DOUBLE,0,world);
MPI_Bcast(&k5[1],atom->nangletypes,MPI_DOUBLE,0,world);
MPI_Bcast(&k6[1],atom->nangletypes,MPI_DOUBLE,0,world);
MPI_Bcast(&ba_k1[1],atom->nangletypes,MPI_DOUBLE,0,world);
MPI_Bcast(&ba_k2[1],atom->nangletypes,MPI_DOUBLE,0,world);
MPI_Bcast(&ba_r1[1],atom->nangletypes,MPI_DOUBLE,0,world);
MPI_Bcast(&ba_r2[1],atom->nangletypes,MPI_DOUBLE,0,world);
MPI_Bcast(&ub_k[1],atom->nangletypes,MPI_DOUBLE,0,world);
MPI_Bcast(&ub_r0[1],atom->nangletypes,MPI_DOUBLE,0,world);
for (int i = 1; i <= atom->nangletypes; i++) setflag[i] = 1;
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void AngleAmoeba::write_data(FILE *fp)
{
for (int i = 1; i <= atom->nangletypes; i++)
fprintf(fp,"%d %d %d %g %g %g %g %g %g\n",
i,pflag[i],ubflag[i],theta0[i]/MY_PI*180.0,
k2[i],k3[i],k4[i],k5[i],k6[i]);
fprintf(fp,"\nBondAngle Coeffs\n\n");
for (int i = 1; i <= atom->nangletypes; i++)
fprintf(fp,"%d %g %g %g %g\n",i,ba_k1[i],ba_k2[i],ba_r1[i],ba_r2[i]);
fprintf(fp,"\nUreyBradley Coeffs\n\n");
for (int i = 1; i <= atom->nangletypes; i++)
fprintf(fp,"%d %g %g\n",i,ub_k[i],ub_r0[i]);
}
/* ----------------------------------------------------------------------
only computes tinker_angle() and tinker_bondangle()
does not compute tinker_anglep() and tinker_urey_bradley()
---------------------------------------------------------------------- */
double AngleAmoeba::single(int type, int i1, int i2, int i3)
{
double **x = atom->x;
double delx1 = x[i1][0] - x[i2][0];
double dely1 = x[i1][1] - x[i2][1];
double delz1 = x[i1][2] - x[i2][2];
domain->minimum_image(delx1,dely1,delz1);
double r1 = sqrt(delx1*delx1 + dely1*dely1 + delz1*delz1);
double delx2 = x[i3][0] - x[i2][0];
double dely2 = x[i3][1] - x[i2][1];
double delz2 = x[i3][2] - x[i2][2];
domain->minimum_image(delx2,dely2,delz2);
double r2 = sqrt(delx2*delx2 + dely2*dely2 + delz2*delz2);
double c = delx1*delx2 + dely1*dely2 + delz1*delz2;
c /= r1*r2;
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
double s = sqrt(1.0 - c*c);
if (s < SMALL) s = SMALL;
s = 1.0/s;
double dtheta = acos(c) - theta0[type];
double dtheta2 = dtheta*dtheta;
double dtheta3 = dtheta2*dtheta;
double dtheta4 = dtheta3*dtheta;
double dtheta5 = dtheta4*dtheta;
double dtheta6 = dtheta5*dtheta;
double energy = k2[type]*dtheta2 + k3[type]*dtheta3 + k4[type]*dtheta4
+ k5[type]*dtheta5 + k6[type]*dtheta6;
double dr1 = r1 - ba_r1[type];
double dr2 = r2 - ba_r2[type];
energy += ba_k1[type]*dr1*dtheta + ba_k2[type]*dr2*dtheta;
return energy;
}

57
src/AMOEBA/angle_amoeba.h Normal file
View File

@ -0,0 +1,57 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, 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 ANGLE_CLASS
// clang-format off
AngleStyle(amoeba,AngleAmoeba);
// clang-format on
#else
#ifndef LMP_ANGLE_AMOEBA_H
#define LMP_ANGLE_AMOEBA_H
#include "angle.h"
namespace LAMMPS_NS {
class AngleAmoeba : public Angle {
public:
AngleAmoeba(class LAMMPS *);
~AngleAmoeba() override;
void compute(int, int) override;
void coeff(int, char **) override;
void init_style() override;
double equilibrium_angle(int) override;
void write_restart(FILE *) override;
void read_restart(FILE *) override;
void write_data(FILE *) override;
double single(int, int, int, int) override;
protected:
int *pflag, *ubflag;
double *theta0, *k2, *k3, *k4, *k5, *k6;
double *ba_k1, *ba_k2, *ba_r1, *ba_r2;
double *ub_k, *ub_r0;
int *setflag_a, *setflag_ba, *setflag_ub;
int enable_angle, enable_urey;
void tinker_angle(int, int, int, int, int);
void tinker_anglep(int, int, int, int, int);
void tinker_bondangle(int, int, int, int, int);
void tinker_urey_bradley(int, int, int, int);
void allocate();
};
} // namespace LAMMPS_NS
#endif
#endif

View File

@ -0,0 +1,226 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/ 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.
------------------------------------------------------------------------- */
#include "atom_vec_amoeba.h"
#include "atom.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
AtomVecAmoeba::AtomVecAmoeba(LAMMPS *lmp) : AtomVec(lmp)
{
molecular = 1;
bonds_allow = angles_allow = dihedrals_allow = impropers_allow = 1;
mass_type = 1;
atom->molecule_flag = atom->q_flag = 1;
atom->nspecial15_flag = 1;
// strings with peratom variables to include in each AtomVec method
// strings cannot contain fields in corresponding AtomVec default strings
// order of fields in a string does not matter
// except: fields_data_atom & fields_data_vel must match data file
// clang-format off
fields_grow = {"q", "molecule", "num_bond", "bond_type", "bond_atom", "num_angle", "angle_type",
"angle_atom1", "angle_atom2", "angle_atom3", "num_dihedral", "dihedral_type", "dihedral_atom1",
"dihedral_atom2", "dihedral_atom3", "dihedral_atom4", "num_improper", "improper_type",
"improper_atom1", "improper_atom2", "improper_atom3", "improper_atom4", "nspecial", "special",
"nspecial15", "special15"};
fields_copy = {"q", "molecule", "num_bond", "bond_type", "bond_atom", "num_angle", "angle_type",
"angle_atom1", "angle_atom2", "angle_atom3", "num_dihedral", "dihedral_type", "dihedral_atom1",
"dihedral_atom2", "dihedral_atom3", "dihedral_atom4", "num_improper", "improper_type",
"improper_atom1", "improper_atom2", "improper_atom3", "improper_atom4", "nspecial", "special",
"nspecial15", "special15"};
fields_border = {"q", "molecule"};
fields_border_vel = {"q", "molecule"};
fields_exchange = {"q", "molecule", "num_bond", "bond_type", "bond_atom", "num_angle",
"angle_type", "angle_atom1", "angle_atom2", "angle_atom3", "num_dihedral", "dihedral_type",
"dihedral_atom1", "dihedral_atom2", "dihedral_atom3", "dihedral_atom4", "num_improper",
"improper_type", "improper_atom1", "improper_atom2", "improper_atom3", "improper_atom4",
"nspecial", "special", "nspecial15", "special15"};
fields_restart = {"q", "molecule", "num_bond", "bond_type", "bond_atom", "num_angle",
"angle_type", "angle_atom1", "angle_atom2", "angle_atom3", "num_dihedral", "dihedral_type",
"dihedral_atom1", "dihedral_atom2", "dihedral_atom3", "dihedral_atom4", "num_improper",
"improper_type", "improper_atom1", "improper_atom2", "improper_atom3", "improper_atom4"};
fields_create = {"q", "molecule", "num_bond", "num_angle", "num_dihedral", "num_improper",
"nspecial", "nspecial15"};
fields_data_atom = {"id", "molecule", "type", "q", "x"};
fields_data_vel = {"id", "v"};
// clang-format on
setup_fields();
bond_per_atom = angle_per_atom = dihedral_per_atom = improper_per_atom = 0;
bond_negative = angle_negative = dihedral_negative = improper_negative = nullptr;
}
/* ---------------------------------------------------------------------- */
AtomVecAmoeba::~AtomVecAmoeba()
{
delete[] bond_negative;
delete[] angle_negative;
delete[] dihedral_negative;
delete[] improper_negative;
}
/* ----------------------------------------------------------------------
set local copies of all grow ptrs used by this class, except defaults
needed in replicate when 2 atom classes exist and it calls pack_restart()
------------------------------------------------------------------------- */
void AtomVecAmoeba::grow_pointers()
{
num_bond = atom->num_bond;
bond_type = atom->bond_type;
num_angle = atom->num_angle;
angle_type = atom->angle_type;
num_dihedral = atom->num_dihedral;
dihedral_type = atom->dihedral_type;
num_improper = atom->num_improper;
improper_type = atom->improper_type;
nspecial = atom->nspecial;
nspecial15 = atom->nspecial15;
}
/* ----------------------------------------------------------------------
modify values for AtomVec::pack_restart() to pack
------------------------------------------------------------------------- */
void AtomVecAmoeba::pack_restart_pre(int ilocal)
{
// insure negative vectors are needed length
if (bond_per_atom < atom->bond_per_atom) {
delete[] bond_negative;
bond_per_atom = atom->bond_per_atom;
bond_negative = new int[bond_per_atom];
}
if (angle_per_atom < atom->angle_per_atom) {
delete[] angle_negative;
angle_per_atom = atom->angle_per_atom;
angle_negative = new int[angle_per_atom];
}
if (dihedral_per_atom < atom->dihedral_per_atom) {
delete[] dihedral_negative;
dihedral_per_atom = atom->dihedral_per_atom;
dihedral_negative = new int[dihedral_per_atom];
}
if (improper_per_atom < atom->improper_per_atom) {
delete[] improper_negative;
improper_per_atom = atom->improper_per_atom;
improper_negative = new int[improper_per_atom];
}
// flip any negative types to positive and flag which ones
any_bond_negative = 0;
for (int m = 0; m < num_bond[ilocal]; m++) {
if (bond_type[ilocal][m] < 0) {
bond_negative[m] = 1;
bond_type[ilocal][m] = -bond_type[ilocal][m];
any_bond_negative = 1;
} else
bond_negative[m] = 0;
}
any_angle_negative = 0;
for (int m = 0; m < num_angle[ilocal]; m++) {
if (angle_type[ilocal][m] < 0) {
angle_negative[m] = 1;
angle_type[ilocal][m] = -angle_type[ilocal][m];
any_angle_negative = 1;
} else
angle_negative[m] = 0;
}
any_dihedral_negative = 0;
for (int m = 0; m < num_dihedral[ilocal]; m++) {
if (dihedral_type[ilocal][m] < 0) {
dihedral_negative[m] = 1;
dihedral_type[ilocal][m] = -dihedral_type[ilocal][m];
any_dihedral_negative = 1;
} else
dihedral_negative[m] = 0;
}
any_improper_negative = 0;
for (int m = 0; m < num_improper[ilocal]; m++) {
if (improper_type[ilocal][m] < 0) {
improper_negative[m] = 1;
improper_type[ilocal][m] = -improper_type[ilocal][m];
any_improper_negative = 1;
} else
improper_negative[m] = 0;
}
}
/* ----------------------------------------------------------------------
unmodify values packed by AtomVec::pack_restart()
------------------------------------------------------------------------- */
void AtomVecAmoeba::pack_restart_post(int ilocal)
{
// restore the flagged types to their negative values
if (any_bond_negative) {
for (int m = 0; m < num_bond[ilocal]; m++)
if (bond_negative[m]) bond_type[ilocal][m] = -bond_type[ilocal][m];
}
if (any_angle_negative) {
for (int m = 0; m < num_angle[ilocal]; m++)
if (angle_negative[m]) angle_type[ilocal][m] = -angle_type[ilocal][m];
}
if (any_dihedral_negative) {
for (int m = 0; m < num_dihedral[ilocal]; m++)
if (dihedral_negative[m]) dihedral_type[ilocal][m] = -dihedral_type[ilocal][m];
}
if (any_improper_negative) {
for (int m = 0; m < num_improper[ilocal]; m++)
if (improper_negative[m]) improper_type[ilocal][m] = -improper_type[ilocal][m];
}
}
/* ----------------------------------------------------------------------
initialize other atom quantities after AtomVec::unpack_restart()
------------------------------------------------------------------------- */
void AtomVecAmoeba::unpack_restart_init(int ilocal)
{
nspecial[ilocal][0] = 0;
nspecial[ilocal][1] = 0;
nspecial[ilocal][2] = 0;
nspecial15[ilocal] = 0;
}
/* ----------------------------------------------------------------------
modify what AtomVec::data_atom() just unpacked
or initialize other atom quantities
------------------------------------------------------------------------- */
void AtomVecAmoeba::data_atom_post(int ilocal)
{
num_bond[ilocal] = 0;
num_angle[ilocal] = 0;
num_dihedral[ilocal] = 0;
num_improper[ilocal] = 0;
nspecial[ilocal][0] = 0;
nspecial[ilocal][1] = 0;
nspecial[ilocal][2] = 0;
nspecial15[ilocal] = 0;
}

View File

@ -0,0 +1,49 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/ 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 ATOM_CLASS
// clang-format off
AtomStyle(amoeba,AtomVecAmoeba);
// clang-format on
#else
#ifndef LMP_ATOM_VEC_AMOEBA_H
#define LMP_ATOM_VEC_AMOEBA_H
#include "atom_vec.h"
namespace LAMMPS_NS {
class AtomVecAmoeba : public AtomVec {
public:
AtomVecAmoeba(class LAMMPS *);
~AtomVecAmoeba() override;
void grow_pointers() override;
void pack_restart_pre(int) override;
void pack_restart_post(int) override;
void unpack_restart_init(int) override;
void data_atom_post(int) override;
private:
int *num_bond, *num_angle, *num_dihedral, *num_improper;
int **bond_type, **angle_type, **dihedral_type, **improper_type;
int **nspecial, *nspecial15;
int any_bond_negative, any_angle_negative, any_dihedral_negative, any_improper_negative;
int bond_per_atom, angle_per_atom, dihedral_per_atom, improper_per_atom;
int *bond_negative, *angle_negative, *dihedral_negative, *improper_negative;
};
} // namespace LAMMPS_NS
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,126 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, 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
// clang-format off
FixStyle(amoeba/bitorsion,FixAmoebaBiTorsion);
// clang-format on
#else
#ifndef LMP_FIX_AMOEBA_BITORSION_H
#define LMP_FIX_AMOEBA_BITORSION_H
#include "fix.h"
namespace LAMMPS_NS {
class FixAmoebaBiTorsion : public Fix {
public:
FixAmoebaBiTorsion(class LAMMPS *, int, char **);
~FixAmoebaBiTorsion() override;
int setmask() override;
void init() override;
void setup(int) override;
void setup_pre_neighbor() override;
void setup_pre_reverse(int, int) override;
void min_setup(int) override;
void pre_neighbor() override;
void pre_reverse(int, int) override;
void post_force(int) override;
void post_force_respa(int, int, int) override;
void min_post_force(int) override;
double compute_scalar() override;
void read_data_header(char *) override;
void read_data_section(char *, int, char *, tagint) override;
bigint read_data_skip_lines(char *) override;
void write_data_header(FILE *, int) override;
void write_data_section_size(int, int &, int &) override;
void write_data_section_pack(int, double **) override;
void write_data_section_keyword(int, FILE *) override;
void write_data_section(int, FILE *, int, double **, int) override;
void write_restart(FILE *) override;
void restart(char *) override;
int pack_restart(int, double *) override;
void unpack_restart(int, int) override;
int size_restart(int) override;
int maxsize_restart() override;
void grow_arrays(int) override;
void copy_arrays(int, int, int) override;
void set_arrays(int) override;
int pack_border(int, int *, double *) override;
int unpack_border(int, int, double *) override;
int pack_exchange(int, double *) override;
int unpack_exchange(int, double *) override;
double memory_usage() override;
private:
int nprocs, me;
int eflag_caller;
int ilevel_respa;
int disable;
bigint nbitorsions; // total count of all bitorsions in system
double ebitorsion;
double onefifth;
// per-atom data for bitorsions stored with each owned atom
int *num_bitorsion;
int **bitorsion_type;
tagint **bitorsion_atom1, **bitorsion_atom2, **bitorsion_atom3;
tagint **bitorsion_atom4, **bitorsion_atom5;
// previous max atoms on this proc before grow() is called
int nmax_previous;
// list of all bitorsions to compute on this proc
int nbitorsion_list;
int max_bitorsion_list;
int **bitorsion_list;
// BiTorsion grid and spline data
int nbitypes;
int *nxgrid, *nygrid;
double **ttx, **tty, **tbf;
double **tbx, **tby, **tbxy;
// data from PairAmoeba
class Pair *pair;
int *amtype, *atomic_num;
// local methods
void read_grid_data(char *);
void create_splines();
void nspline(int, double *, double *, double *, double *, double *, double *, double *, double *,
double *);
void cspline(int, double *, double *, double *, double *, double *, double *, double *, double *,
double *, double *);
void cytsy(int, double *, double *, double *, double *, double *, int &);
void cytsyp(int, double *, double *, double *, int &);
void cytsys(int, double *, double *, double *, double *, double *);
void chkttor(int, int, int, double &, double &, double &);
void bcuint1(double *, double *, double *, double *, double, double, double, double, double,
double, double &, double &, double &);
void bcucof(double *, double *, double *, double *, double, double, double[][4]);
};
} // namespace LAMMPS_NS
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,98 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, 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
// clang-format off
FixStyle(amoeba/pitorsion,FixAmoebaPiTorsion);
// clang-format on
#else
#ifndef LMP_FIX_AMOEBA_PITORSION_H
#define LMP_FIX_AMOEBA_PITORSION_H
#include "fix.h"
namespace LAMMPS_NS {
class FixAmoebaPiTorsion : public Fix {
public:
FixAmoebaPiTorsion(class LAMMPS *, int, char **);
~FixAmoebaPiTorsion() override;
int setmask() override;
void init() override;
void setup(int) override;
void setup_pre_neighbor() override;
void setup_pre_reverse(int, int) override;
void min_setup(int) override;
void pre_neighbor() override;
void pre_reverse(int, int) override;
void post_force(int) override;
void post_force_respa(int, int, int) override;
void min_post_force(int) override;
double compute_scalar() override;
void read_data_header(char *) override;
void read_data_section(char *, int, char *, tagint) override;
bigint read_data_skip_lines(char *) override;
void write_data_header(FILE *, int) override;
void write_data_section_size(int, int &, int &) override;
void write_data_section_pack(int, double **) override;
void write_data_section_keyword(int, FILE *) override;
void write_data_section(int, FILE *, int, double **, int) override;
void write_restart(FILE *) override;
void restart(char *) override;
int pack_restart(int, double *) override;
void unpack_restart(int, int) override;
int size_restart(int) override;
int maxsize_restart() override;
void grow_arrays(int) override;
void copy_arrays(int, int, int) override;
void set_arrays(int) override;
int pack_exchange(int, double *) override;
int unpack_exchange(int, double *) override;
double memory_usage() override;
private:
int nprocs, me;
int eflag_caller;
int ilevel_respa;
int disable;
bigint npitorsions;
int npitorsion_types;
double epitorsion;
double onesixth;
double *kpit;
// per-atom data for pitorsions stored with each owned atom
int *num_pitorsion;
int **pitorsion_type;
tagint **pitorsion_atom1, **pitorsion_atom2, **pitorsion_atom3;
tagint **pitorsion_atom4, **pitorsion_atom5, **pitorsion_atom6;
// previous max atoms on this proc before grow() is called
int nmax_previous;
// list of all pitorsions to compute on this proc
int npitorsion_list;
int max_pitorsion_list;
int **pitorsion_list;
};
} // namespace LAMMPS_NS
#endif
#endif

View File

@ -0,0 +1,338 @@
// clang-format off
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, 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.
------------------------------------------------------------------------- */
#include "improper_amoeba.h"
#include "atom.h"
#include "comm.h"
#include "error.h"
#include "force.h"
#include "math_const.h"
#include "memory.h"
#include "neighbor.h"
#include "pair.h"
#include "update.h"
#include <cmath>
using namespace LAMMPS_NS;
using namespace MathConst;
#define TOLERANCE 0.05
#define SMALL 0.001
/* ---------------------------------------------------------------------- */
ImproperAmoeba::ImproperAmoeba(LAMMPS *lmp) : Improper(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
ImproperAmoeba::~ImproperAmoeba()
{
if (allocated && !copymode) {
memory->destroy(setflag);
memory->destroy(k);
}
}
/* ---------------------------------------------------------------------- */
void ImproperAmoeba::compute(int eflag, int vflag)
{
if (disable) return;
int ia,ib,ic,id,n,type;
double xia,yia,zia,xib,yib,zib,xic,yic,zic,xid,yid,zid;
double xab,yab,zab,xcb,ycb,zcb,xdb,ydb,zdb,xad,yad,zad,xcd,ycd,zcd;
double rad2,rcd2,rdb2,dot,cc,ee;
double sine,angle;
double dt,dt2,dt3,dt4,e;
double deddt,sign,dedcos,term;
double dccdxia,dccdyia,dccdzia,dccdxic,dccdyic,dccdzic;
double dccdxid,dccdyid,dccdzid;
double deedxia,deedyia,deedzia,deedxic,deedyic,deedzic;
double deedxid,deedyid,deedzid;
double fa[3],fb[3],fc[3],fd[3];
ev_init(eflag,vflag);
double **x = atom->x;
double **f = atom->f;
int **improperlist = neighbor->improperlist;
int nimproperlist = neighbor->nimproperlist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
// conversion factors for radians to degrees and vice versa
double rad2degree = 180.0/MY_PI;
double eprefactor = 1.0 / (rad2degree*rad2degree);
double fprefactor = 1.0 / rad2degree;
for (n = 0; n < nimproperlist; n++) {
// in Tinker code, atom1 = D, atom2 = B, atom3 = A, atom4 = C
// for Alligner angle:
// atoms A,C,D form a plane, B is out-of-plane
// angle is between plane and the vector from D to B
id = improperlist[n][0];
ib = improperlist[n][1];
ia = improperlist[n][2];
ic = improperlist[n][3];
type = improperlist[n][4];
// coordinates of the atoms at trigonal center
xia = x[ia][0];
yia = x[ia][1];
zia = x[ia][2];
xib = x[ib][0];
yib = x[ib][1];
zib = x[ib][2];
xic = x[ic][0];
yic = x[ic][1];
zic = x[ic][2];
xid = x[id][0];
yid = x[id][1];
zid = x[id][2];
// compute the out-of-plane bending angle
xab = xia - xib;
yab = yia - yib;
zab = zia - zib;
xcb = xic - xib;
ycb = yic - yib;
zcb = zic - zib;
xdb = xid - xib;
ydb = yid - yib;
zdb = zid - zib;
xad = xia - xid;
yad = yia - yid;
zad = zia - zid;
xcd = xic - xid;
ycd = yic - yid;
zcd = zic - zid;
// Allinger angle between A-C-D plane and D-B vector for D-B < AC
rad2 = xad*xad + yad*yad + zad*zad;
rcd2 = xcd*xcd + ycd*ycd + zcd*zcd;
dot = xad*xcd + yad*ycd + zad*zcd;
cc = rad2*rcd2 - dot*dot;
// find the out-of-plane angle bending energy
ee = xdb*(yab*zcb-zab*ycb) + ydb*(zab*xcb-xab*zcb) + zdb*(xab*ycb-yab*xcb);
rdb2 = xdb*xdb + ydb*ydb + zdb*zdb;
if (rdb2 == 0.0 || cc == 0.0) continue;
sine = fabs(ee) / sqrt(cc*rdb2);
sine = MIN(1.0,sine);
// angle needs to be in degrees for Tinker formulas
// b/c opbend_3456 coeffs are in mixed units
angle = rad2degree * asin(sine);
dt = angle;
dt2 = dt * dt;
dt3 = dt2 * dt;
dt4 = dt2 * dt2;
e = eprefactor * k[type] * dt2 *
(1.0 + opbend_cubic*dt + opbend_quartic*dt2 +
opbend_pentic*dt3 + opbend_sextic*dt4);
deddt = fprefactor * k[type] * dt *
(2.0 + 3.0*opbend_cubic*dt + 4.0*opbend_quartic*dt2 +
5.0*opbend_pentic*dt3 + 6.0*opbend_sextic*dt4);
sign = (ee >= 0.0) ? 1.0 : -1.0;
dedcos = -deddt * sign / sqrt(cc*rdb2 - ee*ee);
// chain rule terms for first derivative components
term = ee / cc;
dccdxia = (xad*rcd2-xcd*dot) * term;
dccdyia = (yad*rcd2-ycd*dot) * term;
dccdzia = (zad*rcd2-zcd*dot) * term;
dccdxic = (xcd*rad2-xad*dot) * term;
dccdyic = (ycd*rad2-yad*dot) * term;
dccdzic = (zcd*rad2-zad*dot) * term;
dccdxid = -dccdxia - dccdxic;
dccdyid = -dccdyia - dccdyic;
dccdzid = -dccdzia - dccdzic;
term = ee / rdb2;
deedxia = ydb*zcb - zdb*ycb;
deedyia = zdb*xcb - xdb*zcb;
deedzia = xdb*ycb - ydb*xcb;
deedxic = yab*zdb - zab*ydb;
deedyic = zab*xdb - xab*zdb;
deedzic = xab*ydb - yab*xdb;
deedxid = ycb*zab - zcb*yab + xdb*term;
deedyid = zcb*xab - xcb*zab + ydb*term;
deedzid = xcb*yab - ycb*xab + zdb*term;
// compute first derivative components for this angle
fa[0] = dedcos * (dccdxia+deedxia);
fa[1] = dedcos * (dccdyia+deedyia);
fa[2] = dedcos * (dccdzia+deedzia);
fc[0] = dedcos * (dccdxic+deedxic);
fc[1] = dedcos * (dccdyic+deedyic);
fc[2] = dedcos * (dccdzic+deedzic);
fd[0] = dedcos * (dccdxid+deedxid);
fd[1] = dedcos * (dccdyid+deedyid);
fd[2] = dedcos * (dccdzid+deedzid);
fb[0] = -fa[0] - fc[0] - fd[0];
fb[1] = -fa[1] - fc[1] - fd[1];
fb[2] = -fa[2] - fc[2] - fd[2];
// apply force to each of 4 atoms
if (newton_bond || id < nlocal) {
f[id][0] -= fd[0];
f[id][1] -= fd[1];
f[id][2] -= fd[2];
}
if (newton_bond || ib < nlocal) {
f[ib][0] -= fb[0];
f[ib][1] -= fb[1];
f[ib][2] -= fb[2];
}
if (newton_bond || ia < nlocal) {
f[ia][0] -= fa[0];
f[ia][1] -= fa[1];
f[ia][2] -= fa[2];
}
if (newton_bond || ic < nlocal) {
f[ic][0] -= fc[0];
f[ic][1] -= fc[1];
f[ic][2] -= fc[2];
}
if (evflag) {
fd[0] = -fd[0]; fd[1] = -fd[1]; fd[2] = -fd[2];
fa[0] = -fa[0]; fa[1] = -fa[1]; fa[2] = -fa[2];
fc[0] = -fc[0]; fc[1] = -fc[1]; fc[2] = -fc[2];
ev_tally(id,ib,ia,ic,nlocal,newton_bond,e,fd,fa,fc,
xdb,ydb,zdb,xab,yab,zab,xic-xia,yic-yia,zic-zia);
}
}
}
/* ---------------------------------------------------------------------- */
void ImproperAmoeba::allocate()
{
allocated = 1;
int n = atom->nimpropertypes;
memory->create(k,n+1,"improper:k");
memory->create(setflag,n+1,"improper:setflag");
for (int i = 1; i <= n; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one type
------------------------------------------------------------------------- */
void ImproperAmoeba::coeff(int narg, char **arg)
{
if (narg != 2) error->all(FLERR,"Incorrect args for improper coefficients");
if (!allocated) allocate();
int ilo,ihi;
utils::bounds(FLERR,arg[0],1,atom->nimpropertypes,ilo,ihi,error);
double k_one = utils::numeric(FLERR,arg[1],false,lmp);
// convert chi from degrees to radians
int count = 0;
for (int i = ilo; i <= ihi; i++) {
k[i] = k_one;
setflag[i] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for improper coefficients");
}
/* ----------------------------------------------------------------------
set opbend higher-order term weights from PairAmoeba
------------------------------------------------------------------------- */
void ImproperAmoeba::init_style()
{
// check if PairAmoeba disabled improper terms
Pair *pair = nullptr;
pair = force->pair_match("amoeba",1,0);
if (!pair) pair = force->pair_match("hippo",1,0);
if (!pair) error->all(FLERR,"Improper amoeba could not find pair amoeba/hippo");
int tmp;
int flag = *((int *) pair->extract("improper_flag",tmp));
disable = flag ? 0 : 1;
// also extract opbend params
int dim;
opbend_cubic = *(double *) pair->extract("opbend_cubic",dim);
opbend_quartic = *(double *) pair->extract("opbend_quartic",dim);
opbend_pentic = *(double *) pair->extract("opbend_pentic",dim);
opbend_sextic = *(double *) pair->extract("opbend_sextic",dim);
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void ImproperAmoeba::write_restart(FILE *fp)
{
fwrite(&k[1],sizeof(double),atom->nimpropertypes,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void ImproperAmoeba::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0)
utils::sfread(FLERR,&k[1],sizeof(double),atom->nimpropertypes,fp,nullptr,error);
MPI_Bcast(&k[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1;
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void ImproperAmoeba::write_data(FILE *fp)
{
for (int i = 1; i <= atom->nimpropertypes; i++)
fprintf(fp,"%d %g\n",i,k[i]);
}

View File

@ -0,0 +1,47 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, 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 IMPROPER_CLASS
// clang-format off
ImproperStyle(amoeba,ImproperAmoeba);
// clang-format on
#else
#ifndef LMP_IMPROPER_AMOEBA_H
#define LMP_IMPROPER_AMOEBA_H
#include "improper.h"
namespace LAMMPS_NS {
class ImproperAmoeba : public Improper {
public:
ImproperAmoeba(class LAMMPS *);
~ImproperAmoeba() override;
void compute(int, int) override;
void coeff(int, char **) override;
void init_style() override;
void write_restart(FILE *) override;
void read_restart(FILE *) override;
void write_data(FILE *) override;
protected:
int disable;
double opbend_cubic, opbend_quartic, opbend_pentic, opbend_sextic;
double *k;
virtual void allocate();
};
} // namespace LAMMPS_NS
#endif
#endif

2336
src/AMOEBA/pair_amoeba.cpp Normal file

File diff suppressed because it is too large Load Diff

480
src/AMOEBA/pair_amoeba.h Normal file
View File

@ -0,0 +1,480 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/ 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
// clang-format off
PairStyle(amoeba,PairAmoeba);
// clang-format on
#else
#ifndef LMP_PAIR_AMOEBA_H
#define LMP_PAIR_AMOEBA_H
#include "lmpfftsettings.h"
#include "pair.h"
namespace LAMMPS_NS {
#define SBBITS15 29
#define NEIGHMASK15 0x1FFFFFFF
class PairAmoeba : public Pair {
public:
PairAmoeba(class LAMMPS *);
~PairAmoeba() override;
void compute(int, int) override;
void settings(int, char **) override;
void coeff(int, char **) override;
void init_style() override;
double init_one(int, int) override;
void finish() override;
int pack_forward_comm(int, int *, double *, int, int *) override;
void unpack_forward_comm(int, int, double *) override;
int pack_reverse_comm(int, int, double *) override;
void unpack_reverse_comm(int, int *, double *) override;
void pack_forward_grid(int, void *, int, int *) override;
void unpack_forward_grid(int, void *, int, int *) override;
void pack_reverse_grid(int, void *, int, int *) override;
void unpack_reverse_grid(int, void *, int, int *) override;
void *extract(const char *, int &) override;
double memory_usage() override;
protected:
int nmax; // allocation for owned+ghost
int cfstyle, crstyle; // style of forward/reverse comm operations
int nualt;
double electric;
double rotate[3][3]; // rotation matrix
bool amoeba; // which force field: amoeba == true, hippo == false
std::string mystyle; // text label for style
int first_flag; // 1 before first init_style()
int first_flag_compute; // 1 before first call to compute()
int optlevel;
// turn on/off components of force field
int hal_flag, repulse_flag, qxfer_flag;
int disp_rspace_flag, disp_kspace_flag;
int polar_rspace_flag, polar_kspace_flag;
int mpole_rspace_flag, mpole_kspace_flag;
int bond_flag, angle_flag, dihedral_flag, improper_flag;
int urey_flag, pitorsion_flag, bitorsion_flag;
// DEBUG timers
double time_init, time_hal, time_repulse, time_disp;
double time_mpole, time_induce, time_polar, time_qxfer;
// energy/virial components
double ehal, erepulse, edisp, epolar, empole, eqxfer;
double virhal[6], virrepulse[6], virdisp[6], virpolar[6], virmpole[6], virqxfer[6];
// scalar values defined in force-field file
char *forcefield; // FF name
double am_dielectric;
int opbendtype, vdwtype;
int radius_rule, radius_type, radius_size, epsilon_rule;
double bond_cubic, bond_quartic;
double angle_cubic, angle_quartic, angle_pentic, angle_sextic;
double opbend_cubic, opbend_quartic, opbend_pentic, opbend_sextic;
double torsion_unit;
int poltyp;
double special_hal[5];
double special_repel[5];
double special_disp[5];
double special_mpole[5];
double special_polar_pscale[5];
double special_polar_piscale[5];
double special_polar_wscale[5];
double polar_dscale, polar_uscale;
// scalar values defined in keyfile
double dhal, ghal;
double vdwcut, vdwtaper;
double repcut, reptaper;
double dispcut, disptaper;
double mpolecut, mpoletaper;
double ctrncut, ctrntaper;
double ewaldcut;
double dewaldcut;
double usolvcut;
int use_ewald, use_dewald;
int use_pred;
int politer, polpred;
int pcgprec, pcgguess;
double pcgpeek;
int tcgnab, optorder;
int maxualt;
double poleps;
double udiag;
int aeewald_key, apewald_key, adewald_key;
int pmegrid_key, dpmegrid_key;
// types and classes
int n_amtype; // # of defined AMOEBA types, 1-N
int n_amclass; // # of defined AMOEBA classes, 1-N
int max_amtype; // allocation length of per-type data
int max_amclass; // allocation length of per-class data
int *amtype_defined; // 1 if type was defined in FF file
int *amclass_defined; // 1 if class was defined in FF file
int *amtype2class; // amt2c[i] = class which type I belongs to
// static per-atom properties, must persist as atoms migrate
int index_amtype, index_amgroup, index_redID;
int index_xyzaxis, index_polaxe, index_pval;
int *amtype; // AMOEBA type, 1 to N_amtype
int *amgroup; // AMOEBA polarization group, 1 to Ngroup
char *id_pole, *id_udalt, *id_upalt;
class FixStorePeratom *fixpole; // stores pole = multipole components
class FixStorePeratom *fixudalt; // stores udalt = induced dipole history
class FixStorePeratom *fixupalt; // stores upalt = induced dipole history
// static per-type properties defined in force-field file
int *atomic_num; // atomic number
int *valence; // valence (# of possible bonds)
double *am_mass; // atomic weight
double *am_q; // charge
double **am_mu; // dipole moment
double *polarity; // for polar
double *pdamp; // for polar
double *thole; // for polar
double *dirdamp; // for polar
int *npolgroup; // # of other types in polarization group, per-type
int **polgroup; // list of other types in polarization group, per-type
double *sizpr, *dmppr, *elepr;
// multipole frame info for each amtype, read from PRM file
int *nmultiframe; // # of frames for each type
int **mpaxis; // polaxe values
int **xpole, **ypole, **zpole; // other types in xyz dirs for multipole frame
double ***fpole; // 13 values from file
// 0 = monopole, same as q
// 1,2,3 = 3 dipole components
// 4-12 = 9 quadrupole components
// static per-class properties defined in force-field file
double *vdwl_eps; // Vdwl epsilon for each class of atom
double *vdwl_sigma; // Vdwl sigma for each class of atom
double *kred; // fraction that H atoms move towards bonded atom
// used in Vdwl, 0.0 if not H atom
double *csix, *adisp; // used in dispersion
double *chgct, *dmpct; // used in charge transfer
double *pcore, *palpha; // for multipole
int **vdwl_class_pair; // Vdwl iclass/jclass for pair of classes
double *vdwl_eps_pair; // Vdwl epsilon for pair of classes
double *vdwl_sigma_pair; // Vdwl sigma for pair of classes
int nvdwl_pair; // # of pairwise Vdwl entries in file
int max_vdwl_pair; // size of allocated data for pairwise Vdwl
// vectors and arrays of small size
double *copt, *copm; // 0:optorder in length
double *gear, *aspc;
double *a_ualt, *ap_ualt; // maxualt*(maxualt+1)/2 in length
double *b_ualt, *bp_ualt; // maxualt in length
double **c_ualt, **cp_ualt; // maxualt x maxualt in size
// indices NOT flipped vs Fortran
double *bpred, *bpredp, *bpreds, *bpredps; // maxualt in length
double vmsave[6]; // multipole virial saved to use in polar
double csixpr; // square of csix for all atoms
// params common to pairwise terms
double off2, cut2;
double c0, c1, c2, c3, c4, c5;
// Vdwl hal params - only for AMOEBA
double **radmin, **epsilon;
double **radmin4, **epsilon4;
// peratom values computed each step
// none of them persist with atoms
// some of them need communication to ghosts
double **rpole; // multipole, comm to ghosts
int *xaxis2local, *yaxis2local, *zaxis2local; // xyz axis IDs -> local indices
// just for owned atoms
// set to self if not defined
int *red2local; // local indices of ired IDs, computed for owned and ghost
double **xred; // altered coords for H atoms for Vdwl, comm to ghosts
double **tq; // torque from pairwise multipole, reverse comm from ghosts
double **uind, **uinp; // computed by induce, comm to ghosts
double **udirp;
double **rsd, **rsdp; // used by induce, comm to ghosts
double **field, **fieldp; // used by induce, reverse comm from ghosts
double ***uopt, ***uoptp; // Nlocal x Optorder+1 x 3 arrays
double **ufld, **dufld; // used by polar, reverse comm from ghosts
double **zrsd, **zrsdp; // used by induce, reverse comm from ghosts
double ***uad, ***uap, ***ubd, ***ubp; // used by TCG (not for now)
double ***fopt, ***foptp; // computed in induce, used by polar, if OPT
// Nlocal x optorder x 10
double *poli;
double **conj, **conjp;
double **vec, **vecp;
double **udir, **usum, **usump;
double **fuind, **fuinp;
double **fdip_phi1, **fdip_phi2, **fdip_sum_phi;
double **dipfield1, **dipfield2;
double **fphid, **fphip;
double **fphidp, **cphidp;
// derived local neighbor lists
int *numneigh_dipole; // number of dipole neighs for each atom
int **firstneigh_dipole; // ptr to each atom's dipole neigh indices
MyPage<int> *ipage_dipole; // pages of neighbor indices for dipole neighs
double **firstneigh_dipdip; // ptr to each atom's dip/dip values
MyPage<double> *dpage_dipdip; // pages of dip/dip values for dipole neighs
int *numneigh_precond; // number of precond neighs for each atom
int **firstneigh_precond; // ptr to each atom's precond neigh indices
MyPage<int> *ipage_precond; // pages of neighbor indices for precond neighs
double **firstneigh_pcpc; // ptr to each atom's pc/pc values
MyPage<double> *dpage_pcpc; // pages of pc/pc values for precond neighs
// KSpace data
// in indices = owned portion of grid in spatial decomp
// out indices = in + ghost grid cells
// fft indices = owned portion of grid in FFT decomp
int nefft1, nefft2, nefft3; // for electrostatic PME operations
int ndfft1, ndfft2, ndfft3; // for dispersion PME operations
int bseorder; // for electrostatics
int bsporder; // for polarization
int bsdorder; // for dispersion
int bsordermax; // max of 3 bsorder values
double aewald; // current Ewald alpha
double aeewald; // for electrostatics
double apewald; // for polarization
double adewald; // for dispersion
double *bsmod1, *bsmod2, *bsmod3; // B-spline module along abc axes
// set to max of any nfft1,nfft2,nfft3
double ***thetai1, ***thetai2, ***thetai3; // B-spline coeffs along abc axes
// Nlocal x max bsorder x 4
int **igrid; // grid indices for each owned particle, Nlocal x 3
double **bsbuild; // used internally in bsplgen, max-bsorder x max-bsorder
// indices ARE flipped vs Fortran
// Kspace data for induce and polar
double *qfac; // convoulution pre-factors
double *gridfft1; // copy of p_kspace FFT grid
double **cmp, **fmp; // Cartesian and fractional multipoles
double **cphi, **fphi;
// params for current KSpace solve and FFT being worked on
int nfft1, nfft2, nfft3; // size of FFT
int bsorder; // stencil size
double recip[3][3]; // indices NOT flipped vs Fortran
double ctf[10][10]; // indices NOT flipped vs Fortran
double ftc[10][10]; // indices NOT flipped vs Fortran
class AmoebaConvolution *m_kspace, *p_kspace, *pc_kspace, *d_kspace;
class AmoebaConvolution *i_kspace, *ic_kspace;
// FFT grid size factors
int nfactors; // # of factors
int *factors; // list of possible factors (2,3,5)
// components of force field
void hal();
void repulsion();
void damprep(double, double, double, double, double, double, double, double, int, double, double,
double *);
void dispersion();
void dispersion_real();
void dispersion_kspace();
void multipole();
void multipole_real();
void multipole_kspace();
void polar();
void polar_energy();
void polar_real();
void polar_kspace();
void damppole(double, int, double, double, double *, double *, double *);
void induce();
void ulspred();
void ufield0c(double **, double **);
void uscale0b(int, double **, double **, double **, double **);
void dfield0c(double **, double **);
void umutual1(double **, double **);
void umutual2b(double **, double **);
void udirect1(double **);
void udirect2b(double **, double **);
void dampmut(double, double, double, double *);
void dampdir(double, double, double, double *, double *);
void cholesky(int, double *, double *);
void charge_transfer();
// KSpace methods
void lattice();
void moduli();
void bspline(double, int, double *);
void dftmod(double *, double *, int, int);
void bspline_fill();
void bsplgen(double, double **);
void cmp_to_fmp(double **, double **);
void cart_to_frac();
void fphi_to_cphi(double **, double **);
void frac_to_cart();
void grid_mpole(double **, double ***);
void fphi_mpole(double ***, double **);
void grid_uind(double **, double **, double ****);
void fphi_uind(double ****, double **, double **, double **);
void grid_disp(double ***);
void kewald();
void kewald_parallel(int, int, int, int, int &, int &, int &, int &, int &, int &, int &, int &,
int &, int &, int &, int &, int &, int &, int &, int &, int &, int &);
double ewaldcof(double);
int factorable(int);
// debug methods
FILE *fp_uind;
void dump6(FILE *, const char *, double, double **, double **);
// functions in pair_amoeba.cpp
void allocate();
void print_settings();
void initialize_vdwl();
void allocate_vdwl();
void deallocate_vdwl();
void initialize_smallsize();
void allocate_smallsize();
void deallocate_smallsize();
void assign_groups();
void pbc_xred();
void precond_neigh();
void choose(int);
void mix();
void zero_energy_force_virial();
void grow_local();
// functions in amoeba_utils.cpp
void kmpole();
void chkpole(int);
void rotmat(int);
void rotsite(int);
void add_onefive_neighbors();
void find_hydrogen_neighbors();
void find_multipole_neighbors();
void torque2force(int, double *, double *, double *, double *, double **);
// functions in file_amoeba.cpp
void set_defaults();
void read_prmfile(char *);
void read_keyfile(char *);
void initialize_type_class();
void allocate_type_class(int, int);
void deallocate_type_class();
void file_ffield(const std::vector<std::string> &, int);
void file_literature(const std::vector<std::string> &, int);
void file_atomtype(const std::vector<std::string> &, int);
void file_vdwl(const std::vector<std::string> &, int);
void file_vdwl_pair(const std::vector<std::string> &, int);
void file_bstretch(const std::vector<std::string> &, int);
void file_sbend(const std::vector<std::string> &, int);
void file_abend(const std::vector<std::string> &, int);
void file_pauli(const std::vector<std::string> &, int);
void file_dispersion(const std::vector<std::string> &, int);
void file_ub(const std::vector<std::string> &, int);
void file_outplane(const std::vector<std::string> &, int);
void file_torsion(const std::vector<std::string> &, int);
void file_pitorsion(const std::vector<std::string> &, int);
void file_multipole(const std::vector<std::string> &, int);
void file_charge_penetration(const std::vector<std::string> &, int);
void file_dippolar(const std::vector<std::string> &, int);
void file_charge_transfer(const std::vector<std::string> &, int);
// inline function for neighbor list unmasking
inline int sbmask15(int j) const { return j >> SBBITS15 & 7; }
};
} // namespace LAMMPS_NS
#endif
#endif

24
src/AMOEBA/pair_hippo.cpp Normal file
View File

@ -0,0 +1,24 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/ 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.
------------------------------------------------------------------------- */
#include "pair_hippo.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
PairHippo::PairHippo(LAMMPS *lmp) : PairAmoeba(lmp)
{
amoeba = false;
mystyle = "hippo";
}

33
src/AMOEBA/pair_hippo.h Normal file
View File

@ -0,0 +1,33 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/ 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
// clang-format off
PairStyle(hippo,PairHippo);
// clang-format on
#else
#ifndef LMP_PAIR_HIPPO_H
#define LMP_PAIR_HIPPO_H
#include "pair_amoeba.h"
namespace LAMMPS_NS {
class PairHippo : public PairAmoeba {
public:
PairHippo(class LAMMPS *);
};
} // namespace LAMMPS_NS
#endif
#endif

View File

@ -43,9 +43,9 @@ void ComputeERotateAsphere::init()
{
// error check
avec_ellipsoid = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
avec_line = (AtomVecLine *) atom->style_match("line");
avec_tri = (AtomVecTri *) atom->style_match("tri");
avec_ellipsoid = dynamic_cast<AtomVecEllipsoid *>( atom->style_match("ellipsoid"));
avec_line = dynamic_cast<AtomVecLine *>( atom->style_match("line"));
avec_tri = dynamic_cast<AtomVecTri *>( atom->style_match("tri"));
if (!avec_ellipsoid && !avec_line && !avec_tri)
error->all(FLERR,"Compute erotate/asphere requires "
"atom style ellipsoid or line or tri");

View File

@ -41,21 +41,3 @@ class ComputeERotateAsphere : public Compute {
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: Compute erotate/asphere requires atom style ellipsoid or line or tri
Self-explanatory.
E: Compute erotate/asphere requires extended particles
This compute cannot be used with point particles.
*/

View File

@ -94,7 +94,7 @@ void ComputeTempAsphere::init()
{
// error check
avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
avec = dynamic_cast<AtomVecEllipsoid *>( atom->style_match("ellipsoid"));
if (!avec)
error->all(FLERR,"Compute temp/asphere requires atom style ellipsoid");

View File

@ -52,43 +52,3 @@ class ComputeTempAsphere : public Compute {
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: Compute temp/asphere requires atom style ellipsoid
Self-explanatory.
E: Compute temp/asphere requires extended particles
This compute cannot be used with point particles.
E: Could not find compute ID for temperature bias
Self-explanatory.
E: Bias compute does not calculate temperature
The specified compute must compute temperature.
E: Bias compute does not calculate a velocity bias
The specified compute must compute a bias for temperature.
E: Bias compute group does not match compute group
The specified compute must operate on the same group as the parent
compute.
E: Temperature compute degrees of freedom < 0
This should not happen if you are calculating the temperature
on a valid set of atoms.
*/

View File

@ -36,7 +36,7 @@ FixNHAsphere::FixNHAsphere(LAMMPS *lmp, int narg, char **arg) :
void FixNHAsphere::init()
{
avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
avec = dynamic_cast<AtomVecEllipsoid *>( atom->style_match("ellipsoid"));
if (!avec)
error->all(FLERR,
"Compute nvt/nph/npt asphere requires atom style ellipsoid");

View File

@ -35,16 +35,3 @@ class FixNHAsphere : public FixNH {
} // namespace LAMMPS_NS
#endif
/* ERROR/WARNING messages:
E: Compute nvt/nph/npt asphere requires atom style ellipsoid
Self-explanatory.
E: Fix nvt/nph/npt asphere requires extended particles
The shape setting for a particle in the fix group has shape = 0.0,
which means it is a point particle.
*/

View File

@ -33,15 +33,3 @@ class FixNPHAsphere : public FixNHAsphere {
#endif
#endif
/* ERROR/WARNING messages:
E: Temperature control can not be used with fix nph/asphere
Self-explanatory.
E: Pressure control must be used with fix nph/asphere
Self-explanatory.
*/

View File

@ -33,15 +33,3 @@ class FixNPTAsphere : public FixNHAsphere {
#endif
#endif
/* ERROR/WARNING messages:
E: Temperature control must be used with fix npt/asphere
Self-explanatory.
E: Pressure control must be used with fix npt/asphere
Self-explanatory.
*/

View File

@ -37,7 +37,7 @@ FixNVEAsphere::FixNVEAsphere(LAMMPS *lmp, int narg, char **arg) :
void FixNVEAsphere::init()
{
avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
avec = dynamic_cast<AtomVecEllipsoid *>( atom->style_match("ellipsoid"));
if (!avec)
error->all(FLERR,"Compute nve/asphere requires atom style ellipsoid");

View File

@ -39,15 +39,3 @@ class FixNVEAsphere : public FixNVE {
} // namespace LAMMPS_NS
#endif
#endif
/* ERROR/WARNING messages:
E: Compute nve/asphere requires atom style ellipsoid
Self-explanatory.
E: Fix nve/asphere requires extended particles
This fix can only be used for particles with a shape setting.
*/

View File

@ -37,7 +37,7 @@ void FixNVEAsphereNoforce::init()
{
// error check
avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
avec = dynamic_cast<AtomVecEllipsoid *>( atom->style_match("ellipsoid"));
if (!atom->ellipsoid_flag)
error->all(FLERR,"Fix nve/asphere/noforce requires atom style ellipsoid");

View File

@ -39,21 +39,3 @@ class FixNVEAsphereNoforce : public FixNVENoforce {
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: Fix nve/asphere/noforce requires atom style ellipsoid
Self-explanatory.
E: Fix nve/asphere/noforce requires extended particles
One of the particles is not an ellipsoid.
*/

View File

@ -56,7 +56,7 @@ void FixNVELine::init()
{
// error checks
avec = (AtomVecLine *) atom->style_match("line");
avec = dynamic_cast<AtomVecLine *>( atom->style_match("line"));
if (!avec) error->all(FLERR,"Fix nve/line requires atom style line");
if (domain->dimension != 2)

View File

@ -41,25 +41,3 @@ class FixNVELine : public FixNVE {
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: Fix nve/line requires atom style line
Self-explanatory.
E: Fix nve/line can only be used for 2d simulations
Self-explanatory.
E: Fix nve/line requires line particles
Self-explanatory.
*/

View File

@ -50,7 +50,7 @@ void FixNVETri::init()
{
// error checks
avec = (AtomVecTri *) atom->style_match("tri");
avec = dynamic_cast<AtomVecTri *>( atom->style_match("tri"));
if (!avec) error->all(FLERR,"Fix nve/tri requires atom style tri");
if (domain->dimension != 3)

View File

@ -41,25 +41,3 @@ class FixNVETri : public FixNVE {
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: Fix nve/tri requires atom style tri
Self-explanatory.
E: Fix nve/tri can only be used for 3d simulations
Self-explanatory.
E: Fix nve/tri requires tri particles
Self-explanatory.
*/

View File

@ -33,15 +33,3 @@ class FixNVTAsphere : public FixNHAsphere {
#endif
#endif
/* ERROR/WARNING messages:
E: Temperature control must be used with fix nvt/asphere
Self-explanatory.
E: Pressure control can not be used with fix nvt/asphere
Self-explanatory.
*/

View File

@ -345,7 +345,7 @@ void PairGayBerne::coeff(int narg, char **arg)
void PairGayBerne::init_style()
{
avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
avec = dynamic_cast<AtomVecEllipsoid *>( atom->style_match("ellipsoid"));
if (!avec) error->all(FLERR,"Pair gayberne requires atom style ellipsoid");
neighbor->add_request(this,NeighConst::REQ_DEFAULT);

View File

@ -72,34 +72,3 @@ class PairGayBerne : public Pair {
} // namespace LAMMPS_NS
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: Incorrect args for pair coefficients
Self-explanatory. Check the input script or data file.
E: Pair gayberne requires atom style ellipsoid
Self-explanatory.
E: Pair gayberne requires atoms with same type have same shape
Self-explanatory.
E: Pair gayberne epsilon a,b,c coeffs are not all set
Each atom type involved in pair_style gayberne must
have these 3 coefficients set at least once.
E: Bad matrix inversion in mldivide3
This error should not occur unless the matrix is badly formed.
*/

View File

@ -402,7 +402,7 @@ void PairLineLJ::coeff(int narg, char **arg)
void PairLineLJ::init_style()
{
avec = (AtomVecLine *) atom->style_match("line");
avec = dynamic_cast<AtomVecLine *>( atom->style_match("line"));
if (!avec) error->all(FLERR,"Pair line/lj requires atom style line");
neighbor->add_request(this,NeighConst::REQ_DEFAULT);

View File

@ -62,26 +62,3 @@ class PairLineLJ : public Pair {
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: Incorrect args for pair coefficients
Self-explanatory. Check the input script or data file.
E: Pair line/lj requires atom style line
Self-explanatory.
E: All pair coeffs are not set
All pair coefficients must be set in the data file or by the
pair_coeff command before running a simulation.
*/

View File

@ -317,10 +317,10 @@ void PairRESquared::coeff(int narg, char **arg)
void PairRESquared::init_style()
{
avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
avec = dynamic_cast<AtomVecEllipsoid *>(atom->style_match("ellipsoid"));
if (!avec) error->all(FLERR, "Pair resquared requires atom style ellipsoid");
neighbor->add_request(this,NeighConst::REQ_DEFAULT);
neighbor->add_request(this, NeighConst::REQ_DEFAULT);
// per-type shape precalculations
// require that atom shapes are identical within each type

View File

@ -92,37 +92,3 @@ class PairRESquared : public Pair {
} // namespace LAMMPS_NS
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: Incorrect args for pair coefficients
Self-explanatory. Check the input script or data file.
E: Pair resquared requires atom style ellipsoid
Self-explanatory.
E: Pair resquared requires atoms with same type have same shape
Self-explanatory.
E: Pair resquared epsilon a,b,c coeffs are not all set
Self-explanatory.
E: Pair resquared epsilon and sigma coeffs are not all set
Self-explanatory.
E: Bad matrix inversion in mldivide3
This error should not occur unless the matrix is badly formed.
*/

View File

@ -467,7 +467,7 @@ void PairTriLJ::coeff(int narg, char **arg)
void PairTriLJ::init_style()
{
avec = (AtomVecTri *) atom->style_match("tri");
avec = dynamic_cast<AtomVecTri *>( atom->style_match("tri"));
if (!avec) error->all(FLERR,"Pair tri/lj requires atom style tri");
neighbor->add_request(this,NeighConst::REQ_DEFAULT);

View File

@ -60,21 +60,3 @@ class PairTriLJ : public Pair {
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: Incorrect args for pair coefficients
Self-explanatory. Check the input script or data file.
E: Pair tri/lj requires atom style tri
Self-explanatory.
*/

View File

@ -284,7 +284,7 @@ FixATC::FixATC(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg),
int me = ATC::LammpsInterface::instance()->comm_rank();
string groupName(arg[1]);
int igroup = group->find(groupName.c_str());
int igroup = group->find(groupName);
int atomCount = group->count(igroup);
try {

View File

@ -1,4 +1,3 @@
// clang-format off
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, Sandia National Laboratories
@ -20,8 +19,6 @@
#include "atom.h"
#include <cstring>
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
@ -32,33 +29,29 @@ AtomVecWavepacket::AtomVecWavepacket(LAMMPS *lmp) : AtomVec(lmp)
molecular = Atom::ATOMIC;
forceclearflag = 1;
atom->wavepacket_flag = 1;
atom->electron_flag = 1; // compatible with eff
atom->q_flag = atom->spin_flag = atom->eradius_flag =
atom->ervel_flag = atom->erforce_flag = 1;
atom->cs_flag = atom->csforce_flag =
atom->vforce_flag = atom->ervelforce_flag = atom->etag_flag = 1;
atom->wavepacket_flag = atom->q_flag = atom->spin_flag = atom->eradius_flag = 1;
atom->ervel_flag = atom->erforce_flag = atom->cs_flag = atom->csforce_flag = 1;
atom->vforce_flag = atom->ervelforce_flag = atom->etag_flag = 1;
// strings with peratom variables to include in each AtomVec method
// strings cannot contain fields in corresponding AtomVec default strings
// order of fields in a string does not matter
// except: fields_data_atom & fields_data_vel must match data file
fields_grow = (char *)
"q spin eradius ervel erforce cs csforce "
"vforce ervelforce etag";
fields_copy = (char *) "q spin eradius ervel cs etag";
fields_comm = (char *) "eradius";
fields_comm_vel = (char *) "eradius ervel cs";
fields_reverse = (char *) "erforce ervelforce vforce csforce";
fields_border = (char *) "q spin eradius etag";
fields_border_vel = (char *) "q spin eradius etag ervel cs";
fields_exchange = (char *) "q spin eradius ervel etag cs";
fields_restart = (char *) "q spin eradius ervel etag cs";
fields_create = (char *) "q spin eradius ervel etag cs";
fields_data_atom = (char *) "id type q spin eradius etag cs x";
fields_data_vel = (char *) "id v ervel";
fields_grow = {"q", "spin", "eradius", "ervel", "erforce",
"cs", "csforce", "vforce", "ervelforce", "etag"};
fields_copy = {"q", "spin", "eradius", "ervel", "cs", "etag"};
fields_comm = {"eradius"};
fields_comm_vel = {"eradius", "ervel", "cs"};
fields_reverse = {"erforce", "ervelforce", "vforce", "csforce"};
fields_border = {"q", "spin", "eradius", "etag"};
fields_border_vel = {"q", "spin", "eradius", "etag", "ervel", "cs"};
fields_exchange = {"q", "spin", "eradius", "ervel", "etag", "cs"};
fields_restart = {"q", "spin", "eradius", "ervel", "etag", "cs"};
fields_create = {"q", "spin", "eradius", "ervel", "etag", "cs"};
fields_data_atom = {"id", "type", "q", "spin", "eradius", "etag", "cs", "x"};
fields_data_vel = {"id", "v", "ervel"};
setup_fields();
}
@ -84,7 +77,7 @@ void AtomVecWavepacket::grow_pointers()
void AtomVecWavepacket::force_clear(int n, size_t nbytes)
{
memset(&erforce[n],0,nbytes);
memset(&erforce[n], 0, nbytes);
}
/* ----------------------------------------------------------------------
@ -112,12 +105,12 @@ void AtomVecWavepacket::data_atom_post(int ilocal)
return -1 if name is unknown to this atom style
------------------------------------------------------------------------- */
int AtomVecWavepacket::property_atom(char *name)
int AtomVecWavepacket::property_atom(const std::string &name)
{
if (strcmp(name,"spin") == 0) return 0;
if (strcmp(name,"eradius") == 0) return 1;
if (strcmp(name,"ervel") == 0) return 2;
if (strcmp(name,"erforce") == 0) return 3;
if (name == "spin") return 0;
if (name == "eradius") return 1;
if (name == "ervel") return 2;
if (name == "erforce") return 3;
return -1;
}
@ -126,34 +119,41 @@ int AtomVecWavepacket::property_atom(char *name)
index maps to data specific to this atom style
------------------------------------------------------------------------- */
void AtomVecWavepacket::pack_property_atom(int index, double *buf,
int nvalues, int groupbit)
void AtomVecWavepacket::pack_property_atom(int index, double *buf, int nvalues, int groupbit)
{
int nlocal = atom->nlocal;
int n = 0;
if (index == 0) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = spin[i];
else buf[n] = 0.0;
if (mask[i] & groupbit)
buf[n] = spin[i];
else
buf[n] = 0.0;
n += nvalues;
}
} else if (index == 1) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = eradius[i];
else buf[n] = 0.0;
if (mask[i] & groupbit)
buf[n] = eradius[i];
else
buf[n] = 0.0;
n += nvalues;
}
} else if (index == 2) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = ervel[i];
else buf[n] = 0.0;
if (mask[i] & groupbit)
buf[n] = ervel[i];
else
buf[n] = 0.0;
n += nvalues;
}
} else if (index == 3) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = erforce[i];
else buf[n] = 0.0;
if (mask[i] & groupbit)
buf[n] = erforce[i];
else
buf[n] = 0.0;
n += nvalues;
}
}

View File

@ -32,7 +32,7 @@ class AtomVecWavepacket : public AtomVec {
void force_clear(int, size_t) override;
void create_atom_post(int) override;
void data_atom_post(int) override;
int property_atom(char *) override;
int property_atom(const std::string &) override;
void pack_property_atom(int, double *, int, int) override;
private:

View File

@ -61,9 +61,9 @@ void FixNVEAwpmd::init()
dtf = 0.5 * update->dt * force->ftm2v;
if (utils::strmatch(update->integrate_style,"^respa"))
step_respa = ((Respa *) update->integrate)->step;
step_respa = (dynamic_cast<Respa *>( update->integrate))->step;
awpmd_pair=(PairAWPMDCut *)force->pair;
awpmd_pair=dynamic_cast<PairAWPMDCut *>(force->pair);
awpmd_pair->wpmd->norm_needed=1;
}

View File

@ -95,10 +95,7 @@ struct cmp_x{
else if (d>tol)
return false;
d=xx[left.second][2]-xx[right.second][2];
if (d<-tol)
return true;
else
return false;
return d < -tol;
}
else
return left.first<right.first;

View File

@ -80,42 +80,3 @@ class ComputePressureBocs : public Compute {
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: Compute pressure must use group all
Virial contributions computed by potentials (pair, bond, etc) are
computed on all atoms.
E: Could not find compute pressure temperature ID
The compute ID for calculating temperature does not exist.
E: Compute pressure temperature ID does not compute temperature
The compute ID assigned to a pressure computation must compute
temperature.
E: Compute pressure requires temperature ID to include kinetic energy
The keflag cannot be used unless a temperature compute is provided.
E: Virial was not tallied on needed timestep
You are using a thermo keyword that requires potentials to
have tallied the virial, but they didn't on this timestep. See the
variable doc page for ideas on how to make this work.
E: Must use 'kspace_modify pressure/scalar no' for tensor components with kspace_style msm
Otherwise MSM will compute only a scalar pressure. See the kspace_modify
command for details on this setting.
*/

View File

@ -489,7 +489,7 @@ void FixBocs::init()
{
for (int i = 0; i < modify->nfix; i++)
if (strcmp(modify->fix[i]->style,"deform") == 0) {
int *dimflag = ((FixDeform *) modify->fix[i])->dimflag;
int *dimflag = (dynamic_cast<FixDeform *>( modify->fix[i]))->dimflag;
if ((p_flag[0] && dimflag[0]) || (p_flag[1] && dimflag[1]) ||
(p_flag[2] && dimflag[2]) || (p_flag[3] && dimflag[3]) ||
(p_flag[4] && dimflag[4]) || (p_flag[5] && dimflag[5]))
@ -523,12 +523,12 @@ void FixBocs::init()
{
if (p_basis_type == BASIS_ANALYTIC)
{
((ComputePressureBocs *)pressure)->send_cg_info(p_basis_type,
(dynamic_cast<ComputePressureBocs *>(pressure))->send_cg_info(p_basis_type,
N_p_match, p_match_coeffs, N_mol, vavg);
}
else if (p_basis_type == BASIS_LINEAR_SPLINE || p_basis_type == BASIS_CUBIC_SPLINE)
{
((ComputePressureBocs *)pressure)->send_cg_info(p_basis_type,
(dynamic_cast<ComputePressureBocs *>(pressure))->send_cg_info(p_basis_type,
splines, spline_length);
}
}
@ -589,8 +589,8 @@ void FixBocs::init()
else kspace_flag = 0;
if (utils::strmatch(update->integrate_style,"^respa")) {
nlevels_respa = ((Respa *) update->integrate)->nlevels;
step_respa = ((Respa *) update->integrate)->step;
nlevels_respa = (dynamic_cast<Respa *>( update->integrate))->nlevels;
step_respa = (dynamic_cast<Respa *>( update->integrate))->step;
dto = 0.5*step_respa[0];
}
@ -1452,7 +1452,7 @@ int FixBocs::pack_restart_data(double *list)
void FixBocs::restart(char *buf)
{
int n = 0;
double *list = (double *) buf;
auto list = (double *) buf;
int flag = static_cast<int> (list[n++]);
if (flag) {
int m = static_cast<int> (list[n++]);
@ -1551,12 +1551,12 @@ int FixBocs::modify_param(int narg, char **arg)
{
if (p_basis_type == BASIS_ANALYTIC)
{
((ComputePressureBocs *)pressure)->send_cg_info(p_basis_type, N_p_match,
(dynamic_cast<ComputePressureBocs *>(pressure))->send_cg_info(p_basis_type, N_p_match,
p_match_coeffs, N_mol, vavg);
}
else if (p_basis_type == BASIS_LINEAR_SPLINE || p_basis_type == BASIS_CUBIC_SPLINE )
{
((ComputePressureBocs *)pressure)->send_cg_info(p_basis_type, splines, spline_length );
(dynamic_cast<ComputePressureBocs *>(pressure))->send_cg_info(p_basis_type, splines, spline_length );
}
}

View File

@ -30,7 +30,7 @@ namespace LAMMPS_NS {
class FixBocs : public Fix {
public:
FixBocs(class LAMMPS *, int, char **); // MRD NJD
~FixBocs() override; // MRD NJD
~FixBocs() override; // MRD NJD
int setmask() override;
void init() override;
void setup(int) override;
@ -169,136 +169,3 @@ class FixBocs : public Fix {
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: CG basis type XXX is not recognized
See second line of message for supported basis types.
E: Target temperature for fix bocs cannot be 0.0
Self-explanatory.
E: Invalid fix bocs command for a 2d simulation
Cannot control z dimension in a 2d model.
E: Fix bocs dilate group ID does not exist
Self-explanatory.
E: Invalid fix bocs command pressure settings
If multiple dimensions are coupled, those dimensions must be
specified.
E: Cannot use fix bocs on a non-periodic dimension
When specifying a diagonal pressure component, the dimension must be
periodic.
E: Cannot use fix bocs on a 2nd non-periodic dimension
When specifying an off-diagonal pressure component, the 2nd of the two
dimensions must be periodic. E.g. if the xy component is specified,
then the y dimension must be periodic.
E: Cannot use fix bocs with yz scaling when z is non-periodic dimension
The 2nd dimension in the barostatted tilt factor must be periodic.
E: Cannot use fix bocs with xz scaling when z is non-periodic dimension
The 2nd dimension in the barostatted tilt factor must be periodic.
E: Cannot use fix bocs with xy scaling when y is non-periodic dimension
The 2nd dimension in the barostatted tilt factor must be periodic.
E: Cannot use fix bocs with both yz dynamics and yz scaling
Self-explanatory.
E: Cannot use fix bocs with both xz dynamics and xz scaling
Self-explanatory.
E: Cannot use fix bocs with both xy dynamics and xy scaling
Self-explanatory.
E: Can not specify Pxy/Pxz/Pyz in fix bocs with non-triclinic box
Only triclinic boxes can be used with off-diagonal pressure components.
See the region prism command for details.
E: Invalid fix bocs pressure settings
Settings for coupled dimensions must be the same.
E: Using update dipole flag requires atom style sphere
Self-explanatory.
E: Using update dipole flag requires atom attribute mu
Self-explanatory.
E: The dlm flag must be used with update dipole
Self-explanatory.
E: Fix bocs damping parameters must be > 0.0
Self-explanatory.
E: Cannot use fix npt and fix deform on same component of stress tensor
This would be changing the same box dimension twice.
E: Temperature ID for fix bocs does not exist
Self-explanatory.
E: Pressure ID for fix bocs does not exist
Self-explanatory.
E: Fix bocs has tilted box too far in one step - periodic cell is too far from equilibrium state
Self-explanatory. The change in the box tilt is too extreme
on a short timescale.
E: Could not find fix_modify temperature ID
The compute ID for computing temperature does not exist.
E: Fix_modify temperature ID does not compute temperature
The compute ID assigned to the fix must compute temperature.
W: Temperature for fix modify is not for group all
The temperature compute is being used with a pressure calculation
which does operate on group all, so this may be inconsistent.
E: Pressure ID for fix modify does not exist
Self-explanatory.
E: Could not find fix_modify pressure ID
The compute ID for computing pressure does not exist.
E: Fix_modify pressure ID does not compute pressure
The compute ID assigned to the fix must compute pressure.
*/

View File

@ -53,27 +53,3 @@ class BodyNparticle : public Body {
#endif
#endif
/* ERROR/WARNING messages:
E: Invalid body nparticle command
Arguments in atom-style command are not correct.
E: Incorrect # of integer values in Bodies section of data file
See doc page for body style.
E: Incorrect integer value in Bodies section of data file
See doc page for body style.
E: Incorrect # of floating-point values in Bodies section of data file
See doc page for body style.
E: Insufficient Jacobi rotations for body nparticle
Eigensolve for rigid body was not sufficiently accurate.
*/

View File

@ -57,32 +57,3 @@ class BodyRoundedPolygon : public Body {
#endif
#endif
/* ERROR/WARNING messages:
E: Invalid body rounded/polygon command
Arguments in atom-style command are not correct.
E: Invalid format in Bodies section of data file
The specified number of integer or floating point values does not
appear.
E: Incorrect # of integer values in Bodies section of data file
See doc page for body style.
E: Incorrect integer value in Bodies section of data file
See doc page for body style.
E: Incorrect # of floating-point values in Bodies section of data file
See doc page for body style.
E: Insufficient Jacobi rotations for body nparticle
Eigensolve for rigid body was not sufficiently accurate.
*/

View File

@ -59,32 +59,3 @@ class BodyRoundedPolyhedron : public Body {
#endif
#endif
/* ERROR/WARNING messages:
E: Invalid body rounded/polyhedron command
Arguments in atom-style command are not correct.
E: Invalid format in Bodies section of data file
The specified number of integer or floating point values does not
appear.
E: Incorrect # of integer values in Bodies section of data file
See doc page for body style.
E: Incorrect integer value in Bodies section of data file
See doc page for body style.
E: Incorrect # of floating-point values in Bodies section of data file
See doc page for body style.
E: Insufficient Jacobi rotations for body rounded/polyhedron
Eigensolve for rigid body was not sufficiently accurate.
*/

View File

@ -53,7 +53,7 @@ ComputeBodyLocal::ComputeBodyLocal(LAMMPS *lmp, int narg, char **arg) :
}
}
avec = (AtomVecBody *) atom->style_match("body");
avec = dynamic_cast<AtomVecBody *>( atom->style_match("body"));
if (!avec) error->all(FLERR,"Compute body/local requires atom style body");
bptr = avec->bptr;
@ -153,7 +153,7 @@ int ComputeBodyLocal::compute_body(int flag)
// perform computation and fill output vector/array
int m,n,ibonus;
double *values = new double[bptr->noutcol()];
auto values = new double[bptr->noutcol()];
double **x = atom->x;
tagint *tag = atom->tag;

View File

@ -49,25 +49,3 @@ class ComputeBodyLocal : public Compute {
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: Compute body/local requires atom style body
Self-explanatory.
E: Invalid index in compute body/local command
Self-explanatory.
E: Invalid index for non-body particles in compute body/local command
Only indices 1,2,3 can be used for non-body particles.
*/

View File

@ -87,7 +87,7 @@ void ComputeTempBody::init()
{
// error check
avec = (AtomVecBody *) atom->style_match("body");
avec = dynamic_cast<AtomVecBody *>( atom->style_match("body"));
if (!avec)
error->all(FLERR,"Compute temp/body requires atom style body");

View File

@ -50,43 +50,3 @@ class ComputeTempBody : public Compute {
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: Compute temp/body requires atom style body
Self-explanatory.
E: Compute temp/body requires bodies
This compute can only be applied to body particles.
E: Could not find compute ID for temperature bias
Self-explanatory.
E: Bias compute does not calculate temperature
The specified compute must compute temperature.
E: Bias compute does not calculate a velocity bias
The specified compute must compute a bias for temperature.
E: Bias compute group does not match compute group
The specified compute must operate on the same group as the parent
compute.
E: Temperature compute degrees of freedom < 0
This should not happen if you are calculating the temperature
on a valid set of atoms.
*/

View File

@ -37,7 +37,7 @@ FixNHBody::FixNHBody(LAMMPS *lmp, int narg, char **arg) :
void FixNHBody::init()
{
avec = (AtomVecBody *) atom->style_match("body");
avec = dynamic_cast<AtomVecBody *>( atom->style_match("body"));
if (!avec)
error->all(FLERR,
"Compute nvt/nph/npt body requires atom style body");

View File

@ -35,15 +35,3 @@ class FixNHBody : public FixNH {
} // namespace LAMMPS_NS
#endif
/* ERROR/WARNING messages:
E: Compute nvt/nph/npt body requires atom style body
Self-explanatory.
E: Fix nvt/nph/npt body requires bodies
Self-explanatory.
*/

View File

@ -33,15 +33,3 @@ class FixNPHBody : public FixNHBody {
#endif
#endif
/* ERROR/WARNING messages:
E: Temperature control can not be used with fix nph/body
Self-explanatory.
E: Pressure control must be used with fix nph/body
Self-explanatory.
*/

View File

@ -33,15 +33,3 @@ class FixNPTBody : public FixNHBody {
#endif
#endif
/* ERROR/WARNING messages:
E: Temperature control must be used with fix npt/body
Self-explanatory.
E: Pressure control must be used with fix npt/body
Self-explanatory.
*/

View File

@ -30,7 +30,7 @@ FixNVEBody::FixNVEBody(LAMMPS *lmp, int narg, char **arg) :
void FixNVEBody::init()
{
avec = (AtomVecBody *) atom->style_match("body");
avec = dynamic_cast<AtomVecBody *>( atom->style_match("body"));
if (!avec) error->all(FLERR,"Fix nve/body requires atom style body");
// check that all particles are bodies

View File

@ -39,15 +39,3 @@ class FixNVEBody : public FixNVE {
} // namespace LAMMPS_NS
#endif
#endif
/* ERROR/WARNING messages:
E: Fix nve/body requires atom style body
Self-explanatory.
E: Fix nve/body requires bodies
This fix can only be used for particles that are bodies.
*/

View File

@ -33,15 +33,3 @@ class FixNVTBody : public FixNHBody {
#endif
#endif
/* ERROR/WARNING messages:
E: Temperature control must be used with fix nvt/body
Self-explanatory.
E: Pressure control can not be used with fix nvt/body
Self-explanatory.
*/

View File

@ -179,13 +179,13 @@ void FixWallBodyPolygon::init()
{
dt = update->dt;
avec = (AtomVecBody *) atom->style_match("body");
avec = dynamic_cast<AtomVecBody *>( atom->style_match("body"));
if (!avec)
error->all(FLERR,"Pair body/rounded/polygon requires atom style body");
if (strcmp(avec->bptr->style,"rounded/polygon") != 0)
error->all(FLERR,"Pair body/rounded/polygon requires "
"body style rounded/polygon");
bptr = (BodyRoundedPolygon *) avec->bptr;
bptr = dynamic_cast<BodyRoundedPolygon *>( avec->bptr);
// set pairstyle from body/polygonular pair style

View File

@ -93,34 +93,3 @@ class FixWallBodyPolygon : public Fix {
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: Fix wall/body/polygon requires atom style body rounded/polygon
Self-explanatory.
E: Cannot use wall in periodic dimension
Self-explanatory.
E: Cannot wiggle and shear fix wall/body/polygon
Cannot specify both options at the same time.
E: Invalid wiggle direction for fix wall/body/polygon
Self-explanatory.
E: Fix wall/body/polygon is incompatible with Pair style
Must use a body pair style to define the parameters needed for
this fix.
*/

View File

@ -184,13 +184,13 @@ void FixWallBodyPolyhedron::init()
{
dt = update->dt;
avec = (AtomVecBody *) atom->style_match("body");
avec = dynamic_cast<AtomVecBody *>( atom->style_match("body"));
if (!avec)
error->all(FLERR,"Pair body/rounded/polyhedron requires atom style body");
if (strcmp(avec->bptr->style,"rounded/polyhedron") != 0)
error->all(FLERR,"Pair body/rounded/polyhedron requires "
"body style rounded/polyhedron");
bptr = (BodyRoundedPolyhedron *) avec->bptr;
bptr = dynamic_cast<BodyRoundedPolyhedron *>( avec->bptr);
// set pairstyle from body/polyhedronular pair style

View File

@ -104,34 +104,3 @@ class FixWallBodyPolyhedron : public Fix {
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: Fix wall/body/polyhedron requires atom style body rounded/polyhedron
Self-explanatory.
E: Cannot use wall in periodic dimension
Self-explanatory.
E: Cannot wiggle and shear fix wall/body/polygon
Cannot specify both options at the same time.
E: Invalid wiggle direction for fix wall/body/polygon
Self-explanatory.
E: Fix wall/body/polygon is incompatible with Pair style
Must use a body pair style to define the parameters needed for
this fix.
*/

View File

@ -416,11 +416,11 @@ void PairBodyNparticle::coeff(int narg, char **arg)
void PairBodyNparticle::init_style()
{
avec = (AtomVecBody *) atom->style_match("body");
avec = dynamic_cast<AtomVecBody *>( atom->style_match("body"));
if (!avec) error->all(FLERR,"Pair body/nparticle requires atom style body");
if (strcmp(avec->bptr->style,"nparticle") != 0)
error->all(FLERR,"Pair body/nparticle requires body style nparticle");
bptr = (BodyNparticle *) avec->bptr;
bptr = dynamic_cast<BodyNparticle *>( avec->bptr);
neighbor->add_request(this);
}

View File

@ -58,25 +58,3 @@ class PairBodyNparticle : public Pair {
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: Incorrect args for pair coefficients
Self-explanatory. Check the input script or data file.
E: Pair body requires atom style body
Self-explanatory.
E: Pair body requires body style nparticle
This pair style is specific to the nparticle body style.
*/

View File

@ -411,13 +411,13 @@ void PairBodyRoundedPolygon::coeff(int narg, char **arg)
void PairBodyRoundedPolygon::init_style()
{
avec = (AtomVecBody *) atom->style_match("body");
avec = dynamic_cast<AtomVecBody *>( atom->style_match("body"));
if (!avec)
error->all(FLERR,"Pair body/rounded/polygon requires atom style body");
if (strcmp(avec->bptr->style,"rounded/polygon") != 0)
error->all(FLERR,"Pair body/rounded/polygon requires "
"body style rounded/polygon");
bptr = (BodyRoundedPolygon *) avec->bptr;
bptr = dynamic_cast<BodyRoundedPolygon *>( avec->bptr);
if (force->newton_pair == 0)
error->all(FLERR,"Pair style body/rounded/polygon requires "

View File

@ -108,25 +108,3 @@ class PairBodyRoundedPolygon : public Pair {
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: Incorrect args for pair coefficients
Self-explanatory. Check the input script or data file.
E: Pair body/rounded/polygon requires atom style body rounded/polygon
Self-explanatory.
E: Pair body requires body style rounded/polygon
This pair style is specific to the rounded/polygon body style.
*/

View File

@ -390,13 +390,13 @@ void PairBodyRoundedPolyhedron::coeff(int narg, char **arg)
void PairBodyRoundedPolyhedron::init_style()
{
avec = (AtomVecBody *) atom->style_match("body");
avec = dynamic_cast<AtomVecBody *>( atom->style_match("body"));
if (!avec) error->all(FLERR,"Pair body/rounded/polyhedron requires "
"atom style body");
if (strcmp(avec->bptr->style,"rounded/polyhedron") != 0)
error->all(FLERR,"Pair body/rounded/polyhedron requires "
"body style rounded/polyhedron");
bptr = (BodyRoundedPolyhedron *) avec->bptr;
bptr = dynamic_cast<BodyRoundedPolyhedron *>( avec->bptr);
if (force->newton_pair == 0)
error->all(FLERR,"Pair style body/rounded/polyhedron requires "

View File

@ -162,25 +162,3 @@ class PairBodyRoundedPolyhedron : public Pair {
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: Incorrect args for pair coefficients
Self-explanatory. Check the input script or data file.
E: Pair body/rounded/polyhedron requires atom style body rounded/polyhedron
Self-explanatory.
E: Pair body requires body style rounded/polyhedron
This pair style is specific to the rounded/polyhedron body style.
*/

View File

@ -0,0 +1,248 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, 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.
------------------------------------------------------------------------- */
#include "atom_vec_bpm_sphere.h"
#include "atom.h"
#include "comm.h"
#include "error.h"
#include "fix.h"
#include "fix_adapt.h"
#include "math_const.h"
#include "modify.h"
#include "utils.h"
#include <cstring>
using namespace LAMMPS_NS;
using MathConst::MY_PI;
/* ---------------------------------------------------------------------- */
AtomVecBPMSphere::AtomVecBPMSphere(LAMMPS *_lmp) : AtomVec(_lmp)
{
mass_type = PER_ATOM;
molecular = Atom::MOLECULAR;
bonds_allow = 1;
atom->molecule_flag = 1;
atom->sphere_flag = 1;
atom->radius_flag = atom->rmass_flag = atom->omega_flag = atom->torque_flag = atom->quat_flag = 1;
// strings with peratom variables to include in each AtomVec method
// strings cannot contain fields in corresponding AtomVec default strings
// order of fields in a string does not matter
// except: fields_data_atom & fields_data_vel must match data file
fields_grow = {"molecule", "num_bond", "bond_type", "bond_atom", "nspecial", "special",
"radius", "rmass", "omega", "torque", "quat"};
fields_copy = {"molecule", "num_bond", "bond_type", "bond_atom", "nspecial",
"special", "radius", "rmass", "omega", "quat"};
fields_comm_vel = {"omega", "quat"};
fields_reverse = {"torque"};
fields_border = {"molecule", "radius", "rmass"};
fields_border_vel = {"molecule", "radius", "rmass", "omega", "quat"};
fields_exchange = {"molecule", "num_bond", "bond_type", "bond_atom", "nspecial",
"special", "radius", "rmass", "omega", "quat"};
fields_restart = {"molecule", "num_bond", "bond_type", "bond_atom",
"radius", "rmass", "omega", "quat"};
fields_create = {"molecule", "num_bond", "nspecial", "radius", "rmass", "omega", "quat"};
fields_data_atom = {"id", "molecule", "type", "radius", "rmass", "x"};
fields_data_vel = {"id", "v", "omega"};
bond_per_atom = 0;
bond_negative = nullptr;
}
/* ----------------------------------------------------------------------
process sub-style args
optional arg = 0/1 for static/dynamic particle radii
------------------------------------------------------------------------- */
void AtomVecBPMSphere::process_args(int narg, char **arg)
{
if (narg != 0 && narg != 1) error->all(FLERR, "Illegal atom_style bpm/sphere command");
radvary = 0;
if (narg == 1) {
radvary = utils::numeric(FLERR, arg[0], true, lmp);
if (radvary < 0 || radvary > 1) error->all(FLERR, "Illegal atom_style bpm/sphere command");
}
// dynamic particle radius and mass must be communicated every step
if (radvary) {
fields_comm = {"radius", "rmass"};
fields_comm_vel = {"radius", "rmass", "omega"};
}
// delay setting up of fields until now
setup_fields();
}
/* ---------------------------------------------------------------------- */
void AtomVecBPMSphere::init()
{
AtomVec::init();
// check if optional radvary setting should have been set to 1
for (auto ifix : modify->get_fix_by_style("^adapt")) {
if (radvary == 0) {
if ((strcmp(ifix->style, "adapt") == 0) && (dynamic_cast<FixAdapt *>(ifix)->diamflag))
error->all(FLERR, "Fix adapt changes atom radii but atom_style bpm/sphere is not dynamic");
// cannot properly check for fix adapt/fep since its header is optional
if ((strcmp(ifix->style, "adapt/fep") == 0) && (comm->me == 0))
error->warning(
FLERR, "Fix adapt/fep may change atom radii but atom_style bpm/sphere is not dynamic");
}
}
}
/* ----------------------------------------------------------------------
set local copies of all grow ptrs used by this class, except defaults
needed in replicate when 2 atom classes exist and it calls pack_restart()
------------------------------------------------------------------------- */
void AtomVecBPMSphere::grow_pointers()
{
radius = atom->radius;
rmass = atom->rmass;
omega = atom->omega;
quat = atom->quat;
num_bond = atom->num_bond;
bond_type = atom->bond_type;
nspecial = atom->nspecial;
}
/* ----------------------------------------------------------------------
initialize non-zero atom quantities
------------------------------------------------------------------------- */
void AtomVecBPMSphere::create_atom_post(int ilocal)
{
radius[ilocal] = 0.5;
rmass[ilocal] = 4.0 * MY_PI / 3.0 * 0.5 * 0.5 * 0.5;
quat[ilocal][0] = 1.0;
quat[ilocal][1] = 0.0;
quat[ilocal][2] = 0.0;
quat[ilocal][3] = 0.0;
}
/* ----------------------------------------------------------------------
modify values for AtomVec::pack_restart() to pack
------------------------------------------------------------------------- */
void AtomVecBPMSphere::pack_restart_pre(int ilocal)
{
// insure bond_negative vector is needed length
if (bond_per_atom < atom->bond_per_atom) {
delete[] bond_negative;
bond_per_atom = atom->bond_per_atom;
bond_negative = new int[bond_per_atom];
}
// flip any negative types to positive and flag which ones
any_bond_negative = 0;
for (int m = 0; m < num_bond[ilocal]; m++) {
if (bond_type[ilocal][m] < 0) {
bond_negative[m] = 1;
bond_type[ilocal][m] = -bond_type[ilocal][m];
any_bond_negative = 1;
} else
bond_negative[m] = 0;
}
}
/* ----------------------------------------------------------------------
unmodify values packed by AtomVec::pack_restart()
------------------------------------------------------------------------- */
void AtomVecBPMSphere::pack_restart_post(int ilocal)
{
// restore the flagged types to their negative values
if (any_bond_negative) {
for (int m = 0; m < num_bond[ilocal]; m++)
if (bond_negative[m]) bond_type[ilocal][m] = -bond_type[ilocal][m];
}
}
/* ----------------------------------------------------------------------
initialize other atom quantities after AtomVec::unpack_restart()
------------------------------------------------------------------------- */
void AtomVecBPMSphere::unpack_restart_init(int ilocal)
{
nspecial[ilocal][0] = 0;
nspecial[ilocal][1] = 0;
nspecial[ilocal][2] = 0;
}
/* ----------------------------------------------------------------------
modify what AtomVec::data_atom() just unpacked
or initialize other atom quantities
------------------------------------------------------------------------- */
void AtomVecBPMSphere::data_atom_post(int ilocal)
{
radius_one = 0.5 * atom->radius[ilocal];
radius[ilocal] = radius_one;
if (radius_one > 0.0) rmass[ilocal] *= 4.0 * MY_PI / 3.0 * radius_one * radius_one * radius_one;
if (rmass[ilocal] <= 0.0) error->one(FLERR, "Invalid density in Atoms section of data file");
omega[ilocal][0] = 0.0;
omega[ilocal][1] = 0.0;
omega[ilocal][2] = 0.0;
quat[ilocal][0] = 1.0;
quat[ilocal][1] = 0.0;
quat[ilocal][2] = 0.0;
quat[ilocal][3] = 0.0;
num_bond[ilocal] = 0;
nspecial[ilocal][0] = 0;
nspecial[ilocal][1] = 0;
nspecial[ilocal][2] = 0;
}
/* ----------------------------------------------------------------------
modify values for AtomVec::pack_data() to pack
------------------------------------------------------------------------- */
void AtomVecBPMSphere::pack_data_pre(int ilocal)
{
radius_one = radius[ilocal];
rmass_one = rmass[ilocal];
radius[ilocal] *= 2.0;
if (radius_one != 0.0)
rmass[ilocal] = rmass_one / (4.0 * MY_PI / 3.0 * radius_one * radius_one * radius_one);
}
/* ----------------------------------------------------------------------
unmodify values packed by AtomVec::pack_data()
------------------------------------------------------------------------- */
void AtomVecBPMSphere::pack_data_post(int ilocal)
{
radius[ilocal] = radius_one;
rmass[ilocal] = rmass_one;
}

View File

@ -0,0 +1,61 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, 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 ATOM_CLASS
// clang-format off
AtomStyle(bpm/sphere,AtomVecBPMSphere);
// clang-format on
#else
#ifndef LMP_ATOM_VEC_BPM_SPHERE_H
#define LMP_ATOM_VEC_BPM_SPHERE_H
#include "atom_vec.h"
namespace LAMMPS_NS {
class AtomVecBPMSphere : public AtomVec {
public:
AtomVecBPMSphere(class LAMMPS *);
void process_args(int, char **) override;
void init() override;
void grow_pointers() override;
void create_atom_post(int) override;
void pack_restart_pre(int) override;
void pack_restart_post(int) override;
void unpack_restart_init(int) override;
void data_atom_post(int) override;
void pack_data_pre(int) override;
void pack_data_post(int) override;
private:
int *num_bond;
int **bond_type;
int **nspecial;
double *radius, *rmass;
double **omega, **quat;
int any_bond_negative;
int bond_per_atom;
int *bond_negative;
int radvary;
double radius_one, rmass_one;
};
} // namespace LAMMPS_NS
#endif
#endif

415
src/BPM/bond_bpm.cpp Normal file
View File

@ -0,0 +1,415 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, 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.
------------------------------------------------------------------------- */
#include "bond_bpm.h"
#include "atom.h"
#include "domain.h"
#include "error.h"
#include "fix_bond_history.h"
#include "fix_store_local.h"
#include "fix_update_special_bonds.h"
#include "force.h"
#include "memory.h"
#include "modify.h"
#include "update.h"
#include <vector>
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
BondBPM::BondBPM(LAMMPS *_lmp) :
Bond(_lmp), id_fix_dummy(nullptr), id_fix_dummy2(nullptr), id_fix_update(nullptr),
id_fix_bond_history(nullptr), id_fix_store_local(nullptr), id_fix_prop_atom(nullptr),
fix_store_local(nullptr), fix_bond_history(nullptr), fix_update_special_bonds(nullptr),
pack_choice(nullptr), output_data(nullptr)
{
overlay_flag = 0;
prop_atom_flag = 0;
nvalues = 0;
r0_max_estimate = 0.0;
max_stretch = 1.0;
// create dummy fix as placeholder for FixUpdateSpecialBonds & BondHistory
// this is so final order of Modify:fix will conform to input script
// BondHistory technically only needs this if updateflag = 1
id_fix_dummy = utils::strdup("BPM_DUMMY");
modify->add_fix(fmt::format("{} all DUMMY ", id_fix_dummy));
id_fix_dummy2 = utils::strdup("BPM_DUMMY2");
modify->add_fix(fmt::format("{} all DUMMY ", id_fix_dummy2));
}
/* ---------------------------------------------------------------------- */
BondBPM::~BondBPM()
{
delete[] pack_choice;
if (id_fix_dummy) modify->delete_fix(id_fix_dummy);
if (id_fix_dummy2) modify->delete_fix(id_fix_dummy2);
if (id_fix_update) modify->delete_fix(id_fix_update);
if (id_fix_bond_history) modify->delete_fix(id_fix_bond_history);
if (id_fix_store_local) modify->delete_fix(id_fix_store_local);
if (id_fix_prop_atom) modify->delete_fix(id_fix_prop_atom);
delete[] id_fix_dummy;
delete[] id_fix_dummy2;
delete[] id_fix_update;
delete[] id_fix_bond_history;
delete[] id_fix_store_local;
delete[] id_fix_prop_atom;
memory->destroy(output_data);
}
/* ---------------------------------------------------------------------- */
void BondBPM::init_style()
{
if (id_fix_store_local) {
auto ifix = modify->get_fix_by_id(id_fix_store_local);
if (!ifix) error->all(FLERR, "Cannot find fix STORE/LOCAL id {}",id_fix_store_local);
if (strcmp(ifix->style, "STORE/LOCAL") != 0)
error->all(FLERR, "Incorrect fix style matched, not STORE/LOCAL: {}",ifix->style);
fix_store_local = dynamic_cast<FixStoreLocal *>(ifix);
fix_store_local->nvalues = nvalues;
}
if (overlay_flag) {
if (force->special_lj[1] != 1.0)
error->all(FLERR,
"With overlay/pair, BPM bond styles require special_bonds weight of 1.0 for "
"first neighbors");
if (id_fix_update) {
modify->delete_fix(id_fix_update);
delete[] id_fix_update;
id_fix_update = nullptr;
}
} else {
// Require atoms know about all of their bonds and if they break
if (force->newton_bond)
error->all(FLERR, "Without overlay/pair, BPM bond styles require Newton bond off");
// special lj must be 0 1 1 to censor pair forces between bonded particles
// special coulomb must be 1 1 1 to ensure all pairs are included in the
// neighbor list and 1-3 and 1-4 special bond lists are skipped
if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0)
error->all(FLERR,
"Without overlay/pair, BPM bond sytles requires special LJ weights = 0,1,1");
if (force->special_coul[1] != 1.0 || force->special_coul[2] != 1.0 ||
force->special_coul[3] != 1.0)
error->all(FLERR,
"Without overlay/pair, BPM bond sytles requires special Coulomb weights = 1,1,1");
if (id_fix_dummy) {
id_fix_update = utils::strdup("BPM_UPDATE_SPECIAL_BONDS");
fix_update_special_bonds = dynamic_cast<FixUpdateSpecialBonds *>(modify->replace_fix(
id_fix_dummy, fmt::format("{} all UPDATE_SPECIAL_BONDS", id_fix_update), 1));
delete[] id_fix_dummy;
id_fix_dummy = nullptr;
}
}
if (force->angle || force->dihedral || force->improper)
error->all(FLERR, "Bond style bpm cannot be used with 3,4-body interactions");
if (atom->molecular == 2)
error->all(FLERR, "Bond style bpm cannot be used with atom style template");
// special 1-3 and 1-4 weights must be 1 to prevent building 1-3 and 1-4 special bond lists
if (force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0 || force->special_coul[2] != 1.0 ||
force->special_coul[3] != 1.0)
error->all(FLERR, "Bond style bpm requires 1-3 and 1-4 special weights of 1.0");
}
/* ----------------------------------------------------------------------
global settings
All args before store/local command are saved for potential args
for specific bond BPM substyles
All args after optional stode/local command are variables stored
in the compute store/local
------------------------------------------------------------------------- */
void BondBPM::settings(int narg, char **arg)
{
leftover_iarg.clear();
int iarg = 0;
while (iarg < narg) {
if (strcmp(arg[iarg], "store/local") == 0) {
nvalues = 0;
id_fix_store_local = utils::strdup(arg[iarg + 1]);
store_local_freq = utils::inumeric(FLERR, arg[iarg + 2], false, lmp);
pack_choice = new FnPtrPack[narg - iarg - 1];
iarg += 3;
while (iarg < narg) {
if (strcmp(arg[iarg], "id1") == 0) {
pack_choice[nvalues++] = &BondBPM::pack_id1;
} else if (strcmp(arg[iarg], "id2") == 0) {
pack_choice[nvalues++] = &BondBPM::pack_id2;
} else if (strcmp(arg[iarg], "time") == 0) {
pack_choice[nvalues++] = &BondBPM::pack_time;
} else if (strcmp(arg[iarg], "x") == 0) {
pack_choice[nvalues++] = &BondBPM::pack_x;
} else if (strcmp(arg[iarg], "y") == 0) {
pack_choice[nvalues++] = &BondBPM::pack_y;
} else if (strcmp(arg[iarg], "z") == 0) {
pack_choice[nvalues++] = &BondBPM::pack_z;
} else if (strcmp(arg[iarg], "x/ref") == 0) {
pack_choice[nvalues++] = &BondBPM::pack_x_ref;
prop_atom_flag = 1;
} else if (strcmp(arg[iarg], "y/ref") == 0) {
pack_choice[nvalues++] = &BondBPM::pack_y_ref;
prop_atom_flag = 1;
} else if (strcmp(arg[iarg], "z/ref") == 0) {
pack_choice[nvalues++] = &BondBPM::pack_z_ref;
prop_atom_flag = 1;
} else {
break;
}
iarg++;
}
} else if (strcmp(arg[iarg], "overlay/pair") == 0) {
overlay_flag = 1;
iarg++;
} else {
leftover_iarg.push_back(iarg);
iarg++;
}
}
if (id_fix_store_local) {
if (nvalues == 0)
error->all(FLERR, "Storing local data must include at least one value to output");
memory->create(output_data, nvalues, "bond/bpm:output_data");
auto ifix = modify->get_fix_by_id(id_fix_store_local);
if (!ifix)
ifix = modify->add_fix(
fmt::format("{} all STORE/LOCAL {} {}", id_fix_store_local, store_local_freq, nvalues));
fix_store_local = dynamic_cast<FixStoreLocal *>(ifix);
// Use property/atom to save reference positions as it can transfer to ghost atoms
// This won't work for instances where bonds are added (e.g. fix pour) but in those cases
// a reference state isn't well defined
if (prop_atom_flag == 1) {
id_fix_prop_atom = utils::strdup("BPM_property_atom");
char *x_ref_id = utils::strdup("BPM_X_REF");
char *y_ref_id = utils::strdup("BPM_Y_REF");
char *z_ref_id = utils::strdup("BPM_Z_REF");
ifix = modify->get_fix_by_id(id_fix_prop_atom);
if (!ifix)
ifix = modify->add_fix(fmt::format("{} all property/atom {} {} {} ghost yes",
id_fix_prop_atom, x_ref_id, y_ref_id, z_ref_id));
int type_flag;
int col_flag;
index_x_ref = atom->find_custom(x_ref_id, type_flag, col_flag);
index_y_ref = atom->find_custom(y_ref_id, type_flag, col_flag);
index_z_ref = atom->find_custom(z_ref_id, type_flag, col_flag);
delete[] x_ref_id;
delete[] y_ref_id;
delete[] z_ref_id;
if (ifix->restart_reset) {
ifix->restart_reset = 0;
} else {
double *x_ref = atom->dvector[index_x_ref];
double *y_ref = atom->dvector[index_y_ref];
double *z_ref = atom->dvector[index_z_ref];
double **x = atom->x;
for (int i = 0; i < atom->nlocal; i++) {
x_ref[i] = x[i][0];
y_ref[i] = x[i][1];
z_ref[i] = x[i][2];
}
}
}
}
}
/* ----------------------------------------------------------------------
used to check bond communiction cutoff - not perfect, estimates based on local-local only
------------------------------------------------------------------------- */
double BondBPM::equilibrium_distance(int /*i*/)
{
// Ghost atoms may not yet be communicated, this may only be an estimate
if (r0_max_estimate == 0) {
int type, j;
double delx, dely, delz, r;
double **x = atom->x;
for (int i = 0; i < atom->nlocal; i++) {
for (int m = 0; m < atom->num_bond[i]; m++) {
type = atom->bond_type[i][m];
if (type == 0) continue;
j = atom->map(atom->bond_atom[i][m]);
if (j == -1) continue;
delx = x[i][0] - x[j][0];
dely = x[i][1] - x[j][1];
delz = x[i][2] - x[j][2];
domain->minimum_image(delx, dely, delz);
r = sqrt(delx * delx + dely * dely + delz * delz);
if (r > r0_max_estimate) r0_max_estimate = r;
}
}
double temp;
MPI_Allreduce(&r0_max_estimate, &temp, 1, MPI_DOUBLE, MPI_MAX, world);
r0_max_estimate = temp;
}
// Divide out heuristic prefactor added in comm class
return max_stretch * r0_max_estimate / 1.5;
}
/* ---------------------------------------------------------------------- */
void BondBPM::process_broken(int i, int j)
{
if (fix_store_local) {
for (int n = 0; n < nvalues; n++) (this->*pack_choice[n])(n, i, j);
fix_store_local->add_data(output_data, i, j);
}
if (fix_update_special_bonds) fix_update_special_bonds->add_broken_bond(i, j);
// Manually search and remove from atom arrays
// need to remove in case special bonds arrays rebuilt
int m, n;
int nlocal = atom->nlocal;
tagint *tag = atom->tag;
tagint **bond_atom = atom->bond_atom;
int **bond_type = atom->bond_type;
int *num_bond = atom->num_bond;
if (i < nlocal) {
for (m = 0; m < num_bond[i]; m++) {
if (bond_atom[i][m] == tag[j]) {
bond_type[i][m] = 0;
n = num_bond[i];
bond_type[i][m] = bond_type[i][n - 1];
bond_atom[i][m] = bond_atom[i][n - 1];
fix_bond_history->shift_history(i, m, n - 1);
fix_bond_history->delete_history(i, n - 1);
num_bond[i]--;
break;
}
}
}
if (j < nlocal) {
for (m = 0; m < num_bond[j]; m++) {
if (bond_atom[j][m] == tag[i]) {
bond_type[j][m] = 0;
n = num_bond[j];
bond_type[j][m] = bond_type[j][n - 1];
bond_atom[j][m] = bond_atom[j][n - 1];
fix_bond_history->shift_history(j, m, n - 1);
fix_bond_history->delete_history(j, n - 1);
num_bond[j]--;
break;
}
}
}
}
/* ----------------------------------------------------------------------
one method for every keyword bond bpm can output
the atom property is packed into array or vector
------------------------------------------------------------------------- */
void BondBPM::pack_id1(int n, int i, int /*j*/)
{
tagint *tag = atom->tag;
output_data[n] = tag[i];
}
/* ---------------------------------------------------------------------- */
void BondBPM::pack_id2(int n, int /*i*/, int j)
{
tagint *tag = atom->tag;
output_data[n] = tag[j];
}
/* ---------------------------------------------------------------------- */
void BondBPM::pack_time(int n, int /*i*/, int /*j*/)
{
bigint time = update->ntimestep;
output_data[n] = time;
}
/* ---------------------------------------------------------------------- */
void BondBPM::pack_x(int n, int i, int j)
{
double **x = atom->x;
output_data[n] = (x[i][0] + x[j][0]) * 0.5;
}
/* ---------------------------------------------------------------------- */
void BondBPM::pack_y(int n, int i, int j)
{
double **x = atom->x;
output_data[n] = (x[i][1] + x[j][1]) * 0.5;
}
/* ---------------------------------------------------------------------- */
void BondBPM::pack_z(int n, int i, int j)
{
double **x = atom->x;
output_data[n] = (x[i][2] + x[j][2]) * 0.5;
}
/* ---------------------------------------------------------------------- */
void BondBPM::pack_x_ref(int n, int i, int j)
{
double *x = atom->dvector[index_x_ref];
output_data[n] = (x[i] + x[j]) * 0.5;
}
/* ---------------------------------------------------------------------- */
void BondBPM::pack_y_ref(int n, int i, int j)
{
double *y = atom->dvector[index_y_ref];
output_data[n] = (y[i] + y[j]) * 0.5;
}
/* ---------------------------------------------------------------------- */
void BondBPM::pack_z_ref(int n, int i, int j)
{
double *z = atom->dvector[index_z_ref];
output_data[n] = (z[i] + z[j]) * 0.5;
}

72
src/BPM/bond_bpm.h Normal file
View File

@ -0,0 +1,72 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, 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.
------------------------------------------------------------------------- */
#ifndef LMP_BOND_BPM_H
#define LMP_BOND_BPM_H
#include "bond.h"
#include <vector>
namespace LAMMPS_NS {
class BondBPM : public Bond {
public:
BondBPM(class LAMMPS *);
~BondBPM() override;
void compute(int, int) override = 0;
void coeff(int, char **) override = 0;
void init_style() override;
void settings(int, char **) override;
double equilibrium_distance(int) override;
void write_restart(FILE *) override{};
void read_restart(FILE *) override{};
void write_data(FILE *) override{};
double single(int, double, int, int, double &) override = 0;
protected:
double r0_max_estimate;
double max_stretch;
int store_local_freq;
std::vector<int> leftover_iarg;
char *id_fix_dummy, *id_fix_dummy2;
char *id_fix_update, *id_fix_bond_history;
char *id_fix_store_local, *id_fix_prop_atom;
class FixStoreLocal *fix_store_local;
class FixBondHistory *fix_bond_history;
class FixUpdateSpecialBonds *fix_update_special_bonds;
void process_broken(int, int);
typedef void (BondBPM::*FnPtrPack)(int, int, int);
FnPtrPack *pack_choice; // ptrs to pack functions
double *output_data;
int prop_atom_flag, nvalues, overlay_flag;
int index_x_ref, index_y_ref, index_z_ref;
void pack_id1(int, int, int);
void pack_id2(int, int, int);
void pack_time(int, int, int);
void pack_x(int, int, int);
void pack_y(int, int, int);
void pack_z(int, int, int);
void pack_x_ref(int, int, int);
void pack_y_ref(int, int, int);
void pack_z_ref(int, int, int);
};
} // namespace LAMMPS_NS
#endif

View File

@ -0,0 +1,796 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, 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.
------------------------------------------------------------------------- */
#include "bond_bpm_rotational.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "error.h"
#include "fix_bond_history.h"
#include "force.h"
#include "math_const.h"
#include "math_extra.h"
#include "memory.h"
#include "modify.h"
#include "neighbor.h"
#include <cmath>
#define EPSILON 1e-10
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
BondBPMRotational::BondBPMRotational(LAMMPS *_lmp) : BondBPM(_lmp)
{
Kr = nullptr;
Ks = nullptr;
Kt = nullptr;
Kb = nullptr;
Fcr = nullptr;
Fcs = nullptr;
Tct = nullptr;
Tcb = nullptr;
gnorm = nullptr;
gslide = nullptr;
groll = nullptr;
gtwist = nullptr;
partial_flag = 1;
smooth_flag = 1;
}
/* ---------------------------------------------------------------------- */
BondBPMRotational::~BondBPMRotational()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(Kr);
memory->destroy(Ks);
memory->destroy(Kt);
memory->destroy(Kb);
memory->destroy(Fcr);
memory->destroy(Fcs);
memory->destroy(Tct);
memory->destroy(Tcb);
memory->destroy(gnorm);
memory->destroy(gslide);
memory->destroy(groll);
memory->destroy(gtwist);
}
}
/* ---------------------------------------------------------------------- */
double BondBPMRotational::acos_limit(double c)
{
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
return acos(c);
}
/* ----------------------------------------------------------------------
Store data for a single bond - if bond added after LAMMPS init (e.g. pour)
------------------------------------------------------------------------- */
double BondBPMRotational::store_bond(int n, int i, int j)
{
double delx, dely, delz, r, rinv;
double **x = atom->x;
tagint *tag = atom->tag;
double **bondstore = fix_bond_history->bondstore;
if (tag[i] < tag[j]) {
delx = x[i][0] - x[j][0];
dely = x[i][1] - x[j][1];
delz = x[i][2] - x[j][2];
} else {
delx = x[j][0] - x[i][0];
dely = x[j][1] - x[i][1];
delz = x[j][2] - x[i][2];
}
r = sqrt(delx * delx + dely * dely + delz * delz);
rinv = 1.0 / r;
bondstore[n][0] = r;
bondstore[n][1] = delx * rinv;
bondstore[n][2] = dely * rinv;
bondstore[n][3] = delz * rinv;
if (i < atom->nlocal) {
for (int m = 0; m < atom->num_bond[i]; m++) {
if (atom->bond_atom[i][m] == tag[j]) {
fix_bond_history->update_atom_value(i, m, 0, r);
fix_bond_history->update_atom_value(i, m, 1, delx * rinv);
fix_bond_history->update_atom_value(i, m, 2, dely * rinv);
fix_bond_history->update_atom_value(i, m, 3, delz * rinv);
}
}
}
if (j < atom->nlocal) {
for (int m = 0; m < atom->num_bond[j]; m++) {
if (atom->bond_atom[j][m] == tag[i]) {
fix_bond_history->update_atom_value(j, m, 0, r);
fix_bond_history->update_atom_value(j, m, 1, delx * rinv);
fix_bond_history->update_atom_value(j, m, 2, dely * rinv);
fix_bond_history->update_atom_value(j, m, 3, delz * rinv);
}
}
}
return r;
}
/* ----------------------------------------------------------------------
Store data for all bonds called once
------------------------------------------------------------------------- */
void BondBPMRotational::store_data()
{
int i, j, m, type;
double delx, dely, delz, r, rinv;
double **x = atom->x;
int **bond_type = atom->bond_type;
tagint *tag = atom->tag;
for (i = 0; i < atom->nlocal; i++) {
for (m = 0; m < atom->num_bond[i]; m++) {
type = bond_type[i][m];
//Skip if bond was turned off
if (type < 0) continue;
// map to find index n for tag
j = atom->map(atom->bond_atom[i][m]);
if (j == -1) error->one(FLERR, "Atom missing in BPM bond");
// Save orientation as pointing towards small tag
if (tag[i] < tag[j]) {
delx = x[i][0] - x[j][0];
dely = x[i][1] - x[j][1];
delz = x[i][2] - x[j][2];
} else {
delx = x[j][0] - x[i][0];
dely = x[j][1] - x[i][1];
delz = x[j][2] - x[i][2];
}
// Get closest image in case bonded with ghost
domain->minimum_image(delx, dely, delz);
r = sqrt(delx * delx + dely * dely + delz * delz);
rinv = 1.0 / r;
fix_bond_history->update_atom_value(i, m, 0, r);
fix_bond_history->update_atom_value(i, m, 1, delx * rinv);
fix_bond_history->update_atom_value(i, m, 2, dely * rinv);
fix_bond_history->update_atom_value(i, m, 3, delz * rinv);
}
}
fix_bond_history->post_neighbor();
}
/* ----------------------------------------------------------------------
Calculate forces using formulation in:
1) Y. Wang Acta Geotechnica 2009
2) P. Mora & Y. Wang Advances in Geomcomputing 2009
---------------------------------------------------------------------- */
double BondBPMRotational::elastic_forces(int i1, int i2, int type, double &Fr, double r_mag,
double r0_mag, double r_mag_inv, double * /*rhat*/,
double *r, double *r0, double *force1on2,
double *torque1on2, double *torque2on1)
{
double breaking, temp, r0_dot_rb, c, gamma;
double psi, theta, cos_phi, sin_phi;
double mag_in_plane, mag_out_plane;
double Fs_mag, Tt_mag, Tb_mag;
double q1[4], q2[4];
double q2inv[4], mq[4], mqinv[4], qp21[4], q21[4], qtmp[4];
double rb[3], rb_x_r0[3], s[3], t[3];
double Fs[3], Fsp[3], F_rot[3], Ftmp[3];
double Ts[3], Tb[3], Tt[3], Tbp[3], Ttp[3], Tsp[3], T_rot[3], Ttmp[3];
double **quat = atom->quat;
q1[0] = quat[i1][0];
q1[1] = quat[i1][1];
q1[2] = quat[i1][2];
q1[3] = quat[i1][3];
q2[0] = quat[i2][0];
q2[1] = quat[i2][1];
q2[2] = quat[i2][2];
q2[3] = quat[i2][3];
// Calculate normal forces, rb = bond vector in particle 1's frame
MathExtra::qconjugate(q2, q2inv);
MathExtra::quatrotvec(q2inv, r, rb);
Fr = Kr[type] * (r_mag - r0_mag);
MathExtra::scale3(Fr * r_mag_inv, rb, F_rot);
// Calculate forces due to tangential displacements (no rotation)
r0_dot_rb = MathExtra::dot3(r0, rb);
c = r0_dot_rb * r_mag_inv / r0_mag;
gamma = acos_limit(c);
MathExtra::cross3(rb, r0, rb_x_r0);
MathExtra::cross3(rb, rb_x_r0, s);
MathExtra::norm3(s);
MathExtra::scale3(Ks[type] * r_mag * gamma, s, Fs);
// Calculate torque due to tangential displacements
MathExtra::cross3(r0, rb, t);
MathExtra::norm3(t);
MathExtra::scale3(0.5 * r_mag * Ks[type] * r_mag * gamma, t, Ts);
// Relative rotation force/torque
// Use representation of X'Y'Z' rotations from Wang, Mora 2009
temp = r_mag + rb[2];
if (temp < 0.0) temp = 0.0;
mq[0] = sqrt(2) * 0.5 * sqrt(temp * r_mag_inv);
temp = sqrt(rb[0] * rb[0] + rb[1] * rb[1]);
if (temp != 0.0) {
mq[1] = -sqrt(2) * 0.5 / temp;
temp = r_mag - rb[2];
if (temp < 0.0) temp = 0.0;
mq[1] *= sqrt(temp * r_mag_inv);
mq[2] = -mq[1];
mq[1] *= rb[1];
mq[2] *= rb[0];
} else {
// If aligned along z axis, x,y terms zero (r_mag-rb[2] = 0)
mq[1] = 0.0;
mq[2] = 0.0;
}
mq[3] = 0.0;
// qp21 = opposite of r^\circ_21 in Wang
// q21 = opposite of r_21 in Wang
MathExtra::quatquat(q2inv, q1, qp21);
MathExtra::qconjugate(mq, mqinv);
MathExtra::quatquat(mqinv, qp21, qtmp);
MathExtra::quatquat(qtmp, mq, q21);
temp = sqrt(q21[0] * q21[0] + q21[3] * q21[3]);
if (temp != 0.0) {
c = q21[0] / temp;
psi = 2.0 * acos_limit(c);
} else {
c = 0.0;
psi = 0.0;
}
// Map negative rotations
if (q21[3] < 0.0) // sin = q21[3]/temp
psi = -psi;
if (q21[3] == 0.0) psi = 0.0;
c = q21[0] * q21[0] - q21[1] * q21[1] - q21[2] * q21[2] + q21[3] * q21[3];
theta = acos_limit(c);
// Separately calculte magnitude of quaternion in x-y and out of x-y planes
// to avoid dividing by zero
mag_out_plane = (q21[0] * q21[0] + q21[3] * q21[3]);
mag_in_plane = (q21[1] * q21[1] + q21[2] * q21[2]);
if (mag_in_plane == 0.0) {
// No rotation => no bending/shear torque or extra shear force
// achieve by setting cos/sin = 0
cos_phi = 0.0;
sin_phi = 0.0;
} else if (mag_out_plane == 0.0) {
// Calculate angle in plane
cos_phi = q21[2] / sqrt(mag_in_plane);
sin_phi = -q21[1] / sqrt(mag_in_plane);
} else {
// Default equations in Mora, Wang 2009
cos_phi = q21[1] * q21[3] + q21[0] * q21[2];
sin_phi = q21[2] * q21[3] - q21[0] * q21[1];
cos_phi /= sqrt(mag_out_plane * mag_in_plane);
sin_phi /= sqrt(mag_out_plane * mag_in_plane);
}
Tbp[0] = -Kb[type] * theta * sin_phi;
Tbp[1] = Kb[type] * theta * cos_phi;
Tbp[2] = 0.0;
Ttp[0] = 0.0;
Ttp[1] = 0.0;
Ttp[2] = Kt[type] * psi;
Fsp[0] = -0.5 * Ks[type] * r_mag * theta * cos_phi;
Fsp[1] = -0.5 * Ks[type] * r_mag * theta * sin_phi;
Fsp[2] = 0.0;
Tsp[0] = 0.25 * Ks[type] * r_mag * r_mag * theta * sin_phi;
Tsp[1] = -0.25 * Ks[type] * r_mag * r_mag * theta * cos_phi;
Tsp[2] = 0.0;
// Rotate forces/torques back to 1st particle's frame
MathExtra::quatrotvec(mq, Fsp, Ftmp);
MathExtra::quatrotvec(mq, Tsp, Ttmp);
for (int m = 0; m < 3; m++) {
Fs[m] += Ftmp[m];
Ts[m] += Ttmp[m];
}
MathExtra::quatrotvec(mq, Tbp, Tb);
MathExtra::quatrotvec(mq, Ttp, Tt);
// Sum forces and calculate magnitudes
F_rot[0] += Fs[0];
F_rot[1] += Fs[1];
F_rot[2] += Fs[2];
MathExtra::quatrotvec(q2, F_rot, force1on2);
T_rot[0] = Ts[0] + Tt[0] + Tb[0];
T_rot[1] = Ts[1] + Tt[1] + Tb[1];
T_rot[2] = Ts[2] + Tt[2] + Tb[2];
MathExtra::quatrotvec(q2, T_rot, torque1on2);
T_rot[0] = Ts[0] - Tt[0] - Tb[0];
T_rot[1] = Ts[1] - Tt[1] - Tb[1];
T_rot[2] = Ts[2] - Tt[2] - Tb[2];
MathExtra::quatrotvec(q2, T_rot, torque2on1);
Fs_mag = MathExtra::len3(Fs);
Tt_mag = MathExtra::len3(Tt);
Tb_mag = MathExtra::len3(Tb);
breaking = Fr / Fcr[type] + Fs_mag / Fcs[type] + Tb_mag / Tcb[type] + Tt_mag / Tct[type];
if (breaking < 0.0) breaking = 0.0;
return breaking;
}
/* ----------------------------------------------------------------------
Calculate damping using formulation in
Y. Wang, F. Alonso-Marroquin, W. Guo 2015
Note: n points towards 1 vs pointing towards 2
---------------------------------------------------------------------- */
void BondBPMRotational::damping_forces(int i1, int i2, int type, double &Fr, double *rhat,
double *r, double *force1on2, double *torque1on2,
double *torque2on1)
{
double v1dotr, v2dotr, w1dotr, w2dotr;
double s1[3], s2[3], tdamp[3], tmp[3];
double vn1[3], vn2[3], vt1[3], vt2[3], vroll[3];
double wxn1[3], wxn2[3], wn1[3], wn2[3];
double **v = atom->v;
double **omega = atom->omega;
// Damp normal velocity difference
v1dotr = MathExtra::dot3(v[i1], rhat);
v2dotr = MathExtra::dot3(v[i2], rhat);
MathExtra::scale3(v1dotr, rhat, vn1);
MathExtra::scale3(v2dotr, rhat, vn2);
MathExtra::sub3(vn1, vn2, tmp);
MathExtra::scale3(gnorm[type], tmp);
Fr = MathExtra::lensq3(tmp);
MathExtra::add3(force1on2, tmp, force1on2);
// Damp tangential objective velocities
MathExtra::sub3(v[i1], vn1, vt1);
MathExtra::sub3(v[i2], vn2, vt2);
MathExtra::sub3(vt2, vt1, tmp);
MathExtra::scale3(0.5, tmp);
MathExtra::cross3(omega[i1], r, s1);
MathExtra::scale3(-0.5, s1);
MathExtra::sub3(s1, tmp, s1); // Eq 12
MathExtra::cross3(omega[i2], r, s2);
MathExtra::scale3(0.5, s2);
MathExtra::add3(s2, tmp, s2); // Eq 13
MathExtra::sub3(s1, s2, tmp);
MathExtra::scale3(gslide[type], tmp);
MathExtra::add3(force1on2, tmp, force1on2);
// Apply corresponding torque
MathExtra::cross3(r, tmp, tdamp);
MathExtra::scale3(0.5, tdamp);
MathExtra::add3(torque1on2, tdamp, torque1on2);
MathExtra::add3(torque2on1, tdamp, torque2on1);
// Damp rolling
MathExtra::cross3(omega[i1], rhat, wxn1);
MathExtra::cross3(omega[i2], rhat, wxn2);
MathExtra::sub3(wxn1, wxn2, vroll); // Eq. 31
MathExtra::cross3(r, vroll, tdamp);
MathExtra::scale3(0.5 * groll[type], tdamp);
MathExtra::add3(torque1on2, tdamp, torque1on2);
MathExtra::scale3(-1.0, tdamp);
MathExtra::add3(torque2on1, tdamp, torque2on1);
// Damp twist
w1dotr = MathExtra::dot3(omega[i1], rhat);
w2dotr = MathExtra::dot3(omega[i2], rhat);
MathExtra::scale3(w1dotr, rhat, wn1);
MathExtra::scale3(w2dotr, rhat, wn2);
MathExtra::sub3(wn1, wn2, tdamp); // Eq. 38
MathExtra::scale3(0.5 * gtwist[type], tdamp);
MathExtra::add3(torque1on2, tdamp, torque1on2);
MathExtra::scale3(-1.0, tdamp);
MathExtra::add3(torque2on1, tdamp, torque2on1);
}
/* ---------------------------------------------------------------------- */
void BondBPMRotational::compute(int eflag, int vflag)
{
if (!fix_bond_history->stored_flag) {
fix_bond_history->stored_flag = true;
store_data();
}
int i1, i2, itmp, n, type;
double r[3], r0[3], rhat[3];
double rsq, r0_mag, r_mag, r_mag_inv;
double Fr, breaking, smooth;
double force1on2[3], torque1on2[3], torque2on1[3];
ev_init(eflag, vflag);
double **x = atom->x;
double **f = atom->f;
double **torque = atom->torque;
tagint *tag = atom->tag;
int **bondlist = neighbor->bondlist;
int nbondlist = neighbor->nbondlist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
double **bondstore = fix_bond_history->bondstore;
for (n = 0; n < nbondlist; n++) {
// skip bond if already broken
if (bondlist[n][2] <= 0) continue;
i1 = bondlist[n][0];
i2 = bondlist[n][1];
type = bondlist[n][2];
r0_mag = bondstore[n][0];
// Ensure pair is always ordered such that r0 points in
// a consistent direction and to ensure numerical operations
// are identical to minimize the possibility that a bond straddling
// an mpi grid (newton off) doesn't break on one proc but not the other
if (tag[i2] < tag[i1]) {
itmp = i1;
i1 = i2;
i2 = itmp;
}
// If bond hasn't been set - should be initialized to zero
if (r0_mag < EPSILON || std::isnan(r0_mag)) r0_mag = store_bond(n, i1, i2);
r0[0] = bondstore[n][1];
r0[1] = bondstore[n][2];
r0[2] = bondstore[n][3];
MathExtra::scale3(r0_mag, r0);
// Note this is the reverse of Mora & Wang
MathExtra::sub3(x[i1], x[i2], r);
rsq = MathExtra::lensq3(r);
r_mag = sqrt(rsq);
r_mag_inv = 1.0 / r_mag;
MathExtra::scale3(r_mag_inv, r, rhat);
// ------------------------------------------------------//
// Calculate forces, check if bond breaks
// ------------------------------------------------------//
breaking = elastic_forces(i1, i2, type, Fr, r_mag, r0_mag, r_mag_inv, rhat, r, r0, force1on2,
torque1on2, torque2on1);
if (breaking >= 1.0) {
bondlist[n][2] = 0;
process_broken(i1, i2);
continue;
}
damping_forces(i1, i2, type, Fr, rhat, r, force1on2, torque1on2, torque2on1);
if (smooth_flag) {
smooth = breaking * breaking;
smooth = 1.0 - smooth * smooth;
} else {
smooth = 1.0;
}
// ------------------------------------------------------//
// Apply forces and torques to particles
// ------------------------------------------------------//
if (newton_bond || i1 < nlocal) {
f[i1][0] -= force1on2[0] * smooth;
f[i1][1] -= force1on2[1] * smooth;
f[i1][2] -= force1on2[2] * smooth;
torque[i1][0] += torque2on1[0] * smooth;
torque[i1][1] += torque2on1[1] * smooth;
torque[i1][2] += torque2on1[2] * smooth;
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += force1on2[0] * smooth;
f[i2][1] += force1on2[1] * smooth;
f[i2][2] += force1on2[2] * smooth;
torque[i2][0] += torque1on2[0] * smooth;
torque[i2][1] += torque1on2[1] * smooth;
torque[i2][2] += torque1on2[2] * smooth;
}
if (evflag) ev_tally(i1, i2, nlocal, newton_bond, 0.0, Fr * smooth, r[0], r[1], r[2]);
}
}
/* ---------------------------------------------------------------------- */
void BondBPMRotational::allocate()
{
allocated = 1;
const int np1 = atom->nbondtypes + 1;
memory->create(Kr, np1, "bond:Kr");
memory->create(Ks, np1, "bond:Ks");
memory->create(Kt, np1, "bond:Kt");
memory->create(Kb, np1, "bond:Kb");
memory->create(Fcr, np1, "bond:Fcr");
memory->create(Fcs, np1, "bond:Fcs");
memory->create(Tct, np1, "bond:Tct");
memory->create(Tcb, np1, "bond:Tcb");
memory->create(gnorm, np1, "bond:gnorm");
memory->create(gslide, np1, "bond:gslide");
memory->create(groll, np1, "bond:groll");
memory->create(gtwist, np1, "bond:gtwist");
memory->create(setflag, np1, "bond:setflag");
for (int i = 1; i < np1; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one or more types
------------------------------------------------------------------------- */
void BondBPMRotational::coeff(int narg, char **arg)
{
if (narg != 13) error->all(FLERR, "Incorrect args for bond coefficients");
if (!allocated) allocate();
int ilo, ihi;
utils::bounds(FLERR, arg[0], 1, atom->nbondtypes, ilo, ihi, error);
double Kr_one = utils::numeric(FLERR, arg[1], false, lmp);
double Ks_one = utils::numeric(FLERR, arg[2], false, lmp);
double Kt_one = utils::numeric(FLERR, arg[3], false, lmp);
double Kb_one = utils::numeric(FLERR, arg[4], false, lmp);
double Fcr_one = utils::numeric(FLERR, arg[5], false, lmp);
double Fcs_one = utils::numeric(FLERR, arg[6], false, lmp);
double Tct_one = utils::numeric(FLERR, arg[7], false, lmp);
double Tcb_one = utils::numeric(FLERR, arg[8], false, lmp);
double gnorm_one = utils::numeric(FLERR, arg[9], false, lmp);
double gslide_one = utils::numeric(FLERR, arg[10], false, lmp);
double groll_one = utils::numeric(FLERR, arg[11], false, lmp);
double gtwist_one = utils::numeric(FLERR, arg[12], false, lmp);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
Kr[i] = Kr_one;
Ks[i] = Ks_one;
Kt[i] = Kt_one;
Kb[i] = Kb_one;
Fcr[i] = Fcr_one;
Fcs[i] = Fcs_one;
Tct[i] = Tct_one;
Tcb[i] = Tcb_one;
gnorm[i] = gnorm_one;
gslide[i] = gslide_one;
groll[i] = groll_one;
gtwist[i] = gtwist_one;
setflag[i] = 1;
count++;
if (Fcr[i] / Kr[i] > max_stretch) max_stretch = Fcr[i] / Kr[i];
}
if (count == 0) error->all(FLERR, "Incorrect args for bond coefficients");
}
/* ----------------------------------------------------------------------
check for correct settings and create fix
------------------------------------------------------------------------- */
void BondBPMRotational::init_style()
{
BondBPM::init_style();
if (!atom->quat_flag || !atom->sphere_flag)
error->all(FLERR, "Bond bpm/rotational requires atom style bpm/sphere");
if (comm->ghost_velocity == 0)
error->all(FLERR, "Bond bpm/rotational requires ghost atoms store velocity");
if (domain->dimension == 2)
error->warning(FLERR, "Bond style bpm/rotational not intended for 2d use");
if (!id_fix_bond_history) {
id_fix_bond_history = utils::strdup("HISTORY_BPM_ROTATIONAL");
fix_bond_history = dynamic_cast<FixBondHistory *>(modify->replace_fix(
id_fix_dummy2, fmt::format("{} all BOND_HISTORY 0 4", id_fix_bond_history), 1));
delete[] id_fix_dummy2;
id_fix_dummy2 = nullptr;
}
}
/* ---------------------------------------------------------------------- */
void BondBPMRotational::settings(int narg, char **arg)
{
BondBPM::settings(narg, arg);
int iarg;
for (std::size_t i = 0; i < leftover_iarg.size(); i++) {
iarg = leftover_iarg[i];
if (strcmp(arg[iarg], "smooth") == 0) {
if (iarg + 1 > narg) error->all(FLERR, "Illegal bond bpm command");
smooth_flag = utils::logical(FLERR, arg[iarg + 1], false, lmp);
i += 1;
} else {
error->all(FLERR, "Illegal bond_style command");
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void BondBPMRotational::write_restart(FILE *fp)
{
fwrite(&Kr[1], sizeof(double), atom->nbondtypes, fp);
fwrite(&Ks[1], sizeof(double), atom->nbondtypes, fp);
fwrite(&Kt[1], sizeof(double), atom->nbondtypes, fp);
fwrite(&Kb[1], sizeof(double), atom->nbondtypes, fp);
fwrite(&Fcr[1], sizeof(double), atom->nbondtypes, fp);
fwrite(&Fcs[1], sizeof(double), atom->nbondtypes, fp);
fwrite(&Tct[1], sizeof(double), atom->nbondtypes, fp);
fwrite(&Tcb[1], sizeof(double), atom->nbondtypes, fp);
fwrite(&gnorm[1], sizeof(double), atom->nbondtypes, fp);
fwrite(&gslide[1], sizeof(double), atom->nbondtypes, fp);
fwrite(&groll[1], sizeof(double), atom->nbondtypes, fp);
fwrite(&gtwist[1], sizeof(double), atom->nbondtypes, fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void BondBPMRotational::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
utils::sfread(FLERR, &Kr[1], sizeof(double), atom->nbondtypes, fp, nullptr, error);
utils::sfread(FLERR, &Ks[1], sizeof(double), atom->nbondtypes, fp, nullptr, error);
utils::sfread(FLERR, &Kt[1], sizeof(double), atom->nbondtypes, fp, nullptr, error);
utils::sfread(FLERR, &Kb[1], sizeof(double), atom->nbondtypes, fp, nullptr, error);
utils::sfread(FLERR, &Fcr[1], sizeof(double), atom->nbondtypes, fp, nullptr, error);
utils::sfread(FLERR, &Fcs[1], sizeof(double), atom->nbondtypes, fp, nullptr, error);
utils::sfread(FLERR, &Tct[1], sizeof(double), atom->nbondtypes, fp, nullptr, error);
utils::sfread(FLERR, &Tcb[1], sizeof(double), atom->nbondtypes, fp, nullptr, error);
utils::sfread(FLERR, &gnorm[1], sizeof(double), atom->nbondtypes, fp, nullptr, error);
utils::sfread(FLERR, &gslide[1], sizeof(double), atom->nbondtypes, fp, nullptr, error);
utils::sfread(FLERR, &groll[1], sizeof(double), atom->nbondtypes, fp, nullptr, error);
utils::sfread(FLERR, &gtwist[1], sizeof(double), atom->nbondtypes, fp, nullptr, error);
}
MPI_Bcast(&Kr[1], atom->nbondtypes, MPI_DOUBLE, 0, world);
MPI_Bcast(&Ks[1], atom->nbondtypes, MPI_DOUBLE, 0, world);
MPI_Bcast(&Kt[1], atom->nbondtypes, MPI_DOUBLE, 0, world);
MPI_Bcast(&Kb[1], atom->nbondtypes, MPI_DOUBLE, 0, world);
MPI_Bcast(&Fcr[1], atom->nbondtypes, MPI_DOUBLE, 0, world);
MPI_Bcast(&Fcs[1], atom->nbondtypes, MPI_DOUBLE, 0, world);
MPI_Bcast(&Tct[1], atom->nbondtypes, MPI_DOUBLE, 0, world);
MPI_Bcast(&Tcb[1], atom->nbondtypes, MPI_DOUBLE, 0, world);
MPI_Bcast(&gnorm[1], atom->nbondtypes, MPI_DOUBLE, 0, world);
MPI_Bcast(&gslide[1], atom->nbondtypes, MPI_DOUBLE, 0, world);
MPI_Bcast(&groll[1], atom->nbondtypes, MPI_DOUBLE, 0, world);
MPI_Bcast(&gtwist[1], atom->nbondtypes, MPI_DOUBLE, 0, world);
for (int i = 1; i <= atom->nbondtypes; i++) setflag[i] = 1;
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void BondBPMRotational::write_data(FILE *fp)
{
for (int i = 1; i <= atom->nbondtypes; i++)
fprintf(fp, "%d %g %g %g %g %g %g %g %g %g %g %g %g\n", i, Kr[i], Ks[i], Kt[i], Kb[i], Fcr[i],
Fcs[i], Tct[i], Tcb[i], gnorm[i], gslide[i], groll[i], gtwist[i]);
}
/* ---------------------------------------------------------------------- */
double BondBPMRotational::single(int type, double rsq, int i, int j, double &fforce)
{
// Not yet enabled
if (type <= 0) return 0.0;
int itmp;
if (atom->tag[j] < atom->tag[i]) {
itmp = i;
i = j;
j = itmp;
}
double r0_mag, r_mag, r_mag_inv;
double r0[3], r[3], rhat[3];
for (int n = 0; n < atom->num_bond[i]; n++) {
if (atom->bond_atom[i][n] == atom->tag[j]) {
r0_mag = fix_bond_history->get_atom_value(i, n, 0);
r0[0] = fix_bond_history->get_atom_value(i, n, 1);
r0[1] = fix_bond_history->get_atom_value(i, n, 2);
r0[2] = fix_bond_history->get_atom_value(i, n, 3);
}
}
double **x = atom->x;
MathExtra::scale3(r0_mag, r0);
MathExtra::sub3(x[i], x[j], r);
r_mag = sqrt(rsq);
r_mag_inv = 1.0 / r_mag;
MathExtra::scale3(r_mag_inv, r, rhat);
double breaking, smooth, Fr;
double force1on2[3], torque1on2[3], torque2on1[3];
breaking = elastic_forces(i, j, type, Fr, r_mag, r0_mag, r_mag_inv, rhat, r, r0, force1on2,
torque1on2, torque2on1);
fforce = Fr;
damping_forces(i, j, type, Fr, rhat, r, force1on2, torque1on2, torque2on1);
fforce += Fr;
if (smooth_flag) {
smooth = breaking * breaking;
smooth = 1.0 - smooth * smooth;
fforce *= smooth;
}
return 0.0;
}

View File

@ -0,0 +1,59 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, 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 BOND_CLASS
// clang-format off
BondStyle(bpm/rotational,BondBPMRotational);
// clang-format on
#else
#ifndef LMP_BOND_BPM_ROTATIONAL_H
#define LMP_BOND_BPM_ROTATIONAL_H
#include "bond_bpm.h"
namespace LAMMPS_NS {
class BondBPMRotational : public BondBPM {
public:
BondBPMRotational(class LAMMPS *);
~BondBPMRotational() override;
void compute(int, int) override;
void coeff(int, char **) override;
void init_style() override;
void settings(int, char **) override;
void write_restart(FILE *) override;
void read_restart(FILE *) override;
void write_data(FILE *) override;
double single(int, double, int, int, double &) override;
protected:
double *Kr, *Ks, *Kt, *Kb, *gnorm, *gslide, *groll, *gtwist;
double *Fcr, *Fcs, *Tct, *Tcb;
int smooth_flag;
double acos_limit(double);
double elastic_forces(int, int, int, double &, double, double, double, double *, double *,
double *, double *, double *, double *);
void damping_forces(int, int, int, double &, double *, double *, double *, double *, double *);
void allocate();
void store_data();
double store_bond(int, int, int);
};
} // namespace LAMMPS_NS
#endif
#endif

381
src/BPM/bond_bpm_spring.cpp Normal file
View File

@ -0,0 +1,381 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, 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.
------------------------------------------------------------------------- */
#include "bond_bpm_spring.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "error.h"
#include "fix_bond_history.h"
#include "force.h"
#include "memory.h"
#include "modify.h"
#include "neighbor.h"
#define EPSILON 1e-10
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
BondBPMSpring::BondBPMSpring(LAMMPS *_lmp) :
BondBPM(_lmp), k(nullptr), ecrit(nullptr), gamma(nullptr)
{
partial_flag = 1;
smooth_flag = 1;
}
/* ---------------------------------------------------------------------- */
BondBPMSpring::~BondBPMSpring()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(k);
memory->destroy(ecrit);
memory->destroy(gamma);
}
}
/* ----------------------------------------------------------------------
Store data for a single bond - if bond added after LAMMPS init (e.g. pour)
------------------------------------------------------------------------- */
double BondBPMSpring::store_bond(int n, int i, int j)
{
double delx, dely, delz, r;
double **x = atom->x;
double **bondstore = fix_bond_history->bondstore;
tagint *tag = atom->tag;
delx = x[i][0] - x[j][0];
dely = x[i][1] - x[j][1];
delz = x[i][2] - x[j][2];
r = sqrt(delx * delx + dely * dely + delz * delz);
bondstore[n][0] = r;
if (i < atom->nlocal) {
for (int m = 0; m < atom->num_bond[i]; m++) {
if (atom->bond_atom[i][m] == tag[j]) { fix_bond_history->update_atom_value(i, m, 0, r); }
}
}
if (j < atom->nlocal) {
for (int m = 0; m < atom->num_bond[j]; m++) {
if (atom->bond_atom[j][m] == tag[i]) { fix_bond_history->update_atom_value(j, m, 0, r); }
}
}
return r;
}
/* ----------------------------------------------------------------------
Store data for all bonds called once
------------------------------------------------------------------------- */
void BondBPMSpring::store_data()
{
int i, j, m, type;
double delx, dely, delz, r;
double **x = atom->x;
int **bond_type = atom->bond_type;
for (i = 0; i < atom->nlocal; i++) {
for (m = 0; m < atom->num_bond[i]; m++) {
type = bond_type[i][m];
//Skip if bond was turned off
if (type < 0) continue;
// map to find index n
j = atom->map(atom->bond_atom[i][m]);
if (j == -1) error->one(FLERR, "Atom missing in BPM bond");
delx = x[i][0] - x[j][0];
dely = x[i][1] - x[j][1];
delz = x[i][2] - x[j][2];
// Get closest image in case bonded with ghost
domain->minimum_image(delx, dely, delz);
r = sqrt(delx * delx + dely * dely + delz * delz);
fix_bond_history->update_atom_value(i, m, 0, r);
}
}
fix_bond_history->post_neighbor();
}
/* ---------------------------------------------------------------------- */
void BondBPMSpring::compute(int eflag, int vflag)
{
if (!fix_bond_history->stored_flag) {
fix_bond_history->stored_flag = true;
store_data();
}
int i1, i2, itmp, n, type;
double delx, dely, delz, delvx, delvy, delvz;
double e, rsq, r, r0, rinv, smooth, fbond, dot;
ev_init(eflag, vflag);
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
tagint *tag = atom->tag;
int **bondlist = neighbor->bondlist;
int nbondlist = neighbor->nbondlist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
double **bondstore = fix_bond_history->bondstore;
for (n = 0; n < nbondlist; n++) {
// skip bond if already broken
if (bondlist[n][2] <= 0) continue;
i1 = bondlist[n][0];
i2 = bondlist[n][1];
type = bondlist[n][2];
r0 = bondstore[n][0];
// Ensure pair is always ordered to ensure numerical operations
// are identical to minimize the possibility that a bond straddling
// an mpi grid (newton off) doesn't break on one proc but not the other
if (tag[i2] < tag[i1]) {
itmp = i1;
i1 = i2;
i2 = itmp;
}
// If bond hasn't been set - should be initialized to zero
if (r0 < EPSILON || std::isnan(r0)) r0 = store_bond(n, i1, i2);
delx = x[i1][0] - x[i2][0];
dely = x[i1][1] - x[i2][1];
delz = x[i1][2] - x[i2][2];
rsq = delx * delx + dely * dely + delz * delz;
r = sqrt(rsq);
e = (r - r0) / r0;
if (fabs(e) > ecrit[type]) {
bondlist[n][2] = 0;
process_broken(i1, i2);
continue;
}
rinv = 1.0 / r;
fbond = k[type] * (r0 - r);
delvx = v[i1][0] - v[i2][0];
delvy = v[i1][1] - v[i2][1];
delvz = v[i1][2] - v[i2][2];
dot = delx * delvx + dely * delvy + delz * delvz;
fbond -= gamma[type] * dot * rinv;
fbond *= rinv;
if (smooth_flag) {
smooth = (r - r0) / (r0 * ecrit[type]);
smooth *= smooth;
smooth *= smooth;
smooth *= smooth;
smooth = 1 - smooth;
fbond *= smooth;
}
if (newton_bond || i1 < nlocal) {
f[i1][0] += delx * fbond;
f[i1][1] += dely * fbond;
f[i1][2] += delz * fbond;
}
if (newton_bond || i2 < nlocal) {
f[i2][0] -= delx * fbond;
f[i2][1] -= dely * fbond;
f[i2][2] -= delz * fbond;
}
if (evflag) ev_tally(i1, i2, nlocal, newton_bond, 0.0, fbond, delx, dely, delz);
}
}
/* ---------------------------------------------------------------------- */
void BondBPMSpring::allocate()
{
allocated = 1;
const int np1 = atom->nbondtypes + 1;
memory->create(k, np1, "bond:k");
memory->create(ecrit, np1, "bond:ecrit");
memory->create(gamma, np1, "bond:gamma");
memory->create(setflag, np1, "bond:setflag");
for (int i = 1; i < np1; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one or more types
------------------------------------------------------------------------- */
void BondBPMSpring::coeff(int narg, char **arg)
{
if (narg != 4) error->all(FLERR, "Incorrect args for bond coefficients");
if (!allocated) allocate();
int ilo, ihi;
utils::bounds(FLERR, arg[0], 1, atom->nbondtypes, ilo, ihi, error);
double k_one = utils::numeric(FLERR, arg[1], false, lmp);
double ecrit_one = utils::numeric(FLERR, arg[2], false, lmp);
double gamma_one = utils::numeric(FLERR, arg[3], false, lmp);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
k[i] = k_one;
ecrit[i] = ecrit_one;
gamma[i] = gamma_one;
setflag[i] = 1;
count++;
if (1.0 + ecrit[i] > max_stretch) max_stretch = 1.0 + ecrit[i];
}
if (count == 0) error->all(FLERR, "Incorrect args for bond coefficients");
}
/* ----------------------------------------------------------------------
check for correct settings and create fix
------------------------------------------------------------------------- */
void BondBPMSpring::init_style()
{
BondBPM::init_style();
if (comm->ghost_velocity == 0)
error->all(FLERR, "Bond bpm/spring requires ghost atoms store velocity");
if (!id_fix_bond_history) {
id_fix_bond_history = utils::strdup("HISTORY_BPM_SPRING");
fix_bond_history = dynamic_cast<FixBondHistory *>(modify->replace_fix(
id_fix_dummy2, fmt::format("{} all BOND_HISTORY 0 1", id_fix_bond_history), 1));
delete[] id_fix_dummy2;
id_fix_dummy2 = nullptr;
}
}
/* ---------------------------------------------------------------------- */
void BondBPMSpring::settings(int narg, char **arg)
{
BondBPM::settings(narg, arg);
int iarg;
for (std::size_t i = 0; i < leftover_iarg.size(); i++) {
iarg = leftover_iarg[i];
if (strcmp(arg[iarg], "smooth") == 0) {
if (iarg + 1 > narg) error->all(FLERR, "Illegal bond bpm command");
smooth_flag = utils::logical(FLERR, arg[iarg + 1], false, lmp);
i += 1;
} else {
error->all(FLERR, "Illegal bond_style command");
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void BondBPMSpring::write_restart(FILE *fp)
{
fwrite(&k[1], sizeof(double), atom->nbondtypes, fp);
fwrite(&ecrit[1], sizeof(double), atom->nbondtypes, fp);
fwrite(&gamma[1], sizeof(double), atom->nbondtypes, fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void BondBPMSpring::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
utils::sfread(FLERR, &k[1], sizeof(double), atom->nbondtypes, fp, nullptr, error);
utils::sfread(FLERR, &ecrit[1], sizeof(double), atom->nbondtypes, fp, nullptr, error);
utils::sfread(FLERR, &gamma[1], sizeof(double), atom->nbondtypes, fp, nullptr, error);
}
MPI_Bcast(&k[1], atom->nbondtypes, MPI_DOUBLE, 0, world);
MPI_Bcast(&ecrit[1], atom->nbondtypes, MPI_DOUBLE, 0, world);
MPI_Bcast(&gamma[1], atom->nbondtypes, MPI_DOUBLE, 0, world);
for (int i = 1; i <= atom->nbondtypes; i++) setflag[i] = 1;
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void BondBPMSpring::write_data(FILE *fp)
{
for (int i = 1; i <= atom->nbondtypes; i++)
fprintf(fp, "%d %g %g %g\n", i, k[i], ecrit[i], gamma[i]);
}
/* ---------------------------------------------------------------------- */
double BondBPMSpring::single(int type, double rsq, int i, int j, double &fforce)
{
if (type <= 0) return 0.0;
double r0;
for (int n = 0; n < atom->num_bond[i]; n++) {
if (atom->bond_atom[i][n] == atom->tag[j]) r0 = fix_bond_history->get_atom_value(i, n, 0);
}
double r = sqrt(rsq);
double rinv = 1.0 / r;
fforce = k[type] * (r0 - r);
double **x = atom->x;
double **v = atom->v;
double delx = x[i][0] - x[j][0];
double dely = x[i][1] - x[j][1];
double delz = x[i][2] - x[j][2];
double delvx = v[i][0] - v[j][0];
double delvy = v[i][1] - v[j][1];
double delvz = v[i][2] - v[j][2];
double dot = delx * delvx + dely * delvy + delz * delvz;
fforce -= gamma[type] * dot * rinv;
fforce *= rinv;
if (smooth_flag) {
double smooth = (r - r0) / (r0 * ecrit[type]);
smooth *= smooth;
smooth *= smooth;
smooth *= smooth;
smooth = 1 - smooth;
fforce *= smooth;
}
return 0.0;
}

Some files were not shown because too many files have changed in this diff Show More