992 lines
35 KiB
C++
992 lines
35 KiB
C++
// clang-format off
|
|
/* ----------------------------------------------------------------------
|
|
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 author: Joel Clemmer (SNL)
|
|
------------------------------------------------------------------------- */
|
|
|
|
#include "fix_deform_pressure.h"
|
|
|
|
#include "comm.h"
|
|
#include "compute.h"
|
|
#include "domain.h"
|
|
#include "error.h"
|
|
#include "group.h"
|
|
#include "input.h"
|
|
#include "irregular.h"
|
|
#include "math_const.h"
|
|
#include "modify.h"
|
|
#include "update.h"
|
|
#include "variable.h"
|
|
|
|
#include <cmath>
|
|
#include <cstring>
|
|
|
|
using namespace LAMMPS_NS;
|
|
using namespace FixConst;
|
|
using namespace MathConst;
|
|
|
|
enum { NOCOUPLE = 0, XYZ, XY, YZ, XZ };
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
FixDeformPressure::FixDeformPressure(LAMMPS *lmp, int narg, char **arg) :
|
|
FixDeform(lmp, narg, arg), id_temp(nullptr), id_press(nullptr), temperature(nullptr),
|
|
pressure(nullptr)
|
|
{
|
|
// set defaults
|
|
|
|
set_extra = new SetExtra[7];
|
|
memset(set_extra, 0, 7 * sizeof(SetExtra));
|
|
memset(&set_box, 0, sizeof(Set));
|
|
|
|
// parse only parameter/style arguments specific to this child class
|
|
|
|
int index, iarg;
|
|
std::size_t i = 0;
|
|
while (i < leftover_iarg.size()) {
|
|
iarg = leftover_iarg[i];
|
|
if (strcmp(arg[iarg], "x") == 0 ||
|
|
strcmp(arg[iarg], "y") == 0 ||
|
|
strcmp(arg[iarg], "z") == 0) {
|
|
|
|
if (strcmp(arg[iarg], "x") == 0) index = 0;
|
|
else if (strcmp(arg[iarg], "y") == 0) index = 1;
|
|
else if (strcmp(arg[iarg], "z") == 0) index = 2;
|
|
|
|
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure", error);
|
|
if (strcmp(arg[iarg + 1], "pressure") == 0) {
|
|
if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure pressure", error);
|
|
set[index].style = PRESSURE;
|
|
if (strstr(arg[iarg + 2], "v_") != arg[iarg + 2]) {
|
|
set_extra[index].ptarget = utils::numeric(FLERR, arg[iarg + 2], false, lmp);
|
|
} else {
|
|
set_extra[index].pstr = utils::strdup(&arg[iarg + 2][2]);
|
|
set_extra[index].pvar_flag = 1;
|
|
}
|
|
set_extra[index].pgain = utils::numeric(FLERR, arg[iarg + 3], false, lmp);
|
|
i += 4;
|
|
} else if (strcmp(arg[iarg + 1], "pressure/mean") == 0) {
|
|
if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure pressure/mean", error);
|
|
set[index].style = PMEAN;
|
|
if (strstr(arg[iarg + 2], "v_") != arg[iarg + 2]) {
|
|
set_extra[index].ptarget = utils::numeric(FLERR, arg[iarg + 2], false, lmp);
|
|
} else {
|
|
set_extra[index].pstr = utils::strdup(&arg[iarg + 2][2]);
|
|
set_extra[index].pvar_flag = 1;
|
|
}
|
|
set_extra[index].pgain = utils::numeric(FLERR, arg[iarg + 3], false, lmp);
|
|
i += 4;
|
|
} else error->all(FLERR, "Illegal fix deform/pressure command argument: {}", arg[iarg + 1]);
|
|
|
|
} else if (strcmp(arg[iarg], "xy") == 0 ||
|
|
strcmp(arg[iarg], "xz") == 0 ||
|
|
strcmp(arg[iarg], "yz") == 0) {
|
|
|
|
if (strcmp(arg[iarg], "xy") == 0) index = 5;
|
|
else if (strcmp(arg[iarg], "xz") == 0) index = 4;
|
|
else if (strcmp(arg[iarg], "yz") == 0) index = 3;
|
|
|
|
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure", error);
|
|
if (strcmp(arg[iarg + 1], "pressure") == 0) {
|
|
if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure pressure", error);
|
|
set[index].style = PRESSURE;
|
|
if (strstr(arg[iarg + 2], "v_") != arg[iarg + 2]) {
|
|
set_extra[index].ptarget = utils::numeric(FLERR, arg[iarg + 2], false, lmp);
|
|
} else {
|
|
set_extra[index].pstr = utils::strdup(&arg[iarg + 2][2]);
|
|
set_extra[index].pvar_flag = 1;
|
|
}
|
|
set_extra[index].pgain = utils::numeric(FLERR, arg[iarg + 3], false, lmp);
|
|
i += 4;
|
|
} else if (strcmp(arg[iarg + 1], "erate/rescale") == 0) {
|
|
if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure erate/rescale", error);
|
|
set[index].style = ERATERS;
|
|
set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp);
|
|
iarg += 3;
|
|
i += 3;
|
|
} else error->all(FLERR, "Illegal fix deform/pressure command: {}", arg[iarg + 1]);
|
|
|
|
} else if (strcmp(arg[iarg], "box") == 0) {
|
|
if (strcmp(arg[iarg + 1], "volume") == 0) {
|
|
set_box.style = VOLUME;
|
|
i += 2;
|
|
} else if (strcmp(arg[iarg + 1], "pressure") == 0) {
|
|
if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure pressure", error);
|
|
set_box.style = PRESSURE;
|
|
if (strstr(arg[iarg + 2], "v_") != arg[iarg + 2]) {
|
|
set_extra[6].ptarget = utils::numeric(FLERR, arg[iarg + 2], false, lmp);
|
|
} else {
|
|
set_extra[6].pstr = utils::strdup(&arg[iarg + 2][2]);
|
|
set_extra[6].pvar_flag = 1;
|
|
}
|
|
set_extra[6].pgain = utils::numeric(FLERR, arg[iarg + 3], false, lmp);
|
|
i += 4;
|
|
} else error->all(FLERR, "Illegal fix deform/pressure command argument: {}", arg[iarg + 1]);
|
|
} else break;
|
|
}
|
|
|
|
// read options from end of input line
|
|
// shift arguments before reading
|
|
|
|
iarg = iarg_options_start;
|
|
options(i, narg - iarg, &arg[iarg]);
|
|
|
|
// repeat: setup dimflags used by other classes to check for volume-change conflicts
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
if (set[i].style == NONE) dimflag[i] = 0;
|
|
else dimflag[i] = 1;
|
|
|
|
if (set_box.style != NONE) {
|
|
dimflag[0] = 1;
|
|
dimflag[1] = 1;
|
|
dimflag[2] = 1;
|
|
}
|
|
|
|
if (dimflag[0]) box_change |= BOX_CHANGE_X;
|
|
if (dimflag[1]) box_change |= BOX_CHANGE_Y;
|
|
if (dimflag[2]) box_change |= BOX_CHANGE_Z;
|
|
if (dimflag[3]) box_change |= BOX_CHANGE_YZ;
|
|
if (dimflag[4]) box_change |= BOX_CHANGE_XZ;
|
|
if (dimflag[5]) box_change |= BOX_CHANGE_XY;
|
|
|
|
// repeat: no tensile deformation on shrink-wrapped dims
|
|
// b/c shrink wrap will change box-length
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
if (set_box.style && (domain->boundary[i][0] >= 2 || domain->boundary[i][1] >= 2))
|
|
error->all(FLERR, "Cannot use fix deform/pressure on a shrink-wrapped boundary");
|
|
|
|
// repeat: no tilt deformation on shrink-wrapped 2nd dim
|
|
// b/c shrink wrap will change tilt factor in domain::reset_box()
|
|
|
|
if (set[3].style && (domain->boundary[2][0] >= 2 || domain->boundary[2][1] >= 2))
|
|
error->all(FLERR, "Cannot use fix deform/pressure tilt on a shrink-wrapped 2nd dim");
|
|
if (set[4].style && (domain->boundary[2][0] >= 2 || domain->boundary[2][1] >= 2))
|
|
error->all(FLERR, "Cannot use fix deform/pressure tilt on a shrink-wrapped 2nd dim");
|
|
if (set[5].style && (domain->boundary[1][0] >= 2 || domain->boundary[1][1] >= 2))
|
|
error->all(FLERR, "Cannot use fix deform/pressure tilt on a shrink-wrapped 2nd dim");
|
|
|
|
// for VOLUME, setup links to other dims
|
|
// fixed, dynamic1, dynamic2
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
if (set[i].style != VOLUME) continue;
|
|
int other1 = (i + 1) % 3;
|
|
int other2 = (i + 2) % 3;
|
|
|
|
// Cannot use VOLUME option without at least one deformed dimension
|
|
if (set[other1].style == NONE || set[other1].style == VOLUME)
|
|
if (set[other2].style == NONE || set[other2].style == VOLUME)
|
|
error->all(FLERR, "Fix {} volume setting is invalid", style);
|
|
|
|
if (set[other1].style == NONE) {
|
|
set[i].substyle = ONE_FROM_ONE;
|
|
set[i].fixed = other1;
|
|
set[i].dynamic1 = other2;
|
|
} else if (set[other2].style == NONE) {
|
|
set[i].substyle = ONE_FROM_ONE;
|
|
set[i].fixed = other2;
|
|
set[i].dynamic1 = other1;
|
|
} else if (set[other1].style == VOLUME) {
|
|
set[i].substyle = TWO_FROM_ONE;
|
|
set[i].fixed = other1;
|
|
set[i].dynamic1 = other2;
|
|
} else if (set[other2].style == VOLUME) {
|
|
set[i].substyle = TWO_FROM_ONE;
|
|
set[i].fixed = other2;
|
|
set[i].dynamic1 = other1;
|
|
} else {
|
|
set[i].substyle = ONE_FROM_TWO;
|
|
set[i].dynamic1 = other1;
|
|
set[i].dynamic2 = other2;
|
|
}
|
|
}
|
|
|
|
// repeat: set varflag
|
|
|
|
for (int i = 0; i < 7; i++)
|
|
if (set_extra[i].pvar_flag) varflag = 1;
|
|
|
|
// repeat: reneighboring only forced if flips can occur due to shape changes
|
|
|
|
if ((!force_reneighbor) && flipflag && (set[3].style || set[4].style || set[5].style)) {
|
|
force_reneighbor = 1;
|
|
irregular = new Irregular(lmp);
|
|
}
|
|
|
|
// set initial values at time fix deform/pressure is issued
|
|
|
|
set_box.vol_initial = domain->xprd * domain->yprd * domain->zprd;
|
|
|
|
// populate coupled pressure controls
|
|
|
|
if (pcouple != NOCOUPLE) {
|
|
|
|
if (domain->dimension == 2)
|
|
if (pcouple == XYZ || pcouple == XZ || pcouple == YZ)
|
|
error->all(FLERR, "Cannot couple Z dimension in fix deform/pressure in 2D");
|
|
|
|
int coupled_indices[3] = {0};
|
|
int j = -1;
|
|
|
|
if (pcouple == XYZ || pcouple == XY || pcouple == XZ)
|
|
coupled_indices[0] = 1;
|
|
if (pcouple == XYZ || pcouple == XY || pcouple == YZ)
|
|
coupled_indices[1] = 1;
|
|
if (pcouple == XYZ || pcouple == XZ || pcouple == YZ)
|
|
coupled_indices[2] = 1;
|
|
|
|
// Check coupled styles and find reference
|
|
for (int i = 0; i < 3; i++) {
|
|
if (coupled_indices[i]) {
|
|
set_extra[i].coupled_flag = 1;
|
|
if (set[i].style != PRESSURE && set[i].style != NONE)
|
|
error->all(FLERR, "Cannot couple non-pressure-controlled dimensions");
|
|
if (set[i].style == PRESSURE)
|
|
j = i;
|
|
}
|
|
}
|
|
|
|
if (j == -1)
|
|
error->all(FLERR, "Must specify deformation style for at least one coupled dimension");
|
|
|
|
// Copy or compare data for each coupled dimension
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
if (coupled_indices[i]) {
|
|
// Copy coupling information if dimension style is undefined
|
|
if (set[i].style == NONE) {
|
|
set[i].style = PRESSURE;
|
|
dimflag[i] = 1;
|
|
set_extra[i].pgain = set_extra[j].pgain;
|
|
if (set_extra[j].pvar_flag) {
|
|
set_extra[i].pstr = set_extra[j].pstr;
|
|
set_extra[i].pvar_flag = 1;
|
|
} else {
|
|
set_extra[i].ptarget = set_extra[j].ptarget;
|
|
}
|
|
} else {
|
|
// Check for incompatibilities in style
|
|
if (set[j].style != set[i].style && set[i].style != NONE)
|
|
error->all(FLERR, "Cannot couple dimensions with different control options");
|
|
if (set[j].style != PRESSURE) continue;
|
|
|
|
// If pressure controlled, check for incompatibilities in parameters
|
|
if (set_extra[i].pgain != set_extra[j].pgain || set_extra[i].pvar_flag != set_extra[j].pvar_flag ||
|
|
set_extra[i].ptarget != set_extra[j].ptarget)
|
|
error->all(FLERR, "Coupled dimensions must have identical gain parameters");
|
|
|
|
if (set_extra[j].pvar_flag)
|
|
if (strcmp(set_extra[i].pstr, set_extra[j].pstr) != 0)
|
|
error->all(FLERR, "Coupled dimensions must have the same target pressure");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if vol/balance/p used, must have 2 free dimensions
|
|
|
|
if (vol_balance_flag) {
|
|
for (int i = 0; i < 3; i++) {
|
|
if (set[i].style != VOLUME) continue;
|
|
if (set[i].substyle != TWO_FROM_ONE)
|
|
error->all(FLERR, "Two dimensions must maintain constant volume to use the vol/balance/p option");
|
|
}
|
|
}
|
|
|
|
// set strain_flag
|
|
|
|
strain_flag = 0;
|
|
for (int i = 0; i < 6; i++)
|
|
if (set[i].style != NONE && set[i].style != VOLUME &&
|
|
set[i].style != PRESSURE && set[i].style != PMEAN)
|
|
strain_flag = 1;
|
|
|
|
// set pressure_flag
|
|
|
|
pressure_flag = 0;
|
|
for (int i = 0; i < 6; i++) {
|
|
if (set[i].style == PRESSURE || set[i].style == PMEAN) {
|
|
pressure_flag = 1;
|
|
if (set_extra[i].pgain <= 0.0)
|
|
error->all(FLERR, "Illegal fix deform/pressure gain constant, must be positive");
|
|
}
|
|
if (set_extra[i].coupled_flag) pressure_flag = 1;
|
|
}
|
|
if (set_box.style == PRESSURE) pressure_flag = 1;
|
|
if (vol_balance_flag) pressure_flag = 1;
|
|
|
|
// check conflict between constant volume/pressure
|
|
|
|
volume_flag = 0;
|
|
for (int i = 0; i < 3; i++)
|
|
if (set[i].style == VOLUME)
|
|
volume_flag = 1;
|
|
|
|
if (volume_flag)
|
|
for (int i = 0; i < 6; i++)
|
|
if (set[i].style == PMEAN)
|
|
error->all(FLERR, "Cannot use fix deform/pressure to assign constant volume and pressure");
|
|
|
|
// check conflicts between x,y,z styles and box
|
|
|
|
if (set_box.style)
|
|
for (int i = 0; i < 3; i++)
|
|
if (set[i].style == FINAL || set[i].style == DELTA || set[i].style == SCALE || set[i].style == PMEAN || set[i].style == VARIABLE)
|
|
error->all(FLERR, "Cannot use fix deform/pressure box parameter with x, y, or z styles other than vel, erate, trate, pressure, and wiggle");
|
|
|
|
// check pressure used for max rate and normalize error flag
|
|
|
|
if (!pressure_flag && max_h_rate != 0)
|
|
error->all(FLERR, "Can only assign a maximum strain rate using pressure-controlled dimensions");
|
|
|
|
if (!pressure_flag && normalize_pressure_flag)
|
|
error->all(FLERR, "Can only normalize error using pressure-controlled dimensions");
|
|
|
|
// Create pressure compute, if needed
|
|
|
|
pflag = 0;
|
|
tflag = 0;
|
|
if (pressure_flag) {
|
|
// create a new compute temp style
|
|
// id = fix-ID + temp
|
|
// compute group = all since pressure is always global (group all)
|
|
// and thus its KE/temperature contribution should use group all
|
|
|
|
id_temp = utils::strdup(std::string(id) + "_temp");
|
|
temperature = modify->add_compute(fmt::format("{} all temp", id_temp));
|
|
tflag = 1;
|
|
|
|
// create a new compute pressure style
|
|
// id = fix-ID + press, compute group = all
|
|
// pass id_temp as 4th arg to pressure constructor
|
|
|
|
id_press = utils::strdup(std::string(id) + "_press");
|
|
pressure = modify->add_compute(fmt::format("{} all pressure {}", id_press, id_temp));
|
|
pflag = 1;
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
FixDeformPressure::~FixDeformPressure()
|
|
{
|
|
if (set_extra)
|
|
for (int i = 0; i < 7; i++)
|
|
delete[] set_extra[i].pstr;
|
|
delete[] set_extra;
|
|
|
|
delete[] set_box.hstr;
|
|
delete[] set_box.hratestr;
|
|
|
|
// delete temperature and pressure if fix created them
|
|
|
|
if (tflag) modify->delete_compute(id_temp);
|
|
if (pflag) modify->delete_compute(id_press);
|
|
delete [] id_temp;
|
|
delete [] id_press;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixDeformPressure::init()
|
|
{
|
|
FixDeform::init();
|
|
|
|
set_box.vol_start = domain->xprd * domain->yprd * domain->zprd;
|
|
|
|
// check optional variables for PRESSURE or PMEAN style
|
|
|
|
for (int i = 0; i < 7; i++) {
|
|
if (!set_extra[i].pvar_flag) continue;
|
|
set_extra[i].pvar = input->variable->find(set_extra[i].pstr);
|
|
if (set_extra[i].pvar < 0)
|
|
error->all(FLERR, "Variable name {} for fix deform/pressure does not exist", set_extra[i].pstr);
|
|
if (!input->variable->equalstyle(set_extra[i].pvar))
|
|
error->all(FLERR, "Variable {} for fix deform/pressure is invalid style", set_extra[i].pstr);
|
|
}
|
|
|
|
// Find pressure/temp computes if needed
|
|
|
|
if (pressure_flag) {
|
|
temperature = modify->get_compute_by_id(id_temp);
|
|
if (!temperature)
|
|
error->all(FLERR, "Temperature ID {} for fix deform/pressure does not exist", id_temp);
|
|
|
|
pressure = modify->get_compute_by_id(id_press);
|
|
if (!pressure)
|
|
error->all(FLERR, "Pressure ID {} for fix deform/pressure does not exist", id_press);
|
|
}
|
|
|
|
// if yz [3] changes and will cause box flip, then xy [5] cannot be changing
|
|
// this is b/c the flips would induce continuous changes in xz
|
|
// in order to keep the edge vectors of the flipped shape matrix
|
|
// an integer combination of the edge vectors of the unflipped shape matrix
|
|
// error if style PRESSURE/ERATEER for yz, can't calculate if box flip occurs
|
|
|
|
if (set[3].style && set[5].style) {
|
|
if (flipflag && set[3].style == PRESSURE)
|
|
error->all(FLERR, "Fix {} cannot use yz pressure with xy", style);
|
|
if (flipflag && set[3].style == ERATERS)
|
|
error->all(FLERR, "Fix {} cannot use yz erate/rescale with xy", style);
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
compute T,P before integrator starts
|
|
------------------------------------------------------------------------- */
|
|
|
|
void FixDeformPressure::setup(int /*vflag*/)
|
|
{
|
|
// trigger virial computation, if needed, on next timestep
|
|
if (pressure_flag) pressure->addstep(update->ntimestep + 1);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixDeformPressure::end_of_step()
|
|
{
|
|
// wrap variable evaluations with clear/add
|
|
|
|
if (varflag) modify->clearstep_compute();
|
|
|
|
// set new box size for strain-based dims
|
|
|
|
if (strain_flag) {
|
|
FixDeform::apply_strain();
|
|
|
|
for (int i = 3; i < 6; i++) {
|
|
if (set[i].style == ERATERS) {
|
|
double L = domain->zprd;
|
|
if (i == 5) L = domain->yprd;
|
|
|
|
h_rate[i] = set[i].rate * L;
|
|
set_extra[i].cumulative_shift += update->dt * h_rate[i];
|
|
set[i].tilt_target = set[i].tilt_start + set_extra[i].cumulative_shift;
|
|
}
|
|
}
|
|
}
|
|
|
|
// set new box size for pressure-based dims
|
|
|
|
if (pressure_flag) {
|
|
temperature->compute_vector();
|
|
pressure->compute_vector();
|
|
pressure->compute_scalar();
|
|
for (int i = 0; i < 3; i++) {
|
|
if (!set_extra[i].saved) {
|
|
set_extra[i].saved = 1;
|
|
set_extra[i].prior_rate = 0.0;
|
|
set_extra[i].prior_pressure = pressure->vector[i];
|
|
}
|
|
}
|
|
apply_pressure();
|
|
}
|
|
|
|
// set new box size for VOLUME dims that are linked to other dims
|
|
// NOTE: still need to set h_rate for these dims
|
|
|
|
if (volume_flag) apply_volume();
|
|
|
|
// apply any final box scalings
|
|
|
|
if (set_box.style) apply_box();
|
|
|
|
// Save pressure/strain rate if required
|
|
|
|
if (pressure_flag) {
|
|
for (int i = 0; i < 3; i++) {
|
|
set_extra[i].prior_pressure = pressure->vector[i];
|
|
set_extra[i].prior_rate = ((set[i].hi_target - set[i].lo_target) /
|
|
domain->prd[i] - 1.0) / update->dt;
|
|
}
|
|
}
|
|
|
|
if (varflag) modify->addstep_compute(update->ntimestep + nevery);
|
|
|
|
// If tilting while evolving linear dimension, sum remapping effects
|
|
// otherwise, update_domain() will inaccurately use the current
|
|
// linear dimension to apply prior remappings
|
|
|
|
for (int i = 3; i < 6; i++) {
|
|
int idenom = 0;
|
|
if (i == 3) idenom = 1;
|
|
if (set[i].style && (set_box.style || set[idenom].style) && domain->periodicity[idenom]) {
|
|
// Add prior remappings. If the box remaps this timestep, don't
|
|
// add it yet so update_domain() will first detect the remapping
|
|
set[i].tilt_target += set_extra[i].cumulative_remap;
|
|
|
|
// Update remapping for next timestep
|
|
double prd = set[idenom].hi_target - set[idenom].lo_target;
|
|
double prdinv = 1.0 / prd;
|
|
if (set[i].tilt_target * prdinv < -0.5)
|
|
set_extra[i].cumulative_remap += prd;
|
|
if (set[i].tilt_target * prdinv > 0.5)
|
|
set_extra[i].cumulative_remap -= prd;
|
|
}
|
|
}
|
|
|
|
FixDeform::update_domain();
|
|
|
|
// trigger virial computation, if needed, on next timestep
|
|
|
|
if (pressure_flag)
|
|
pressure->addstep(update->ntimestep+1);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
apply pressure controls
|
|
------------------------------------------------------------------------- */
|
|
|
|
void FixDeformPressure::apply_pressure()
|
|
{
|
|
// If variable pressure, calculate current target
|
|
for (int i = 0; i < 6; i++)
|
|
if (set[i].style == PRESSURE || set[i].style == PMEAN)
|
|
if (set_extra[i].pvar_flag)
|
|
set_extra[i].ptarget = input->variable->compute_equal(set_extra[i].pvar);
|
|
|
|
// Find current (possibly coupled/hydrostatic) pressure for X, Y, Z
|
|
double *tensor = pressure->vector;
|
|
double scalar = pressure->scalar;
|
|
double p_current[3] = {0.0, 0.0, 0.0};
|
|
|
|
if (pcouple == XYZ) {
|
|
double ave = THIRD * (tensor[0] + tensor[1] + tensor[2]);
|
|
p_current[0] = p_current[1] = p_current[2] = ave;
|
|
} else if (pcouple == XY) {
|
|
double ave = 0.5 * (tensor[0] + tensor[1]);
|
|
p_current[0] = p_current[1] = ave;
|
|
p_current[2] = tensor[2];
|
|
} else if (pcouple == YZ) {
|
|
double ave = 0.5 * (tensor[1] + tensor[2]);
|
|
p_current[1] = p_current[2] = ave;
|
|
p_current[0] = tensor[0];
|
|
} else if (pcouple == XZ) {
|
|
double ave = 0.5 * (tensor[0] + tensor[2]);
|
|
p_current[0] = p_current[2] = ave;
|
|
p_current[1] = tensor[1];
|
|
} else {
|
|
if (set[0].style == PRESSURE) p_current[0] = tensor[0];
|
|
else if (set[0].style == PMEAN) p_current[0] = scalar;
|
|
|
|
if (set[1].style == PRESSURE) p_current[1] = tensor[1];
|
|
else if (set[1].style == PMEAN) p_current[1] = scalar;
|
|
|
|
if (set[2].style == PRESSURE) p_current[2] = tensor[2];
|
|
else if (set[2].style == PMEAN) p_current[2] = scalar;
|
|
}
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
if (set[i].style != PRESSURE && set[i].style != PMEAN) continue;
|
|
|
|
h_rate[i] = set_extra[i].pgain * (p_current[i] - set_extra[i].ptarget);
|
|
|
|
if (normalize_pressure_flag) {
|
|
if (set_extra[i].ptarget == 0) {
|
|
if (max_h_rate == 0) {
|
|
error->all(FLERR, "Cannot normalize error for zero pressure without defining a max rate");
|
|
} else h_rate[i] = max_h_rate * h_rate[i] / fabs(h_rate[i]);
|
|
} else h_rate[i] /= fabs(set_extra[i].ptarget);
|
|
}
|
|
|
|
if (max_h_rate != 0)
|
|
if (fabs(h_rate[i]) > max_h_rate)
|
|
h_rate[i] = max_h_rate * h_rate[i] / fabs(h_rate[i]);
|
|
|
|
h_ratelo[i] = -0.5 * h_rate[i];
|
|
|
|
double shift = domain->prd[i] * update->dt * h_rate[i];
|
|
set_extra[i].cumulative_shift += shift;
|
|
set[i].lo_target = set[i].lo_start - 0.5 * set_extra[i].cumulative_shift;
|
|
set[i].hi_target = set[i].hi_start + 0.5 * set_extra[i].cumulative_shift;
|
|
}
|
|
|
|
for (int i = 3; i < 6; i++) {
|
|
if (set[i].style != PRESSURE) continue;
|
|
|
|
double L, pcurrent;
|
|
if (i == 3) {
|
|
L = domain->zprd;
|
|
pcurrent = tensor[5];
|
|
} else if (i == 4) {
|
|
L = domain->zprd;
|
|
pcurrent = tensor[4];
|
|
} else {
|
|
L = domain->yprd;
|
|
pcurrent = tensor[3];
|
|
}
|
|
|
|
h_rate[i] = L * set_extra[i].pgain * (pcurrent - set_extra[i].ptarget);
|
|
if (normalize_pressure_flag) {
|
|
if (set_extra[i].ptarget == 0) {
|
|
if (max_h_rate == 0) {
|
|
error->all(FLERR, "Cannot normalize error for zero pressure without defining a max rate");
|
|
} else h_rate[i] = max_h_rate * h_rate[i] / fabs(h_rate[i]);
|
|
} else h_rate[i] /= fabs(set_extra[i].ptarget);
|
|
}
|
|
|
|
if (max_h_rate != 0)
|
|
if (fabs(h_rate[i]) > max_h_rate)
|
|
h_rate[i] = max_h_rate * h_rate[i] / fabs(h_rate[i]);
|
|
|
|
set_extra[i].cumulative_shift += update->dt * h_rate[i];
|
|
set[i].tilt_target = set[i].tilt_start + set_extra[i].cumulative_shift;
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
apply volume controls
|
|
------------------------------------------------------------------------- */
|
|
|
|
void FixDeformPressure::apply_volume()
|
|
{
|
|
double e1, e2;
|
|
int linked_pressure = 0;
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
if (set[i].style != VOLUME) continue;
|
|
|
|
int dynamic1 = set[i].dynamic1;
|
|
int dynamic2 = set[i].dynamic2;
|
|
int fixed = set[i].fixed;
|
|
double v0 = set[i].vol_start;
|
|
double shift = 0.0;
|
|
|
|
if (set[i].substyle == ONE_FROM_ONE) {
|
|
shift = 0.5 * (v0 / (set[dynamic1].hi_target - set[dynamic1].lo_target) /
|
|
(set[fixed].hi_start-set[fixed].lo_start));
|
|
} else if (set[i].substyle == ONE_FROM_TWO) {
|
|
shift = 0.5 * (v0 / (set[dynamic1].hi_target - set[dynamic1].lo_target) /
|
|
(set[dynamic2].hi_target - set[dynamic2].lo_target));
|
|
} else if (set[i].substyle == TWO_FROM_ONE) {
|
|
if (!vol_balance_flag) {
|
|
shift = 0.5 * sqrt(v0 * (set[i].hi_start - set[i].lo_start) /
|
|
(set[dynamic1].hi_target - set[dynamic1].lo_target) /
|
|
(set[fixed].hi_start - set[fixed].lo_start));
|
|
} else {
|
|
double dt = update->dt;
|
|
double e1i = set_extra[i].prior_rate;
|
|
double e2i = set_extra[fixed].prior_rate;
|
|
double L1i = domain->prd[i];
|
|
double L2i = domain->prd[fixed];
|
|
double L3i = domain->prd[dynamic1];
|
|
double L3 = (set[dynamic1].hi_target - set[dynamic1].lo_target);
|
|
double Vi = L1i * L2i * L3i;
|
|
double V = L3 * L1i * L2i;
|
|
double e3 = (L3 / L3i - 1.0) / dt;
|
|
double p1 = pressure->vector[i];
|
|
double p2 = pressure->vector[fixed];
|
|
double p1i = set_extra[i].prior_pressure;
|
|
double p2i = set_extra[fixed].prior_pressure;
|
|
double denominator;
|
|
|
|
if (e3 == 0) {
|
|
e1 = 0.0;
|
|
e2 = 0.0;
|
|
shift = 0.5 * L1i;
|
|
} else if (e1i == 0 || e2i == 0 || (p2 == p2i && p1 == p1i)) {
|
|
// If no prior strain or no change in pressure (initial step) just scale shift by relative box lengths
|
|
shift = 0.5 * sqrt(v0 * L1i / L3 / L2i);
|
|
} else {
|
|
if (!linked_pressure) {
|
|
// Calculate first strain rate by expanding stress to linear order, p1(t+dt) = p2(t+dt)
|
|
// Calculate second strain rate to preserve volume
|
|
denominator = p2 - p2i + e2i * ((p1 - p1i) / e1i);
|
|
if (denominator != 0.0 && e1i != 0.0) {
|
|
e1 = (((p2 - p2i) * (Vi - V) / (V * dt)) - e2i * (p1 - p2)) / denominator;
|
|
} else {
|
|
e1 = e2i;
|
|
}
|
|
e2 = (Vi - V * (1 + e1 * dt)) / (V * (1 + e1 * dt) * dt);
|
|
|
|
// If strain rate exceeds limit in either dimension, cap it at the maximum compatible rate
|
|
if (max_h_rate != 0) {
|
|
if ((fabs(e1) > max_h_rate) || (fabs(e2) > max_h_rate)) {
|
|
if (fabs(e1) > fabs(e2))
|
|
adjust_linked_rates(e1, e2, e3, Vi, V);
|
|
else
|
|
adjust_linked_rates(e2, e1, e3, Vi, V);
|
|
}
|
|
}
|
|
shift = 0.5 * L1i * (1.0 + e1 * dt);
|
|
linked_pressure = 1;
|
|
} else {
|
|
// Already calculated value of e2
|
|
shift = 0.5 * L1i * (1.0 + e2 * dt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
h_rate[i] = (2.0 * shift / domain->prd[i] - 1.0) / update->dt;
|
|
h_ratelo[i] = -0.5 * h_rate[i];
|
|
|
|
set[i].lo_target = 0.5 * (set[i].lo_start + set[i].hi_start) - shift;
|
|
set[i].hi_target = 0.5 * (set[i].lo_start + set[i].hi_start) + shift;
|
|
}
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
Rescale volume preserving strain rates to enforce max rate
|
|
------------------------------------------------------------------------- */
|
|
|
|
void FixDeformPressure::adjust_linked_rates(double &e_larger, double &e_smaller, double e3, double Vi, double V)
|
|
{
|
|
double dt = update->dt;
|
|
double e_lim_positive = (Vi - V * (1 + max_h_rate * dt)) / (V * (1 + max_h_rate * dt) * dt);
|
|
double e_lim_negative = (Vi - V * (1 - max_h_rate * dt)) / (V * (1 - max_h_rate * dt) * dt);
|
|
if ((e_larger * e3) >= 0) {
|
|
if (e_larger > 0.0) {
|
|
// Same sign as primary strain rate, cap third dimension
|
|
e_smaller = -max_h_rate;
|
|
e_larger = e_lim_negative;
|
|
} else {
|
|
e_smaller = max_h_rate;
|
|
e_larger = e_lim_positive;
|
|
}
|
|
} else {
|
|
// Opposite sign, set to maxrate.
|
|
if (e_larger > 0.0) {
|
|
e_larger = max_h_rate;
|
|
e_smaller = e_lim_positive;
|
|
} else {
|
|
e_larger = -max_h_rate;
|
|
e_smaller = e_lim_negative;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
apply box controls
|
|
------------------------------------------------------------------------- */
|
|
|
|
void FixDeformPressure::apply_box()
|
|
{
|
|
int i;
|
|
double scale, shift = 0.0;
|
|
double v_rate;
|
|
|
|
if (set_box.style == VOLUME) {
|
|
double v0 = set_box.vol_start;
|
|
double v = 1.0;
|
|
for (i = 0; i < 3; i++)
|
|
v *= (set[i].hi_target - set[i].lo_target);
|
|
|
|
scale = std::pow(v0 / v, THIRD);
|
|
for (i = 0; i < 3; i++) {
|
|
shift = 0.5 * (set[i].hi_target - set[i].lo_target) * scale;
|
|
set[i].lo_target = 0.5 * (set[i].lo_start + set[i].hi_start) - shift;
|
|
set[i].hi_target = 0.5 * (set[i].lo_start + set[i].hi_start) + shift;
|
|
|
|
// Recalculate h_rate
|
|
h_rate[i] = (set[i].hi_target - set[i].lo_target) / domain->prd[i] - 1.0;
|
|
h_rate[i] /= update->dt;
|
|
h_ratelo[i] = -0.5 * h_rate[i];
|
|
}
|
|
|
|
} else if (set_box.style == PRESSURE) {
|
|
|
|
// If variable pressure, calculate current target
|
|
if (set_extra[6].pvar_flag)
|
|
set_extra[6].ptarget = input->variable->compute_equal(set_extra[6].pvar);
|
|
|
|
v_rate = set_extra[6].pgain * (pressure->scalar - set_extra[6].ptarget);
|
|
|
|
if (normalize_pressure_flag) {
|
|
if (set_extra[6].ptarget == 0) {
|
|
if (max_h_rate == 0) {
|
|
error->all(FLERR, "Cannot normalize error for zero pressure without defining a max rate");
|
|
} else v_rate = max_h_rate * v_rate / fabs(v_rate);
|
|
} else v_rate /= fabs(set_extra[6].ptarget);
|
|
}
|
|
|
|
if (max_h_rate != 0)
|
|
if (fabs(v_rate) > max_h_rate)
|
|
v_rate = max_h_rate * v_rate / fabs(v_rate);
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
shift = (set[i].hi_target - set[i].lo_target) * update->dt * v_rate;
|
|
set_extra[6].cumulative_vshift[i] += shift;
|
|
|
|
if (set[i].style == NONE) {
|
|
// Overwrite default targets of current length
|
|
set[i].lo_target = set[i].lo_start;
|
|
set[i].hi_target = set[i].hi_start;
|
|
}
|
|
|
|
set[i].lo_target -= 0.5 * set_extra[6].cumulative_vshift[i];
|
|
set[i].hi_target += 0.5 * set_extra[6].cumulative_vshift[i];
|
|
|
|
// Recalculate h_rate
|
|
h_rate[i] = (set[i].hi_target - set[i].lo_target) / domain->prd[i] - 1.0;
|
|
h_rate[i] /= update->dt;
|
|
h_ratelo[i] = -0.5 * h_rate[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
write Set data to restart file
|
|
------------------------------------------------------------------------- */
|
|
|
|
void FixDeformPressure::write_restart(FILE *fp)
|
|
{
|
|
if (comm->me == 0) {
|
|
int size = 7 * sizeof(Set) + 7 * sizeof(SetExtra);
|
|
fwrite(&size, sizeof(int), 1, fp);
|
|
fwrite(set, sizeof(Set), 6, fp);
|
|
fwrite(&set_box, sizeof(Set), 1, fp);
|
|
fwrite(set_extra, sizeof(SetExtra), 7, fp);
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
use selected state info from restart file to restart the Fix
|
|
------------------------------------------------------------------------- */
|
|
|
|
void FixDeformPressure::restart(char *buf)
|
|
{
|
|
int n = 0;
|
|
int samestyle = 1;
|
|
Set *set_restart = (Set *) buf;
|
|
for (int i = 0; i < 6; ++i) {
|
|
// restore data from initial state
|
|
set[i].lo_initial = set_restart[i].lo_initial;
|
|
set[i].hi_initial = set_restart[i].hi_initial;
|
|
set[i].vol_initial = set_restart[i].vol_initial;
|
|
set[i].tilt_initial = set_restart[i].tilt_initial;
|
|
|
|
// check if style settings are consistent
|
|
if (set[i].style != set_restart[i].style)
|
|
samestyle = 0;
|
|
if (set[i].substyle != set_restart[i].substyle)
|
|
samestyle = 0;
|
|
}
|
|
n += 6 * sizeof(Set);
|
|
|
|
// Only restore relevant box variables & check consistency
|
|
Set set_box_restart;
|
|
memcpy(&set_box_restart, (Set *) &buf[n], sizeof(Set));
|
|
set_box.vol_initial = set_box_restart.vol_initial;
|
|
if (set_box.style != set_box_restart.style)
|
|
samestyle = 0;
|
|
|
|
if (!samestyle)
|
|
error->all(FLERR, "Fix deform/pressure settings not consistent with restart");
|
|
|
|
n += sizeof(Set);
|
|
SetExtra *set_extra_restart = (SetExtra *) &buf[n];
|
|
for (int i = 0; i < 7; ++i) {
|
|
set_extra[i].saved = set_extra_restart[i].saved;
|
|
set_extra[i].prior_rate = set_extra_restart[i].prior_rate;
|
|
set_extra[i].prior_pressure = set_extra_restart[i].prior_pressure;
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixDeformPressure::options(int i, int narg, char **arg)
|
|
{
|
|
pcouple = NOCOUPLE;
|
|
max_h_rate = 0.0;
|
|
vol_balance_flag = 0;
|
|
normalize_pressure_flag = 0;
|
|
|
|
// parse only options not handled by parent class
|
|
|
|
int iarg;
|
|
while (i < (int) leftover_iarg.size()) {
|
|
iarg = leftover_iarg[i];
|
|
if (strcmp(arg[iarg], "couple") == 0) {
|
|
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure couple", error);
|
|
if (strcmp(arg[iarg + 1], "xyz") == 0) pcouple = XYZ;
|
|
else if (strcmp(arg[iarg + 1], "xy") == 0) pcouple = XY;
|
|
else if (strcmp(arg[iarg + 1], "yz") == 0) pcouple = YZ;
|
|
else if (strcmp(arg[iarg + 1], "xz") == 0) pcouple = XZ;
|
|
else if (strcmp(arg[iarg + 1], "none") == 0) pcouple = NOCOUPLE;
|
|
else error->all(FLERR, "Illegal fix deform/pressure couple command: {}", arg[iarg + 1]);
|
|
i += 2;
|
|
} else if (strcmp(arg[iarg], "max/rate") == 0) {
|
|
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure max/rate", error);
|
|
max_h_rate = utils::numeric(FLERR, arg[iarg + 1], false, lmp);
|
|
if (max_h_rate <= 0.0)
|
|
error->all(FLERR, "Maximum strain rate must be a positive, non-zero value");
|
|
i += 2;
|
|
} else if (strcmp(arg[iarg], "normalize/pressure") == 0) {
|
|
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure normalize/pressure", error);
|
|
normalize_pressure_flag = utils::logical(FLERR, arg[iarg + 1], false, lmp);
|
|
i += 2;
|
|
} else if (strcmp(arg[iarg], "vol/balance/p") == 0) {
|
|
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure vol/balance/p", error);
|
|
vol_balance_flag = utils::logical(FLERR, arg[iarg + 1], false, lmp);
|
|
i += 2;
|
|
} else error->all(FLERR, "Illegal fix deform/pressure command: {}", arg[iarg]);
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
int FixDeformPressure::modify_param(int narg, char **arg)
|
|
{
|
|
if (strcmp(arg[0], "temp") == 0) {
|
|
if (narg < 2) error->all(FLERR, "Illegal fix_modify command");
|
|
if (tflag) {
|
|
modify->delete_compute(id_temp);
|
|
tflag = 0;
|
|
}
|
|
delete[] id_temp;
|
|
id_temp = utils::strdup(arg[1]);
|
|
|
|
temperature = modify->get_compute_by_id(arg[1]);
|
|
if (!temperature)
|
|
error->all(FLERR, "Could not find fix_modify temperature compute ID: ", arg[1]);
|
|
|
|
if (temperature->tempflag == 0)
|
|
error->all(FLERR, "Fix_modify temperature compute {} does not compute temperature", arg[1]);
|
|
if (temperature->igroup != 0 && comm->me == 0)
|
|
error->warning(FLERR, "Temperature compute {} for fix {} is not for group all: {}",
|
|
arg[1], style, group->names[temperature->igroup]);
|
|
|
|
// reset id_temp of pressure to new temperature ID
|
|
|
|
auto icompute = modify->get_compute_by_id(id_press);
|
|
if (!icompute)
|
|
error->all(FLERR, "Pressure compute ID {} for fix {} does not exist", id_press, style);
|
|
icompute->reset_extra_compute_fix(id_temp);
|
|
|
|
return 2;
|
|
|
|
} else if (strcmp(arg[0], "press") == 0) {
|
|
if (narg < 2) error->all(FLERR, "Illegal fix_modify command");
|
|
if (pflag) {
|
|
modify->delete_compute(id_press);
|
|
pflag = 0;
|
|
}
|
|
delete[] id_press;
|
|
id_press = utils::strdup(arg[1]);
|
|
|
|
pressure = modify->get_compute_by_id(arg[1]);
|
|
if (!pressure) error->all(FLERR, "Could not find fix_modify pressure compute ID: {}", arg[1]);
|
|
if (pressure->pressflag == 0)
|
|
error->all(FLERR, "Fix_modify pressure compute {} does not compute pressure", arg[1]);
|
|
return 2;
|
|
}
|
|
|
|
return 0;
|
|
}
|