// clang-format off /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator https://www.lammps.org/, Sandia National Laboratories LAMMPS development team: developers@lammps.org Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: Laurence Fried (LLNL), Evan Reed (LLNL, Stanford) implementation of the Multi-Scale Shock Method see Reed, Fried, Joannopoulos, Phys Rev Lett, 90, 235503 (2003) ------------------------------------------------------------------------- */ #include "fix_msst.h" #include "atom.h" #include "comm.h" #include "compute.h" #include "domain.h" #include "error.h" #include "fix_external.h" #include "force.h" #include "kspace.h" #include "memory.h" #include "modify.h" #include "update.h" #include #include using namespace LAMMPS_NS; using namespace FixConst; /* ---------------------------------------------------------------------- */ FixMSST::FixMSST(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), old_velocity(nullptr), rfix(nullptr), id_temp(nullptr), id_press(nullptr), id_pe(nullptr), temperature(nullptr), pressure(nullptr), pe(nullptr) { if (narg < 4) error->all(FLERR,"Illegal fix msst command"); restart_global = 1; time_integrate = 1; scalar_flag = 1; vector_flag = 1; size_vector = 4; global_freq = 1; extscalar = 1; extvector = 0; ecouple_flag = 1; // set defaults velocity = 0.0; dilation[0] = dilation[1] = dilation[2] = 1.0; p0 = 0.0; v0 = 1.0; e0 = 0.0; TS_int = 0; T0S0 = 0.0; S_elec = 0.0; S_elec_1 = 0.0; S_elec_2 = 0.0; qmass = 1.0e1; mu = 0.0; direction = 2; p0_set = 0; v0_set = 0; e0_set = 0; tscale = 0.01; dftb = 0; beta = 0.0; if (strcmp(arg[3],"x") == 0) { direction = 0; box_change |= BOX_CHANGE_X; } else if (strcmp(arg[3],"y") == 0) { direction = 1; box_change |= BOX_CHANGE_Y; } else if (strcmp(arg[3],"z") == 0) { direction = 2; box_change |= BOX_CHANGE_Z; } else error->all(FLERR,"Illegal fix msst command"); velocity = utils::numeric(FLERR,arg[4],false,lmp); if (velocity < 0) error->all(FLERR,"Illegal fix msst command"); // optional args int iarg = 5; while (iarg < narg) { if (strcmp(arg[iarg],"q") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix msst command"); qmass = utils::numeric(FLERR,arg[iarg+1],false,lmp); iarg += 2; } else if (strcmp(arg[iarg],"mu") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix msst command"); mu = utils::numeric(FLERR,arg[iarg+1],false,lmp); iarg += 2; } else if (strcmp(arg[iarg],"p0") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix msst command"); p0 = utils::numeric(FLERR,arg[iarg+1],false,lmp); p0_set = 1; iarg += 2; } else if (strcmp(arg[iarg],"v0") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix msst command"); v0 = utils::numeric(FLERR,arg[iarg+1],false,lmp); v0_set = 1; iarg += 2; } else if (strcmp(arg[iarg],"e0") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix msst command"); e0 = utils::numeric(FLERR,arg[iarg+1],false,lmp); e0_set = 1; iarg += 2; } else if (strcmp(arg[iarg],"tscale") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix msst command"); tscale = utils::numeric(FLERR,arg[iarg+1],false,lmp); if (tscale < 0.0 || tscale > 1.0) error->all(FLERR,"Fix msst tscale must satisfy 0 <= tscale < 1"); iarg += 2; } else if (strcmp(arg[iarg],"dftb") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix msst command"); dftb = utils::logical(FLERR,arg[iarg+1],false,lmp); iarg += 2; } else if (strcmp(arg[iarg],"beta") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix msst command"); beta = utils::numeric(FLERR,arg[iarg+1],false,lmp); if (beta < 0.0 || beta > 1.0) error->all(FLERR,"Illegal fix msst command"); iarg += 2; } else error->all(FLERR,"Illegal fix msst command"); } // output MSST info if (comm->me == 0) { std::string mesg = "MSST parameters:\n"; if (direction == 0) mesg += " Shock in x direction\n"; else if (direction == 1) mesg += " Shock in y direction\n"; else if (direction == 2) mesg += " Shock in z direction\n"; mesg += fmt::format(" Cell mass-like parameter qmass " "(units of mass^2/length^4) = {:.8g}\n", qmass); mesg += fmt::format(" Shock velocity = {:.8g}\n", velocity); mesg += fmt::format(" Artificial viscosity (units of mass/length/time) = {:.8g}\n", mu); if (p0_set) mesg += fmt::format(" Initial pressure specified to be {:.8g}\n", p0); else mesg += " Initial pressure calculated on first step\n"; if (v0_set) mesg += fmt::format(" Initial volume specified to be {:.8g}\n", v0); else mesg += " Initial volume calculated on first step\n"; if (e0_set) mesg += fmt::format(" Initial energy specified to be {:.8g}\n", e0); else mesg += " Initial energy calculated on first step\n"; utils::logmesg(lmp,mesg); } // check for periodicity in controlled dimensions if (domain->nonperiodic) error->all(FLERR,"Fix msst requires a periodic box"); // create a new temperature compute // id = fix-ID + "MSST_temp" // compute group = all since pressure is always global (group all) // and thus its KE/temperature contribution should use group all std::string fixcmd = std::string(id) + "MSST_temp"; id_temp = utils::strdup(fixcmd); modify->add_compute(fixcmd + " all temp"); tflag = 1; // create a new pressure compute // id = fix-ID + "MSST_press", compute group = all // pass id_temp as 4th arg to pressure constructor fixcmd = std::string(id) + "MSST_press"; id_press = utils::strdup(fixcmd); modify->add_compute(fixcmd + " all pressure " + std::string(id_temp)); pflag = 1; // create a new potential energy compute // id = fix-ID + "MSST_pe", compute group = all fixcmd = std::string(id) + "MSST_pe"; id_pe = utils::strdup(fixcmd); modify->add_compute(fixcmd + " all pe"); peflag = 1; // initialize the time derivative of the volume omega[0] = omega[1] = omega[2] = 0.0; nrigid = 0; rfix = nullptr; maxold = -1; old_velocity = nullptr; } /* ---------------------------------------------------------------------- */ FixMSST::~FixMSST() { delete [] rfix; // delete temperature and pressure if fix created them if (tflag) modify->delete_compute(id_temp); if (pflag) modify->delete_compute(id_press); if (peflag) modify->delete_compute(id_pe); delete [] id_temp; delete [] id_press; delete [] id_pe; memory->destroy(old_velocity); } /* ---------------------------------------------------------------------- */ int FixMSST::setmask() { int mask = 0; mask |= INITIAL_INTEGRATE; mask |= FINAL_INTEGRATE; return mask; } /* ---------------------------------------------------------------------- */ void FixMSST::init() { if (atom->mass == nullptr) error->all(FLERR,"Cannot use fix msst without per-type mass defined"); // set compute ptrs int itemp = modify->find_compute(id_temp); int ipress = modify->find_compute(id_press); int ipe = modify->find_compute(id_pe); if (itemp < 0 || ipress < 0|| ipe < 0) error->all(FLERR,"Could not find fix msst compute ID"); if (modify->compute[itemp]->tempflag == 0) error->all(FLERR,"Fix msst compute ID does not compute temperature"); if (modify->compute[ipress]->pressflag == 0) error->all(FLERR,"Fix msst compute ID does not compute pressure"); if (modify->compute[ipe]->peflag == 0) error->all(FLERR,"Fix msst compute ID does not compute potential energy"); temperature = modify->compute[itemp]; pressure = modify->compute[ipress]; pe = modify->compute[ipe]; dtv = update->dt; dtf = 0.5 * update->dt * force->ftm2v; dthalf = 0.5 * update->dt; boltz = force->boltz; nktv2p = force->nktv2p; mvv2e = force->mvv2e; double mass = 0.0; for (int i = 0; i < atom->nlocal; i++) mass += atom->mass[atom->type[i]]; MPI_Allreduce(&mass,&total_mass,1,MPI_DOUBLE,MPI_SUM,world); if (force->kspace) kspace_flag = 1; else kspace_flag = 0; // detect if any fix rigid exist so rigid bodies move when box is dilated // rfix[] = indices to each fix rigid delete [] rfix; nrigid = 0; rfix = nullptr; for (int i = 0; i < modify->nfix; i++) if (utils::strmatch(modify->fix[i]->style,"^rigid") || utils::strmatch(modify->fix[i]->style,"^poems$")) nrigid++; if (nrigid) { rfix = new int[nrigid]; nrigid = 0; for (int i = 0; i < modify->nfix; i++) if (utils::strmatch(modify->fix[i]->style,"^rigid") || utils::strmatch(modify->fix[i]->style,"^poems$")) rfix[nrigid++] = i; } // find fix external being used to drive LAMMPS from DFTB+ if (dftb) { for (int i = 0; i < modify->nfix; i++) if (utils::strmatch(modify->fix[i]->style,"^external$")) fix_external = dynamic_cast(modify->fix[i]); if (fix_external == nullptr) error->all(FLERR,"Fix msst dftb cannot be used w/out fix external"); } } /* ---------------------------------------------------------------------- compute T,P before integrator starts ------------------------------------------------------------------------- */ void FixMSST::setup(int /*vflag*/) { lagrangian_position = 0.0; temperature->compute_vector(); pressure->compute_vector(); couple(); velocity_sum = compute_vsum(); if (v0_set == 0) { v0 = compute_vol(); v0_set = 1; if (comm->me == 0) utils::logmesg(lmp,"Fix MSST v0 = {:.8g}\n", v0); } if (p0_set == 0) { p0 = p_current[direction]; p0_set = 1; if (comm->me == 0) utils::logmesg(lmp,"Fix MSST p0 = {:.8g}\n", p0); } if (e0_set == 0) { e0 = compute_etotal(); e0_set = 1; if (comm->me == 0) utils::logmesg(lmp,"Fix MSST e0 = {:.8g}\n", e0); } temperature->compute_vector(); double *ke_tensor = temperature->vector; double ke_temp = ke_tensor[0]+ke_tensor[1]+ke_tensor[2]; if (ke_temp > 0.0 && tscale > 0.0) { // transfer energy from atom velocities to cell volume motion // to bias initial compression double **v = atom->v; int *mask = atom->mask; double sqrt_initial_temperature_scaling = sqrt(1.0-tscale); double fac1 = tscale*total_mass/qmass*ke_temp/force->mvv2e; omega[direction]=-1*sqrt(fac1); double fac2 = omega[direction]/v0; if ( comm->me == 0 && tscale != 1.0) utils::logmesg(lmp,"Fix MSST initial strain rate of {:.8g} " "established by reducing temperature by factor " "of {:.8g}\n",fac2,tscale); for (int i = 0; i < atom->nlocal; i++) { if (mask[i] & groupbit) { for (int k = 0; k < 3; k++) { v[i][k]*=sqrt_initial_temperature_scaling; } } } } // trigger virial computation on next timestep pe->addstep(update->ntimestep+1); pressure->addstep(update->ntimestep+1); } /* ---------------------------------------------------------------------- 1st half of Verlet update ------------------------------------------------------------------------- */ void FixMSST::initial_integrate(int /*vflag*/) { int i,k; double p_msst; // MSST driving pressure double vol; int nlocal = atom->nlocal; int *mask = atom->mask; double **v = atom->v; double **f = atom->f; double *mass = atom->mass; int *type = atom->type; double **x = atom->x; int sd = direction; // realloc old_velocity if necessary if (nlocal > maxold) { memory->destroy(old_velocity); maxold = atom->nmax; memory->create(old_velocity,maxold,3,"msst:old_velocity"); } // for DFTB, extract TS_dftb from fix external // must convert energy to mv^2 units if (dftb) { const double TS_dftb = fix_external->compute_vector(0); const double TS = force->ftm2v*TS_dftb; // update S_elec terms and compute TS_dot via finite differences S_elec_2 = S_elec_1; S_elec_1 = S_elec; const double Temp = temperature->compute_scalar(); S_elec = TS/Temp; TS_dot = Temp*(3.0*S_elec-4.0*S_elec_1+S_elec_2)/(2.0*update->dt); TS_int += (update->dt*TS_dot); if (update->ntimestep == 1) T0S0 = TS; } // compute new pressure and volume temperature->compute_vector(); pressure->compute_vector(); couple(); vol = compute_vol(); // compute etot + extra terms for conserved quantity double e_scale = compute_etotal() + compute_scalar(); // propagate the time derivative of // the volume 1/2 step at fixed vol, r, rdot p_msst = nktv2p * mvv2e * velocity * velocity * total_mass * ( v0 - vol)/( v0 * v0); double A = total_mass * ( p_current[sd] - p0 - p_msst ) / (qmass * nktv2p * mvv2e); double B = total_mass * mu / ( qmass * vol ); // prevent blow-up of the volume if (vol > v0 && A > 0.0) A = -A; // use Taylor expansion to avoid singularity at B = 0 if (B * dthalf > 1.0e-06) { omega[sd] = ( omega[sd] + A * ( exp(B * dthalf) - 1.0 ) / B ) * exp(-B * dthalf); } else { omega[sd] = omega[sd] + (A - B * omega[sd]) * dthalf + 0.5 * (B * B * omega[sd] - A * B ) * dthalf * dthalf; } // propagate velocity sum 1/2 step by // temporarily propagating the velocities velocity_sum = compute_vsum(); if (dftb) { for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { for (k = 0; k < 3; k++) { const double C = f[i][k] * force->ftm2v / mass[type[i]]; const double TS_term = TS_dot/(mass[type[i]]*velocity_sum); const double escale_term = force->ftm2v*beta*(e0-e_scale) / (mass[type[i]]*velocity_sum); double D = mu * omega[sd] * omega[sd] / (velocity_sum * mass[type[i]] * vol ); D += escale_term - TS_term; old_velocity[i][k] = v[i][k]; if (k == direction) D -= 2.0 * omega[sd] / vol; if (fabs(dthalf * D) > 1.0e-06) { const double expd = exp(D * dthalf); v[i][k] = expd * ( C + D * v[i][k] - C / expd ) / D; } else { v[i][k] = v[i][k] + ( C + D * v[i][k] ) * dthalf + 0.5 * (D * D * v[i][k] + C * D ) * dthalf * dthalf; } } } } } else { for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { for (k = 0; k < 3; k++) { const double C = f[i][k] * force->ftm2v / mass[type[i]]; double D = mu * omega[sd] * omega[sd] / (velocity_sum * mass[type[i]] * vol ); old_velocity[i][k] = v[i][k]; if (k == direction) { D -= 2.0 * omega[sd] / vol; } if (fabs(dthalf * D) > 1.0e-06) { const double expd = exp(D * dthalf); v[i][k] = expd * ( C + D * v[i][k] - C / expd ) / D; } else { v[i][k] = v[i][k] + ( C + D * v[i][k] ) * dthalf + 0.5 * (D * D * v[i][k] + C * D ) * dthalf * dthalf; } } } } } velocity_sum = compute_vsum(); // reset the velocities for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { v[i][0] = old_velocity[i][0]; v[i][1] = old_velocity[i][1]; v[i][2] = old_velocity[i][2]; } } // propagate velocities 1/2 step using the new velocity sum if (dftb) { for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { for (k = 0; k < 3; k++) { const double C = f[i][k] * force->ftm2v / mass[type[i]]; const double TS_term = TS_dot/(mass[type[i]]*velocity_sum); const double escale_term = force->ftm2v*beta*(e0-e_scale) / (mass[type[i]]*velocity_sum); double D = mu * omega[sd] * omega[sd] / (velocity_sum * mass[type[i]] * vol ); D += escale_term - TS_term; if (k == direction) D -= 2.0 * omega[sd] / vol; if (fabs(dthalf * D) > 1.0e-06) { const double expd = exp(D * dthalf); v[i][k] = expd * ( C + D * v[i][k] - C / expd ) / D; } else { v[i][k] = v[i][k] + ( C + D * v[i][k] ) * dthalf + 0.5 * (D * D * v[i][k] + C * D ) * dthalf * dthalf; } } } } } else { for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { for (k = 0; k < 3; k++) { const double C = f[i][k] * force->ftm2v / mass[type[i]]; double D = mu * omega[sd] * omega[sd] / (velocity_sum * mass[type[i]] * vol ); if (k == direction) { D -= 2.0 * omega[sd] / vol; } if (fabs(dthalf * D) > 1.0e-06) { const double expd = exp(D * dthalf); v[i][k] = expd * ( C + D * v[i][k] - C / expd ) / D; } else { v[i][k] = v[i][k] + ( C + D * v[i][k] ) * dthalf + 0.5 * (D * D * v[i][k] + C * D ) * dthalf * dthalf; } } } } } // propagate the volume 1/2 step double vol1 = vol + omega[sd] * dthalf; // rescale positions and change box size dilation[sd] = vol1/vol; remap(0); // propagate particle positions 1 time step for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { x[i][0] += dtv * v[i][0]; x[i][1] += dtv * v[i][1]; x[i][2] += dtv * v[i][2]; } } // propagate the volume 1/2 step double vol2 = vol1 + omega[sd] * dthalf; // rescale positions and change box size dilation[sd] = vol2/vol1; remap(0); if (kspace_flag) force->kspace->setup(); } /* ---------------------------------------------------------------------- 2nd half of Verlet update ------------------------------------------------------------------------- */ void FixMSST::final_integrate() { int i; double p_msst; // MSST driving pressure // v update only for atoms in MSST group double **v = atom->v; double **f = atom->f; double *mass = atom->mass; int *type = atom->type; int *mask = atom->mask; int nlocal = atom->nlocal; double vol = compute_vol(); int sd = direction; // compute etot + extra terms for conserved quantity double e_scale = compute_etotal() + compute_scalar(); // for DFTB, extract TS_dftb from fix external // must convert energy to mv^2 units if (dftb) { const double TS_dftb = fix_external->compute_vector(0); const double TS = force->ftm2v*TS_dftb; S_elec_2 = S_elec_1; S_elec_1 = S_elec; const double Temp = temperature->compute_scalar(); // update S_elec terms and compute TS_dot via finite differences S_elec = TS/Temp; TS_dot = Temp*(3.0*S_elec-4.0*S_elec_1+S_elec_2)/(2.0*update->dt); TS_int += (update->dt*TS_dot); if (update->ntimestep == 1) T0S0 = TS; } // propagate particle velocities 1/2 step if (dftb) { for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { for (int k = 0; k < 3; k++) { const double C = f[i][k] * force->ftm2v / mass[type[i]]; const double TS_term = TS_dot/(mass[type[i]]*velocity_sum); const double escale_term = force->ftm2v*beta*(e0-e_scale) / (mass[type[i]]*velocity_sum); double D = mu * omega[sd] * omega[sd] / (velocity_sum * mass[type[i]] * vol ); D += escale_term - TS_term; if (k == direction) D -= 2.0 * omega[sd] / vol; if (fabs(dthalf * D) > 1.0e-06) { const double expd = exp(D * dthalf); v[i][k] = expd * ( C + D * v[i][k] - C / expd ) / D; } else { v[i][k] = v[i][k] + ( C + D * v[i][k] ) * dthalf + 0.5 * (D * D * v[i][k] + C * D ) * dthalf * dthalf; } } } } } else { for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { for (int k = 0; k < 3; k++) { const double C = f[i][k] * force->ftm2v / mass[type[i]]; double D = mu * omega[sd] * omega[sd] / (velocity_sum * mass[type[i]] * vol ); if (k == direction) { D -= 2.0 * omega[sd] / vol; } if (fabs(dthalf * D) > 1.0e-06) { const double expd = exp(D * dthalf); v[i][k] = expd * ( C + D * v[i][k] - C / expd ) / D; } else { v[i][k] = v[i][k] + ( C + D * v[i][k] ) * dthalf + 0.5 * (D * D * v[i][k] + C * D ) * dthalf * dthalf; } } } } } // compute new pressure and volume temperature->compute_vector(); pressure->compute_vector(); couple(); velocity_sum = compute_vsum(); vol = compute_vol(); // propagate the time derivative of the volume 1/2 step at fixed V, r, rdot p_msst = nktv2p * mvv2e * velocity * velocity * total_mass * ( v0 - vol )/( v0 * v0 ); double A = total_mass * ( p_current[sd] - p0 - p_msst ) / ( qmass * nktv2p * mvv2e ); const double B = total_mass * mu / ( qmass * vol ); // prevent blow-up of the volume if (vol > v0 && A > 0.0) A = -A; // use taylor expansion to avoid singularity at B == 0. if (B * dthalf > 1.0e-06) { omega[sd] = ( omega[sd] + A * ( exp(B * dthalf) - 1.0 ) / B ) * exp(-B * dthalf); } else { omega[sd] = omega[sd] + (A - B * omega[sd]) * dthalf + 0.5 * (B * B * omega[sd] - A * B ) * dthalf * dthalf; } // calculate Lagrangian position of computational cell lagrangian_position -= velocity*vol/v0*update->dt; // trigger energy and virial computation on next timestep pe->addstep(update->ntimestep+1); pressure->addstep(update->ntimestep+1); } /* ---------------------------------------------------------------------- */ void FixMSST::couple() { double *tensor = pressure->vector; p_current[0] = tensor[0]; p_current[1] = tensor[1]; p_current[2] = tensor[2]; } /* ---------------------------------------------------------------------- change box size remap owned or owned+ghost atoms depending on flag if rigid bodies exist, scale rigid body centers-of-mass ------------------------------------------------------------------------- */ void FixMSST::remap(int flag) { int i,n; double oldlo,oldhi,ctr; double **v = atom->v; if (flag) n = atom->nlocal + atom->nghost; else n = atom->nlocal; // convert pertinent atoms and rigid bodies to lamda coords domain->x2lamda(n); if (nrigid) for (i = 0; i < nrigid; i++) modify->fix[rfix[i]]->deform(0); // reset global and local box to new size/shape for (i = 0; i < 3; i++) { if (direction == i) { oldlo = domain->boxlo[i]; oldhi = domain->boxhi[i]; ctr = 0.5 * (oldlo + oldhi); domain->boxlo[i] = (oldlo-ctr)*dilation[i] + ctr; domain->boxhi[i] = (oldhi-ctr)*dilation[i] + ctr; } } domain->set_global_box(); domain->set_local_box(); // convert pertinent atoms and rigid bodies back to box coords domain->lamda2x(n); if (nrigid) for (i = 0; i < nrigid; i++) modify->fix[rfix[i]]->deform(1); for (i = 0; i < n; i++) { v[i][direction] = v[i][direction] * dilation[direction]; } } /* ---------------------------------------------------------------------- pack entire state of Fix into one write ------------------------------------------------------------------------- */ void FixMSST::write_restart(FILE *fp) { int n = 0; double list[5]; list[n++] = omega[direction]; list[n++] = e0; list[n++] = v0; list[n++] = p0; list[n++] = TS_int; if (comm->me == 0) { int size = n * sizeof(double); fwrite(&size,sizeof(int),1,fp); fwrite(&list,sizeof(double),n,fp); } } /* ---------------------------------------------------------------------- use state info from restart file to restart the Fix ------------------------------------------------------------------------- */ void FixMSST::restart(char *buf) { int n = 0; auto list = (double *) buf; omega[direction] = list[n++]; e0 = list[n++]; v0 = list[n++]; p0 = list[n++]; TS_int = list[n++]; tscale = 0.0; // set tscale to zero for restart p0_set = 1; v0_set = 1; e0_set = 1; } /* ---------------------------------------------------------------------- */ int FixMSST::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]); int icompute = modify->find_compute(id_temp); 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 MSST is not for group all"); 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(id_press); 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; } /* ---------------------------------------------------------------------- */ double FixMSST::compute_scalar() { // compute new pressure and volume temperature->compute_vector(); pressure->compute_vector(); couple(); double volume = compute_vol(); double energy = 0.0; int i; i = direction; energy = qmass * omega[i] * omega[i] / (2.0 * total_mass) * mvv2e; energy -= 0.5 * total_mass * velocity * velocity * (1.0 - volume/ v0) * (1.0 - volume/ v0) * mvv2e; energy -= p0 * ( v0 - volume ) / nktv2p; // subtract off precomputed TS_int integral value // TS_int = 0 for non DFTB calculations if (dftb) energy -= TS_int; return energy; } /* ---------------------------------------------------------------------- return a single element from the following vector, [dhug,dray,lgr_vel,lgr_pos] ------------------------------------------------------------------------- */ double FixMSST::compute_vector(int n) { if (n == 0) { return compute_hugoniot(); } else if (n == 1) { return compute_rayleigh(); } else if (n == 2) { return compute_lagrangian_speed(); } else if (n == 3) { return compute_lagrangian_position(); } return 0.0; } /* ---------------------------------------------------------------------- Computes the deviation of the current point from the Hugoniot in Kelvin for the MSST ------------------------------------------------------------------------- */ double FixMSST::compute_hugoniot() { if (!temperature) return 0.0; double v, e, p; double dhugo; e = compute_etotal(); temperature->compute_vector(); pressure->compute_vector(); p = pressure->vector[direction]; v = compute_vol(); dhugo = (0.5 * (p + p0 ) * ( v0 - v)) / force->nktv2p + e0 - e; dhugo /= temperature->dof * force->boltz; return dhugo; } /* ---------------------------------------------------------------------- Computes the deviation of the current point from the Rayleigh in pressure units for the MSST ------------------------------------------------------------------------- */ double FixMSST::compute_rayleigh() { if (!temperature) return 0.0; double v, p; double drayleigh; temperature->compute_vector(); pressure->compute_vector(); p = pressure->vector[direction]; v = compute_vol(); drayleigh = p - p0 - total_mass * velocity * velocity * force->mvv2e * (1.0 - v / v0 ) * force->nktv2p / v0; return drayleigh; } /* ---------------------------------------------------------------------- Computes the speed of the MSST computational cell in the unshocked material rest-frame ------------------------------------------------------------------------- */ double FixMSST::compute_lagrangian_speed() { double v = compute_vol(); return velocity*(1.0-v/v0); } /* ---------------------------------------------------------------------- Computes the distance behind the shock front of the MSST computational cell. ------------------------------------------------------------------------- */ double FixMSST::compute_lagrangian_position() { return lagrangian_position; } /* ---------------------------------------------------------------------- */ double FixMSST::compute_etotal() { if (!pe) return 0.0; double epot,ekin,etot; epot = pe->compute_scalar(); ekin = temperature->compute_scalar(); ekin *= 0.5 * temperature->dof * force->boltz; etot = epot+ekin; return etot; } /* ---------------------------------------------------------------------- */ double FixMSST::compute_vol() { if (domain->dimension == 3) return domain->xprd * domain->yprd * domain->zprd; else return domain->xprd * domain->yprd; } /* ---------------------------------------------------------------------- */ double FixMSST::compute_vsum() { double vsum; double **v = atom->v; int *mask = atom->mask; int nlocal = atom->nlocal; double t = 0.0; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { t += (v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]) ; } } MPI_Allreduce(&t,&vsum,1,MPI_DOUBLE,MPI_SUM,world); return vsum; } /* ---------------------------------------------------------------------- memory usage of local atom-based array ------------------------------------------------------------------------- */ double FixMSST::memory_usage() { double bytes = 3*atom->nmax * sizeof(double); return bytes; }