From b8728884fc900dd43f6c565dbe686d5eb5a68d06 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 10 Oct 2022 10:33:47 -0600 Subject: [PATCH 01/29] Drafting stress controls in fix deform --- src/fix_deform.cpp | 505 ++++++++++++++++++++++++++++++++++++--------- src/fix_deform.h | 21 +- 2 files changed, 430 insertions(+), 96 deletions(-) diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index bc6e61a69ed..40221df839b 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -16,6 +16,11 @@ Contributing author: Pieter in 't Veld (SNL) ------------------------------------------------------------------------- */ +// Save previous state to restart file for derivatives +// define hrate_lo/hi for volume +// add modify command +// add pressure code + #include "fix_deform.h" #include "atom.h" @@ -39,8 +44,9 @@ using namespace LAMMPS_NS; using namespace FixConst; using namespace MathConst; -enum{NONE=0,FINAL,DELTA,SCALE,VEL,ERATE,TRATE,VOLUME,WIGGLE,VARIABLE}; +enum{NONE=0,FINAL,DELTA,SCALE,VEL,ERATE,TRATE,VOLUME,WIGGLE,VARIABLE,PRESSURE,PISOTROPIC}; enum{ONE_FROM_ONE,ONE_FROM_TWO,TWO_FROM_ONE}; +enum{NOCOUPLE=0,XYZ,XY,YZ,XZ}; /* ---------------------------------------------------------------------- */ @@ -52,6 +58,8 @@ irregular(nullptr), set(nullptr) no_change_box = 1; restart_global = 1; pre_exchange_migrate = 1; + pcouple = NOCOUPLE; + dimension = domain->dimension; nevery = utils::inumeric(FLERR,arg[3],false,lmp); if (nevery <= 0) error->all(FLERR,"Illegal fix deform command"); @@ -132,7 +140,35 @@ irregular(nullptr), set(nullptr) set[index].hstr = utils::strdup(&arg[iarg+2][2]); set[index].hratestr = utils::strdup(&arg[iarg+3][2]); iarg += 4; - } else error->all(FLERR,"Illegal fix deform command"); + } else if (strcmp(arg[iarg+1],"pressure") == 0) { + if (iarg+4 > narg) error->all(FLERR, "Illegal fix deform command"); + set[index].style = PRESSURE; + if (strstr(arg[iarg+2],"v_") != arg[iarg+2]) { + set[index].ptarget = utils::numeric(FLERR,arg[iarg+2],false,lmp); + } else { + if (iarg+ > narg) error->all(FLERR,"Illegal fix deform command"); + set[index].pstr = utils::strdup(&arg[iarg+2][2]); + set[index].pvar = 1; + } + set[index].pgain = utils::numeric(FLERR,arg[iarg+3],false,lmp); + if (set[index].pgain <= 0.0) + error->all(FLERR,"Illegal fix deform command"); + iarg += 4; + } else if (strcmp(arg[iarg+1],"pressure/isotropic") == 0) { + if (iarg+4 > narg) error->all(FLERR, "Illegal fix deform command"); + set[index].style = PISOTROPIC; + if (strstr(arg[iarg+2],"v_") != arg[iarg+2]) { + set[index].ptarget = utils::numeric(FLERR,arg[iarg+2],false,lmp); + } else { + if (iarg+ > narg) error->all(FLERR,"Illegal fix deform command"); + set[index].pstr = utils::strdup(&arg[iarg+2][2]); + set[index].pvar = 1; + } + set[index].pgain = utils::numeric(FLERR,arg[iarg+3],false,lmp); + if (set[index].pgain <= 0.0) + error->all(FLERR,"Illegal fix deform command"); + iarg += 4; + } error->all(FLERR,"Illegal fix deform command"); } else if (strcmp(arg[iarg],"xy") == 0 || strcmp(arg[iarg],"xz") == 0 || @@ -190,8 +226,21 @@ irregular(nullptr), set(nullptr) set[index].hstr = utils::strdup(&arg[iarg+2][2]); set[index].hratestr = utils::strdup(&arg[iarg+3][2]); iarg += 4; + } else if (strcmp(arg[iarg+1],"pressure") == 0) { + if (iarg+4 > narg) error->all(FLERR, "Illegal fix deform command"); + set[index].style = PRESSURE; + if (strstr(arg[iarg+2],"v_") != arg[iarg+2]) { + set[index].ptarget = utils::numeric(FLERR,arg[iarg+2],false,lmp); + } else { + if (iarg+ > narg) error->all(FLERR,"Illegal fix deform command"); + set[index].pstr = utils::strdup(&arg[iarg+2][2]); + set[index].pvar = 1; + } + set[index].pgain = utils::numeric(FLERR,arg[iarg+3],false,lmp); + if (set[index].pgain <= 0.0) + error->all(FLERR,"Illegal fix deform command"); + iarg += 4; } else error->all(FLERR,"Illegal fix deform command"); - } else break; } @@ -201,6 +250,63 @@ irregular(nullptr), set(nullptr) options(narg-iarg,&arg[iarg]); if (remapflag != Domain::X_REMAP) restart_pbc = 1; + // populate coupled pressure controls + + if (pcouple != NOCOUPLE) { + int coupled_indices[3] = {0}; + int j = -1; + double couple_gain, coupled_pressure; + char *couple_str; + + 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[i].coupled_flag = 1; + if (set[i].style != VOLUME && set[i].style != PRESSURE && set[i].style != NONE) + error->all(FLERR, "Cannot couple dimensions not controlled by pressure or volume in fix deform"); + if (set[i].style == PRESSURE || set[i].style == VOLUME) + j = i; + } + } + + if (j == -1) + error->all(FLERR, "Must specify pressure style for a coupled dimension in fix deform"); + + // Copy data to each coupled dimension + for (int i = 0; i < 3; i++) { + if (coupled_indices[i]) { + 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 && set[i].style == NONE) { + set[i].style = PRESSURE; + set[i].pgain = set[j].pgain; + if (set[j].pvar == 1) { + set[i].pstr = set[j].pstr; + set[i].pvar = 1; + } else { + set[i].ptarget = set[j].ptarget; + } + } else if (set[j].style == VOLUME && set[i].style == NONE) { + set[i].style = VOLUME; + set[i].saved = -1; + if (domain->dimension == 2) + error->all(FLERR, "Cannot couple pressure with constant volume in two dimensions"); + } + } else { + if (set[i].style == VOLUME && set[j].style == VOLUME) + error->all(FLERR, "Dimensions used to maintain constant volume must either be all be coupled or not coupled"); + } + } + } + // setup dimflags used by other classes to check for volume-change conflicts for (int i = 0; i < 6; i++) @@ -285,32 +391,31 @@ irregular(nullptr), set(nullptr) // for VOLUME, setup links to other dims // fixed, dynamic1, dynamic2 + volume_flag = 0; for (int i = 0; i < 3; i++) { if (set[i].style != VOLUME) continue; + volume_flag = 1; int other1 = (i+1) % 3; int other2 = (i+2) % 3; - if (set[other1].style == NONE) { + // 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 deform volume setting is invalid"); + + 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) { - if (set[other1].style == NONE || set[other1].style == VOLUME) - error->all(FLERR,"Fix deform volume setting is invalid"); set[i].substyle = ONE_FROM_ONE; set[i].fixed = other2; set[i].dynamic1 = other1; } else if (set[other1].style == VOLUME) { - if (set[other2].style == NONE || set[other2].style == VOLUME) - error->all(FLERR,"Fix deform volume setting is invalid"); set[i].substyle = TWO_FROM_ONE; set[i].fixed = other1; set[i].dynamic1 = other2; } else if (set[other2].style == VOLUME) { - if (set[other1].style == NONE || set[other1].style == VOLUME) - error->all(FLERR,"Fix deform volume setting is invalid"); set[i].substyle = TWO_FROM_ONE; set[i].fixed = other2; set[i].dynamic1 = other1; @@ -321,12 +426,34 @@ irregular(nullptr), set(nullptr) } } + // 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 != PISOTROPIC) + strain_flag = 1; + // set varflag varflag = 0; for (int i = 0; i < 6; i++) if (set[i].style == VARIABLE) varflag = 1; + // set pressure_flag + + pressure_flag = 0; + for (int i = 0; i < 6; i++) { + if (set[i].style == PRESSURE || set[i].style == PISOTROPIC) pressure_flag = 1; + if (set[i].coupled_flag) pressure_flag = 1; + } + + // check conflict between constant volume/pressure + + if (volume_flag) + for (int i = 0; i < 6; i++) + if (set[i].style == PISOTROPIC) + error->all(FLERR, "Cannot use fix deform to assign constant volume and pressure"); + // set initial values at time fix deform is issued for (int i = 0; i < 3; i++) { @@ -350,6 +477,29 @@ irregular(nullptr), set(nullptr) else irregular = nullptr; TWOPI = 2.0*MY_PI; + + // 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"); + 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"); + modify->add_compute(fmt::format("{} all pressure {}",id_press, id_temp)); + pflag = 1; + } } /* ---------------------------------------------------------------------- */ @@ -360,6 +510,7 @@ FixDeform::~FixDeform() for (int i = 0; i < 6; i++) { delete[] set[i].hstr; delete[] set[i].hratestr; + delete[] set[i].pstr; } } delete[] set; @@ -374,6 +525,13 @@ FixDeform::~FixDeform() h_rate[0] = h_rate[1] = h_rate[2] = h_rate[3] = h_rate[4] = h_rate[5] = 0.0; h_ratelo[0] = h_ratelo[1] = h_ratelo[2] = 0.0; + + // 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; } /* ---------------------------------------------------------------------- */ @@ -574,7 +732,7 @@ void FixDeform::init() // set domain->h_rate values for use by domain and other fixes/computes // initialize all rates to 0.0 - // cannot set here for TRATE,VOLUME,WIGGLE,VARIABLE since not constant + // cannot set here for TRATE,VOLUME,WIGGLE,VARIABLE,PRESSURE since not constant h_rate = domain->h_rate; h_ratelo = domain->h_ratelo; @@ -611,6 +769,31 @@ void FixDeform::init() for (auto ifix : modify->get_fix_list()) if (ifix->rigid_flag) rfix.push_back(ifix); + + // Find pressure/temp computes if needed + + if (pressure_flag) { + int icompute = modify->find_compute(id_temp); + if (icompute < 0) + error->all(FLERR,"Temperature ID for fix deform does not exist"); + temperature = modify->compute[icompute]; + + icompute = modify->find_compute(id_press); + if (icompute < 0) + error->all(FLERR,"Pressure ID for fix deform does not exist"); + pressure = modify->compute[icompute]; + } +} + +/* ---------------------------------------------------------------------- + compute T,P if needed before integrator starts +------------------------------------------------------------------------- */ + +void FixDeform::setup(int /*vflag*/) +{ + // trigger virial computation on next timestep + + if (pressure_flag) pressure->addstep(update->ntimestep+1); } /* ---------------------------------------------------------------------- @@ -660,95 +843,40 @@ void FixDeform::end_of_step() if (varflag) modify->clearstep_compute(); - // set new box size - // for NONE, target is current box size - // for TRATE, set target directly based on current time, also set h_rate - // for WIGGLE, set target directly based on current time, also set h_rate - // for VARIABLE, set target directly via variable eval, also set h_rate - // for others except VOLUME, target is linear value between start and stop + // set new box size for strain-based dims - for (i = 0; i < 3; i++) { - if (set[i].style == NONE) { - set[i].lo_target = domain->boxlo[i]; - set[i].hi_target = domain->boxhi[i]; - } else if (set[i].style == TRATE) { - double delt = (update->ntimestep - update->beginstep) * update->dt; - set[i].lo_target = 0.5*(set[i].lo_start+set[i].hi_start) - - 0.5*((set[i].hi_start-set[i].lo_start) * exp(set[i].rate*delt)); - set[i].hi_target = 0.5*(set[i].lo_start+set[i].hi_start) + - 0.5*((set[i].hi_start-set[i].lo_start) * exp(set[i].rate*delt)); - h_rate[i] = set[i].rate * domain->h[i]; - h_ratelo[i] = -0.5*h_rate[i]; - } else if (set[i].style == WIGGLE) { - double delt = (update->ntimestep - update->beginstep) * update->dt; - set[i].lo_target = set[i].lo_start - - 0.5*set[i].amplitude * sin(TWOPI*delt/set[i].tperiod); - set[i].hi_target = set[i].hi_start + - 0.5*set[i].amplitude * sin(TWOPI*delt/set[i].tperiod); - h_rate[i] = TWOPI/set[i].tperiod * set[i].amplitude * - cos(TWOPI*delt/set[i].tperiod); - h_ratelo[i] = -0.5*h_rate[i]; - } else if (set[i].style == VARIABLE) { - double del = input->variable->compute_equal(set[i].hvar); - set[i].lo_target = set[i].lo_start - 0.5*del; - set[i].hi_target = set[i].hi_start + 0.5*del; - h_rate[i] = input->variable->compute_equal(set[i].hratevar); - h_ratelo[i] = -0.5*h_rate[i]; - } else if (set[i].style != VOLUME) { - set[i].lo_target = set[i].lo_start + - delta*(set[i].lo_stop - set[i].lo_start); - set[i].hi_target = set[i].hi_start + - delta*(set[i].hi_stop - set[i].hi_start); + set_strain(); + + // set new box size for pressure-based dims + + if (pressure_flag) { + temperature->compute_vector(); + pressure->compute_vector(); + for (int i = 0; i < 3; i++) { + if (set[i].saved == -1) { + set[i].saved = 1; + set[i].rate = 0.0; + set[i].prior_pressure = pressure->vector[i]; + if (i == 0) set[i].box_length = domain->xprd; + else if (i == 1) set[i].box_length = domain->yprd; + else (i == 2) set[i].box_length = domain->zprd; + } } + set_pressure(); } // set new box size for VOLUME dims that are linked to other dims // NOTE: still need to set h_rate for these dims - for (i = 0; i < 3; i++) { - if (set[i].style != VOLUME) continue; - - if (set[i].substyle == ONE_FROM_ONE) { - set[i].lo_target = 0.5*(set[i].lo_start+set[i].hi_start) - - 0.5*(set[i].vol_start / - (set[set[i].dynamic1].hi_target - - set[set[i].dynamic1].lo_target) / - (set[set[i].fixed].hi_start-set[set[i].fixed].lo_start)); - set[i].hi_target = 0.5*(set[i].lo_start+set[i].hi_start) + - 0.5*(set[i].vol_start / - (set[set[i].dynamic1].hi_target - - set[set[i].dynamic1].lo_target) / - (set[set[i].fixed].hi_start-set[set[i].fixed].lo_start)); + if (volume_flag) set_volume(); - } else if (set[i].substyle == ONE_FROM_TWO) { - set[i].lo_target = 0.5*(set[i].lo_start+set[i].hi_start) - - 0.5*(set[i].vol_start / - (set[set[i].dynamic1].hi_target - - set[set[i].dynamic1].lo_target) / - (set[set[i].dynamic2].hi_target - - set[set[i].dynamic2].lo_target)); - set[i].hi_target = 0.5*(set[i].lo_start+set[i].hi_start) + - 0.5*(set[i].vol_start / - (set[set[i].dynamic1].hi_target - - set[set[i].dynamic1].lo_target) / - (set[set[i].dynamic2].hi_target - - set[set[i].dynamic2].lo_target)); + // Save pressure/strain rate if required - } else if (set[i].substyle == TWO_FROM_ONE) { - set[i].lo_target = 0.5*(set[i].lo_start+set[i].hi_start) - - 0.5*sqrt(set[i].vol_start / - (set[set[i].dynamic1].hi_target - - set[set[i].dynamic1].lo_target) / - (set[set[i].fixed].hi_start - - set[set[i].fixed].lo_start) * - (set[i].hi_start - set[i].lo_start)); - set[i].hi_target = 0.5*(set[i].lo_start+set[i].hi_start) + - 0.5*sqrt(set[i].vol_start / - (set[set[i].dynamic1].hi_target - - set[set[i].dynamic1].lo_target) / - (set[set[i].fixed].hi_start - - set[set[i].fixed].lo_start) * - (set[i].hi_start - set[i].lo_start)); + if (pressure_flag) { + double dt_inv = 1.0 / update->dt; + for (int i = 0; i < 3; i++) { + set[i].prior_pressure = pressure->vector[i]; + set[i].prior_rate = ((set[i].hi_target - set[i].lo_target) / set[i].box_length - 1.0) * dt_inv; } } @@ -882,7 +1010,7 @@ void FixDeform::end_of_step() if (mask[i] & groupbit) domain->x2lamda(x[i],x[i]); - for (auto &ifix : rfix) + for (auto ifix : rfix) ifix->deform(0); } @@ -921,13 +1049,134 @@ void FixDeform::end_of_step() if (mask[i] & groupbit) domain->lamda2x(x[i],x[i]); - for (auto &ifix : rfix) + for (auto ifix : rfix) ifix->deform(1); } // redo KSpace coeffs since box has changed if (kspace_flag) force->kspace->setup(); + + // trigger virial computation, if needed, on next timestep + + if (pressure_flag) { + pressure->addstep(update->ntimestep+1); + set[0].box_length = domain->xprd; + set[1].box_length = domain->yprd; + set[2].box_length = domain->zprd; + } +} + +/* ---------------------------------------------------------------------- + set box size for strain-based dimensions +------------------------------------------------------------------------- */ + +void FixDeform::set_strain() +{ + // for NONE, target is current box size + // for TRATE, set target directly based on current time, also set h_rate + // for WIGGLE, set target directly based on current time, also set h_rate + // for VARIABLE, set target directly via variable eval, also set h_rate + // for others except VOLUME, target is linear value between start and stop + + for (int i = 0; i < 3; i++) { + if (set[i].style == NONE) { + set[i].lo_target = domain->boxlo[i]; + set[i].hi_target = domain->boxhi[i]; + } else if (set[i].style == TRATE) { + double delt = (update->ntimestep - update->beginstep) * update->dt; + set[i].lo_target = 0.5*(set[i].lo_start+set[i].hi_start) - + 0.5*((set[i].hi_start-set[i].lo_start) * exp(set[i].rate*delt)); + set[i].hi_target = 0.5*(set[i].lo_start+set[i].hi_start) + + 0.5*((set[i].hi_start-set[i].lo_start) * exp(set[i].rate*delt)); + h_rate[i] = set[i].rate * domain->h[i]; + h_ratelo[i] = -0.5*h_rate[i]; + } else if (set[i].style == WIGGLE) { + double delt = (update->ntimestep - update->beginstep) * update->dt; + set[i].lo_target = set[i].lo_start - + 0.5*set[i].amplitude * sin(TWOPI*delt/set[i].tperiod); + set[i].hi_target = set[i].hi_start + + 0.5*set[i].amplitude * sin(TWOPI*delt/set[i].tperiod); + h_rate[i] = TWOPI/set[i].tperiod * set[i].amplitude * + cos(TWOPI*delt/set[i].tperiod); + h_ratelo[i] = -0.5*h_rate[i]; + } else if (set[i].style == VARIABLE) { + double del = input->variable->compute_equal(set[i].hvar); + set[i].lo_target = set[i].lo_start - 0.5*del; + set[i].hi_target = set[i].hi_start + 0.5*del; + h_rate[i] = input->variable->compute_equal(set[i].hratevar); + h_ratelo[i] = -0.5*h_rate[i]; + } else if (set[i].style != VOLUME) { + set[i].lo_target = set[i].lo_start + + delta*(set[i].lo_stop - set[i].lo_start); + set[i].hi_target = set[i].hi_start + + delta*(set[i].hi_stop - set[i].hi_start); + } + } +} + +/* ---------------------------------------------------------------------- + set box size for pressure-based dimensions +------------------------------------------------------------------------- */ + +void FixDeform::set_pressure() +{ + for (int i = 0; i < 3; i++) { + + + } + // must define hi+lo target + // + +} + +/* ---------------------------------------------------------------------- + set box size for VOLUME dimensions +------------------------------------------------------------------------- */ + +void FixDeform::set_volume() +{ + for (int i = 0; i < 3; i++) { + if (set[i].style != VOLUME) continue; + + double v0 = set[i].vol_start; + double center_start = 0.5 * (set[i].lo_start + set[i].hi_start); + double offset; + + if (set[i].substyle == ONE_FROM_ONE) { + offset = 0.5 * (v0 / + (set[set[i].dynamic1].hi_target - set[set[i].dynamic1].lo_target) / + (set[set[i].fixed].hi_start-set[set[i].fixed].lo_start)); + } else if (set[i].substyle == ONE_FROM_TWO) { + offset = 0.5 * (v0 / + (set[set[i].dynamic1].hi_target - set[set[i].dynamic1].lo_target) / + (set[set[i].dynamic2].hi_target - set[set[i].dynamic2].lo_target)) + } else if (set[i].substyle == TWO_FROM_ONE) { + if (!set[i].coupled_flag) { + offset = 0.5 * sqrt(v0 * (set[i].hi_start - set[i].lo_start) / + (set[set[i].dynamic1].hi_target - set[set[i].dynamic1].lo_target) / + (set[set[i].fixed].hi_start - set[set[i].fixed].lo_start)) + } else { + double p1 = pressure->vector[i]; + double p2 = pressure->vector[set[i].fixed]; + double p1i = set[i].prior_pressure; + double p2i = set[set[i].fixed].prior_pressure; + double e1i = set[i].prior_rate; + double e2i = set[set[i].fixed].prior_rate; + double L3 = (set[set[i].dynamic1].hi_target - set[set[i].dynamic1].lo_target); + double dt = update->dt; + + double e3 = (L3 / set[set[i].dynamic1].box_length - 1.0) / dt; + double e1 = -e3 * dt / (1 + e3 * dt) * (p2 - p2i) - e2i * (p1 - p2); + e1 /= (p2 - p2i + (p1 - p1i) / e1p * e2p); + double e2 = (1.0 - (1 + e3 * dt) * (1 + e1 * dt)); + e2 /= (1 + e3 * dt) * (1 + e1 * dt) * dt; + offset = 0.5 * set[i].box_length * (1.0 - e3 * dt); + } + } + set[i].lo_target = center_start - offset; + set[i].hi_target = center_start + offset; + } } /* ---------------------------------------------------------------------- @@ -937,7 +1186,7 @@ void FixDeform::end_of_step() void FixDeform::write_restart(FILE *fp) { if (comm->me == 0) { - int size = 6*sizeof(Set); + int size = 6 * sizeof(Set); fwrite(&size,sizeof(int),1,fp); fwrite(set,sizeof(Set),6,fp); } @@ -996,8 +1245,22 @@ void FixDeform::options(int narg, char **arg) if (iarg+2 > narg) error->all(FLERR,"Illegal fix deform command"); flipflag = utils::logical(FLERR,arg[iarg+1],false,lmp); iarg += 2; + } else if (strcmp(arg[iarg],"couple") == 0) { + if (iarg+2 > narg) + error->all(FLERR,"Illegal fix fix deform command"); + 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 fix deform command"); + iarg += 2; } else error->all(FLERR,"Illegal fix deform command"); } + + if (dimension == 2) + if (pcouple == XYZ || pcouple == XZ || pcouple == YZ) + error->all(FLERR, "Cannot couple Z dimension in fix deform in 2D"); } /* ---------------------------------------------------------------------- @@ -1010,3 +1273,57 @@ double FixDeform::memory_usage() if (irregular) bytes += irregular->memory_usage(); return bytes; } + + +/* ---------------------------------------------------------------------- */ + +int FixDeform::modify_param(int narg, char **arg) +{ + if (!pressure_flag) error->all(FLERR,"Cannot modify fix deform without a pressure control"); + 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]); + + int icompute = modify->find_compute(arg[1]); + if (icompute < 0) error->all(FLERR,"Could not find fix_modify temperature ID"); + temperature = modify->compute[icompute]; + + if (temperature->tempflag == 0) + error->all(FLERR,"Fix_modify temperature ID does not compute temperature"); + if (temperature->igroup != 0 && comm->me == 0) + error->warning(FLERR,"Temperature for deform is not for group all"); + + // reset id_temp of pressure to new temperature ID + + icompute = modify->find_compute(id_press); + if (icompute < 0) + error->all(FLERR,"Pressure ID for fix deform does not exist"); + modify->compute[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]); + + int icompute = modify->find_compute(arg[1]); + if (icompute < 0) error->all(FLERR,"Could not find fix_modify pressure ID"); + pressure = modify->compute[icompute]; + + if (pressure->pressflag == 0) + error->all(FLERR,"Fix_modify pressure ID does not compute pressure"); + return 2; + } + + return 0; +} diff --git a/src/fix_deform.h b/src/fix_deform.h index 76f5fc9d4a2..7297874258c 100644 --- a/src/fix_deform.h +++ b/src/fix_deform.h @@ -33,23 +33,32 @@ class FixDeform : public Fix { ~FixDeform() override; int setmask() override; void init() override; + void setup(int) override; void pre_exchange() override; void end_of_step() override; void write_restart(FILE *) override; void restart(char *buf) override; double memory_usage() override; + int modify_param(int, char **) override; protected: - int triclinic, scaleflag, flipflag; + int dimension, triclinic, scaleflag, flipflag, pcouple; int flip, flipxy, flipxz, flipyz; double *h_rate, *h_ratelo; int varflag; // 1 if VARIABLE option is used, 0 if not + int strain_flag; // 1 if strain-based option is used, 0 if not + int volume_flag; // 1 if VOLUME option is used, 0 if not + int pressure_flag; // 1 if pressure tensor used, 0 if not int kspace_flag; // 1 if KSpace invoked, 0 if not std::vector rfix; // pointers to rigid fixes class Irregular *irregular; // for migrating atoms after box flips double TWOPI; + char *id_temp, *id_press; + class Compute *temperature, *pressure; + int tflag, pflag; + struct Set { int style, substyle; double flo, fhi, ftilt; @@ -61,13 +70,21 @@ class FixDeform : public Fix { double tilt_initial, tilt_start, tilt_stop, tilt_target, tilt_flip; double tilt_min, tilt_max; double vol_initial, vol_start; + double ptarget, pgain; + double prior_pressure, prior_rate; + double box_length; + int saved; int fixed, dynamic1, dynamic2; - char *hstr, *hratestr; + char *hstr, *hratestr, *pstr; int hvar, hratevar; + int pvar; + int coupled_flag; }; Set *set; void options(int, char **); + void set_volume(); + void couple(); }; } // namespace LAMMPS_NS From 66471c146537d8d1a32e00c8c7d9e68c4bc8ff07 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 11 Oct 2022 16:52:02 -0600 Subject: [PATCH 02/29] Adding pressure controls and fixing misc errors --- src/fix_deform.cpp | 377 ++++++++++++++++++++++++++++----------------- src/fix_deform.h | 4 +- 2 files changed, 236 insertions(+), 145 deletions(-) diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index 40221df839b..766d7c22ae6 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -17,14 +17,14 @@ ------------------------------------------------------------------------- */ // Save previous state to restart file for derivatives -// define hrate_lo/hi for volume -// add modify command -// add pressure code +// define hrate_lo/hi for volume/pressure +// add logic for hi_stop and flip flag #include "fix_deform.h" #include "atom.h" #include "comm.h" +#include "compute.h" #include "domain.h" #include "error.h" #include "force.h" @@ -84,36 +84,36 @@ irregular(nullptr), set(nullptr) else if (strcmp(arg[iarg],"y") == 0) index = 1; else if (strcmp(arg[iarg],"z") == 0) index = 2; - if (iarg+2 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "fix deform", error); if (strcmp(arg[iarg+1],"final") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform final", error); set[index].style = FINAL; set[index].flo = utils::numeric(FLERR,arg[iarg+2],false,lmp); set[index].fhi = utils::numeric(FLERR,arg[iarg+3],false,lmp); iarg += 4; } else if (strcmp(arg[iarg+1],"delta") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform delta", error); set[index].style = DELTA; set[index].dlo = utils::numeric(FLERR,arg[iarg+2],false,lmp); set[index].dhi = utils::numeric(FLERR,arg[iarg+3],false,lmp); iarg += 4; } else if (strcmp(arg[iarg+1],"scale") == 0) { - if (iarg+3 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix deform scale", error); set[index].style = SCALE; set[index].scale = utils::numeric(FLERR,arg[iarg+2],false,lmp); iarg += 3; } else if (strcmp(arg[iarg+1],"vel") == 0) { - if (iarg+3 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix deform vel", error); set[index].style = VEL; set[index].vel = utils::numeric(FLERR,arg[iarg+2],false,lmp); iarg += 3; } else if (strcmp(arg[iarg+1],"erate") == 0) { - if (iarg+3 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix deform erate", error); set[index].style = ERATE; set[index].rate = utils::numeric(FLERR,arg[iarg+2],false,lmp); iarg += 3; } else if (strcmp(arg[iarg+1],"trate") == 0) { - if (iarg+3 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix deform trate", error); set[index].style = TRATE; set[index].rate = utils::numeric(FLERR,arg[iarg+2],false,lmp); iarg += 3; @@ -121,54 +121,52 @@ irregular(nullptr), set(nullptr) set[index].style = VOLUME; iarg += 2; } else if (strcmp(arg[iarg+1],"wiggle") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform wiggle", error); set[index].style = WIGGLE; set[index].amplitude = utils::numeric(FLERR,arg[iarg+2],false,lmp); set[index].tperiod = utils::numeric(FLERR,arg[iarg+3],false,lmp); if (set[index].tperiod <= 0.0) - error->all(FLERR,"Illegal fix deform command"); + error->all(FLERR,"Illegal fix deform wiggle period, must be positive"); iarg += 4; } else if (strcmp(arg[iarg+1],"variable") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform variable", error); set[index].style = VARIABLE; if (strstr(arg[iarg+2],"v_") != arg[iarg+2]) - error->all(FLERR,"Illegal fix deform command"); + error->all(FLERR,"Illegal fix deform variable name {}", arg[iarg+2]); if (strstr(arg[iarg+3],"v_") != arg[iarg+3]) - error->all(FLERR,"Illegal fix deform command"); + error->all(FLERR,"Illegal fix deform variable name {}", arg[iarg+3]); delete[] set[index].hstr; delete[] set[index].hratestr; set[index].hstr = utils::strdup(&arg[iarg+2][2]); set[index].hratestr = utils::strdup(&arg[iarg+3][2]); iarg += 4; } else if (strcmp(arg[iarg+1],"pressure") == 0) { - if (iarg+4 > narg) error->all(FLERR, "Illegal fix deform command"); + if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform pressure", error); set[index].style = PRESSURE; if (strstr(arg[iarg+2],"v_") != arg[iarg+2]) { set[index].ptarget = utils::numeric(FLERR,arg[iarg+2],false,lmp); } else { - if (iarg+ > narg) error->all(FLERR,"Illegal fix deform command"); set[index].pstr = utils::strdup(&arg[iarg+2][2]); - set[index].pvar = 1; + set[index].pvar_flag = 1; } set[index].pgain = utils::numeric(FLERR,arg[iarg+3],false,lmp); if (set[index].pgain <= 0.0) - error->all(FLERR,"Illegal fix deform command"); + error->all(FLERR,"Illegal fix deform pressure gain, must be positive"); iarg += 4; } else if (strcmp(arg[iarg+1],"pressure/isotropic") == 0) { - if (iarg+4 > narg) error->all(FLERR, "Illegal fix deform command"); + if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform pressure/isotropic", error); set[index].style = PISOTROPIC; if (strstr(arg[iarg+2],"v_") != arg[iarg+2]) { set[index].ptarget = utils::numeric(FLERR,arg[iarg+2],false,lmp); } else { - if (iarg+ > narg) error->all(FLERR,"Illegal fix deform command"); set[index].pstr = utils::strdup(&arg[iarg+2][2]); - set[index].pvar = 1; + set[index].pvar_flag = 1; } set[index].pgain = utils::numeric(FLERR,arg[iarg+3],false,lmp); if (set[index].pgain <= 0.0) - error->all(FLERR,"Illegal fix deform command"); + error->all(FLERR,"Illegal fix deform pressure gain, must be positive"); iarg += 4; - } error->all(FLERR,"Illegal fix deform command"); + } else error->all(FLERR,"Illegal fix deform command argument: {}", arg[iarg+1]); } else if (strcmp(arg[iarg],"xy") == 0 || strcmp(arg[iarg],"xz") == 0 || @@ -180,67 +178,66 @@ irregular(nullptr), set(nullptr) else if (strcmp(arg[iarg],"xz") == 0) index = 4; else if (strcmp(arg[iarg],"yz") == 0) index = 3; - if (iarg+2 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "fix deform", error); if (strcmp(arg[iarg+1],"final") == 0) { - if (iarg+3 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix deform final", error); set[index].style = FINAL; set[index].ftilt = utils::numeric(FLERR,arg[iarg+2],false,lmp); iarg += 3; } else if (strcmp(arg[iarg+1],"delta") == 0) { - if (iarg+3 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix deform delta", error); set[index].style = DELTA; set[index].dtilt = utils::numeric(FLERR,arg[iarg+2],false,lmp); iarg += 3; } else if (strcmp(arg[iarg+1],"vel") == 0) { - if (iarg+3 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix deform vel", error); set[index].style = VEL; set[index].vel = utils::numeric(FLERR,arg[iarg+2],false,lmp); iarg += 3; } else if (strcmp(arg[iarg+1],"erate") == 0) { - if (iarg+3 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix deform erate", error); set[index].style = ERATE; set[index].rate = utils::numeric(FLERR,arg[iarg+2],false,lmp); iarg += 3; } else if (strcmp(arg[iarg+1],"trate") == 0) { - if (iarg+3 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix deform trate", error); set[index].style = TRATE; set[index].rate = utils::numeric(FLERR,arg[iarg+2],false,lmp); iarg += 3; } else if (strcmp(arg[iarg+1],"wiggle") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform wiggle", error); set[index].style = WIGGLE; set[index].amplitude = utils::numeric(FLERR,arg[iarg+2],false,lmp); set[index].tperiod = utils::numeric(FLERR,arg[iarg+3],false,lmp); if (set[index].tperiod <= 0.0) - error->all(FLERR,"Illegal fix deform command"); + error->all(FLERR,"Illegal fix deform wiggle period, must be positive"); iarg += 4; } else if (strcmp(arg[iarg+1],"variable") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform variable", error); set[index].style = VARIABLE; if (strstr(arg[iarg+2],"v_") != arg[iarg+2]) - error->all(FLERR,"Illegal fix deform command"); + error->all(FLERR,"Illegal fix deform variable name {}", arg[iarg+2]); if (strstr(arg[iarg+3],"v_") != arg[iarg+3]) - error->all(FLERR,"Illegal fix deform command"); + error->all(FLERR,"Illegal fix deform variable name {}", arg[iarg+3]); delete[] set[index].hstr; delete[] set[index].hratestr; set[index].hstr = utils::strdup(&arg[iarg+2][2]); set[index].hratestr = utils::strdup(&arg[iarg+3][2]); iarg += 4; } else if (strcmp(arg[iarg+1],"pressure") == 0) { - if (iarg+4 > narg) error->all(FLERR, "Illegal fix deform command"); + if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform pressure", error); set[index].style = PRESSURE; if (strstr(arg[iarg+2],"v_") != arg[iarg+2]) { set[index].ptarget = utils::numeric(FLERR,arg[iarg+2],false,lmp); } else { - if (iarg+ > narg) error->all(FLERR,"Illegal fix deform command"); set[index].pstr = utils::strdup(&arg[iarg+2][2]); - set[index].pvar = 1; + set[index].pvar_flag = 1; } set[index].pgain = utils::numeric(FLERR,arg[iarg+3],false,lmp); if (set[index].pgain <= 0.0) - error->all(FLERR,"Illegal fix deform command"); + error->all(FLERR,"Illegal fix deform pressure gain, must be positive"); iarg += 4; - } else error->all(FLERR,"Illegal fix deform command"); + } else error->all(FLERR,"Illegal fix deform command: {}", arg[iarg+1]); } else break; } @@ -270,7 +267,7 @@ irregular(nullptr), set(nullptr) if (coupled_indices[i]) { set[i].coupled_flag = 1; if (set[i].style != VOLUME && set[i].style != PRESSURE && set[i].style != NONE) - error->all(FLERR, "Cannot couple dimensions not controlled by pressure or volume in fix deform"); + error->all(FLERR, "Cannot couple dimensions unless they are controlled using the pressure or volume option in fix deform"); if (set[i].style == PRESSURE || set[i].style == VOLUME) j = i; } @@ -279,30 +276,45 @@ irregular(nullptr), set(nullptr) if (j == -1) error->all(FLERR, "Must specify pressure style for a coupled dimension in fix deform"); - // Copy data to each coupled dimension + // Copy or compare data for each coupled dimension for (int i = 0; i < 3; i++) { if (coupled_indices[i]) { - if (set[j].style != set[i].style && set[i].style != NONE) - error->all(FLERR, "Cannot couple dimensions with different control options"); - + // Copy coupling information if dimension style is undefined if (set[j].style == PRESSURE && set[i].style == NONE) { set[i].style = PRESSURE; set[i].pgain = set[j].pgain; - if (set[j].pvar == 1) { + if (set[j].pvar_flag) { set[i].pstr = set[j].pstr; - set[i].pvar = 1; + set[i].pvar_flag = 1; } else { set[i].ptarget = set[j].ptarget; } } else if (set[j].style == VOLUME && set[i].style == NONE) { set[i].style = VOLUME; - set[i].saved = -1; if (domain->dimension == 2) error->all(FLERR, "Cannot couple pressure with constant volume in two dimensions"); } + + // 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[i].pgain != set[j].pgain) + error->all(FLERR, "Coupled dimensions must have identical gain parameters\n"); + + if (set[i].pvar_flag != set[j].pvar_flag) + error->all(FLERR, "Coupled dimensions must have the same target pressure\n"); + if (set[j].pvar_flag) + if (strcmp(set[i].pstr, set[j].pstr) != 0) + error->all(FLERR, "Coupled dimensions must have the same target pressure\n"); + if (set[i].ptarget != set[j].ptarget) + error->all(FLERR, "Coupled dimensions must have the same target pressure\n"); + } else { if (set[i].style == VOLUME && set[j].style == VOLUME) - error->all(FLERR, "Dimensions used to maintain constant volume must either be all be coupled or not coupled"); + error->all(FLERR, "Dimensions used to maintain constant volume must either all be coupled or uncoupled"); } } } @@ -427,6 +439,7 @@ irregular(nullptr), set(nullptr) } // set strain_flag + strain_flag = 0; for (int i = 0; i < 6; i++) if (set[i].style != NONE && set[i].style != VOLUME && @@ -569,14 +582,25 @@ void FixDeform::init() if (set[i].style != VARIABLE) continue; set[i].hvar = input->variable->find(set[i].hstr); if (set[i].hvar < 0) - error->all(FLERR,"Variable name for fix deform does not exist"); + error->all(FLERR,"Variable name {} for fix deform does not exist", set[i].hstr); if (!input->variable->equalstyle(set[i].hvar)) - error->all(FLERR,"Variable for fix deform is invalid style"); + error->all(FLERR,"Variable {} for fix deform is invalid style", set[i].hstr); set[i].hratevar = input->variable->find(set[i].hratestr); if (set[i].hratevar < 0) - error->all(FLERR,"Variable name for fix deform does not exist"); + error->all(FLERR,"Variable name {} for fix deform does not exist", set[i].hratestr); if (!input->variable->equalstyle(set[i].hratevar)) - error->all(FLERR,"Variable for fix deform is invalid style"); + error->all(FLERR,"Variable {} for fix deform is invalid style", set[i].hratestr); + } + + // check optional variables for PRESSURE or PISOTROPIC style + + for (int i = 0; i < 6; i++) { + if (!set[i].pvar_flag) continue; + set[i].pvar = input->variable->find(set[i].pstr); + if (set[i].pvar < 0) + error->all(FLERR,"Variable name {} for fix deform does not exist", set[i].pstr); + if (!input->variable->equalstyle(set[i].pvar)) + error->all(FLERR,"Variable {} for fix deform is invalid style", set[i].pstr); } // set start/stop values for box size and shape @@ -834,11 +858,6 @@ void FixDeform::pre_exchange() void FixDeform::end_of_step() { - int i; - - double delta = update->ntimestep - update->beginstep; - if (delta != 0.0) delta /= update->endstep - update->beginstep; - // wrap variable evaluations with clear/add if (varflag) modify->clearstep_compute(); @@ -853,13 +872,13 @@ void FixDeform::end_of_step() temperature->compute_vector(); pressure->compute_vector(); for (int i = 0; i < 3; i++) { - if (set[i].saved == -1) { + if (! set[i].saved) { set[i].saved = 1; - set[i].rate = 0.0; + set[i].prior_rate = 0.0; set[i].prior_pressure = pressure->vector[i]; if (i == 0) set[i].box_length = domain->xprd; else if (i == 1) set[i].box_length = domain->yprd; - else (i == 2) set[i].box_length = domain->zprd; + else set[i].box_length = domain->zprd; } } set_pressure(); @@ -880,61 +899,6 @@ void FixDeform::end_of_step() } } - // for triclinic, set new box shape - // for NONE, target is current tilt - // for TRATE, set target directly based on current time. also set h_rate - // for WIGGLE, set target directly based on current time. also set h_rate - // for VARIABLE, set target directly via variable eval. also set h_rate - // for other styles, target is linear value between start and stop values - - if (triclinic) { - double *h = domain->h; - - for (i = 3; i < 6; i++) { - if (set[i].style == NONE) { - if (i == 5) set[i].tilt_target = domain->xy; - else if (i == 4) set[i].tilt_target = domain->xz; - else if (i == 3) set[i].tilt_target = domain->yz; - } else if (set[i].style == TRATE) { - double delt = (update->ntimestep - update->beginstep) * update->dt; - set[i].tilt_target = set[i].tilt_start * exp(set[i].rate*delt); - h_rate[i] = set[i].rate * domain->h[i]; - } else if (set[i].style == WIGGLE) { - double delt = (update->ntimestep - update->beginstep) * update->dt; - set[i].tilt_target = set[i].tilt_start + - set[i].amplitude * sin(TWOPI*delt/set[i].tperiod); - h_rate[i] = TWOPI/set[i].tperiod * set[i].amplitude * - cos(TWOPI*delt/set[i].tperiod); - } else if (set[i].style == VARIABLE) { - double delta_tilt = input->variable->compute_equal(set[i].hvar); - set[i].tilt_target = set[i].tilt_start + delta_tilt; - h_rate[i] = input->variable->compute_equal(set[i].hratevar); - } else { - set[i].tilt_target = set[i].tilt_start + - delta*(set[i].tilt_stop - set[i].tilt_start); - } - - // tilt_target can be large positive or large negative value - // add/subtract box lengths until tilt_target is closest to current value - - int idenom = 0; - if (i == 5) idenom = 0; - else if (i == 4) idenom = 0; - else if (i == 3) idenom = 1; - double denom = set[idenom].hi_target - set[idenom].lo_target; - - double current = h[i]/h[idenom]; - - while (set[i].tilt_target/denom - current > 0.0) - set[i].tilt_target -= denom; - while (set[i].tilt_target/denom - current < 0.0) - set[i].tilt_target += denom; - if (fabs(set[i].tilt_target/denom - 1.0 - current) < - fabs(set[i].tilt_target/denom - current)) - set[i].tilt_target -= denom; - } - } - if (varflag) modify->addstep_compute(update->ntimestep + nevery); // if any tilt ratios exceed 0.5, set flip = 1 and compute new tilt values @@ -1006,7 +970,7 @@ void FixDeform::end_of_step() int *mask = atom->mask; int nlocal = atom->nlocal; - for (i = 0; i < nlocal; i++) + for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) domain->x2lamda(x[i],x[i]); @@ -1045,7 +1009,7 @@ void FixDeform::end_of_step() int *mask = atom->mask; int nlocal = atom->nlocal; - for (i = 0; i < nlocal; i++) + for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) domain->lamda2x(x[i],x[i]); @@ -1079,6 +1043,9 @@ void FixDeform::set_strain() // for VARIABLE, set target directly via variable eval, also set h_rate // for others except VOLUME, target is linear value between start and stop + double delta = update->ntimestep - update->beginstep; + if (delta != 0.0) delta /= update->endstep - update->beginstep; + for (int i = 0; i < 3; i++) { if (set[i].style == NONE) { set[i].lo_target = domain->boxlo[i]; @@ -1113,6 +1080,62 @@ void FixDeform::set_strain() delta*(set[i].hi_stop - set[i].hi_start); } } + + + // for triclinic, set new box shape + // for NONE, target is current tilt + // for TRATE, set target directly based on current time. also set h_rate + // for WIGGLE, set target directly based on current time. also set h_rate + // for VARIABLE, set target directly via variable eval. also set h_rate + // for other styles, target is linear value between start and stop values + + if (triclinic) { + double *h = domain->h; + + for (int i = 3; i < 6; i++) { + if (set[i].style == NONE) { + if (i == 5) set[i].tilt_target = domain->xy; + else if (i == 4) set[i].tilt_target = domain->xz; + else if (i == 3) set[i].tilt_target = domain->yz; + } else if (set[i].style == TRATE) { + double delt = (update->ntimestep - update->beginstep) * update->dt; + set[i].tilt_target = set[i].tilt_start * exp(set[i].rate*delt); + h_rate[i] = set[i].rate * domain->h[i]; + } else if (set[i].style == WIGGLE) { + double delt = (update->ntimestep - update->beginstep) * update->dt; + set[i].tilt_target = set[i].tilt_start + + set[i].amplitude * sin(TWOPI*delt/set[i].tperiod); + h_rate[i] = TWOPI/set[i].tperiod * set[i].amplitude * + cos(TWOPI*delt/set[i].tperiod); + } else if (set[i].style == VARIABLE) { + double delta_tilt = input->variable->compute_equal(set[i].hvar); + set[i].tilt_target = set[i].tilt_start + delta_tilt; + h_rate[i] = input->variable->compute_equal(set[i].hratevar); + } else { + set[i].tilt_target = set[i].tilt_start + + delta*(set[i].tilt_stop - set[i].tilt_start); + } + + // tilt_target can be large positive or large negative value + // add/subtract box lengths until tilt_target is closest to current value + + int idenom = 0; + if (i == 5) idenom = 0; + else if (i == 4) idenom = 0; + else if (i == 3) idenom = 1; + double denom = set[idenom].hi_target - set[idenom].lo_target; + + double current = h[i]/h[idenom]; + + while (set[i].tilt_target/denom - current > 0.0) + set[i].tilt_target -= denom; + while (set[i].tilt_target/denom - current < 0.0) + set[i].tilt_target += denom; + if (fabs(set[i].tilt_target/denom - 1.0 - current) < + fabs(set[i].tilt_target/denom - current)) + set[i].tilt_target -= denom; + } + } } /* ---------------------------------------------------------------------- @@ -1121,13 +1144,59 @@ void FixDeform::set_strain() void FixDeform::set_pressure() { - for (int i = 0; i < 3; i++) { - + // If variable pressure, calculate current target + for (int i = 0; i < 6; i++) + if (set[i].style == PRESSURE) + if (set[i].pvar_flag) + set[i].ptarget = input->variable->compute_equal(set[i].pvar); + + // Find current (possibly coupled/hydrostatic) pressure for X, Y, Z + double *tensor = pressure->vector; + double scalar = pressure->scalar; + double p_current[3]; + + if (pcouple == XYZ) { + double ave = 1.0/3.0 * (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 == PISOTROPIC) p_current[0] = scalar; + + if (set[1].style == PRESSURE) p_current[1] = tensor[1]; + else if (set[1].style == PISOTROPIC) p_current[1] = scalar; + + if (set[2].style == PRESSURE) p_current[2] = tensor[2]; + else if (set[2].style == PISOTROPIC) p_current[2] = scalar; + } + for (int i = 0; i < 3; i++) { + if (set[i].style != PRESSURE && set[i].style != PISOTROPIC) continue; + double dilation = 1.0 - update->dt * set[i].pgain * (set[i].ptarget - p_current[i]); + double center_start = 0.5 * (set[i].lo_start + set[i].hi_start); + double offset = 0.5 * set[i].box_length * dilation; + //printf("ptarget %g vs %g, dilation %g cs %g ofset %g box %g\n", set[i].ptarget, p_current[i], dilation, center_start, offset, set[i].box_length); + set[i].lo_target = center_start - offset; + set[i].hi_target = center_start + offset; } - // must define hi+lo target - // + for (int i = 3; i < 6; i++) { + double shift = update->dt * set[i].pgain * (set[i].ptarget - tensor[i]); + if (i == 3) set[i].tilt_target = domain->xy + shift * domain->xprd; + else if (i == 4) set[i].tilt_target = domain->xz + shift * domain->xprd; + else set[i].tilt_target = domain->yz + shift * domain->yprd; + } } /* ---------------------------------------------------------------------- @@ -1136,6 +1205,9 @@ void FixDeform::set_pressure() void FixDeform::set_volume() { + double e1, e2; + int linked_pressure = 0; + for (int i = 0; i < 3; i++) { if (set[i].style != VOLUME) continue; @@ -1150,28 +1222,46 @@ void FixDeform::set_volume() } else if (set[i].substyle == ONE_FROM_TWO) { offset = 0.5 * (v0 / (set[set[i].dynamic1].hi_target - set[set[i].dynamic1].lo_target) / - (set[set[i].dynamic2].hi_target - set[set[i].dynamic2].lo_target)) + (set[set[i].dynamic2].hi_target - set[set[i].dynamic2].lo_target)); } else if (set[i].substyle == TWO_FROM_ONE) { if (!set[i].coupled_flag) { offset = 0.5 * sqrt(v0 * (set[i].hi_start - set[i].lo_start) / (set[set[i].dynamic1].hi_target - set[set[i].dynamic1].lo_target) / - (set[set[i].fixed].hi_start - set[set[i].fixed].lo_start)) + (set[set[i].fixed].hi_start - set[set[i].fixed].lo_start)); } else { + double dt = update->dt; + double e1i = set[i].prior_rate; + double e2i = set[set[i].fixed].prior_rate; + double L3 = (set[set[i].dynamic1].hi_target - set[set[i].dynamic1].lo_target); + double e3 = (L3 / set[set[i].dynamic1].box_length - 1.0) / dt; double p1 = pressure->vector[i]; double p2 = pressure->vector[set[i].fixed]; double p1i = set[i].prior_pressure; double p2i = set[set[i].fixed].prior_pressure; - double e1i = set[i].prior_rate; - double e2i = set[set[i].fixed].prior_rate; - double L3 = (set[set[i].dynamic1].hi_target - set[set[i].dynamic1].lo_target); - double dt = update->dt; - double e3 = (L3 / set[set[i].dynamic1].box_length - 1.0) / dt; - double e1 = -e3 * dt / (1 + e3 * dt) * (p2 - p2i) - e2i * (p1 - p2); - e1 /= (p2 - p2i + (p1 - p1i) / e1p * e2p); - double e2 = (1.0 - (1 + e3 * dt) * (1 + e1 * dt)); - e2 /= (1 + e3 * dt) * (1 + e1 * dt) * dt; - offset = 0.5 * set[i].box_length * (1.0 - e3 * dt); + if (e3 == 0) { + e1 = 0.0; + e2 = 0.0; + offset = 0.5 * set[i].box_length; + } else if (e1i == 0 || e2i == 0 || (p2 == p2i && p1 == p1i)) { + // If no prior strain or no change in pressure (initial step) just scale offset by relative box lengths + offset = 0.5 * sqrt(v0 * set[i].box_length / L3 / set[set[i].fixed].box_length); + } else { + if (! linked_pressure) { + // Calculate first strain rate by expanding stress to linear order in strain to achieve p1(t+dt) = p2(t+dt) + e1 = -e3 / (1 + e3 * dt) * (p2 - p2i) - e2i * (p1 - p2); + e1 /= (p2 - p2i + (p1 - p1i) / e1i * e2i); + + // Calculate second strain rate to preserve volume + e2 = (1.0 - (1 + e3 * dt) * (1 + e1 * dt)); + e2 /= (1 + e3 * dt) * (1 + e1 * dt) * dt; + + offset = 0.5 * set[i].box_length * (1.0 + e1 * dt); + linked_pressure = 1; + } else { + offset = 0.5 * set[i].box_length * (1.0 + e2 * dt); + } + } } } set[i].lo_target = center_start - offset; @@ -1229,33 +1319,32 @@ void FixDeform::options(int narg, char **arg) int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"remap") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "fix deform remap", error); if (strcmp(arg[iarg+1],"x") == 0) remapflag = Domain::X_REMAP; else if (strcmp(arg[iarg+1],"v") == 0) remapflag = Domain::V_REMAP; else if (strcmp(arg[iarg+1],"none") == 0) remapflag = Domain::NO_REMAP; - else error->all(FLERR,"Illegal fix deform command"); + else error->all(FLERR,"Illegal fix deform remap command: {}", arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"units") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "fix deform units", error); if (strcmp(arg[iarg+1],"box") == 0) scaleflag = 0; else if (strcmp(arg[iarg+1],"lattice") == 0) scaleflag = 1; - else error->all(FLERR,"Illegal fix deform command"); + else error->all(FLERR,"Illegal fix deform units command: {}", arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"flip") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal fix deform command"); + if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "fix deform flip", error); flipflag = utils::logical(FLERR,arg[iarg+1],false,lmp); iarg += 2; } else if (strcmp(arg[iarg],"couple") == 0) { - if (iarg+2 > narg) - error->all(FLERR,"Illegal fix fix deform command"); + if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "fix deform 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 fix deform command"); + else error->all(FLERR,"Illegal fix fix deform couple command: {}", arg[iarg+1]); iarg += 2; - } else error->all(FLERR,"Illegal fix deform command"); + } else error->all(FLERR,"Illegal fix deform command: {}", arg[iarg]); } if (dimension == 2) @@ -1281,7 +1370,7 @@ int FixDeform::modify_param(int narg, char **arg) { if (!pressure_flag) error->all(FLERR,"Cannot modify fix deform without a pressure control"); if (strcmp(arg[0],"temp") == 0) { - if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); + if (narg < 2) utils::missing_cmd_args(FLERR, "fix_modify deform", error); if (tflag) { modify->delete_compute(id_temp); tflag = 0; diff --git a/src/fix_deform.h b/src/fix_deform.h index 7297874258c..9ecb9a577dd 100644 --- a/src/fix_deform.h +++ b/src/fix_deform.h @@ -77,12 +77,14 @@ class FixDeform : public Fix { int fixed, dynamic1, dynamic2; char *hstr, *hratestr, *pstr; int hvar, hratevar; - int pvar; + int pvar, pvar_flag; int coupled_flag; }; Set *set; void options(int, char **); + void set_strain(); + void set_pressure(); void set_volume(); void couple(); }; From 173e2382b3c3752439b601e7fa88f1a7523b50ce Mon Sep 17 00:00:00 2001 From: jtclemm Date: Sat, 22 Oct 2022 19:03:52 -0600 Subject: [PATCH 03/29] Adding documentation, various updates --- doc/src/fix_deform.rst | 169 ++++++++++++++- src/fix_deform.cpp | 482 ++++++++++++++++++++++------------------- src/fix_deform.h | 7 +- 3 files changed, 425 insertions(+), 233 deletions(-) diff --git a/doc/src/fix_deform.rst b/doc/src/fix_deform.rst index 805bd843827..d46f1204f5e 100644 --- a/doc/src/fix_deform.rst +++ b/doc/src/fix_deform.rst @@ -34,6 +34,12 @@ Syntax effectively an engineering strain rate *erate* value = R R = engineering strain rate (1/time units) + *pressure* values = target gain + target = target pressure (pressure units) + gain = proportional gain constant (1/(time * pressure) or 1/time units) + *pressure/mean* values = target gain + target = target pressure (pressure units) + gain = proportional gain constant (1/(time * pressure) or 1/time units) *trate* value = R R = true strain rate (1/time units) *volume* value = none = adjust this dim to preserve volume of system @@ -54,6 +60,9 @@ Syntax effectively an engineering shear strain rate *erate* value = R R = engineering shear strain rate (1/time units) + *pressure* values = target gain + target = target pressure (pressure units) + gain = proportional gain constant (1/(time * pressure) or 1/time units) *trate* value = R R = true shear strain rate (1/time units) *wiggle* values = A Tp @@ -64,7 +73,7 @@ Syntax v_name2 = variable with name2 for change rate as function of time * zero or more keyword/value pairs may be appended -* keyword = *remap* or *flip* or *units* +* keyword = *remap* or *flip* or *units* or *couple* or *vol/balance/p* or *max/rate* or *normalize/pressure* .. parsed-literal:: @@ -77,6 +86,14 @@ Syntax *units* value = *lattice* or *box* lattice = distances are defined in lattice units box = distances are defined in simulation box units + *couple* value = *none* or *xyz* or *xy* or *yz* or *xz* + couple pressure values of various dimensions + *vol/balance/p* = *yes* or *no* + Modifies the behavior of the *volume* option to try and balance pressures + *max/rate* value = *rate* + rate = maximum strain rate for pressure control + *normalize/pressure* value = *yes* or *no* + determine whether pressure deviation is normalized by target pressure Examples """""""" @@ -87,6 +104,9 @@ Examples fix 1 all deform 1 x trate 0.1 y volume z volume fix 1 all deform 1 xy erate 0.001 remap v fix 1 all deform 10 y delta -0.5 0.5 xz vel 1.0 + fix 1 all deform 1 x pressure 2.0 0.1 normalize/pressure yes max/rate 0.001 + fix 1 all deform 1 x trate 0.1 y volume z volume vol/balance/p yes + fix 1 all deform 1 x trate 0.1 y pressure/mean 0.0 1.0 z pressure/mean 0.0 1.0 Description """"""""""" @@ -230,7 +250,11 @@ the product of x,z lengths constant. If "x scale 1.1 y volume z volume" is specified, then both the y,z box lengths will shrink as x increases to keep the volume constant (product of x,y,z lengths). In this case, the y,z box lengths shrink so as to keep their relative -aspect ratio constant. +aspect ratio constant. When maintaining a constant volume using two +separate dimensions, one can alternatively allow the two dimensions +to adjust their aspect ratio to attempt to maintain equivalent +pressures along the two dimensions. See the +:ref:`vol/balance/p ` option for more details. For solids or liquids, note that when one dimension of the box is expanded via fix deform (i.e. tensile strain), it may be physically @@ -292,6 +316,38 @@ For the *scale*, *vel*, *erate*, *trate*, *volume*, *wiggle*, and *variable* styles, the box length is expanded or compressed around its mid point. +The *pressure* style adjusts a dimensions's box length to control that +component of the pressure tensor. This option attempts to maintain a +specified target value using a linear controller where the box length L +evolves according to the equation + +.. parsed-literal:: + + \frac{d L(t)}{dt} = L(t) k (P_t - P) + +where :math:`k` is a proportional gain constant, :math:`P_t` is the target +pressure, and :math:`P` is the current pressure along that dimension. This +approach is similar to the method used to control the pressure by +:doc:`fix press/berendsen `. The target pressure +accepts either a constant numeric value or a LAMMPS :ref:`variable `. +Notably, this variable can be a function of time or other components of +the pressure tensor. By default, :math:`k` has units of 1/(time * pressure) +although this will change if the *normalize/pessure* option is set as +:ref:`discussed below `. There is no proven method +to choosing an appropriate value of :math:`k` as it will depend on the +specific details of a simulation and testing different values is +recommended. One can also apply a maximum limit to the magnitude of the +applied strain using the :ref:`max/rate ` option and couple +pressures in different dimensions using the :ref:`couple ` +option. + +The *pressure/mean* style is changes a dimension in order to maintain +a constant mean pressure defined as the trace of the pressure tensor. +This option is therefore very similar to the *presssure* style with +identical arguments except the current and target pressures refer to the +mean trace of the pressure tensor. The same options also apply except +for the :ref:`couple ` option. + ---------- For the *xy*, *xz*, and *yz* parameters, this is the meaning of their @@ -433,6 +489,27 @@ assume that the current timestep = 0. variable rate equal "2*PI*v_A/v_Tp * cos(2*PI * step*dt/v_Tp)" fix 2 all deform 1 xy variable v_displace v_rate remap v +The *pressure* style adjusts a tilt factor to control the corresponding +off-diagonal component of the pressure tensor. This option attempts to +maintain a specified target value using a linear controller where the +tilt factor T evolves according to the equation + +.. parsed-literal:: + + \frac{d T(t)}{dt} = L(t) k (P - P_t) + +where :math:`k` is a proportional gain constant, :math:`P_t` is the target +pressure, :math:`P` is the current pressure, and :math:`L` is the perpendicular +box length. The target pressure accepts either a constant numeric value or a +LAMMPS :ref:`variable `. Notably, this variable can be a function +of time or other components of the pressure tensor. By default, :math:`k` +has units of 1/(time * pressure) although this will change if the +*normalize/pessure* option is set as :ref:`discussed below `. +There is no proven method to choosing an appropriate value of :math:`k` as it +will depend on thespecific details of a simulation and testing different +values isrecommended. One can also apply a maximum limit to the magnitude +of the applied strain using the :ref:`max/rate ` option. + ---------- All of the tilt styles change the xy, xz, yz tilt factors during a @@ -561,6 +638,73 @@ does not affect the *variable* style. You should use the *xlat*, *ylat*, *zlat* keywords of the :doc:`thermo_style ` command if you want to include lattice spacings in a variable formula. +.. _deform_normalize: + +The *normalize/pressure* keyword changes how box dimensions evolve when +using the *pressure* or *pressure/mean* deformation options. If the +*deform/normalize* value is set to *yes*, then the deviation from the +target pressure is normalized by the absolute value of the target +pressure such that the proportional gain constant scales a percentage +error and has units of 1/time. If the target pressure is ever zero, this +will produce an error unless the *max/rate* keyword is defined, +described below, which will cap the divergence. + +.. _deform_max_rate: + +The *max/rate* keyword sets an upper threshold, *rate*, that limits the +maximum magnitude of the strain rate applied in any dimension. This keyword +only applies to the *pressure* and *pressure/mean* options. + +.. _deform_couple: + +The *couple* keyword allows two or three of the diagonal components of +the pressure tensor to be "coupled" together for the *pressure* option. +The value specified with the keyword determines which are coupled. For +example, *xz* means the *Pxx* and *Pzz* components of the stress tensor +are coupled. *Xyz* means all 3 diagonal components are coupled. Coupling +means two things: the instantaneous stress will be computed as an average +of the corresponding diagonal components, and the coupled box dimensions +will be changed together in lockstep, meaning coupled dimensions will be +dilated or contracted by the same percentage every timestep. The target +pressures and gain constants for any coupled dimensions must be identical. +*Couple xyz* can be used for a 2d simulation; the *z* dimension is simply +ignored. + +.. _deform_balance: + +The *vol/balance/p* keyword modifies the behavior of *volume* when two +dimensions are used to maintain a fixed volume. Instead of straining +the two dimensions in lockstep, the two dimensions are allowed to +separately dilate or contract in a manner to maintain a constant +volume while simultaneously trying to keep the pressure along each +dimension equal using a method described in :ref:`(Huang2014) `. + +---------- + +If any pressure controls are used, this fix computes a temperature and +pressure each timestep. To do this, the fix creates its own computes of +style "temp" and "pressure", as if these commands had been issued: + +.. code-block:: LAMMPS + + compute fix-ID_temp group-ID temp + compute fix-ID_press group-ID pressure fix-ID_temp + +See the :doc:`compute temp ` and :doc:`compute pressure ` commands for details. Note that the +IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID ++ underscore + "press", and the group for the new computes is the same +as the fix group. + +Note that these are NOT the computes used by thermodynamic output (see +the :doc:`thermo_style ` command) with ID = *thermo_temp* +and *thermo_press*. This means you can change the attributes of this +fix's temperature or pressure via the +:doc:`compute_modify ` command or print this temperature +or pressure during thermodynamic output via the +:doc:`thermo_style custom ` command using the appropriate +compute-ID. It also means that changing attributes of *thermo_temp* or +*thermo_press* will have no effect on this fix. + ---------- .. include:: accel_styles.rst @@ -574,6 +718,15 @@ command. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored by this fix for access by various :doc:`output commands `. +If any pressure controls are used, the :doc:`fix_modify ` *temp* +and *press* options are supported by this fix. You can use them to assign a +:doc:`compute ` you have defined to this fix which will be used +in its temperature and pressure calculations. If you do this, note +that the kinetic energy derived from the compute temperature should be +consistent with the virial term computed using all atoms for the +pressure. LAMMPS will warn you if you choose to compute temperature +on a subset of atoms. + This fix can perform deformation over multiple runs, using the *start* and *stop* keywords of the :doc:`run ` command. See the :doc:`run ` command for details of how to do this. @@ -597,4 +750,14 @@ Related commands Default """"""" -The option defaults are remap = x, flip = yes, and units = lattice. +The option defaults are remap = x, flip = yes, units = lattice, and +normalize/pressure = no. + +---------- + +.. _Li2014b: + +**(Huang2014)** X. Huang, +"Exploring critical-state behavior using DEM", +Doctoral dissertation, Imperial College. +(2014). https://doi.org/10.25560/25316 diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index 766d7c22ae6..db3fad6a958 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -13,13 +13,9 @@ ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- - Contributing author: Pieter in 't Veld (SNL) + Contributing author: Pieter in 't Veld (SNL), Joel Clemmer (SNL) ------------------------------------------------------------------------- */ -// Save previous state to restart file for derivatives -// define hrate_lo/hi for volume/pressure -// add logic for hi_stop and flip flag - #include "fix_deform.h" #include "atom.h" @@ -44,7 +40,7 @@ using namespace LAMMPS_NS; using namespace FixConst; using namespace MathConst; -enum{NONE=0,FINAL,DELTA,SCALE,VEL,ERATE,TRATE,VOLUME,WIGGLE,VARIABLE,PRESSURE,PISOTROPIC}; +enum{NONE=0,FINAL,DELTA,SCALE,VEL,ERATE,TRATE,VOLUME,WIGGLE,VARIABLE,PRESSURE,PMEAN}; enum{ONE_FROM_ONE,ONE_FROM_TWO,TWO_FROM_ONE}; enum{NOCOUPLE=0,XYZ,XY,YZ,XZ}; @@ -60,6 +56,9 @@ irregular(nullptr), set(nullptr) pre_exchange_migrate = 1; pcouple = NOCOUPLE; dimension = domain->dimension; + max_h_rate = 0.0; + vol_balance_flag = 0; + normalize_pressure_flag = 0; nevery = utils::inumeric(FLERR,arg[3],false,lmp); if (nevery <= 0) error->all(FLERR,"Illegal fix deform command"); @@ -153,9 +152,9 @@ irregular(nullptr), set(nullptr) if (set[index].pgain <= 0.0) error->all(FLERR,"Illegal fix deform pressure gain, must be positive"); iarg += 4; - } else if (strcmp(arg[iarg+1],"pressure/isotropic") == 0) { - if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform pressure/isotropic", error); - set[index].style = PISOTROPIC; + } else if (strcmp(arg[iarg+1],"pressure/mean") == 0) { + if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform pressure/mean", error); + set[index].style = PMEAN; if (strstr(arg[iarg+2],"v_") != arg[iarg+2]) { set[index].ptarget = utils::numeric(FLERR,arg[iarg+2],false,lmp); } else { @@ -266,21 +265,21 @@ irregular(nullptr), set(nullptr) for (int i = 0; i < 3; i++) { if (coupled_indices[i]) { set[i].coupled_flag = 1; - if (set[i].style != VOLUME && set[i].style != PRESSURE && set[i].style != NONE) - error->all(FLERR, "Cannot couple dimensions unless they are controlled using the pressure or volume option in fix deform"); - if (set[i].style == PRESSURE || set[i].style == VOLUME) + 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 pressure style for a coupled dimension in fix deform"); + 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[j].style == PRESSURE && set[i].style == NONE) { + if (set[i].style == NONE) { set[i].style = PRESSURE; set[i].pgain = set[j].pgain; if (set[j].pvar_flag) { @@ -289,32 +288,21 @@ irregular(nullptr), set(nullptr) } else { set[i].ptarget = set[j].ptarget; } - } else if (set[j].style == VOLUME && set[i].style == NONE) { - set[i].style = VOLUME; - if (domain->dimension == 2) - error->all(FLERR, "Cannot couple pressure with constant volume in two dimensions"); + } 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[i].pgain != set[j].pgain || set[i].pvar_flag != set[j].pvar_flag || + set[i].ptarget != set[j].ptarget) + error->all(FLERR, "Coupled dimensions must have identical gain parameters"); + + if (set[j].pvar_flag) + if (strcmp(set[i].pstr, set[j].pstr) != 0) + error->all(FLERR, "Coupled dimensions must have the same target pressure"); } - - // 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[i].pgain != set[j].pgain) - error->all(FLERR, "Coupled dimensions must have identical gain parameters\n"); - - if (set[i].pvar_flag != set[j].pvar_flag) - error->all(FLERR, "Coupled dimensions must have the same target pressure\n"); - if (set[j].pvar_flag) - if (strcmp(set[i].pstr, set[j].pstr) != 0) - error->all(FLERR, "Coupled dimensions must have the same target pressure\n"); - if (set[i].ptarget != set[j].ptarget) - error->all(FLERR, "Coupled dimensions must have the same target pressure\n"); - - } else { - if (set[i].style == VOLUME && set[j].style == VOLUME) - error->all(FLERR, "Dimensions used to maintain constant volume must either all be coupled or uncoupled"); } } } @@ -335,27 +323,18 @@ irregular(nullptr), set(nullptr) // no tensile deformation on shrink-wrapped dims // b/c shrink wrap will change box-length - if (set[0].style && - (domain->boundary[0][0] >= 2 || domain->boundary[0][1] >= 2)) - error->all(FLERR,"Cannot use fix deform on a shrink-wrapped boundary"); - if (set[1].style && - (domain->boundary[1][0] >= 2 || domain->boundary[1][1] >= 2)) - error->all(FLERR,"Cannot use fix deform on a shrink-wrapped boundary"); - if (set[2].style && - (domain->boundary[2][0] >= 2 || domain->boundary[2][1] >= 2)) + for (int i = 0; i < 3; i++) + if (set[i].style && (domain->boundary[i][0] >= 2 || domain->boundary[i][1] >= 2)) error->all(FLERR,"Cannot use fix deform on a shrink-wrapped boundary"); // 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)) + if (set[3].style && (domain->boundary[2][0] >= 2 || domain->boundary[2][1] >= 2)) error->all(FLERR,"Cannot use fix deform tilt on a shrink-wrapped 2nd dim"); - if (set[4].style && - (domain->boundary[2][0] >= 2 || domain->boundary[2][1] >= 2)) + if (set[4].style && (domain->boundary[2][0] >= 2 || domain->boundary[2][1] >= 2)) error->all(FLERR,"Cannot use fix deform tilt on a shrink-wrapped 2nd dim"); - if (set[5].style && - (domain->boundary[1][0] >= 2 || domain->boundary[1][1] >= 2)) + if (set[5].style && (domain->boundary[1][0] >= 2 || domain->boundary[1][1] >= 2)) error->all(FLERR,"Cannot use fix deform tilt on a shrink-wrapped 2nd dim"); // apply scaling to FINAL,DELTA,VEL,WIGGLE since they have dist/vel units @@ -436,6 +415,9 @@ irregular(nullptr), set(nullptr) set[i].dynamic1 = other1; set[i].dynamic2 = other2; } + + if (vol_balance_flag && 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 @@ -443,30 +425,41 @@ irregular(nullptr), set(nullptr) 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 != PISOTROPIC) + set[i].style != PRESSURE && set[i].style != PMEAN) strain_flag = 1; // set varflag varflag = 0; - for (int i = 0; i < 6; i++) + for (int i = 0; i < 6; i++) { if (set[i].style == VARIABLE) varflag = 1; + if (set[i].pvar_flag) varflag = 1; + } // set pressure_flag pressure_flag = 0; for (int i = 0; i < 6; i++) { - if (set[i].style == PRESSURE || set[i].style == PISOTROPIC) pressure_flag = 1; + if (set[i].style == PRESSURE || set[i].style == PMEAN) pressure_flag = 1; if (set[i].coupled_flag) pressure_flag = 1; } + if (vol_balance_flag) pressure_flag = 1; // check conflict between constant volume/pressure if (volume_flag) for (int i = 0; i < 6; i++) - if (set[i].style == PISOTROPIC) + if (set[i].style == PMEAN) error->all(FLERR, "Cannot use fix deform to assign constant volume and pressure"); + // 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"); + // set initial values at time fix deform is issued for (int i = 0; i < 3; i++) { @@ -489,8 +482,6 @@ irregular(nullptr), set(nullptr) if (force_reneighbor) irregular = new Irregular(lmp); else irregular = nullptr; - TWOPI = 2.0*MY_PI; - // Create pressure compute, if needed pflag = 0; @@ -592,7 +583,7 @@ void FixDeform::init() error->all(FLERR,"Variable {} for fix deform is invalid style", set[i].hratestr); } - // check optional variables for PRESSURE or PISOTROPIC style + // check optional variables for PRESSURE or PMEAN style for (int i = 0; i < 6; i++) { if (!set[i].pvar_flag) continue; @@ -627,30 +618,26 @@ void FixDeform::init() set[i].lo_stop = set[i].lo_start + set[i].dlo; set[i].hi_stop = set[i].hi_start + set[i].dhi; } else if (set[i].style == SCALE) { - set[i].lo_stop = 0.5*(set[i].lo_start+set[i].hi_start) - - 0.5*set[i].scale*(set[i].hi_start-set[i].lo_start); - set[i].hi_stop = 0.5*(set[i].lo_start+set[i].hi_start) + - 0.5*set[i].scale*(set[i].hi_start-set[i].lo_start); + double shift = 0.5 * set[i].scale * (set[i].hi_start - set[i].lo_start); + set[i].lo_stop = 0.5 * (set[i].lo_start + set[i].hi_start) - shift; + set[i].hi_stop = 0.5 * (set[i].lo_start + set[i].hi_start) + shift; } else if (set[i].style == VEL) { - set[i].lo_stop = set[i].lo_start - 0.5*delt*set[i].vel; - set[i].hi_stop = set[i].hi_start + 0.5*delt*set[i].vel; + set[i].lo_stop = set[i].lo_start - 0.5 * delt * set[i].vel; + set[i].hi_stop = set[i].hi_start + 0.5 * delt * set[i].vel; } else if (set[i].style == ERATE) { - set[i].lo_stop = set[i].lo_start - - 0.5*delt*set[i].rate * (set[i].hi_start-set[i].lo_start); - set[i].hi_stop = set[i].hi_start + - 0.5*delt*set[i].rate * (set[i].hi_start-set[i].lo_start); + double shift = 0.5 * delt * set[i].rate * (set[i].hi_start - set[i].lo_start); + set[i].lo_stop = set[i].lo_start - shift; + set[i].hi_stop = set[i].hi_start + shift; if (set[i].hi_stop <= set[i].lo_stop) error->all(FLERR,"Final box dimension due to fix deform is < 0.0"); } else if (set[i].style == TRATE) { - set[i].lo_stop = 0.5*(set[i].lo_start+set[i].hi_start) - - 0.5*((set[i].hi_start-set[i].lo_start) * exp(set[i].rate*delt)); - set[i].hi_stop = 0.5*(set[i].lo_start+set[i].hi_start) + - 0.5*((set[i].hi_start-set[i].lo_start) * exp(set[i].rate*delt)); + double shift = 0.5 * ((set[i].hi_start - set[i].lo_start) * exp(set[i].rate * delt)); + set[i].lo_stop = 0.5 * (set[i].lo_start + set[i].hi_start) - shift; + set[i].hi_stop = 0.5 * (set[i].lo_start + set[i].hi_start) + shift; } else if (set[i].style == WIGGLE) { - set[i].lo_stop = set[i].lo_start - - 0.5*set[i].amplitude * sin(TWOPI*delt/set[i].tperiod); - set[i].hi_stop = set[i].hi_start + - 0.5*set[i].amplitude * sin(TWOPI*delt/set[i].tperiod); + double shift = 0.5 * set[i].amplitude * sin(MY_2PI * delt / set[i].tperiod); + set[i].lo_stop = set[i].lo_start - shift; + set[i].hi_stop = set[i].hi_start + shift; } } @@ -666,50 +653,46 @@ void FixDeform::init() } else if (set[i].style == DELTA) { set[i].tilt_stop = set[i].tilt_start + set[i].dtilt; } else if (set[i].style == VEL) { - set[i].tilt_stop = set[i].tilt_start + delt*set[i].vel; + set[i].tilt_stop = set[i].tilt_start + delt * set[i].vel; } else if (set[i].style == ERATE) { if (i == 3) set[i].tilt_stop = set[i].tilt_start + - delt*set[i].rate * (set[2].hi_start-set[2].lo_start); + delt * set[i].rate * (set[2].hi_start - set[2].lo_start); if (i == 4) set[i].tilt_stop = set[i].tilt_start + - delt*set[i].rate * (set[2].hi_start-set[2].lo_start); + delt * set[i].rate * (set[2].hi_start - set[2].lo_start); if (i == 5) set[i].tilt_stop = set[i].tilt_start + - delt*set[i].rate * (set[1].hi_start-set[1].lo_start); + delt * set[i].rate * (set[1].hi_start - set[1].lo_start); } else if (set[i].style == TRATE) { - set[i].tilt_stop = set[i].tilt_start * exp(set[i].rate*delt); + set[i].tilt_stop = set[i].tilt_start * exp(set[i].rate * delt); } else if (set[i].style == WIGGLE) { - set[i].tilt_stop = set[i].tilt_start + - set[i].amplitude * sin(TWOPI*delt/set[i].tperiod); + double shift = set[i].amplitude * sin(MY_2PI * delt / set[i].tperiod); + set[i].tilt_stop = set[i].tilt_start + shift; // compute min/max for WIGGLE = extrema tilt factor will ever reach if (set[i].amplitude >= 0.0) { - if (delt < 0.25*set[i].tperiod) { + if (delt < 0.25 * set[i].tperiod) { set[i].tilt_min = set[i].tilt_start; - set[i].tilt_max = set[i].tilt_start + - set[i].amplitude*sin(TWOPI*delt/set[i].tperiod); - } else if (delt < 0.5*set[i].tperiod) { + set[i].tilt_max = set[i].tilt_start + shift; + } else if (delt < 0.5 * set[i].tperiod) { set[i].tilt_min = set[i].tilt_start; set[i].tilt_max = set[i].tilt_start + set[i].amplitude; - } else if (delt < 0.75*set[i].tperiod) { - set[i].tilt_min = set[i].tilt_start - - set[i].amplitude*sin(TWOPI*delt/set[i].tperiod); + } else if (delt < 0.75 * set[i].tperiod) { + set[i].tilt_min = set[i].tilt_start - shift; set[i].tilt_max = set[i].tilt_start + set[i].amplitude; } else { set[i].tilt_min = set[i].tilt_start - set[i].amplitude; set[i].tilt_max = set[i].tilt_start + set[i].amplitude; } } else { - if (delt < 0.25*set[i].tperiod) { - set[i].tilt_min = set[i].tilt_start - - set[i].amplitude*sin(TWOPI*delt/set[i].tperiod); + if (delt < 0.25 * set[i].tperiod) { + set[i].tilt_min = set[i].tilt_start - shift; set[i].tilt_max = set[i].tilt_start; - } else if (delt < 0.5*set[i].tperiod) { + } else if (delt < 0.5 * set[i].tperiod) { set[i].tilt_min = set[i].tilt_start - set[i].amplitude; set[i].tilt_max = set[i].tilt_start; - } else if (delt < 0.75*set[i].tperiod) { + } else if (delt < 0.75 * set[i].tperiod) { set[i].tilt_min = set[i].tilt_start - set[i].amplitude; - set[i].tilt_max = set[i].tilt_start + - set[i].amplitude*sin(TWOPI*delt/set[i].tperiod); + set[i].tilt_max = set[i].tilt_start + shift; } else { set[i].tilt_min = set[i].tilt_start - set[i].amplitude; set[i].tilt_max = set[i].tilt_start + set[i].amplitude; @@ -729,25 +712,25 @@ void FixDeform::init() // 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 - // VARIABLE for yz is error, since no way to calculate if box flip occurs + // VARIABLE or PRESSURE for yz is error, since no way to calculate if box flip occurs // WIGGLE lo/hi flip test is on min/max oscillation limit, not tilt_stop // only trigger actual errors if flipflag is set if (set[3].style && set[5].style) { int flag = 0; double lo,hi; - if (flipflag && set[3].style == VARIABLE) - error->all(FLERR,"Fix deform cannot use yz variable with xy"); + if (flipflag && (set[3].style == VARIABLE || set[3].style == PRESSURE)) + error->all(FLERR,"Fix deform cannot use yz variable or pressure with xy"); if (set[3].style == WIGGLE) { lo = set[3].tilt_min; hi = set[3].tilt_max; } else lo = hi = set[3].tilt_stop; if (flipflag) { - if (lo/(set[1].hi_start-set[1].lo_start) < -0.5 || - hi/(set[1].hi_start-set[1].lo_start) > 0.5) flag = 1; + if (lo / (set[1].hi_start - set[1].lo_start) < -0.5 || + hi / (set[1].hi_start - set[1].lo_start) > 0.5) flag = 1; if (set[1].style) { - if (lo/(set[1].hi_stop-set[1].lo_stop) < -0.5 || - hi/(set[1].hi_stop-set[1].lo_stop) > 0.5) flag = 1; + if (lo / (set[1].hi_stop - set[1].lo_stop) < -0.5 || + hi / (set[1].hi_stop - set[1].lo_stop) > 0.5) flag = 1; } if (flag) error->all(FLERR,"Fix deform is changing yz too much with xy"); @@ -798,13 +781,11 @@ void FixDeform::init() if (pressure_flag) { int icompute = modify->find_compute(id_temp); - if (icompute < 0) - error->all(FLERR,"Temperature ID for fix deform does not exist"); + if (icompute < 0) error->all(FLERR,"Temperature ID for fix deform does not exist"); temperature = modify->compute[icompute]; icompute = modify->find_compute(id_press); - if (icompute < 0) - error->all(FLERR,"Pressure ID for fix deform does not exist"); + if (icompute < 0) error->all(FLERR,"Pressure ID for fix deform does not exist"); pressure = modify->compute[icompute]; } } @@ -816,7 +797,6 @@ void FixDeform::init() void FixDeform::setup(int /*vflag*/) { // trigger virial computation on next timestep - if (pressure_flag) pressure->addstep(update->ntimestep+1); } @@ -872,13 +852,10 @@ void FixDeform::end_of_step() temperature->compute_vector(); pressure->compute_vector(); for (int i = 0; i < 3; i++) { - if (! set[i].saved) { + if (!set[i].saved) { set[i].saved = 1; set[i].prior_rate = 0.0; set[i].prior_pressure = pressure->vector[i]; - if (i == 0) set[i].box_length = domain->xprd; - else if (i == 1) set[i].box_length = domain->yprd; - else set[i].box_length = domain->zprd; } } set_pressure(); @@ -892,15 +869,39 @@ void FixDeform::end_of_step() // Save pressure/strain rate if required if (pressure_flag) { - double dt_inv = 1.0 / update->dt; for (int i = 0; i < 3; i++) { set[i].prior_pressure = pressure->vector[i]; - set[i].prior_rate = ((set[i].hi_target - set[i].lo_target) / set[i].box_length - 1.0) * dt_inv; + set[i].prior_rate = ((set[i].hi_target - set[i].lo_target) / + (domain->boxhi[i] - domain->boxlo[i]) - 1.0) / update->dt; } } if (varflag) modify->addstep_compute(update->ntimestep + nevery); + // tilt_target can be large positive or large negative value + // add/subtract box lengths until tilt_target is closest to current value + + if (triclinic) { + double *h = domain->h; + for (int i = 3; i < 6; i++) { + int idenom = 0; + if (i == 5) idenom = 0; + else if (i == 4) idenom = 0; + else if (i == 3) idenom = 1; + double denom = set[idenom].hi_target - set[idenom].lo_target; + + double current = h[i] / h[idenom]; + + while (set[i].tilt_target / denom - current > 0.0) + set[i].tilt_target -= denom; + while (set[i].tilt_target / denom - current < 0.0) + set[i].tilt_target += denom; + if (fabs(set[i].tilt_target / denom - 1.0 - current) < + fabs(set[i].tilt_target / denom - current)) + set[i].tilt_target -= denom; + } + } + // if any tilt ratios exceed 0.5, set flip = 1 and compute new tilt values // do not flip in x or y if non-periodic (can tilt but not flip) // this is b/c the box length would be changed (dramatically) by flip @@ -915,12 +916,12 @@ void FixDeform::end_of_step() double yprd = set[1].hi_target - set[1].lo_target; double xprdinv = 1.0 / xprd; double yprdinv = 1.0 / yprd; - if (set[3].tilt_target*yprdinv < -0.5 || - set[3].tilt_target*yprdinv > 0.5 || - set[4].tilt_target*xprdinv < -0.5 || - set[4].tilt_target*xprdinv > 0.5 || - set[5].tilt_target*xprdinv < -0.5 || - set[5].tilt_target*xprdinv > 0.5) { + if (set[3].tilt_target * yprdinv < -0.5 || + set[3].tilt_target * yprdinv > 0.5 || + set[4].tilt_target * xprdinv < -0.5 || + set[4].tilt_target * xprdinv > 0.5 || + set[5].tilt_target * xprdinv < -0.5 || + set[5].tilt_target * xprdinv > 0.5) { set[3].tilt_flip = set[3].tilt_target; set[4].tilt_flip = set[4].tilt_target; set[5].tilt_flip = set[5].tilt_target; @@ -928,30 +929,30 @@ void FixDeform::end_of_step() flipxy = flipxz = flipyz = 0; if (domain->yperiodic) { - if (set[3].tilt_flip*yprdinv < -0.5) { + if (set[3].tilt_flip * yprdinv < -0.5) { set[3].tilt_flip += yprd; set[4].tilt_flip += set[5].tilt_flip; flipyz = 1; - } else if (set[3].tilt_flip*yprdinv > 0.5) { + } else if (set[3].tilt_flip * yprdinv > 0.5) { set[3].tilt_flip -= yprd; set[4].tilt_flip -= set[5].tilt_flip; flipyz = -1; } } if (domain->xperiodic) { - if (set[4].tilt_flip*xprdinv < -0.5) { + if (set[4].tilt_flip * xprdinv < -0.5) { set[4].tilt_flip += xprd; flipxz = 1; } - if (set[4].tilt_flip*xprdinv > 0.5) { + if (set[4].tilt_flip * xprdinv > 0.5) { set[4].tilt_flip -= xprd; flipxz = -1; } - if (set[5].tilt_flip*xprdinv < -0.5) { + if (set[5].tilt_flip * xprdinv < -0.5) { set[5].tilt_flip += xprd; flipxy = 1; } - if (set[5].tilt_flip*xprdinv > 0.5) { + if (set[5].tilt_flip * xprdinv > 0.5) { set[5].tilt_flip -= xprd; flipxy = -1; } @@ -1023,12 +1024,8 @@ void FixDeform::end_of_step() // trigger virial computation, if needed, on next timestep - if (pressure_flag) { + if (pressure_flag) pressure->addstep(update->ntimestep+1); - set[0].box_length = domain->xprd; - set[1].box_length = domain->yprd; - set[2].box_length = domain->zprd; - } } /* ---------------------------------------------------------------------- @@ -1052,36 +1049,31 @@ void FixDeform::set_strain() set[i].hi_target = domain->boxhi[i]; } else if (set[i].style == TRATE) { double delt = (update->ntimestep - update->beginstep) * update->dt; - set[i].lo_target = 0.5*(set[i].lo_start+set[i].hi_start) - - 0.5*((set[i].hi_start-set[i].lo_start) * exp(set[i].rate*delt)); - set[i].hi_target = 0.5*(set[i].lo_start+set[i].hi_start) + - 0.5*((set[i].hi_start-set[i].lo_start) * exp(set[i].rate*delt)); + double shift = 0.5 * ((set[i].hi_start - set[i].lo_start) * exp(set[i].rate * delt)); + 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; h_rate[i] = set[i].rate * domain->h[i]; - h_ratelo[i] = -0.5*h_rate[i]; + h_ratelo[i] = -0.5 * h_rate[i]; } else if (set[i].style == WIGGLE) { double delt = (update->ntimestep - update->beginstep) * update->dt; - set[i].lo_target = set[i].lo_start - - 0.5*set[i].amplitude * sin(TWOPI*delt/set[i].tperiod); - set[i].hi_target = set[i].hi_start + - 0.5*set[i].amplitude * sin(TWOPI*delt/set[i].tperiod); - h_rate[i] = TWOPI/set[i].tperiod * set[i].amplitude * - cos(TWOPI*delt/set[i].tperiod); - h_ratelo[i] = -0.5*h_rate[i]; + double shift = 0.5 * set[i].amplitude * sin(MY_2PI * delt / set[i].tperiod); + set[i].lo_target = set[i].lo_start - shift; + set[i].hi_target = set[i].hi_start + shift; + h_rate[i] = MY_2PI / set[i].tperiod * set[i].amplitude * + cos(MY_2PI * delt / set[i].tperiod); + h_ratelo[i] = -0.5 * h_rate[i]; } else if (set[i].style == VARIABLE) { double del = input->variable->compute_equal(set[i].hvar); - set[i].lo_target = set[i].lo_start - 0.5*del; - set[i].hi_target = set[i].hi_start + 0.5*del; + set[i].lo_target = set[i].lo_start - 0.5 * del; + set[i].hi_target = set[i].hi_start + 0.5 * del; h_rate[i] = input->variable->compute_equal(set[i].hratevar); - h_ratelo[i] = -0.5*h_rate[i]; + h_ratelo[i] = -0.5 * h_rate[i]; } else if (set[i].style != VOLUME) { - set[i].lo_target = set[i].lo_start + - delta*(set[i].lo_stop - set[i].lo_start); - set[i].hi_target = set[i].hi_start + - delta*(set[i].hi_stop - set[i].hi_start); + set[i].lo_target = set[i].lo_start + delta * (set[i].lo_stop - set[i].lo_start); + set[i].hi_target = set[i].hi_start + delta * (set[i].hi_stop - set[i].hi_start); } } - // for triclinic, set new box shape // for NONE, target is current tilt // for TRATE, set target directly based on current time. also set h_rate @@ -1099,41 +1091,21 @@ void FixDeform::set_strain() else if (i == 3) set[i].tilt_target = domain->yz; } else if (set[i].style == TRATE) { double delt = (update->ntimestep - update->beginstep) * update->dt; - set[i].tilt_target = set[i].tilt_start * exp(set[i].rate*delt); + set[i].tilt_target = set[i].tilt_start * exp(set[i].rate * delt); h_rate[i] = set[i].rate * domain->h[i]; } else if (set[i].style == WIGGLE) { double delt = (update->ntimestep - update->beginstep) * update->dt; set[i].tilt_target = set[i].tilt_start + - set[i].amplitude * sin(TWOPI*delt/set[i].tperiod); - h_rate[i] = TWOPI/set[i].tperiod * set[i].amplitude * - cos(TWOPI*delt/set[i].tperiod); + set[i].amplitude * sin(MY_2PI * delt / set[i].tperiod); + h_rate[i] = MY_2PI / set[i].tperiod * set[i].amplitude * + cos(MY_2PI * delt / set[i].tperiod); } else if (set[i].style == VARIABLE) { double delta_tilt = input->variable->compute_equal(set[i].hvar); set[i].tilt_target = set[i].tilt_start + delta_tilt; h_rate[i] = input->variable->compute_equal(set[i].hratevar); } else { - set[i].tilt_target = set[i].tilt_start + - delta*(set[i].tilt_stop - set[i].tilt_start); + set[i].tilt_target = set[i].tilt_start + delta * (set[i].tilt_stop - set[i].tilt_start); } - - // tilt_target can be large positive or large negative value - // add/subtract box lengths until tilt_target is closest to current value - - int idenom = 0; - if (i == 5) idenom = 0; - else if (i == 4) idenom = 0; - else if (i == 3) idenom = 1; - double denom = set[idenom].hi_target - set[idenom].lo_target; - - double current = h[i]/h[idenom]; - - while (set[i].tilt_target/denom - current > 0.0) - set[i].tilt_target -= denom; - while (set[i].tilt_target/denom - current < 0.0) - set[i].tilt_target += denom; - if (fabs(set[i].tilt_target/denom - 1.0 - current) < - fabs(set[i].tilt_target/denom - current)) - set[i].tilt_target -= denom; } } } @@ -1156,7 +1128,7 @@ void FixDeform::set_pressure() double p_current[3]; if (pcouple == XYZ) { - double ave = 1.0/3.0 * (tensor[0] + tensor[1] + tensor[2]); + 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]); @@ -1172,30 +1144,68 @@ void FixDeform::set_pressure() p_current[1] = tensor[1]; } else { if (set[0].style == PRESSURE) p_current[0] = tensor[0]; - else if (set[0].style == PISOTROPIC) p_current[0] = scalar; + 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 == PISOTROPIC) p_current[1] = scalar; + 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 == PISOTROPIC) p_current[2] = scalar; + 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 != PISOTROPIC) continue; - double dilation = 1.0 - update->dt * set[i].pgain * (set[i].ptarget - p_current[i]); - double center_start = 0.5 * (set[i].lo_start + set[i].hi_start); - double offset = 0.5 * set[i].box_length * dilation; - //printf("ptarget %g vs %g, dilation %g cs %g ofset %g box %g\n", set[i].ptarget, p_current[i], dilation, center_start, offset, set[i].box_length); - set[i].lo_target = center_start - offset; - set[i].hi_target = center_start + offset; + if (set[i].style != PRESSURE && set[i].style != PMEAN) continue; + + h_rate[i] = set[i].pgain * (p_current[i] - set[i].ptarget); + if (normalize_pressure_flag) { + if (set[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[i].ptarget); + } + + if (max_h_rate != 0) + if (fabs(set[i].ptarget) > max_h_rate) + h_rate[i] = max_h_rate * h_rate[i] / fabs(h_rate[i]); + + double offset = 0.5 * (domain->boxhi[i] - domain->boxlo[i]) * (1.0 + update->dt * h_rate[i]); + set[i].lo_target = 0.5 * (set[i].lo_start + set[i].hi_start) - offset; + set[i].hi_target = 0.5 * (set[i].lo_start + set[i].hi_start) + offset; } for (int i = 3; i < 6; i++) { - double shift = update->dt * set[i].pgain * (set[i].ptarget - tensor[i]); - if (i == 3) set[i].tilt_target = domain->xy + shift * domain->xprd; - else if (i == 4) set[i].tilt_target = domain->xz + shift * domain->xprd; - else set[i].tilt_target = domain->yz + shift * domain->yprd; + if (set[i].style != PRESSURE) continue; + + double L, tilt, pcurrent; + if (i == 3) { + L = domain->zprd; + tilt = domain->yz; + pcurrent = tensor[5]; + } else if (i == 4) { + L = domain->zprd; + tilt = domain->xz + update->dt; + pcurrent = tensor[4]; + } else { + L = domain->yprd; + tilt = domain->xy; + pcurrent = tensor[3]; + } + + h_rate[i] = L * set[i].pgain * (pcurrent - set[i].ptarget); + if (normalize_pressure_flag) { + if (set[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[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[i].tilt_target = tilt + update->dt * h_rate[i]; } } @@ -1211,61 +1221,65 @@ void FixDeform::set_volume() 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 center_start = 0.5 * (set[i].lo_start + set[i].hi_start); - double offset; + double shift; if (set[i].substyle == ONE_FROM_ONE) { - offset = 0.5 * (v0 / - (set[set[i].dynamic1].hi_target - set[set[i].dynamic1].lo_target) / - (set[set[i].fixed].hi_start-set[set[i].fixed].lo_start)); + 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) { - offset = 0.5 * (v0 / - (set[set[i].dynamic1].hi_target - set[set[i].dynamic1].lo_target) / - (set[set[i].dynamic2].hi_target - set[set[i].dynamic2].lo_target)); + 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 (!set[i].coupled_flag) { - offset = 0.5 * sqrt(v0 * (set[i].hi_start - set[i].lo_start) / - (set[set[i].dynamic1].hi_target - set[set[i].dynamic1].lo_target) / - (set[set[i].fixed].hi_start - set[set[i].fixed].lo_start)); + 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[i].prior_rate; - double e2i = set[set[i].fixed].prior_rate; - double L3 = (set[set[i].dynamic1].hi_target - set[set[i].dynamic1].lo_target); - double e3 = (L3 / set[set[i].dynamic1].box_length - 1.0) / dt; + double e2i = set[fixed].prior_rate; + double L1i = domain->boxhi[i] - domain->boxlo[i]; + double L2i = domain->boxhi[fixed] - domain->boxlo[fixed]; + double L3i = domain->boxhi[dynamic1] - domain->boxlo[dynamic1]; + double L3 = (set[dynamic1].hi_target - set[dynamic1].lo_target); + double e3 = (L3 / L3i - 1.0) / dt; double p1 = pressure->vector[i]; - double p2 = pressure->vector[set[i].fixed]; + double p2 = pressure->vector[fixed]; double p1i = set[i].prior_pressure; - double p2i = set[set[i].fixed].prior_pressure; + double p2i = set[fixed].prior_pressure; if (e3 == 0) { e1 = 0.0; e2 = 0.0; - offset = 0.5 * set[i].box_length; + 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 offset by relative box lengths - offset = 0.5 * sqrt(v0 * set[i].box_length / L3 / set[set[i].fixed].box_length); + // 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 in strain to achieve p1(t+dt) = p2(t+dt) - e1 = -e3 / (1 + e3 * dt) * (p2 - p2i) - e2i * (p1 - p2); - e1 /= (p2 - p2i + (p1 - p1i) / e1i * e2i); - + 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 - e2 = (1.0 - (1 + e3 * dt) * (1 + e1 * dt)); - e2 /= (1 + e3 * dt) * (1 + e1 * dt) * dt; + e1 = -e3 / (1 + e3 * dt) * (p2 - p2i) - e2i * (p1 - p2) / (p2 - p2i + (p1 - p1i) / e1i * e2i); + e2 = (1.0 - (1 + e3 * dt) * (1 + e1 * dt)) / ((1 + e3 * dt) * (1 + e1 * dt) * dt); - offset = 0.5 * set[i].box_length * (1.0 + e1 * dt); + shift = 0.5 * L1i * (1.0 + e1 * dt); linked_pressure = 1; } else { - offset = 0.5 * set[i].box_length * (1.0 + e2 * dt); + // Already calculated value of e2 + shift = 0.5 * L1i * (1.0 + e2 * dt); } } } } - set[i].lo_target = center_start - offset; - set[i].hi_target = center_start + offset; + + h_rate[i] = (2.0 * shift / (domain->boxhi[i] - domain->boxlo[i]) - 1.0) / update->dt; + + 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; } } @@ -1296,6 +1310,9 @@ void FixDeform::restart(char *buf) 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; + set[i].saved = set_restart[i].saved; + set[i].prior_rate = set_restart[i].prior_rate; + set[i].prior_pressure = set_restart[i].prior_pressure; // check if style settings are consistent (should do the whole set?) if (set[i].style != set_restart[i].style) samestyle = 0; @@ -1344,6 +1361,20 @@ void FixDeform::options(int narg, char **arg) else if (strcmp(arg[iarg+1],"none") == 0) pcouple = NOCOUPLE; else error->all(FLERR,"Illegal fix fix deform couple command: {}", arg[iarg+1]); iarg += 2; + } else if (strcmp(arg[iarg],"max/rate") == 0) { + if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "fix deform 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"); + iarg += 2; + } else if (strcmp(arg[iarg],"normalize/pressure") == 0) { + if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "fix deform normalize/pressure", error); + normalize_pressure_flag = utils::logical(FLERR,arg[iarg+1],false,lmp); + iarg += 2; + } else if (strcmp(arg[iarg],"vol/balance/p") == 0) { + if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "fix deform vol/balance/p", error); + vol_balance_flag = utils::logical(FLERR,arg[iarg+1],false,lmp); + iarg += 2; } else error->all(FLERR,"Illegal fix deform command: {}", arg[iarg]); } @@ -1363,7 +1394,6 @@ double FixDeform::memory_usage() return bytes; } - /* ---------------------------------------------------------------------- */ int FixDeform::modify_param(int narg, char **arg) diff --git a/src/fix_deform.h b/src/fix_deform.h index 9ecb9a577dd..eda97f7c908 100644 --- a/src/fix_deform.h +++ b/src/fix_deform.h @@ -44,17 +44,17 @@ class FixDeform : public Fix { protected: int dimension, triclinic, scaleflag, flipflag, pcouple; int flip, flipxy, flipxz, flipyz; - double *h_rate, *h_ratelo; + double *h_rate, *h_ratelo, max_h_rate; int varflag; // 1 if VARIABLE option is used, 0 if not int strain_flag; // 1 if strain-based option is used, 0 if not int volume_flag; // 1 if VOLUME option is used, 0 if not int pressure_flag; // 1 if pressure tensor used, 0 if not int kspace_flag; // 1 if KSpace invoked, 0 if not + int normalize_pressure_flag; // 1 if normalize pressure deviation by target + int vol_balance_flag; // 1 if pressures balanced when maintaining const vol std::vector rfix; // pointers to rigid fixes class Irregular *irregular; // for migrating atoms after box flips - double TWOPI; - char *id_temp, *id_press; class Compute *temperature, *pressure; int tflag, pflag; @@ -72,7 +72,6 @@ class FixDeform : public Fix { double vol_initial, vol_start; double ptarget, pgain; double prior_pressure, prior_rate; - double box_length; int saved; int fixed, dynamic1, dynamic2; char *hstr, *hratestr, *pstr; From 63618d249056b6008d34486301d841fa7bc47ccf Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 24 Oct 2022 10:59:22 -0600 Subject: [PATCH 04/29] Adding scalar pressure compute --- src/fix_deform.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index db3fad6a958..29c286ed029 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -851,6 +851,7 @@ void FixDeform::end_of_step() if (pressure_flag) { temperature->compute_vector(); pressure->compute_vector(); + pressure->compute_scalar(); for (int i = 0; i < 3; i++) { if (!set[i].saved) { set[i].saved = 1; @@ -1157,6 +1158,7 @@ void FixDeform::set_pressure() if (set[i].style != PRESSURE && set[i].style != PMEAN) continue; h_rate[i] = set[i].pgain * (p_current[i] - set[i].ptarget); + if (normalize_pressure_flag) { if (set[i].ptarget == 0) { if (max_h_rate == 0) { From 6de50fbd33a130e8a2ecac07a5bc31ac5467969d Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 14 Jun 2023 13:39:24 -0600 Subject: [PATCH 05/29] Adding iso options to fix deform --- doc/src/fix_deform.rst | 46 ++++++++++++--- src/fix_deform.cpp | 129 ++++++++++++++++++++++++++++++++++++----- src/fix_deform.h | 2 + 3 files changed, 155 insertions(+), 22 deletions(-) diff --git a/doc/src/fix_deform.rst b/doc/src/fix_deform.rst index d46f1204f5e..7a17f14fed0 100644 --- a/doc/src/fix_deform.rst +++ b/doc/src/fix_deform.rst @@ -20,7 +20,7 @@ Syntax .. parsed-literal:: - parameter = *x* or *y* or *z* or *xy* or *xz* or *yz* + parameter = *x* or *y* or *z* or *xy* or *xz* or *yz* or *iso* *x*, *y*, *z* args = style value(s) style = *final* or *delta* or *scale* or *vel* or *erate* or *trate* or *volume* or *wiggle* or *variable* *final* values = lo hi @@ -71,6 +71,12 @@ Syntax *variable* values = v_name1 v_name2 v_name1 = variable with name1 for tilt change as function of time v_name2 = variable with name2 for change rate as function of time + *iso* = style value + style = *volume* or *pressure* + *volume* value = none = isotropically adjust system to preserve volume of system + *pressure* values = target gain + target = target mean pressure (pressure units) + gain = proportional gain constant (1/(time * pressure) or 1/time units) * zero or more keyword/value pairs may be appended * keyword = *remap* or *flip* or *units* or *couple* or *vol/balance/p* or *max/rate* or *normalize/pressure* @@ -88,12 +94,10 @@ Syntax box = distances are defined in simulation box units *couple* value = *none* or *xyz* or *xy* or *yz* or *xz* couple pressure values of various dimensions - *vol/balance/p* = *yes* or *no* + *vol/balance/p* value = *yes* or *no* Modifies the behavior of the *volume* option to try and balance pressures *max/rate* value = *rate* rate = maximum strain rate for pressure control - *normalize/pressure* value = *yes* or *no* - determine whether pressure deviation is normalized by target pressure Examples """""""" @@ -107,6 +111,7 @@ Examples fix 1 all deform 1 x pressure 2.0 0.1 normalize/pressure yes max/rate 0.001 fix 1 all deform 1 x trate 0.1 y volume z volume vol/balance/p yes fix 1 all deform 1 x trate 0.1 y pressure/mean 0.0 1.0 z pressure/mean 0.0 1.0 + fix 1 all deform 1 x trate 0.1 y trate -0.1 overlay/pressure/mean 1.0 0.1 Description """"""""""" @@ -318,8 +323,8 @@ mid point. The *pressure* style adjusts a dimensions's box length to control that component of the pressure tensor. This option attempts to maintain a -specified target value using a linear controller where the box length L -evolves according to the equation +specified target value using a linear controller where the box length +:math:`L` evolves according to the equation .. parsed-literal:: @@ -343,7 +348,7 @@ option. The *pressure/mean* style is changes a dimension in order to maintain a constant mean pressure defined as the trace of the pressure tensor. -This option is therefore very similar to the *presssure* style with +This option is therefore very similar to the *pressure* style with identical arguments except the current and target pressures refer to the mean trace of the pressure tensor. The same options also apply except for the :ref:`couple ` option. @@ -512,6 +517,25 @@ of the applied strain using the :ref:`max/rate ` option. ---------- +The *iso* parameter provides an additonal control over the x, y, +and z box lengths. This parameter can only be used in combination with +the *x*, *y*, or *z* comamnds: *vel*, *erate*, *trate*, *pressure*, or +*wiggle*. Note that this parameter will change the overall strain rate in +the *x*, *y*, or *z* dimensions. This is the meaning of its styles and values. + +The *volume* style isotropically scales box lengths to maintain a constant +box volume in response to deformation from other parameters. + +The *pressure* style controls the box volume to maintain the mean pressure +of the system. This is accomplished by isotropically scaling all box +lengths :math:`L` by an additional factor of :math:`k (P_t - P_m)` where +:math:`k` is the proportional gain constant, :math:`P_t` is the target +pressure, and :math:`P_m` is the current mean pressure (the trace of the +pressure tensor). This style allows one to control the deviatoric strain +tensor while maintaining a fixed mean pressure. + +---------- + All of the tilt styles change the xy, xz, yz tilt factors during a simulation. In LAMMPS, tilt factors (xy,xz,yz) for triclinic boxes are normally bounded by half the distance of the parallel box length. @@ -652,8 +676,12 @@ described below, which will cap the divergence. .. _deform_max_rate: The *max/rate* keyword sets an upper threshold, *rate*, that limits the -maximum magnitude of the strain rate applied in any dimension. This keyword -only applies to the *pressure* and *pressure/mean* options. +maximum magnitude of the instantaneous strain rate applied in any dimension. +This keyword only applies to the *pressure* and *pressure/mean* options. If +a pressure-controlled rate is used for both *iso* and either *x*, *y*, or +*z*, then this threshold will apply separately to each individual controller +such that the cumulative strain rate on a box dimension may be up to twice +the value of *rate*. .. _deform_couple: diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index 29c286ed029..e76b34f302b 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -65,8 +65,8 @@ irregular(nullptr), set(nullptr) // set defaults - set = new Set[6]; - memset(set,0,6*sizeof(Set)); + set = new Set[7]; + memset(set,0,7*sizeof(Set)); // parse arguments @@ -237,6 +237,25 @@ irregular(nullptr), set(nullptr) error->all(FLERR,"Illegal fix deform pressure gain, must be positive"); iarg += 4; } else error->all(FLERR,"Illegal fix deform command: {}", arg[iarg+1]); + } else if (strcmp(arg[iarg],"iso") == 0) { + index = 6; + if (strcmp(arg[iarg+1],"volume") == 0) { + set[index].style = VOLUME; + iarg += 2; + } else if (strcmp(arg[iarg+1],"pressure") == 0) { + if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform pressure", error); + set[index].style = PRESSURE; + if (strstr(arg[iarg+2],"v_") != arg[iarg+2]) { + set[index].ptarget = utils::numeric(FLERR,arg[iarg+2],false,lmp); + } else { + set[index].pstr = utils::strdup(&arg[iarg+2][2]); + set[index].pvar_flag = 1; + } + set[index].pgain = utils::numeric(FLERR,arg[iarg+3],false,lmp); + if (set[index].pgain <= 0.0) + error->all(FLERR,"Illegal fix deform pressure gain, must be positive"); + iarg += 4; + } } else break; } @@ -313,6 +332,12 @@ irregular(nullptr), set(nullptr) if (set[i].style == NONE) dimflag[i] = 0; else dimflag[i] = 1; + if (set[6].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; @@ -324,7 +349,7 @@ irregular(nullptr), set(nullptr) // b/c shrink wrap will change box-length for (int i = 0; i < 3; i++) - if (set[i].style && (domain->boundary[i][0] >= 2 || domain->boundary[i][1] >= 2)) + if ((set[i].style || set[6].style) && (domain->boundary[i][0] >= 2 || domain->boundary[i][1] >= 2)) error->all(FLERR,"Cannot use fix deform on a shrink-wrapped boundary"); // no tilt deformation on shrink-wrapped 2nd dim @@ -431,7 +456,7 @@ irregular(nullptr), set(nullptr) // set varflag varflag = 0; - for (int i = 0; i < 6; i++) { + for (int i = 0; i < 7; i++) { if (set[i].style == VARIABLE) varflag = 1; if (set[i].pvar_flag) varflag = 1; } @@ -439,7 +464,7 @@ irregular(nullptr), set(nullptr) // set pressure_flag pressure_flag = 0; - for (int i = 0; i < 6; i++) { + for (int i = 0; i < 7; i++) { if (set[i].style == PRESSURE || set[i].style == PMEAN) pressure_flag = 1; if (set[i].coupled_flag) pressure_flag = 1; } @@ -452,6 +477,14 @@ irregular(nullptr), set(nullptr) if (set[i].style == PMEAN) error->all(FLERR, "Cannot use fix deform to assign constant volume and pressure"); + // check conflicts between x,y,z styles and iso + + if (set[6].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 iso 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) @@ -470,6 +503,7 @@ irregular(nullptr), set(nullptr) set[3].tilt_initial = domain->yz; set[4].tilt_initial = domain->xz; set[5].tilt_initial = domain->xy; + set[6].vol_initial = domain->xprd * domain->yprd * domain->zprd; // reneighboring only forced if flips can occur due to shape changes @@ -511,7 +545,7 @@ irregular(nullptr), set(nullptr) FixDeform::~FixDeform() { if (set) { - for (int i = 0; i < 6; i++) { + for (int i = 0; i < 7; i++) { delete[] set[i].hstr; delete[] set[i].hratestr; delete[] set[i].pstr; @@ -569,7 +603,7 @@ void FixDeform::init() // check variables for VARIABLE style - for (int i = 0; i < 6; i++) { + for (int i = 0; i < 7; i++) { if (set[i].style != VARIABLE) continue; set[i].hvar = input->variable->find(set[i].hstr); if (set[i].hvar < 0) @@ -585,7 +619,7 @@ void FixDeform::init() // check optional variables for PRESSURE or PMEAN style - for (int i = 0; i < 6; i++) { + for (int i = 0; i < 7; i++) { if (!set[i].pvar_flag) continue; set[i].pvar = input->variable->find(set[i].pstr); if (set[i].pvar < 0) @@ -701,6 +735,8 @@ void FixDeform::init() } } + set[6].vol_start = domain->xprd * domain->yprd * domain->zprd; + // if using tilt TRATE, then initial tilt must be non-zero for (int i = 3; i < 6; i++) @@ -740,6 +776,7 @@ void FixDeform::init() // set domain->h_rate values for use by domain and other fixes/computes // initialize all rates to 0.0 // cannot set here for TRATE,VOLUME,WIGGLE,VARIABLE,PRESSURE since not constant + // if iso style is used, these will also not be constant h_rate = domain->h_rate; h_ratelo = domain->h_ratelo; @@ -867,6 +904,10 @@ void FixDeform::end_of_step() if (volume_flag) set_volume(); + // apply any final isotropic scalings + + if (set[6].style) set_iso(); + // Save pressure/strain rate if required if (pressure_flag) { @@ -983,15 +1024,15 @@ void FixDeform::end_of_step() // reset global and local box to new size/shape // only if deform fix is controlling the dimension - if (set[0].style) { + if (set[0].style || set[6].style) { domain->boxlo[0] = set[0].lo_target; domain->boxhi[0] = set[0].hi_target; } - if (set[1].style) { + if (set[1].style || set[6].style) { domain->boxlo[1] = set[1].lo_target; domain->boxhi[1] = set[1].hi_target; } - if (set[2].style) { + if (set[2].style || set[6].style) { domain->boxlo[2] = set[2].lo_target; domain->boxhi[2] = set[2].hi_target; } @@ -1285,6 +1326,67 @@ void FixDeform::set_volume() } } +/* ---------------------------------------------------------------------- + apply isotropic controls +------------------------------------------------------------------------- */ + +void FixDeform::set_iso() +{ + int i; + double scale, shift; + double v_rate; + + if (set[6].style == VOLUME) { + double v0 = set[6].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->boxhi[i] - domain->boxlo[i]) - 1.0; + h_rate[i] /= update->dt; + } + + } else if (set[6].style == PRESSURE) { + + // If variable pressure, calculate current target + if (set[6].pvar_flag) + set[6].ptarget = input->variable->compute_equal(set[6].pvar); + + v_rate = set[6].pgain * (pressure->scalar- set[6].ptarget); + + if (normalize_pressure_flag) { + if (set[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[6].ptarget); + } + + if (max_h_rate != 0) + if (fabs(set[6].ptarget) > max_h_rate) + v_rate = max_h_rate * v_rate / fabs(v_rate); + + set[6].cumulative_strain += update->dt * v_rate; + scale = (1.0 + set[6].cumulative_strain); + 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->boxhi[i] - domain->boxlo[i]) - 1.0; + h_rate[i] /= update->dt; + } + } +} + /* ---------------------------------------------------------------------- write Set data to restart file ------------------------------------------------------------------------- */ @@ -1294,7 +1396,7 @@ void FixDeform::write_restart(FILE *fp) if (comm->me == 0) { int size = 6 * sizeof(Set); fwrite(&size,sizeof(int),1,fp); - fwrite(set,sizeof(Set),6,fp); + fwrite(set,sizeof(Set),7,fp); } } @@ -1306,7 +1408,7 @@ void FixDeform::restart(char *buf) { int samestyle = 1; Set *set_restart = (Set *) buf; - for (int i=0; i<6; ++i) { + for (int i=0; i<7; ++i) { // restore data from initial state set[i].lo_initial = set_restart[i].lo_initial; set[i].hi_initial = set_restart[i].hi_initial; @@ -1315,6 +1417,7 @@ void FixDeform::restart(char *buf) set[i].saved = set_restart[i].saved; set[i].prior_rate = set_restart[i].prior_rate; set[i].prior_pressure = set_restart[i].prior_pressure; + set[i].cumulative_strain = set_restart[i].cumulative_strain; // check if style settings are consistent (should do the whole set?) if (set[i].style != set_restart[i].style) samestyle = 0; diff --git a/src/fix_deform.h b/src/fix_deform.h index eda97f7c908..e8a4766b124 100644 --- a/src/fix_deform.h +++ b/src/fix_deform.h @@ -72,6 +72,7 @@ class FixDeform : public Fix { double vol_initial, vol_start; double ptarget, pgain; double prior_pressure, prior_rate; + double cumulative_strain; int saved; int fixed, dynamic1, dynamic2; char *hstr, *hratestr, *pstr; @@ -85,6 +86,7 @@ class FixDeform : public Fix { void set_strain(); void set_pressure(); void set_volume(); + void set_iso(); void couple(); }; From f75eda4bf4f5d223eaf469a5f42d7b8377c0547b Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 14 Jun 2023 14:16:46 -0600 Subject: [PATCH 06/29] Updating size of set in restart --- src/fix_deform.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index e76b34f302b..34e73b4e10f 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -1394,7 +1394,7 @@ void FixDeform::set_iso() void FixDeform::write_restart(FILE *fp) { if (comm->me == 0) { - int size = 6 * sizeof(Set); + int size = 7 * sizeof(Set); fwrite(&size,sizeof(int),1,fp); fwrite(set,sizeof(Set),7,fp); } From 60173c477d59c770e1bbac40e68111a01f28fd67 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 14 Jun 2023 15:14:19 -0600 Subject: [PATCH 07/29] Creating persistent h_rate variable --- src/fix_deform.cpp | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index 34e73b4e10f..b595901a058 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -47,7 +47,7 @@ enum{NOCOUPLE=0,XYZ,XY,YZ,XZ}; /* ---------------------------------------------------------------------- */ FixDeform::FixDeform(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), -irregular(nullptr), set(nullptr) +irregular(nullptr), set(nullptr), id_temp(nullptr), id_press(nullptr) { if (narg < 4) error->all(FLERR,"Illegal fix deform command"); @@ -538,6 +538,16 @@ irregular(nullptr), set(nullptr) modify->add_compute(fmt::format("{} all pressure {}",id_press, id_temp)); pflag = 1; } + + // initialize all rates to 0.0 in constructor instead of init so values persist + // across run statements and ghosts have correct velocities until the destructor + h_rate = domain->h_rate; + h_ratelo = domain->h_ratelo; + + for (int i = 0; i < 3; i++) + h_rate[i] = h_ratelo[i] = 0.0; + for (int i = 3; i < 6; i++) + h_rate[i] = 0.0; } /* ---------------------------------------------------------------------- */ @@ -774,15 +784,10 @@ void FixDeform::init() } // set domain->h_rate values for use by domain and other fixes/computes - // initialize all rates to 0.0 // cannot set here for TRATE,VOLUME,WIGGLE,VARIABLE,PRESSURE since not constant // if iso style is used, these will also not be constant - h_rate = domain->h_rate; - h_ratelo = domain->h_ratelo; - for (int i = 0; i < 3; i++) { - h_rate[i] = h_ratelo[i] = 0.0; if (set[i].style == FINAL || set[i].style == DELTA || set[i].style == SCALE || set[i].style == VEL || set[i].style == ERATE) { @@ -797,7 +802,6 @@ void FixDeform::init() } for (int i = 3; i < 6; i++) { - h_rate[i] = 0.0; if (set[i].style == FINAL || set[i].style == DELTA || set[i].style == VEL || set[i].style == ERATE) { if (delt != 0.0) @@ -1394,8 +1398,10 @@ void FixDeform::set_iso() void FixDeform::write_restart(FILE *fp) { if (comm->me == 0) { - int size = 7 * sizeof(Set); + int size = 9 * sizeof(double) + 7 * sizeof(Set); fwrite(&size,sizeof(int),1,fp); + fwrite(h_rate,sizeof(double),6,fp); + fwrite(h_ratelo,sizeof(double),3,fp); fwrite(set,sizeof(Set),7,fp); } } @@ -1406,9 +1412,16 @@ void FixDeform::write_restart(FILE *fp) void FixDeform::restart(char *buf) { + int n = 0; + auto list = (double *) buf; + for (int i = 0; i < 6; i++) + h_rate[i] = list[n++]; + for (int i = 0; i < 3; i++) + h_ratelo[i] = list[n++]; + int samestyle = 1; - Set *set_restart = (Set *) buf; - for (int i=0; i<7; ++i) { + Set *set_restart = (Set *) &buf[n * sizeof(double)]; + for (int i = 0; i < 7; ++i) { // restore data from initial state set[i].lo_initial = set_restart[i].lo_initial; set[i].hi_initial = set_restart[i].hi_initial; From d6532d3550694d3f5ce4a1ae83ff4b57ce1598a6 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 23 Jun 2023 14:13:32 -0600 Subject: [PATCH 08/29] Adding h_ratelo calculation --- src/fix_deform.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index b595901a058..8da904100e1 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -1114,7 +1114,8 @@ void FixDeform::set_strain() set[i].hi_target = set[i].hi_start + 0.5 * del; h_rate[i] = input->variable->compute_equal(set[i].hratevar); h_ratelo[i] = -0.5 * h_rate[i]; - } else if (set[i].style != VOLUME) { + } else if (set[i].style == FINAL || set[i].style == DELTA || set[i].style == SCALE || + set[i].style == VEL || set[i].style == ERATE) { set[i].lo_target = set[i].lo_start + delta * (set[i].lo_stop - set[i].lo_start); set[i].hi_target = set[i].hi_start + delta * (set[i].hi_stop - set[i].hi_start); } @@ -1215,6 +1216,7 @@ void FixDeform::set_pressure() if (max_h_rate != 0) if (fabs(set[i].ptarget) > 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 offset = 0.5 * (domain->boxhi[i] - domain->boxlo[i]) * (1.0 + update->dt * h_rate[i]); set[i].lo_target = 0.5 * (set[i].lo_start + set[i].hi_start) - offset; @@ -1324,6 +1326,7 @@ void FixDeform::set_volume() } h_rate[i] = (2.0 * shift / (domain->boxhi[i] - domain->boxlo[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; @@ -1355,6 +1358,7 @@ void FixDeform::set_iso() // Recalculate h_rate h_rate[i] = (set[i].hi_target - set[i].lo_target) / (domain->boxhi[i] - domain->boxlo[i]) - 1.0; h_rate[i] /= update->dt; + h_ratelo[i] = -0.5 * h_rate[i]; } } else if (set[6].style == PRESSURE) { @@ -1387,6 +1391,7 @@ void FixDeform::set_iso() // Recalculate h_rate h_rate[i] = (set[i].hi_target - set[i].lo_target) / (domain->boxhi[i] - domain->boxlo[i]) - 1.0; h_rate[i] /= update->dt; + h_ratelo[i] = -0.5 * h_rate[i]; } } } From 2ef326273d703eeee71cbb894a451810ea3055db Mon Sep 17 00:00:00 2001 From: jtclemm Date: Sat, 15 Jul 2023 16:09:53 -0600 Subject: [PATCH 09/29] Fixing bug in max rate threshold --- src/fix_deform.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index 8da904100e1..ff6caf5a1db 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -1214,8 +1214,9 @@ void FixDeform::set_pressure() } if (max_h_rate != 0) - if (fabs(set[i].ptarget) > max_h_rate) + 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 offset = 0.5 * (domain->boxhi[i] - domain->boxlo[i]) * (1.0 + update->dt * h_rate[i]); @@ -1378,7 +1379,7 @@ void FixDeform::set_iso() } if (max_h_rate != 0) - if (fabs(set[6].ptarget) > max_h_rate) + if (fabs(v_rate) > max_h_rate) v_rate = max_h_rate * v_rate / fabs(v_rate); set[6].cumulative_strain += update->dt * v_rate; From ec65fc48adbe1d2edb40db35e1ae6f85f7b5f7fb Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 18 Jul 2023 09:25:22 -0600 Subject: [PATCH 10/29] Cleaning up files, fixing bug in berendsen --- doc/src/fix_deform.rst | 10 ++++++---- src/fix_deform.cpp | 35 +++++++++++++++++------------------ src/fix_press_berendsen.cpp | 2 +- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/doc/src/fix_deform.rst b/doc/src/fix_deform.rst index 7a17f14fed0..a4d449850ed 100644 --- a/doc/src/fix_deform.rst +++ b/doc/src/fix_deform.rst @@ -98,6 +98,8 @@ Syntax Modifies the behavior of the *volume* option to try and balance pressures *max/rate* value = *rate* rate = maximum strain rate for pressure control + *normalize/pressure* value = *yes* or *no* + Modifies pressure controls such that the deviation in pressure is normalized by the target pressure Examples """""""" @@ -111,7 +113,6 @@ Examples fix 1 all deform 1 x pressure 2.0 0.1 normalize/pressure yes max/rate 0.001 fix 1 all deform 1 x trate 0.1 y volume z volume vol/balance/p yes fix 1 all deform 1 x trate 0.1 y pressure/mean 0.0 1.0 z pressure/mean 0.0 1.0 - fix 1 all deform 1 x trate 0.1 y trate -0.1 overlay/pressure/mean 1.0 0.1 Description """"""""""" @@ -346,12 +347,13 @@ applied strain using the :ref:`max/rate ` option and couple pressures in different dimensions using the :ref:`couple ` option. -The *pressure/mean* style is changes a dimension in order to maintain +The *pressure/mean* style changes a dimension's box length to maintain a constant mean pressure defined as the trace of the pressure tensor. This option is therefore very similar to the *pressure* style with identical arguments except the current and target pressures refer to the -mean trace of the pressure tensor. The same options also apply except -for the :ref:`couple ` option. +mean trace of the pressure tensor. All options for the *pressure* style +also apply to the *pressure/mean* style except for the +:ref:`couple ` option. ---------- diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index ff6caf5a1db..79f9b3a5ba2 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -24,6 +24,7 @@ #include "domain.h" #include "error.h" #include "force.h" +#include "group.h" #include "input.h" #include "irregular.h" #include "kspace.h" @@ -1522,31 +1523,31 @@ double FixDeform::memory_usage() int FixDeform::modify_param(int narg, char **arg) { - if (!pressure_flag) error->all(FLERR,"Cannot modify fix deform without a pressure control"); if (strcmp(arg[0],"temp") == 0) { - if (narg < 2) utils::missing_cmd_args(FLERR, "fix_modify deform", error); + if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); if (tflag) { modify->delete_compute(id_temp); tflag = 0; } - delete [] id_temp; + delete[] id_temp; id_temp = utils::strdup(arg[1]); - int icompute = modify->find_compute(arg[1]); - if (icompute < 0) error->all(FLERR,"Could not find fix_modify temperature ID"); - temperature = modify->compute[icompute]; + 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 ID does not compute temperature"); + error->all(FLERR,"Fix_modify temperature compute {} does not compute temperature", arg[1]); if (temperature->igroup != 0 && comm->me == 0) - error->warning(FLERR,"Temperature for deform is not for group all"); + 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 - icompute = modify->find_compute(id_press); - if (icompute < 0) - error->all(FLERR,"Pressure ID for fix deform does not exist"); - modify->compute[icompute]->reset_extra_compute_fix(id_temp); + 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; @@ -1556,15 +1557,13 @@ int FixDeform::modify_param(int narg, char **arg) modify->delete_compute(id_press); pflag = 0; } - delete [] id_press; + delete[] id_press; id_press = utils::strdup(arg[1]); - int icompute = modify->find_compute(arg[1]); - if (icompute < 0) error->all(FLERR,"Could not find fix_modify pressure ID"); - pressure = modify->compute[icompute]; - + 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 ID does not compute pressure"); + error->all(FLERR,"Fix_modify pressure compute {} does not compute pressure", arg[1]); return 2; } diff --git a/src/fix_press_berendsen.cpp b/src/fix_press_berendsen.cpp index 67802654ba4..ee9a8796160 100644 --- a/src/fix_press_berendsen.cpp +++ b/src/fix_press_berendsen.cpp @@ -491,7 +491,7 @@ int FixPressBerendsen::modify_param(int narg, char **arg) 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) 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; From 77a5fd16dd5309d1955aae573ed41d66bc0caede Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 19 Sep 2023 13:37:47 +0200 Subject: [PATCH 11/29] Fixing bug in link pressure --- src/fix_deform.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index 79f9b3a5ba2..139f1e08352 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -1302,6 +1302,7 @@ void FixDeform::set_volume() double p2 = pressure->vector[fixed]; double p1i = set[i].prior_pressure; double p2i = set[fixed].prior_pressure; + double denominator; if (e3 == 0) { e1 = 0.0; @@ -1314,7 +1315,12 @@ void FixDeform::set_volume() 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 - e1 = -e3 / (1 + e3 * dt) * (p2 - p2i) - e2i * (p1 - p2) / (p2 - p2i + (p1 - p1i) / e1i * e2i); + denominator = (p2 - p2i + (p1 - p1i) / e1i * e2i); + if (denominator != 0.0 && e1i != 0.0) { + e1 = (-e3 / (1 + e3 * dt) * (p2 - p2i) - e2i * (p1 - p2)) / denominator; + } else { + e1 = e2i; + } e2 = (1.0 - (1 + e3 * dt) * (1 + e1 * dt)) / ((1 + e3 * dt) * (1 + e1 * dt) * dt); shift = 0.5 * L1i * (1.0 + e1 * dt); From 5ff16da2725e641c3a4eae7db763dd8f0d2cf8fa Mon Sep 17 00:00:00 2001 From: jtclemm Date: Thu, 21 Sep 2023 12:17:47 +0200 Subject: [PATCH 12/29] Adding rate cap on vol link pressure --- src/fix_deform.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++--- src/fix_deform.h | 1 + 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index 139f1e08352..3430c26061f 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -1297,6 +1297,8 @@ void FixDeform::set_volume() double L2i = domain->boxhi[fixed] - domain->boxlo[fixed]; double L3i = domain->boxhi[dynamic1] - domain->boxlo[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]; @@ -1315,13 +1317,22 @@ void FixDeform::set_volume() 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 + (p1 - p1i) / e1i * e2i); + denominator = p2 - p2i + e2i * ((p1 - p1i) / e1i); if (denominator != 0.0 && e1i != 0.0) { - e1 = (-e3 / (1 + e3 * dt) * (p2 - p2i) - e2i * (p1 - p2)) / denominator; + e1 = (((p2 - p2i) * (Vi - V) / (V * dt)) - e2i * (p1 - p2)) / denominator; } else { e1 = e2i; } - e2 = (1.0 - (1 + e3 * dt) * (1 + e1 * dt)) / ((1 + e3 * dt) * (1 + e1 * dt) * dt); + 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; @@ -1341,6 +1352,37 @@ void FixDeform::set_volume() } } + +/* ---------------------------------------------------------------------- + Rescale volume preserving strain rates to enforce max rate +------------------------------------------------------------------------- */ + +void FixDeform::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 isotropic controls ------------------------------------------------------------------------- */ diff --git a/src/fix_deform.h b/src/fix_deform.h index e8a4766b124..2f0b66aa714 100644 --- a/src/fix_deform.h +++ b/src/fix_deform.h @@ -88,6 +88,7 @@ class FixDeform : public Fix { void set_volume(); void set_iso(); void couple(); + void adjust_linked_rates(double&, double&, double, double, double); }; } // namespace LAMMPS_NS From e69a079545dcf9801f0099c268fb781567fe7b61 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 20 Dec 2023 10:50:54 -0700 Subject: [PATCH 13/29] Fixing invalid variable deform kokkos --- src/KOKKOS/fix_deform_kokkos.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/KOKKOS/fix_deform_kokkos.cpp b/src/KOKKOS/fix_deform_kokkos.cpp index 104ac41188d..7a2b3e2481a 100644 --- a/src/KOKKOS/fix_deform_kokkos.cpp +++ b/src/KOKKOS/fix_deform_kokkos.cpp @@ -120,11 +120,11 @@ void FixDeformKokkos::end_of_step() } else if (set[i].style == WIGGLE) { double delt = (update->ntimestep - update->beginstep) * update->dt; set[i].lo_target = set[i].lo_start - - 0.5*set[i].amplitude * sin(TWOPI*delt/set[i].tperiod); + 0.5*set[i].amplitude * sin(MY_2PI*delt/set[i].tperiod); set[i].hi_target = set[i].hi_start + - 0.5*set[i].amplitude * sin(TWOPI*delt/set[i].tperiod); - h_rate[i] = TWOPI/set[i].tperiod * set[i].amplitude * - cos(TWOPI*delt/set[i].tperiod); + 0.5*set[i].amplitude * sin(MY_2PI*delt/set[i].tperiod); + h_rate[i] = MY_2PI/set[i].tperiod * set[i].amplitude * + cos(MY_2PI*delt/set[i].tperiod); h_ratelo[i] = -0.5*h_rate[i]; } else if (set[i].style == VARIABLE) { double del = input->variable->compute_equal(set[i].hvar); @@ -212,9 +212,9 @@ void FixDeformKokkos::end_of_step() } else if (set[i].style == WIGGLE) { double delt = (update->ntimestep - update->beginstep) * update->dt; set[i].tilt_target = set[i].tilt_start + - set[i].amplitude * sin(TWOPI*delt/set[i].tperiod); - h_rate[i] = TWOPI/set[i].tperiod * set[i].amplitude * - cos(TWOPI*delt/set[i].tperiod); + set[i].amplitude * sin(MY_2PI*delt/set[i].tperiod); + h_rate[i] = MY_2PI/set[i].tperiod * set[i].amplitude * + cos(MY_2PI*delt/set[i].tperiod); } else if (set[i].style == VARIABLE) { double delta_tilt = input->variable->compute_equal(set[i].hvar); set[i].tilt_target = set[i].tilt_start + delta_tilt; From 87b2662ee9351958b8a2af0c0ae27b41796ad33a Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 22 Jan 2024 21:21:20 -0700 Subject: [PATCH 14/29] Moving pressure options to subclass --- doc/src/fix_deform.rst | 201 +--- doc/src/fix_deform_pressure.rst | 793 ++++++++++++++++ src/.gitignore | 2 + src/EXTRA-FIX/fix_deform_pressure.cpp | 905 ++++++++++++++++++ src/EXTRA-FIX/fix_deform_pressure.h | 60 ++ src/fix_deform.cpp | 1207 +++++++------------------ src/fix_deform.h | 20 +- 7 files changed, 2074 insertions(+), 1114 deletions(-) create mode 100644 doc/src/fix_deform_pressure.rst create mode 100644 src/EXTRA-FIX/fix_deform_pressure.cpp create mode 100644 src/EXTRA-FIX/fix_deform_pressure.h diff --git a/doc/src/fix_deform.rst b/doc/src/fix_deform.rst index a4d449850ed..924397c42a8 100644 --- a/doc/src/fix_deform.rst +++ b/doc/src/fix_deform.rst @@ -20,7 +20,7 @@ Syntax .. parsed-literal:: - parameter = *x* or *y* or *z* or *xy* or *xz* or *yz* or *iso* + parameter = *x* or *y* or *z* or *xy* or *xz* or *yz* *x*, *y*, *z* args = style value(s) style = *final* or *delta* or *scale* or *vel* or *erate* or *trate* or *volume* or *wiggle* or *variable* *final* values = lo hi @@ -34,12 +34,6 @@ Syntax effectively an engineering strain rate *erate* value = R R = engineering strain rate (1/time units) - *pressure* values = target gain - target = target pressure (pressure units) - gain = proportional gain constant (1/(time * pressure) or 1/time units) - *pressure/mean* values = target gain - target = target pressure (pressure units) - gain = proportional gain constant (1/(time * pressure) or 1/time units) *trate* value = R R = true strain rate (1/time units) *volume* value = none = adjust this dim to preserve volume of system @@ -60,9 +54,6 @@ Syntax effectively an engineering shear strain rate *erate* value = R R = engineering shear strain rate (1/time units) - *pressure* values = target gain - target = target pressure (pressure units) - gain = proportional gain constant (1/(time * pressure) or 1/time units) *trate* value = R R = true shear strain rate (1/time units) *wiggle* values = A Tp @@ -71,15 +62,9 @@ Syntax *variable* values = v_name1 v_name2 v_name1 = variable with name1 for tilt change as function of time v_name2 = variable with name2 for change rate as function of time - *iso* = style value - style = *volume* or *pressure* - *volume* value = none = isotropically adjust system to preserve volume of system - *pressure* values = target gain - target = target mean pressure (pressure units) - gain = proportional gain constant (1/(time * pressure) or 1/time units) * zero or more keyword/value pairs may be appended -* keyword = *remap* or *flip* or *units* or *couple* or *vol/balance/p* or *max/rate* or *normalize/pressure* +* keyword = *remap* or *flip* or *units* .. parsed-literal:: @@ -92,14 +77,6 @@ Syntax *units* value = *lattice* or *box* lattice = distances are defined in lattice units box = distances are defined in simulation box units - *couple* value = *none* or *xyz* or *xy* or *yz* or *xz* - couple pressure values of various dimensions - *vol/balance/p* value = *yes* or *no* - Modifies the behavior of the *volume* option to try and balance pressures - *max/rate* value = *rate* - rate = maximum strain rate for pressure control - *normalize/pressure* value = *yes* or *no* - Modifies pressure controls such that the deviation in pressure is normalized by the target pressure Examples """""""" @@ -110,9 +87,6 @@ Examples fix 1 all deform 1 x trate 0.1 y volume z volume fix 1 all deform 1 xy erate 0.001 remap v fix 1 all deform 10 y delta -0.5 0.5 xz vel 1.0 - fix 1 all deform 1 x pressure 2.0 0.1 normalize/pressure yes max/rate 0.001 - fix 1 all deform 1 x trate 0.1 y volume z volume vol/balance/p yes - fix 1 all deform 1 x trate 0.1 y pressure/mean 0.0 1.0 z pressure/mean 0.0 1.0 Description """"""""""" @@ -256,11 +230,7 @@ the product of x,z lengths constant. If "x scale 1.1 y volume z volume" is specified, then both the y,z box lengths will shrink as x increases to keep the volume constant (product of x,y,z lengths). In this case, the y,z box lengths shrink so as to keep their relative -aspect ratio constant. When maintaining a constant volume using two -separate dimensions, one can alternatively allow the two dimensions -to adjust their aspect ratio to attempt to maintain equivalent -pressures along the two dimensions. See the -:ref:`vol/balance/p ` option for more details. +aspect ratio constant. For solids or liquids, note that when one dimension of the box is expanded via fix deform (i.e. tensile strain), it may be physically @@ -322,39 +292,6 @@ For the *scale*, *vel*, *erate*, *trate*, *volume*, *wiggle*, and *variable* styles, the box length is expanded or compressed around its mid point. -The *pressure* style adjusts a dimensions's box length to control that -component of the pressure tensor. This option attempts to maintain a -specified target value using a linear controller where the box length -:math:`L` evolves according to the equation - -.. parsed-literal:: - - \frac{d L(t)}{dt} = L(t) k (P_t - P) - -where :math:`k` is a proportional gain constant, :math:`P_t` is the target -pressure, and :math:`P` is the current pressure along that dimension. This -approach is similar to the method used to control the pressure by -:doc:`fix press/berendsen `. The target pressure -accepts either a constant numeric value or a LAMMPS :ref:`variable `. -Notably, this variable can be a function of time or other components of -the pressure tensor. By default, :math:`k` has units of 1/(time * pressure) -although this will change if the *normalize/pessure* option is set as -:ref:`discussed below `. There is no proven method -to choosing an appropriate value of :math:`k` as it will depend on the -specific details of a simulation and testing different values is -recommended. One can also apply a maximum limit to the magnitude of the -applied strain using the :ref:`max/rate ` option and couple -pressures in different dimensions using the :ref:`couple ` -option. - -The *pressure/mean* style changes a dimension's box length to maintain -a constant mean pressure defined as the trace of the pressure tensor. -This option is therefore very similar to the *pressure* style with -identical arguments except the current and target pressures refer to the -mean trace of the pressure tensor. All options for the *pressure* style -also apply to the *pressure/mean* style except for the -:ref:`couple ` option. - ---------- For the *xy*, *xz*, and *yz* parameters, this is the meaning of their @@ -496,46 +433,6 @@ assume that the current timestep = 0. variable rate equal "2*PI*v_A/v_Tp * cos(2*PI * step*dt/v_Tp)" fix 2 all deform 1 xy variable v_displace v_rate remap v -The *pressure* style adjusts a tilt factor to control the corresponding -off-diagonal component of the pressure tensor. This option attempts to -maintain a specified target value using a linear controller where the -tilt factor T evolves according to the equation - -.. parsed-literal:: - - \frac{d T(t)}{dt} = L(t) k (P - P_t) - -where :math:`k` is a proportional gain constant, :math:`P_t` is the target -pressure, :math:`P` is the current pressure, and :math:`L` is the perpendicular -box length. The target pressure accepts either a constant numeric value or a -LAMMPS :ref:`variable `. Notably, this variable can be a function -of time or other components of the pressure tensor. By default, :math:`k` -has units of 1/(time * pressure) although this will change if the -*normalize/pessure* option is set as :ref:`discussed below `. -There is no proven method to choosing an appropriate value of :math:`k` as it -will depend on thespecific details of a simulation and testing different -values isrecommended. One can also apply a maximum limit to the magnitude -of the applied strain using the :ref:`max/rate ` option. - ----------- - -The *iso* parameter provides an additonal control over the x, y, -and z box lengths. This parameter can only be used in combination with -the *x*, *y*, or *z* comamnds: *vel*, *erate*, *trate*, *pressure*, or -*wiggle*. Note that this parameter will change the overall strain rate in -the *x*, *y*, or *z* dimensions. This is the meaning of its styles and values. - -The *volume* style isotropically scales box lengths to maintain a constant -box volume in response to deformation from other parameters. - -The *pressure* style controls the box volume to maintain the mean pressure -of the system. This is accomplished by isotropically scaling all box -lengths :math:`L` by an additional factor of :math:`k (P_t - P_m)` where -:math:`k` is the proportional gain constant, :math:`P_t` is the target -pressure, and :math:`P_m` is the current mean pressure (the trace of the -pressure tensor). This style allows one to control the deviatoric strain -tensor while maintaining a fixed mean pressure. - ---------- All of the tilt styles change the xy, xz, yz tilt factors during a @@ -664,77 +561,6 @@ does not affect the *variable* style. You should use the *xlat*, *ylat*, *zlat* keywords of the :doc:`thermo_style ` command if you want to include lattice spacings in a variable formula. -.. _deform_normalize: - -The *normalize/pressure* keyword changes how box dimensions evolve when -using the *pressure* or *pressure/mean* deformation options. If the -*deform/normalize* value is set to *yes*, then the deviation from the -target pressure is normalized by the absolute value of the target -pressure such that the proportional gain constant scales a percentage -error and has units of 1/time. If the target pressure is ever zero, this -will produce an error unless the *max/rate* keyword is defined, -described below, which will cap the divergence. - -.. _deform_max_rate: - -The *max/rate* keyword sets an upper threshold, *rate*, that limits the -maximum magnitude of the instantaneous strain rate applied in any dimension. -This keyword only applies to the *pressure* and *pressure/mean* options. If -a pressure-controlled rate is used for both *iso* and either *x*, *y*, or -*z*, then this threshold will apply separately to each individual controller -such that the cumulative strain rate on a box dimension may be up to twice -the value of *rate*. - -.. _deform_couple: - -The *couple* keyword allows two or three of the diagonal components of -the pressure tensor to be "coupled" together for the *pressure* option. -The value specified with the keyword determines which are coupled. For -example, *xz* means the *Pxx* and *Pzz* components of the stress tensor -are coupled. *Xyz* means all 3 diagonal components are coupled. Coupling -means two things: the instantaneous stress will be computed as an average -of the corresponding diagonal components, and the coupled box dimensions -will be changed together in lockstep, meaning coupled dimensions will be -dilated or contracted by the same percentage every timestep. The target -pressures and gain constants for any coupled dimensions must be identical. -*Couple xyz* can be used for a 2d simulation; the *z* dimension is simply -ignored. - -.. _deform_balance: - -The *vol/balance/p* keyword modifies the behavior of *volume* when two -dimensions are used to maintain a fixed volume. Instead of straining -the two dimensions in lockstep, the two dimensions are allowed to -separately dilate or contract in a manner to maintain a constant -volume while simultaneously trying to keep the pressure along each -dimension equal using a method described in :ref:`(Huang2014) `. - ----------- - -If any pressure controls are used, this fix computes a temperature and -pressure each timestep. To do this, the fix creates its own computes of -style "temp" and "pressure", as if these commands had been issued: - -.. code-block:: LAMMPS - - compute fix-ID_temp group-ID temp - compute fix-ID_press group-ID pressure fix-ID_temp - -See the :doc:`compute temp ` and :doc:`compute pressure ` commands for details. Note that the -IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID -+ underscore + "press", and the group for the new computes is the same -as the fix group. - -Note that these are NOT the computes used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo_temp* -and *thermo_press*. This means you can change the attributes of this -fix's temperature or pressure via the -:doc:`compute_modify ` command or print this temperature -or pressure during thermodynamic output via the -:doc:`thermo_style custom ` command using the appropriate -compute-ID. It also means that changing attributes of *thermo_temp* or -*thermo_press* will have no effect on this fix. - ---------- .. include:: accel_styles.rst @@ -748,15 +574,6 @@ command. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored by this fix for access by various :doc:`output commands `. -If any pressure controls are used, the :doc:`fix_modify ` *temp* -and *press* options are supported by this fix. You can use them to assign a -:doc:`compute ` you have defined to this fix which will be used -in its temperature and pressure calculations. If you do this, note -that the kinetic energy derived from the compute temperature should be -consistent with the virial term computed using all atoms for the -pressure. LAMMPS will warn you if you choose to compute temperature -on a subset of atoms. - This fix can perform deformation over multiple runs, using the *start* and *stop* keywords of the :doc:`run ` command. See the :doc:`run ` command for details of how to do this. @@ -780,14 +597,4 @@ Related commands Default """"""" -The option defaults are remap = x, flip = yes, units = lattice, and -normalize/pressure = no. - ----------- - -.. _Li2014b: - -**(Huang2014)** X. Huang, -"Exploring critical-state behavior using DEM", -Doctoral dissertation, Imperial College. -(2014). https://doi.org/10.25560/25316 +The option defaults are remap = x, flip = yes, units = lattice diff --git a/doc/src/fix_deform_pressure.rst b/doc/src/fix_deform_pressure.rst new file mode 100644 index 00000000000..d19e5fba7e8 --- /dev/null +++ b/doc/src/fix_deform_pressure.rst @@ -0,0 +1,793 @@ +.. index:: fix deform +.. index:: fix deform/kk + +fix deform command +================== + +Accelerator Variants: *deform/kk* + +Syntax +"""""" + +.. parsed-literal:: + + fix ID group-ID deform N parameter args ... keyword value ... + +* ID, group-ID are documented in :doc:`fix ` command +* deform = style name of this fix command +* N = perform box deformation every this many timesteps +* one or more parameter/arg pairs may be appended + + .. parsed-literal:: + + parameter = *x* or *y* or *z* or *xy* or *xz* or *yz* or *iso* + *x*, *y*, *z* args = style value(s) + style = *final* or *delta* or *scale* or *vel* or *erate* or *trate* or *volume* or *wiggle* or *variable* + *final* values = lo hi + lo hi = box boundaries at end of run (distance units) + *delta* values = dlo dhi + dlo dhi = change in box boundaries at end of run (distance units) + *scale* values = factor + factor = multiplicative factor for change in box length at end of run + *vel* value = V + V = change box length at this velocity (distance/time units), + effectively an engineering strain rate + *erate* value = R + R = engineering strain rate (1/time units) + *pressure* values = target gain + target = target pressure (pressure units) + gain = proportional gain constant (1/(time * pressure) or 1/time units) + *pressure/mean* values = target gain + target = target pressure (pressure units) + gain = proportional gain constant (1/(time * pressure) or 1/time units) + *trate* value = R + R = true strain rate (1/time units) + *volume* value = none = adjust this dim to preserve volume of system + *wiggle* values = A Tp + A = amplitude of oscillation (distance units) + Tp = period of oscillation (time units) + *variable* values = v_name1 v_name2 + v_name1 = variable with name1 for box length change as function of time + v_name2 = variable with name2 for change rate as function of time + *xy*, *xz*, *yz* args = style value + style = *final* or *delta* or *vel* or *erate* or *trate* or *wiggle* + *final* value = tilt + tilt = tilt factor at end of run (distance units) + *delta* value = dtilt + dtilt = change in tilt factor at end of run (distance units) + *vel* value = V + V = change tilt factor at this velocity (distance/time units), + effectively an engineering shear strain rate + *erate* value = R + R = engineering shear strain rate (1/time units) + *pressure* values = target gain + target = target pressure (pressure units) + gain = proportional gain constant (1/(time * pressure) or 1/time units) + *trate* value = R + R = true shear strain rate (1/time units) + *wiggle* values = A Tp + A = amplitude of oscillation (distance units) + Tp = period of oscillation (time units) + *variable* values = v_name1 v_name2 + v_name1 = variable with name1 for tilt change as function of time + v_name2 = variable with name2 for change rate as function of time + *iso* = style value + style = *volume* or *pressure* + *volume* value = none = isotropically adjust system to preserve volume of system + *pressure* values = target gain + target = target mean pressure (pressure units) + gain = proportional gain constant (1/(time * pressure) or 1/time units) + +* zero or more keyword/value pairs may be appended +* keyword = *remap* or *flip* or *units* or *couple* or *vol/balance/p* or *max/rate* or *normalize/pressure* + + .. parsed-literal:: + + *remap* value = *x* or *v* or *none* + x = remap coords of atoms in group into deforming box + v = remap velocities of atoms in group when they cross periodic boundaries + none = no remapping of x or v + *flip* value = *yes* or *no* + allow or disallow box flips when it becomes highly skewed + *units* value = *lattice* or *box* + lattice = distances are defined in lattice units + box = distances are defined in simulation box units + *couple* value = *none* or *xyz* or *xy* or *yz* or *xz* + couple pressure values of various dimensions + *vol/balance/p* value = *yes* or *no* + Modifies the behavior of the *volume* option to try and balance pressures + *max/rate* value = *rate* + rate = maximum strain rate for pressure control + *normalize/pressure* value = *yes* or *no* + Modifies pressure controls such that the deviation in pressure is normalized by the target pressure + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix 1 all deform 1 x final 0.0 9.0 z final 0.0 5.0 units box + fix 1 all deform 1 x trate 0.1 y volume z volume + fix 1 all deform 1 xy erate 0.001 remap v + fix 1 all deform 10 y delta -0.5 0.5 xz vel 1.0 + fix 1 all deform 1 x pressure 2.0 0.1 normalize/pressure yes max/rate 0.001 + fix 1 all deform 1 x trate 0.1 y volume z volume vol/balance/p yes + fix 1 all deform 1 x trate 0.1 y pressure/mean 0.0 1.0 z pressure/mean 0.0 1.0 + +Description +""""""""""" + +Change the volume and/or shape of the simulation box during a dynamics +run. Orthogonal simulation boxes have 3 adjustable parameters +(x,y,z). Triclinic (non-orthogonal) simulation boxes have 6 +adjustable parameters (x,y,z,xy,xz,yz). Any or all of them can be +adjusted independently and simultaneously by this command. + +This fix can be used to perform non-equilibrium MD (NEMD) simulations +of a continuously strained system. See the :doc:`fix nvt/sllod ` and :doc:`compute temp/deform ` commands for more details. Note +that simulation of a continuously extended system (extensional flow) +can be modeled using the :ref:`UEF package ` and its :doc:`fix commands `. + +For the *x*, *y*, *z* parameters, the associated dimension cannot be +shrink-wrapped. For the *xy*, *yz*, *xz* parameters, the associated +second dimension cannot be shrink-wrapped. Dimensions not varied by this +command can be periodic or non-periodic. Dimensions corresponding to +unspecified parameters can also be controlled by a :doc:`fix npt ` or :doc:`fix nph ` command. + +The size and shape of the simulation box at the beginning of the +simulation run were either specified by the +:doc:`create_box ` or :doc:`read_data ` or +:doc:`read_restart ` command used to setup the simulation +initially if it is the first run, or they are the values from the end +of the previous run. The :doc:`create_box `, :doc:`read data `, and :doc:`read_restart ` commands +specify whether the simulation box is orthogonal or non-orthogonal +(triclinic) and explain the meaning of the xy,xz,yz tilt factors. If +fix deform changes the xy,xz,yz tilt factors, then the simulation box +must be triclinic, even if its initial tilt factors are 0.0. + +As described below, the desired simulation box size and shape at the +end of the run are determined by the parameters of the fix deform +command. Every Nth timestep during the run, the simulation box is +expanded, contracted, or tilted to ramped values between the initial +and final values. + +---------- + +For the *x*, *y*, and *z* parameters, this is the meaning of their +styles and values. + +The *final*, *delta*, *scale*, *vel*, and *erate* styles all change +the specified dimension of the box via "constant displacement" which +is effectively a "constant engineering strain rate". This means the +box dimension changes linearly with time from its initial to final +value. + +For style *final*, the final lo and hi box boundaries of a dimension +are specified. The values can be in lattice or box distance units. +See the discussion of the units keyword below. + +For style *delta*, plus or minus changes in the lo/hi box boundaries +of a dimension are specified. The values can be in lattice or box +distance units. See the discussion of the units keyword below. + +For style *scale*, a multiplicative factor to apply to the box length +of a dimension is specified. For example, if the initial box length +is 10, and the factor is 1.1, then the final box length will be 11. A +factor less than 1.0 means compression. + +For style *vel*, a velocity at which the box length changes is +specified in units of distance/time. This is effectively a "constant +engineering strain rate", where rate = V/L0 and L0 is the initial box +length. The distance can be in lattice or box distance units. See +the discussion of the units keyword below. For example, if the +initial box length is 100 Angstroms, and V is 10 Angstroms/ps, then +after 10 ps, the box length will have doubled. After 20 ps, it +will have tripled. + +The *erate* style changes a dimension of the box at a "constant +engineering strain rate". The units of the specified strain rate are +1/time. See the :doc:`units ` command for the time units +associated with different choices of simulation units, +e.g. picoseconds for "metal" units). Tensile strain is unitless and +is defined as delta/L0, where L0 is the original box length and delta +is the change relative to the original length. The box length L as a +function of time will change as + +.. parsed-literal:: + + L(t) = L0 (1 + erate\*dt) + +where dt is the elapsed time (in time units). Thus if *erate* R is +specified as 0.1 and time units are picoseconds, this means the box +length will increase by 10% of its original length every picosecond. +I.e. strain after 1 ps = 0.1, strain after 2 ps = 0.2, etc. R = +-0.01 means the box length will shrink by 1% of its original length +every picosecond. Note that for an "engineering" rate the change is +based on the original box length, so running with R = 1 for 10 +picoseconds expands the box length by a factor of 11 (strain of 10), +which is different that what the *trate* style would induce. + +The *trate* style changes a dimension of the box at a "constant true +strain rate". Note that this is not an "engineering strain rate", as +the other styles are. Rather, for a "true" rate, the rate of change +is constant, which means the box dimension changes non-linearly with +time from its initial to final value. The units of the specified +strain rate are 1/time. See the :doc:`units ` command for the +time units associated with different choices of simulation units, +e.g. picoseconds for "metal" units). Tensile strain is unitless and +is defined as delta/L0, where L0 is the original box length and delta +is the change relative to the original length. + +The box length L as a function of time will change as + +.. parsed-literal:: + + L(t) = L0 exp(trate\*dt) + +where dt is the elapsed time (in time units). Thus if *trate* R is +specified as ln(1.1) and time units are picoseconds, this means the +box length will increase by 10% of its current (not original) length +every picosecond. I.e. strain after 1 ps = 0.1, strain after 2 ps += 0.21, etc. R = ln(2) or ln(3) means the box length will double or +triple every picosecond. R = ln(0.99) means the box length will +shrink by 1% of its current length every picosecond. Note that for a +"true" rate the change is continuous and based on the current length, +so running with R = ln(2) for 10 picoseconds does not expand the box +length by a factor of 11 as it would with *erate*, but by a factor of +1024 since the box length will double every picosecond. + +Note that to change the volume (or cross-sectional area) of the +simulation box at a constant rate, you can change multiple dimensions +via *erate* or *trate*\ . E.g. to double the box volume in a picosecond +picosecond, you could set "x erate M", "y erate M", "z erate M", with +M = pow(2,1/3) - 1 = 0.26, since if each box dimension grows by 26%, +the box volume doubles. Or you could set "x trate M", "y trate M", "z +trate M", with M = ln(1.26) = 0.231, and the box volume would double +every picosecond. + +The *volume* style changes the specified dimension in such a way that +the box volume remains constant while other box dimensions are changed +explicitly via the styles discussed above. For example, "x scale 1.1 +y scale 1.1 z volume" will shrink the z box length as the x,y box +lengths increase, to keep the volume constant (product of x,y,z +lengths). If "x scale 1.1 z volume" is specified and parameter *y* is +unspecified, then the z box length will shrink as x increases to keep +the product of x,z lengths constant. If "x scale 1.1 y volume z +volume" is specified, then both the y,z box lengths will shrink as x +increases to keep the volume constant (product of x,y,z lengths). In +this case, the y,z box lengths shrink so as to keep their relative +aspect ratio constant. When maintaining a constant volume using two +separate dimensions, one can alternatively allow the two dimensions +to adjust their aspect ratio to attempt to maintain equivalent +pressures along the two dimensions. See the +:ref:`vol/balance/p ` option for more details. + +For solids or liquids, note that when one dimension of the box is +expanded via fix deform (i.e. tensile strain), it may be physically +undesirable to hold the other 2 box lengths constant (unspecified by +fix deform) since that implies a density change. Using the *volume* +style for those 2 dimensions to keep the box volume constant may make +more physical sense, but may also not be correct for materials and +potentials whose Poisson ratio is not 0.5. An alternative is to use +:doc:`fix npt aniso ` with zero applied pressure on those 2 +dimensions, so that they respond to the tensile strain dynamically. + +The *wiggle* style oscillates the specified box length dimension +sinusoidally with the specified amplitude and period. I.e. the box +length L as a function of time is given by + +.. parsed-literal:: + + L(t) = L0 + A sin(2\*pi t/Tp) + +where L0 is its initial length. If the amplitude A is a positive +number the box initially expands, then contracts, etc. If A is +negative then the box initially contracts, then expands, etc. The +amplitude can be in lattice or box distance units. See the discussion +of the units keyword below. + +The *variable* style changes the specified box length dimension by +evaluating a variable, which presumably is a function of time. The +variable with *name1* must be an :doc:`equal-style variable ` +and should calculate a change in box length in units of distance. +Note that this distance is in box units, not lattice units; see the +discussion of the *units* keyword below. The formula associated with +variable *name1* can reference the current timestep. Note that it +should return the "change" in box length, not the absolute box length. +This means it should evaluate to 0.0 when invoked on the initial +timestep of the run following the definition of fix deform. It should +evaluate to a value > 0.0 to dilate the box at future times, or a +value < 0.0 to compress the box. + +The variable *name2* must also be an :doc:`equal-style variable ` and should calculate the rate of box length +change, in units of distance/time, i.e. the time-derivative of the +*name1* variable. This quantity is used internally by LAMMPS to reset +atom velocities when they cross periodic boundaries. It is computed +internally for the other styles, but you must provide it when using an +arbitrary variable. + +Here is an example of using the *variable* style to perform the same +box deformation as the *wiggle* style formula listed above, where we +assume that the current timestep = 0. + +.. code-block:: LAMMPS + + variable A equal 5.0 + variable Tp equal 10.0 + variable displace equal "v_A * sin(2*PI * step*dt/v_Tp)" + variable rate equal "2*PI*v_A/v_Tp * cos(2*PI * step*dt/v_Tp)" + fix 2 all deform 1 x variable v_displace v_rate remap v + +For the *scale*, *vel*, *erate*, *trate*, *volume*, *wiggle*, and +*variable* styles, the box length is expanded or compressed around its +mid point. + +The *pressure* style adjusts a dimensions's box length to control that +component of the pressure tensor. This option attempts to maintain a +specified target value using a linear controller where the box length +:math:`L` evolves according to the equation + +.. parsed-literal:: + + \frac{d L(t)}{dt} = L(t) k (P_t - P) + +where :math:`k` is a proportional gain constant, :math:`P_t` is the target +pressure, and :math:`P` is the current pressure along that dimension. This +approach is similar to the method used to control the pressure by +:doc:`fix press/berendsen `. The target pressure +accepts either a constant numeric value or a LAMMPS :ref:`variable `. +Notably, this variable can be a function of time or other components of +the pressure tensor. By default, :math:`k` has units of 1/(time * pressure) +although this will change if the *normalize/pessure* option is set as +:ref:`discussed below `. There is no proven method +to choosing an appropriate value of :math:`k` as it will depend on the +specific details of a simulation and testing different values is +recommended. One can also apply a maximum limit to the magnitude of the +applied strain using the :ref:`max/rate ` option and couple +pressures in different dimensions using the :ref:`couple ` +option. + +The *pressure/mean* style changes a dimension's box length to maintain +a constant mean pressure defined as the trace of the pressure tensor. +This option is therefore very similar to the *pressure* style with +identical arguments except the current and target pressures refer to the +mean trace of the pressure tensor. All options for the *pressure* style +also apply to the *pressure/mean* style except for the +:ref:`couple ` option. + +---------- + +For the *xy*, *xz*, and *yz* parameters, this is the meaning of their +styles and values. Note that changing the tilt factors of a triclinic +box does not change its volume. + +The *final*, *delta*, *vel*, and *erate* styles all change the shear +strain at a "constant engineering shear strain rate". This means the +tilt factor changes linearly with time from its initial to final +value. + +For style *final*, the final tilt factor is specified. The value +can be in lattice or box distance units. See the discussion of the +units keyword below. + +For style *delta*, a plus or minus change in the tilt factor is +specified. The value can be in lattice or box distance units. See +the discussion of the units keyword below. + +For style *vel*, a velocity at which the tilt factor changes is +specified in units of distance/time. This is effectively an +"engineering shear strain rate", where rate = V/L0 and L0 is the +initial box length perpendicular to the direction of shear. The +distance can be in lattice or box distance units. See the discussion +of the units keyword below. For example, if the initial tilt factor +is 5 Angstroms, and the V is 10 Angstroms/ps, then after 1 ps, the +tilt factor will be 15 Angstroms. After 2 ps, it will be 25 +Angstroms. + +The *erate* style changes a tilt factor at a "constant engineering +shear strain rate". The units of the specified shear strain rate are +1/time. See the :doc:`units ` command for the time units +associated with different choices of simulation units, +e.g. picoseconds for "metal" units). Shear strain is unitless and is +defined as offset/length, where length is the box length perpendicular +to the shear direction (e.g. y box length for xy deformation) and +offset is the displacement distance in the shear direction (e.g. x +direction for xy deformation) from the unstrained orientation. + +The tilt factor T as a function of time will change as + +.. parsed-literal:: + + T(t) = T0 + L0\*erate\*dt + +where T0 is the initial tilt factor, L0 is the original length of the +box perpendicular to the shear direction (e.g. y box length for xy +deformation), and dt is the elapsed time (in time units). Thus if +*erate* R is specified as 0.1 and time units are picoseconds, this +means the shear strain will increase by 0.1 every picosecond. I.e. if +the xy shear strain was initially 0.0, then strain after 1 ps = 0.1, +strain after 2 ps = 0.2, etc. Thus the tilt factor would be 0.0 at +time 0, 0.1\*ybox at 1 ps, 0.2\*ybox at 2 ps, etc, where ybox is the +original y box length. R = 1 or 2 means the tilt factor will increase +by 1 or 2 every picosecond. R = -0.01 means a decrease in shear +strain by 0.01 every picosecond. + +The *trate* style changes a tilt factor at a "constant true shear +strain rate". Note that this is not an "engineering shear strain +rate", as the other styles are. Rather, for a "true" rate, the rate +of change is constant, which means the tilt factor changes +non-linearly with time from its initial to final value. The units of +the specified shear strain rate are 1/time. See the +:doc:`units ` command for the time units associated with +different choices of simulation units, e.g. picoseconds for "metal" +units). Shear strain is unitless and is defined as offset/length, +where length is the box length perpendicular to the shear direction +(e.g. y box length for xy deformation) and offset is the displacement +distance in the shear direction (e.g. x direction for xy deformation) +from the unstrained orientation. + +The tilt factor T as a function of time will change as + +.. parsed-literal:: + + T(t) = T0 exp(trate\*dt) + +where T0 is the initial tilt factor and dt is the elapsed time (in +time units). Thus if *trate* R is specified as ln(1.1) and time units +are picoseconds, this means the shear strain or tilt factor will +increase by 10% every picosecond. I.e. if the xy shear strain was +initially 0.1, then strain after 1 ps = 0.11, strain after 2 ps = +0.121, etc. R = ln(2) or ln(3) means the tilt factor will double or +triple every picosecond. R = ln(0.99) means the tilt factor will +shrink by 1% every picosecond. Note that the change is continuous, so +running with R = ln(2) for 10 picoseconds does not change the tilt +factor by a factor of 10, but by a factor of 1024 since it doubles +every picosecond. Note that the initial tilt factor must be non-zero +to use the *trate* option. + +Note that shear strain is defined as the tilt factor divided by the +perpendicular box length. The *erate* and *trate* styles control the +tilt factor, but assume the perpendicular box length remains constant. +If this is not the case (e.g. it changes due to another fix deform +parameter), then this effect on the shear strain is ignored. + +The *wiggle* style oscillates the specified tilt factor sinusoidally +with the specified amplitude and period. I.e. the tilt factor T as a +function of time is given by + +.. parsed-literal:: + + T(t) = T0 + A sin(2\*pi t/Tp) + +where T0 is its initial value. If the amplitude A is a positive +number the tilt factor initially becomes more positive, then more +negative, etc. If A is negative then the tilt factor initially +becomes more negative, then more positive, etc. The amplitude can be +in lattice or box distance units. See the discussion of the units +keyword below. + +The *variable* style changes the specified tilt factor by evaluating a +variable, which presumably is a function of time. The variable with +*name1* must be an :doc:`equal-style variable ` and should +calculate a change in tilt in units of distance. Note that this +distance is in box units, not lattice units; see the discussion of the +*units* keyword below. The formula associated with variable *name1* +can reference the current timestep. Note that it should return the +"change" in tilt factor, not the absolute tilt factor. This means it +should evaluate to 0.0 when invoked on the initial timestep of the run +following the definition of fix deform. + +The variable *name2* must also be an :doc:`equal-style variable ` and should calculate the rate of tilt change, +in units of distance/time, i.e. the time-derivative of the *name1* +variable. This quantity is used internally by LAMMPS to reset atom +velocities when they cross periodic boundaries. It is computed +internally for the other styles, but you must provide it when using an +arbitrary variable. + +Here is an example of using the *variable* style to perform the same +box deformation as the *wiggle* style formula listed above, where we +assume that the current timestep = 0. + +.. code-block:: LAMMPS + + variable A equal 5.0 + variable Tp equal 10.0 + variable displace equal "v_A * sin(2*PI * step*dt/v_Tp)" + variable rate equal "2*PI*v_A/v_Tp * cos(2*PI * step*dt/v_Tp)" + fix 2 all deform 1 xy variable v_displace v_rate remap v + +The *pressure* style adjusts a tilt factor to control the corresponding +off-diagonal component of the pressure tensor. This option attempts to +maintain a specified target value using a linear controller where the +tilt factor T evolves according to the equation + +.. parsed-literal:: + + \frac{d T(t)}{dt} = L(t) k (P - P_t) + +where :math:`k` is a proportional gain constant, :math:`P_t` is the target +pressure, :math:`P` is the current pressure, and :math:`L` is the perpendicular +box length. The target pressure accepts either a constant numeric value or a +LAMMPS :ref:`variable `. Notably, this variable can be a function +of time or other components of the pressure tensor. By default, :math:`k` +has units of 1/(time * pressure) although this will change if the +*normalize/pessure* option is set as :ref:`discussed below `. +There is no proven method to choosing an appropriate value of :math:`k` as it +will depend on thespecific details of a simulation and testing different +values is recommended. One can also apply a maximum limit to the magnitude +of the applied strain using the :ref:`max/rate ` option. + +---------- + +The *iso* parameter provides an additonal control over the x, y, +and z box lengths. This parameter can only be used in combination with +the *x*, *y*, or *z* comamnds: *vel*, *erate*, *trate*, *pressure*, or +*wiggle*. Note that this parameter will change the overall strain rate in +the *x*, *y*, or *z* dimensions. This is the meaning of its styles and values. + +The *volume* style isotropically scales box lengths to maintain a constant +box volume in response to deformation from other parameters. + +The *pressure* style controls the box volume to maintain the mean pressure +of the system. This is accomplished by isotropically scaling all box +lengths :math:`L` by an additional factor of :math:`k (P_t - P_m)` where +:math:`k` is the proportional gain constant, :math:`P_t` is the target +pressure, and :math:`P_m` is the current mean pressure (the trace of the +pressure tensor). This style allows one to control the deviatoric strain +tensor while maintaining a fixed mean pressure. + +---------- + +All of the tilt styles change the xy, xz, yz tilt factors during a +simulation. In LAMMPS, tilt factors (xy,xz,yz) for triclinic boxes +are normally bounded by half the distance of the parallel box length. +See the discussion of the *flip* keyword below, to allow this bound to +be exceeded, if desired. + +For example, if xlo = 2 and xhi = 12, then the x box length is 10 and +the xy tilt factor must be between -5 and 5. Similarly, both xz and +yz must be between -(xhi-xlo)/2 and +(yhi-ylo)/2. Note that this is +not a limitation, since if the maximum tilt factor is 5 (as in this +example), then configurations with tilt = ..., -15, -5, 5, 15, 25, +... are all equivalent. + +To obey this constraint and allow for large shear deformations to be +applied via the *xy*, *xz*, or *yz* parameters, the following +algorithm is used. If *prd* is the associated parallel box length (10 +in the example above), then if the tilt factor exceeds the accepted +range of -5 to 5 during the simulation, then the box is flipped to the +other limit (an equivalent box) and the simulation continues. Thus +for this example, if the initial xy tilt factor was 0.0 and "xy final +100.0" was specified, then during the simulation the xy tilt factor +would increase from 0.0 to 5.0, the box would be flipped so that the +tilt factor becomes -5.0, the tilt factor would increase from -5.0 to +5.0, the box would be flipped again, etc. The flip occurs 10 times +and the final tilt factor at the end of the simulation would be 0.0. +During each flip event, atoms are remapped into the new box in the +appropriate manner. + +The one exception to this rule is if the first dimension in the tilt +factor (x for xy) is non-periodic. In that case, the limits on the +tilt factor are not enforced, since flipping the box in that dimension +does not change the atom positions due to non-periodicity. In this +mode, if you tilt the system to extreme angles, the simulation will +simply become inefficient due to the highly skewed simulation box. + +---------- + +Each time the box size or shape is changed, the *remap* keyword +determines whether atom positions are remapped to the new box. If +*remap* is set to *x* (the default), atoms in the fix group are +remapped; otherwise they are not. Note that their velocities are not +changed, just their positions are altered. If *remap* is set to *v*, +then any atom in the fix group that crosses a periodic boundary will +have a delta added to its velocity equal to the difference in +velocities between the lo and hi boundaries. Note that this velocity +difference can include tilt components, e.g. a delta in the x velocity +when an atom crosses the y periodic boundary. If *remap* is set to +*none*, then neither of these remappings take place. + +Conceptually, setting *remap* to *x* forces the atoms to deform via an +affine transformation that exactly matches the box deformation. This +setting is typically appropriate for solids. Note that though the +atoms are effectively "moving" with the box over time, it is not due +to their having a velocity that tracks the box change, but only due to +the remapping. By contrast, setting *remap* to *v* is typically +appropriate for fluids, where you want the atoms to respond to the +change in box size/shape on their own and acquire a velocity that +matches the box change, so that their motion will naturally track the +box without explicit remapping of their coordinates. + +.. note:: + + When non-equilibrium MD (NEMD) simulations are performed using + this fix, the option "remap v" should normally be used. This is + because :doc:`fix nvt/sllod ` adjusts the atom positions + and velocities to induce a velocity profile that matches the changing + box size/shape. Thus atom coordinates should NOT be remapped by fix + deform, but velocities SHOULD be when atoms cross periodic boundaries, + since that is consistent with maintaining the velocity profile already + created by fix nvt/sllod. LAMMPS will warn you if the *remap* setting + is not consistent with fix nvt/sllod. + +.. note:: + + For non-equilibrium MD (NEMD) simulations using "remap v" it is + usually desirable that the fluid (or flowing material, e.g. granular + particles) stream with a velocity profile consistent with the + deforming box. As mentioned above, using a thermostat such as :doc:`fix nvt/sllod ` or :doc:`fix lavgevin ` + (with a bias provided by :doc:`compute temp/deform `), will typically accomplish + that. If you do not use a thermostat, then there is no driving force + pushing the atoms to flow in a manner consistent with the deforming + box. E.g. for a shearing system the box deformation velocity may vary + from 0 at the bottom to 10 at the top of the box. But the stream + velocity profile of the atoms may vary from -5 at the bottom to +5 at + the top. You can monitor these effects using the :doc:`fix ave/chunk `, :doc:`compute temp/deform `, and :doc:`compute temp/profile ` commands. One way to induce + atoms to stream consistent with the box deformation is to give them an + initial velocity profile, via the :doc:`velocity ramp ` + command, that matches the box deformation rate. This also typically + helps the system come to equilibrium more quickly, even if a + thermostat is used. + +.. note:: + + If a :doc:`fix rigid ` is defined for rigid bodies, and + *remap* is set to *x*, then the center-of-mass coordinates of rigid + bodies will be remapped to the changing simulation box. This will be + done regardless of whether atoms in the rigid bodies are in the fix + deform group or not. The velocity of the centers of mass are not + remapped even if *remap* is set to *v*, since :doc:`fix nvt/sllod ` does not currently do anything special + for rigid particles. If you wish to perform a NEMD simulation of + rigid particles, you can either thermostat them independently or + include a background fluid and thermostat the fluid via :doc:`fix nvt/sllod `. + +The *flip* keyword allows the tilt factors for a triclinic box to +exceed half the distance of the parallel box length, as discussed +above. If the *flip* value is set to *yes*, the bound is enforced by +flipping the box when it is exceeded. If the *flip* value is set to +*no*, the tilt will continue to change without flipping. Note that if +you apply large deformations, this means the box shape can tilt +dramatically LAMMPS will run less efficiently, due to the large volume +of communication needed to acquire ghost atoms around a processor's +irregular-shaped sub-domain. For extreme values of tilt, LAMMPS may +also lose atoms and generate an error. + +The *units* keyword determines the meaning of the distance units used +to define various arguments. A *box* value selects standard distance +units as defined by the :doc:`units ` command, e.g. Angstroms for +units = real or metal. A *lattice* value means the distance units are +in lattice spacings. The :doc:`lattice ` command must have +been previously used to define the lattice spacing. Note that the +units choice also affects the *vel* style parameters since it is +defined in terms of distance/time. Also note that the units keyword +does not affect the *variable* style. You should use the *xlat*, +*ylat*, *zlat* keywords of the :doc:`thermo_style ` +command if you want to include lattice spacings in a variable formula. + +.. _deform_normalize: + +The *normalize/pressure* keyword changes how box dimensions evolve when +using the *pressure* or *pressure/mean* deformation options. If the +*deform/normalize* value is set to *yes*, then the deviation from the +target pressure is normalized by the absolute value of the target +pressure such that the proportional gain constant scales a percentage +error and has units of 1/time. If the target pressure is ever zero, this +will produce an error unless the *max/rate* keyword is defined, +described below, which will cap the divergence. + +.. _deform_max_rate: + +The *max/rate* keyword sets an upper threshold, *rate*, that limits the +maximum magnitude of the instantaneous strain rate applied in any dimension. +This keyword only applies to the *pressure* and *pressure/mean* options. If +a pressure-controlled rate is used for both *iso* and either *x*, *y*, or +*z*, then this threshold will apply separately to each individual controller +such that the cumulative strain rate on a box dimension may be up to twice +the value of *rate*. + +.. _deform_couple: + +The *couple* keyword allows two or three of the diagonal components of +the pressure tensor to be "coupled" together for the *pressure* option. +The value specified with the keyword determines which are coupled. For +example, *xz* means the *Pxx* and *Pzz* components of the stress tensor +are coupled. *Xyz* means all 3 diagonal components are coupled. Coupling +means two things: the instantaneous stress will be computed as an average +of the corresponding diagonal components, and the coupled box dimensions +will be changed together in lockstep, meaning coupled dimensions will be +dilated or contracted by the same percentage every timestep. The target +pressures and gain constants for any coupled dimensions must be identical. +*Couple xyz* can be used for a 2d simulation; the *z* dimension is simply +ignored. + +.. _deform_balance: + +The *vol/balance/p* keyword modifies the behavior of *volume* when two +dimensions are used to maintain a fixed volume. Instead of straining +the two dimensions in lockstep, the two dimensions are allowed to +separately dilate or contract in a manner to maintain a constant +volume while simultaneously trying to keep the pressure along each +dimension equal using a method described in :ref:`(Huang2014) `. + +---------- + +If any pressure controls are used, this fix computes a temperature and +pressure each timestep. To do this, the fix creates its own computes of +style "temp" and "pressure", as if these commands had been issued: + +.. code-block:: LAMMPS + + compute fix-ID_temp group-ID temp + compute fix-ID_press group-ID pressure fix-ID_temp + +See the :doc:`compute temp ` and :doc:`compute pressure ` commands for details. Note that the +IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID ++ underscore + "press", and the group for the new computes is the same +as the fix group. + +Note that these are NOT the computes used by thermodynamic output (see +the :doc:`thermo_style ` command) with ID = *thermo_temp* +and *thermo_press*. This means you can change the attributes of this +fix's temperature or pressure via the +:doc:`compute_modify ` command or print this temperature +or pressure during thermodynamic output via the +:doc:`thermo_style custom ` command using the appropriate +compute-ID. It also means that changing attributes of *thermo_temp* or +*thermo_press* will have no effect on this fix. + +---------- + +.. include:: accel_styles.rst + +Restart, fix_modify, output, run start/stop, minimize info +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +This fix will restore the initial box settings from :doc:`binary restart files `, which allows the fix to be properly continue +deformation, when using the start/stop options of the :doc:`run ` +command. None of the :doc:`fix_modify ` options are +relevant to this fix. No global or per-atom quantities are stored by +this fix for access by various :doc:`output commands `. + +If any pressure controls are used, the :doc:`fix_modify ` *temp* +and *press* options are supported by this fix. You can use them to assign a +:doc:`compute ` you have defined to this fix which will be used +in its temperature and pressure calculations. If you do this, note +that the kinetic energy derived from the compute temperature should be +consistent with the virial term computed using all atoms for the +pressure. LAMMPS will warn you if you choose to compute temperature +on a subset of atoms. + +This fix can perform deformation over multiple runs, using the *start* +and *stop* keywords of the :doc:`run ` command. See the +:doc:`run ` command for details of how to do this. + +This fix is not invoked during :doc:`energy minimization `. + +Restrictions +"""""""""""" + +You cannot apply x, y, or z deformations to a dimension that is +shrink-wrapped via the :doc:`boundary ` command. + +You cannot apply xy, yz, or xz deformations to a second dimension (y in +xy) that is shrink-wrapped via the :doc:`boundary ` command. + +Related commands +"""""""""""""""" + +:doc:`change_box ` + +Default +""""""" + +The option defaults are remap = x, flip = yes, units = lattice, and +normalize/pressure = no. + +---------- + +.. _Li2014b: + +**(Huang2014)** X. Huang, +"Exploring critical-state behavior using DEM", +Doctoral dissertation, Imperial College. +(2014). https://doi.org/10.25560/25316 diff --git a/src/.gitignore b/src/.gitignore index 0d3cb2ff4a2..ab68aa1055c 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -724,6 +724,8 @@ /fix_cmap.h /fix_damping_cundall.cpp /fix_damping_cundall.h +/fix_deform_pressure.cpp +/fix_deform_pressure.h /fix_dpd_energy.cpp /fix_dpd_energy.h /fix_electron_stopping.cpp diff --git a/src/EXTRA-FIX/fix_deform_pressure.cpp b/src/EXTRA-FIX/fix_deform_pressure.cpp new file mode 100644 index 00000000000..666ca5f2af8 --- /dev/null +++ b/src/EXTRA-FIX/fix_deform_pressure.cpp @@ -0,0 +1,905 @@ +// clang-format off +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Joel Clemmer (SNL) +------------------------------------------------------------------------- */ + +#include "fix_deform_pressure.h" + +#include "atom.h" +#include "comm.h" +#include "compute.h" +#include "domain.h" +#include "error.h" +#include "force.h" +#include "group.h" +#include "input.h" +#include "irregular.h" +#include "kspace.h" +#include "lattice.h" +#include "math_const.h" +#include "modify.h" +#include "update.h" +#include "variable.h" + +#include +#include + +using namespace LAMMPS_NS; +using namespace FixConst; +using namespace MathConst; + +enum{NONE=0,FINAL,DELTA,SCALE,VEL,ERATE,TRATE,VOLUME,WIGGLE,VARIABLE,PRESSURE,PMEAN}; +enum{ONE_FROM_ONE,ONE_FROM_TWO,TWO_FROM_ONE}; +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) +{ + // populate coupled pressure controls + + if (pcouple != NOCOUPLE) { + int coupled_indices[3] = {0}; + int j = -1; + double couple_gain, coupled_pressure; + char *couple_str; + + 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[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[i].pgain = set[j].pgain; + if (set[j].pvar_flag) { + set[i].pstr = set[j].pstr; + set[i].pvar_flag = 1; + } else { + set[i].ptarget = set[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[i].pgain != set[j].pgain || set[i].pvar_flag != set[j].pvar_flag || + set[i].ptarget != set[j].ptarget) + error->all(FLERR, "Coupled dimensions must have identical gain parameters"); + + if (set[j].pvar_flag) + if (strcmp(set[i].pstr, set[j].pstr) != 0) + error->all(FLERR, "Coupled dimensions must have the same target pressure"); + } + } + } + } + + // repeat some checks in child class to catch changes to pcouple + + if (dimflag[0]) box_change |= BOX_CHANGE_X; + if (dimflag[1]) box_change |= BOX_CHANGE_Y; + if (dimflag[2]) box_change |= BOX_CHANGE_Z; + + // no tensile deformation on shrink-wrapped dims + // b/c shrink wrap will change box-length + + for (int i = 0; i < 3; i++) + if ((set[i].style || set[6].style) && (domain->boundary[i][0] >= 2 || domain->boundary[i][1] >= 2)) + error->all(FLERR, "Cannot use fix deform/pressure on a shrink-wrapped boundary"); + + // 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 < 7; i++) { + if (set[i].style == PRESSURE || set[i].style == PMEAN) pressure_flag = 1; + if (set[i].coupled_flag) 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 iso + + if (set[6].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 iso 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"); + 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"); + modify->add_compute(fmt::format("{} all pressure {}",id_press, id_temp)); + pflag = 1; + } +} + +/* ---------------------------------------------------------------------- */ + +FixDeformPressure::~FixDeformPressure() +{ + // 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(); + + // check optional variables for PRESSURE or PMEAN style + + for (int i = 0; i < 7; i++) { + if (!set[i].pvar_flag) continue; + set[i].pvar = input->variable->find(set[i].pstr); + if (set[i].pvar < 0) + error->all(FLERR, "Variable name {} for fix deform/pressure does not exist", set[i].pstr); + if (!input->variable->equalstyle(set[i].pvar)) + error->all(FLERR, "Variable {} for fix deform/pressure is invalid style", set[i].pstr); + } + + // Find pressure/temp computes if needed + + if (pressure_flag) { + int icompute = modify->find_compute(id_temp); + if (icompute < 0) error->all(FLERR, "Temperature ID for fix deform/pressure does not exist"); + temperature = modify->compute[icompute]; + + icompute = modify->find_compute(id_press); + if (icompute < 0) error->all(FLERR, "Pressure ID for fix deform/pressure does not exist"); + pressure = modify->compute[icompute]; + } +} + +/* ---------------------------------------------------------------------- + compute T,P if needed before integrator starts +------------------------------------------------------------------------- */ + +void FixDeformPressure::setup(int /*vflag*/) +{ + // trigger virial computation 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::set_strain(); + + // 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[i].saved) { + set[i].saved = 1; + set[i].prior_rate = 0.0; + set[i].prior_pressure = pressure->vector[i]; + } + } + set_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) set_volume(); + + // apply any final isotropic scalings + + if (set[6].style) set_iso(); + + // Save pressure/strain rate if required + + if (pressure_flag) { + for (int i = 0; i < 3; i++) { + set[i].prior_pressure = pressure->vector[i]; + set[i].prior_rate = ((set[i].hi_target - set[i].lo_target) / + (domain->boxhi[i] - domain->boxlo[i]) - 1.0) / update->dt; + } + } + + if (varflag) modify->addstep_compute(update->ntimestep + nevery); + + + FixDeform::apply_deformation(); + + // trigger virial computation, if needed, on next timestep + + if (pressure_flag) + pressure->addstep(update->ntimestep+1); +} + +/* ---------------------------------------------------------------------- + set box size for pressure-based dimensions +------------------------------------------------------------------------- */ + +void FixDeformPressure::set_pressure() +{ + // If variable pressure, calculate current target + for (int i = 0; i < 6; i++) + if (set[i].style == PRESSURE) + if (set[i].pvar_flag) + set[i].ptarget = input->variable->compute_equal(set[i].pvar); + + // Find current (possibly coupled/hydrostatic) pressure for X, Y, Z + double *tensor = pressure->vector; + double scalar = pressure->scalar; + double p_current[3]; + + 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[i].pgain * (p_current[i] - set[i].ptarget); + + if (normalize_pressure_flag) { + if (set[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[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 offset = 0.5 * (domain->boxhi[i] - domain->boxlo[i]) * (1.0 + update->dt * h_rate[i]); + set[i].lo_target = 0.5 * (set[i].lo_start + set[i].hi_start) - offset; + set[i].hi_target = 0.5 * (set[i].lo_start + set[i].hi_start) + offset; + } + + for (int i = 3; i < 6; i++) { + if (set[i].style != PRESSURE) continue; + + double L, tilt, pcurrent; + if (i == 3) { + L = domain->zprd; + tilt = domain->yz; + pcurrent = tensor[5]; + } else if (i == 4) { + L = domain->zprd; + tilt = domain->xz + update->dt; + pcurrent = tensor[4]; + } else { + L = domain->yprd; + tilt = domain->xy; + pcurrent = tensor[3]; + } + + h_rate[i] = L * set[i].pgain * (pcurrent - set[i].ptarget); + if (normalize_pressure_flag) { + if (set[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[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[i].tilt_target = tilt + update->dt * h_rate[i]; + } +} + +/* ---------------------------------------------------------------------- + set box size for VOLUME dimensions +------------------------------------------------------------------------- */ + +void FixDeformPressure::set_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; + + 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[i].prior_rate; + double e2i = set[fixed].prior_rate; + double L1i = domain->boxhi[i] - domain->boxlo[i]; + double L2i = domain->boxhi[fixed] - domain->boxlo[fixed]; + double L3i = domain->boxhi[dynamic1] - domain->boxlo[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[i].prior_pressure; + double p2i = set[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->boxhi[i] - domain->boxlo[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 isotropic controls +------------------------------------------------------------------------- */ + +void FixDeformPressure::set_iso() +{ + int i; + double scale, shift; + double v_rate; + + if (set[6].style == VOLUME) { + double v0 = set[6].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->boxhi[i] - domain->boxlo[i]) - 1.0; + h_rate[i] /= update->dt; + h_ratelo[i] = -0.5 * h_rate[i]; + } + + } else if (set[6].style == PRESSURE) { + + // If variable pressure, calculate current target + if (set[6].pvar_flag) + set[6].ptarget = input->variable->compute_equal(set[6].pvar); + + v_rate = set[6].pgain * (pressure->scalar- set[6].ptarget); + + if (normalize_pressure_flag) { + if (set[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[6].ptarget); + } + + if (max_h_rate != 0) + if (fabs(v_rate) > max_h_rate) + v_rate = max_h_rate * v_rate / fabs(v_rate); + + set[6].cumulative_strain += update->dt * v_rate; + scale = (1.0 + set[6].cumulative_strain); + 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->boxhi[i] - domain->boxlo[i]) - 1.0; + h_rate[i] /= update->dt; + h_ratelo[i] = -0.5 * h_rate[i]; + } + } +} + +/* ---------------------------------------------------------------------- */ + +void FixDeformPressure::options(int narg, char **arg) +{ + if (narg < 0) error->all(FLERR, "Illegal fix deform/pressure command"); + + remapflag = Domain::X_REMAP; + scaleflag = 1; + flipflag = 1; + + pcouple = NOCOUPLE; + dimension = domain->dimension; + max_h_rate = 0.0; + vol_balance_flag = 0; + normalize_pressure_flag = 0; + + int index; + int iarg = 4; + while (iarg < narg) { + 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], "final") == 0) { + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure final", error); + set[index].style = FINAL; + set[index].flo = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + set[index].fhi = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + iarg += 4; + } else if (strcmp(arg[iarg + 1], "delta") == 0) { + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure delta", error); + set[index].style = DELTA; + set[index].dlo = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + set[index].dhi = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + iarg += 4; + } else if (strcmp(arg[iarg + 1], "scale") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure scale", error); + set[index].style = SCALE; + set[index].scale = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "vel") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure vel", error); + set[index].style = VEL; + set[index].vel = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "erate") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure erate", error); + set[index].style = ERATE; + set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "trate") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure trate", error); + set[index].style = TRATE; + set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "volume") == 0) { + set[index].style = VOLUME; + iarg += 2; + } else if (strcmp(arg[iarg + 1], "wiggle") == 0) { + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure wiggle", error); + set[index].style = WIGGLE; + set[index].amplitude = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + set[index].tperiod = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + if (set[index].tperiod <= 0.0) + error->all(FLERR, "Illegal fix deform/pressure wiggle period, must be positive"); + iarg += 4; + } else if (strcmp(arg[iarg + 1], "variable") == 0) { + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure variable", error); + set[index].style = VARIABLE; + if (strstr(arg[iarg + 2], "v_") != arg[iarg + 2]) + error->all(FLERR, "Illegal fix deform/pressure variable name {}", arg[iarg + 2]); + if (strstr(arg[iarg + 3], "v_") != arg[iarg + 3]) + error->all(FLERR, "Illegal fix deform/pressure variable name {}", arg[iarg + 3]); + delete[] set[index].hstr; + delete[] set[index].hratestr; + set[index].hstr = utils::strdup(&arg[iarg + 2][2]); + set[index].hratestr = utils::strdup(&arg[iarg + 3][2]); + iarg += 4; + } else 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[index].ptarget = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + } else { + set[index].pstr = utils::strdup(&arg[iarg + 2][2]); + set[index].pvar_flag = 1; + } + set[index].pgain = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + if (set[index].pgain <= 0.0) + error->all(FLERR, "Illegal fix deform/pressure pressure gain, must be positive"); + iarg += 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[index].ptarget = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + } else { + set[index].pstr = utils::strdup(&arg[iarg + 2][2]); + set[index].pvar_flag = 1; + } + set[index].pgain = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + if (set[index].pgain <= 0.0) + error->all(FLERR, "Illegal fix deform/pressure pressure gain, must be positive"); + iarg += 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 (triclinic == 0) + error->all(FLERR, "fix deform/pressure tilt factors require triclinic box"); + 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], "final") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure final", error); + set[index].style = FINAL; + set[index].ftilt = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "delta") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure delta", error); + set[index].style = DELTA; + set[index].dtilt = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "vel") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure vel", error); + set[index].style = VEL; + set[index].vel = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "erate") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure erate", error); + set[index].style = ERATE; + set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "trate") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure trate", error); + set[index].style = TRATE; + set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "wiggle") == 0) { + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure wiggle", error); + set[index].style = WIGGLE; + set[index].amplitude = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + set[index].tperiod = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + if (set[index].tperiod <= 0.0) + error->all(FLERR, "Illegal fix deform/pressure wiggle period, must be positive"); + iarg += 4; + } else if (strcmp(arg[iarg + 1], "variable") == 0) { + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure variable", error); + set[index].style = VARIABLE; + if (strstr(arg[iarg + 2], "v_") != arg[iarg + 2]) + error->all(FLERR, "Illegal fix deform/pressure variable name {}", arg[iarg + 2]); + if (strstr(arg[iarg + 3], "v_") != arg[iarg + 3]) + error->all(FLERR, "Illegal fix deform/pressure variable name {}", arg[iarg + 3]); + delete[] set[index].hstr; + delete[] set[index].hratestr; + set[index].hstr = utils::strdup(&arg[iarg + 2][2]); + set[index].hratestr = utils::strdup(&arg[iarg + 3][2]); + iarg += 4; + } else 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[index].ptarget = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + } else { + set[index].pstr = utils::strdup(&arg[iarg + 2][2]); + set[index].pvar_flag = 1; + } + set[index].pgain = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + if (set[index].pgain <= 0.0) + error->all(FLERR, "Illegal fix deform/pressure pressure gain, must be positive"); + iarg += 4; + } else error->all(FLERR, "Illegal fix deform/pressure command: {}", arg[iarg + 1]); + } else if (strcmp(arg[iarg], "iso") == 0) { + index = 6; + if (strcmp(arg[iarg + 1], "volume") == 0) { + set[index].style = VOLUME; + iarg += 2; + } else 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[index].ptarget = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + } else { + set[index].pstr = utils::strdup(&arg[iarg + 2][2]); + set[index].pvar_flag = 1; + } + set[index].pgain = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + if (set[index].pgain <= 0.0) + error->all(FLERR, "Illegal fix deform/pressure pressure gain, must be positive"); + iarg += 4; + } + } else break; + } + + while (iarg < narg) { + if (strcmp(arg[iarg], "remap") == 0) { + if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure remap", error); + if (strcmp(arg[iarg + 1], "x") == 0) remapflag = Domain::X_REMAP; + else if (strcmp(arg[iarg + 1], "v") == 0) remapflag = Domain::V_REMAP; + else if (strcmp(arg[iarg + 1], "none") == 0) remapflag = Domain::NO_REMAP; + else error->all(FLERR, "Illegal fix deform/pressure remap command: {}", arg[iarg + 1]); + iarg += 2; + } else if (strcmp(arg[iarg], "units") == 0) { + if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure units", error); + if (strcmp(arg[iarg + 1], "box") == 0) scaleflag = 0; + else if (strcmp(arg[iarg + 1], "lattice") == 0) scaleflag = 1; + else error->all(FLERR, "Illegal fix deform/pressure units command: {}", arg[iarg + 1]); + iarg += 2; + } else if (strcmp(arg[iarg], "flip") == 0) { + if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure flip", error); + flipflag = utils::logical(FLERR, arg[iarg + 1], false, lmp); + iarg += 2; + } else 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 fix deform/pressure couple command: {}", arg[iarg + 1]); + iarg += 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"); + iarg += 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); + iarg += 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); + iarg += 2; + } else error->all(FLERR, "Illegal fix deform/pressure command: {}", arg[iarg]); + } + + if (dimension == 2) + if (pcouple == XYZ || pcouple == XZ || pcouple == YZ) + error->all(FLERR, "Cannot couple Z dimension in fix deform/pressure in 2D"); +} + +/* ---------------------------------------------------------------------- */ + +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; +} diff --git a/src/EXTRA-FIX/fix_deform_pressure.h b/src/EXTRA-FIX/fix_deform_pressure.h new file mode 100644 index 00000000000..d3a05d949d3 --- /dev/null +++ b/src/EXTRA-FIX/fix_deform_pressure.h @@ -0,0 +1,60 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS +// clang-format off +FixStyle(deform/pressure,FixDeformPressure); +// clang-format on +#else + +#ifndef LMP_FIX_DEFORM_PRESSURE_H +#define LMP_FIX_DEFORM_PRESSURE_H + +#include "fix_deform.h" + +namespace LAMMPS_NS { + +class FixDeformPressure : public FixDeform { + public: + FixDeformPressure(class LAMMPS *, int, char **); + ~FixDeformPressure() override; + void init() override; + void setup(int) override; + void end_of_step() override; + int modify_param(int, char **) override; + + protected: + int pcouple, dimension; + double *h_rate, *h_ratelo, max_h_rate; + int strain_flag; // 1 if strain-based option is used, 0 if not + int pressure_flag; // 1 if pressure tensor used, 0 if not + int volume_flag; // 1 if VOLUME option is used, 0 if not + int normalize_pressure_flag; // 1 if normalize pressure deviation by target + int vol_balance_flag; // 1 if pressures balanced when maintaining const vol + + char *id_temp, *id_press; + class Compute *temperature, *pressure; + int tflag, pflag; + + void options(int, char **); + void set_pressure(); + void set_volume(); + void set_iso(); + void couple(); + void adjust_linked_rates(double&, double&, double, double, double); +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index 3430c26061f..0bd392367fd 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -20,11 +20,9 @@ #include "atom.h" #include "comm.h" -#include "compute.h" #include "domain.h" #include "error.h" #include "force.h" -#include "group.h" #include "input.h" #include "irregular.h" #include "kspace.h" @@ -41,292 +39,37 @@ using namespace LAMMPS_NS; using namespace FixConst; using namespace MathConst; -enum{NONE=0,FINAL,DELTA,SCALE,VEL,ERATE,TRATE,VOLUME,WIGGLE,VARIABLE,PRESSURE,PMEAN}; +enum{NONE=0,FINAL,DELTA,SCALE,VEL,ERATE,TRATE,VOLUME,WIGGLE,VARIABLE}; enum{ONE_FROM_ONE,ONE_FROM_TWO,TWO_FROM_ONE}; -enum{NOCOUPLE=0,XYZ,XY,YZ,XZ}; /* ---------------------------------------------------------------------- */ FixDeform::FixDeform(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), -irregular(nullptr), set(nullptr), id_temp(nullptr), id_press(nullptr) +irregular(nullptr), set(nullptr) { - if (narg < 4) error->all(FLERR,"Illegal fix deform command"); + if (narg < 4) error->all(FLERR, "Illegal fix deform command"); no_change_box = 1; restart_global = 1; pre_exchange_migrate = 1; - pcouple = NOCOUPLE; - dimension = domain->dimension; - max_h_rate = 0.0; - vol_balance_flag = 0; - normalize_pressure_flag = 0; - nevery = utils::inumeric(FLERR,arg[3],false,lmp); - if (nevery <= 0) error->all(FLERR,"Illegal fix deform command"); + nevery = utils::inumeric(FLERR, arg[3], false, lmp); + if (nevery <= 0) error->all(FLERR, "Illegal fix deform command"); // set defaults set = new Set[7]; - memset(set,0,7*sizeof(Set)); + memset(set, 0, 7 * sizeof(Set)); // parse arguments triclinic = domain->triclinic; + options(narg, arg); - int index; - int iarg = 4; - while (iarg < narg) { - 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", error); - if (strcmp(arg[iarg+1],"final") == 0) { - if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform final", error); - set[index].style = FINAL; - set[index].flo = utils::numeric(FLERR,arg[iarg+2],false,lmp); - set[index].fhi = utils::numeric(FLERR,arg[iarg+3],false,lmp); - iarg += 4; - } else if (strcmp(arg[iarg+1],"delta") == 0) { - if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform delta", error); - set[index].style = DELTA; - set[index].dlo = utils::numeric(FLERR,arg[iarg+2],false,lmp); - set[index].dhi = utils::numeric(FLERR,arg[iarg+3],false,lmp); - iarg += 4; - } else if (strcmp(arg[iarg+1],"scale") == 0) { - if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix deform scale", error); - set[index].style = SCALE; - set[index].scale = utils::numeric(FLERR,arg[iarg+2],false,lmp); - iarg += 3; - } else if (strcmp(arg[iarg+1],"vel") == 0) { - if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix deform vel", error); - set[index].style = VEL; - set[index].vel = utils::numeric(FLERR,arg[iarg+2],false,lmp); - iarg += 3; - } else if (strcmp(arg[iarg+1],"erate") == 0) { - if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix deform erate", error); - set[index].style = ERATE; - set[index].rate = utils::numeric(FLERR,arg[iarg+2],false,lmp); - iarg += 3; - } else if (strcmp(arg[iarg+1],"trate") == 0) { - if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix deform trate", error); - set[index].style = TRATE; - set[index].rate = utils::numeric(FLERR,arg[iarg+2],false,lmp); - iarg += 3; - } else if (strcmp(arg[iarg+1],"volume") == 0) { - set[index].style = VOLUME; - iarg += 2; - } else if (strcmp(arg[iarg+1],"wiggle") == 0) { - if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform wiggle", error); - set[index].style = WIGGLE; - set[index].amplitude = utils::numeric(FLERR,arg[iarg+2],false,lmp); - set[index].tperiod = utils::numeric(FLERR,arg[iarg+3],false,lmp); - if (set[index].tperiod <= 0.0) - error->all(FLERR,"Illegal fix deform wiggle period, must be positive"); - iarg += 4; - } else if (strcmp(arg[iarg+1],"variable") == 0) { - if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform variable", error); - set[index].style = VARIABLE; - if (strstr(arg[iarg+2],"v_") != arg[iarg+2]) - error->all(FLERR,"Illegal fix deform variable name {}", arg[iarg+2]); - if (strstr(arg[iarg+3],"v_") != arg[iarg+3]) - error->all(FLERR,"Illegal fix deform variable name {}", arg[iarg+3]); - delete[] set[index].hstr; - delete[] set[index].hratestr; - set[index].hstr = utils::strdup(&arg[iarg+2][2]); - set[index].hratestr = utils::strdup(&arg[iarg+3][2]); - iarg += 4; - } else if (strcmp(arg[iarg+1],"pressure") == 0) { - if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform pressure", error); - set[index].style = PRESSURE; - if (strstr(arg[iarg+2],"v_") != arg[iarg+2]) { - set[index].ptarget = utils::numeric(FLERR,arg[iarg+2],false,lmp); - } else { - set[index].pstr = utils::strdup(&arg[iarg+2][2]); - set[index].pvar_flag = 1; - } - set[index].pgain = utils::numeric(FLERR,arg[iarg+3],false,lmp); - if (set[index].pgain <= 0.0) - error->all(FLERR,"Illegal fix deform pressure gain, must be positive"); - iarg += 4; - } else if (strcmp(arg[iarg+1],"pressure/mean") == 0) { - if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform pressure/mean", error); - set[index].style = PMEAN; - if (strstr(arg[iarg+2],"v_") != arg[iarg+2]) { - set[index].ptarget = utils::numeric(FLERR,arg[iarg+2],false,lmp); - } else { - set[index].pstr = utils::strdup(&arg[iarg+2][2]); - set[index].pvar_flag = 1; - } - set[index].pgain = utils::numeric(FLERR,arg[iarg+3],false,lmp); - if (set[index].pgain <= 0.0) - error->all(FLERR,"Illegal fix deform pressure gain, must be positive"); - iarg += 4; - } else error->all(FLERR,"Illegal fix deform command argument: {}", arg[iarg+1]); - - } else if (strcmp(arg[iarg],"xy") == 0 || - strcmp(arg[iarg],"xz") == 0 || - strcmp(arg[iarg],"yz") == 0) { - - if (triclinic == 0) - error->all(FLERR,"Fix deform tilt factors require triclinic box"); - 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", error); - if (strcmp(arg[iarg+1],"final") == 0) { - if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix deform final", error); - set[index].style = FINAL; - set[index].ftilt = utils::numeric(FLERR,arg[iarg+2],false,lmp); - iarg += 3; - } else if (strcmp(arg[iarg+1],"delta") == 0) { - if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix deform delta", error); - set[index].style = DELTA; - set[index].dtilt = utils::numeric(FLERR,arg[iarg+2],false,lmp); - iarg += 3; - } else if (strcmp(arg[iarg+1],"vel") == 0) { - if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix deform vel", error); - set[index].style = VEL; - set[index].vel = utils::numeric(FLERR,arg[iarg+2],false,lmp); - iarg += 3; - } else if (strcmp(arg[iarg+1],"erate") == 0) { - if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix deform erate", error); - set[index].style = ERATE; - set[index].rate = utils::numeric(FLERR,arg[iarg+2],false,lmp); - iarg += 3; - } else if (strcmp(arg[iarg+1],"trate") == 0) { - if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix deform trate", error); - set[index].style = TRATE; - set[index].rate = utils::numeric(FLERR,arg[iarg+2],false,lmp); - iarg += 3; - } else if (strcmp(arg[iarg+1],"wiggle") == 0) { - if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform wiggle", error); - set[index].style = WIGGLE; - set[index].amplitude = utils::numeric(FLERR,arg[iarg+2],false,lmp); - set[index].tperiod = utils::numeric(FLERR,arg[iarg+3],false,lmp); - if (set[index].tperiod <= 0.0) - error->all(FLERR,"Illegal fix deform wiggle period, must be positive"); - iarg += 4; - } else if (strcmp(arg[iarg+1],"variable") == 0) { - if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform variable", error); - set[index].style = VARIABLE; - if (strstr(arg[iarg+2],"v_") != arg[iarg+2]) - error->all(FLERR,"Illegal fix deform variable name {}", arg[iarg+2]); - if (strstr(arg[iarg+3],"v_") != arg[iarg+3]) - error->all(FLERR,"Illegal fix deform variable name {}", arg[iarg+3]); - delete[] set[index].hstr; - delete[] set[index].hratestr; - set[index].hstr = utils::strdup(&arg[iarg+2][2]); - set[index].hratestr = utils::strdup(&arg[iarg+3][2]); - iarg += 4; - } else if (strcmp(arg[iarg+1],"pressure") == 0) { - if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform pressure", error); - set[index].style = PRESSURE; - if (strstr(arg[iarg+2],"v_") != arg[iarg+2]) { - set[index].ptarget = utils::numeric(FLERR,arg[iarg+2],false,lmp); - } else { - set[index].pstr = utils::strdup(&arg[iarg+2][2]); - set[index].pvar_flag = 1; - } - set[index].pgain = utils::numeric(FLERR,arg[iarg+3],false,lmp); - if (set[index].pgain <= 0.0) - error->all(FLERR,"Illegal fix deform pressure gain, must be positive"); - iarg += 4; - } else error->all(FLERR,"Illegal fix deform command: {}", arg[iarg+1]); - } else if (strcmp(arg[iarg],"iso") == 0) { - index = 6; - if (strcmp(arg[iarg+1],"volume") == 0) { - set[index].style = VOLUME; - iarg += 2; - } else if (strcmp(arg[iarg+1],"pressure") == 0) { - if (iarg+4 > narg) utils::missing_cmd_args(FLERR, "fix deform pressure", error); - set[index].style = PRESSURE; - if (strstr(arg[iarg+2],"v_") != arg[iarg+2]) { - set[index].ptarget = utils::numeric(FLERR,arg[iarg+2],false,lmp); - } else { - set[index].pstr = utils::strdup(&arg[iarg+2][2]); - set[index].pvar_flag = 1; - } - set[index].pgain = utils::numeric(FLERR,arg[iarg+3],false,lmp); - if (set[index].pgain <= 0.0) - error->all(FLERR,"Illegal fix deform pressure gain, must be positive"); - iarg += 4; - } - } else break; - } - - // read options from end of input line // no x remap effectively moves atoms within box, so set restart_pbc - options(narg-iarg,&arg[iarg]); if (remapflag != Domain::X_REMAP) restart_pbc = 1; - // populate coupled pressure controls - - if (pcouple != NOCOUPLE) { - int coupled_indices[3] = {0}; - int j = -1; - double couple_gain, coupled_pressure; - char *couple_str; - - 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[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; - set[i].pgain = set[j].pgain; - if (set[j].pvar_flag) { - set[i].pstr = set[j].pstr; - set[i].pvar_flag = 1; - } else { - set[i].ptarget = set[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[i].pgain != set[j].pgain || set[i].pvar_flag != set[j].pvar_flag || - set[i].ptarget != set[j].ptarget) - error->all(FLERR, "Coupled dimensions must have identical gain parameters"); - - if (set[j].pvar_flag) - if (strcmp(set[i].pstr, set[j].pstr) != 0) - error->all(FLERR, "Coupled dimensions must have the same target pressure"); - } - } - } - } - // setup dimflags used by other classes to check for volume-change conflicts for (int i = 0; i < 6; i++) @@ -351,17 +94,17 @@ irregular(nullptr), set(nullptr), id_temp(nullptr), id_press(nullptr) for (int i = 0; i < 3; i++) if ((set[i].style || set[6].style) && (domain->boundary[i][0] >= 2 || domain->boundary[i][1] >= 2)) - error->all(FLERR,"Cannot use fix deform on a shrink-wrapped boundary"); + error->all(FLERR, "Cannot use fix deform on a shrink-wrapped boundary"); // 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 tilt on a shrink-wrapped 2nd dim"); + error->all(FLERR, "Cannot use fix deform 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 tilt on a shrink-wrapped 2nd dim"); + error->all(FLERR, "Cannot use fix deform 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 tilt on a shrink-wrapped 2nd dim"); + error->all(FLERR, "Cannot use fix deform tilt on a shrink-wrapped 2nd dim"); // apply scaling to FINAL,DELTA,VEL,WIGGLE since they have dist/vel units @@ -408,17 +151,15 @@ irregular(nullptr), set(nullptr), id_temp(nullptr), id_press(nullptr) // for VOLUME, setup links to other dims // fixed, dynamic1, dynamic2 - volume_flag = 0; for (int i = 0; i < 3; i++) { if (set[i].style != VOLUME) continue; - volume_flag = 1; - int other1 = (i+1) % 3; - int other2 = (i+2) % 3; + 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 deform volume setting is invalid"); + error->all(FLERR, "Fix deform volume setting is invalid"); if (set[other1].style == NONE) { set[i].substyle = ONE_FROM_ONE; @@ -441,19 +182,8 @@ irregular(nullptr), set(nullptr), id_temp(nullptr), id_press(nullptr) set[i].dynamic1 = other1; set[i].dynamic2 = other2; } - - if (vol_balance_flag && 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 varflag varflag = 0; @@ -462,38 +192,6 @@ irregular(nullptr), set(nullptr), id_temp(nullptr), id_press(nullptr) if (set[i].pvar_flag) varflag = 1; } - // set pressure_flag - - pressure_flag = 0; - for (int i = 0; i < 7; i++) { - if (set[i].style == PRESSURE || set[i].style == PMEAN) pressure_flag = 1; - if (set[i].coupled_flag) pressure_flag = 1; - } - if (vol_balance_flag) pressure_flag = 1; - - // check conflict between constant volume/pressure - - if (volume_flag) - for (int i = 0; i < 6; i++) - if (set[i].style == PMEAN) - error->all(FLERR, "Cannot use fix deform to assign constant volume and pressure"); - - // check conflicts between x,y,z styles and iso - - if (set[6].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 iso 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"); - // set initial values at time fix deform is issued for (int i = 0; i < 3; i++) { @@ -517,29 +215,6 @@ irregular(nullptr), set(nullptr), id_temp(nullptr), id_press(nullptr) if (force_reneighbor) irregular = new Irregular(lmp); else irregular = nullptr; - // 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"); - 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"); - modify->add_compute(fmt::format("{} all pressure {}",id_press, id_temp)); - pflag = 1; - } - // initialize all rates to 0.0 in constructor instead of init so values persist // across run statements and ghosts have correct velocities until the destructor h_rate = domain->h_rate; @@ -574,13 +249,6 @@ FixDeform::~FixDeform() h_rate[0] = h_rate[1] = h_rate[2] = h_rate[3] = h_rate[4] = h_rate[5] = 0.0; h_ratelo[0] = h_ratelo[1] = h_ratelo[2] = 0.0; - - // 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; } /* ---------------------------------------------------------------------- */ @@ -601,7 +269,7 @@ void FixDeform::init() // domain, fix nvt/sllod, compute temp/deform only work on single h_rate if (modify->get_fix_by_style("deform").size() > 1) - error->all(FLERR,"More than one fix deform"); + error->all(FLERR, "More than one fix deform"); // Kspace setting @@ -618,25 +286,14 @@ void FixDeform::init() if (set[i].style != VARIABLE) continue; set[i].hvar = input->variable->find(set[i].hstr); if (set[i].hvar < 0) - error->all(FLERR,"Variable name {} for fix deform does not exist", set[i].hstr); + error->all(FLERR, "Variable name {} for fix deform does not exist", set[i].hstr); if (!input->variable->equalstyle(set[i].hvar)) - error->all(FLERR,"Variable {} for fix deform is invalid style", set[i].hstr); + error->all(FLERR, "Variable {} for fix deform is invalid style", set[i].hstr); set[i].hratevar = input->variable->find(set[i].hratestr); if (set[i].hratevar < 0) - error->all(FLERR,"Variable name {} for fix deform does not exist", set[i].hratestr); + error->all(FLERR, "Variable name {} for fix deform does not exist", set[i].hratestr); if (!input->variable->equalstyle(set[i].hratevar)) - error->all(FLERR,"Variable {} for fix deform is invalid style", set[i].hratestr); - } - - // check optional variables for PRESSURE or PMEAN style - - for (int i = 0; i < 7; i++) { - if (!set[i].pvar_flag) continue; - set[i].pvar = input->variable->find(set[i].pstr); - if (set[i].pvar < 0) - error->all(FLERR,"Variable name {} for fix deform does not exist", set[i].pstr); - if (!input->variable->equalstyle(set[i].pvar)) - error->all(FLERR,"Variable {} for fix deform is invalid style", set[i].pstr); + error->all(FLERR, "Variable {} for fix deform is invalid style", set[i].hratestr); } // set start/stop values for box size and shape @@ -674,7 +331,7 @@ void FixDeform::init() set[i].lo_stop = set[i].lo_start - shift; set[i].hi_stop = set[i].hi_start + shift; if (set[i].hi_stop <= set[i].lo_stop) - error->all(FLERR,"Final box dimension due to fix deform is < 0.0"); + error->all(FLERR, "Final box dimension due to fix deform is < 0.0"); } else if (set[i].style == TRATE) { double shift = 0.5 * ((set[i].hi_start - set[i].lo_start) * exp(set[i].rate * delt)); set[i].lo_stop = 0.5 * (set[i].lo_start + set[i].hi_start) - shift; @@ -752,22 +409,22 @@ void FixDeform::init() for (int i = 3; i < 6; i++) if (set[i].style == TRATE && set[i].tilt_start == 0.0) - error->all(FLERR,"Cannot use fix deform trate on a box with zero tilt"); + error->all(FLERR, "Cannot use fix deform trate on a box with zero tilt"); // if yz changes and will cause box flip, then xy cannot be changing // yz = [3], xy = [5] // 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 - // VARIABLE or PRESSURE for yz is error, since no way to calculate if box flip occurs + // VARIABLE for yz is error, since no way to calculate if box flip occurs // WIGGLE lo/hi flip test is on min/max oscillation limit, not tilt_stop // only trigger actual errors if flipflag is set if (set[3].style && set[5].style) { int flag = 0; double lo,hi; - if (flipflag && (set[3].style == VARIABLE || set[3].style == PRESSURE)) - error->all(FLERR,"Fix deform cannot use yz variable or pressure with xy"); + if (flipflag && set[3].style == VARIABLE) + error->all(FLERR, "Fix deform cannot use yz variable with xy"); if (set[3].style == WIGGLE) { lo = set[3].tilt_min; hi = set[3].tilt_max; @@ -780,13 +437,12 @@ void FixDeform::init() hi / (set[1].hi_stop - set[1].lo_stop) > 0.5) flag = 1; } if (flag) - error->all(FLERR,"Fix deform is changing yz too much with xy"); + error->all(FLERR, "Fix deform is changing yz too much with xy"); } } // set domain->h_rate values for use by domain and other fixes/computes - // cannot set here for TRATE,VOLUME,WIGGLE,VARIABLE,PRESSURE since not constant - // if iso style is used, these will also not be constant + // cannot set here for TRATE,VOLUME,WIGGLE,VARIABLE since not constant for (int i = 0; i < 3; i++) { if (set[i].style == FINAL || set[i].style == DELTA || @@ -818,28 +474,6 @@ void FixDeform::init() for (auto ifix : modify->get_fix_list()) if (ifix->rigid_flag) rfix.push_back(ifix); - - // Find pressure/temp computes if needed - - if (pressure_flag) { - int icompute = modify->find_compute(id_temp); - if (icompute < 0) error->all(FLERR,"Temperature ID for fix deform does not exist"); - temperature = modify->compute[icompute]; - - icompute = modify->find_compute(id_press); - if (icompute < 0) error->all(FLERR,"Pressure ID for fix deform does not exist"); - pressure = modify->compute[icompute]; - } -} - -/* ---------------------------------------------------------------------- - compute T,P if needed before integrator starts -------------------------------------------------------------------------- */ - -void FixDeform::setup(int /*vflag*/) -{ - // trigger virial computation on next timestep - if (pressure_flag) pressure->addstep(update->ntimestep+1); } /* ---------------------------------------------------------------------- @@ -862,7 +496,7 @@ void FixDeform::pre_exchange() domain->set_global_box(); domain->set_local_box(); - domain->image_flip(flipxy,flipxz,flipyz); + domain->image_flip(flipxy, flipxz, flipyz); double **x = atom->x; imageint *image = atom->image; @@ -888,43 +522,146 @@ void FixDeform::end_of_step() set_strain(); - // 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[i].saved) { - set[i].saved = 1; - set[i].prior_rate = 0.0; - set[i].prior_pressure = pressure->vector[i]; - } + // set new box size for VOLUME dims that are linked to other dims + // NOTE: still need to set h_rate for these dims + + set_volume(); + + if (varflag) modify->addstep_compute(update->ntimestep + nevery); + + apply_deformation(); + + // redo KSpace coeffs since box has changed + + if (kspace_flag) force->kspace->setup(); +} + +/* ---------------------------------------------------------------------- + set box size for strain-based dimensions +------------------------------------------------------------------------- */ + +void FixDeform::set_strain() +{ + // for NONE, target is current box size + // for TRATE, set target directly based on current time, also set h_rate + // for WIGGLE, set target directly based on current time, also set h_rate + // for VARIABLE, set target directly via variable eval, also set h_rate + // for others except VOLUME, target is linear value between start and stop + + double delta = update->ntimestep - update->beginstep; + if (delta != 0.0) delta /= update->endstep - update->beginstep; + + for (int i = 0; i < 3; i++) { + if (set[i].style == NONE) { + set[i].lo_target = domain->boxlo[i]; + set[i].hi_target = domain->boxhi[i]; + } else if (set[i].style == TRATE) { + double delt = (update->ntimestep - update->beginstep) * update->dt; + double shift = 0.5 * ((set[i].hi_start - set[i].lo_start) * exp(set[i].rate * delt)); + 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; + h_rate[i] = set[i].rate * domain->h[i]; + h_ratelo[i] = -0.5 * h_rate[i]; + } else if (set[i].style == WIGGLE) { + double delt = (update->ntimestep - update->beginstep) * update->dt; + double shift = 0.5 * set[i].amplitude * sin(MY_2PI * delt / set[i].tperiod); + set[i].lo_target = set[i].lo_start - shift; + set[i].hi_target = set[i].hi_start + shift; + h_rate[i] = MY_2PI / set[i].tperiod * set[i].amplitude * + cos(MY_2PI * delt / set[i].tperiod); + h_ratelo[i] = -0.5 * h_rate[i]; + } else if (set[i].style == VARIABLE) { + double del = input->variable->compute_equal(set[i].hvar); + set[i].lo_target = set[i].lo_start - 0.5 * del; + set[i].hi_target = set[i].hi_start + 0.5 * del; + h_rate[i] = input->variable->compute_equal(set[i].hratevar); + h_ratelo[i] = -0.5 * h_rate[i]; + } else if (set[i].style == FINAL || set[i].style == DELTA || set[i].style == SCALE || + set[i].style == VEL || set[i].style == ERATE) { + set[i].lo_target = set[i].lo_start + delta * (set[i].lo_stop - set[i].lo_start); + set[i].hi_target = set[i].hi_start + delta * (set[i].hi_stop - set[i].hi_start); } - set_pressure(); } - // set new box size for VOLUME dims that are linked to other dims - // NOTE: still need to set h_rate for these dims + // for triclinic, set new box shape + // for NONE, target is current tilt + // for TRATE, set target directly based on current time. also set h_rate + // for WIGGLE, set target directly based on current time. also set h_rate + // for VARIABLE, set target directly via variable eval. also set h_rate + // for other styles, target is linear value between start and stop values + + if (triclinic) { + double *h = domain->h; + + for (int i = 3; i < 6; i++) { + if (set[i].style == NONE) { + if (i == 5) set[i].tilt_target = domain->xy; + else if (i == 4) set[i].tilt_target = domain->xz; + else if (i == 3) set[i].tilt_target = domain->yz; + } else if (set[i].style == TRATE) { + double delt = (update->ntimestep - update->beginstep) * update->dt; + set[i].tilt_target = set[i].tilt_start * exp(set[i].rate * delt); + h_rate[i] = set[i].rate * domain->h[i]; + } else if (set[i].style == WIGGLE) { + double delt = (update->ntimestep - update->beginstep) * update->dt; + set[i].tilt_target = set[i].tilt_start + + set[i].amplitude * sin(MY_2PI * delt / set[i].tperiod); + h_rate[i] = MY_2PI / set[i].tperiod * set[i].amplitude * + cos(MY_2PI * delt / set[i].tperiod); + } else if (set[i].style == VARIABLE) { + double delta_tilt = input->variable->compute_equal(set[i].hvar); + set[i].tilt_target = set[i].tilt_start + delta_tilt; + h_rate[i] = input->variable->compute_equal(set[i].hratevar); + } else { + set[i].tilt_target = set[i].tilt_start + delta * (set[i].tilt_stop - set[i].tilt_start); + } + } + } +} - if (volume_flag) set_volume(); +/* ---------------------------------------------------------------------- + set box size for VOLUME dimensions +------------------------------------------------------------------------- */ - // apply any final isotropic scalings +void FixDeform::set_volume() +{ + double e1, e2; - if (set[6].style) set_iso(); + for (int i = 0; i < 3; i++) { + if (set[i].style != VOLUME) continue; - // Save pressure/strain rate if required + int dynamic1 = set[i].dynamic1; + int dynamic2 = set[i].dynamic2; + int fixed = set[i].fixed; + double v0 = set[i].vol_start; + double shift; - if (pressure_flag) { - for (int i = 0; i < 3; i++) { - set[i].prior_pressure = pressure->vector[i]; - set[i].prior_rate = ((set[i].hi_target - set[i].lo_target) / - (domain->boxhi[i] - domain->boxlo[i]) - 1.0) / update->dt; + 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) { + 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)); } + + h_rate[i] = (2.0 * shift / (domain->boxhi[i] - domain->boxlo[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; } +} - if (varflag) modify->addstep_compute(update->ntimestep + nevery); +/* ---------------------------------------------------------------------- + Apply calculated deformation +------------------------------------------------------------------------- */ +void FixDeform::apply_deformation() +{ // tilt_target can be large positive or large negative value // add/subtract box lengths until tilt_target is closest to current value @@ -1020,7 +757,7 @@ void FixDeform::end_of_step() for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) - domain->x2lamda(x[i],x[i]); + domain->x2lamda(x[i], x[i]); for (auto ifix : rfix) ifix->deform(0); @@ -1059,391 +796,11 @@ void FixDeform::end_of_step() for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) - domain->lamda2x(x[i],x[i]); + domain->lamda2x(x[i], x[i]); for (auto ifix : rfix) ifix->deform(1); } - - // redo KSpace coeffs since box has changed - - if (kspace_flag) force->kspace->setup(); - - // trigger virial computation, if needed, on next timestep - - if (pressure_flag) - pressure->addstep(update->ntimestep+1); -} - -/* ---------------------------------------------------------------------- - set box size for strain-based dimensions -------------------------------------------------------------------------- */ - -void FixDeform::set_strain() -{ - // for NONE, target is current box size - // for TRATE, set target directly based on current time, also set h_rate - // for WIGGLE, set target directly based on current time, also set h_rate - // for VARIABLE, set target directly via variable eval, also set h_rate - // for others except VOLUME, target is linear value between start and stop - - double delta = update->ntimestep - update->beginstep; - if (delta != 0.0) delta /= update->endstep - update->beginstep; - - for (int i = 0; i < 3; i++) { - if (set[i].style == NONE) { - set[i].lo_target = domain->boxlo[i]; - set[i].hi_target = domain->boxhi[i]; - } else if (set[i].style == TRATE) { - double delt = (update->ntimestep - update->beginstep) * update->dt; - double shift = 0.5 * ((set[i].hi_start - set[i].lo_start) * exp(set[i].rate * delt)); - 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; - h_rate[i] = set[i].rate * domain->h[i]; - h_ratelo[i] = -0.5 * h_rate[i]; - } else if (set[i].style == WIGGLE) { - double delt = (update->ntimestep - update->beginstep) * update->dt; - double shift = 0.5 * set[i].amplitude * sin(MY_2PI * delt / set[i].tperiod); - set[i].lo_target = set[i].lo_start - shift; - set[i].hi_target = set[i].hi_start + shift; - h_rate[i] = MY_2PI / set[i].tperiod * set[i].amplitude * - cos(MY_2PI * delt / set[i].tperiod); - h_ratelo[i] = -0.5 * h_rate[i]; - } else if (set[i].style == VARIABLE) { - double del = input->variable->compute_equal(set[i].hvar); - set[i].lo_target = set[i].lo_start - 0.5 * del; - set[i].hi_target = set[i].hi_start + 0.5 * del; - h_rate[i] = input->variable->compute_equal(set[i].hratevar); - h_ratelo[i] = -0.5 * h_rate[i]; - } else if (set[i].style == FINAL || set[i].style == DELTA || set[i].style == SCALE || - set[i].style == VEL || set[i].style == ERATE) { - set[i].lo_target = set[i].lo_start + delta * (set[i].lo_stop - set[i].lo_start); - set[i].hi_target = set[i].hi_start + delta * (set[i].hi_stop - set[i].hi_start); - } - } - - // for triclinic, set new box shape - // for NONE, target is current tilt - // for TRATE, set target directly based on current time. also set h_rate - // for WIGGLE, set target directly based on current time. also set h_rate - // for VARIABLE, set target directly via variable eval. also set h_rate - // for other styles, target is linear value between start and stop values - - if (triclinic) { - double *h = domain->h; - - for (int i = 3; i < 6; i++) { - if (set[i].style == NONE) { - if (i == 5) set[i].tilt_target = domain->xy; - else if (i == 4) set[i].tilt_target = domain->xz; - else if (i == 3) set[i].tilt_target = domain->yz; - } else if (set[i].style == TRATE) { - double delt = (update->ntimestep - update->beginstep) * update->dt; - set[i].tilt_target = set[i].tilt_start * exp(set[i].rate * delt); - h_rate[i] = set[i].rate * domain->h[i]; - } else if (set[i].style == WIGGLE) { - double delt = (update->ntimestep - update->beginstep) * update->dt; - set[i].tilt_target = set[i].tilt_start + - set[i].amplitude * sin(MY_2PI * delt / set[i].tperiod); - h_rate[i] = MY_2PI / set[i].tperiod * set[i].amplitude * - cos(MY_2PI * delt / set[i].tperiod); - } else if (set[i].style == VARIABLE) { - double delta_tilt = input->variable->compute_equal(set[i].hvar); - set[i].tilt_target = set[i].tilt_start + delta_tilt; - h_rate[i] = input->variable->compute_equal(set[i].hratevar); - } else { - set[i].tilt_target = set[i].tilt_start + delta * (set[i].tilt_stop - set[i].tilt_start); - } - } - } -} - -/* ---------------------------------------------------------------------- - set box size for pressure-based dimensions -------------------------------------------------------------------------- */ - -void FixDeform::set_pressure() -{ - // If variable pressure, calculate current target - for (int i = 0; i < 6; i++) - if (set[i].style == PRESSURE) - if (set[i].pvar_flag) - set[i].ptarget = input->variable->compute_equal(set[i].pvar); - - // Find current (possibly coupled/hydrostatic) pressure for X, Y, Z - double *tensor = pressure->vector; - double scalar = pressure->scalar; - double p_current[3]; - - 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[i].pgain * (p_current[i] - set[i].ptarget); - - if (normalize_pressure_flag) { - if (set[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[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 offset = 0.5 * (domain->boxhi[i] - domain->boxlo[i]) * (1.0 + update->dt * h_rate[i]); - set[i].lo_target = 0.5 * (set[i].lo_start + set[i].hi_start) - offset; - set[i].hi_target = 0.5 * (set[i].lo_start + set[i].hi_start) + offset; - } - - for (int i = 3; i < 6; i++) { - if (set[i].style != PRESSURE) continue; - - double L, tilt, pcurrent; - if (i == 3) { - L = domain->zprd; - tilt = domain->yz; - pcurrent = tensor[5]; - } else if (i == 4) { - L = domain->zprd; - tilt = domain->xz + update->dt; - pcurrent = tensor[4]; - } else { - L = domain->yprd; - tilt = domain->xy; - pcurrent = tensor[3]; - } - - h_rate[i] = L * set[i].pgain * (pcurrent - set[i].ptarget); - if (normalize_pressure_flag) { - if (set[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[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[i].tilt_target = tilt + update->dt * h_rate[i]; - } -} - -/* ---------------------------------------------------------------------- - set box size for VOLUME dimensions -------------------------------------------------------------------------- */ - -void FixDeform::set_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; - - 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[i].prior_rate; - double e2i = set[fixed].prior_rate; - double L1i = domain->boxhi[i] - domain->boxlo[i]; - double L2i = domain->boxhi[fixed] - domain->boxlo[fixed]; - double L3i = domain->boxhi[dynamic1] - domain->boxlo[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[i].prior_pressure; - double p2i = set[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->boxhi[i] - domain->boxlo[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 FixDeform::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 isotropic controls -------------------------------------------------------------------------- */ - -void FixDeform::set_iso() -{ - int i; - double scale, shift; - double v_rate; - - if (set[6].style == VOLUME) { - double v0 = set[6].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->boxhi[i] - domain->boxlo[i]) - 1.0; - h_rate[i] /= update->dt; - h_ratelo[i] = -0.5 * h_rate[i]; - } - - } else if (set[6].style == PRESSURE) { - - // If variable pressure, calculate current target - if (set[6].pvar_flag) - set[6].ptarget = input->variable->compute_equal(set[6].pvar); - - v_rate = set[6].pgain * (pressure->scalar- set[6].ptarget); - - if (normalize_pressure_flag) { - if (set[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[6].ptarget); - } - - if (max_h_rate != 0) - if (fabs(v_rate) > max_h_rate) - v_rate = max_h_rate * v_rate / fabs(v_rate); - - set[6].cumulative_strain += update->dt * v_rate; - scale = (1.0 + set[6].cumulative_strain); - 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->boxhi[i] - domain->boxlo[i]) - 1.0; - h_rate[i] /= update->dt; - h_ratelo[i] = -0.5 * h_rate[i]; - } - } } /* ---------------------------------------------------------------------- @@ -1454,10 +811,10 @@ void FixDeform::write_restart(FILE *fp) { if (comm->me == 0) { int size = 9 * sizeof(double) + 7 * sizeof(Set); - fwrite(&size,sizeof(int),1,fp); - fwrite(h_rate,sizeof(double),6,fp); - fwrite(h_ratelo,sizeof(double),3,fp); - fwrite(set,sizeof(Set),7,fp); + fwrite(&size, sizeof(int), 1, fp); + fwrite(h_rate, sizeof(double), 6, fp); + fwrite(h_ratelo, sizeof(double), 3, fp); + fwrite(set, sizeof(Set), 7, fp); } } @@ -1493,67 +850,168 @@ void FixDeform::restart(char *buf) samestyle = 0; } if (!samestyle) - error->all(FLERR,"Fix deform settings not consistent with restart"); + error->all(FLERR, "Fix deform settings not consistent with restart"); } /* ---------------------------------------------------------------------- */ void FixDeform::options(int narg, char **arg) { - if (narg < 0) error->all(FLERR,"Illegal fix deform command"); + if (narg < 0) error->all(FLERR, "Illegal fix deform command"); remapflag = Domain::X_REMAP; scaleflag = 1; flipflag = 1; - int iarg = 0; + int index; + int iarg = 4; while (iarg < narg) { - if (strcmp(arg[iarg],"remap") == 0) { - if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "fix deform remap", error); - if (strcmp(arg[iarg+1],"x") == 0) remapflag = Domain::X_REMAP; - else if (strcmp(arg[iarg+1],"v") == 0) remapflag = Domain::V_REMAP; - else if (strcmp(arg[iarg+1],"none") == 0) remapflag = Domain::NO_REMAP; - else error->all(FLERR,"Illegal fix deform remap command: {}", arg[iarg+1]); - iarg += 2; - } else if (strcmp(arg[iarg],"units") == 0) { - if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "fix deform units", error); - if (strcmp(arg[iarg+1],"box") == 0) scaleflag = 0; - else if (strcmp(arg[iarg+1],"lattice") == 0) scaleflag = 1; - else error->all(FLERR,"Illegal fix deform units command: {}", arg[iarg+1]); - iarg += 2; - } else if (strcmp(arg[iarg],"flip") == 0) { - if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "fix deform flip", error); - flipflag = utils::logical(FLERR,arg[iarg+1],false,lmp); - iarg += 2; - } else if (strcmp(arg[iarg],"couple") == 0) { - if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "fix deform 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 fix deform couple command: {}", arg[iarg+1]); - iarg += 2; - } else if (strcmp(arg[iarg],"max/rate") == 0) { - if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "fix deform 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"); + 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", error); + if (strcmp(arg[iarg + 1], "final") == 0) { + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform final", error); + set[index].style = FINAL; + set[index].flo = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + set[index].fhi = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + iarg += 4; + } else if (strcmp(arg[iarg + 1], "delta") == 0) { + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform delta", error); + set[index].style = DELTA; + set[index].dlo = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + set[index].dhi = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + iarg += 4; + } else if (strcmp(arg[iarg + 1], "scale") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform scale", error); + set[index].style = SCALE; + set[index].scale = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "vel") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform vel", error); + set[index].style = VEL; + set[index].vel = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "erate") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform erate", error); + set[index].style = ERATE; + set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "trate") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform trate", error); + set[index].style = TRATE; + set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "volume") == 0) { + set[index].style = VOLUME; + iarg += 2; + } else if (strcmp(arg[iarg + 1], "wiggle") == 0) { + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform wiggle", error); + set[index].style = WIGGLE; + set[index].amplitude = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + set[index].tperiod = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + if (set[index].tperiod <= 0.0) + error->all(FLERR, "Illegal fix deform wiggle period, must be positive"); + iarg += 4; + } else if (strcmp(arg[iarg + 1], "variable") == 0) { + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform variable", error); + set[index].style = VARIABLE; + if (strstr(arg[iarg + 2], "v_") != arg[iarg + 2]) + error->all(FLERR, "Illegal fix deform variable name {}", arg[iarg + 2]); + if (strstr(arg[iarg + 3], "v_") != arg[iarg + 3]) + error->all(FLERR, "Illegal fix deform variable name {}", arg[iarg + 3]); + delete[] set[index].hstr; + delete[] set[index].hratestr; + set[index].hstr = utils::strdup(&arg[iarg + 2][2]); + set[index].hratestr = utils::strdup(&arg[iarg + 3][2]); + iarg += 4; + } else error->all(FLERR, "Illegal fix deform command argument: {}", arg[iarg + 1]); + + } else if (strcmp(arg[iarg], "xy") == 0 || + strcmp(arg[iarg], "xz") == 0 || + strcmp(arg[iarg], "yz") == 0) { + + if (triclinic == 0) + error->all(FLERR, "Fix deform tilt factors require triclinic box"); + 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", error); + if (strcmp(arg[iarg + 1], "final") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform final", error); + set[index].style = FINAL; + set[index].ftilt = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "delta") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform delta", error); + set[index].style = DELTA; + set[index].dtilt = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "vel") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform vel", error); + set[index].style = VEL; + set[index].vel = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "erate") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform erate", error); + set[index].style = ERATE; + set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "trate") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform trate", error); + set[index].style = TRATE; + set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "wiggle") == 0) { + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform wiggle", error); + set[index].style = WIGGLE; + set[index].amplitude = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + set[index].tperiod = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + if (set[index].tperiod <= 0.0) + error->all(FLERR, "Illegal fix deform wiggle period, must be positive"); + iarg += 4; + } else if (strcmp(arg[iarg + 1], "variable") == 0) { + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform variable", error); + set[index].style = VARIABLE; + if (strstr(arg[iarg + 2], "v_") != arg[iarg + 2]) + error->all(FLERR, "Illegal fix deform variable name {}", arg[iarg + 2]); + if (strstr(arg[iarg + 3], "v_") != arg[iarg + 3]) + error->all(FLERR, "Illegal fix deform variable name {}", arg[iarg + 3]); + delete[] set[index].hstr; + delete[] set[index].hratestr; + set[index].hstr = utils::strdup(&arg[iarg + 2][2]); + set[index].hratestr = utils::strdup(&arg[iarg + 3][2]); + iarg += 4; + } else error->all(FLERR, "Illegal fix deform command: {}", arg[iarg + 1]); + } else break; + } + + while (iarg < narg) { + if (strcmp(arg[iarg], "remap") == 0) { + if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform remap", error); + if (strcmp(arg[iarg + 1], "x") == 0) remapflag = Domain::X_REMAP; + else if (strcmp(arg[iarg + 1], "v") == 0) remapflag = Domain::V_REMAP; + else if (strcmp(arg[iarg + 1], "none") == 0) remapflag = Domain::NO_REMAP; + else error->all(FLERR, "Illegal fix deform remap command: {}", arg[iarg + 1]); iarg += 2; - } else if (strcmp(arg[iarg],"normalize/pressure") == 0) { - if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "fix deform normalize/pressure", error); - normalize_pressure_flag = utils::logical(FLERR,arg[iarg+1],false,lmp); + } else if (strcmp(arg[iarg], "units") == 0) { + if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform units", error); + if (strcmp(arg[iarg + 1], "box") == 0) scaleflag = 0; + else if (strcmp(arg[iarg + 1], "lattice") == 0) scaleflag = 1; + else error->all(FLERR, "Illegal fix deform units command: {}", arg[iarg + 1]); iarg += 2; - } else if (strcmp(arg[iarg],"vol/balance/p") == 0) { - if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "fix deform vol/balance/p", error); - vol_balance_flag = utils::logical(FLERR,arg[iarg+1],false,lmp); + } else if (strcmp(arg[iarg], "flip") == 0) { + if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform flip", error); + flipflag = utils::logical(FLERR, arg[iarg + 1], false, lmp); iarg += 2; - } else error->all(FLERR,"Illegal fix deform command: {}", arg[iarg]); + } else error->all(FLERR, "Illegal fix deform command: {}", arg[iarg]); } - - if (dimension == 2) - if (pcouple == XYZ || pcouple == XZ || pcouple == YZ) - error->all(FLERR, "Cannot couple Z dimension in fix deform in 2D"); } /* ---------------------------------------------------------------------- @@ -1566,54 +1024,3 @@ double FixDeform::memory_usage() if (irregular) bytes += irregular->memory_usage(); return bytes; } - -/* ---------------------------------------------------------------------- */ - -int FixDeform::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; -} diff --git a/src/fix_deform.h b/src/fix_deform.h index 2f0b66aa714..dc4af75d33a 100644 --- a/src/fix_deform.h +++ b/src/fix_deform.h @@ -33,32 +33,21 @@ class FixDeform : public Fix { ~FixDeform() override; int setmask() override; void init() override; - void setup(int) override; void pre_exchange() override; void end_of_step() override; void write_restart(FILE *) override; void restart(char *buf) override; double memory_usage() override; - int modify_param(int, char **) override; protected: - int dimension, triclinic, scaleflag, flipflag, pcouple; + int triclinic, scaleflag, flipflag; int flip, flipxy, flipxz, flipyz; - double *h_rate, *h_ratelo, max_h_rate; + double *h_rate, *h_ratelo; int varflag; // 1 if VARIABLE option is used, 0 if not - int strain_flag; // 1 if strain-based option is used, 0 if not - int volume_flag; // 1 if VOLUME option is used, 0 if not - int pressure_flag; // 1 if pressure tensor used, 0 if not int kspace_flag; // 1 if KSpace invoked, 0 if not - int normalize_pressure_flag; // 1 if normalize pressure deviation by target - int vol_balance_flag; // 1 if pressures balanced when maintaining const vol std::vector rfix; // pointers to rigid fixes class Irregular *irregular; // for migrating atoms after box flips - char *id_temp, *id_press; - class Compute *temperature, *pressure; - int tflag, pflag; - struct Set { int style, substyle; double flo, fhi, ftilt; @@ -84,11 +73,8 @@ class FixDeform : public Fix { void options(int, char **); void set_strain(); - void set_pressure(); void set_volume(); - void set_iso(); - void couple(); - void adjust_linked_rates(double&, double&, double, double, double); + void apply_deformation(); }; } // namespace LAMMPS_NS From 7c7f07e28d199fc7ac3948d02bb27a85b65ac5ce Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 22 Jan 2024 22:13:29 -0700 Subject: [PATCH 15/29] Misc patches and missed changes --- doc/src/fix_deform.rst | 2 +- src/EXTRA-FIX/fix_deform_pressure.cpp | 2 +- src/EXTRA-FIX/fix_deform_pressure.h | 4 ++-- src/fix_deform.cpp | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/src/fix_deform.rst b/doc/src/fix_deform.rst index 84670b37a8b..ee010f5645c 100644 --- a/doc/src/fix_deform.rst +++ b/doc/src/fix_deform.rst @@ -597,4 +597,4 @@ Related commands Default """"""" -The option defaults are remap = x, flip = yes, units = lattice +The option defaults are remap = x, flip = yes, and units = lattice. diff --git a/src/EXTRA-FIX/fix_deform_pressure.cpp b/src/EXTRA-FIX/fix_deform_pressure.cpp index 666ca5f2af8..c76550b40f2 100644 --- a/src/EXTRA-FIX/fix_deform_pressure.cpp +++ b/src/EXTRA-FIX/fix_deform_pressure.cpp @@ -2,7 +2,7 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator https://www.lammps.org/, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov + 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 diff --git a/src/EXTRA-FIX/fix_deform_pressure.h b/src/EXTRA-FIX/fix_deform_pressure.h index d3a05d949d3..7e4ad6e35a9 100644 --- a/src/EXTRA-FIX/fix_deform_pressure.h +++ b/src/EXTRA-FIX/fix_deform_pressure.h @@ -1,7 +1,7 @@ /* -*- c++ -*- ---------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator https://www.lammps.org/, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov + 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 @@ -35,7 +35,7 @@ class FixDeformPressure : public FixDeform { protected: int pcouple, dimension; - double *h_rate, *h_ratelo, max_h_rate; + double max_h_rate; int strain_flag; // 1 if strain-based option is used, 0 if not int pressure_flag; // 1 if pressure tensor used, 0 if not int volume_flag; // 1 if VOLUME option is used, 0 if not diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index d78e28ef2fc..cf45a12f5db 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -13,7 +13,7 @@ ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- - Contributing author: Pieter in 't Veld (SNL), Joel Clemmer (SNL) + Contributing author: Pieter in 't Veld (SNL) ------------------------------------------------------------------------- */ #include "fix_deform.h" @@ -759,7 +759,7 @@ void FixDeform::apply_deformation() if (mask[i] & groupbit) domain->x2lamda(x[i], x[i]); - for (auto ifix : rfix) + for (auto &ifix : rfix) ifix->deform(0); } @@ -798,7 +798,7 @@ void FixDeform::apply_deformation() if (mask[i] & groupbit) domain->lamda2x(x[i], x[i]); - for (auto ifix : rfix) + for (auto &ifix : rfix) ifix->deform(1); } } From 7f152de062c9e7f1bb356a4d2b846d748eb313bb Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 30 Jan 2024 15:29:02 -0700 Subject: [PATCH 16/29] Rewiring arg parsing and data ownership --- src/EXTRA-FIX/fix_deform_pressure.cpp | 589 +++++++++++++------------- src/EXTRA-FIX/fix_deform_pressure.h | 20 +- src/fix_deform.cpp | 367 ++++++++-------- src/fix_deform.h | 18 +- 4 files changed, 520 insertions(+), 474 deletions(-) diff --git a/src/EXTRA-FIX/fix_deform_pressure.cpp b/src/EXTRA-FIX/fix_deform_pressure.cpp index c76550b40f2..7f3a627b66b 100644 --- a/src/EXTRA-FIX/fix_deform_pressure.cpp +++ b/src/EXTRA-FIX/fix_deform_pressure.cpp @@ -50,9 +50,160 @@ 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) { + // set defaults + + set_extra = new SetExtra[7]; + memset(set_extra, 0, 7 * sizeof(SetExtra)); + memset(&set_box, 0, sizeof(Set)); + + // parse child-specific arguments + + int index; + int iarg = 4; + while (iarg < narg) { + 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); + iarg += 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); + iarg += 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); + iarg += 4; + } 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; + iarg += 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); + iarg += 4; + } else error->all(FLERR, "Illegal fix deform/pressure command argument: {}", arg[iarg + 1]); + } else break; + } + + // read options from end of input line + + options(narg - iarg, &arg[iarg]); + + // repeat: check triclinic + + dimension = domain->dimension; + if (triclinic == 0 && (set[3].style || set[4].style || set[5].style)) + error->all(FLERR, "Fix deform tilt factors require triclinic box"); + + // 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 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 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 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 tilt on a shrink-wrapped 2nd dim"); + + // 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 is issued + + set_box.vol_initial = domain->xprd * domain->yprd * domain->zprd; + // populate coupled pressure controls if (pcouple != NOCOUPLE) { + + if (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; double couple_gain, coupled_pressure; @@ -68,7 +219,7 @@ id_temp(nullptr), id_press(nullptr) // Check coupled styles and find reference for (int i = 0; i < 3; i++) { if (coupled_indices[i]) { - set[i].coupled_flag = 1; + 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) @@ -86,12 +237,12 @@ id_temp(nullptr), id_press(nullptr) if (set[i].style == NONE) { set[i].style = PRESSURE; dimflag[i] = 1; - set[i].pgain = set[j].pgain; - if (set[j].pvar_flag) { - set[i].pstr = set[j].pstr; - set[i].pvar_flag = 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[i].ptarget = set[j].ptarget; + set_extra[i].ptarget = set_extra[j].ptarget; } } else { // Check for incompatibilities in style @@ -100,31 +251,18 @@ id_temp(nullptr), id_press(nullptr) if (set[j].style != PRESSURE) continue; // If pressure controlled, check for incompatibilities in parameters - if (set[i].pgain != set[j].pgain || set[i].pvar_flag != set[j].pvar_flag || - set[i].ptarget != set[j].ptarget) + 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[j].pvar_flag) - if (strcmp(set[i].pstr, set[j].pstr) != 0) + 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"); } } } } - // repeat some checks in child class to catch changes to pcouple - - if (dimflag[0]) box_change |= BOX_CHANGE_X; - if (dimflag[1]) box_change |= BOX_CHANGE_Y; - if (dimflag[2]) box_change |= BOX_CHANGE_Z; - - // no tensile deformation on shrink-wrapped dims - // b/c shrink wrap will change box-length - - for (int i = 0; i < 3; i++) - if ((set[i].style || set[6].style) && (domain->boundary[i][0] >= 2 || domain->boundary[i][1] >= 2)) - error->all(FLERR, "Cannot use fix deform/pressure on a shrink-wrapped boundary"); - // if vol/balance/p used, must have 2 free dimensions if (vol_balance_flag) { @@ -146,10 +284,15 @@ id_temp(nullptr), id_press(nullptr) // set pressure_flag pressure_flag = 0; - for (int i = 0; i < 7; i++) { - if (set[i].style == PRESSURE || set[i].style == PMEAN) pressure_flag = 1; - if (set[i].coupled_flag) pressure_flag = 1; + 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 @@ -164,12 +307,12 @@ id_temp(nullptr), id_press(nullptr) 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 iso + // check conflicts between x,y,z styles and box - if (set[6].style) + 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 iso parameter with x, y, or z styles other than vel, erate, trate, pressure, and wiggle"); + 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 @@ -207,6 +350,14 @@ id_temp(nullptr), id_press(nullptr) 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); @@ -221,15 +372,17 @@ 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[i].pvar_flag) continue; - set[i].pvar = input->variable->find(set[i].pstr); - if (set[i].pvar < 0) - error->all(FLERR, "Variable name {} for fix deform/pressure does not exist", set[i].pstr); - if (!input->variable->equalstyle(set[i].pvar)) - error->all(FLERR, "Variable {} for fix deform/pressure is invalid style", set[i].pstr); + 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 @@ -265,7 +418,7 @@ void FixDeformPressure::end_of_step() // set new box size for strain-based dims - if (strain_flag) FixDeform::set_strain(); + if (strain_flag) FixDeform::apply_strain(); // set new box size for pressure-based dims @@ -274,30 +427,30 @@ void FixDeformPressure::end_of_step() pressure->compute_vector(); pressure->compute_scalar(); for (int i = 0; i < 3; i++) { - if (!set[i].saved) { - set[i].saved = 1; - set[i].prior_rate = 0.0; - set[i].prior_pressure = pressure->vector[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]; } } - set_pressure(); + 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) set_volume(); + if (volume_flag) apply_volume(); - // apply any final isotropic scalings + // apply any final box scalings - if (set[6].style) set_iso(); + if (set_box.style) apply_box(); // Save pressure/strain rate if required if (pressure_flag) { for (int i = 0; i < 3; i++) { - set[i].prior_pressure = pressure->vector[i]; - set[i].prior_rate = ((set[i].hi_target - set[i].lo_target) / + set_extra[i].prior_pressure = pressure->vector[i]; + set_extra[i].prior_rate = ((set[i].hi_target - set[i].lo_target) / (domain->boxhi[i] - domain->boxlo[i]) - 1.0) / update->dt; } } @@ -305,7 +458,7 @@ void FixDeformPressure::end_of_step() if (varflag) modify->addstep_compute(update->ntimestep + nevery); - FixDeform::apply_deformation(); + FixDeform::update_domain(); // trigger virial computation, if needed, on next timestep @@ -314,16 +467,16 @@ void FixDeformPressure::end_of_step() } /* ---------------------------------------------------------------------- - set box size for pressure-based dimensions + apply pressure controls ------------------------------------------------------------------------- */ -void FixDeformPressure::set_pressure() +void FixDeformPressure::apply_pressure() { // If variable pressure, calculate current target for (int i = 0; i < 6; i++) if (set[i].style == PRESSURE) - if (set[i].pvar_flag) - set[i].ptarget = input->variable->compute_equal(set[i].pvar); + 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; @@ -359,14 +512,14 @@ void FixDeformPressure::set_pressure() for (int i = 0; i < 3; i++) { if (set[i].style != PRESSURE && set[i].style != PMEAN) continue; - h_rate[i] = set[i].pgain * (p_current[i] - set[i].ptarget); + h_rate[i] = set_extra[i].pgain * (p_current[i] - set_extra[i].ptarget); if (normalize_pressure_flag) { - if (set[i].ptarget == 0) { + 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[i].ptarget); + } else h_rate[i] /= fabs(set_extra[i].ptarget); } if (max_h_rate != 0) @@ -398,13 +551,13 @@ void FixDeformPressure::set_pressure() pcurrent = tensor[3]; } - h_rate[i] = L * set[i].pgain * (pcurrent - set[i].ptarget); + h_rate[i] = L * set_extra[i].pgain * (pcurrent - set_extra[i].ptarget); if (normalize_pressure_flag) { - if (set[i].ptarget == 0) { + 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[i].ptarget); + } else h_rate[i] /= fabs(set_extra[i].ptarget); } if (max_h_rate != 0) @@ -416,10 +569,10 @@ void FixDeformPressure::set_pressure() } /* ---------------------------------------------------------------------- - set box size for VOLUME dimensions + apply volume controls ------------------------------------------------------------------------- */ -void FixDeformPressure::set_volume() +void FixDeformPressure::apply_volume() { double e1, e2; int linked_pressure = 0; @@ -446,8 +599,8 @@ void FixDeformPressure::set_volume() (set[fixed].hi_start - set[fixed].lo_start)); } else { double dt = update->dt; - double e1i = set[i].prior_rate; - double e2i = set[fixed].prior_rate; + double e1i = set_extra[i].prior_rate; + double e2i = set_extra[fixed].prior_rate; double L1i = domain->boxhi[i] - domain->boxlo[i]; double L2i = domain->boxhi[fixed] - domain->boxlo[fixed]; double L3i = domain->boxhi[dynamic1] - domain->boxlo[dynamic1]; @@ -457,8 +610,8 @@ void FixDeformPressure::set_volume() double e3 = (L3 / L3i - 1.0) / dt; double p1 = pressure->vector[i]; double p2 = pressure->vector[fixed]; - double p1i = set[i].prior_pressure; - double p2i = set[fixed].prior_pressure; + double p1i = set_extra[i].prior_pressure; + double p2i = set_extra[fixed].prior_pressure; double denominator; if (e3 == 0) { @@ -539,17 +692,17 @@ void FixDeformPressure::adjust_linked_rates(double &e_larger, double &e_smaller, } /* ---------------------------------------------------------------------- - apply isotropic controls + apply box controls ------------------------------------------------------------------------- */ -void FixDeformPressure::set_iso() +void FixDeformPressure::apply_box() { int i; double scale, shift; double v_rate; - if (set[6].style == VOLUME) { - double v0 = set[6].vol_start; + 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); @@ -566,28 +719,28 @@ void FixDeformPressure::set_iso() h_ratelo[i] = -0.5 * h_rate[i]; } - } else if (set[6].style == PRESSURE) { + } else if (set_box.style == PRESSURE) { // If variable pressure, calculate current target - if (set[6].pvar_flag) - set[6].ptarget = input->variable->compute_equal(set[6].pvar); + if (set_extra[6].pvar_flag) + set_extra[6].ptarget = input->variable->compute_equal(set_extra[6].pvar); - v_rate = set[6].pgain * (pressure->scalar- set[6].ptarget); + v_rate = set_extra[6].pgain * (pressure->scalar - set_extra[6].ptarget); if (normalize_pressure_flag) { - if (set[6].ptarget == 0) { + 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[6].ptarget); + } 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); - set[6].cumulative_strain += update->dt * v_rate; - scale = (1.0 + set[6].cumulative_strain); + set_extra[6].cumulative_strain += update->dt * v_rate; + scale = (1.0 + set_extra[6].cumulative_strain); 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; @@ -601,235 +754,95 @@ void FixDeformPressure::set_iso() } } +/* ---------------------------------------------------------------------- + write Set data to restart file +------------------------------------------------------------------------- */ + +void FixDeformPressure::write_restart(FILE *fp) +{ + if (comm->me == 0) { + int size = 9 * sizeof(double) + 7 * sizeof(Set) + 7 * sizeof(SetExtra); + fwrite(&size, sizeof(int), 1, fp); + fwrite(h_rate, sizeof(double), 6, fp); + fwrite(h_ratelo, sizeof(double), 3, 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; + auto list = (double *) buf; + for (int i = 0; i < 6; i++) + h_rate[i] = list[n++]; + for (int i = 0; i < 3; i++) + h_ratelo[i] = list[n++]; + + n = n * sizeof(double); + int samestyle = 1; + Set *set_restart = (Set *) &buf[n]; + 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 (should do the whole set?) + 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; + set_extra[i].cumulative_strain = set_extra_restart[i].cumulative_strain; + } +} + + /* ---------------------------------------------------------------------- */ void FixDeformPressure::options(int narg, char **arg) { if (narg < 0) error->all(FLERR, "Illegal fix deform/pressure command"); - remapflag = Domain::X_REMAP; - scaleflag = 1; - flipflag = 1; - pcouple = NOCOUPLE; - dimension = domain->dimension; max_h_rate = 0.0; vol_balance_flag = 0; normalize_pressure_flag = 0; - int index; - int iarg = 4; + int iarg = 0; while (iarg < narg) { - 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], "final") == 0) { - if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure final", error); - set[index].style = FINAL; - set[index].flo = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - set[index].fhi = utils::numeric(FLERR, arg[iarg + 3], false, lmp); - iarg += 4; - } else if (strcmp(arg[iarg + 1], "delta") == 0) { - if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure delta", error); - set[index].style = DELTA; - set[index].dlo = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - set[index].dhi = utils::numeric(FLERR, arg[iarg + 3], false, lmp); - iarg += 4; - } else if (strcmp(arg[iarg + 1], "scale") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure scale", error); - set[index].style = SCALE; - set[index].scale = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 3; - } else if (strcmp(arg[iarg + 1], "vel") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure vel", error); - set[index].style = VEL; - set[index].vel = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 3; - } else if (strcmp(arg[iarg + 1], "erate") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure erate", error); - set[index].style = ERATE; - set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 3; - } else if (strcmp(arg[iarg + 1], "trate") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure trate", error); - set[index].style = TRATE; - set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 3; - } else if (strcmp(arg[iarg + 1], "volume") == 0) { - set[index].style = VOLUME; - iarg += 2; - } else if (strcmp(arg[iarg + 1], "wiggle") == 0) { - if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure wiggle", error); - set[index].style = WIGGLE; - set[index].amplitude = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - set[index].tperiod = utils::numeric(FLERR, arg[iarg + 3], false, lmp); - if (set[index].tperiod <= 0.0) - error->all(FLERR, "Illegal fix deform/pressure wiggle period, must be positive"); - iarg += 4; - } else if (strcmp(arg[iarg + 1], "variable") == 0) { - if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure variable", error); - set[index].style = VARIABLE; - if (strstr(arg[iarg + 2], "v_") != arg[iarg + 2]) - error->all(FLERR, "Illegal fix deform/pressure variable name {}", arg[iarg + 2]); - if (strstr(arg[iarg + 3], "v_") != arg[iarg + 3]) - error->all(FLERR, "Illegal fix deform/pressure variable name {}", arg[iarg + 3]); - delete[] set[index].hstr; - delete[] set[index].hratestr; - set[index].hstr = utils::strdup(&arg[iarg + 2][2]); - set[index].hratestr = utils::strdup(&arg[iarg + 3][2]); - iarg += 4; - } else 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[index].ptarget = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - } else { - set[index].pstr = utils::strdup(&arg[iarg + 2][2]); - set[index].pvar_flag = 1; - } - set[index].pgain = utils::numeric(FLERR, arg[iarg + 3], false, lmp); - if (set[index].pgain <= 0.0) - error->all(FLERR, "Illegal fix deform/pressure pressure gain, must be positive"); - iarg += 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[index].ptarget = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - } else { - set[index].pstr = utils::strdup(&arg[iarg + 2][2]); - set[index].pvar_flag = 1; - } - set[index].pgain = utils::numeric(FLERR, arg[iarg + 3], false, lmp); - if (set[index].pgain <= 0.0) - error->all(FLERR, "Illegal fix deform/pressure pressure gain, must be positive"); - iarg += 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 (triclinic == 0) - error->all(FLERR, "fix deform/pressure tilt factors require triclinic box"); - 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], "final") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure final", error); - set[index].style = FINAL; - set[index].ftilt = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 3; - } else if (strcmp(arg[iarg + 1], "delta") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure delta", error); - set[index].style = DELTA; - set[index].dtilt = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 3; - } else if (strcmp(arg[iarg + 1], "vel") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure vel", error); - set[index].style = VEL; - set[index].vel = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 3; - } else if (strcmp(arg[iarg + 1], "erate") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure erate", error); - set[index].style = ERATE; - set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 3; - } else if (strcmp(arg[iarg + 1], "trate") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure trate", error); - set[index].style = TRATE; - set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 3; - } else if (strcmp(arg[iarg + 1], "wiggle") == 0) { - if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure wiggle", error); - set[index].style = WIGGLE; - set[index].amplitude = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - set[index].tperiod = utils::numeric(FLERR, arg[iarg + 3], false, lmp); - if (set[index].tperiod <= 0.0) - error->all(FLERR, "Illegal fix deform/pressure wiggle period, must be positive"); - iarg += 4; - } else if (strcmp(arg[iarg + 1], "variable") == 0) { - if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure variable", error); - set[index].style = VARIABLE; - if (strstr(arg[iarg + 2], "v_") != arg[iarg + 2]) - error->all(FLERR, "Illegal fix deform/pressure variable name {}", arg[iarg + 2]); - if (strstr(arg[iarg + 3], "v_") != arg[iarg + 3]) - error->all(FLERR, "Illegal fix deform/pressure variable name {}", arg[iarg + 3]); - delete[] set[index].hstr; - delete[] set[index].hratestr; - set[index].hstr = utils::strdup(&arg[iarg + 2][2]); - set[index].hratestr = utils::strdup(&arg[iarg + 3][2]); - iarg += 4; - } else 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[index].ptarget = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - } else { - set[index].pstr = utils::strdup(&arg[iarg + 2][2]); - set[index].pvar_flag = 1; - } - set[index].pgain = utils::numeric(FLERR, arg[iarg + 3], false, lmp); - if (set[index].pgain <= 0.0) - error->all(FLERR, "Illegal fix deform/pressure pressure gain, must be positive"); - iarg += 4; - } else error->all(FLERR, "Illegal fix deform/pressure command: {}", arg[iarg + 1]); - } else if (strcmp(arg[iarg], "iso") == 0) { - index = 6; - if (strcmp(arg[iarg + 1], "volume") == 0) { - set[index].style = VOLUME; - iarg += 2; - } else 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[index].ptarget = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - } else { - set[index].pstr = utils::strdup(&arg[iarg + 2][2]); - set[index].pvar_flag = 1; - } - set[index].pgain = utils::numeric(FLERR, arg[iarg + 3], false, lmp); - if (set[index].pgain <= 0.0) - error->all(FLERR, "Illegal fix deform/pressure pressure gain, must be positive"); - iarg += 4; - } - } else break; - } - - while (iarg < narg) { - if (strcmp(arg[iarg], "remap") == 0) { - if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure remap", error); - if (strcmp(arg[iarg + 1], "x") == 0) remapflag = Domain::X_REMAP; - else if (strcmp(arg[iarg + 1], "v") == 0) remapflag = Domain::V_REMAP; - else if (strcmp(arg[iarg + 1], "none") == 0) remapflag = Domain::NO_REMAP; - else error->all(FLERR, "Illegal fix deform/pressure remap command: {}", arg[iarg + 1]); - iarg += 2; - } else if (strcmp(arg[iarg], "units") == 0) { - if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure units", error); - if (strcmp(arg[iarg + 1], "box") == 0) scaleflag = 0; - else if (strcmp(arg[iarg + 1], "lattice") == 0) scaleflag = 1; - else error->all(FLERR, "Illegal fix deform/pressure units command: {}", arg[iarg + 1]); - iarg += 2; - } else if (strcmp(arg[iarg], "flip") == 0) { - if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure flip", error); - flipflag = utils::logical(FLERR, arg[iarg + 1], false, lmp); - iarg += 2; - } else if (strcmp(arg[iarg], "couple") == 0) { + 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 fix deform/pressure couple command: {}", arg[iarg + 1]); + else error->all(FLERR, "Illegal fix deform/pressure couple command: {}", arg[iarg + 1]); iarg += 2; } else if (strcmp(arg[iarg], "max/rate") == 0) { if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform/pressure max/rate", error); @@ -847,10 +860,6 @@ void FixDeformPressure::options(int narg, char **arg) iarg += 2; } else error->all(FLERR, "Illegal fix deform/pressure command: {}", arg[iarg]); } - - if (dimension == 2) - if (pcouple == XYZ || pcouple == XZ || pcouple == YZ) - error->all(FLERR, "Cannot couple Z dimension in fix deform/pressure in 2D"); } /* ---------------------------------------------------------------------- */ diff --git a/src/EXTRA-FIX/fix_deform_pressure.h b/src/EXTRA-FIX/fix_deform_pressure.h index 7e4ad6e35a9..41b93f6e987 100644 --- a/src/EXTRA-FIX/fix_deform_pressure.h +++ b/src/EXTRA-FIX/fix_deform_pressure.h @@ -31,6 +31,8 @@ class FixDeformPressure : public FixDeform { void init() override; void setup(int) override; void end_of_step() override; + void write_restart(FILE *) override; + void restart(char *buf) override; int modify_param(int, char **) override; protected: @@ -46,10 +48,22 @@ class FixDeformPressure : public FixDeform { class Compute *temperature, *pressure; int tflag, pflag; + struct SetExtra { + double ptarget, pgain; + double prior_pressure, prior_rate; + double cumulative_strain; + int saved; + char *pstr; + int pvar, pvar_flag; + int coupled_flag; + }; + SetExtra *set_extra; + Set set_box; + void options(int, char **); - void set_pressure(); - void set_volume(); - void set_iso(); + void apply_volume() override; + void apply_pressure(); + void apply_box(); void couple(); void adjust_linked_rates(double&, double&, double, double, double); }; diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index cf45a12f5db..ea68574bf22 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -34,6 +34,8 @@ #include #include +#include +#include using namespace LAMMPS_NS; using namespace FixConst; @@ -56,15 +58,174 @@ irregular(nullptr), set(nullptr) nevery = utils::inumeric(FLERR, arg[3], false, lmp); if (nevery <= 0) error->all(FLERR, "Illegal fix deform command"); + // arguments for child classes + + std::unordered_set child_parameters; + std::unordered_map child_styles; + int nskip; + if (utils::strmatch(style, "pressure$")) { + child_parameters.insert("box"); + child_styles.insert({{"pressure", 4}, {"pressure/mean", 4}, {"volume", 3}}); + } + // set defaults - set = new Set[7]; - memset(set, 0, 7 * sizeof(Set)); + set = new Set[6]; + memset(set, 0, 6 * sizeof(Set)); // parse arguments + int index; + int iarg = 4; + while (iarg < narg) { + 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 (strcmp(arg[iarg + 1], "final") == 0) { + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform final", error); + set[index].style = FINAL; + set[index].flo = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + set[index].fhi = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + iarg += 4; + } else if (strcmp(arg[iarg + 1], "delta") == 0) { + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform delta", error); + set[index].style = DELTA; + set[index].dlo = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + set[index].dhi = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + iarg += 4; + } else if (strcmp(arg[iarg + 1], "scale") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform scale", error); + set[index].style = SCALE; + set[index].scale = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "vel") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform vel", error); + set[index].style = VEL; + set[index].vel = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "erate") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform erate", error); + set[index].style = ERATE; + set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "trate") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform trate", error); + set[index].style = TRATE; + set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "volume") == 0) { + set[index].style = VOLUME; + iarg += 2; + } else if (strcmp(arg[iarg + 1], "wiggle") == 0) { + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform wiggle", error); + set[index].style = WIGGLE; + set[index].amplitude = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + set[index].tperiod = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + if (set[index].tperiod <= 0.0) + error->all(FLERR, "Illegal fix deform wiggle period, must be positive"); + iarg += 4; + } else if (strcmp(arg[iarg + 1], "variable") == 0) { + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform variable", error); + set[index].style = VARIABLE; + if (strstr(arg[iarg + 2], "v_") != arg[iarg + 2]) + error->all(FLERR, "Illegal fix deform variable name {}", arg[iarg + 2]); + if (strstr(arg[iarg + 3], "v_") != arg[iarg + 3]) + error->all(FLERR, "Illegal fix deform variable name {}", arg[iarg + 3]); + delete[] set[index].hstr; + delete[] set[index].hratestr; + set[index].hstr = utils::strdup(&arg[iarg + 2][2]); + set[index].hratestr = utils::strdup(&arg[iarg + 3][2]); + iarg += 4; + } else if (child_styles.find(arg[iarg + 1]) != child_styles.end()) { + nskip = child_styles[arg[iarg + 1]]; + if (iarg + nskip > narg) + utils::missing_cmd_args(FLERR, fmt::format("fix {} {}", style, arg[iarg + 1]), error); + iarg += nskip; + } error->all(FLERR, "Illegal fix deform 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 (strcmp(arg[iarg + 1], "final") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform final", error); + set[index].style = FINAL; + set[index].ftilt = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "delta") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform delta", error); + set[index].style = DELTA; + set[index].dtilt = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "vel") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform vel", error); + set[index].style = VEL; + set[index].vel = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "erate") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform erate", error); + set[index].style = ERATE; + set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "trate") == 0) { + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform trate", error); + set[index].style = TRATE; + set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 3; + } else if (strcmp(arg[iarg + 1], "wiggle") == 0) { + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform wiggle", error); + set[index].style = WIGGLE; + set[index].amplitude = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + set[index].tperiod = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + if (set[index].tperiod <= 0.0) + error->all(FLERR, "Illegal fix deform wiggle period, must be positive"); + iarg += 4; + } else if (strcmp(arg[iarg + 1], "variable") == 0) { + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform variable", error); + set[index].style = VARIABLE; + if (strstr(arg[iarg + 2], "v_") != arg[iarg + 2]) + error->all(FLERR, "Illegal fix deform variable name {}", arg[iarg + 2]); + if (strstr(arg[iarg + 3], "v_") != arg[iarg + 3]) + error->all(FLERR, "Illegal fix deform variable name {}", arg[iarg + 3]); + delete[] set[index].hstr; + delete[] set[index].hratestr; + set[index].hstr = utils::strdup(&arg[iarg + 2][2]); + set[index].hratestr = utils::strdup(&arg[iarg + 3][2]); + iarg += 4; + } else if (child_styles.find(arg[iarg + 1]) != child_styles.end()) { + nskip = child_styles[arg[iarg + 1]]; + if (iarg + nskip > narg) + utils::missing_cmd_args(FLERR, fmt::format("fix {} {}", style, arg[iarg + 1]), error); + iarg += nskip; + } error->all(FLERR, "Illegal fix deform command argument: {}", arg[iarg + 1]); + } else if (child_parameters.find(arg[iarg]) != child_parameters.end()) { + if (child_styles.find(arg[iarg + 1]) != child_styles.end()) { + nskip = child_styles[arg[iarg + 1]]; + if (iarg + nskip > narg) + utils::missing_cmd_args(FLERR, fmt::format("fix {} {}", style, arg[iarg + 1]), error); + iarg += nskip; + } error->all(FLERR, "Illegal fix {} command argument: {}", style, arg[iarg + 1]); + } else break; + } + + // reparse all arguments for optional keywords + + options(narg - 4, &arg[4]); + + // check triclinic + triclinic = domain->triclinic; - options(narg, arg); + if (triclinic == 0 && (set[3].style || set[4].style || set[5].style)) + error->all(FLERR, "Fix deform tilt factors require triclinic box"); // no x remap effectively moves atoms within box, so set restart_pbc @@ -76,12 +237,6 @@ irregular(nullptr), set(nullptr) if (set[i].style == NONE) dimflag[i] = 0; else dimflag[i] = 1; - if (set[6].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; @@ -93,7 +248,7 @@ irregular(nullptr), set(nullptr) // b/c shrink wrap will change box-length for (int i = 0; i < 3; i++) - if ((set[i].style || set[6].style) && (domain->boundary[i][0] >= 2 || domain->boundary[i][1] >= 2)) + if (set[i].style && (domain->boundary[i][0] >= 2 || domain->boundary[i][1] >= 2)) error->all(FLERR, "Cannot use fix deform on a shrink-wrapped boundary"); // no tilt deformation on shrink-wrapped 2nd dim @@ -113,7 +268,7 @@ irregular(nullptr), set(nullptr) if (set[i].style == FINAL || set[i].style == DELTA || set[i].style == VEL || set[i].style == WIGGLE) flag = 1; - double xscale,yscale,zscale; + double xscale, yscale, zscale; if (flag && scaleflag) { xscale = domain->lattice->xlattice; yscale = domain->lattice->ylattice; @@ -187,10 +342,8 @@ irregular(nullptr), set(nullptr) // set varflag varflag = 0; - for (int i = 0; i < 7; i++) { + for (int i = 0; i < 6; i++) if (set[i].style == VARIABLE) varflag = 1; - if (set[i].pvar_flag) varflag = 1; - } // set initial values at time fix deform is issued @@ -202,7 +355,6 @@ irregular(nullptr), set(nullptr) set[3].tilt_initial = domain->yz; set[4].tilt_initial = domain->xz; set[5].tilt_initial = domain->xy; - set[6].vol_initial = domain->xprd * domain->yprd * domain->zprd; // reneighboring only forced if flips can occur due to shape changes @@ -231,10 +383,9 @@ irregular(nullptr), set(nullptr) FixDeform::~FixDeform() { if (set) { - for (int i = 0; i < 7; i++) { + for (int i = 0; i < 6; i++) { delete[] set[i].hstr; delete[] set[i].hratestr; - delete[] set[i].pstr; } } delete[] set; @@ -282,7 +433,7 @@ void FixDeform::init() // check variables for VARIABLE style - for (int i = 0; i < 7; i++) { + for (int i = 0; i < 6; i++) { if (set[i].style != VARIABLE) continue; set[i].hvar = input->variable->find(set[i].hstr); if (set[i].hvar < 0) @@ -403,8 +554,6 @@ void FixDeform::init() } } - set[6].vol_start = domain->xprd * domain->yprd * domain->zprd; - // if using tilt TRATE, then initial tilt must be non-zero for (int i = 3; i < 6; i++) @@ -520,16 +669,16 @@ void FixDeform::end_of_step() // set new box size for strain-based dims - set_strain(); + apply_strain(); // set new box size for VOLUME dims that are linked to other dims // NOTE: still need to set h_rate for these dims - set_volume(); + apply_volume(); if (varflag) modify->addstep_compute(update->ntimestep + nevery); - apply_deformation(); + update_domain(); // redo KSpace coeffs since box has changed @@ -537,10 +686,10 @@ void FixDeform::end_of_step() } /* ---------------------------------------------------------------------- - set box size for strain-based dimensions + apply strain controls ------------------------------------------------------------------------- */ -void FixDeform::set_strain() +void FixDeform::apply_strain() { // for NONE, target is current box size // for TRATE, set target directly based on current time, also set h_rate @@ -620,10 +769,10 @@ void FixDeform::set_strain() } /* ---------------------------------------------------------------------- - set box size for VOLUME dimensions + apply volume controls ------------------------------------------------------------------------- */ -void FixDeform::set_volume() +void FixDeform::apply_volume() { double e1, e2; @@ -657,10 +806,10 @@ void FixDeform::set_volume() } /* ---------------------------------------------------------------------- - Apply calculated deformation + Update box domain ------------------------------------------------------------------------- */ -void FixDeform::apply_deformation() +void FixDeform::update_domain() { // tilt_target can be large positive or large negative value // add/subtract box lengths until tilt_target is closest to current value @@ -766,22 +915,22 @@ void FixDeform::apply_deformation() // reset global and local box to new size/shape // only if deform fix is controlling the dimension - if (set[0].style || set[6].style) { + if (dimflag[0]) { domain->boxlo[0] = set[0].lo_target; domain->boxhi[0] = set[0].hi_target; } - if (set[1].style || set[6].style) { + if (dimflag[1]) { domain->boxlo[1] = set[1].lo_target; domain->boxhi[1] = set[1].hi_target; } - if (set[2].style || set[6].style) { + if (dimflag[2]) { domain->boxlo[2] = set[2].lo_target; domain->boxhi[2] = set[2].hi_target; } if (triclinic) { - if (set[3].style) domain->yz = set[3].tilt_target; - if (set[4].style) domain->xz = set[4].tilt_target; - if (set[5].style) domain->xy = set[5].tilt_target; + if (dimflag[3]) domain->yz = set[3].tilt_target; + if (dimflag[4]) domain->xz = set[4].tilt_target; + if (dimflag[5]) domain->xy = set[5].tilt_target; } domain->set_global_box(); @@ -810,11 +959,11 @@ void FixDeform::apply_deformation() void FixDeform::write_restart(FILE *fp) { if (comm->me == 0) { - int size = 9 * sizeof(double) + 7 * sizeof(Set); + int size = 9 * sizeof(double) + 6 * sizeof(Set); fwrite(&size, sizeof(int), 1, fp); fwrite(h_rate, sizeof(double), 6, fp); fwrite(h_ratelo, sizeof(double), 3, fp); - fwrite(set, sizeof(Set), 7, fp); + fwrite(set, sizeof(Set), 6, fp); } } @@ -833,16 +982,12 @@ void FixDeform::restart(char *buf) int samestyle = 1; Set *set_restart = (Set *) &buf[n * sizeof(double)]; - for (int i = 0; i < 7; ++i) { + 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; - set[i].saved = set_restart[i].saved; - set[i].prior_rate = set_restart[i].prior_rate; - set[i].prior_pressure = set_restart[i].prior_pressure; - set[i].cumulative_strain = set_restart[i].cumulative_strain; // check if style settings are consistent (should do the whole set?) if (set[i].style != set_restart[i].style) samestyle = 0; @@ -863,135 +1008,14 @@ void FixDeform::options(int narg, char **arg) scaleflag = 1; flipflag = 1; - int index; - int iarg = 4; - while (iarg < narg) { - 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; + // arguments for child classes - if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform", error); - if (strcmp(arg[iarg + 1], "final") == 0) { - if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform final", error); - set[index].style = FINAL; - set[index].flo = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - set[index].fhi = utils::numeric(FLERR, arg[iarg + 3], false, lmp); - iarg += 4; - } else if (strcmp(arg[iarg + 1], "delta") == 0) { - if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform delta", error); - set[index].style = DELTA; - set[index].dlo = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - set[index].dhi = utils::numeric(FLERR, arg[iarg + 3], false, lmp); - iarg += 4; - } else if (strcmp(arg[iarg + 1], "scale") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform scale", error); - set[index].style = SCALE; - set[index].scale = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 3; - } else if (strcmp(arg[iarg + 1], "vel") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform vel", error); - set[index].style = VEL; - set[index].vel = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 3; - } else if (strcmp(arg[iarg + 1], "erate") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform erate", error); - set[index].style = ERATE; - set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 3; - } else if (strcmp(arg[iarg + 1], "trate") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform trate", error); - set[index].style = TRATE; - set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 3; - } else if (strcmp(arg[iarg + 1], "volume") == 0) { - set[index].style = VOLUME; - iarg += 2; - } else if (strcmp(arg[iarg + 1], "wiggle") == 0) { - if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform wiggle", error); - set[index].style = WIGGLE; - set[index].amplitude = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - set[index].tperiod = utils::numeric(FLERR, arg[iarg + 3], false, lmp); - if (set[index].tperiod <= 0.0) - error->all(FLERR, "Illegal fix deform wiggle period, must be positive"); - iarg += 4; - } else if (strcmp(arg[iarg + 1], "variable") == 0) { - if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform variable", error); - set[index].style = VARIABLE; - if (strstr(arg[iarg + 2], "v_") != arg[iarg + 2]) - error->all(FLERR, "Illegal fix deform variable name {}", arg[iarg + 2]); - if (strstr(arg[iarg + 3], "v_") != arg[iarg + 3]) - error->all(FLERR, "Illegal fix deform variable name {}", arg[iarg + 3]); - delete[] set[index].hstr; - delete[] set[index].hratestr; - set[index].hstr = utils::strdup(&arg[iarg + 2][2]); - set[index].hratestr = utils::strdup(&arg[iarg + 3][2]); - iarg += 4; - } else error->all(FLERR, "Illegal fix deform command argument: {}", arg[iarg + 1]); - - } else if (strcmp(arg[iarg], "xy") == 0 || - strcmp(arg[iarg], "xz") == 0 || - strcmp(arg[iarg], "yz") == 0) { - - if (triclinic == 0) - error->all(FLERR, "Fix deform tilt factors require triclinic box"); - 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", error); - if (strcmp(arg[iarg + 1], "final") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform final", error); - set[index].style = FINAL; - set[index].ftilt = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 3; - } else if (strcmp(arg[iarg + 1], "delta") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform delta", error); - set[index].style = DELTA; - set[index].dtilt = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 3; - } else if (strcmp(arg[iarg + 1], "vel") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform vel", error); - set[index].style = VEL; - set[index].vel = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 3; - } else if (strcmp(arg[iarg + 1], "erate") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform erate", error); - set[index].style = ERATE; - set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 3; - } else if (strcmp(arg[iarg + 1], "trate") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform trate", error); - set[index].style = TRATE; - set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 3; - } else if (strcmp(arg[iarg + 1], "wiggle") == 0) { - if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform wiggle", error); - set[index].style = WIGGLE; - set[index].amplitude = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - set[index].tperiod = utils::numeric(FLERR, arg[iarg + 3], false, lmp); - if (set[index].tperiod <= 0.0) - error->all(FLERR, "Illegal fix deform wiggle period, must be positive"); - iarg += 4; - } else if (strcmp(arg[iarg + 1], "variable") == 0) { - if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform variable", error); - set[index].style = VARIABLE; - if (strstr(arg[iarg + 2], "v_") != arg[iarg + 2]) - error->all(FLERR, "Illegal fix deform variable name {}", arg[iarg + 2]); - if (strstr(arg[iarg + 3], "v_") != arg[iarg + 3]) - error->all(FLERR, "Illegal fix deform variable name {}", arg[iarg + 3]); - delete[] set[index].hstr; - delete[] set[index].hratestr; - set[index].hstr = utils::strdup(&arg[iarg + 2][2]); - set[index].hratestr = utils::strdup(&arg[iarg + 3][2]); - iarg += 4; - } else error->all(FLERR, "Illegal fix deform command: {}", arg[iarg + 1]); - } else break; - } + std::unordered_map child_options; + int nskip; + if (utils::strmatch(style, "pressure$")) + child_options.insert({{"couple", 2}, {"max/rate", 2}, {"normalize/pressure", 2}, {"vol/balance/p", 2}}); + int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg], "remap") == 0) { if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform remap", error); @@ -1010,6 +1034,11 @@ void FixDeform::options(int narg, char **arg) if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform flip", error); flipflag = utils::logical(FLERR, arg[iarg + 1], false, lmp); iarg += 2; + } else if (child_options.find(arg[iarg]) != child_options.end()) { + nskip = child_options[arg[iarg]]; + if (iarg + nskip > narg) + utils::missing_cmd_args(FLERR, fmt::format("fix {} {}", style, arg[iarg]), error); + iarg += nskip; } else error->all(FLERR, "Illegal fix deform command: {}", arg[iarg]); } } diff --git a/src/fix_deform.h b/src/fix_deform.h index 16a563cf4f7..69f62fe5580 100644 --- a/src/fix_deform.h +++ b/src/fix_deform.h @@ -35,8 +35,8 @@ class FixDeform : public Fix { void init() override; void pre_exchange() override; void end_of_step() override; - void write_restart(FILE *) override; - void restart(char *buf) override; + void virtual write_restart(FILE *) override; + void virtual restart(char *buf) override; double memory_usage() override; protected: @@ -59,22 +59,16 @@ class FixDeform : public Fix { double tilt_initial, tilt_start, tilt_stop, tilt_target, tilt_flip; double tilt_min, tilt_max; double vol_initial, vol_start; - double ptarget, pgain; - double prior_pressure, prior_rate; - double cumulative_strain; - int saved; int fixed, dynamic1, dynamic2; - char *hstr, *hratestr, *pstr; + char *hstr, *hratestr; int hvar, hratevar; - int pvar, pvar_flag; - int coupled_flag; }; Set *set; void options(int, char **); - void set_strain(); - void set_volume(); - void apply_deformation(); + void virtual apply_volume(); + void apply_strain(); + void update_domain(); }; } // namespace LAMMPS_NS From a835c5f3d98be243bd0e5b9f95b382da5f1c0229 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 30 Jan 2024 15:50:40 -0700 Subject: [PATCH 17/29] Restoring some error message locations, minor edits --- src/EXTRA-FIX/fix_deform_pressure.cpp | 6 ------ src/fix_deform.cpp | 19 ++++++++++--------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/EXTRA-FIX/fix_deform_pressure.cpp b/src/EXTRA-FIX/fix_deform_pressure.cpp index 7f3a627b66b..7fb60e13fbc 100644 --- a/src/EXTRA-FIX/fix_deform_pressure.cpp +++ b/src/EXTRA-FIX/fix_deform_pressure.cpp @@ -138,12 +138,6 @@ id_temp(nullptr), id_press(nullptr) options(narg - iarg, &arg[iarg]); - // repeat: check triclinic - - dimension = domain->dimension; - if (triclinic == 0 && (set[3].style || set[4].style || set[5].style)) - error->all(FLERR, "Fix deform tilt factors require triclinic box"); - // repeat: setup dimflags used by other classes to check for volume-change conflicts for (int i = 0; i < 6; i++) diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index ea68574bf22..94b28a5cd3e 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -75,6 +75,8 @@ irregular(nullptr), set(nullptr) // parse arguments + triclinic = domain->triclinic; + int index; int iarg = 4; while (iarg < narg) { @@ -86,6 +88,7 @@ irregular(nullptr), set(nullptr) 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", error); if (strcmp(arg[iarg + 1], "final") == 0) { if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform final", error); set[index].style = FINAL; @@ -152,10 +155,14 @@ irregular(nullptr), set(nullptr) strcmp(arg[iarg], "xz") == 0 || strcmp(arg[iarg], "yz") == 0) { + + if (triclinic == 0) + error->all(FLERR,"Fix deform tilt factors require triclinic box"); 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", error); if (strcmp(arg[iarg + 1], "final") == 0) { if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform final", error); set[index].style = FINAL; @@ -217,15 +224,9 @@ irregular(nullptr), set(nullptr) } else break; } - // reparse all arguments for optional keywords + // read options from end of input line - options(narg - 4, &arg[4]); - - // check triclinic - - triclinic = domain->triclinic; - if (triclinic == 0 && (set[3].style || set[4].style || set[5].style)) - error->all(FLERR, "Fix deform tilt factors require triclinic box"); + options(narg - iarg, &arg[iarg]); // no x remap effectively moves atoms within box, so set restart_pbc @@ -787,7 +788,7 @@ void FixDeform::apply_volume() 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)); + (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)); From 103dc9ef668153a9494593c5952278358a7c1669 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 30 Jan 2024 19:21:48 -0500 Subject: [PATCH 18/29] fix missing "else" bug --- src/fix_deform.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index 94b28a5cd3e..8e9b4899795 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -149,7 +149,7 @@ irregular(nullptr), set(nullptr) if (iarg + nskip > narg) utils::missing_cmd_args(FLERR, fmt::format("fix {} {}", style, arg[iarg + 1]), error); iarg += nskip; - } error->all(FLERR, "Illegal fix deform command argument: {}", arg[iarg + 1]); + } else error->all(FLERR, "Illegal fix deform command argument: {}", arg[iarg + 1]); } else if (strcmp(arg[iarg], "xy") == 0 || strcmp(arg[iarg], "xz") == 0 || @@ -213,7 +213,7 @@ irregular(nullptr), set(nullptr) if (iarg + nskip > narg) utils::missing_cmd_args(FLERR, fmt::format("fix {} {}", style, arg[iarg + 1]), error); iarg += nskip; - } error->all(FLERR, "Illegal fix deform command argument: {}", arg[iarg + 1]); + } else error->all(FLERR, "Illegal fix deform command argument: {}", arg[iarg + 1]); } else if (child_parameters.find(arg[iarg]) != child_parameters.end()) { if (child_styles.find(arg[iarg + 1]) != child_styles.end()) { nskip = child_styles[arg[iarg + 1]]; From 9d46408fa41c0122b77e9140d77e23ca05812161 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 30 Jan 2024 19:23:40 -0500 Subject: [PATCH 19/29] delete unused variables --- src/fix_deform.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index 8e9b4899795..cf4a1242c03 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -741,8 +741,6 @@ void FixDeform::apply_strain() // for other styles, target is linear value between start and stop values if (triclinic) { - double *h = domain->h; - for (int i = 3; i < 6; i++) { if (set[i].style == NONE) { if (i == 5) set[i].tilt_target = domain->xy; @@ -775,8 +773,6 @@ void FixDeform::apply_strain() void FixDeform::apply_volume() { - double e1, e2; - for (int i = 0; i < 3; i++) { if (set[i].style != VOLUME) continue; From 840577114ee1255ce091d5b50e8cf10af66fce72 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 30 Jan 2024 19:38:58 -0500 Subject: [PATCH 20/29] force enumerators to be consistent by moving them to base class declaration --- src/EXTRA-FIX/fix_deform_pressure.cpp | 4 +--- src/fix_deform.cpp | 3 --- src/fix_deform.h | 3 +++ 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/EXTRA-FIX/fix_deform_pressure.cpp b/src/EXTRA-FIX/fix_deform_pressure.cpp index 7fb60e13fbc..a1eab084700 100644 --- a/src/EXTRA-FIX/fix_deform_pressure.cpp +++ b/src/EXTRA-FIX/fix_deform_pressure.cpp @@ -41,9 +41,7 @@ using namespace LAMMPS_NS; using namespace FixConst; using namespace MathConst; -enum{NONE=0,FINAL,DELTA,SCALE,VEL,ERATE,TRATE,VOLUME,WIGGLE,VARIABLE,PRESSURE,PMEAN}; -enum{ONE_FROM_ONE,ONE_FROM_TWO,TWO_FROM_ONE}; -enum{NOCOUPLE=0,XYZ,XY,YZ,XZ}; +enum{ NOCOUPLE=0, XYZ, XY, YZ, XZ }; /* ---------------------------------------------------------------------- */ diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index cf4a1242c03..7f9ec14c5dd 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -41,9 +41,6 @@ using namespace LAMMPS_NS; using namespace FixConst; using namespace MathConst; -enum{NONE=0,FINAL,DELTA,SCALE,VEL,ERATE,TRATE,VOLUME,WIGGLE,VARIABLE}; -enum{ONE_FROM_ONE,ONE_FROM_TWO,TWO_FROM_ONE}; - /* ---------------------------------------------------------------------- */ FixDeform::FixDeform(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), diff --git a/src/fix_deform.h b/src/fix_deform.h index 69f62fe5580..fa92b851e6b 100644 --- a/src/fix_deform.h +++ b/src/fix_deform.h @@ -29,6 +29,9 @@ class FixDeform : public Fix { int remapflag; // whether x,v are remapped across PBC int dimflag[6]; // which dims are deformed + enum { NONE, FINAL, DELTA, SCALE, VEL, ERATE, TRATE, VOLUME, WIGGLE, VARIABLE, PRESSURE, PMEAN }; + enum { ONE_FROM_ONE, ONE_FROM_TWO, TWO_FROM_ONE }; + FixDeform(class LAMMPS *, int, char **); ~FixDeform() override; int setmask() override; From bff789aac9bcaa4e607d8f334c393814c2c8f62e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 30 Jan 2024 20:03:26 -0500 Subject: [PATCH 21/29] silence compiler warnings and update format --- src/EXTRA-FIX/fix_deform_pressure.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/EXTRA-FIX/fix_deform_pressure.cpp b/src/EXTRA-FIX/fix_deform_pressure.cpp index a1eab084700..9fb85843a22 100644 --- a/src/EXTRA-FIX/fix_deform_pressure.cpp +++ b/src/EXTRA-FIX/fix_deform_pressure.cpp @@ -41,12 +41,12 @@ using namespace LAMMPS_NS; using namespace FixConst; using namespace MathConst; -enum{ NOCOUPLE=0, XYZ, XY, YZ, XZ }; +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) +FixDeformPressure::FixDeformPressure(LAMMPS *lmp, int narg, char **arg) : + FixDeform(lmp, narg, arg), id_temp(nullptr), id_press(nullptr) { // set defaults @@ -198,8 +198,6 @@ id_temp(nullptr), id_press(nullptr) int coupled_indices[3] = {0}; int j = -1; - double couple_gain, coupled_pressure; - char *couple_str; if (pcouple == XYZ || pcouple == XY || pcouple == XZ) coupled_indices[0] = 1; @@ -626,14 +624,14 @@ void FixDeformPressure::apply_volume() 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 (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 { From e649c0e0704b2f899238332639e49582cbbd82f5 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 30 Jan 2024 20:04:07 -0500 Subject: [PATCH 22/29] consistent error messages for parent and child class --- src/EXTRA-FIX/fix_deform_pressure.cpp | 10 +-- src/fix_deform.cpp | 125 +++++++++++++------------- 2 files changed, 70 insertions(+), 65 deletions(-) diff --git a/src/EXTRA-FIX/fix_deform_pressure.cpp b/src/EXTRA-FIX/fix_deform_pressure.cpp index 9fb85843a22..91a0591cd29 100644 --- a/src/EXTRA-FIX/fix_deform_pressure.cpp +++ b/src/EXTRA-FIX/fix_deform_pressure.cpp @@ -160,17 +160,17 @@ FixDeformPressure::FixDeformPressure(LAMMPS *lmp, int narg, char **arg) : 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 on a shrink-wrapped boundary"); + 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 tilt on a shrink-wrapped 2nd dim"); + 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 tilt on a shrink-wrapped 2nd dim"); + 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 tilt on a shrink-wrapped 2nd dim"); + error->all(FLERR, "Cannot use fix deform/pressure tilt on a shrink-wrapped 2nd dim"); // repeat: set varflag @@ -184,7 +184,7 @@ FixDeformPressure::FixDeformPressure(LAMMPS *lmp, int narg, char **arg) : irregular = new Irregular(lmp); } - // set initial values at time fix deform is issued + // set initial values at time fix deform/pressure is issued set_box.vol_initial = domain->xprd * domain->yprd * domain->zprd; diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index 7f9ec14c5dd..9c6bfb9d8b4 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -46,21 +46,22 @@ using namespace MathConst; FixDeform::FixDeform(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), irregular(nullptr), set(nullptr) { - if (narg < 4) error->all(FLERR, "Illegal fix deform command"); + const std::string thiscmd = fmt::format("fix {}", style); + if (narg < 4) utils::missing_cmd_args(FLERR, thiscmd, error); no_change_box = 1; restart_global = 1; pre_exchange_migrate = 1; nevery = utils::inumeric(FLERR, arg[3], false, lmp); - if (nevery <= 0) error->all(FLERR, "Illegal fix deform command"); + if (nevery <= 0) error->all(FLERR, "Fix {} Nevery must be > 0", style); // arguments for child classes std::unordered_set child_parameters; std::unordered_map child_styles; int nskip; - if (utils::strmatch(style, "pressure$")) { + if (utils::strmatch(style, "^deform/pressure")) { child_parameters.insert("box"); child_styles.insert({{"pressure", 4}, {"pressure/mean", 4}, {"volume", 3}}); } @@ -76,45 +77,46 @@ irregular(nullptr), set(nullptr) int index; int iarg = 4; + while (iarg < narg) { - if (strcmp(arg[iarg], "x") == 0 || - strcmp(arg[iarg], "y") == 0 || - strcmp(arg[iarg], "z") == 0) { + 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", error); + if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, thiscmd, error); if (strcmp(arg[iarg + 1], "final") == 0) { - if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform final", error); + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, thiscmd + " final", error); set[index].style = FINAL; set[index].flo = utils::numeric(FLERR, arg[iarg + 2], false, lmp); set[index].fhi = utils::numeric(FLERR, arg[iarg + 3], false, lmp); iarg += 4; } else if (strcmp(arg[iarg + 1], "delta") == 0) { - if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform delta", error); + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, thiscmd + " delta", error); set[index].style = DELTA; set[index].dlo = utils::numeric(FLERR, arg[iarg + 2], false, lmp); set[index].dhi = utils::numeric(FLERR, arg[iarg + 3], false, lmp); iarg += 4; } else if (strcmp(arg[iarg + 1], "scale") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform scale", error); + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, thiscmd + " scale", error); set[index].style = SCALE; set[index].scale = utils::numeric(FLERR, arg[iarg + 2], false, lmp); iarg += 3; } else if (strcmp(arg[iarg + 1], "vel") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform vel", error); + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, thiscmd + " vel", error); set[index].style = VEL; set[index].vel = utils::numeric(FLERR, arg[iarg + 2], false, lmp); iarg += 3; } else if (strcmp(arg[iarg + 1], "erate") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform erate", error); + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, thiscmd + " erate", error); set[index].style = ERATE; set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); iarg += 3; } else if (strcmp(arg[iarg + 1], "trate") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform trate", error); + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, thiscmd + " trate", error); set[index].style = TRATE; set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); iarg += 3; @@ -122,20 +124,20 @@ irregular(nullptr), set(nullptr) set[index].style = VOLUME; iarg += 2; } else if (strcmp(arg[iarg + 1], "wiggle") == 0) { - if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform wiggle", error); + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, thiscmd + " wiggle", error); set[index].style = WIGGLE; set[index].amplitude = utils::numeric(FLERR, arg[iarg + 2], false, lmp); set[index].tperiod = utils::numeric(FLERR, arg[iarg + 3], false, lmp); if (set[index].tperiod <= 0.0) - error->all(FLERR, "Illegal fix deform wiggle period, must be positive"); + error->all(FLERR, "Illegal fix {} wiggle period, must be positive", style); iarg += 4; } else if (strcmp(arg[iarg + 1], "variable") == 0) { - if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform variable", error); + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, thiscmd + " variable", error); set[index].style = VARIABLE; if (strstr(arg[iarg + 2], "v_") != arg[iarg + 2]) - error->all(FLERR, "Illegal fix deform variable name {}", arg[iarg + 2]); + error->all(FLERR, "Illegal fix {} variable name {}", style, arg[iarg + 2]); if (strstr(arg[iarg + 3], "v_") != arg[iarg + 3]) - error->all(FLERR, "Illegal fix deform variable name {}", arg[iarg + 3]); + error->all(FLERR, "Illegal fix {} variable name {}", style, arg[iarg + 3]); delete[] set[index].hstr; delete[] set[index].hratestr; set[index].hstr = utils::strdup(&arg[iarg + 2][2]); @@ -146,60 +148,58 @@ irregular(nullptr), set(nullptr) if (iarg + nskip > narg) utils::missing_cmd_args(FLERR, fmt::format("fix {} {}", style, arg[iarg + 1]), error); iarg += nskip; - } else error->all(FLERR, "Illegal fix deform command argument: {}", arg[iarg + 1]); - - } else if (strcmp(arg[iarg], "xy") == 0 || - strcmp(arg[iarg], "xz") == 0 || - strcmp(arg[iarg], "yz") == 0) { + } else error->all(FLERR, "Illegal fix {} command argument: {}", style, arg[iarg + 1]); + } else if ((strcmp(arg[iarg], "xy") == 0) + || (strcmp(arg[iarg], "xz") == 0) + || (strcmp(arg[iarg], "yz") == 0)) { - if (triclinic == 0) - error->all(FLERR,"Fix deform tilt factors require triclinic box"); + if (triclinic == 0) error->all(FLERR,"Fix {} tilt factors require triclinic box", style); 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", error); + if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, thiscmd, error); if (strcmp(arg[iarg + 1], "final") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform final", error); + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, thiscmd + " final", error); set[index].style = FINAL; set[index].ftilt = utils::numeric(FLERR, arg[iarg + 2], false, lmp); iarg += 3; } else if (strcmp(arg[iarg + 1], "delta") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform delta", error); + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, thiscmd + " delta", error); set[index].style = DELTA; set[index].dtilt = utils::numeric(FLERR, arg[iarg + 2], false, lmp); iarg += 3; } else if (strcmp(arg[iarg + 1], "vel") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform vel", error); + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, thiscmd + " vel", error); set[index].style = VEL; set[index].vel = utils::numeric(FLERR, arg[iarg + 2], false, lmp); iarg += 3; } else if (strcmp(arg[iarg + 1], "erate") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform erate", error); + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, thiscmd + " erate", error); set[index].style = ERATE; set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); iarg += 3; } else if (strcmp(arg[iarg + 1], "trate") == 0) { - if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, "fix deform trate", error); + if (iarg + 3 > narg) utils::missing_cmd_args(FLERR, thiscmd + " trate", error); set[index].style = TRATE; set[index].rate = utils::numeric(FLERR, arg[iarg + 2], false, lmp); iarg += 3; } else if (strcmp(arg[iarg + 1], "wiggle") == 0) { - if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform wiggle", error); + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, thiscmd + " wiggle", error); set[index].style = WIGGLE; set[index].amplitude = utils::numeric(FLERR, arg[iarg + 2], false, lmp); set[index].tperiod = utils::numeric(FLERR, arg[iarg + 3], false, lmp); if (set[index].tperiod <= 0.0) - error->all(FLERR, "Illegal fix deform wiggle period, must be positive"); + error->all(FLERR, "Illegal fix {} wiggle period, must be positive", style); iarg += 4; } else if (strcmp(arg[iarg + 1], "variable") == 0) { - if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "fix deform variable", error); + if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, thiscmd + " variable", error); set[index].style = VARIABLE; if (strstr(arg[iarg + 2], "v_") != arg[iarg + 2]) - error->all(FLERR, "Illegal fix deform variable name {}", arg[iarg + 2]); + error->all(FLERR, "Illegal fix {} variable name {}", style, arg[iarg + 2]); if (strstr(arg[iarg + 3], "v_") != arg[iarg + 3]) - error->all(FLERR, "Illegal fix deform variable name {}", arg[iarg + 3]); + error->all(FLERR, "Illegal fix {} variable name {}", style, arg[iarg + 3]); delete[] set[index].hstr; delete[] set[index].hratestr; set[index].hstr = utils::strdup(&arg[iarg + 2][2]); @@ -210,7 +210,7 @@ irregular(nullptr), set(nullptr) if (iarg + nskip > narg) utils::missing_cmd_args(FLERR, fmt::format("fix {} {}", style, arg[iarg + 1]), error); iarg += nskip; - } else error->all(FLERR, "Illegal fix deform command argument: {}", arg[iarg + 1]); + } else error->all(FLERR, "Illegal fix {} command argument: {}", style, arg[iarg + 1]); } else if (child_parameters.find(arg[iarg]) != child_parameters.end()) { if (child_styles.find(arg[iarg + 1]) != child_styles.end()) { nskip = child_styles[arg[iarg + 1]]; @@ -247,17 +247,17 @@ irregular(nullptr), set(nullptr) for (int i = 0; i < 3; i++) if (set[i].style && (domain->boundary[i][0] >= 2 || domain->boundary[i][1] >= 2)) - error->all(FLERR, "Cannot use fix deform on a shrink-wrapped boundary"); + error->all(FLERR, "Cannot use fix {} on a shrink-wrapped boundary", style); // 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 tilt on a shrink-wrapped 2nd dim"); + error->all(FLERR, "Cannot use fix {} tilt on a shrink-wrapped 2nd dim", style); if (set[4].style && (domain->boundary[2][0] >= 2 || domain->boundary[2][1] >= 2)) - error->all(FLERR, "Cannot use fix deform tilt on a shrink-wrapped 2nd dim"); + error->all(FLERR, "Cannot use fix {} tilt on a shrink-wrapped 2nd dim", style); if (set[5].style && (domain->boundary[1][0] >= 2 || domain->boundary[1][1] >= 2)) - error->all(FLERR, "Cannot use fix deform tilt on a shrink-wrapped 2nd dim"); + error->all(FLERR, "Cannot use fix {} tilt on a shrink-wrapped 2nd dim", style); // apply scaling to FINAL,DELTA,VEL,WIGGLE since they have dist/vel units @@ -312,7 +312,7 @@ irregular(nullptr), set(nullptr) // 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 deform volume setting is invalid"); + error->all(FLERR, "Fix {} volume setting is invalid", style); if (set[other1].style == NONE) { set[i].substyle = ONE_FROM_ONE; @@ -435,14 +435,14 @@ void FixDeform::init() if (set[i].style != VARIABLE) continue; set[i].hvar = input->variable->find(set[i].hstr); if (set[i].hvar < 0) - error->all(FLERR, "Variable name {} for fix deform does not exist", set[i].hstr); + error->all(FLERR, "Variable name {} for fix {} does not exist", set[i].hstr, style); if (!input->variable->equalstyle(set[i].hvar)) - error->all(FLERR, "Variable {} for fix deform is invalid style", set[i].hstr); + error->all(FLERR, "Variable {} for fix {} is invalid style", set[i].hstr, style); set[i].hratevar = input->variable->find(set[i].hratestr); if (set[i].hratevar < 0) - error->all(FLERR, "Variable name {} for fix deform does not exist", set[i].hratestr); + error->all(FLERR, "Variable name {} for fix {} does not exist", set[i].hratestr, style); if (!input->variable->equalstyle(set[i].hratevar)) - error->all(FLERR, "Variable {} for fix deform is invalid style", set[i].hratestr); + error->all(FLERR, "Variable {} for fix {} is invalid style", set[i].hratestr, style); } // set start/stop values for box size and shape @@ -480,7 +480,7 @@ void FixDeform::init() set[i].lo_stop = set[i].lo_start - shift; set[i].hi_stop = set[i].hi_start + shift; if (set[i].hi_stop <= set[i].lo_stop) - error->all(FLERR, "Final box dimension due to fix deform is < 0.0"); + error->all(FLERR, "Final box dimension due to fix {} is < 0.0", style); } else if (set[i].style == TRATE) { double shift = 0.5 * ((set[i].hi_start - set[i].lo_start) * exp(set[i].rate * delt)); set[i].lo_stop = 0.5 * (set[i].lo_start + set[i].hi_start) - shift; @@ -556,7 +556,7 @@ void FixDeform::init() for (int i = 3; i < 6; i++) if (set[i].style == TRATE && set[i].tilt_start == 0.0) - error->all(FLERR, "Cannot use fix deform trate on a box with zero tilt"); + error->all(FLERR, "Cannot use fix {} trate on a box with zero tilt", style); // if yz changes and will cause box flip, then xy cannot be changing // yz = [3], xy = [5] @@ -571,7 +571,7 @@ void FixDeform::init() int flag = 0; double lo,hi; if (flipflag && set[3].style == VARIABLE) - error->all(FLERR, "Fix deform cannot use yz variable with xy"); + error->all(FLERR, "Fix {} cannot use yz variable with xy", style); if (set[3].style == WIGGLE) { lo = set[3].tilt_min; hi = set[3].tilt_max; @@ -584,7 +584,7 @@ void FixDeform::init() hi / (set[1].hi_stop - set[1].lo_stop) > 0.5) flag = 1; } if (flag) - error->all(FLERR, "Fix deform is changing yz too much with xy"); + error->all(FLERR, "Fix {} is changing yz too much with xy", style); } } @@ -989,14 +989,15 @@ void FixDeform::restart(char *buf) samestyle = 0; } if (!samestyle) - error->all(FLERR, "Fix deform settings not consistent with restart"); + error->all(FLERR, "Fix {} settings not consistent with restart", style); } /* ---------------------------------------------------------------------- */ void FixDeform::options(int narg, char **arg) { - if (narg < 0) error->all(FLERR, "Illegal fix deform command"); + const std::string thiscmd = fmt::format("fix {}", style); + if (narg < 0) utils::missing_cmd_args(FLERR, thiscmd, error); remapflag = Domain::X_REMAP; scaleflag = 1; @@ -1006,26 +1007,30 @@ void FixDeform::options(int narg, char **arg) std::unordered_map child_options; int nskip; - if (utils::strmatch(style, "pressure$")) - child_options.insert({{"couple", 2}, {"max/rate", 2}, {"normalize/pressure", 2}, {"vol/balance/p", 2}}); + if (utils::strmatch(style, "^deform/pressure")) { + child_options.insert({{"couple", 2}, + {"max/rate", 2}, + {"normalize/pressure", 2}, + {"vol/balance/p", 2}}); + } int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg], "remap") == 0) { - if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform remap", error); + if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, thiscmd + " remap", error); if (strcmp(arg[iarg + 1], "x") == 0) remapflag = Domain::X_REMAP; else if (strcmp(arg[iarg + 1], "v") == 0) remapflag = Domain::V_REMAP; else if (strcmp(arg[iarg + 1], "none") == 0) remapflag = Domain::NO_REMAP; - else error->all(FLERR, "Illegal fix deform remap command: {}", arg[iarg + 1]); + else error->all(FLERR, "Illegal fix {} remap command: {}", style, arg[iarg + 1]); iarg += 2; } else if (strcmp(arg[iarg], "units") == 0) { - if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform units", error); + if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, thiscmd + " units", error); if (strcmp(arg[iarg + 1], "box") == 0) scaleflag = 0; else if (strcmp(arg[iarg + 1], "lattice") == 0) scaleflag = 1; - else error->all(FLERR, "Illegal fix deform units command: {}", arg[iarg + 1]); + else error->all(FLERR, "Illegal fix {} units command: {}", style, arg[iarg + 1]); iarg += 2; } else if (strcmp(arg[iarg], "flip") == 0) { - if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "fix deform flip", error); + if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, thiscmd + " flip", error); flipflag = utils::logical(FLERR, arg[iarg + 1], false, lmp); iarg += 2; } else if (child_options.find(arg[iarg]) != child_options.end()) { @@ -1033,7 +1038,7 @@ void FixDeform::options(int narg, char **arg) if (iarg + nskip > narg) utils::missing_cmd_args(FLERR, fmt::format("fix {} {}", style, arg[iarg]), error); iarg += nskip; - } else error->all(FLERR, "Illegal fix deform command: {}", arg[iarg]); + } else error->all(FLERR, "Unknown fix {} keyword: {}", style, arg[iarg]); } } From 1afb9e9dcb0fe6cff7ea2d226ea4020a179857b2 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 2 Feb 2024 17:10:35 -0700 Subject: [PATCH 23/29] Revamping arg parsing in child class, updates to doc pages --- src/EXTRA-FIX/fix_deform_pressure.cpp | 76 ++++++++++++++++++++------- src/EXTRA-FIX/fix_deform_pressure.h | 2 +- src/fix_deform.cpp | 71 ++++++++++++++----------- src/fix_deform.h | 3 ++ 4 files changed, 102 insertions(+), 50 deletions(-) diff --git a/src/EXTRA-FIX/fix_deform_pressure.cpp b/src/EXTRA-FIX/fix_deform_pressure.cpp index 91a0591cd29..26dd85b78bd 100644 --- a/src/EXTRA-FIX/fix_deform_pressure.cpp +++ b/src/EXTRA-FIX/fix_deform_pressure.cpp @@ -36,6 +36,7 @@ #include #include +#include using namespace LAMMPS_NS; using namespace FixConst; @@ -56,9 +57,10 @@ FixDeformPressure::FixDeformPressure(LAMMPS *lmp, int narg, char **arg) : // parse child-specific arguments - int index; - int iarg = 4; - while (iarg < narg) { + int index, iarg; + int 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) { @@ -78,7 +80,7 @@ FixDeformPressure::FixDeformPressure(LAMMPS *lmp, int narg, char **arg) : set_extra[index].pvar_flag = 1; } set_extra[index].pgain = utils::numeric(FLERR, arg[iarg + 3], false, lmp); - iarg += 4; + 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; @@ -89,7 +91,7 @@ FixDeformPressure::FixDeformPressure(LAMMPS *lmp, int narg, char **arg) : set_extra[index].pvar_flag = 1; } set_extra[index].pgain = utils::numeric(FLERR, arg[iarg + 3], false, lmp); - iarg += 4; + i += 4; } else error->all(FLERR, "Illegal fix deform/pressure command argument: {}", arg[iarg + 1]); } else if (strcmp(arg[iarg], "xy") == 0 || @@ -111,12 +113,12 @@ FixDeformPressure::FixDeformPressure(LAMMPS *lmp, int narg, char **arg) : set_extra[index].pvar_flag = 1; } set_extra[index].pgain = utils::numeric(FLERR, arg[iarg + 3], false, lmp); - iarg += 4; + i += 4; } 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; - iarg += 2; + 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; @@ -127,14 +129,16 @@ FixDeformPressure::FixDeformPressure(LAMMPS *lmp, int narg, char **arg) : set_extra[6].pvar_flag = 1; } set_extra[6].pgain = utils::numeric(FLERR, arg[iarg + 3], false, lmp); - iarg += 4; + 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 - options(narg - iarg, &arg[iarg]); + iarg = iarg_options_start; + options(i, narg - iarg, &arg[iarg]); // repeat: setup dimflags used by other classes to check for volume-change conflicts @@ -172,6 +176,42 @@ FixDeformPressure::FixDeformPressure(LAMMPS *lmp, int narg, char **arg) : 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++) @@ -221,6 +261,7 @@ FixDeformPressure::FixDeformPressure(LAMMPS *lmp, int narg, char **arg) : 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 @@ -814,17 +855,16 @@ void FixDeformPressure::restart(char *buf) /* ---------------------------------------------------------------------- */ -void FixDeformPressure::options(int narg, char **arg) +void FixDeformPressure::options(int i, int narg, char **arg) { - if (narg < 0) error->all(FLERR, "Illegal fix deform/pressure command"); - pcouple = NOCOUPLE; max_h_rate = 0.0; vol_balance_flag = 0; normalize_pressure_flag = 0; - int iarg = 0; - while (iarg < narg) { + int iarg, nskip; + while (i < 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; @@ -833,21 +873,21 @@ void FixDeformPressure::options(int narg, char **arg) 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]); - iarg += 2; + 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"); - iarg += 2; + 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); - iarg += 2; + 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); - iarg += 2; + i += 2; } else error->all(FLERR, "Illegal fix deform/pressure command: {}", arg[iarg]); } } diff --git a/src/EXTRA-FIX/fix_deform_pressure.h b/src/EXTRA-FIX/fix_deform_pressure.h index 41b93f6e987..a52bb01c042 100644 --- a/src/EXTRA-FIX/fix_deform_pressure.h +++ b/src/EXTRA-FIX/fix_deform_pressure.h @@ -60,7 +60,7 @@ class FixDeformPressure : public FixDeform { SetExtra *set_extra; Set set_box; - void options(int, char **); + void options(int, int, char **); void apply_volume() override; void apply_pressure(); void apply_box(); diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index 9c6bfb9d8b4..010250ed921 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -36,6 +36,7 @@ #include #include #include +#include using namespace LAMMPS_NS; using namespace FixConst; @@ -147,6 +148,7 @@ irregular(nullptr), set(nullptr) nskip = child_styles[arg[iarg + 1]]; if (iarg + nskip > narg) utils::missing_cmd_args(FLERR, fmt::format("fix {} {}", style, arg[iarg + 1]), error); + for (int i = 0; i < nskip; i++) leftover_iarg.push_back(iarg + i); iarg += nskip; } else error->all(FLERR, "Illegal fix {} command argument: {}", style, arg[iarg + 1]); @@ -209,6 +211,7 @@ irregular(nullptr), set(nullptr) nskip = child_styles[arg[iarg + 1]]; if (iarg + nskip > narg) utils::missing_cmd_args(FLERR, fmt::format("fix {} {}", style, arg[iarg + 1]), error); + for (int i = 0; i < nskip; i++) leftover_iarg.push_back(iarg + i); iarg += nskip; } else error->all(FLERR, "Illegal fix {} command argument: {}", style, arg[iarg + 1]); } else if (child_parameters.find(arg[iarg]) != child_parameters.end()) { @@ -216,6 +219,7 @@ irregular(nullptr), set(nullptr) nskip = child_styles[arg[iarg + 1]]; if (iarg + nskip > narg) utils::missing_cmd_args(FLERR, fmt::format("fix {} {}", style, arg[iarg + 1]), error); + for (int i = 0; i < nskip; i++) leftover_iarg.push_back(iarg + i); iarg += nskip; } error->all(FLERR, "Illegal fix {} command argument: {}", style, arg[iarg + 1]); } else break; @@ -223,6 +227,7 @@ irregular(nullptr), set(nullptr) // read options from end of input line + iarg_options_start = iarg; options(narg - iarg, &arg[iarg]); // no x remap effectively moves atoms within box, so set restart_pbc @@ -303,37 +308,40 @@ irregular(nullptr), set(nullptr) // 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; + // only check for parent, otherwise child will check + + if (strcmp(style, "deform") == 0) { + 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; + } } } @@ -1037,6 +1045,7 @@ void FixDeform::options(int narg, char **arg) nskip = child_options[arg[iarg]]; if (iarg + nskip > narg) utils::missing_cmd_args(FLERR, fmt::format("fix {} {}", style, arg[iarg]), error); + for (int i = 0; i < nskip; i++) leftover_iarg.push_back(iarg + i); iarg += nskip; } else error->all(FLERR, "Unknown fix {} keyword: {}", style, arg[iarg]); } diff --git a/src/fix_deform.h b/src/fix_deform.h index fa92b851e6b..b1337294448 100644 --- a/src/fix_deform.h +++ b/src/fix_deform.h @@ -68,6 +68,9 @@ class FixDeform : public Fix { }; Set *set; + std::vector leftover_iarg; + int iarg_options_start; + void options(int, char **); void virtual apply_volume(); void apply_strain(); From 3358fe36d1ae7c8723dd454d00e00ff3d200ca13 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Thu, 8 Feb 2024 21:27:58 -0700 Subject: [PATCH 24/29] Fixing bugs in child arg parsing --- src/fix_deform.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index 010250ed921..4b774b79d36 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -64,7 +64,7 @@ irregular(nullptr), set(nullptr) int nskip; if (utils::strmatch(style, "^deform/pressure")) { child_parameters.insert("box"); - child_styles.insert({{"pressure", 4}, {"pressure/mean", 4}, {"volume", 3}}); + child_styles.insert({{"pressure", 4}, {"pressure/mean", 4}, {"volume", 2}}); } // set defaults @@ -221,7 +221,7 @@ irregular(nullptr), set(nullptr) utils::missing_cmd_args(FLERR, fmt::format("fix {} {}", style, arg[iarg + 1]), error); for (int i = 0; i < nskip; i++) leftover_iarg.push_back(iarg + i); iarg += nskip; - } error->all(FLERR, "Illegal fix {} command argument: {}", style, arg[iarg + 1]); + } else error->all(FLERR, "Illegal fix {} command argument: {}", style, arg[iarg + 1]); } else break; } From 4c0952dc70d3537e92e9a7e7c50a4befea61f094 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 20 Feb 2024 21:02:55 -0700 Subject: [PATCH 25/29] Doc file updates, reverting h_rate initialization --- doc/src/fix_deform.rst | 8 +- doc/src/fix_deform_pressure.rst | 661 ++++---------------------- src/EXTRA-FIX/fix_deform_pressure.cpp | 2 - src/fix_deform.cpp | 31 +- 4 files changed, 106 insertions(+), 596 deletions(-) diff --git a/doc/src/fix_deform.rst b/doc/src/fix_deform.rst index ee010f5645c..c0ea50ae412 100644 --- a/doc/src/fix_deform.rst +++ b/doc/src/fix_deform.rst @@ -44,7 +44,7 @@ Syntax v_name1 = variable with name1 for box length change as function of time v_name2 = variable with name2 for change rate as function of time *xy*, *xz*, *yz* args = style value - style = *final* or *delta* or *vel* or *erate* or *trate* or *wiggle* + style = *final* or *delta* or *vel* or *erate* or *trate* or *wiggle* or *variable* *final* value = tilt tilt = tilt factor at end of run (distance units) *delta* value = dtilt @@ -95,7 +95,9 @@ Change the volume and/or shape of the simulation box during a dynamics run. Orthogonal simulation boxes have 3 adjustable parameters (x,y,z). Triclinic (non-orthogonal) simulation boxes have 6 adjustable parameters (x,y,z,xy,xz,yz). Any or all of them can be -adjusted independently and simultaneously by this command. +adjusted independently and simultaneously by this command. For +additional pressure-based controls, see +:doc:`fix deform/pressure `. This fix can be used to perform non-equilibrium MD (NEMD) simulations of a continuously strained system. See the :doc:`fix nvt/sllod ` and :doc:`compute temp/deform ` commands for more details. Note @@ -592,7 +594,7 @@ xy) that is shrink-wrapped via the :doc:`boundary ` command. Related commands """""""""""""""" -:doc:`change_box ` +:doc:`fix deform/pressure `, :doc:`change_box ` Default """"""" diff --git a/doc/src/fix_deform_pressure.rst b/doc/src/fix_deform_pressure.rst index d19e5fba7e8..d45c10b3518 100644 --- a/doc/src/fix_deform_pressure.rst +++ b/doc/src/fix_deform_pressure.rst @@ -1,10 +1,7 @@ -.. index:: fix deform -.. index:: fix deform/kk +.. index:: fix deform/pressure -fix deform command -================== - -Accelerator Variants: *deform/kk* +fix deform/pressure command +=========================== Syntax """""" @@ -20,58 +17,23 @@ Syntax .. parsed-literal:: - parameter = *x* or *y* or *z* or *xy* or *xz* or *yz* or *iso* + parameter = *x* or *y* or *z* or *xy* or *xz* or *yz* or *box* *x*, *y*, *z* args = style value(s) - style = *final* or *delta* or *scale* or *vel* or *erate* or *trate* or *volume* or *wiggle* or *variable* - *final* values = lo hi - lo hi = box boundaries at end of run (distance units) - *delta* values = dlo dhi - dlo dhi = change in box boundaries at end of run (distance units) - *scale* values = factor - factor = multiplicative factor for change in box length at end of run - *vel* value = V - V = change box length at this velocity (distance/time units), - effectively an engineering strain rate - *erate* value = R - R = engineering strain rate (1/time units) + style = *final* or *delta* or *scale* or *vel* or *erate* or *trate* or *volume* or *wiggle* or *variable* or *pressure* or *pressure/mean* *pressure* values = target gain target = target pressure (pressure units) gain = proportional gain constant (1/(time * pressure) or 1/time units) *pressure/mean* values = target gain target = target pressure (pressure units) gain = proportional gain constant (1/(time * pressure) or 1/time units) - *trate* value = R - R = true strain rate (1/time units) - *volume* value = none = adjust this dim to preserve volume of system - *wiggle* values = A Tp - A = amplitude of oscillation (distance units) - Tp = period of oscillation (time units) - *variable* values = v_name1 v_name2 - v_name1 = variable with name1 for box length change as function of time - v_name2 = variable with name2 for change rate as function of time + All other styles operate identically to those in :doc:`fix deform ` *xy*, *xz*, *yz* args = style value - style = *final* or *delta* or *vel* or *erate* or *trate* or *wiggle* - *final* value = tilt - tilt = tilt factor at end of run (distance units) - *delta* value = dtilt - dtilt = change in tilt factor at end of run (distance units) - *vel* value = V - V = change tilt factor at this velocity (distance/time units), - effectively an engineering shear strain rate - *erate* value = R - R = engineering shear strain rate (1/time units) + style = *final* or *delta* or *vel* or *erate* or *trate* or *wiggle* or *variable* or *pressure* *pressure* values = target gain target = target pressure (pressure units) gain = proportional gain constant (1/(time * pressure) or 1/time units) - *trate* value = R - R = true shear strain rate (1/time units) - *wiggle* values = A Tp - A = amplitude of oscillation (distance units) - Tp = period of oscillation (time units) - *variable* values = v_name1 v_name2 - v_name1 = variable with name1 for tilt change as function of time - v_name2 = variable with name2 for change rate as function of time - *iso* = style value + All other styles operate identically to those in :doc:`fix deform ` + *box* = style value style = *volume* or *pressure* *volume* value = none = isotropically adjust system to preserve volume of system *pressure* values = target gain @@ -83,15 +45,6 @@ Syntax .. parsed-literal:: - *remap* value = *x* or *v* or *none* - x = remap coords of atoms in group into deforming box - v = remap velocities of atoms in group when they cross periodic boundaries - none = no remapping of x or v - *flip* value = *yes* or *no* - allow or disallow box flips when it becomes highly skewed - *units* value = *lattice* or *box* - lattice = distances are defined in lattice units - box = distances are defined in simulation box units *couple* value = *none* or *xyz* or *xy* or *yz* or *xz* couple pressure values of various dimensions *vol/balance/p* value = *yes* or *no* @@ -100,232 +53,38 @@ Syntax rate = maximum strain rate for pressure control *normalize/pressure* value = *yes* or *no* Modifies pressure controls such that the deviation in pressure is normalized by the target pressure + All other options operate identically to those in :doc:`fix deform ` Examples """""""" .. code-block:: LAMMPS - fix 1 all deform 1 x final 0.0 9.0 z final 0.0 5.0 units box - fix 1 all deform 1 x trate 0.1 y volume z volume - fix 1 all deform 1 xy erate 0.001 remap v - fix 1 all deform 10 y delta -0.5 0.5 xz vel 1.0 - fix 1 all deform 1 x pressure 2.0 0.1 normalize/pressure yes max/rate 0.001 - fix 1 all deform 1 x trate 0.1 y volume z volume vol/balance/p yes - fix 1 all deform 1 x trate 0.1 y pressure/mean 0.0 1.0 z pressure/mean 0.0 1.0 + fix 1 all deform/pressure 1 x pressure 2.0 0.1 normalize/pressure yes max/rate 0.001 + fix 1 all deform/pressure 1 x trate 0.1 y volume z volume vol/balance/p yes + fix 1 all deform/pressure 1 x trate 0.1 y pressure/mean 0.0 1.0 z pressure/mean 0.0 1.0 Description """"""""""" -Change the volume and/or shape of the simulation box during a dynamics -run. Orthogonal simulation boxes have 3 adjustable parameters -(x,y,z). Triclinic (non-orthogonal) simulation boxes have 6 -adjustable parameters (x,y,z,xy,xz,yz). Any or all of them can be -adjusted independently and simultaneously by this command. - -This fix can be used to perform non-equilibrium MD (NEMD) simulations -of a continuously strained system. See the :doc:`fix nvt/sllod ` and :doc:`compute temp/deform ` commands for more details. Note -that simulation of a continuously extended system (extensional flow) -can be modeled using the :ref:`UEF package ` and its :doc:`fix commands `. - -For the *x*, *y*, *z* parameters, the associated dimension cannot be -shrink-wrapped. For the *xy*, *yz*, *xz* parameters, the associated -second dimension cannot be shrink-wrapped. Dimensions not varied by this -command can be periodic or non-periodic. Dimensions corresponding to -unspecified parameters can also be controlled by a :doc:`fix npt ` or :doc:`fix nph ` command. - -The size and shape of the simulation box at the beginning of the -simulation run were either specified by the -:doc:`create_box ` or :doc:`read_data ` or -:doc:`read_restart ` command used to setup the simulation -initially if it is the first run, or they are the values from the end -of the previous run. The :doc:`create_box `, :doc:`read data `, and :doc:`read_restart ` commands -specify whether the simulation box is orthogonal or non-orthogonal -(triclinic) and explain the meaning of the xy,xz,yz tilt factors. If -fix deform changes the xy,xz,yz tilt factors, then the simulation box -must be triclinic, even if its initial tilt factors are 0.0. - -As described below, the desired simulation box size and shape at the -end of the run are determined by the parameters of the fix deform -command. Every Nth timestep during the run, the simulation box is -expanded, contracted, or tilted to ramped values between the initial -and final values. +This fix is an extension of :doc:`fix deform `, inheriting +all of its features and adding new pressure-based controls to allow for +new deformation protocols. All details in :doc:`fix deform ` +apply to this fix unless otherwise noted. ---------- For the *x*, *y*, and *z* parameters, this is the meaning of their styles and values. -The *final*, *delta*, *scale*, *vel*, and *erate* styles all change -the specified dimension of the box via "constant displacement" which -is effectively a "constant engineering strain rate". This means the -box dimension changes linearly with time from its initial to final -value. - -For style *final*, the final lo and hi box boundaries of a dimension -are specified. The values can be in lattice or box distance units. -See the discussion of the units keyword below. - -For style *delta*, plus or minus changes in the lo/hi box boundaries -of a dimension are specified. The values can be in lattice or box -distance units. See the discussion of the units keyword below. - -For style *scale*, a multiplicative factor to apply to the box length -of a dimension is specified. For example, if the initial box length -is 10, and the factor is 1.1, then the final box length will be 11. A -factor less than 1.0 means compression. - -For style *vel*, a velocity at which the box length changes is -specified in units of distance/time. This is effectively a "constant -engineering strain rate", where rate = V/L0 and L0 is the initial box -length. The distance can be in lattice or box distance units. See -the discussion of the units keyword below. For example, if the -initial box length is 100 Angstroms, and V is 10 Angstroms/ps, then -after 10 ps, the box length will have doubled. After 20 ps, it -will have tripled. - -The *erate* style changes a dimension of the box at a "constant -engineering strain rate". The units of the specified strain rate are -1/time. See the :doc:`units ` command for the time units -associated with different choices of simulation units, -e.g. picoseconds for "metal" units). Tensile strain is unitless and -is defined as delta/L0, where L0 is the original box length and delta -is the change relative to the original length. The box length L as a -function of time will change as - -.. parsed-literal:: - - L(t) = L0 (1 + erate\*dt) - -where dt is the elapsed time (in time units). Thus if *erate* R is -specified as 0.1 and time units are picoseconds, this means the box -length will increase by 10% of its original length every picosecond. -I.e. strain after 1 ps = 0.1, strain after 2 ps = 0.2, etc. R = --0.01 means the box length will shrink by 1% of its original length -every picosecond. Note that for an "engineering" rate the change is -based on the original box length, so running with R = 1 for 10 -picoseconds expands the box length by a factor of 11 (strain of 10), -which is different that what the *trate* style would induce. - -The *trate* style changes a dimension of the box at a "constant true -strain rate". Note that this is not an "engineering strain rate", as -the other styles are. Rather, for a "true" rate, the rate of change -is constant, which means the box dimension changes non-linearly with -time from its initial to final value. The units of the specified -strain rate are 1/time. See the :doc:`units ` command for the -time units associated with different choices of simulation units, -e.g. picoseconds for "metal" units). Tensile strain is unitless and -is defined as delta/L0, where L0 is the original box length and delta -is the change relative to the original length. - -The box length L as a function of time will change as - -.. parsed-literal:: - - L(t) = L0 exp(trate\*dt) - -where dt is the elapsed time (in time units). Thus if *trate* R is -specified as ln(1.1) and time units are picoseconds, this means the -box length will increase by 10% of its current (not original) length -every picosecond. I.e. strain after 1 ps = 0.1, strain after 2 ps -= 0.21, etc. R = ln(2) or ln(3) means the box length will double or -triple every picosecond. R = ln(0.99) means the box length will -shrink by 1% of its current length every picosecond. Note that for a -"true" rate the change is continuous and based on the current length, -so running with R = ln(2) for 10 picoseconds does not expand the box -length by a factor of 11 as it would with *erate*, but by a factor of -1024 since the box length will double every picosecond. - -Note that to change the volume (or cross-sectional area) of the -simulation box at a constant rate, you can change multiple dimensions -via *erate* or *trate*\ . E.g. to double the box volume in a picosecond -picosecond, you could set "x erate M", "y erate M", "z erate M", with -M = pow(2,1/3) - 1 = 0.26, since if each box dimension grows by 26%, -the box volume doubles. Or you could set "x trate M", "y trate M", "z -trate M", with M = ln(1.26) = 0.231, and the box volume would double -every picosecond. - -The *volume* style changes the specified dimension in such a way that -the box volume remains constant while other box dimensions are changed -explicitly via the styles discussed above. For example, "x scale 1.1 -y scale 1.1 z volume" will shrink the z box length as the x,y box -lengths increase, to keep the volume constant (product of x,y,z -lengths). If "x scale 1.1 z volume" is specified and parameter *y* is -unspecified, then the z box length will shrink as x increases to keep -the product of x,z lengths constant. If "x scale 1.1 y volume z -volume" is specified, then both the y,z box lengths will shrink as x -increases to keep the volume constant (product of x,y,z lengths). In -this case, the y,z box lengths shrink so as to keep their relative -aspect ratio constant. When maintaining a constant volume using two -separate dimensions, one can alternatively allow the two dimensions -to adjust their aspect ratio to attempt to maintain equivalent -pressures along the two dimensions. See the -:ref:`vol/balance/p ` option for more details. - -For solids or liquids, note that when one dimension of the box is -expanded via fix deform (i.e. tensile strain), it may be physically -undesirable to hold the other 2 box lengths constant (unspecified by -fix deform) since that implies a density change. Using the *volume* -style for those 2 dimensions to keep the box volume constant may make -more physical sense, but may also not be correct for materials and -potentials whose Poisson ratio is not 0.5. An alternative is to use -:doc:`fix npt aniso ` with zero applied pressure on those 2 -dimensions, so that they respond to the tensile strain dynamically. - -The *wiggle* style oscillates the specified box length dimension -sinusoidally with the specified amplitude and period. I.e. the box -length L as a function of time is given by - -.. parsed-literal:: - - L(t) = L0 + A sin(2\*pi t/Tp) - -where L0 is its initial length. If the amplitude A is a positive -number the box initially expands, then contracts, etc. If A is -negative then the box initially contracts, then expands, etc. The -amplitude can be in lattice or box distance units. See the discussion -of the units keyword below. - -The *variable* style changes the specified box length dimension by -evaluating a variable, which presumably is a function of time. The -variable with *name1* must be an :doc:`equal-style variable ` -and should calculate a change in box length in units of distance. -Note that this distance is in box units, not lattice units; see the -discussion of the *units* keyword below. The formula associated with -variable *name1* can reference the current timestep. Note that it -should return the "change" in box length, not the absolute box length. -This means it should evaluate to 0.0 when invoked on the initial -timestep of the run following the definition of fix deform. It should -evaluate to a value > 0.0 to dilate the box at future times, or a -value < 0.0 to compress the box. - -The variable *name2* must also be an :doc:`equal-style variable ` and should calculate the rate of box length -change, in units of distance/time, i.e. the time-derivative of the -*name1* variable. This quantity is used internally by LAMMPS to reset -atom velocities when they cross periodic boundaries. It is computed -internally for the other styles, but you must provide it when using an -arbitrary variable. - -Here is an example of using the *variable* style to perform the same -box deformation as the *wiggle* style formula listed above, where we -assume that the current timestep = 0. - -.. code-block:: LAMMPS - - variable A equal 5.0 - variable Tp equal 10.0 - variable displace equal "v_A * sin(2*PI * step*dt/v_Tp)" - variable rate equal "2*PI*v_A/v_Tp * cos(2*PI * step*dt/v_Tp)" - fix 2 all deform 1 x variable v_displace v_rate remap v - -For the *scale*, *vel*, *erate*, *trate*, *volume*, *wiggle*, and -*variable* styles, the box length is expanded or compressed around its -mid point. +The *final*, *delta*, *scale*, *vel*, *erate*, *trate*, *volume*, +*wiggle*, and *variable* styles all behave identically to those in +:doc:`fix deform `. Additional styles are described below. -The *pressure* style adjusts a dimensions's box length to control that -component of the pressure tensor. This option attempts to maintain a -specified target value using a linear controller where the box length -:math:`L` evolves according to the equation +The *pressure* style adjusts a dimension's box length to control the +corresponding component of the pressure tensor. This option attempts to +maintain a specified target pressure using a linear controller where the +box length :math:`L` evolves according to the equation .. parsed-literal:: @@ -338,163 +97,43 @@ approach is similar to the method used to control the pressure by accepts either a constant numeric value or a LAMMPS :ref:`variable `. Notably, this variable can be a function of time or other components of the pressure tensor. By default, :math:`k` has units of 1/(time * pressure) -although this will change if the *normalize/pessure* option is set as +although this will change if the *normalize/pressure* option is set as :ref:`discussed below `. There is no proven method to choosing an appropriate value of :math:`k` as it will depend on the -specific details of a simulation and testing different values is -recommended. One can also apply a maximum limit to the magnitude of the -applied strain using the :ref:`max/rate ` option and couple -pressures in different dimensions using the :ref:`couple ` -option. +specific details of a simulation. Testing different values is recommended. + +By default, there is no limit on the resulting strain rate in any dimension. +A maximum limit can be applied using the :ref:`max/rate ` +option. Akin to :ref:`fix nh `, pressures in different dimensions +can be coupled using the :ref:`couple ` option. This means +the instantaneous pressure along coupled dimensions are averaged and the box +strains identically along the coupled dimensions. The *pressure/mean* style changes a dimension's box length to maintain a constant mean pressure defined as the trace of the pressure tensor. -This option is therefore very similar to the *pressure* style with -identical arguments except the current and target pressures refer to the +This option has identical arguments to the *pressure* style and a similar +functional equation, except the current and target pressures refer to the mean trace of the pressure tensor. All options for the *pressure* style also apply to the *pressure/mean* style except for the :ref:`couple ` option. +Note that while this style can be identical to coupled *pressure* styles, +it is generally not the same. For instance in 2D, a coupled *pressure* +style in the *x* and *y* dimensions would be equivalent to using the +*pressure/mean* style with identical settings in each dimension. However, +it would not be the same if settings (e.g. gain constants) were used in +the *x* and *y* dimensions or if the *pressure/mean* command was only applied +along one dimension. + ---------- For the *xy*, *xz*, and *yz* parameters, this is the meaning of their styles and values. Note that changing the tilt factors of a triclinic box does not change its volume. -The *final*, *delta*, *vel*, and *erate* styles all change the shear -strain at a "constant engineering shear strain rate". This means the -tilt factor changes linearly with time from its initial to final -value. - -For style *final*, the final tilt factor is specified. The value -can be in lattice or box distance units. See the discussion of the -units keyword below. - -For style *delta*, a plus or minus change in the tilt factor is -specified. The value can be in lattice or box distance units. See -the discussion of the units keyword below. - -For style *vel*, a velocity at which the tilt factor changes is -specified in units of distance/time. This is effectively an -"engineering shear strain rate", where rate = V/L0 and L0 is the -initial box length perpendicular to the direction of shear. The -distance can be in lattice or box distance units. See the discussion -of the units keyword below. For example, if the initial tilt factor -is 5 Angstroms, and the V is 10 Angstroms/ps, then after 1 ps, the -tilt factor will be 15 Angstroms. After 2 ps, it will be 25 -Angstroms. - -The *erate* style changes a tilt factor at a "constant engineering -shear strain rate". The units of the specified shear strain rate are -1/time. See the :doc:`units ` command for the time units -associated with different choices of simulation units, -e.g. picoseconds for "metal" units). Shear strain is unitless and is -defined as offset/length, where length is the box length perpendicular -to the shear direction (e.g. y box length for xy deformation) and -offset is the displacement distance in the shear direction (e.g. x -direction for xy deformation) from the unstrained orientation. - -The tilt factor T as a function of time will change as - -.. parsed-literal:: - - T(t) = T0 + L0\*erate\*dt - -where T0 is the initial tilt factor, L0 is the original length of the -box perpendicular to the shear direction (e.g. y box length for xy -deformation), and dt is the elapsed time (in time units). Thus if -*erate* R is specified as 0.1 and time units are picoseconds, this -means the shear strain will increase by 0.1 every picosecond. I.e. if -the xy shear strain was initially 0.0, then strain after 1 ps = 0.1, -strain after 2 ps = 0.2, etc. Thus the tilt factor would be 0.0 at -time 0, 0.1\*ybox at 1 ps, 0.2\*ybox at 2 ps, etc, where ybox is the -original y box length. R = 1 or 2 means the tilt factor will increase -by 1 or 2 every picosecond. R = -0.01 means a decrease in shear -strain by 0.01 every picosecond. - -The *trate* style changes a tilt factor at a "constant true shear -strain rate". Note that this is not an "engineering shear strain -rate", as the other styles are. Rather, for a "true" rate, the rate -of change is constant, which means the tilt factor changes -non-linearly with time from its initial to final value. The units of -the specified shear strain rate are 1/time. See the -:doc:`units ` command for the time units associated with -different choices of simulation units, e.g. picoseconds for "metal" -units). Shear strain is unitless and is defined as offset/length, -where length is the box length perpendicular to the shear direction -(e.g. y box length for xy deformation) and offset is the displacement -distance in the shear direction (e.g. x direction for xy deformation) -from the unstrained orientation. - -The tilt factor T as a function of time will change as - -.. parsed-literal:: - - T(t) = T0 exp(trate\*dt) - -where T0 is the initial tilt factor and dt is the elapsed time (in -time units). Thus if *trate* R is specified as ln(1.1) and time units -are picoseconds, this means the shear strain or tilt factor will -increase by 10% every picosecond. I.e. if the xy shear strain was -initially 0.1, then strain after 1 ps = 0.11, strain after 2 ps = -0.121, etc. R = ln(2) or ln(3) means the tilt factor will double or -triple every picosecond. R = ln(0.99) means the tilt factor will -shrink by 1% every picosecond. Note that the change is continuous, so -running with R = ln(2) for 10 picoseconds does not change the tilt -factor by a factor of 10, but by a factor of 1024 since it doubles -every picosecond. Note that the initial tilt factor must be non-zero -to use the *trate* option. - -Note that shear strain is defined as the tilt factor divided by the -perpendicular box length. The *erate* and *trate* styles control the -tilt factor, but assume the perpendicular box length remains constant. -If this is not the case (e.g. it changes due to another fix deform -parameter), then this effect on the shear strain is ignored. - -The *wiggle* style oscillates the specified tilt factor sinusoidally -with the specified amplitude and period. I.e. the tilt factor T as a -function of time is given by - -.. parsed-literal:: - - T(t) = T0 + A sin(2\*pi t/Tp) - -where T0 is its initial value. If the amplitude A is a positive -number the tilt factor initially becomes more positive, then more -negative, etc. If A is negative then the tilt factor initially -becomes more negative, then more positive, etc. The amplitude can be -in lattice or box distance units. See the discussion of the units -keyword below. - -The *variable* style changes the specified tilt factor by evaluating a -variable, which presumably is a function of time. The variable with -*name1* must be an :doc:`equal-style variable ` and should -calculate a change in tilt in units of distance. Note that this -distance is in box units, not lattice units; see the discussion of the -*units* keyword below. The formula associated with variable *name1* -can reference the current timestep. Note that it should return the -"change" in tilt factor, not the absolute tilt factor. This means it -should evaluate to 0.0 when invoked on the initial timestep of the run -following the definition of fix deform. - -The variable *name2* must also be an :doc:`equal-style variable ` and should calculate the rate of tilt change, -in units of distance/time, i.e. the time-derivative of the *name1* -variable. This quantity is used internally by LAMMPS to reset atom -velocities when they cross periodic boundaries. It is computed -internally for the other styles, but you must provide it when using an -arbitrary variable. - -Here is an example of using the *variable* style to perform the same -box deformation as the *wiggle* style formula listed above, where we -assume that the current timestep = 0. - -.. code-block:: LAMMPS - - variable A equal 5.0 - variable Tp equal 10.0 - variable displace equal "v_A * sin(2*PI * step*dt/v_Tp)" - variable rate equal "2*PI*v_A/v_Tp * cos(2*PI * step*dt/v_Tp)" - fix 2 all deform 1 xy variable v_displace v_rate remap v +The *final*, *delta*, *vel*, *erate*, *trate*, *wiggle*, and *variable* +styles all behave identically to those in :doc:`fix deform `. +Additional styles are described below. The *pressure* style adjusts a tilt factor to control the corresponding off-diagonal component of the pressure tensor. This option attempts to @@ -519,155 +158,42 @@ of the applied strain using the :ref:`max/rate ` option. ---------- -The *iso* parameter provides an additonal control over the x, y, -and z box lengths. This parameter can only be used in combination with -the *x*, *y*, or *z* comamnds: *vel*, *erate*, *trate*, *pressure*, or -*wiggle*. Note that this parameter will change the overall strain rate in -the *x*, *y*, or *z* dimensions. This is the meaning of its styles and values. +The *box* parameter provides an additonal control over the *x*, *y*, +and *z* box lengths by isotropically dilating or contracting the box to +either maintain a fixed mean pressure or volume. This isotropic scaling +is applied after the box is deformed by the above *x*, *y*, *z*, *xy*, +*xz*, and *yz* styles, acting as a second deformation step. This parameter +will change the overall strain rate in the *x*, *y*, or *z* dimensions. +This parameter can only be used in combination with the *x*, *y*, or *z* +commands: *vel*, *erate*, *trate*, *pressure*, or *wiggle*. This is the meaning +of its styles and values. The *volume* style isotropically scales box lengths to maintain a constant -box volume in response to deformation from other parameters. - -The *pressure* style controls the box volume to maintain the mean pressure -of the system. This is accomplished by isotropically scaling all box -lengths :math:`L` by an additional factor of :math:`k (P_t - P_m)` where -:math:`k` is the proportional gain constant, :math:`P_t` is the target -pressure, and :math:`P_m` is the current mean pressure (the trace of the -pressure tensor). This style allows one to control the deviatoric strain -tensor while maintaining a fixed mean pressure. - ----------- - -All of the tilt styles change the xy, xz, yz tilt factors during a -simulation. In LAMMPS, tilt factors (xy,xz,yz) for triclinic boxes -are normally bounded by half the distance of the parallel box length. -See the discussion of the *flip* keyword below, to allow this bound to -be exceeded, if desired. - -For example, if xlo = 2 and xhi = 12, then the x box length is 10 and -the xy tilt factor must be between -5 and 5. Similarly, both xz and -yz must be between -(xhi-xlo)/2 and +(yhi-ylo)/2. Note that this is -not a limitation, since if the maximum tilt factor is 5 (as in this -example), then configurations with tilt = ..., -15, -5, 5, 15, 25, -... are all equivalent. - -To obey this constraint and allow for large shear deformations to be -applied via the *xy*, *xz*, or *yz* parameters, the following -algorithm is used. If *prd* is the associated parallel box length (10 -in the example above), then if the tilt factor exceeds the accepted -range of -5 to 5 during the simulation, then the box is flipped to the -other limit (an equivalent box) and the simulation continues. Thus -for this example, if the initial xy tilt factor was 0.0 and "xy final -100.0" was specified, then during the simulation the xy tilt factor -would increase from 0.0 to 5.0, the box would be flipped so that the -tilt factor becomes -5.0, the tilt factor would increase from -5.0 to -5.0, the box would be flipped again, etc. The flip occurs 10 times -and the final tilt factor at the end of the simulation would be 0.0. -During each flip event, atoms are remapped into the new box in the -appropriate manner. - -The one exception to this rule is if the first dimension in the tilt -factor (x for xy) is non-periodic. In that case, the limits on the -tilt factor are not enforced, since flipping the box in that dimension -does not change the atom positions due to non-periodicity. In this -mode, if you tilt the system to extreme angles, the simulation will -simply become inefficient due to the highly skewed simulation box. +box volume in response to deformation from other parameters. This style +may be useful in scenarios where one wants to apply a constant deviatoric +pressure using *pressure* styles in the *x*, *y*, and *z* dimensions ( +deforming the shape of the box), while maintaining a constant volume. + +The *pressure* style isotropically scales box lengths in an attempt to +maintain a target mean pressure (the trace of the pressure tensor) of the +system. This is accomplished by isotropically scaling all box lengths +:math:`L` by an additional factor of :math:`k (P_t - P_m)` where :math:`k` +is the proportional gain constant, :math:`P_t` is the target pressure, and +:math:`P_m` is the current mean pressure. This style may be useful in +scenarios where one wants to apply a constant deviatoric strain rate +using various strain-based styles (e.g. *trate*) along the *x*, *y*, and *z* +dimensions (deforming the shape of the box), while maintaining a mean pressure. ---------- -Each time the box size or shape is changed, the *remap* keyword -determines whether atom positions are remapped to the new box. If -*remap* is set to *x* (the default), atoms in the fix group are -remapped; otherwise they are not. Note that their velocities are not -changed, just their positions are altered. If *remap* is set to *v*, -then any atom in the fix group that crosses a periodic boundary will -have a delta added to its velocity equal to the difference in -velocities between the lo and hi boundaries. Note that this velocity -difference can include tilt components, e.g. a delta in the x velocity -when an atom crosses the y periodic boundary. If *remap* is set to -*none*, then neither of these remappings take place. - -Conceptually, setting *remap* to *x* forces the atoms to deform via an -affine transformation that exactly matches the box deformation. This -setting is typically appropriate for solids. Note that though the -atoms are effectively "moving" with the box over time, it is not due -to their having a velocity that tracks the box change, but only due to -the remapping. By contrast, setting *remap* to *v* is typically -appropriate for fluids, where you want the atoms to respond to the -change in box size/shape on their own and acquire a velocity that -matches the box change, so that their motion will naturally track the -box without explicit remapping of their coordinates. - -.. note:: - - When non-equilibrium MD (NEMD) simulations are performed using - this fix, the option "remap v" should normally be used. This is - because :doc:`fix nvt/sllod ` adjusts the atom positions - and velocities to induce a velocity profile that matches the changing - box size/shape. Thus atom coordinates should NOT be remapped by fix - deform, but velocities SHOULD be when atoms cross periodic boundaries, - since that is consistent with maintaining the velocity profile already - created by fix nvt/sllod. LAMMPS will warn you if the *remap* setting - is not consistent with fix nvt/sllod. - -.. note:: - - For non-equilibrium MD (NEMD) simulations using "remap v" it is - usually desirable that the fluid (or flowing material, e.g. granular - particles) stream with a velocity profile consistent with the - deforming box. As mentioned above, using a thermostat such as :doc:`fix nvt/sllod ` or :doc:`fix lavgevin ` - (with a bias provided by :doc:`compute temp/deform `), will typically accomplish - that. If you do not use a thermostat, then there is no driving force - pushing the atoms to flow in a manner consistent with the deforming - box. E.g. for a shearing system the box deformation velocity may vary - from 0 at the bottom to 10 at the top of the box. But the stream - velocity profile of the atoms may vary from -5 at the bottom to +5 at - the top. You can monitor these effects using the :doc:`fix ave/chunk `, :doc:`compute temp/deform `, and :doc:`compute temp/profile ` commands. One way to induce - atoms to stream consistent with the box deformation is to give them an - initial velocity profile, via the :doc:`velocity ramp ` - command, that matches the box deformation rate. This also typically - helps the system come to equilibrium more quickly, even if a - thermostat is used. - -.. note:: - - If a :doc:`fix rigid ` is defined for rigid bodies, and - *remap* is set to *x*, then the center-of-mass coordinates of rigid - bodies will be remapped to the changing simulation box. This will be - done regardless of whether atoms in the rigid bodies are in the fix - deform group or not. The velocity of the centers of mass are not - remapped even if *remap* is set to *v*, since :doc:`fix nvt/sllod ` does not currently do anything special - for rigid particles. If you wish to perform a NEMD simulation of - rigid particles, you can either thermostat them independently or - include a background fluid and thermostat the fluid via :doc:`fix nvt/sllod `. - -The *flip* keyword allows the tilt factors for a triclinic box to -exceed half the distance of the parallel box length, as discussed -above. If the *flip* value is set to *yes*, the bound is enforced by -flipping the box when it is exceeded. If the *flip* value is set to -*no*, the tilt will continue to change without flipping. Note that if -you apply large deformations, this means the box shape can tilt -dramatically LAMMPS will run less efficiently, due to the large volume -of communication needed to acquire ghost atoms around a processor's -irregular-shaped sub-domain. For extreme values of tilt, LAMMPS may -also lose atoms and generate an error. - -The *units* keyword determines the meaning of the distance units used -to define various arguments. A *box* value selects standard distance -units as defined by the :doc:`units ` command, e.g. Angstroms for -units = real or metal. A *lattice* value means the distance units are -in lattice spacings. The :doc:`lattice ` command must have -been previously used to define the lattice spacing. Note that the -units choice also affects the *vel* style parameters since it is -defined in terms of distance/time. Also note that the units keyword -does not affect the *variable* style. You should use the *xlat*, -*ylat*, *zlat* keywords of the :doc:`thermo_style ` -command if you want to include lattice spacings in a variable formula. +The *flip*, *remap*, and *units* keywords all behave identically +to those in :doc:`fix deform `. Additional optional +keywords are described below. .. _deform_normalize: The *normalize/pressure* keyword changes how box dimensions evolve when -using the *pressure* or *pressure/mean* deformation options. If the +using the *pressure* or *pressure/mean* deformation styles. If the *deform/normalize* value is set to *yes*, then the deviation from the target pressure is normalized by the absolute value of the target pressure such that the proportional gain constant scales a percentage @@ -680,7 +206,7 @@ described below, which will cap the divergence. The *max/rate* keyword sets an upper threshold, *rate*, that limits the maximum magnitude of the instantaneous strain rate applied in any dimension. This keyword only applies to the *pressure* and *pressure/mean* options. If -a pressure-controlled rate is used for both *iso* and either *x*, *y*, or +a pressure-controlled rate is used for both *box* and either *x*, *y*, or *z*, then this threshold will apply separately to each individual controller such that the cumulative strain rate on a box dimension may be up to twice the value of *rate*. @@ -695,15 +221,17 @@ are coupled. *Xyz* means all 3 diagonal components are coupled. Coupling means two things: the instantaneous stress will be computed as an average of the corresponding diagonal components, and the coupled box dimensions will be changed together in lockstep, meaning coupled dimensions will be -dilated or contracted by the same percentage every timestep. The target -pressures and gain constants for any coupled dimensions must be identical. -*Couple xyz* can be used for a 2d simulation; the *z* dimension is simply -ignored. +dilated or contracted by the same percentage every timestep. If a *pressure* +style is defined for more than one coupled dimension, the target pressures +and gain constants must be identical. Alternatively, if a *pressure* +style is only defined for one of the coupled dimensions, its settings are +copied to other dimensions with undefined styles. *Couple xyz* can be used +for a 2d simulation; the *z* dimension is simply ignored. .. _deform_balance: -The *vol/balance/p* keyword modifies the behavior of *volume* when two -dimensions are used to maintain a fixed volume. Instead of straining +The *vol/balance/p* keyword modifies the behavior of the *volume* style when +applied to two of the *x*, *y*, and *z* dimensions. Instead of straining the two dimensions in lockstep, the two dimensions are allowed to separately dilate or contract in a manner to maintain a constant volume while simultaneously trying to keep the pressure along each @@ -735,27 +263,22 @@ or pressure during thermodynamic output via the compute-ID. It also means that changing attributes of *thermo_temp* or *thermo_press* will have no effect on this fix. ----------- - -.. include:: accel_styles.rst - Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" This fix will restore the initial box settings from :doc:`binary restart files `, which allows the fix to be properly continue deformation, when using the start/stop options of the :doc:`run ` -command. None of the :doc:`fix_modify ` options are -relevant to this fix. No global or per-atom quantities are stored by -this fix for access by various :doc:`output commands `. +command. No global or per-atom quantities are stored by this fix for access +by various :doc:`output commands `. If any pressure controls are used, the :doc:`fix_modify ` *temp* -and *press* options are supported by this fix. You can use them to assign a -:doc:`compute ` you have defined to this fix which will be used -in its temperature and pressure calculations. If you do this, note -that the kinetic energy derived from the compute temperature should be -consistent with the virial term computed using all atoms for the -pressure. LAMMPS will warn you if you choose to compute temperature -on a subset of atoms. +and *press* options are supported by this fix, unklike in :doc:`fix deform `. +You can use them to assign a :doc:`compute ` you have defined to +this fix which will be used in its temperature and pressure calculations. +If you do this, note that the kinetic energy derived from the compute +temperature should be consistent with the virial term computed using all +atoms for the pressure. LAMMPS will warn you if you choose to compute +temperature on a subset of atoms. This fix can perform deformation over multiple runs, using the *start* and *stop* keywords of the :doc:`run ` command. See the @@ -775,7 +298,7 @@ xy) that is shrink-wrapped via the :doc:`boundary ` command. Related commands """""""""""""""" -:doc:`change_box ` +:doc:`fix deform `, :doc:`change_box ` Default """"""" diff --git a/src/EXTRA-FIX/fix_deform_pressure.cpp b/src/EXTRA-FIX/fix_deform_pressure.cpp index 26dd85b78bd..5eafebc9de3 100644 --- a/src/EXTRA-FIX/fix_deform_pressure.cpp +++ b/src/EXTRA-FIX/fix_deform_pressure.cpp @@ -794,8 +794,6 @@ void FixDeformPressure::write_restart(FILE *fp) if (comm->me == 0) { int size = 9 * sizeof(double) + 7 * sizeof(Set) + 7 * sizeof(SetExtra); fwrite(&size, sizeof(int), 1, fp); - fwrite(h_rate, sizeof(double), 6, fp); - fwrite(h_ratelo, sizeof(double), 3, fp); fwrite(set, sizeof(Set), 6, fp); fwrite(&set_box, sizeof(Set), 1, fp); fwrite(set_extra, sizeof(SetExtra), 7, fp); diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index 4b774b79d36..6a585d8b268 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -372,16 +372,6 @@ irregular(nullptr), set(nullptr) if (force_reneighbor) irregular = new Irregular(lmp); else irregular = nullptr; - - // initialize all rates to 0.0 in constructor instead of init so values persist - // across run statements and ghosts have correct velocities until the destructor - h_rate = domain->h_rate; - h_ratelo = domain->h_ratelo; - - for (int i = 0; i < 3; i++) - h_rate[i] = h_ratelo[i] = 0.0; - for (int i = 3; i < 6; i++) - h_rate[i] = 0.0; } /* ---------------------------------------------------------------------- */ @@ -597,13 +587,18 @@ void FixDeform::init() } // set domain->h_rate values for use by domain and other fixes/computes + // initialize all rates to 0.0 // cannot set here for TRATE,VOLUME,WIGGLE,VARIABLE since not constant + h_rate = domain->h_rate; + h_ratelo = domain->h_ratelo; + for (int i = 0; i < 3; i++) { + h_rate[i] = h_ratelo[i] = 0.0; if (set[i].style == FINAL || set[i].style == DELTA || set[i].style == SCALE || set[i].style == VEL || set[i].style == ERATE) { - double dlo_dt,dhi_dt; + double dlo_dt, dhi_dt; if (delt != 0.0) { dlo_dt = (set[i].lo_stop - set[i].lo_start) / delt; dhi_dt = (set[i].hi_stop - set[i].hi_start) / delt; @@ -614,6 +609,7 @@ void FixDeform::init() } for (int i = 3; i < 6; i++) { + h_rate[i] = 0.0; if (set[i].style == FINAL || set[i].style == DELTA || set[i].style == VEL || set[i].style == ERATE) { if (delt != 0.0) @@ -961,10 +957,8 @@ void FixDeform::update_domain() void FixDeform::write_restart(FILE *fp) { if (comm->me == 0) { - int size = 9 * sizeof(double) + 6 * sizeof(Set); + int size = 6 * sizeof(Set); fwrite(&size, sizeof(int), 1, fp); - fwrite(h_rate, sizeof(double), 6, fp); - fwrite(h_ratelo, sizeof(double), 3, fp); fwrite(set, sizeof(Set), 6, fp); } } @@ -975,15 +969,8 @@ void FixDeform::write_restart(FILE *fp) void FixDeform::restart(char *buf) { - int n = 0; - auto list = (double *) buf; - for (int i = 0; i < 6; i++) - h_rate[i] = list[n++]; - for (int i = 0; i < 3; i++) - h_ratelo[i] = list[n++]; - int samestyle = 1; - Set *set_restart = (Set *) &buf[n * sizeof(double)]; + 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; From cd4c97f8d8f8a7a111d0ab7de17185446ef60f40 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Wed, 21 Feb 2024 14:18:26 -0700 Subject: [PATCH 26/29] doc adjust and code comments --- doc/src/fix_deform.rst | 187 ++++++++++++++++---------- doc/src/fix_deform_pressure.rst | 149 ++++++++++---------- src/EXTRA-FIX/fix_deform_pressure.cpp | 6 +- src/fix_deform.cpp | 6 +- 4 files changed, 204 insertions(+), 144 deletions(-) diff --git a/doc/src/fix_deform.rst b/doc/src/fix_deform.rst index c0ea50ae412..e882c22bf64 100644 --- a/doc/src/fix_deform.rst +++ b/doc/src/fix_deform.rst @@ -4,6 +4,9 @@ fix deform command ================== +:doc:`fix deform/pressure ` command +================== + Accelerator Variants: *deform/kk* Syntax @@ -11,18 +14,18 @@ Syntax .. code-block:: LAMMPS - fix ID group-ID deform N parameter args ... keyword value ... + fix ID group-ID fixstyle N parameter style args ... keyword value ... * ID, group-ID are documented in :doc:`fix ` command -* deform = style name of this fix command +* fixstyle = *deform* or *deform/pressure* * N = perform box deformation every this many timesteps -* one or more parameter/arg pairs may be appended +* one or more parameter/style/args sequences of arguments may be appended .. parsed-literal:: parameter = *x* or *y* or *z* or *xy* or *xz* or *yz* *x*, *y*, *z* args = style value(s) - style = *final* or *delta* or *scale* or *vel* or *erate* or *trate* or *volume* or *wiggle* or *variable* + style = *final* or *delta* or *scale* or *vel* or *erate* or *trate* or *volume* or *wiggle* or *variable* or *pressure* or *pressure/mean* *final* values = lo hi lo hi = box boundaries at end of run (distance units) *delta* values = dlo dhi @@ -43,6 +46,13 @@ Syntax *variable* values = v_name1 v_name2 v_name1 = variable with name1 for box length change as function of time v_name2 = variable with name2 for change rate as function of time + *pressure* values = target gain (ONLY available in :doc:`fix deform/pressure ` command) + target = target pressure (pressure units) + gain = proportional gain constant (1/(time * pressure) or 1/time units) + *pressure/mean* values = target gain (ONLY available in :doc:`fix deform/pressure ` command) + target = target pressure (pressure units) + gain = proportional gain constant (1/(time * pressure) or 1/time units) + *xy*, *xz*, *yz* args = style value style = *final* or *delta* or *vel* or *erate* or *trate* or *wiggle* or *variable* *final* value = tilt @@ -62,9 +72,12 @@ Syntax *variable* values = v_name1 v_name2 v_name1 = variable with name1 for tilt change as function of time v_name2 = variable with name2 for change rate as function of time + *pressure* values = target gain (ONLY available in :doc:`fix deform/pressure ` command) + target = target pressure (pressure units) + gain = proportional gain constant (1/(time * pressure) or 1/time units) * zero or more keyword/value pairs may be appended -* keyword = *remap* or *flip* or *units* +* keyword = *remap* or *flip* or *units* or *couple* or *vol/balance/p* or *max/rate* or *normalize/pressure* .. parsed-literal:: @@ -77,6 +90,15 @@ Syntax *units* value = *lattice* or *box* lattice = distances are defined in lattice units box = distances are defined in simulation box units + *couple* value = *none* or *xyz* or *xy* or *yz* or *xz* (ONLY available in :doc:`fix deform/pressure ` command) + couple pressure values of various dimensions + *vol/balance/p* value = *yes* or *no* (ONLY available in :doc:`fix deform/pressure ` command) + Modifies the behavior of the *volume* option to try and balance pressures + *max/rate* value = *rate* (ONLY available in :doc:`fix deform/pressure ` command) + rate = maximum strain rate for pressure control + *normalize/pressure* value = *yes* or *no* (ONLY available in :doc:`fix deform/pressure ` command) + Modifies pressure controls such that the deviation in pressure is normalized by the target pressure + Examples """""""" @@ -88,6 +110,8 @@ Examples fix 1 all deform 1 xy erate 0.001 remap v fix 1 all deform 10 y delta -0.5 0.5 xz vel 1.0 + See examples for :doc:`fix deform/pressure ` on its doc page + Description """"""""""" @@ -95,31 +119,46 @@ Change the volume and/or shape of the simulation box during a dynamics run. Orthogonal simulation boxes have 3 adjustable parameters (x,y,z). Triclinic (non-orthogonal) simulation boxes have 6 adjustable parameters (x,y,z,xy,xz,yz). Any or all of them can be -adjusted independently and simultaneously by this command. For -additional pressure-based controls, see -:doc:`fix deform/pressure `. - -This fix can be used to perform non-equilibrium MD (NEMD) simulations -of a continuously strained system. See the :doc:`fix nvt/sllod ` and :doc:`compute temp/deform ` commands for more details. Note -that simulation of a continuously extended system (extensional flow) -can be modeled using the :ref:`UEF package ` and its :doc:`fix commands `. +adjusted independently and simultaneously. + +The fix deform command allows use of all the arguments listed above, +except those flagged as available ONLY for the :doc:`fix +deform/pressure ` command, which are +pressure-based controls. The fix deform/pressure command allows use +of all the arguments listed above. + +The rest of this doc page explains the options common to both +commands. The :doc:`fix deform/pressure ` doc +page explains the options available ONLY with the fix deform/pressure +command. Note that a simulation can define only a single deformation +command: fix deform or fix deform/pressure. + +Both these fixes can be used to perform non-equilibrium MD (NEMD) +simulations of a continuously strained system. See the :doc:`fix +nvt/sllod ` and :doc:`compute temp/deform +` commands for more details. Note that +simulation of a continuously extended system (extensional flow) can be +modeled using the :ref:`UEF package ` and its :doc:`fix +commands `. For the *x*, *y*, *z* parameters, the associated dimension cannot be shrink-wrapped. For the *xy*, *yz*, *xz* parameters, the associated -second dimension cannot be shrink-wrapped. Dimensions not varied by this -command can be periodic or non-periodic. Dimensions corresponding to -unspecified parameters can also be controlled by a :doc:`fix npt ` or :doc:`fix nph ` command. +second dimension cannot be shrink-wrapped. Dimensions not varied by +this command can be periodic or non-periodic. Dimensions +corresponding to unspecified parameters can also be controlled by a +:doc:`fix npt ` or :doc:`fix nph ` command. The size and shape of the simulation box at the beginning of the -simulation run were either specified by the -:doc:`create_box ` or :doc:`read_data ` or -:doc:`read_restart ` command used to setup the simulation -initially if it is the first run, or they are the values from the end -of the previous run. The :doc:`create_box `, :doc:`read data `, and :doc:`read_restart ` commands -specify whether the simulation box is orthogonal or non-orthogonal -(triclinic) and explain the meaning of the xy,xz,yz tilt factors. If -fix deform changes the xy,xz,yz tilt factors, then the simulation box -must be triclinic, even if its initial tilt factors are 0.0. +simulation run were either specified by the :doc:`create_box +` or :doc:`read_data ` or :doc:`read_restart +` command used to setup the simulation initially if it +is the first run, or they are the values from the end of the previous +run. The :doc:`create_box `, :doc:`read data +`, and :doc:`read_restart ` commands specify +whether the simulation box is orthogonal or non-orthogonal (triclinic) +and explain the meaning of the xy,xz,yz tilt factors. If fix deform +changes the xy,xz,yz tilt factors, then the simulation box must be +triclinic, even if its initial tilt factors are 0.0. As described below, the desired simulation box size and shape at the end of the run are determined by the parameters of the fix deform @@ -260,21 +299,22 @@ of the units keyword below. The *variable* style changes the specified box length dimension by evaluating a variable, which presumably is a function of time. The -variable with *name1* must be an :doc:`equal-style variable ` -and should calculate a change in box length in units of distance. -Note that this distance is in box units, not lattice units; see the -discussion of the *units* keyword below. The formula associated with -variable *name1* can reference the current timestep. Note that it -should return the "change" in box length, not the absolute box length. -This means it should evaluate to 0.0 when invoked on the initial -timestep of the run following the definition of fix deform. It should -evaluate to a value > 0.0 to dilate the box at future times, or a -value < 0.0 to compress the box. - -The variable *name2* must also be an :doc:`equal-style variable ` and should calculate the rate of box length -change, in units of distance/time, i.e. the time-derivative of the -*name1* variable. This quantity is used internally by LAMMPS to reset -atom velocities when they cross periodic boundaries. It is computed +variable with *name1* must be an :doc:`equal-style variable +` and should calculate a change in box length in units of +distance. Note that this distance is in box units, not lattice units; +see the discussion of the *units* keyword below. The formula +associated with variable *name1* can reference the current timestep. +Note that it should return the "change" in box length, not the +absolute box length. This means it should evaluate to 0.0 when +invoked on the initial timestep of the run following the definition of +fix deform. It should evaluate to a value > 0.0 to dilate the box at +future times, or a value < 0.0 to compress the box. + +The variable *name2* must also be an :doc:`equal-style variable +` and should calculate the rate of box length change, in +units of distance/time, i.e. the time-derivative of the *name1* +variable. This quantity is used internally by LAMMPS to reset atom +velocities when they cross periodic boundaries. It is computed internally for the other styles, but you must provide it when using an arbitrary variable. @@ -416,12 +456,13 @@ can reference the current timestep. Note that it should return the should evaluate to 0.0 when invoked on the initial timestep of the run following the definition of fix deform. -The variable *name2* must also be an :doc:`equal-style variable ` and should calculate the rate of tilt change, -in units of distance/time, i.e. the time-derivative of the *name1* -variable. This quantity is used internally by LAMMPS to reset atom -velocities when they cross periodic boundaries. It is computed -internally for the other styles, but you must provide it when using an -arbitrary variable. +The variable *name2* must also be an :doc:`equal-style variable +` and should calculate the rate of tilt change, in units of +distance/time, i.e. the time-derivative of the *name1* variable. This +quantity is used internally by LAMMPS to reset atom velocities when +they cross periodic boundaries. It is computed internally for the +other styles, but you must provide it when using an arbitrary +variable. Here is an example of using the *variable* style to perform the same box deformation as the *wiggle* style formula listed above, where we @@ -512,33 +553,40 @@ box without explicit remapping of their coordinates. .. note:: For non-equilibrium MD (NEMD) simulations using "remap v" it is - usually desirable that the fluid (or flowing material, e.g. granular - particles) stream with a velocity profile consistent with the - deforming box. As mentioned above, using a thermostat such as :doc:`fix nvt/sllod ` or :doc:`fix lavgevin ` - (with a bias provided by :doc:`compute temp/deform `), will typically accomplish - that. If you do not use a thermostat, then there is no driving force - pushing the atoms to flow in a manner consistent with the deforming - box. E.g. for a shearing system the box deformation velocity may vary + usually desirable that the fluid (or flowing material, + e.g. granular particles) stream with a velocity profile consistent + with the deforming box. As mentioned above, using a thermostat + such as :doc:`fix nvt/sllod ` or :doc:`fix lavgevin + ` (with a bias provided by :doc:`compute temp/deform + `), will typically accomplish that. If you do + not use a thermostat, then there is no driving force pushing the + atoms to flow in a manner consistent with the deforming box. + E.g. for a shearing system the box deformation velocity may vary from 0 at the bottom to 10 at the top of the box. But the stream - velocity profile of the atoms may vary from -5 at the bottom to +5 at - the top. You can monitor these effects using the :doc:`fix ave/chunk `, :doc:`compute temp/deform `, and :doc:`compute temp/profile ` commands. One way to induce - atoms to stream consistent with the box deformation is to give them an + velocity profile of the atoms may vary from -5 at the bottom to +5 + at the top. You can monitor these effects using the :doc:`fix + ave/chunk `, :doc:`compute temp/deform + `, and :doc:`compute temp/profile + ` commands. One way to induce atoms to + stream consistent with the box deformation is to give them an initial velocity profile, via the :doc:`velocity ramp ` - command, that matches the box deformation rate. This also typically - helps the system come to equilibrium more quickly, even if a - thermostat is used. + command, that matches the box deformation rate. This also + typically helps the system come to equilibrium more quickly, even + if a thermostat is used. .. note:: If a :doc:`fix rigid ` is defined for rigid bodies, and *remap* is set to *x*, then the center-of-mass coordinates of rigid - bodies will be remapped to the changing simulation box. This will be - done regardless of whether atoms in the rigid bodies are in the fix - deform group or not. The velocity of the centers of mass are not - remapped even if *remap* is set to *v*, since :doc:`fix nvt/sllod ` does not currently do anything special + bodies will be remapped to the changing simulation box. This will + be done regardless of whether atoms in the rigid bodies are in the + fix deform group or not. The velocity of the centers of mass are + not remapped even if *remap* is set to *v*, since :doc:`fix + nvt/sllod ` does not currently do anything special for rigid particles. If you wish to perform a NEMD simulation of rigid particles, you can either thermostat them independently or - include a background fluid and thermostat the fluid via :doc:`fix nvt/sllod `. + include a background fluid and thermostat the fluid via :doc:`fix + nvt/sllod `. The *flip* keyword allows the tilt factors for a triclinic box to exceed half the distance of the parallel box length, as discussed @@ -570,7 +618,8 @@ command if you want to include lattice spacings in a variable formula. Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" -This fix will restore the initial box settings from :doc:`binary restart files `, which allows the fix to be properly continue +This fix will restore the initial box settings from :doc:`binary +restart files `, which allows the fix to be properly continue deformation, when using the start/stop options of the :doc:`run ` command. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored by @@ -588,13 +637,15 @@ Restrictions You cannot apply x, y, or z deformations to a dimension that is shrink-wrapped via the :doc:`boundary ` command. -You cannot apply xy, yz, or xz deformations to a second dimension (y in -xy) that is shrink-wrapped via the :doc:`boundary ` command. +You cannot apply xy, yz, or xz deformations to a second dimension (y +in xy) that is shrink-wrapped via the :doc:`boundary ` +command. Related commands """""""""""""""" -:doc:`fix deform/pressure `, :doc:`change_box ` +:doc:`fix deform/pressure `, :doc:`change_box + ` Default """"""" diff --git a/doc/src/fix_deform_pressure.rst b/doc/src/fix_deform_pressure.rst index d45c10b3518..64bf2104469 100644 --- a/doc/src/fix_deform_pressure.rst +++ b/doc/src/fix_deform_pressure.rst @@ -8,12 +8,12 @@ Syntax .. parsed-literal:: - fix ID group-ID deform N parameter args ... keyword value ... + fix ID group-ID deform/pressure N parameter style args ... keyword value ... * ID, group-ID are documented in :doc:`fix ` command -* deform = style name of this fix command +* deform/pressure = style name of this fix command * N = perform box deformation every this many timesteps -* one or more parameter/arg pairs may be appended +* one or more parameter/arg sequences may be appended .. parsed-literal:: @@ -26,13 +26,15 @@ Syntax *pressure/mean* values = target gain target = target pressure (pressure units) gain = proportional gain constant (1/(time * pressure) or 1/time units) - All other styles operate identically to those in :doc:`fix deform ` + NOTE: All other styles are documented by the :doc:`fix deform ` command + *xy*, *xz*, *yz* args = style value style = *final* or *delta* or *vel* or *erate* or *trate* or *wiggle* or *variable* or *pressure* *pressure* values = target gain target = target pressure (pressure units) gain = proportional gain constant (1/(time * pressure) or 1/time units) - All other styles operate identically to those in :doc:`fix deform ` + NOTE: All other styles are documented by the :doc:`fix deform ` command + *box* = style value style = *volume* or *pressure* *volume* value = none = isotropically adjust system to preserve volume of system @@ -53,7 +55,7 @@ Syntax rate = maximum strain rate for pressure control *normalize/pressure* value = *yes* or *no* Modifies pressure controls such that the deviation in pressure is normalized by the target pressure - All other options operate identically to those in :doc:`fix deform ` + NOTE: All other keywords are documented by the :doc:`fix deform ` command Examples """""""" @@ -67,19 +69,20 @@ Examples Description """"""""""" -This fix is an extension of :doc:`fix deform `, inheriting -all of its features and adding new pressure-based controls to allow for -new deformation protocols. All details in :doc:`fix deform ` -apply to this fix unless otherwise noted. +This fix is an extension of the :doc:`fix deform ` +command, which allows all of its options to be used as well as new +pressure-based controls implemented by this command. ----------- +All arguments described on the :doc:`fix deform ` doc page +also apply to this fix unless otherwise noted below. The rest of this +doc page explains the arguments specific to this fix. Note that a +simulation can define only a single deformation command: fix deform or +fix deform/pressure. -For the *x*, *y*, and *z* parameters, this is the meaning of their -styles and values. +---------- -The *final*, *delta*, *scale*, *vel*, *erate*, *trate*, *volume*, -*wiggle*, and *variable* styles all behave identically to those in -:doc:`fix deform `. Additional styles are described below. +For the *x*, *y*, and *z* parameters, this is the meaning of the +styles and values provided by this fix. The *pressure* style adjusts a dimension's box length to control the corresponding component of the pressure tensor. This option attempts to @@ -127,13 +130,9 @@ along one dimension. ---------- -For the *xy*, *xz*, and *yz* parameters, this is the meaning of their -styles and values. Note that changing the tilt factors of a triclinic -box does not change its volume. - -The *final*, *delta*, *vel*, *erate*, *trate*, *wiggle*, and *variable* -styles all behave identically to those in :doc:`fix deform `. -Additional styles are described below. +For the *xy*, *xz*, and *yz* parameters, this is the meaning of the +styles and values provided by this fix. Note that changing the +tilt factors of a triclinic box does not change its volume. The *pressure* style adjusts a tilt factor to control the corresponding off-diagonal component of the pressure tensor. This option attempts to @@ -144,29 +143,32 @@ tilt factor T evolves according to the equation \frac{d T(t)}{dt} = L(t) k (P - P_t) -where :math:`k` is a proportional gain constant, :math:`P_t` is the target -pressure, :math:`P` is the current pressure, and :math:`L` is the perpendicular -box length. The target pressure accepts either a constant numeric value or a -LAMMPS :ref:`variable `. Notably, this variable can be a function -of time or other components of the pressure tensor. By default, :math:`k` -has units of 1/(time * pressure) although this will change if the -*normalize/pessure* option is set as :ref:`discussed below `. -There is no proven method to choosing an appropriate value of :math:`k` as it -will depend on thespecific details of a simulation and testing different -values is recommended. One can also apply a maximum limit to the magnitude -of the applied strain using the :ref:`max/rate ` option. +where :math:`k` is a proportional gain constant, :math:`P_t` is the +target pressure, :math:`P` is the current pressure, and :math:`L` is +the perpendicular box length. The target pressure accepts either a +constant numeric value or a LAMMPS :ref:`variable +`. Notably, this variable can be a function of time or other +components of the pressure tensor. By default, :math:`k` has units of +1/(time * pressure) although this will change if the +*normalize/pessure* option is set as :ref:`discussed below +`. There is no proven method to choosing an +appropriate value of :math:`k` as it will depend on the specific +details of a simulation and testing different values is +recommended. One can also apply a maximum limit to the magnitude of +the applied strain using the :ref:`max/rate ` option. ---------- -The *box* parameter provides an additonal control over the *x*, *y*, -and *z* box lengths by isotropically dilating or contracting the box to -either maintain a fixed mean pressure or volume. This isotropic scaling -is applied after the box is deformed by the above *x*, *y*, *z*, *xy*, -*xz*, and *yz* styles, acting as a second deformation step. This parameter -will change the overall strain rate in the *x*, *y*, or *z* dimensions. -This parameter can only be used in combination with the *x*, *y*, or *z* -commands: *vel*, *erate*, *trate*, *pressure*, or *wiggle*. This is the meaning -of its styles and values. +The *box* parameter provides an additional control over the *x*, *y*, +and *z* box lengths by isotropically dilating or contracting the box +to either maintain a fixed mean pressure or volume. This isotropic +scaling is applied after the box is deformed by the above *x*, *y*, +*z*, *xy*, *xz*, and *yz* styles, acting as a second deformation +step. This parameter will change the overall strain rate in the *x*, +*y*, or *z* dimensions. This parameter can only be used in +combination with the *x*, *y*, or *z* commands: *vel*, *erate*, +*trate*, *pressure*, or *wiggle*. This is the meaning of its styles +and values. The *volume* style isotropically scales box lengths to maintain a constant box volume in response to deformation from other parameters. This style @@ -186,9 +188,7 @@ dimensions (deforming the shape of the box), while maintaining a mean pressure. ---------- -The *flip*, *remap*, and *units* keywords all behave identically -to those in :doc:`fix deform `. Additional optional -keywords are described below. +The optional keywords provided by this fix are described below. .. _deform_normalize: @@ -240,44 +240,47 @@ dimension equal using a method described in :ref:`(Huang2014) `. ---------- If any pressure controls are used, this fix computes a temperature and -pressure each timestep. To do this, the fix creates its own computes of -style "temp" and "pressure", as if these commands had been issued: +pressure each timestep. To do this, the fix creates its own computes +of style "temp" and "pressure", as if these commands had been issued: .. code-block:: LAMMPS compute fix-ID_temp group-ID temp compute fix-ID_press group-ID pressure fix-ID_temp -See the :doc:`compute temp ` and :doc:`compute pressure ` commands for details. Note that the -IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID +See the :doc:`compute temp ` and :doc:`compute pressure +` commands for details. Note that the IDs of the +new computes are the fix-ID + underscore + "temp" or fix_ID + underscore + "press", and the group for the new computes is the same as the fix group. Note that these are NOT the computes used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo_temp* -and *thermo_press*. This means you can change the attributes of this -fix's temperature or pressure via the -:doc:`compute_modify ` command or print this temperature -or pressure during thermodynamic output via the -:doc:`thermo_style custom ` command using the appropriate -compute-ID. It also means that changing attributes of *thermo_temp* or -*thermo_press* will have no effect on this fix. +the :doc:`thermo_style ` command) with ID = +*thermo_temp* and *thermo_press*. This means you can change the +attributes of this fix's temperature or pressure via the +:doc:`compute_modify ` command or print this +temperature or pressure during thermodynamic output via the +:doc:`thermo_style custom ` command using the +appropriate compute-ID. It also means that changing attributes of +*thermo_temp* or *thermo_press* will have no effect on this fix. Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" -This fix will restore the initial box settings from :doc:`binary restart files `, which allows the fix to be properly continue +This fix will restore the initial box settings from :doc:`binary +restart files `, which allows the fix to be properly continue deformation, when using the start/stop options of the :doc:`run ` -command. No global or per-atom quantities are stored by this fix for access -by various :doc:`output commands `. - -If any pressure controls are used, the :doc:`fix_modify ` *temp* -and *press* options are supported by this fix, unklike in :doc:`fix deform `. -You can use them to assign a :doc:`compute ` you have defined to -this fix which will be used in its temperature and pressure calculations. -If you do this, note that the kinetic energy derived from the compute -temperature should be consistent with the virial term computed using all -atoms for the pressure. LAMMPS will warn you if you choose to compute +command. No global or per-atom quantities are stored by this fix for +access by various :doc:`output commands `. + +If any pressure controls are used, the :doc:`fix_modify ` +*temp* and *press* options are supported by this fix, unlike in +:doc:`fix deform `. You can use them to assign a +:doc:`compute ` you have defined to this fix which will be +used in its temperature and pressure calculations. If you do this, +note that the kinetic energy derived from the compute temperature +should be consistent with the virial term computed using all atoms for +the pressure. LAMMPS will warn you if you choose to compute temperature on a subset of atoms. This fix can perform deformation over multiple runs, using the *start* @@ -292,8 +295,9 @@ Restrictions You cannot apply x, y, or z deformations to a dimension that is shrink-wrapped via the :doc:`boundary ` command. -You cannot apply xy, yz, or xz deformations to a second dimension (y in -xy) that is shrink-wrapped via the :doc:`boundary ` command. +You cannot apply xy, yz, or xz deformations to a second dimension (y +in xy) that is shrink-wrapped via the :doc:`boundary ` +command. Related commands """""""""""""""" @@ -303,8 +307,7 @@ Related commands Default """"""" -The option defaults are remap = x, flip = yes, units = lattice, and -normalize/pressure = no. +The option defaults are normalize/pressure = no. ---------- diff --git a/src/EXTRA-FIX/fix_deform_pressure.cpp b/src/EXTRA-FIX/fix_deform_pressure.cpp index 5eafebc9de3..d8374bcc75c 100644 --- a/src/EXTRA-FIX/fix_deform_pressure.cpp +++ b/src/EXTRA-FIX/fix_deform_pressure.cpp @@ -55,7 +55,7 @@ FixDeformPressure::FixDeformPressure(LAMMPS *lmp, int narg, char **arg) : memset(set_extra, 0, 7 * sizeof(SetExtra)); memset(&set_box, 0, sizeof(Set)); - // parse child-specific arguments + // parse only parameter/style arguments specific to this child class int index, iarg; int i = 0; @@ -115,6 +115,7 @@ FixDeformPressure::FixDeformPressure(LAMMPS *lmp, int narg, char **arg) : set_extra[index].pgain = utils::numeric(FLERR, arg[iarg + 3], false, lmp); i += 4; } 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; @@ -850,7 +851,6 @@ void FixDeformPressure::restart(char *buf) } } - /* ---------------------------------------------------------------------- */ void FixDeformPressure::options(int i, int narg, char **arg) @@ -860,6 +860,8 @@ void FixDeformPressure::options(int i, int narg, char **arg) vol_balance_flag = 0; normalize_pressure_flag = 0; + // parse only options not handled by parent class + int iarg, nskip; while (i < leftover_iarg.size()) { iarg = leftover_iarg[i]; diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index 6a585d8b268..9ee72594826 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -72,7 +72,8 @@ irregular(nullptr), set(nullptr) set = new Set[6]; memset(set, 0, 6 * sizeof(Set)); - // parse arguments + // parse all parameter/style arguments for this parent and also child classes + // for child classes, simply store them in leftover_iarg and skip over them triclinic = domain->triclinic; @@ -1009,6 +1010,9 @@ void FixDeform::options(int narg, char **arg) {"vol/balance/p", 2}}); } + // parse all optional arguments for this parent and also child classes + // for child classes, simply store them in leftover_iarg and skip over them + int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg], "remap") == 0) { From 11675587df2666d7309a39fcbdcd82428ae8090a Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Wed, 21 Feb 2024 14:28:53 -0700 Subject: [PATCH 27/29] tweak to underlining --- doc/src/fix_deform.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/src/fix_deform.rst b/doc/src/fix_deform.rst index e882c22bf64..7f81bcf68d8 100644 --- a/doc/src/fix_deform.rst +++ b/doc/src/fix_deform.rst @@ -5,7 +5,7 @@ fix deform command ================== :doc:`fix deform/pressure ` command -================== +======================================================== Accelerator Variants: *deform/kk* @@ -110,7 +110,7 @@ Examples fix 1 all deform 1 xy erate 0.001 remap v fix 1 all deform 10 y delta -0.5 0.5 xz vel 1.0 - See examples for :doc:`fix deform/pressure ` on its doc page +See examples for :doc:`fix deform/pressure ` on its doc page Description """"""""""" From 06b69f2d401aecf17a26760e0480fa9141a74696 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 21 Feb 2024 17:35:28 -0500 Subject: [PATCH 28/29] whitespace --- doc/src/fix_deform.rst | 2 +- doc/src/fix_deform_pressure.rst | 6 ++++-- src/EXTRA-FIX/fix_deform_pressure.cpp | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/doc/src/fix_deform.rst b/doc/src/fix_deform.rst index 7f81bcf68d8..6d415fd0a9c 100644 --- a/doc/src/fix_deform.rst +++ b/doc/src/fix_deform.rst @@ -111,7 +111,7 @@ Examples fix 1 all deform 10 y delta -0.5 0.5 xz vel 1.0 See examples for :doc:`fix deform/pressure ` on its doc page - + Description """"""""""" diff --git a/doc/src/fix_deform_pressure.rst b/doc/src/fix_deform_pressure.rst index 64bf2104469..15dcc9f7a43 100644 --- a/doc/src/fix_deform_pressure.rst +++ b/doc/src/fix_deform_pressure.rst @@ -27,14 +27,14 @@ Syntax target = target pressure (pressure units) gain = proportional gain constant (1/(time * pressure) or 1/time units) NOTE: All other styles are documented by the :doc:`fix deform ` command - + *xy*, *xz*, *yz* args = style value style = *final* or *delta* or *vel* or *erate* or *trate* or *wiggle* or *variable* or *pressure* *pressure* values = target gain target = target pressure (pressure units) gain = proportional gain constant (1/(time * pressure) or 1/time units) NOTE: All other styles are documented by the :doc:`fix deform ` command - + *box* = style value style = *volume* or *pressure* *volume* value = none = isotropically adjust system to preserve volume of system @@ -69,6 +69,8 @@ Examples Description """"""""""" +.. versionadded:: TBD + This fix is an extension of the :doc:`fix deform ` command, which allows all of its options to be used as well as new pressure-based controls implemented by this command. diff --git a/src/EXTRA-FIX/fix_deform_pressure.cpp b/src/EXTRA-FIX/fix_deform_pressure.cpp index d8374bcc75c..7f15870ef12 100644 --- a/src/EXTRA-FIX/fix_deform_pressure.cpp +++ b/src/EXTRA-FIX/fix_deform_pressure.cpp @@ -115,7 +115,7 @@ FixDeformPressure::FixDeformPressure(LAMMPS *lmp, int narg, char **arg) : set_extra[index].pgain = utils::numeric(FLERR, arg[iarg + 3], false, lmp); i += 4; } 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; @@ -861,7 +861,7 @@ void FixDeformPressure::options(int i, int narg, char **arg) normalize_pressure_flag = 0; // parse only options not handled by parent class - + int iarg, nskip; while (i < leftover_iarg.size()) { iarg = leftover_iarg[i]; From 71385add8bfb7e79297f3ef1d511fde3924af541 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 21 Feb 2024 17:50:55 -0500 Subject: [PATCH 29/29] integrate into documentation system. correct links/references. --- doc/src/Commands_fix.rst | 1 + doc/src/fix.rst | 1 + doc/src/fix_deform.rst | 8 ++++---- doc/src/fix_deform_pressure.rst | 10 ++++------ 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/src/Commands_fix.rst b/doc/src/Commands_fix.rst index e89e302673a..ea50e68cdd2 100644 --- a/doc/src/Commands_fix.rst +++ b/doc/src/Commands_fix.rst @@ -61,6 +61,7 @@ OPT. * :doc:`controller ` * :doc:`damping/cundall ` * :doc:`deform (k) ` + * :doc:`deform/pressure ` * :doc:`deposit ` * :doc:`dpd/energy (k) ` * :doc:`drag ` diff --git a/doc/src/fix.rst b/doc/src/fix.rst index 69a72124875..d03cab46876 100644 --- a/doc/src/fix.rst +++ b/doc/src/fix.rst @@ -226,6 +226,7 @@ accelerated styles exist. * :doc:`controller ` - apply control loop feedback mechanism * :doc:`damping/cundall ` - Cundall non-viscous damping for granular simulations * :doc:`deform ` - change the simulation box size/shape +* :doc:`deform/pressure ` - change the simulation box size/shape with additional loading conditions * :doc:`deposit ` - add new atoms above a surface * :doc:`dpd/energy ` - constant energy dissipative particle dynamics * :doc:`drag ` - drag atoms towards a defined coordinate diff --git a/doc/src/fix_deform.rst b/doc/src/fix_deform.rst index 6d415fd0a9c..9146b987c86 100644 --- a/doc/src/fix_deform.rst +++ b/doc/src/fix_deform.rst @@ -14,10 +14,10 @@ Syntax .. code-block:: LAMMPS - fix ID group-ID fixstyle N parameter style args ... keyword value ... + fix ID group-ID fix_style N parameter style args ... keyword value ... * ID, group-ID are documented in :doc:`fix ` command -* fixstyle = *deform* or *deform/pressure* +* fix_style = *deform* or *deform/pressure* * N = perform box deformation every this many timesteps * one or more parameter/style/args sequences of arguments may be appended @@ -644,8 +644,8 @@ command. Related commands """""""""""""""" -:doc:`fix deform/pressure `, :doc:`change_box - ` +:doc:`fix deform/pressure `, +:doc:`change_box ` Default """"""" diff --git a/doc/src/fix_deform_pressure.rst b/doc/src/fix_deform_pressure.rst index 15dcc9f7a43..f85ad37238b 100644 --- a/doc/src/fix_deform_pressure.rst +++ b/doc/src/fix_deform_pressure.rst @@ -109,7 +109,7 @@ specific details of a simulation. Testing different values is recommended. By default, there is no limit on the resulting strain rate in any dimension. A maximum limit can be applied using the :ref:`max/rate ` -option. Akin to :ref:`fix nh `, pressures in different dimensions +option. Akin to :doc:`fix nh `, pressures in different dimensions can be coupled using the :ref:`couple ` option. This means the instantaneous pressure along coupled dimensions are averaged and the box strains identically along the coupled dimensions. @@ -313,9 +313,7 @@ The option defaults are normalize/pressure = no. ---------- -.. _Li2014b: +.. _Huang2014: -**(Huang2014)** X. Huang, -"Exploring critical-state behavior using DEM", -Doctoral dissertation, Imperial College. -(2014). https://doi.org/10.25560/25316 +**(Huang2014)** X. Huang, "Exploring critical-state behavior using DEM", +Doctoral dissertation, Imperial College. (2014). https://doi.org/10.25560/25316