Merge pull request #3573 from akohlmey/angle-write
Implement angle_write and dihedral_write commands
This commit is contained in:
@ -24,6 +24,7 @@ table above.
|
|||||||
|
|
||||||
* :doc:`angle_coeff <angle_coeff>`
|
* :doc:`angle_coeff <angle_coeff>`
|
||||||
* :doc:`angle_style <angle_style>`
|
* :doc:`angle_style <angle_style>`
|
||||||
|
* :doc:`angle_write <angle_write>`
|
||||||
* :doc:`atom_modify <atom_modify>`
|
* :doc:`atom_modify <atom_modify>`
|
||||||
* :doc:`atom_style <atom_style>`
|
* :doc:`atom_style <atom_style>`
|
||||||
* :doc:`balance <balance>`
|
* :doc:`balance <balance>`
|
||||||
@ -45,6 +46,7 @@ table above.
|
|||||||
* :doc:`dielectric <dielectric>`
|
* :doc:`dielectric <dielectric>`
|
||||||
* :doc:`dihedral_coeff <dihedral_coeff>`
|
* :doc:`dihedral_coeff <dihedral_coeff>`
|
||||||
* :doc:`dihedral_style <dihedral_style>`
|
* :doc:`dihedral_style <dihedral_style>`
|
||||||
|
* :doc:`dihedral_write <dihedral_write>`
|
||||||
* :doc:`dimension <dimension>`
|
* :doc:`dimension <dimension>`
|
||||||
* :doc:`displace_atoms <displace_atoms>`
|
* :doc:`displace_atoms <displace_atoms>`
|
||||||
* :doc:`dump <dump>`
|
* :doc:`dump <dump>`
|
||||||
|
|||||||
@ -59,9 +59,12 @@ format of this file is described below.
|
|||||||
|
|
||||||
----------
|
----------
|
||||||
|
|
||||||
Suitable tables for use with this angle style can be created using the
|
Suitable tables for use with this angle style can be created by LAMMPS
|
||||||
Python code in the ``tools/tabulate`` folder of the LAMMPS source code
|
itself from existing angle styles using the :doc:`angle_write
|
||||||
distribution.
|
<angle_write>` command. This can be useful to have a template file for
|
||||||
|
testing the angle style settings and to build a compatible custom file.
|
||||||
|
Another option to generate tables is the Python code in the
|
||||||
|
``tools/tabulate`` folder of the LAMMPS source code distribution.
|
||||||
|
|
||||||
The format of a tabulated file is as follows (without the
|
The format of a tabulated file is as follows (without the
|
||||||
parenthesized comments):
|
parenthesized comments):
|
||||||
@ -154,7 +157,7 @@ for more info.
|
|||||||
Related commands
|
Related commands
|
||||||
""""""""""""""""
|
""""""""""""""""
|
||||||
|
|
||||||
:doc:`angle_coeff <angle_coeff>`
|
:doc:`angle_coeff <angle_coeff>`, :doc:`angle_write <angle_write>`
|
||||||
|
|
||||||
Default
|
Default
|
||||||
"""""""
|
"""""""
|
||||||
|
|||||||
99
doc/src/angle_write.rst
Normal file
99
doc/src/angle_write.rst
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
.. index:: angle_write
|
||||||
|
|
||||||
|
angle_write command
|
||||||
|
===================
|
||||||
|
|
||||||
|
Syntax
|
||||||
|
""""""
|
||||||
|
|
||||||
|
.. code-block:: LAMMPS
|
||||||
|
|
||||||
|
angle_write atype N file keyword
|
||||||
|
|
||||||
|
* atype = angle type
|
||||||
|
* N = # of values
|
||||||
|
* file = name of file to write values to
|
||||||
|
* keyword = section name in file for this set of tabulated values
|
||||||
|
|
||||||
|
Examples
|
||||||
|
""""""""
|
||||||
|
|
||||||
|
.. code-block:: LAMMPS
|
||||||
|
|
||||||
|
angle_write 1 500 table.txt Harmonic_1
|
||||||
|
angle_write 3 1000 table.txt Harmonic_3
|
||||||
|
|
||||||
|
Description
|
||||||
|
"""""""""""
|
||||||
|
|
||||||
|
.. versionadded:: TBD
|
||||||
|
|
||||||
|
Write energy and force values to a file as a function of angle for the
|
||||||
|
currently defined angle potential. Force in this context means the
|
||||||
|
force with respect to the angle, not the force on individual atoms.
|
||||||
|
This is useful for plotting the potential function or otherwise
|
||||||
|
debugging its values. The resulting file can also be used as input for
|
||||||
|
use with :doc:`angle style table <angle_table>`.
|
||||||
|
|
||||||
|
If the file already exists, the table of values is appended to the end
|
||||||
|
of the file to allow multiple tables of energy and force to be included
|
||||||
|
in one file. The individual sections may be identified by the *keyword*.
|
||||||
|
|
||||||
|
The energy and force values are computed for angles ranging from 0
|
||||||
|
degrees to 180 degrees for 3 interacting atoms forming an angle type
|
||||||
|
atype, using the appropriate :doc:`angle_coeff <angle_coeff>`
|
||||||
|
coefficients. N evenly spaced angles are used.
|
||||||
|
|
||||||
|
For example, for N = 6, values are computed at :math:`\theta = 0, 36,
|
||||||
|
72, 108, 144, 180`.
|
||||||
|
|
||||||
|
The file is written in the format used as input for the
|
||||||
|
:doc:`angle_style table <angle_table>` option with *keyword* as the
|
||||||
|
section name. Each line written to the file lists an index number
|
||||||
|
(1-N), an angle (in degrees), an energy (in energy units), and a force
|
||||||
|
(in force units per radians^2). In case a new file is created, the
|
||||||
|
first line will be a comment with a "DATE:" and "UNITS:" tag with the
|
||||||
|
current date and :doc:`units <units>` settings. For subsequent
|
||||||
|
invocations of the *angle_write* command for the same file, data will be
|
||||||
|
appended and the current units settings will be compared to the data
|
||||||
|
from the header, if present. The *angle_write* will refuse to add a
|
||||||
|
table to an existing file if the units are not the same.
|
||||||
|
|
||||||
|
Restrictions
|
||||||
|
""""""""""""
|
||||||
|
|
||||||
|
All force field coefficients for angle and other kinds of interactions
|
||||||
|
must be set before this command can be invoked.
|
||||||
|
|
||||||
|
The table of the angle energy and force data data is created by using a
|
||||||
|
separate, internally created, new LAMMPS instance with a dummy system of
|
||||||
|
3 atoms for which the angle potential energy is computed after
|
||||||
|
transferring the angle style and coefficients and arranging the 3 atoms
|
||||||
|
into the corresponding geometries. The angle force is then determined
|
||||||
|
from the potential energies through numerical differentiation. As a
|
||||||
|
consequence of this approach, not all angle styles are compatible. The
|
||||||
|
following conditions must be met:
|
||||||
|
|
||||||
|
- The angle style must be able to write its coefficients to a data file.
|
||||||
|
This condition excludes for example :doc:`angle style hybrid <angle_hybrid>` and
|
||||||
|
:doc:`angle style table <angle_table>`.
|
||||||
|
- The potential function must not have any terms that depend on geometry
|
||||||
|
properties other than the angle. This condition excludes for example
|
||||||
|
:doc:`angle style class2 <angle_class2>` all angle types for
|
||||||
|
:doc:`angle style charmm <angle_charmm>` that have non-zero
|
||||||
|
Urey-Bradley terms. Please note that the *write_angle* command has no
|
||||||
|
way of checking for this condition, so the resulting tables may be
|
||||||
|
bogus if the requirement is not met. It is thus recommended to make
|
||||||
|
careful tests for any created tables.
|
||||||
|
|
||||||
|
Related commands
|
||||||
|
""""""""""""""""
|
||||||
|
|
||||||
|
:doc:`angle_style table <angle_table>`, :doc:`bond_write <bond_write>`,
|
||||||
|
:doc:`dihedral_write <dihedral_write>`, :doc:`angle_style <angle_style>`,
|
||||||
|
:doc:`angle_coeff <angle_coeff>`
|
||||||
|
|
||||||
|
Default
|
||||||
|
"""""""
|
||||||
|
|
||||||
|
none
|
||||||
@ -67,7 +67,7 @@ be specified even if the potential has a finite value at r = 0.0.
|
|||||||
Related commands
|
Related commands
|
||||||
""""""""""""""""
|
""""""""""""""""
|
||||||
|
|
||||||
:doc:`bond_style table <bond_table>`,
|
:doc:`bond_style table <bond_table>`, `angle_write <angle_write>`,
|
||||||
:doc:`bond_style <bond_style>`, :doc:`bond_coeff <bond_coeff>`
|
:doc:`bond_style <bond_style>`, :doc:`bond_coeff <bond_coeff>`
|
||||||
|
|
||||||
Default
|
Default
|
||||||
|
|||||||
@ -6,6 +6,7 @@ Commands
|
|||||||
|
|
||||||
angle_coeff
|
angle_coeff
|
||||||
angle_style
|
angle_style
|
||||||
|
angle_write
|
||||||
atom_modify
|
atom_modify
|
||||||
atom_style
|
atom_style
|
||||||
balance
|
balance
|
||||||
@ -27,6 +28,7 @@ Commands
|
|||||||
dielectric
|
dielectric
|
||||||
dihedral_coeff
|
dihedral_coeff
|
||||||
dihedral_style
|
dihedral_style
|
||||||
|
dihedral_write
|
||||||
dimension
|
dimension
|
||||||
displace_atoms
|
displace_atoms
|
||||||
dump
|
dump
|
||||||
|
|||||||
101
doc/src/dihedral_write.rst
Normal file
101
doc/src/dihedral_write.rst
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
.. index:: dihedral_write
|
||||||
|
|
||||||
|
dihedral_write command
|
||||||
|
======================
|
||||||
|
|
||||||
|
Syntax
|
||||||
|
""""""
|
||||||
|
|
||||||
|
.. code-block:: LAMMPS
|
||||||
|
|
||||||
|
dihedral_write dtype N file keyword
|
||||||
|
|
||||||
|
* dtype = dihedral type
|
||||||
|
* N = # of values
|
||||||
|
* file = name of file to write values to
|
||||||
|
* keyword = section name in file for this set of tabulated values
|
||||||
|
|
||||||
|
Examples
|
||||||
|
""""""""
|
||||||
|
|
||||||
|
.. code-block:: LAMMPS
|
||||||
|
|
||||||
|
dihedral_write 1 500 table.txt Harmonic_1
|
||||||
|
dihedral_write 3 1000 table.txt Harmonic_3
|
||||||
|
|
||||||
|
Description
|
||||||
|
"""""""""""
|
||||||
|
|
||||||
|
.. versionadded:: TBD
|
||||||
|
|
||||||
|
Write energy and force values to a file as a function of the dihedral
|
||||||
|
angle for the currently defined dihedral potential. Force in this
|
||||||
|
context means the force with respect to the dihedral angle, not the
|
||||||
|
force on individual atoms. This is useful for plotting the potential
|
||||||
|
function or otherwise debugging its values. The resulting file can also
|
||||||
|
be used as input for use with :doc:`dihedral style table
|
||||||
|
<dihedral_table>`.
|
||||||
|
|
||||||
|
If the file already exists, the table of values is appended to the end
|
||||||
|
of the file to allow multiple tables of energy and force to be included
|
||||||
|
in one file. The individual sections may be identified by the *keyword*.
|
||||||
|
|
||||||
|
The energy and force values are computed for dihedrals ranging from 0
|
||||||
|
degrees to 360 degrees for 4 interacting atoms forming an dihedral type
|
||||||
|
dtype, using the appropriate :doc:`dihedral_coeff <dihedral_coeff>`
|
||||||
|
coefficients. N evenly spaced dihedrals are used. Since 0 and 360
|
||||||
|
degrees are the same dihedral angle, the latter entry is skipped.
|
||||||
|
|
||||||
|
For example, for N = 6, values would be computed at
|
||||||
|
:math:`\phi = 0, 60, 120, 180, 240, 300`.
|
||||||
|
|
||||||
|
The file is written in the format used as input for the
|
||||||
|
:doc:`dihedral_style table <dihedral_table>` option with *keyword* as
|
||||||
|
the section name. Each line written to the file lists an index number
|
||||||
|
(1-N), an dihedral angle (in degrees), an energy (in energy units), and
|
||||||
|
a force (in force units per radians^2). In case a new file is created,
|
||||||
|
the first line will be a comment with a "DATE:" and "UNITS:" tag with
|
||||||
|
the current date and :doc:`units <units>` settings. For subsequent
|
||||||
|
invocations of the *dihedral_write* command for the same file, data will
|
||||||
|
be appended and the current units settings will be compared to the data
|
||||||
|
from the header, if present. The *dihedral_write* will refuse to add a
|
||||||
|
table to an existing file if the units are not the same.
|
||||||
|
|
||||||
|
Restrictions
|
||||||
|
""""""""""""
|
||||||
|
|
||||||
|
All force field coefficients for dihedrals and other kinds of interactions
|
||||||
|
must be set before this command can be invoked.
|
||||||
|
|
||||||
|
The table of the dihedral energy and force data data is created by using a
|
||||||
|
separate, internally created, new LAMMPS instance with a dummy system of
|
||||||
|
4 atoms for which the dihedral potential energy is computed after
|
||||||
|
transferring the dihedral style and coefficients and arranging the 4 atoms
|
||||||
|
into the corresponding geometries. The dihedral force is then determined
|
||||||
|
from the potential energies through numerical differentiation. As a
|
||||||
|
consequence of this approach, not all dihedral styles are compatible. The
|
||||||
|
following conditions must be met:
|
||||||
|
|
||||||
|
- The dihedral style must be able to write its coefficients to a data file.
|
||||||
|
This condition excludes for example :doc:`dihedral style hybrid <dihedral_hybrid>` and
|
||||||
|
:doc:`dihedral style table <dihedral_table>`.
|
||||||
|
- The potential function must not have any terms that depend on geometry
|
||||||
|
properties other than the dihedral. This condition excludes for
|
||||||
|
example :doc:`dihedral style class2 <dihedral_class2>`. Please note
|
||||||
|
that the *write_dihedral* command has no way of checking for this
|
||||||
|
condition. It will check the style name against an internal list of
|
||||||
|
known to be incompatible styles. The resulting tables may be bogus
|
||||||
|
for unlisted dihedral styles if the requirement is not met. It is
|
||||||
|
thus recommended to make careful tests for any created tables.
|
||||||
|
|
||||||
|
Related commands
|
||||||
|
""""""""""""""""
|
||||||
|
|
||||||
|
:doc:`dihedral_style table <dihedral_table>`, :doc:`bond_write <bond_write>`,
|
||||||
|
:doc:`angle_write <angle_write>`, :doc:`dihedral_style <dihedral_style>`,
|
||||||
|
:doc:`dihedral_coeff <dihedral_coeff>`
|
||||||
|
|
||||||
|
Default
|
||||||
|
"""""""
|
||||||
|
|
||||||
|
none
|
||||||
@ -174,6 +174,7 @@ attrac
|
|||||||
Atw
|
Atw
|
||||||
Atwater
|
Atwater
|
||||||
atwt
|
atwt
|
||||||
|
atype
|
||||||
augt
|
augt
|
||||||
AuO
|
AuO
|
||||||
automagically
|
automagically
|
||||||
@ -828,6 +829,7 @@ dtemp
|
|||||||
dtgrow
|
dtgrow
|
||||||
dtheta
|
dtheta
|
||||||
dtshrink
|
dtshrink
|
||||||
|
dtype
|
||||||
du
|
du
|
||||||
dU
|
dU
|
||||||
Ducastelle
|
Ducastelle
|
||||||
|
|||||||
227
src/angle_write.cpp
Normal file
227
src/angle_write.cpp
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
||||||
|
https://www.lammps.org/, Sandia National Laboratories
|
||||||
|
LAMMPS development team: developers@lammps.org
|
||||||
|
|
||||||
|
Copyright (2003) Sandia Corporation. Under the terms of Contract
|
||||||
|
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
|
||||||
|
certain rights in this software. This software is distributed under
|
||||||
|
the GNU General Public License.
|
||||||
|
|
||||||
|
See the README file in the top-level LAMMPS directory.
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
Contributing authors: Axel Kohlmeyer (Temple U)
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#include "angle_write.h"
|
||||||
|
|
||||||
|
#include "angle.h"
|
||||||
|
#include "atom.h"
|
||||||
|
#include "atom_vec.h"
|
||||||
|
#include "comm.h"
|
||||||
|
#include "domain.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "force.h"
|
||||||
|
#include "input.h"
|
||||||
|
#include "lammps.h"
|
||||||
|
#include "math_const.h"
|
||||||
|
#include "update.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
using namespace LAMMPS_NS;
|
||||||
|
using MathConst::DEG2RAD;
|
||||||
|
using MathConst::RAD2DEG;
|
||||||
|
|
||||||
|
static constexpr double epsilon = 6.5e-6;
|
||||||
|
#define MAXLINE 1024
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void AngleWrite::command(int narg, char **arg)
|
||||||
|
{
|
||||||
|
// sanity checks
|
||||||
|
|
||||||
|
if (domain->box_exist == 0)
|
||||||
|
error->all(FLERR, "Angle_write command before simulation box is defined");
|
||||||
|
if (atom->avec->angles_allow == 0)
|
||||||
|
error->all(FLERR, "Angle_write command when no angles allowed");
|
||||||
|
auto angle = force->angle;
|
||||||
|
if (angle == nullptr) error->all(FLERR, "Angle_write command before an angle_style is defined");
|
||||||
|
if (angle && (force->angle->writedata == 0))
|
||||||
|
error->all(FLERR, "Angle style must support writing coeffs to data file for angle_write");
|
||||||
|
|
||||||
|
if (angle && (utils::strmatch(force->angle_style, "^class2")))
|
||||||
|
error->all(FLERR, "Angle_write command is not compatible with angle style {}",
|
||||||
|
force->angle_style);
|
||||||
|
|
||||||
|
// parse arguments
|
||||||
|
|
||||||
|
if (narg != 4) error->all(FLERR, "Illegal angle_write command");
|
||||||
|
|
||||||
|
int atype = utils::inumeric(FLERR, arg[0], false, lmp);
|
||||||
|
if ((atype <= 0) || (atype > atom->nangletypes))
|
||||||
|
error->all(FLERR, "Invalid angle type {} in angle_write command", atype);
|
||||||
|
|
||||||
|
int n = utils::inumeric(FLERR, arg[1], false, lmp);
|
||||||
|
std::string table_file = arg[2];
|
||||||
|
std::string keyword = arg[3];
|
||||||
|
|
||||||
|
// make sure system is initialized before calling any functions
|
||||||
|
|
||||||
|
lmp->init();
|
||||||
|
|
||||||
|
double theta0 = angle->equilibrium_angle(atype) * RAD2DEG;
|
||||||
|
|
||||||
|
// write out all angle_coeff settings to file. use function from write_data.
|
||||||
|
// open table file in append mode if it already exists
|
||||||
|
// add line with DATE: and UNITS: tag when creating new file
|
||||||
|
// otherwise make certain that units are consistent
|
||||||
|
// print header in format used by angle_style table
|
||||||
|
|
||||||
|
FILE *fp = nullptr;
|
||||||
|
std::string coeffs_file = table_file + ".tmp.coeffs";
|
||||||
|
if (comm->me == 0) {
|
||||||
|
|
||||||
|
fp = fopen(coeffs_file.c_str(), "w");
|
||||||
|
force->angle->write_data(fp);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
// units sanity check:
|
||||||
|
// - if this is the first time we write to this potential file,
|
||||||
|
// write out a line with "DATE:" and "UNITS:" tags
|
||||||
|
// - if the file already exists, print a message about appending
|
||||||
|
// while printing the date and check that units are consistent.
|
||||||
|
if (platform::file_is_readable(table_file)) {
|
||||||
|
std::string units = utils::get_potential_units(table_file, "table");
|
||||||
|
if (!units.empty() && (units != update->unit_style)) {
|
||||||
|
error->one(FLERR, "Trying to append to a table file with UNITS: {} while units are {}",
|
||||||
|
units, update->unit_style);
|
||||||
|
}
|
||||||
|
std::string date = utils::get_potential_date(table_file, "table");
|
||||||
|
utils::logmesg(lmp, "Appending to table file {} with DATE: {}\n", table_file, date);
|
||||||
|
fp = fopen(table_file.c_str(), "a");
|
||||||
|
} else {
|
||||||
|
utils::logmesg(lmp, "Creating table file {} with DATE: {}\n", table_file,
|
||||||
|
utils::current_date());
|
||||||
|
fp = fopen(table_file.c_str(), "w");
|
||||||
|
if (fp)
|
||||||
|
fmt::print(fp, "# DATE: {} UNITS: {} Created by angle_write\n", utils::current_date(),
|
||||||
|
update->unit_style);
|
||||||
|
}
|
||||||
|
if (fp == nullptr)
|
||||||
|
error->one(FLERR, "Cannot open angle_write file {}: {}", table_file, utils::getsyserror());
|
||||||
|
}
|
||||||
|
|
||||||
|
// split communicator so that we can run a new LAMMPS class instance only on comm->me == 0
|
||||||
|
|
||||||
|
MPI_Comm singlecomm;
|
||||||
|
int color = (comm->me == 0) ? 1 : MPI_UNDEFINED;
|
||||||
|
int key = comm->me;
|
||||||
|
MPI_Comm_split(world, color, key, &singlecomm);
|
||||||
|
|
||||||
|
if (comm->me == 0) {
|
||||||
|
// set up new LAMMPS instance with dummy system to evaluate angle potential
|
||||||
|
const char *args[] = {"AngleWrite", "-nocite", "-echo", "none",
|
||||||
|
"-log", "none", "-screen", "none"};
|
||||||
|
char **argv = (char **) args;
|
||||||
|
int argc = sizeof(args) / sizeof(char *);
|
||||||
|
LAMMPS *writer = new LAMMPS(argc, argv, singlecomm);
|
||||||
|
|
||||||
|
// create dummy system replicating angle style settings
|
||||||
|
writer->input->one(fmt::format("units {}", update->unit_style));
|
||||||
|
writer->input->one("atom_style angle");
|
||||||
|
writer->input->one("atom_modify map array");
|
||||||
|
writer->input->one("boundary f f f");
|
||||||
|
writer->input->one("region box block -2 2 -2 2 -1 1");
|
||||||
|
writer->input->one(fmt::format("create_box {} box angle/types {} "
|
||||||
|
"extra/angle/per/atom 1 "
|
||||||
|
"extra/special/per/atom 4",
|
||||||
|
atom->ntypes, atom->nangletypes));
|
||||||
|
writer->input->one("create_atoms 1 single 0.0 0.0 0.0");
|
||||||
|
writer->input->one("create_atoms 1 single 1.0 0.0 0.0");
|
||||||
|
writer->input->one("create_atoms 1 single -1.0 0.0 0.0");
|
||||||
|
writer->input->one(fmt::format("create_bonds single/angle {} 2 1 3", atype));
|
||||||
|
|
||||||
|
writer->input->one("pair_style zero 10.0");
|
||||||
|
writer->input->one("pair_coeff * *");
|
||||||
|
writer->input->one("mass * 1.0");
|
||||||
|
writer->input->one(fmt::format("angle_style {}", force->angle_style));
|
||||||
|
FILE *coeffs;
|
||||||
|
char line[MAXLINE];
|
||||||
|
coeffs = fopen(coeffs_file.c_str(), "r");
|
||||||
|
for (int i = 0; i < atom->nangletypes; ++i) {
|
||||||
|
fgets(line, MAXLINE, coeffs);
|
||||||
|
writer->input->one(fmt::format("angle_coeff {}", line));
|
||||||
|
}
|
||||||
|
fclose(coeffs);
|
||||||
|
platform::unlink(coeffs_file);
|
||||||
|
|
||||||
|
// initialize system
|
||||||
|
|
||||||
|
writer->init();
|
||||||
|
|
||||||
|
// move third atom to reproduce angles
|
||||||
|
|
||||||
|
double theta, phi, phi1, phi2, f;
|
||||||
|
angle = writer->force->angle;
|
||||||
|
int i1, i2, i3;
|
||||||
|
i1 = writer->atom->map(1);
|
||||||
|
i2 = writer->atom->map(2);
|
||||||
|
i3 = writer->atom->map(3);
|
||||||
|
auto atom3 = writer->atom->x[i3];
|
||||||
|
|
||||||
|
// evaluate energy and force at each of N distances
|
||||||
|
|
||||||
|
fmt::print(fp, "# Angle potential {} for angle type {}: i,theta,energy,force\n",
|
||||||
|
force->angle_style, atype);
|
||||||
|
fmt::print(fp, "\n{}\nN {} EQ {:.15g}\n\n", keyword, n, theta0);
|
||||||
|
|
||||||
|
#define GET_ENERGY(myphi, mytheta) \
|
||||||
|
theta = mytheta; \
|
||||||
|
atom3[0] = cos(theta * DEG2RAD); \
|
||||||
|
atom3[1] = sin(theta * DEG2RAD); \
|
||||||
|
myphi = angle->single(atype, i2, i1, i3)
|
||||||
|
|
||||||
|
const double dtheta = 180.0 / static_cast<double>(n - 1);
|
||||||
|
|
||||||
|
// get force for divergent 0 degree angle from interpolation to the right
|
||||||
|
|
||||||
|
GET_ENERGY(phi, 0.0);
|
||||||
|
GET_ENERGY(phi1, epsilon);
|
||||||
|
GET_ENERGY(phi2, 2.0 * epsilon);
|
||||||
|
|
||||||
|
f = (1.5 * phi - 2.0 * phi1 + 0.5 * phi2) / epsilon;
|
||||||
|
if (!std::isfinite(f)) f = 0.0;
|
||||||
|
if (!std::isfinite(phi)) phi = 0.0;
|
||||||
|
fprintf(fp, "%8d %- 22.15g %- 22.15g %- 22.15g\n", 1, 0.0, phi, f);
|
||||||
|
|
||||||
|
for (int i = 1; i < n - 1; i++) {
|
||||||
|
GET_ENERGY(phi1, dtheta * static_cast<double>(i) - epsilon);
|
||||||
|
GET_ENERGY(phi2, dtheta * static_cast<double>(i) + epsilon);
|
||||||
|
GET_ENERGY(phi, dtheta * static_cast<double>(i));
|
||||||
|
|
||||||
|
if (!std::isfinite(phi)) phi = 0.0;
|
||||||
|
|
||||||
|
// get force from numerical differentiation
|
||||||
|
f = -0.5 * (phi2 - phi1) / epsilon;
|
||||||
|
if (!std::isfinite(f)) f = 0.0;
|
||||||
|
fprintf(fp, "%8d %- 22.15g %- 22.15g %- 22.15g\n", i + 1, theta, phi, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get force for divergent 180 degree angle from interpolation to the left
|
||||||
|
GET_ENERGY(phi, 180.0);
|
||||||
|
GET_ENERGY(phi1, 180.0 - epsilon);
|
||||||
|
GET_ENERGY(phi2, 180.0 - 2.0 * epsilon);
|
||||||
|
|
||||||
|
f = (2.0 * phi1 - 1.5 * phi - 0.5 * phi2) / epsilon;
|
||||||
|
if (!std::isfinite(f)) f = 0.0;
|
||||||
|
if (!std::isfinite(phi)) phi = 0.0;
|
||||||
|
fprintf(fp, "%8d %- 22.15g %- 22.15g %- 22.15g\n", 1, 180.0, phi, f);
|
||||||
|
|
||||||
|
// clean up
|
||||||
|
delete writer;
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
MPI_Comm_free(&singlecomm);
|
||||||
|
}
|
||||||
34
src/angle_write.h
Normal file
34
src/angle_write.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/* -*- c++ -*- ----------------------------------------------------------
|
||||||
|
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
||||||
|
https://www.lammps.org/, Sandia National Laboratories
|
||||||
|
LAMMPS development team: developers@lammps.org
|
||||||
|
|
||||||
|
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 COMMAND_CLASS
|
||||||
|
// clang-format off
|
||||||
|
CommandStyle(angle_write,AngleWrite);
|
||||||
|
// clang-format on
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifndef LMP_ANGLE_WRITE_H
|
||||||
|
#define LMP_ANGLE_WRITE_H
|
||||||
|
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
namespace LAMMPS_NS {
|
||||||
|
|
||||||
|
class AngleWrite : public Command {
|
||||||
|
public:
|
||||||
|
AngleWrite(class LAMMPS *lmp) : Command(lmp){};
|
||||||
|
void command(int, char **) override;
|
||||||
|
};
|
||||||
|
} // namespace LAMMPS_NS
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
206
src/dihedral_write.cpp
Normal file
206
src/dihedral_write.cpp
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
||||||
|
https://www.lammps.org/, Sandia National Laboratories
|
||||||
|
LAMMPS development team: developers@lammps.org
|
||||||
|
|
||||||
|
Copyright (2003) Sandia Corporation. Under the terms of Contract
|
||||||
|
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
|
||||||
|
certain rights in this software. This software is distributed under
|
||||||
|
the GNU General Public License.
|
||||||
|
|
||||||
|
See the README file in the top-level LAMMPS directory.
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
Contributing authors: Axel Kohlmeyer (Temple U)
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#include "dihedral_write.h"
|
||||||
|
|
||||||
|
#include "atom.h"
|
||||||
|
#include "atom_vec.h"
|
||||||
|
#include "comm.h"
|
||||||
|
#include "dihedral.h"
|
||||||
|
#include "domain.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "force.h"
|
||||||
|
#include "input.h"
|
||||||
|
#include "lammps.h"
|
||||||
|
#include "math_const.h"
|
||||||
|
#include "update.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
using namespace LAMMPS_NS;
|
||||||
|
using MathConst::DEG2RAD;
|
||||||
|
using MathConst::RAD2DEG;
|
||||||
|
|
||||||
|
static constexpr double epsilon = 6.5e-6;
|
||||||
|
#define MAXLINE 1024
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void DihedralWrite::command(int narg, char **arg)
|
||||||
|
{
|
||||||
|
// sanity checks
|
||||||
|
|
||||||
|
if (domain->box_exist == 0)
|
||||||
|
error->all(FLERR, "Dihedral_write command before simulation box is defined");
|
||||||
|
if (atom->avec->dihedrals_allow == 0)
|
||||||
|
error->all(FLERR, "Dihedral_write command when no dihedrals allowed");
|
||||||
|
auto dihedral = force->dihedral;
|
||||||
|
if (dihedral == nullptr)
|
||||||
|
error->all(FLERR, "Dihedral_write command before an dihedral_style is defined");
|
||||||
|
if (dihedral && (force->dihedral->writedata == 0))
|
||||||
|
error->all(FLERR, "Dihedral style must support writing coeffs to data file for dihedral_write");
|
||||||
|
|
||||||
|
if (dihedral &&
|
||||||
|
(utils::strmatch(force->dihedral_style, "^charmm") ||
|
||||||
|
utils::strmatch(force->dihedral_style, "^class2")))
|
||||||
|
error->all(FLERR, "Dihedral_write command is not compatible with dihedral style {}",
|
||||||
|
force->dihedral_style);
|
||||||
|
|
||||||
|
// parse arguments
|
||||||
|
|
||||||
|
if (narg != 4) error->all(FLERR, "Illegal dihedral_write command");
|
||||||
|
|
||||||
|
int dtype = utils::inumeric(FLERR, arg[0], false, lmp);
|
||||||
|
if ((dtype <= 0) || (dtype > atom->ndihedraltypes))
|
||||||
|
error->all(FLERR, "Invalid dihedral type {} in dihedral_write command", dtype);
|
||||||
|
|
||||||
|
int n = utils::inumeric(FLERR, arg[1], false, lmp);
|
||||||
|
std::string table_file = arg[2];
|
||||||
|
std::string keyword = arg[3];
|
||||||
|
|
||||||
|
// make sure system is initialized before calling any functions
|
||||||
|
|
||||||
|
lmp->init();
|
||||||
|
|
||||||
|
// write out all dihedral_coeff settings to file. use function from write_data.
|
||||||
|
// open table file in append mode if it already exists
|
||||||
|
// add line with DATE: and UNITS: tag when creating new file
|
||||||
|
// otherwise make certain that units are consistent
|
||||||
|
// print header in format used by dihedral_style table
|
||||||
|
|
||||||
|
FILE *fp = nullptr;
|
||||||
|
std::string coeffs_file = table_file + ".tmp.coeffs";
|
||||||
|
if (comm->me == 0) {
|
||||||
|
|
||||||
|
fp = fopen(coeffs_file.c_str(), "w");
|
||||||
|
force->dihedral->write_data(fp);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
// units sanity check:
|
||||||
|
// - if this is the first time we write to this potential file,
|
||||||
|
// write out a line with "DATE:" and "UNITS:" tags
|
||||||
|
// - if the file already exists, print a message about appending
|
||||||
|
// while printing the date and check that units are consistent.
|
||||||
|
if (platform::file_is_readable(table_file)) {
|
||||||
|
std::string units = utils::get_potential_units(table_file, "table");
|
||||||
|
if (!units.empty() && (units != update->unit_style)) {
|
||||||
|
error->one(FLERR, "Trying to append to a table file with UNITS: {} while units are {}",
|
||||||
|
units, update->unit_style);
|
||||||
|
}
|
||||||
|
std::string date = utils::get_potential_date(table_file, "table");
|
||||||
|
utils::logmesg(lmp, "Appending to table file {} with DATE: {}\n", table_file, date);
|
||||||
|
fp = fopen(table_file.c_str(), "a");
|
||||||
|
} else {
|
||||||
|
utils::logmesg(lmp, "Creating table file {} with DATE: {}\n", table_file,
|
||||||
|
utils::current_date());
|
||||||
|
fp = fopen(table_file.c_str(), "w");
|
||||||
|
if (fp)
|
||||||
|
fmt::print(fp, "# DATE: {} UNITS: {} Created by dihedral_write\n", utils::current_date(),
|
||||||
|
update->unit_style);
|
||||||
|
}
|
||||||
|
if (fp == nullptr)
|
||||||
|
error->one(FLERR, "Cannot open dihedral_write file {}: {}", table_file, utils::getsyserror());
|
||||||
|
}
|
||||||
|
|
||||||
|
// split communicator so that we can run a new LAMMPS class instance only on comm->me == 0
|
||||||
|
|
||||||
|
MPI_Comm singlecomm;
|
||||||
|
int color = (comm->me == 0) ? 1 : MPI_UNDEFINED;
|
||||||
|
int key = comm->me;
|
||||||
|
MPI_Comm_split(world, color, key, &singlecomm);
|
||||||
|
|
||||||
|
if (comm->me == 0) {
|
||||||
|
// set up new LAMMPS instance with dummy system to evaluate dihedral potential
|
||||||
|
// const char *args[] = {"DihedralWrite", "-nocite", "-echo", "none",
|
||||||
|
// "-log", "none", "-screen", "none"};
|
||||||
|
const char *args[] = {"DihedralWrite", "-nocite", "-echo", "screen", "-log", "none"};
|
||||||
|
char **argv = (char **) args;
|
||||||
|
int argc = sizeof(args) / sizeof(char *);
|
||||||
|
LAMMPS *writer = new LAMMPS(argc, argv, singlecomm);
|
||||||
|
|
||||||
|
// create dummy system replicating dihedral style settings
|
||||||
|
writer->input->one(fmt::format("units {}", update->unit_style));
|
||||||
|
writer->input->one("atom_style molecular");
|
||||||
|
writer->input->one("atom_modify map array");
|
||||||
|
writer->input->one("boundary f f f");
|
||||||
|
writer->input->one("region box block -2 2 -2 2 -2 2");
|
||||||
|
writer->input->one(fmt::format("create_box {} box dihedral/types {} "
|
||||||
|
"extra/dihedral/per/atom 1 "
|
||||||
|
"extra/special/per/atom 4",
|
||||||
|
atom->ntypes, atom->ndihedraltypes));
|
||||||
|
writer->input->one("create_atoms 1 single 1.0 0.0 -1.0");
|
||||||
|
writer->input->one("create_atoms 1 single 0.0 0.0 -1.0");
|
||||||
|
writer->input->one("create_atoms 1 single 0.0 0.0 1.0");
|
||||||
|
writer->input->one("create_atoms 1 single 1.0 0.0 1.0");
|
||||||
|
writer->input->one(fmt::format("create_bonds single/dihedral {} 1 2 3 4", dtype));
|
||||||
|
|
||||||
|
writer->input->one("pair_style zero 10.0");
|
||||||
|
writer->input->one("pair_coeff * *");
|
||||||
|
writer->input->one("mass * 1.0");
|
||||||
|
writer->input->one(fmt::format("dihedral_style {}", force->dihedral_style));
|
||||||
|
FILE *coeffs;
|
||||||
|
char line[MAXLINE];
|
||||||
|
coeffs = fopen(coeffs_file.c_str(), "r");
|
||||||
|
for (int i = 0; i < atom->ndihedraltypes; ++i) {
|
||||||
|
fgets(line, MAXLINE, coeffs);
|
||||||
|
writer->input->one(fmt::format("dihedral_coeff {}", line));
|
||||||
|
}
|
||||||
|
fclose(coeffs);
|
||||||
|
platform::unlink(coeffs_file);
|
||||||
|
|
||||||
|
// must complete a full setup() to initialize system including neighbor and dihedral lists.
|
||||||
|
|
||||||
|
writer->input->one("run 0 post no");
|
||||||
|
|
||||||
|
// move third atom to reproduce dihedrals
|
||||||
|
|
||||||
|
double theta, phi, phi1, phi2, f;
|
||||||
|
dihedral = writer->force->dihedral;
|
||||||
|
auto atom4 = writer->atom->x[writer->atom->map(4)];
|
||||||
|
|
||||||
|
// evaluate energy and force at each of N distances
|
||||||
|
|
||||||
|
fmt::print(fp, "# Dihedral potential {} for dihedral type {}: i,theta,energy,force\n",
|
||||||
|
force->dihedral_style, dtype);
|
||||||
|
fmt::print(fp, "\n{}\nN {} DEGREES\n\n", keyword, n);
|
||||||
|
|
||||||
|
#define GET_ENERGY(myphi, mytheta) \
|
||||||
|
theta = mytheta; \
|
||||||
|
atom4[0] = cos(theta * DEG2RAD); \
|
||||||
|
atom4[1] = sin(theta * DEG2RAD); \
|
||||||
|
dihedral->energy = 0.0; \
|
||||||
|
dihedral->compute(ENERGY_GLOBAL, 0); \
|
||||||
|
myphi = dihedral->energy
|
||||||
|
|
||||||
|
const double dtheta = 360.0 / static_cast<double>(n);
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
GET_ENERGY(phi1, dtheta * static_cast<double>(i) - epsilon);
|
||||||
|
GET_ENERGY(phi2, dtheta * static_cast<double>(i) + epsilon);
|
||||||
|
GET_ENERGY(phi, dtheta * static_cast<double>(i));
|
||||||
|
|
||||||
|
if (!std::isfinite(phi)) phi = 0.0;
|
||||||
|
|
||||||
|
// get force from numerical differentiation
|
||||||
|
f = -0.5 * (phi2 - phi1) / epsilon;
|
||||||
|
if (!std::isfinite(f)) f = 0.0;
|
||||||
|
fprintf(fp, "%8d %- 22.15g %- 22.15g %- 22.15g\n", i + 1, theta, phi, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean up
|
||||||
|
delete writer;
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
MPI_Comm_free(&singlecomm);
|
||||||
|
}
|
||||||
34
src/dihedral_write.h
Normal file
34
src/dihedral_write.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/* -*- c++ -*- ----------------------------------------------------------
|
||||||
|
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
||||||
|
https://www.lammps.org/, Sandia National Laboratories
|
||||||
|
LAMMPS development team: developers@lammps.org
|
||||||
|
|
||||||
|
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 COMMAND_CLASS
|
||||||
|
// clang-format off
|
||||||
|
CommandStyle(dihedral_write,DihedralWrite);
|
||||||
|
// clang-format on
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifndef LMP_DIHEDRAL_WRITE_H
|
||||||
|
#define LMP_DIHEDRAL_WRITE_H
|
||||||
|
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
namespace LAMMPS_NS {
|
||||||
|
|
||||||
|
class DihedralWrite : public Command {
|
||||||
|
public:
|
||||||
|
DihedralWrite(class LAMMPS *lmp) : Command(lmp){};
|
||||||
|
void command(int, char **) override;
|
||||||
|
};
|
||||||
|
} // namespace LAMMPS_NS
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user