Merge pull request #4359 from jtclemm/BPM

Adding new force options to BPM package
This commit is contained in:
Axel Kohlmeyer
2024-10-29 21:31:03 -04:00
committed by GitHub
13 changed files with 514 additions and 125 deletions

View File

@ -42,7 +42,8 @@ Currently, there are two types of bonds included in the BPM package. The
first bond style, :doc:`bond bpm/spring <bond_bpm_spring>`, only applies
pairwise, central body forces. Point particles must have :doc:`bond atom
style <atom_style>` and may be thought of as nodes in a spring
network. Alternatively, the second bond style, :doc:`bond bpm/rotational
network. An optional multibody term can be used to adjust the network's
Poisson's ratio. Alternatively, the second bond style, :doc:`bond bpm/rotational
<bond_bpm_rotational>`, resolves tangential forces and torques arising
with the shearing, bending, and twisting of the bond due to rotation or
displacement of particles. Particles are similar to those used in the
@ -55,8 +56,9 @@ orientation similar to :doc:`fix nve/asphere <fix_nve_asphere>`.
In addition to bond styles, a new pair style :doc:`pair bpm/spring
<pair_bpm_spring>` was added to accompany the bpm/spring bond
style. This pair style is simply a hookean repulsion with similar
velocity damping as its sister bond style.
style. By default, this pair style is simply a hookean repulsion with
similar velocity damping as its sister bond style, but optional
arguments can be used to modify the force.
----------

View File

@ -10,7 +10,7 @@ Syntax
bond_style bpm/spring keyword value attribute1 attribute2 ...
* optional keyword = *overlay/pair* or *store/local* or *smooth* or *break*
* optional keyword = *overlay/pair* or *store/local* or *smooth* or *break* or *volume/factor*
.. parsed-literal::
@ -36,6 +36,9 @@ Syntax
*break* value = *yes* or *no*
indicates whether bonds break during a run
*volume/factor* value = *yes* or *no*
indicates whether forces include the volumetric contribution
Examples
""""""""
@ -44,6 +47,9 @@ Examples
bond_style bpm/spring
bond_coeff 1 1.0 0.05 0.1
bond_style bpm/spring volume/factor yes
bond_coeff 1 1.0 0.05 0.1 0.5
bond_style bpm/spring myfix 1000 time id1 id2
dump 1 all local 1000 dump.broken f_myfix[1] f_myfix[2] f_myfix[3]
dump_modify 1 write_header no
@ -97,15 +103,6 @@ approach the critical strain
w = 1.0 - \left( \frac{r - r_0}{r_0 \epsilon_c} \right)^8 .
The following coefficients must be defined for each bond type via the
:doc:`bond_coeff <bond_coeff>` command as in the example above, or in
the data file or restart files read by the :doc:`read_data
<read_data>` or :doc:`read_restart <read_restart>` commands:
* :math:`k` (force/distance units)
* :math:`\epsilon_c` (unit less)
* :math:`\gamma` (force/velocity units)
If the *normalize* keyword is set to *yes*, the elastic bond force will be
normalized by :math:`r_0` such that :math:`k` must be given in force units.
@ -123,6 +120,43 @@ during a simulation run. This will prevent some unnecessary calculation.
However, if a bond reaches a strain greater than :math:`\epsilon_c`,
it will trigger an error.
.. versionadded:: TBD
The *volume/factor* keyword toggles whether an additional multibody
contribution is added to he force using the formulation in
:ref:`(Clemmer2) <multibody-Clemmer>`,
.. math::
\alpha_v \left(\left[\frac{V_i + V_j}{V_{0,i} + V_{0,j}}\right]^{1/3} - \frac{r_{ij}}{r_{0,ij}}\right)
where :math:`\alpha_v` is a user specified coefficient and :math:`V_i`
and :math:`V_{0,i}` are estimates of the current and local volume
of atom :math:`i`. These volumes are calculated as the sum of current
or initial bond lengths cubed. In 2D, the volume is replaced with an area
calculated using bond lengths squared and the cube root in the above equation
is accordingly replaced with a square root. This approximation assumes bonds
are evenly distributed on a spherical surface and neglects constant prefactors
which are irrelevant since only the ratio of volumes matters. This term may be
used to adjust the Poisson's ratio.
If a bond is broken (or created), :math:`V_{0,i}` is updated by subtracting
(or adding) that bond's contribution.
The following coefficients must be defined for each bond type via the
:doc:`bond_coeff <bond_coeff>` command as in the example above, or in
the data file or restart files read by the :doc:`read_data
<read_data>` or :doc:`read_restart <read_restart>` commands:
* :math:`k` (force/distance units)
* :math:`\epsilon_c` (unit less)
* :math:`\gamma` (force/velocity units)
Additionally, if *volume/factor* is set to *yes*, a fourth coefficient
must be provided:
* :math:`a_v` (force units)
If the *store/local* keyword is used, an internal fix will track bonds that
break during the simulation. Whenever a bond breaks, data is processed
and transferred to an internal fix labeled *fix_ID*. This allows the
@ -213,7 +247,7 @@ Related commands
Default
"""""""
The option defaults are *overlay/pair* = *no*, *smooth* = *yes*, *normalize* = *no*, and *break* = *yes*
The option defaults are *overlay/pair* = *no*, *smooth* = *yes*, *normalize* = *no*, *break* = *yes*, and *volume/factor* = *no*
----------
@ -224,3 +258,7 @@ The option defaults are *overlay/pair* = *no*, *smooth* = *yes*, *normalize* = *
.. _Groot4:
**(Groot)** Groot and Warren, J Chem Phys, 107, 4423-35 (1997).
.. _multibody-Clemmer:
**(Clemmer2)** Clemmer, Monti, Lechman, Soft Matter, 20, 1702 (2024).

View File

@ -8,7 +8,14 @@ Syntax
.. code-block:: LAMMPS
pair_style bpm/spring
pair_style bpm/spring keyword value ...
* optional keyword = *anharmonic*
.. parsed-literal::
*anharmonic* value = *yes* or *no*
whether forces include the anharmonic term
Examples
""""""""
@ -17,7 +24,8 @@ Examples
pair_style bpm/spring
pair_coeff * * 1.0 1.0 1.0
pair_coeff 1 1 1.0 1.0 1.0
pair_style bpm/spring anharmonic yes
pair_coeff 1 1 1.0 1.0 1.0 50.0
Description
"""""""""""
@ -28,12 +36,16 @@ Style *bpm/spring* computes pairwise forces with the formula
.. math::
F = k (r - r_c)
F = k (r - r_c) + k_a (r - r_c)^3
where :math:`k` is a stiffness and :math:`r_c` is the cutoff length.
An additional damping force is also applied to interacting
particles. The force is proportional to the difference in the
normal velocity of particles
where :math:`k` is a stiffness, :math:`r_c` is the cutoff
length, and :math:`k_a` is an optional anharmonic cubic prefactor
that can be enabled using the *anharmonic* keyword. The anharmonic
term may be useful in scenarios that need to prevent large particle overlap.
An additional damping force is also applied to interacting particles.
The force is proportional to the difference in the normal velocity of
particles
.. math::
@ -73,6 +85,12 @@ commands, or by mixing as described below:
* :math:`r_c` (distance units)
* :math:`\gamma` (force/velocity units)
.. versionadded:: TBD
Additionally, if *anharmonic* is set to *yes*, a fourth coefficient
must be provided:
* :math:`k_a` (force/distance\^3 units)
----------
@ -117,4 +135,5 @@ Related commands
Default
"""""""
none
The option defaults are *anharmonic* = *no*

View File

@ -45,7 +45,7 @@ thermo 100
thermo_modify lost ignore lost/bond ignore
#dump 1 all custom 100 atomDump id radius x y z c_nbond
dump 2 all local 100 brokenDump f_brkbond[1] f_brkbond[2] f_brkbond[3]
dump_modify 2 header no
#dump 2 all local 100 brokenDump f_brkbond[1] f_brkbond[2] f_brkbond[3]
#dump_modify 2 header no
run 7500

View File

@ -47,7 +47,7 @@ thermo 100
thermo_modify lost ignore lost/bond ignore
#dump 1 all custom 100 atomDump id x y z c_nbond
dump 2 all local 100 brokenDump f_brkbond[1] f_brkbond[2] f_brkbond[3]
dump_modify 2 header no
#dump 2 all local 100 brokenDump f_brkbond[1] f_brkbond[2] f_brkbond[3]
#dump_modify 2 header no
run 7500

View File

@ -33,31 +33,32 @@
using namespace LAMMPS_NS;
static const char cite_bpm[] =
"BPM bond style: doi:10.1039/D3SM01373A\n\n"
"@Article{Clemmer2024,\n"
" author = {Clemmer, Joel T. and Monti, Joseph M. and Lechman, Jeremy B.},\n"
" title = {A soft departure from jamming: the compaction of deformable\n"
" granular matter under high pressures},\n"
" journal = {Soft Matter},\n"
" year = 2024,\n"
" volume = 20,\n"
" number = 8,\n"
" pages = {1702--1718}\n"
"}\n\n";
"BPM bond style: doi:10.1039/D3SM01373A\n\n"
"@Article{Clemmer2024,\n"
" author = {Clemmer, Joel T. and Monti, Joseph M. and Lechman, Jeremy B.},\n"
" title = {A soft departure from jamming: the compaction of deformable\n"
" granular matter under high pressures},\n"
" journal = {Soft Matter},\n"
" year = 2024,\n"
" volume = 20,\n"
" number = 8,\n"
" pages = {1702--1718}\n"
"}\n\n";
/* ---------------------------------------------------------------------- */
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)
Bond(_lmp), id_fix_dummy_special(nullptr), id_fix_dummy_history(nullptr),
id_fix_update_special_bonds(nullptr), id_fix_bond_history(nullptr), id_fix_store_local(nullptr),
id_fix_property_atom(nullptr), fix_store_local(nullptr), fix_bond_history(nullptr),
fix_update_special_bonds(nullptr), pack_choice(nullptr), output_data(nullptr)
{
overlay_flag = 0;
ignore_special_flag = 0;
prop_atom_flag = 0;
property_atom_flag = 0;
break_flag = 1;
nvalues = 0;
writedata = 0;
nhistory = 0;
update_flag = 0;
@ -69,11 +70,11 @@ BondBPM::BondBPM(LAMMPS *_lmp) :
// 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(fmt::format("BPM_DUMMY_{}", instance_total));
modify->add_fix(fmt::format("{} all DUMMY ", id_fix_dummy));
id_fix_dummy_special = utils::strdup(fmt::format("BPM_DUMMY_SPECIAL_{}", instance_total));
modify->add_fix(fmt::format("{} all DUMMY ", id_fix_dummy_special));
id_fix_dummy2 = utils::strdup(fmt::format("BPM_DUMMY2_{}", instance_total));
modify->add_fix(fmt::format("{} all DUMMY ", id_fix_dummy2));
id_fix_dummy_history = utils::strdup(fmt::format("BPM_DUMMY_HISTORY_{}", instance_total));
modify->add_fix(fmt::format("{} all DUMMY ", id_fix_dummy_history));
if (lmp->citeme) lmp->citeme->add(cite_bpm);
}
@ -84,19 +85,17 @@ 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_dummy_special) modify->delete_fix(id_fix_dummy_special);
if (id_fix_dummy_history) modify->delete_fix(id_fix_dummy_history);
if (id_fix_update_special_bonds) modify->delete_fix(id_fix_update_special_bonds);
if (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);
if (id_fix_property_atom) modify->delete_fix(id_fix_property_atom);
delete[] id_fix_dummy;
delete[] id_fix_dummy2;
delete[] id_fix_update;
delete[] id_fix_update_special_bonds;
delete[] id_fix_bond_history;
delete[] id_fix_store_local;
delete[] id_fix_prop_atom;
delete[] id_fix_property_atom;
memory->destroy(output_data);
}
@ -116,19 +115,22 @@ void BondBPM::init_style()
if (!ignore_special_flag) {
if (overlay_flag) {
if (force->special_lj[1] != 1.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0 ||
force->special_coul[1] != 1.0 || force->special_coul[2] != 1.0 || force->special_coul[3] != 1.0)
if (force->special_lj[1] != 1.0 || force->special_lj[2] != 1.0 ||
force->special_lj[3] != 1.0 || force->special_coul[1] != 1.0 ||
force->special_coul[2] != 1.0 || force->special_coul[3] != 1.0)
error->all(FLERR,
"With overlay/pair yes, BPM bond styles require a value of 1.0 for all special_bonds weights");
if (id_fix_update) {
modify->delete_fix(id_fix_update);
delete[] id_fix_update;
id_fix_update = nullptr;
"With overlay/pair yes, BPM bond styles require a value of 1.0 for all "
"special_bonds weights");
if (id_fix_update_special_bonds) {
modify->delete_fix(id_fix_update_special_bonds);
delete[] id_fix_update_special_bonds;
id_fix_update_special_bonds = nullptr;
}
} else {
// Require atoms know about all of their bonds and if they break
if (force->newton_bond && break_flag)
error->all(FLERR, "With overlay/pair no, or break yes, BPM bond styles require Newton bond off");
error->all(FLERR,
"With overlay/pair no, or break yes, BPM bond styles require Newton bond off");
// special lj must be 0 1 1 to censor pair forces between bonded particles
if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0)
@ -136,23 +138,27 @@ void BondBPM::init_style()
"With overlay/pair no, BPM bond styles require special LJ weights = 0,1,1");
// if bonds can break, 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 (break_flag && (force->special_coul[1] != 1.0 || force->special_coul[2] != 1.0 ||
force->special_coul[3] != 1.0))
if (break_flag &&
(force->special_coul[1] != 1.0 || force->special_coul[2] != 1.0 ||
force->special_coul[3] != 1.0))
error->all(FLERR,
"With overlay/pair no, and break yes, BPM bond styles requires special Coulomb weights = 1,1,1");
"With overlay/pair no, and break yes, BPM bond styles requires special Coulomb "
"weights = 1,1,1");
if (id_fix_dummy && break_flag) {
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 (id_fix_dummy_special && break_flag) {
id_fix_update_special_bonds = utils::strdup("BPM_UPDATE_SPECIAL_BONDS");
auto newfix = modify->replace_fix(
id_fix_dummy_special,
fmt::format("{} all UPDATE_SPECIAL_BONDS", id_fix_update_special_bonds), 1);
fix_update_special_bonds = dynamic_cast<FixUpdateSpecialBonds *>(newfix);
delete[] id_fix_dummy_special;
id_fix_dummy_special = nullptr;
}
}
// 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)
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");
}
@ -170,6 +176,17 @@ void BondBPM::init_style()
hybrid_flag = 0;
for (int i = 1; i <= atom->nbondtypes; i++)
if (!setflag[i]) hybrid_flag = 1;
// Set up necessary history fix
if (!fix_bond_history) {
auto newfix = modify->replace_fix(
id_fix_dummy_history,
fmt::format("{} all BOND_HISTORY {} {}", id_fix_bond_history, update_flag, nhistory), 1);
fix_bond_history = dynamic_cast<FixBondHistory *>(newfix);
delete[] id_fix_dummy_history;
id_fix_dummy_history = nullptr;
}
fix_bond_history->setflag = setflag;
}
@ -208,20 +225,21 @@ void BondBPM::settings(int narg, char **arg)
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;
property_atom_flag = 1;
} else if (strcmp(arg[iarg], "y/ref") == 0) {
pack_choice[nvalues++] = &BondBPM::pack_y_ref;
prop_atom_flag = 1;
property_atom_flag = 1;
} else if (strcmp(arg[iarg], "z/ref") == 0) {
pack_choice[nvalues++] = &BondBPM::pack_z_ref;
prop_atom_flag = 1;
property_atom_flag = 1;
} else {
break;
}
iarg++;
}
} else if (strcmp(arg[iarg], "overlay/pair") == 0) {
if (iarg + 1 > narg) error->all(FLERR, "Illegal bond bpm command, missing option for overlay/pair");
if (iarg + 1 > narg)
error->all(FLERR, "Illegal bond bpm command, missing option for overlay/pair");
overlay_flag = utils::logical(FLERR, arg[iarg + 1], false, lmp);
iarg += 2;
} else if (strcmp(arg[iarg], "break") == 0) {
@ -249,17 +267,17 @@ void BondBPM::settings(int narg, char **arg)
// 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) {
if (property_atom_flag == 1) {
id_fix_prop_atom = utils::strdup("BPM_property_atom");
id_fix_property_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);
ifix = modify->get_fix_by_id(id_fix_property_atom);
if (!ifix)
ifix = modify->add_fix(fmt::format("{} all property/atom d_{} d_{} d_{} ghost yes",
id_fix_prop_atom, x_ref_id, y_ref_id, z_ref_id));
id_fix_property_atom, x_ref_id, y_ref_id, z_ref_id));
int type_flag;
int col_flag;
@ -290,10 +308,12 @@ void BondBPM::settings(int narg, char **arg)
// Set up necessary history fix
if (!fix_bond_history) {
fix_bond_history = dynamic_cast<FixBondHistory *>(modify->replace_fix(
id_fix_dummy2, fmt::format("{} all BOND_HISTORY {} {}", id_fix_bond_history, update_flag, nhistory), 1));
delete[] id_fix_dummy2;
id_fix_dummy2 = nullptr;
auto newfix = modify->replace_fix(
id_fix_dummy_history,
fmt::format("{} all BOND_HISTORY {} {}", id_fix_bond_history, update_flag, nhistory), 1);
fix_bond_history = dynamic_cast<FixBondHistory *>(newfix);
delete[] id_fix_dummy_history;
id_fix_dummy_history = nullptr;
}
}
@ -376,8 +396,7 @@ void BondBPM::read_restart(FILE *fp)
void BondBPM::process_broken(int i, int j)
{
if (!break_flag)
error->one(FLERR, "BPM bond broke with break no option");
if (!break_flag) error->one(FLERR, "BPM bond broke with break no option");
int nlocal = atom->nlocal;
if (fix_store_local) {
@ -415,8 +434,8 @@ void BondBPM::process_broken(int i, int j)
n = num_bond[i];
bond_type[i][m] = bond_type[i][n - 1];
bond_atom[i][m] = bond_atom[i][n - 1];
for (auto &ihistory: histories) {
auto fix_bond_history2 = dynamic_cast<FixBondHistory *> (ihistory);
for (auto &ihistory : histories) {
auto fix_bond_history2 = dynamic_cast<FixBondHistory *>(ihistory);
fix_bond_history2->shift_history(i, m, n - 1);
fix_bond_history2->delete_history(i, n - 1);
}
@ -432,8 +451,8 @@ void BondBPM::process_broken(int i, int j)
n = num_bond[j];
bond_type[j][m] = bond_type[j][n - 1];
bond_atom[j][m] = bond_atom[j][n - 1];
for (auto &ihistory: histories) {
auto fix_bond_history2 = dynamic_cast<FixBondHistory *> (ihistory);
for (auto &ihistory : histories) {
auto fix_bond_history2 = dynamic_cast<FixBondHistory *>(ihistory);
fix_bond_history2->shift_history(j, m, n - 1);
fix_bond_history2->delete_history(j, n - 1);
}

View File

@ -42,9 +42,9 @@ class BondBPM : public Bond {
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;
char *id_fix_dummy_special, *id_fix_dummy_history;
char *id_fix_update_special_bonds, *id_fix_bond_history;
char *id_fix_store_local, *id_fix_property_atom;
class FixStoreLocal *fix_store_local;
class FixBondHistory *fix_bond_history;
class FixUpdateSpecialBonds *fix_update_special_bonds;
@ -54,7 +54,7 @@ class BondBPM : public Bond {
FnPtrPack *pack_choice; // ptrs to pack functions
double *output_data;
int prop_atom_flag, nvalues, overlay_flag, break_flag, ignore_special_flag;
int property_atom_flag, nvalues, overlay_flag, break_flag, ignore_special_flag;
int index_x_ref, index_y_ref, index_z_ref;
int n_histories;

View File

@ -51,6 +51,7 @@ BondBPMRotational::BondBPMRotational(LAMMPS *_lmp) :
partial_flag = 1;
smooth_flag = 1;
normalize_flag = 0;
writedata = 0;
nhistory = 4;
id_fix_bond_history = utils::strdup("HISTORY_BPM_ROTATIONAL");

View File

@ -33,17 +33,25 @@ using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
BondBPMSpring::BondBPMSpring(LAMMPS *_lmp) :
BondBPM(_lmp), k(nullptr), ecrit(nullptr), gamma(nullptr)
BondBPM(_lmp), k(nullptr), av(nullptr), ecrit(nullptr), gamma(nullptr),
id_fix_property_bond(nullptr), vol_current(nullptr), dvol0(nullptr)
{
partial_flag = 1;
smooth_flag = 1;
normalize_flag = 0;
volume_flag = 0;
writedata = 0;
nhistory = 1;
id_fix_bond_history = utils::strdup("HISTORY_BPM_SPRING");
single_extra = 1;
svector = new double[1];
nmax = 0;
comm_forward = 0;
comm_reverse = 0;
}
/* ---------------------------------------------------------------------- */
@ -51,13 +59,20 @@ BondBPMSpring::BondBPMSpring(LAMMPS *_lmp) :
BondBPMSpring::~BondBPMSpring()
{
delete[] svector;
if (id_fix_property_bond && modify->nfix) {
modify->delete_fix(id_fix_property_bond);
delete[] id_fix_property_bond;
}
if (allocated) {
memory->destroy(setflag);
memory->destroy(k);
memory->destroy(ecrit);
memory->destroy(gamma);
memory->destroy(av);
}
memory->destroy(dvol0);
}
/* ----------------------------------------------------------------------
@ -134,18 +149,56 @@ void BondBPMSpring::store_data()
void BondBPMSpring::compute(int eflag, int vflag)
{
if (hybrid_flag) fix_bond_history->compress_history();
int i, bond_change_flag;
double *vol0, *vol;
if (volume_flag) {
vol0 = atom->dvector[index_vol0];
vol = atom->dvector[index_vol];
// grow + initialize dvol0 as necessary
if (nmax < atom->nmax) {
nmax = atom->nmax;
memory->create(dvol0, nmax, "bond/bpm/spring:dvol0");
for (i = 0; i < nmax; i++) dvol0[i] = 0.0;
}
}
if (!fix_bond_history->stored_flag) {
fix_bond_history->stored_flag = true;
store_data();
if (volume_flag) {
vol_current = vol0;
bond_change_flag = calculate_vol();
// zero dvol0, not needed since vol0 just calculated
for (i = 0; i < nmax; i++) dvol0[i] = 0.0;
}
}
if (hybrid_flag)
fix_bond_history->compress_history();
if (volume_flag) {
vol_current = vol;
bond_change_flag = calculate_vol();
// Update vol0 to account for any new bonds
if (bond_change_flag) {
update_vol0();
// forward new vol0 to ghosts before force calculation
vol_current = vol0;
comm->forward_comm(this);
bond_change_flag = 0;
}
}
int i1, i2, itmp, n, type;
double delx, dely, delz, delvx, delvy, delvz;
double e, rsq, r, r0, rinv, smooth, fbond, dot;
double vol_sum, vol0_sum, vol_temp;
ev_init(eflag, vflag);
@ -157,6 +210,8 @@ void BondBPMSpring::compute(int eflag, int vflag)
int nbondlist = neighbor->nbondlist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
double dim = domain->dimension;
double invdim = 1.0 / dim;
double **bondstore = fix_bond_history->bondstore;
@ -193,6 +248,15 @@ void BondBPMSpring::compute(int eflag, int vflag)
if (fabs(e) > ecrit[type]) {
bondlist[n][2] = 0;
process_broken(i1, i2);
if (volume_flag) {
bond_change_flag = 1;
vol_temp = r0 * r0;
if (dim == 3) vol_temp *= r0;
if (newton_bond || i1 < nlocal) dvol0[i1] -= vol_temp;
if (newton_bond || i2 < nlocal) dvol0[i2] -= vol_temp;
}
continue;
}
@ -202,6 +266,12 @@ void BondBPMSpring::compute(int eflag, int vflag)
else
fbond = k[type] * (r0 - r);
if (volume_flag) {
vol_sum = vol[i1] + vol[i2];
vol0_sum = vol0[i1] + vol0[i2];
fbond += av[type] * (pow(vol_sum / vol0_sum, invdim) - 1.0 - e);
}
delvx = v[i1][0] - v[i2][0];
delvy = v[i1][1] - v[i2][1];
delvz = v[i1][2] - v[i2][2];
@ -233,8 +303,77 @@ void BondBPMSpring::compute(int eflag, int vflag)
if (evflag) ev_tally(i1, i2, nlocal, newton_bond, 0.0, fbond, delx, dely, delz);
}
if (hybrid_flag)
fix_bond_history->uncompress_history();
// Update vol0 to account for any broken bonds
if (volume_flag && bond_change_flag) update_vol0();
if (hybrid_flag) fix_bond_history->uncompress_history();
}
/* ---------------------------------------------------------------------- */
int BondBPMSpring::calculate_vol()
{
int n, i1, i2;
double r0, delx, dely, delz, rsq, vol_temp;
int nlocal = atom->nlocal;
int ntotal = nlocal + atom->nghost;
int newton_bond = force->newton_bond;
int dim = domain->dimension;
double **x = atom->x;
int **bondlist = neighbor->bondlist;
int nbondlist = neighbor->nbondlist;
double **bondstore = fix_bond_history->bondstore;
for (n = 0; n < ntotal; n++) vol_current[n] = 0.0;
int bond_change_flag = 0;
for (n = 0; n < nbondlist; n++) {
if (bondlist[n][2] <= 0) continue;
i1 = bondlist[n][0];
i2 = bondlist[n][1];
r0 = bondstore[n][0];
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;
vol_temp = rsq;
if (dim == 3) vol_temp *= sqrt(rsq);
if (newton_bond || i1 < nlocal) vol_current[i1] += vol_temp;
if (newton_bond || i2 < nlocal) vol_current[i2] += vol_temp;
// If bond hasn't been set - increment dvol0 too to update vol0
if (r0 < EPSILON || std::isnan(r0)) {
bond_change_flag = 1;
if (newton_bond || i1 < nlocal) dvol0[i1] += vol_temp;
if (newton_bond || i2 < nlocal) dvol0[i2] += vol_temp;
}
}
if (newton_bond) comm->reverse_comm(this);
comm->forward_comm(this);
return bond_change_flag;
}
/* ---------------------------------------------------------------------- */
void BondBPMSpring::update_vol0()
{
// accumulate changes in vol0 from ghosts
vol_current = dvol0;
if (force->newton_bond) comm->reverse_comm(this);
double *vol0 = atom->dvector[index_vol0];
for (int i = 0; i < atom->nlocal; i++) vol0[i] += dvol0[i];
// zero dvol0 for next change
for (int i = 0; i < nmax; i++) dvol0[i] = 0.0;
}
/* ---------------------------------------------------------------------- */
@ -247,6 +386,7 @@ void BondBPMSpring::allocate()
memory->create(k, np1, "bond:k");
memory->create(ecrit, np1, "bond:ecrit");
memory->create(gamma, np1, "bond:gamma");
memory->create(av, np1, "bond:av");
memory->create(setflag, np1, "bond:setflag");
for (int i = 1; i < np1; i++) setflag[i] = 0;
@ -258,7 +398,8 @@ void BondBPMSpring::allocate()
void BondBPMSpring::coeff(int narg, char **arg)
{
if (narg != 4) error->all(FLERR, "Incorrect args for bond coefficients");
if ((!volume_flag && narg != 4) || (volume_flag && narg != 5))
error->all(FLERR, "Incorrect args for bond coefficients");
if (!allocated) allocate();
int ilo, ihi;
@ -268,11 +409,15 @@ void BondBPMSpring::coeff(int narg, char **arg)
double ecrit_one = utils::numeric(FLERR, arg[2], false, lmp);
double gamma_one = utils::numeric(FLERR, arg[3], false, lmp);
double av_one = 0.0;
if (volume_flag) av_one = utils::numeric(FLERR, arg[4], false, lmp);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
k[i] = k_one;
ecrit[i] = ecrit_one;
gamma[i] = gamma_one;
av[i] = av_one;
setflag[i] = 1;
count++;
@ -292,6 +437,16 @@ void BondBPMSpring::init_style()
if (comm->ghost_velocity == 0)
error->all(FLERR, "Bond bpm/spring requires ghost atoms store velocity");
if (volume_flag && !id_fix_property_bond) {
id_fix_property_bond = utils::strdup("BOND_BPM_SPRING_FIX_PROPERTY_ATOM");
modify->add_fix(fmt::format("{} all property/atom d_vol d_vol0 ghost yes writedata no",
id_fix_property_bond));
int tmp1 = 0, tmp2 = 0;
index_vol = atom->find_custom("vol", tmp1, tmp2);
index_vol0 = atom->find_custom("vol0", tmp1, tmp2);
}
}
/* ---------------------------------------------------------------------- */
@ -308,8 +463,23 @@ void BondBPMSpring::settings(int narg, char **arg)
smooth_flag = utils::logical(FLERR, arg[iarg + 1], false, lmp);
i += 1;
} else if (strcmp(arg[iarg], "normalize") == 0) {
if (iarg + 1 > narg) error->all(FLERR, "Illegal bond bpm command, missing option for normalize");
if (iarg + 1 > narg)
error->all(FLERR, "Illegal bond bpm command, missing option for normalize");
normalize_flag = utils::logical(FLERR, arg[iarg + 1], false, lmp);
i += 1;
} else if (strcmp(arg[iarg], "volume/factor") == 0) {
if (iarg + 1 > narg)
error->all(FLERR, "Illegal bond bpm command, missing option for volume/factor");
volume_flag = utils::logical(FLERR, arg[iarg + 1], false, lmp);
if (volume_flag) {
comm_forward = 1;
comm_reverse = 1;
} else {
comm_forward = 0;
comm_reverse = 0;
}
i += 1;
} else {
error->all(FLERR, "Illegal bond bpm command, invalid argument {}", arg[iarg]);
@ -329,6 +499,7 @@ 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);
fwrite(&av[1], sizeof(double), atom->nbondtypes, fp);
}
/* ----------------------------------------------------------------------
@ -345,10 +516,12 @@ void BondBPMSpring::read_restart(FILE *fp)
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);
utils::sfread(FLERR, &av[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);
MPI_Bcast(&av[1], atom->nbondtypes, MPI_DOUBLE, 0, world);
for (int i = 1; i <= atom->nbondtypes; i++) setflag[i] = 1;
}
@ -360,6 +533,8 @@ void BondBPMSpring::read_restart(FILE *fp)
void BondBPMSpring::write_restart_settings(FILE *fp)
{
fwrite(&smooth_flag, sizeof(int), 1, fp);
fwrite(&normalize_flag, sizeof(int), 1, fp);
fwrite(&volume_flag, sizeof(int), 1, fp);
}
/* ----------------------------------------------------------------------
@ -368,8 +543,14 @@ void BondBPMSpring::write_restart_settings(FILE *fp)
void BondBPMSpring::read_restart_settings(FILE *fp)
{
if (comm->me == 0) utils::sfread(FLERR, &smooth_flag, sizeof(int), 1, fp, nullptr, error);
if (comm->me == 0) {
utils::sfread(FLERR, &smooth_flag, sizeof(int), 1, fp, nullptr, error);
utils::sfread(FLERR, &normalize_flag, sizeof(int), 1, fp, nullptr, error);
utils::sfread(FLERR, &volume_flag, sizeof(int), 1, fp, nullptr, error);
}
MPI_Bcast(&smooth_flag, 1, MPI_INT, 0, world);
MPI_Bcast(&normalize_flag, 1, MPI_INT, 0, world);
MPI_Bcast(&volume_flag, 1, MPI_INT, 0, world);
}
/* ---------------------------------------------------------------------- */
@ -385,12 +566,22 @@ double BondBPMSpring::single(int type, double rsq, int i, int j, double &fforce)
double r = sqrt(rsq);
double rinv = 1.0 / r;
double e = (r - r0) / r0;
if (normalize_flag)
fforce = k[type] * (r0 - r) / r0;
fforce = -k[type] * e;
else
fforce = k[type] * (r0 - r);
if (volume_flag) {
double invdim = 1.0 / domain->dimension;
double *vol0 = atom->dvector[index_vol0];
double *vol = atom->dvector[index_vol];
double vol_sum = vol[i] + vol[j];
double vol0_sum = vol0[i] + vol0[j];
fforce += av[type] * (pow(vol_sum / vol0_sum, invdim) - 1.0 - e);
}
double **x = atom->x;
double **v = atom->v;
double delx = x[i][0] - x[j][0];
@ -418,3 +609,49 @@ double BondBPMSpring::single(int type, double rsq, int i, int j, double &fforce)
return 0.0;
}
/* ---------------------------------------------------------------------- */
int BondBPMSpring::pack_reverse_comm(int n, int first, double *buf)
{
int i, m, last;
m = 0;
last = first + n;
for (i = first; i < last; i++) buf[m++] = vol_current[i];
return m;
}
/* ---------------------------------------------------------------------- */
void BondBPMSpring::unpack_reverse_comm(int n, int *list, double *buf)
{
int i, j, m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
vol_current[j] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int BondBPMSpring::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/)
{
int i, j, m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = vol_current[j];
}
return m;
}
/* ---------------------------------------------------------------------- */
void BondBPMSpring::unpack_forward_comm(int n, int first, double *buf)
{
int i, m, last;
m = 0;
last = first + n;
for (i = first; i < last; i++) vol_current[i] = buf[m++];
}

View File

@ -37,14 +37,24 @@ class BondBPMSpring : public BondBPM {
void write_restart_settings(FILE *) override;
void read_restart_settings(FILE *) override;
double single(int, double, int, int, double &) 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;
protected:
double *k, *ecrit, *gamma;
int smooth_flag, normalize_flag;
double *k, *av, *ecrit, *gamma;
int smooth_flag, normalize_flag, volume_flag;
int index_vol, index_vol0, nmax;
char *id_fix_property_bond;
double *vol_current, *dvol0;
void allocate();
void store_data();
double store_bond(int, int, int);
int calculate_vol();
void update_vol0();
};
} // namespace LAMMPS_NS

View File

@ -27,9 +27,10 @@ using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
PairBPMSpring::PairBPMSpring(LAMMPS *_lmp) : Pair(_lmp), k(nullptr), cut(nullptr), gamma(nullptr)
PairBPMSpring::PairBPMSpring(LAMMPS *_lmp) : Pair(_lmp), k(nullptr), ka(nullptr), cut(nullptr), gamma(nullptr)
{
writedata = 1;
anharmonic_flag = 0;
}
/* ---------------------------------------------------------------------- */
@ -41,6 +42,7 @@ PairBPMSpring::~PairBPMSpring()
memory->destroy(cutsq);
memory->destroy(k);
memory->destroy(ka);
memory->destroy(cut);
memory->destroy(gamma);
}
@ -51,7 +53,7 @@ PairBPMSpring::~PairBPMSpring()
void PairBPMSpring::compute(int eflag, int vflag)
{
int i, j, ii, jj, inum, jnum, itype, jtype;
double xtmp, ytmp, ztmp, delx, dely, delz, evdwl, fpair;
double xtmp, ytmp, ztmp, delx, dely, delz, dr, evdwl, fpair;
double r, rsq, rinv, factor_lj;
int *ilist, *jlist, *numneigh, **firstneigh;
double vxtmp, vytmp, vztmp, delvx, delvy, delvz, dot, smooth;
@ -107,7 +109,11 @@ void PairBPMSpring::compute(int eflag, int vflag)
r = sqrt(rsq);
rinv = 1.0 / r;
fpair = k[itype][jtype] * (cut[itype][jtype] - r);
dr = r - cut[itype][jtype];
fpair = -k[itype][jtype] * dr;
if (anharmonic_flag)
fpair += -ka[itype][jtype] * dr * dr * dr;
smooth = rsq / cutsq[itype][jtype];
smooth *= smooth;
@ -156,6 +162,7 @@ void PairBPMSpring::allocate()
memory->create(cutsq, np1, np1, "pair:cutsq");
memory->create(k, np1, np1, "pair:k");
memory->create(ka, np1, np1, "pair:ka");
memory->create(cut, np1, np1, "pair:cut");
memory->create(gamma, np1, np1, "pair:gamma");
}
@ -164,9 +171,17 @@ void PairBPMSpring::allocate()
global settings
------------------------------------------------------------------------- */
void PairBPMSpring::settings(int narg, char ** /*arg*/)
void PairBPMSpring::settings(int narg, char ** arg)
{
if (narg != 0) error->all(FLERR, "Illegal pair_style command");
int iarg = 0;
while (iarg < narg) {
if (strcmp(arg[iarg], "anharmonic") == 0) {
if (iarg + 1 >= narg)
utils::missing_cmd_args(FLERR, "pair_coeff bpm/spring anharmonic", error);
anharmonic_flag = utils::logical(FLERR, arg[iarg + 1], false, lmp);
iarg += 2;
} else error->all(FLERR, "Illegal pair_style command {}", arg[iarg]);
}
}
/* ----------------------------------------------------------------------
@ -175,7 +190,8 @@ void PairBPMSpring::settings(int narg, char ** /*arg*/)
void PairBPMSpring::coeff(int narg, char **arg)
{
if (narg != 5) error->all(FLERR, "Incorrect args for pair coefficients");
if ((!anharmonic_flag && narg != 5) || (anharmonic_flag && narg != 6))
error->all(FLERR, "Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo, ihi, jlo, jhi;
@ -186,6 +202,10 @@ void PairBPMSpring::coeff(int narg, char **arg)
double cut_one = utils::numeric(FLERR, arg[3], false, lmp);
double gamma_one = utils::numeric(FLERR, arg[4], false, lmp);
double ka_one = 0.0;
if (anharmonic_flag)
ka_one = utils::numeric(FLERR, arg[5], false, lmp);
if (cut_one <= 0.0) error->all(FLERR, "Incorrect args for pair coefficients");
int count = 0;
@ -194,6 +214,7 @@ void PairBPMSpring::coeff(int narg, char **arg)
k[i][j] = k_one;
cut[i][j] = cut_one;
gamma[i][j] = gamma_one;
ka[i][j] = ka_one;
setflag[i][j] = 1;
count++;
@ -230,6 +251,7 @@ double PairBPMSpring::init_one(int i, int j)
cut[j][i] = cut[i][j];
k[j][i] = k[i][j];
gamma[j][i] = gamma[i][j];
ka[j][i] = ka[i][j];
return cut[i][j];
}
@ -250,6 +272,7 @@ void PairBPMSpring::write_restart(FILE *fp)
fwrite(&k[i][j], sizeof(double), 1, fp);
fwrite(&cut[i][j], sizeof(double), 1, fp);
fwrite(&gamma[i][j], sizeof(double), 1, fp);
fwrite(&ka[i][j], sizeof(double), 1, fp);
}
}
}
@ -274,22 +297,50 @@ void PairBPMSpring::read_restart(FILE *fp)
utils::sfread(FLERR, &k[i][j], sizeof(double), 1, fp, nullptr, error);
utils::sfread(FLERR, &cut[i][j], sizeof(double), 1, fp, nullptr, error);
utils::sfread(FLERR, &gamma[i][j], sizeof(double), 1, fp, nullptr, error);
utils::sfread(FLERR, &ka[i][j], sizeof(double), 1, fp, nullptr, error);
}
MPI_Bcast(&k[i][j], 1, MPI_DOUBLE, 0, world);
MPI_Bcast(&cut[i][j], 1, MPI_DOUBLE, 0, world);
MPI_Bcast(&gamma[i][j], 1, MPI_DOUBLE, 0, world);
MPI_Bcast(&ka[i][j], 1, MPI_DOUBLE, 0, world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBPMSpring::write_restart_settings(FILE *fp)
{
fwrite(&anharmonic_flag, sizeof(int), 1, fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBPMSpring::read_restart_settings(FILE *fp)
{
if (comm->me == 0)
utils::sfread(FLERR, &anharmonic_flag, sizeof(int), 1, fp, nullptr, error);
MPI_Bcast(&anharmonic_flag, 1, MPI_INT, 0, world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairBPMSpring::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp, "%d %g %g %g\n", i, k[i][i], cut[i][i], gamma[i][i]);
if (anharmonic_flag) {
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp, "%d %g %g %g %g\n", i, k[i][i], cut[i][i], gamma[i][i], ka[i][i]);
} else {
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp, "%d %g %g %g\n", i, k[i][i], cut[i][i], gamma[i][i]);
}
}
/* ----------------------------------------------------------------------
@ -298,9 +349,15 @@ void PairBPMSpring::write_data(FILE *fp)
void PairBPMSpring::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp, "%d %d %g %g %g\n", i, j, k[i][j], cut[i][j], gamma[i][j]);
if (anharmonic_flag) {
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp, "%d %d %g %g %g %g\n", i, j, k[i][j], cut[i][j], gamma[i][j], ka[i][j]);
} else {
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp, "%d %d %g %g %g\n", i, j, k[i][j], cut[i][j], gamma[i][j]);
}
}
/* ---------------------------------------------------------------------- */
@ -308,7 +365,7 @@ void PairBPMSpring::write_data_all(FILE *fp)
double PairBPMSpring::single(int i, int j, int itype, int jtype, double rsq, double /*factor_coul*/,
double factor_lj, double &fforce)
{
double fpair, r, rinv;
double fpair, r, rinv, dr;
double delx, dely, delz, delvx, delvy, delvz, dot, smooth;
if (rsq > cutsq[itype][jtype]) return 0.0;
@ -319,7 +376,10 @@ double PairBPMSpring::single(int i, int j, int itype, int jtype, double rsq, dou
r = sqrt(rsq);
rinv = 1.0 / r;
fpair = k[itype][jtype] * (cut[itype][jtype] - r);
dr = r - cut[itype][jtype];
fpair = -k[itype][jtype] * dr;
if (anharmonic_flag)
fpair += -ka[itype][jtype] * dr * dr * dr;
smooth = rsq / cutsq[itype][jtype];
smooth *= smooth;

View File

@ -29,18 +29,21 @@ class PairBPMSpring : public Pair {
PairBPMSpring(class LAMMPS *);
~PairBPMSpring() override;
void compute(int, int) override;
void settings(int, char **) override;
void coeff(int, char **) override;
void settings(int, char **) override;
void init_style() override;
double init_one(int, int) override;
void write_restart(FILE *) override;
void read_restart(FILE *) override;
void write_restart_settings(FILE *) override;
void read_restart_settings(FILE *) override;
void write_data(FILE *) override;
void write_data_all(FILE *) override;
double single(int, int, int, int, double, double, double, double &) override;
protected:
double **k, **cut, **gamma;
int anharmonic_flag;
double **k, **ka, **cut, **gamma;
void allocate();
};

View File

@ -825,16 +825,16 @@ Fix *Modify::add_fix(int narg, char **arg, int trysuffix)
// clang-format off
const char *exceptions[] =
{"GPU", "OMP", "INTEL", "property/atom", "cmap", "cmap3", "rx",
"deprecated", "STORE/KIM", "amoeba/pitorsion", "amoeba/bitorsion",
nullptr};
{"GPU", "OMP", "INTEL", "property/atom", "cmap", "cmap3", "rx", "deprecated", "STORE/KIM",
"amoeba/pitorsion", "amoeba/bitorsion", "DUMMY", nullptr};
// clang-format on
if (domain->box_exist == 0) {
int m;
for (m = 0; exceptions[m] != nullptr; m++)
if (strcmp(arg[2], exceptions[m]) == 0) break;
if (exceptions[m] == nullptr) error->all(FLERR, "Fix command before simulation box is defined");
if (exceptions[m] == nullptr)
error->all(FLERR, "Fix {} command before simulation box is defined", arg[2]);
}
// check group ID