diff --git a/src/compute_temp_sphere.cpp b/src/compute_temp_sphere.cpp index 6a376f20f..ec570d22e 100644 --- a/src/compute_temp_sphere.cpp +++ b/src/compute_temp_sphere.cpp @@ -1,329 +1,330 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, 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. ------------------------------------------------------------------------- */ #include "mpi.h" #include "string.h" #include "compute_temp_sphere.h" #include "atom.h" #include "atom_vec.h" #include "update.h" #include "force.h" #include "domain.h" #include "modify.h" #include "fix.h" #include "group.h" #include "error.h" using namespace LAMMPS_NS; enum{ROTATE,ALL}; #define INERTIA 0.4 // moment of inertia prefactor for sphere /* ---------------------------------------------------------------------- */ ComputeTempSphere::ComputeTempSphere(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg) { if (narg < 3) error->all(FLERR,"Illegal compute temp/sphere command"); scalar_flag = vector_flag = 1; size_vector = 6; extscalar = 0; extvector = 1; tempflag = 1; tempbias = 0; id_bias = NULL; mode = ALL; int iarg = 3; while (iarg < narg) { if (strcmp(arg[iarg],"bias") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal compute temp/sphere command"); tempbias = 1; int n = strlen(arg[iarg+1]) + 1; id_bias = new char[n]; strcpy(id_bias,arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"dof") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal compute temp/sphere command"); if (strcmp(arg[iarg+1],"rotate") == 0) mode = ROTATE; else if (strcmp(arg[iarg+1],"all") == 0) mode = ALL; else error->all(FLERR,"Illegal compute temp/sphere command"); iarg += 2; } else error->all(FLERR,"Illegal compute temp/sphere command"); } vector = new double[6]; // error checks if (!atom->sphere_flag) error->all(FLERR,"Compute temp/sphere requires atom style sphere"); } /* ---------------------------------------------------------------------- */ ComputeTempSphere::~ComputeTempSphere() { delete [] id_bias; delete [] vector; } /* ---------------------------------------------------------------------- */ void ComputeTempSphere::init() { if (tempbias) { int i = modify->find_compute(id_bias); if (i < 0) error->all(FLERR,"Could not find compute ID for temperature bias"); tbias = modify->compute[i]; if (tbias->tempflag == 0) error->all(FLERR,"Bias compute does not calculate temperature"); if (tbias->tempbias == 0) error->all(FLERR,"Bias compute does not calculate a velocity bias"); if (tbias->igroup != igroup) error->all(FLERR,"Bias compute group does not match compute group"); tbias->init(); + tbias->setup(); if (strcmp(tbias->style,"temp/region") == 0) tempbias = 2; else tempbias = 1; } } /* ---------------------------------------------------------------------- */ void ComputeTempSphere::setup() { fix_dof = 0; for (int i = 0; i < modify->nfix; i++) fix_dof += modify->fix[i]->dof(igroup); dof_compute(); } /* ---------------------------------------------------------------------- */ void ComputeTempSphere::dof_compute() { int count,count_all; // 6 or 3 dof for extended/point particles for 3d // 3 or 2 dof for extended/point particles for 2d // which dof are included also depends on mode // assume full rotation of extended particles // user should correct this via compute_modify if needed double *radius = atom->radius; int *mask = atom->mask; int nlocal = atom->nlocal; count = 0; if (domain->dimension == 3) { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { if (radius[i] == 0.0) { if (mode == ALL) count += 3; } else { if (mode == ALL) count += 6; else count += 3; } } } else { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { if (radius[i] == 0.0) { if (mode == ALL) count += 2; } else { if (mode == ALL) count += 3; else count += 1; } } } MPI_Allreduce(&count,&count_all,1,MPI_INT,MPI_SUM,world); dof = count_all; // additional adjustments to dof if (tempbias == 1) { if (mode == ALL) { double natoms = group->count(igroup); dof -= tbias->dof_remove(-1) * natoms; } } else if (tempbias == 2) { int *mask = atom->mask; int nlocal = atom->nlocal; count = 0; if (domain->dimension == 3) { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { if (tbias->dof_remove(i)) { if (radius[i] == 0.0) { if (mode == ALL) count += 3; } else { if (mode == ALL) count += 6; else count += 3; } } } } else { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { if (tbias->dof_remove(i)) { if (radius[i] == 0.0) { if (mode == ALL) count += 2; } else { if (mode == ALL) count += 3; else count += 1; } } } } MPI_Allreduce(&count,&count_all,1,MPI_INT,MPI_SUM,world); dof -= count_all; } dof -= extra_dof + fix_dof; if (dof > 0) tfactor = force->mvv2e / (dof * force->boltz); else tfactor = 0.0; } /* ---------------------------------------------------------------------- */ double ComputeTempSphere::compute_scalar() { invoked_scalar = update->ntimestep; if (tempbias) { if (tbias->invoked_scalar != update->ntimestep) tbias->compute_scalar(); tbias->remove_bias_all(); } double **v = atom->v; double **omega = atom->omega; double *radius = atom->radius; double *rmass = atom->rmass; int *mask = atom->mask; int nlocal = atom->nlocal; // point particles will not contribute rotation due to radius = 0 double t = 0.0; if (mode == ALL) { 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]) * rmass[i]; t += (omega[i][0]*omega[i][0] + omega[i][1]*omega[i][1] + omega[i][2]*omega[i][2]) * INERTIA*rmass[i]*radius[i]*radius[i]; } } else { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) t += (omega[i][0]*omega[i][0] + omega[i][1]*omega[i][1] + omega[i][2]*omega[i][2]) * INERTIA*rmass[i]*radius[i]*radius[i]; } if (tempbias) tbias->restore_bias_all(); MPI_Allreduce(&t,&scalar,1,MPI_DOUBLE,MPI_SUM,world); if (dynamic || tempbias == 2) dof_compute(); scalar *= tfactor; return scalar; } /* ---------------------------------------------------------------------- */ void ComputeTempSphere::compute_vector() { invoked_vector = update->ntimestep; if (tempbias) { if (tbias->invoked_vector != update->ntimestep) tbias->compute_vector(); tbias->remove_bias_all(); } double **v = atom->v; double **omega = atom->omega; double *rmass = atom->rmass; double *radius = atom->radius; int *mask = atom->mask; int nlocal = atom->nlocal; // point particles will not contribute rotation due to radius = 0 double massone,inertiaone,t[6]; for (int i = 0; i < 6; i++) t[i] = 0.0; if (mode == ALL) { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { massone = rmass[i]; t[0] += massone * v[i][0]*v[i][0]; t[1] += massone * v[i][1]*v[i][1]; t[2] += massone * v[i][2]*v[i][2]; t[3] += massone * v[i][0]*v[i][1]; t[4] += massone * v[i][0]*v[i][2]; t[5] += massone * v[i][1]*v[i][2]; inertiaone = INERTIA*rmass[i]*radius[i]*radius[i]; t[0] += inertiaone * omega[i][0]*omega[i][0]; t[1] += inertiaone * omega[i][1]*omega[i][1]; t[2] += inertiaone * omega[i][2]*omega[i][2]; t[3] += inertiaone * omega[i][0]*omega[i][1]; t[4] += inertiaone * omega[i][0]*omega[i][2]; t[5] += inertiaone * omega[i][1]*omega[i][2]; } } else { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { inertiaone = INERTIA*rmass[i]*radius[i]*radius[i]; t[0] += inertiaone * omega[i][0]*omega[i][0]; t[1] += inertiaone * omega[i][1]*omega[i][1]; t[2] += inertiaone * omega[i][2]*omega[i][2]; t[3] += inertiaone * omega[i][0]*omega[i][1]; t[4] += inertiaone * omega[i][0]*omega[i][2]; t[5] += inertiaone * omega[i][1]*omega[i][2]; } } if (tempbias) tbias->restore_bias_all(); MPI_Allreduce(t,vector,6,MPI_DOUBLE,MPI_SUM,world); for (int i = 0; i < 6; i++) vector[i] *= force->mvv2e; } /* ---------------------------------------------------------------------- remove velocity bias from atom I to leave thermal velocity ------------------------------------------------------------------------- */ void ComputeTempSphere::remove_bias(int i, double *v) { tbias->remove_bias(i,v); } /* ---------------------------------------------------------------------- add back in velocity bias to atom I removed by remove_bias() assume remove_bias() was previously called ------------------------------------------------------------------------- */ void ComputeTempSphere::restore_bias(int i, double *v) { tbias->restore_bias(i,v); } diff --git a/src/modify.cpp b/src/modify.cpp index 47b382116..9c843b8ab 100644 --- a/src/modify.cpp +++ b/src/modify.cpp @@ -1,1197 +1,1198 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, 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. ------------------------------------------------------------------------- */ #include "stdio.h" #include "string.h" #include "modify.h" #include "style_compute.h" #include "style_fix.h" #include "atom.h" #include "comm.h" #include "fix.h" #include "compute.h" #include "group.h" #include "update.h" #include "domain.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace FixConst; #define DELTA 4 #define BIG 1.0e20 #define NEXCEPT 3 // change when add to exceptions in add_fix() /* ---------------------------------------------------------------------- */ Modify::Modify(LAMMPS *lmp) : Pointers(lmp) { nfix = maxfix = 0; n_initial_integrate = n_post_integrate = 0; n_pre_exchange = n_pre_neighbor = 0; n_pre_force = n_post_force = 0; n_final_integrate = n_end_of_step = n_thermo_energy = 0; n_initial_integrate_respa = n_post_integrate_respa = 0; n_pre_force_respa = n_post_force_respa = n_final_integrate_respa = 0; n_min_pre_exchange = n_min_pre_force = n_min_post_force = n_min_energy = 0; fix = NULL; fmask = NULL; list_initial_integrate = list_post_integrate = NULL; list_pre_exchange = list_pre_neighbor = NULL; list_pre_force = list_post_force = NULL; list_final_integrate = list_end_of_step = NULL; list_thermo_energy = NULL; list_initial_integrate_respa = list_post_integrate_respa = NULL; list_pre_force_respa = list_post_force_respa = NULL; list_final_integrate_respa = NULL; list_min_pre_exchange = list_min_pre_neighbor = NULL; list_min_pre_force = list_min_post_force = NULL; list_min_energy = NULL; end_of_step_every = NULL; list_timeflag = NULL; nfix_restart_global = 0; id_restart_global = style_restart_global = state_restart_global = NULL; nfix_restart_peratom = 0; id_restart_peratom = style_restart_peratom = NULL; index_restart_peratom = NULL; ncompute = maxcompute = 0; compute = NULL; } /* ---------------------------------------------------------------------- */ Modify::~Modify() { // delete all fixes // do it via delete_fix() so callbacks in Atom are also updated correctly while (nfix) delete_fix(fix[0]->id); memory->sfree(fix); memory->destroy(fmask); // delete all computes for (int i = 0; i < ncompute; i++) delete compute[i]; memory->sfree(compute); delete [] list_initial_integrate; delete [] list_post_integrate; delete [] list_pre_exchange; delete [] list_pre_neighbor; delete [] list_pre_force; delete [] list_post_force; delete [] list_final_integrate; delete [] list_end_of_step; delete [] list_thermo_energy; delete [] list_initial_integrate_respa; delete [] list_post_integrate_respa; delete [] list_pre_force_respa; delete [] list_post_force_respa; delete [] list_final_integrate_respa; delete [] list_min_pre_exchange; delete [] list_min_pre_neighbor; delete [] list_min_pre_force; delete [] list_min_post_force; delete [] list_min_energy; delete [] end_of_step_every; delete [] list_timeflag; restart_deallocate(); } /* ---------------------------------------------------------------------- initialize all fixes and computes ------------------------------------------------------------------------- */ void Modify::init() { int i,j; // delete storage of restart info since it is not valid after 1st run restart_deallocate(); // create lists of fixes to call at each stage of run list_init(INITIAL_INTEGRATE,n_initial_integrate,list_initial_integrate); list_init(POST_INTEGRATE,n_post_integrate,list_post_integrate); list_init(PRE_EXCHANGE,n_pre_exchange,list_pre_exchange); list_init(PRE_NEIGHBOR,n_pre_neighbor,list_pre_neighbor); list_init(PRE_FORCE,n_pre_force,list_pre_force); list_init(POST_FORCE,n_post_force,list_post_force); list_init(FINAL_INTEGRATE,n_final_integrate,list_final_integrate); list_init_end_of_step(END_OF_STEP,n_end_of_step,list_end_of_step); list_init_thermo_energy(THERMO_ENERGY,n_thermo_energy,list_thermo_energy); list_init(INITIAL_INTEGRATE_RESPA, n_initial_integrate_respa,list_initial_integrate_respa); list_init(POST_INTEGRATE_RESPA, n_post_integrate_respa,list_post_integrate_respa); list_init(POST_FORCE_RESPA, n_post_force_respa,list_post_force_respa); list_init(PRE_FORCE_RESPA, n_pre_force_respa,list_pre_force_respa); list_init(FINAL_INTEGRATE_RESPA, n_final_integrate_respa,list_final_integrate_respa); list_init(MIN_PRE_EXCHANGE,n_min_pre_exchange,list_min_pre_exchange); list_init(MIN_PRE_NEIGHBOR,n_min_pre_neighbor,list_min_pre_neighbor); list_init(MIN_PRE_FORCE,n_min_pre_force,list_min_pre_force); list_init(MIN_POST_FORCE,n_min_post_force,list_min_post_force); list_init(MIN_ENERGY,n_min_energy,list_min_energy); // init each fix // needs to come before compute init // this is b/c some computes call fix->dof() // FixRigid::dof() depends on its own init having been called + // NOTE: 2/13, this may no longer be needed b/c computes do dof in setup() for (i = 0; i < nfix; i++) fix[i]->init(); // set global flag if any fix has its restart_pbc flag set restart_pbc_any = 0; for (i = 0; i < nfix; i++) if (fix[i]->restart_pbc) restart_pbc_any = 1; // create list of computes that store invocation times list_init_compute(); // init each compute // set invoked_scalar,vector,etc to -1 to force new run to re-compute them // add initial timestep to all computes that store invocation times // since any of them may be invoked by initial thermo // do not clear out invocation times stored within a compute, // b/c some may be holdovers from previous run, like for ave fixes for (i = 0; i < ncompute; i++) { compute[i]->init(); compute[i]->invoked_scalar = -1; compute[i]->invoked_vector = -1; compute[i]->invoked_array = -1; compute[i]->invoked_peratom = -1; compute[i]->invoked_local = -1; } addstep_compute_all(update->ntimestep); // warn if any particle is time integrated more than once int nlocal = atom->nlocal; int *mask = atom->mask; int *flag = new int[nlocal]; for (i = 0; i < nlocal; i++) flag[i] = 0; int groupbit; for (i = 0; i < nfix; i++) { if (fix[i]->time_integrate == 0) continue; groupbit = fix[i]->groupbit; for (j = 0; j < nlocal; j++) if (mask[j] & groupbit) flag[j]++; } int check = 0; for (i = 0; i < nlocal; i++) if (flag[i] > 1) check = 1; delete [] flag; int checkall; MPI_Allreduce(&check,&checkall,1,MPI_INT,MPI_SUM,world); if (comm->me == 0 && checkall) error->warning(FLERR, "One or more atoms are time integrated more than once"); } /* ---------------------------------------------------------------------- setup for run, calls setup() of all fixes and computes called from Verlet, RESPA, Min ------------------------------------------------------------------------- */ void Modify::setup(int vflag) { if (update->whichflag == 1) for (int i = 0; i < nfix; i++) fix[i]->setup(vflag); else if (update->whichflag == 2) for (int i = 0; i < nfix; i++) fix[i]->min_setup(vflag); // call computes after fixes // fix rigid dof() can't be called by temperature computes at init for (int i = 0; i < ncompute; i++) compute[i]->setup(); } /* ---------------------------------------------------------------------- setup pre_exchange call, only for fixes that define pre_exchange called from Verlet, RESPA, Min, and WriteRestart with whichflag = 0 ------------------------------------------------------------------------- */ void Modify::setup_pre_exchange() { if (update->whichflag <= 1) for (int i = 0; i < n_pre_exchange; i++) fix[list_pre_exchange[i]]->setup_pre_exchange(); else if (update->whichflag == 2) for (int i = 0; i < n_min_pre_exchange; i++) fix[list_min_pre_exchange[i]]->min_setup_pre_exchange(); } /* ---------------------------------------------------------------------- setup pre_neighbor call, only for fixes that define pre_neighbor called from Verlet, RESPA ------------------------------------------------------------------------- */ void Modify::setup_pre_neighbor() { if (update->whichflag == 1) for (int i = 0; i < n_pre_neighbor; i++) fix[list_pre_neighbor[i]]->setup_pre_neighbor(); else if (update->whichflag == 2) for (int i = 0; i < n_pre_neighbor; i++) fix[list_min_pre_neighbor[i]]->min_setup_pre_neighbor(); } /* ---------------------------------------------------------------------- setup pre_force call, only for fixes that define pre_force called from Verlet, RESPA, Min ------------------------------------------------------------------------- */ void Modify::setup_pre_force(int vflag) { if (update->whichflag == 1) for (int i = 0; i < n_pre_force; i++) fix[list_pre_force[i]]->setup_pre_force(vflag); else if (update->whichflag == 2) for (int i = 0; i < n_min_pre_force; i++) fix[list_min_pre_force[i]]->min_setup_pre_force(vflag); } /* ---------------------------------------------------------------------- 1st half of integrate call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::initial_integrate(int vflag) { for (int i = 0; i < n_initial_integrate; i++) fix[list_initial_integrate[i]]->initial_integrate(vflag); } /* ---------------------------------------------------------------------- post_integrate call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::post_integrate() { for (int i = 0; i < n_post_integrate; i++) fix[list_post_integrate[i]]->post_integrate(); } /* ---------------------------------------------------------------------- pre_exchange call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::pre_exchange() { for (int i = 0; i < n_pre_exchange; i++) fix[list_pre_exchange[i]]->pre_exchange(); } /* ---------------------------------------------------------------------- pre_neighbor call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::pre_neighbor() { for (int i = 0; i < n_pre_neighbor; i++) fix[list_pre_neighbor[i]]->pre_neighbor(); } /* ---------------------------------------------------------------------- pre_force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::pre_force(int vflag) { for (int i = 0; i < n_pre_force; i++) fix[list_pre_force[i]]->pre_force(vflag); } /* ---------------------------------------------------------------------- post_force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::post_force(int vflag) { for (int i = 0; i < n_post_force; i++) fix[list_post_force[i]]->post_force(vflag); } /* ---------------------------------------------------------------------- 2nd half of integrate call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::final_integrate() { for (int i = 0; i < n_final_integrate; i++) fix[list_final_integrate[i]]->final_integrate(); } /* ---------------------------------------------------------------------- end-of-timestep call, only for relevant fixes only call fix->end_of_step() on timesteps that are multiples of nevery ------------------------------------------------------------------------- */ void Modify::end_of_step() { for (int i = 0; i < n_end_of_step; i++) if (update->ntimestep % end_of_step_every[i] == 0) fix[list_end_of_step[i]]->end_of_step(); } /* ---------------------------------------------------------------------- thermo energy call, only for relevant fixes called by Thermo class compute_scalar() is fix call to return energy ------------------------------------------------------------------------- */ double Modify::thermo_energy() { double energy = 0.0; for (int i = 0; i < n_thermo_energy; i++) energy += fix[list_thermo_energy[i]]->compute_scalar(); return energy; } /* ---------------------------------------------------------------------- post_run call ------------------------------------------------------------------------- */ void Modify::post_run() { for (int i = 0; i < nfix; i++) fix[i]->post_run(); } /* ---------------------------------------------------------------------- setup rRESPA pre_force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::setup_pre_force_respa(int vflag, int ilevel) { for (int i = 0; i < n_pre_force; i++) fix[list_pre_force[i]]->setup_pre_force_respa(vflag,ilevel); } /* ---------------------------------------------------------------------- 1st half of rRESPA integrate call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::initial_integrate_respa(int vflag, int ilevel, int iloop) { for (int i = 0; i < n_initial_integrate_respa; i++) fix[list_initial_integrate_respa[i]]-> initial_integrate_respa(vflag,ilevel,iloop); } /* ---------------------------------------------------------------------- rRESPA post_integrate call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::post_integrate_respa(int ilevel, int iloop) { for (int i = 0; i < n_post_integrate_respa; i++) fix[list_post_integrate_respa[i]]->post_integrate_respa(ilevel,iloop); } /* ---------------------------------------------------------------------- rRESPA pre_force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::pre_force_respa(int vflag, int ilevel, int iloop) { for (int i = 0; i < n_pre_force_respa; i++) fix[list_pre_force_respa[i]]->pre_force_respa(vflag,ilevel,iloop); } /* ---------------------------------------------------------------------- rRESPA post_force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::post_force_respa(int vflag, int ilevel, int iloop) { for (int i = 0; i < n_post_force_respa; i++) fix[list_post_force_respa[i]]->post_force_respa(vflag,ilevel,iloop); } /* ---------------------------------------------------------------------- 2nd half of rRESPA integrate call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::final_integrate_respa(int ilevel, int iloop) { for (int i = 0; i < n_final_integrate_respa; i++) fix[list_final_integrate_respa[i]]->final_integrate_respa(ilevel,iloop); } /* ---------------------------------------------------------------------- minimizer pre-exchange call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_pre_exchange() { for (int i = 0; i < n_min_pre_exchange; i++) fix[list_min_pre_exchange[i]]->min_pre_exchange(); } /* ---------------------------------------------------------------------- minimizer pre-neighbor call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_pre_neighbor() { for (int i = 0; i < n_min_pre_neighbor; i++) fix[list_min_pre_neighbor[i]]->min_pre_neighbor(); } /* ---------------------------------------------------------------------- minimizer pre-force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_pre_force(int vflag) { for (int i = 0; i < n_min_pre_force; i++) fix[list_min_pre_force[i]]->min_pre_force(vflag); } /* ---------------------------------------------------------------------- minimizer force adjustment call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_post_force(int vflag) { for (int i = 0; i < n_min_post_force; i++) fix[list_min_post_force[i]]->min_post_force(vflag); } /* ---------------------------------------------------------------------- minimizer energy/force evaluation, only for relevant fixes return energy and forces on extra degrees of freedom ------------------------------------------------------------------------- */ double Modify::min_energy(double *fextra) { int ifix,index; index = 0; double eng = 0.0; for (int i = 0; i < n_min_energy; i++) { ifix = list_min_energy[i]; eng += fix[ifix]->min_energy(&fextra[index]); index += fix[ifix]->min_dof(); } return eng; } /* ---------------------------------------------------------------------- store current state of extra dof, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_store() { for (int i = 0; i < n_min_energy; i++) fix[list_min_energy[i]]->min_store(); } /* ---------------------------------------------------------------------- mange state of extra dof on a stack, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_clearstore() { for (int i = 0; i < n_min_energy; i++) fix[list_min_energy[i]]->min_clearstore(); } void Modify::min_pushstore() { for (int i = 0; i < n_min_energy; i++) fix[list_min_energy[i]]->min_pushstore(); } void Modify::min_popstore() { for (int i = 0; i < n_min_energy; i++) fix[list_min_energy[i]]->min_popstore(); } /* ---------------------------------------------------------------------- displace extra dof along vector hextra, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_step(double alpha, double *hextra) { int ifix,index; index = 0; for (int i = 0; i < n_min_energy; i++) { ifix = list_min_energy[i]; fix[ifix]->min_step(alpha,&hextra[index]); index += fix[ifix]->min_dof(); } } /* ---------------------------------------------------------------------- compute max allowed step size along vector hextra, only for relevant fixes ------------------------------------------------------------------------- */ double Modify::max_alpha(double *hextra) { int ifix,index; double alpha = BIG; index = 0; for (int i = 0; i < n_min_energy; i++) { ifix = list_min_energy[i]; double alpha_one = fix[ifix]->max_alpha(&hextra[index]); alpha = MIN(alpha,alpha_one); index += fix[ifix]->min_dof(); } return alpha; } /* ---------------------------------------------------------------------- extract extra dof for minimization, only for relevant fixes ------------------------------------------------------------------------- */ int Modify::min_dof() { int ndof = 0; for (int i = 0; i < n_min_energy; i++) ndof += fix[list_min_energy[i]]->min_dof(); return ndof; } /* ---------------------------------------------------------------------- reset reference state of fix, only for relevant fixes ------------------------------------------------------------------------- */ int Modify::min_reset_ref() { int itmp,itmpall; itmpall = 0; for (int i = 0; i < n_min_energy; i++) { itmp = fix[list_min_energy[i]]->min_reset_ref(); if (itmp) itmpall = 1; } return itmpall; } /* ---------------------------------------------------------------------- add a new fix or replace one with same ID ------------------------------------------------------------------------- */ void Modify::add_fix(int narg, char **arg, char *suffix) { const char *exceptions[NEXCEPT] = {"GPU","OMP","cmap"}; if (narg < 3) error->all(FLERR,"Illegal fix command"); // cannot define fix before box exists unless style is in exception list // don't like this way of checking for exceptions by adding fixes to list, // but can't think of better way // too late if instantiate fix, then check flag set in fix constructor, // since some fixes access domain settings in their constructor if (domain->box_exist == 0) { int m; for (m = 0; m < NEXCEPT; m++) if (strcmp(arg[2],exceptions[m]) == 0) break; if (m == NEXCEPT) error->all(FLERR,"Fix command before simulation box is defined"); } // check group ID int igroup = group->find(arg[1]); if (igroup == -1) error->all(FLERR,"Could not find fix group ID"); // if fix ID exists: // set newflag = 0 so create new fix in same location in fix list // error if new style does not match old style // since can't replace it (all when-to-invoke ptrs would be invalid) // warn if new group != old group // delete old fix, but do not call update_callback(), // since will replace this fix and thus other fix locs will not change // set ptr to NULL in case new fix scans list of fixes, // e.g. scan will occur in add_callback() if called by new fix // if fix ID does not exist: // set newflag = 1 so create new fix // extend fix and fmask lists as necessary int ifix,newflag; for (ifix = 0; ifix < nfix; ifix++) if (strcmp(arg[0],fix[ifix]->id) == 0) break; if (ifix < nfix) { newflag = 0; if (strcmp(arg[2],fix[ifix]->style) != 0) error->all(FLERR,"Replacing a fix, but new style != old style"); if (fix[ifix]->igroup != igroup && comm->me == 0) error->warning(FLERR,"Replacing a fix, but new group != old group"); delete fix[ifix]; fix[ifix] = NULL; } else { newflag = 1; if (nfix == maxfix) { maxfix += DELTA; fix = (Fix **) memory->srealloc(fix,maxfix*sizeof(Fix *),"modify:fix"); memory->grow(fmask,maxfix,"modify:fmask"); } } // create the Fix, first with suffix appended int success = 0; if (suffix && lmp->suffix_enable) { char estyle[256]; sprintf(estyle,"%s/%s",arg[2],suffix); success = 1; if (0) return; #define FIX_CLASS #define FixStyle(key,Class) \ else if (strcmp(estyle,#key) == 0) fix[ifix] = new Class(lmp,narg,arg); #include "style_fix.h" #undef FixStyle #undef FIX_CLASS else success = 0; } if (!success) { if (0) return; #define FIX_CLASS #define FixStyle(key,Class) \ else if (strcmp(arg[2],#key) == 0) fix[ifix] = new Class(lmp,narg,arg); #include "style_fix.h" #undef FixStyle #undef FIX_CLASS else error->all(FLERR,"Invalid fix style"); } // set fix mask values and increment nfix (if new) fmask[ifix] = fix[ifix]->setmask(); if (newflag) nfix++; // check if Fix is in restart_global list // if yes, pass state info to the Fix so it can reset itself for (int i = 0; i < nfix_restart_global; i++) if (strcmp(id_restart_global[i],fix[ifix]->id) == 0 && strcmp(style_restart_global[i],fix[ifix]->style) == 0) { fix[ifix]->restart(state_restart_global[i]); if (comm->me == 0) { char *str = (char *) ("Resetting global state of Fix %s Style %s " "from restart file info\n"); if (screen) fprintf(screen,str,fix[ifix]->id,fix[ifix]->style); if (logfile) fprintf(logfile,str,fix[ifix]->id,fix[ifix]->style); } } // check if Fix is in restart_peratom list // if yes, loop over atoms so they can extract info from atom->extra array for (int i = 0; i < nfix_restart_peratom; i++) if (strcmp(id_restart_peratom[i],fix[ifix]->id) == 0 && strcmp(style_restart_peratom[i],fix[ifix]->style) == 0) { for (int j = 0; j < atom->nlocal; j++) fix[ifix]->unpack_restart(j,index_restart_peratom[i]); if (comm->me == 0) { char *str = (char *) ("Resetting per-atom state of Fix %s Style %s " "from restart file info\n"); if (screen) fprintf(screen,str,fix[ifix]->id,fix[ifix]->style); if (logfile) fprintf(logfile,str,fix[ifix]->id,fix[ifix]->style); } } } /* ---------------------------------------------------------------------- modify a Fix's parameters ------------------------------------------------------------------------- */ void Modify::modify_fix(int narg, char **arg) { if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); // lookup Fix ID int ifix; for (ifix = 0; ifix < nfix; ifix++) if (strcmp(arg[0],fix[ifix]->id) == 0) break; if (ifix == nfix) error->all(FLERR,"Could not find fix_modify ID"); fix[ifix]->modify_params(narg-1,&arg[1]); } /* ---------------------------------------------------------------------- delete a Fix from list of Fixes Atom class must update indices in its list of callbacks to fixes ------------------------------------------------------------------------- */ void Modify::delete_fix(const char *id) { int ifix = find_fix(id); if (ifix < 0) error->all(FLERR,"Could not find fix ID to delete"); delete fix[ifix]; atom->update_callback(ifix); // move other Fixes and fmask down in list one slot for (int i = ifix+1; i < nfix; i++) fix[i-1] = fix[i]; for (int i = ifix+1; i < nfix; i++) fmask[i-1] = fmask[i]; nfix--; } /* ---------------------------------------------------------------------- find a fix by ID return index of fix or -1 if not found ------------------------------------------------------------------------- */ int Modify::find_fix(const char *id) { int ifix; for (ifix = 0; ifix < nfix; ifix++) if (strcmp(id,fix[ifix]->id) == 0) break; if (ifix == nfix) return -1; return ifix; } /* ---------------------------------------------------------------------- add a new compute ------------------------------------------------------------------------- */ void Modify::add_compute(int narg, char **arg, char *suffix) { if (narg < 3) error->all(FLERR,"Illegal compute command"); // error check for (int icompute = 0; icompute < ncompute; icompute++) if (strcmp(arg[0],compute[icompute]->id) == 0) error->all(FLERR,"Reuse of compute ID"); // extend Compute list if necessary if (ncompute == maxcompute) { maxcompute += DELTA; compute = (Compute **) memory->srealloc(compute,maxcompute*sizeof(Compute *),"modify:compute"); } // create the Compute, first with suffix appended int success = 0; if (suffix && lmp->suffix_enable) { char estyle[256]; sprintf(estyle,"%s/%s",arg[2],suffix); success = 1; if (0) return; #define COMPUTE_CLASS #define ComputeStyle(key,Class) \ else if (strcmp(estyle,#key) == 0) \ compute[ncompute] = new Class(lmp,narg,arg); #include "style_compute.h" #undef ComputeStyle #undef COMPUTE_CLASS else success = 0; } if (!success) { if (0) return; #define COMPUTE_CLASS #define ComputeStyle(key,Class) \ else if (strcmp(arg[2],#key) == 0) \ compute[ncompute] = new Class(lmp,narg,arg); #include "style_compute.h" #undef ComputeStyle #undef COMPUTE_CLASS else error->all(FLERR,"Invalid compute style"); } ncompute++; } /* ---------------------------------------------------------------------- modify a Compute's parameters ------------------------------------------------------------------------- */ void Modify::modify_compute(int narg, char **arg) { if (narg < 2) error->all(FLERR,"Illegal compute_modify command"); // lookup Compute ID int icompute; for (icompute = 0; icompute < ncompute; icompute++) if (strcmp(arg[0],compute[icompute]->id) == 0) break; if (icompute == ncompute) error->all(FLERR,"Could not find compute_modify ID"); compute[icompute]->modify_params(narg-1,&arg[1]); } /* ---------------------------------------------------------------------- delete a Compute from list of Computes ------------------------------------------------------------------------- */ void Modify::delete_compute(const char *id) { int icompute = find_compute(id); if (icompute < 0) error->all(FLERR,"Could not find compute ID to delete"); delete compute[icompute]; // move other Computes down in list one slot for (int i = icompute+1; i < ncompute; i++) compute[i-1] = compute[i]; ncompute--; } /* ---------------------------------------------------------------------- find a compute by ID return index of compute or -1 if not found ------------------------------------------------------------------------- */ int Modify::find_compute(const char *id) { int icompute; for (icompute = 0; icompute < ncompute; icompute++) if (strcmp(id,compute[icompute]->id) == 0) break; if (icompute == ncompute) return -1; return icompute; } /* ---------------------------------------------------------------------- clear invoked flag of all computes called everywhere that computes are used, before computes are invoked invoked flag used to avoid re-invoking same compute multiple times and to flag computes that store invocation times as having been invoked ------------------------------------------------------------------------- */ void Modify::clearstep_compute() { for (int icompute = 0; icompute < ncompute; icompute++) compute[icompute]->invoked_flag = 0; } /* ---------------------------------------------------------------------- loop over computes that store invocation times if its invoked flag set on this timestep, schedule next invocation called everywhere that computes are used, after computes are invoked ------------------------------------------------------------------------- */ void Modify::addstep_compute(bigint newstep) { for (int icompute = 0; icompute < n_timeflag; icompute++) if (compute[list_timeflag[icompute]]->invoked_flag) compute[list_timeflag[icompute]]->addstep(newstep); } /* ---------------------------------------------------------------------- loop over all computes schedule next invocation for those that store invocation times called when not sure what computes will be needed on newstep do not loop only over n_timeflag, since may not be set yet ------------------------------------------------------------------------- */ void Modify::addstep_compute_all(bigint newstep) { for (int icompute = 0; icompute < ncompute; icompute++) if (compute[icompute]->timeflag) compute[icompute]->addstep(newstep); } /* ---------------------------------------------------------------------- write to restart file for all Fixes with restart info (1) fixes that have global state (2) fixes that store per-atom quantities ------------------------------------------------------------------------- */ void Modify::write_restart(FILE *fp) { int me = comm->me; int count = 0; for (int i = 0; i < nfix; i++) if (fix[i]->restart_global) count++; if (me == 0) fwrite(&count,sizeof(int),1,fp); int n; for (int i = 0; i < nfix; i++) if (fix[i]->restart_global) { if (me == 0) { n = strlen(fix[i]->id) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(fix[i]->id,sizeof(char),n,fp); n = strlen(fix[i]->style) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(fix[i]->style,sizeof(char),n,fp); } fix[i]->write_restart(fp); } count = 0; for (int i = 0; i < nfix; i++) if (fix[i]->restart_peratom) count++; if (me == 0) fwrite(&count,sizeof(int),1,fp); for (int i = 0; i < nfix; i++) if (fix[i]->restart_peratom) { if (me == 0) { n = strlen(fix[i]->id) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(fix[i]->id,sizeof(char),n,fp); n = strlen(fix[i]->style) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(fix[i]->style,sizeof(char),n,fp); n = fix[i]->maxsize_restart(); fwrite(&n,sizeof(int),1,fp); } } } /* ---------------------------------------------------------------------- read in restart file data on all previously defined Fixes with restart info (1) fixes that have global state (2) fixes that store per-atom quantities return maxsize of extra info that will be stored with any atom ------------------------------------------------------------------------- */ int Modify::read_restart(FILE *fp) { // nfix_restart_global = # of restart entries with global state info int me = comm->me; if (me == 0) fread(&nfix_restart_global,sizeof(int),1,fp); MPI_Bcast(&nfix_restart_global,1,MPI_INT,0,world); // allocate space for each entry if (nfix_restart_global) { id_restart_global = new char*[nfix_restart_global]; style_restart_global = new char*[nfix_restart_global]; state_restart_global = new char*[nfix_restart_global]; } // read each entry and Bcast to all procs // each entry has id string, style string, chunk of state data int n; for (int i = 0; i < nfix_restart_global; i++) { if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); id_restart_global[i] = new char[n]; if (me == 0) fread(id_restart_global[i],sizeof(char),n,fp); MPI_Bcast(id_restart_global[i],n,MPI_CHAR,0,world); if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); style_restart_global[i] = new char[n]; if (me == 0) fread(style_restart_global[i],sizeof(char),n,fp); MPI_Bcast(style_restart_global[i],n,MPI_CHAR,0,world); if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); state_restart_global[i] = new char[n]; if (me == 0) fread(state_restart_global[i],sizeof(char),n,fp); MPI_Bcast(state_restart_global[i],n,MPI_CHAR,0,world); } // nfix_restart_peratom = # of restart entries with peratom info int maxsize = 0; if (me == 0) fread(&nfix_restart_peratom,sizeof(int),1,fp); MPI_Bcast(&nfix_restart_peratom,1,MPI_INT,0,world); // allocate space for each entry if (nfix_restart_peratom) { id_restart_peratom = new char*[nfix_restart_peratom]; style_restart_peratom = new char*[nfix_restart_peratom]; index_restart_peratom = new int[nfix_restart_peratom]; } // read each entry and Bcast to all procs // each entry has id string, style string, maxsize of one atom's data // set index = which set of extra data this fix represents for (int i = 0; i < nfix_restart_peratom; i++) { if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); id_restart_peratom[i] = new char[n]; if (me == 0) fread(id_restart_peratom[i],sizeof(char),n,fp); MPI_Bcast(id_restart_peratom[i],n,MPI_CHAR,0,world); if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); style_restart_peratom[i] = new char[n]; if (me == 0) fread(style_restart_peratom[i],sizeof(char),n,fp); MPI_Bcast(style_restart_peratom[i],n,MPI_CHAR,0,world); if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); maxsize += n; index_restart_peratom[i] = i; } return maxsize; } /* ---------------------------------------------------------------------- delete all lists of restart file Fix info ------------------------------------------------------------------------- */ void Modify::restart_deallocate() { if (nfix_restart_global) { for (int i = 0; i < nfix_restart_global; i++) { delete [] id_restart_global[i]; delete [] style_restart_global[i]; delete [] state_restart_global[i]; } delete [] id_restart_global; delete [] style_restart_global; delete [] state_restart_global; } if (nfix_restart_peratom) { for (int i = 0; i < nfix_restart_peratom; i++) { delete [] id_restart_peratom[i]; delete [] style_restart_peratom[i]; } delete [] id_restart_peratom; delete [] style_restart_peratom; delete [] index_restart_peratom; } nfix_restart_global = nfix_restart_peratom = 0; } /* ---------------------------------------------------------------------- create list of fix indices for fixes which match mask ------------------------------------------------------------------------- */ void Modify::list_init(int mask, int &n, int *&list) { delete [] list; n = 0; for (int i = 0; i < nfix; i++) if (fmask[i] & mask) n++; list = new int[n]; n = 0; for (int i = 0; i < nfix; i++) if (fmask[i] & mask) list[n++] = i; } /* ---------------------------------------------------------------------- create list of fix indices for end_of_step fixes also create end_of_step_every[] ------------------------------------------------------------------------- */ void Modify::list_init_end_of_step(int mask, int &n, int *&list) { delete [] list; delete [] end_of_step_every; n = 0; for (int i = 0; i < nfix; i++) if (fmask[i] & mask) n++; list = new int[n]; end_of_step_every = new int[n]; n = 0; for (int i = 0; i < nfix; i++) if (fmask[i] & mask) { list[n] = i; end_of_step_every[n++] = fix[i]->nevery; } } /* ---------------------------------------------------------------------- create list of fix indices for thermo energy fixes only added to list if fix has THERMO_ENERGY mask and its thermo_energy flag was set via fix_modify ------------------------------------------------------------------------- */ void Modify::list_init_thermo_energy(int mask, int &n, int *&list) { delete [] list; n = 0; for (int i = 0; i < nfix; i++) if (fmask[i] & mask && fix[i]->thermo_energy) n++; list = new int[n]; n = 0; for (int i = 0; i < nfix; i++) if (fmask[i] & mask && fix[i]->thermo_energy) list[n++] = i; } /* ---------------------------------------------------------------------- create list of compute indices for computes which store invocation times ------------------------------------------------------------------------- */ void Modify::list_init_compute() { delete [] list_timeflag; n_timeflag = 0; for (int i = 0; i < ncompute; i++) if (compute[i]->timeflag) n_timeflag++; list_timeflag = new int[n_timeflag]; n_timeflag = 0; for (int i = 0; i < ncompute; i++) if (compute[i]->timeflag) list_timeflag[n_timeflag++] = i; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory from all fixes ------------------------------------------------------------------------- */ bigint Modify::memory_usage() { bigint bytes = 0; for (int i = 0; i < nfix; i++) bytes += static_cast<bigint> (fix[i]->memory_usage()); for (int i = 0; i < ncompute; i++) bytes += static_cast<bigint> (compute[i]->memory_usage()); return bytes; } diff --git a/src/velocity.cpp b/src/velocity.cpp index e69b6d67a..eb64b8cc9 100644 --- a/src/velocity.cpp +++ b/src/velocity.cpp @@ -1,797 +1,799 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, 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. ------------------------------------------------------------------------- */ #include "lmptype.h" #include "mpi.h" #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "velocity.h" #include "atom.h" #include "update.h" #include "domain.h" #include "lattice.h" #include "input.h" #include "variable.h" #include "force.h" #include "modify.h" #include "compute.h" #include "compute_temp.h" #include "random_park.h" #include "group.h" #include "comm.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{CREATE,SET,SCALE,RAMP,ZERO}; enum{ALL,LOCAL,GEOM}; enum{NONE,CONSTANT,EQUAL,ATOM}; #define WARMUP 100 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ Velocity::Velocity(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- */ void Velocity::command(int narg, char **arg) { if (narg < 2) error->all(FLERR,"Illegal velocity command"); if (domain->box_exist == 0) error->all(FLERR,"Velocity command before simulation box is defined"); if (atom->natoms == 0) error->all(FLERR,"Velocity command with no atoms existing"); // atom masses must all be set atom->check_mass(); // identify group igroup = group->find(arg[0]); if (igroup == -1) error->all(FLERR,"Could not find velocity group ID"); groupbit = group->bitmask[igroup]; // identify style if (strcmp(arg[1],"create") == 0) style = CREATE; else if (strcmp(arg[1],"set") == 0) style = SET; else if (strcmp(arg[1],"scale") == 0) style = SCALE; else if (strcmp(arg[1],"ramp") == 0) style = RAMP; else if (strcmp(arg[1],"zero") == 0) style = ZERO; else error->all(FLERR,"Illegal velocity command"); // set defaults temperature = NULL; dist_flag = 0; sum_flag = 0; momentum_flag = 1; rotation_flag = 0; loop_flag = ALL; scale_flag = 1; // read options from end of input line // change defaults as options specify if (style == CREATE) options(narg-4,&arg[4]); else if (style == SET) options(narg-5,&arg[5]); else if (style == SCALE) options(narg-3,&arg[3]); else if (style == RAMP) options(narg-8,&arg[8]); else if (style == ZERO) options(narg-3,&arg[3]); // initialize velocities based on style // create() invoked differently, so can be called externally if (style == CREATE) { double t_desired = atof(arg[2]); int seed = atoi(arg[3]); create(t_desired,seed); } else if (style == SET) set(narg-2,&arg[2]); else if (style == SCALE) scale(narg-2,&arg[2]); else if (style == RAMP) ramp(narg-2,&arg[2]); else if (style == ZERO) zero(narg-2,&arg[2]); } /* ---------------------------------------------------------------------- initialization of defaults before calling velocity methods externaly ------------------------------------------------------------------------- */ void Velocity::init_external(const char *extgroup) { igroup = group->find(extgroup); if (igroup == -1) error->all(FLERR,"Could not find velocity group ID"); groupbit = group->bitmask[igroup]; temperature = NULL; dist_flag = 0; sum_flag = 0; momentum_flag = 1; rotation_flag = 0; loop_flag = ALL; scale_flag = 1; } /* ---------------------------------------------------------------------- */ void Velocity::create(double t_desired, int seed) { int i; if (seed <= 0) error->all(FLERR,"Illegal velocity create command"); // if temperature = NULL, create a new ComputeTemp with the velocity group int tflag = 0; if (temperature == NULL) { char **arg = new char*[3]; arg[0] = (char *) "velocity_temp"; arg[1] = group->names[igroup]; arg[2] = (char *) "temp"; temperature = new ComputeTemp(lmp,3,arg); tflag = 1; delete [] arg; } // initialize temperature computation // warn if groups don't match if (igroup != temperature->igroup && comm->me == 0) error->warning(FLERR,"Mismatch between velocity and compute groups"); temperature->init(); + temperature->setup(); // store a copy of current velocities double **v = atom->v; int nlocal = atom->nlocal; double **vhold; memory->create(vhold,nlocal,3,"velocity:vnew"); for (i = 0; i < nlocal; i++) { vhold[i][0] = v[i][0]; vhold[i][1] = v[i][1]; vhold[i][2] = v[i][2]; } // create new velocities, in uniform or gaussian distribution // loop option determines looping style, ALL is default // ALL = loop over all natoms, only set those I own via atom->map // cannot do this if atom IDs do not span 1-Natoms (some were deleted) // will produce same V, independent of P, if atoms were read-in // will NOT produce same V, independent of P, if used create_atoms // LOCAL = only loop over my atoms, adjust RNG to be proc-specific // will never produce same V, independent of P // GEOM = only loop over my atoms // choose RNG for each atom based on its xyz coord (geometry) // via random->reset() // will always produce same V, independent of P // adjust by factor for atom mass // for 2d, set Vz to 0.0 double *rmass = atom->rmass; double *mass = atom->mass; int *type = atom->type; int *mask = atom->mask; int dimension = domain->dimension; int m; double vx,vy,vz,factor; RanPark *random; if (loop_flag == ALL) { // create an atom map if one doesn't exist already int mapflag = 0; if (atom->map_style == 0) { mapflag = 1; atom->map_style = 1; atom->nghost = 0; atom->map_init(); atom->map_set(); } // error check if (atom->natoms > MAXSMALLINT) error->all(FLERR,"Too big a problem to use velocity create loop all"); if (atom->tag_enable == 0) error->all(FLERR, "Cannot use velocity create loop all unless atoms have IDs"); if (atom->tag_consecutive() == 0) error->all(FLERR, "Atom IDs must be consecutive for velocity create loop all"); // loop over all atoms in system // generate RNGs for all atoms, only assign to ones I own // use either per-type mass or per-atom rmass random = new RanPark(lmp,seed); int natoms = static_cast<int> (atom->natoms); for (i = 1; i <= natoms; i++) { if (dist_flag == 0) { vx = random->uniform(); vy = random->uniform(); vz = random->uniform(); } else { vx = random->gaussian(); vy = random->gaussian(); vz = random->gaussian(); } m = atom->map(i); if (m >= 0 && m < nlocal) { if (mask[m] & groupbit) { if (rmass) factor = 1.0/sqrt(rmass[m]); else factor = 1.0/sqrt(mass[type[m]]); v[m][0] = vx * factor; v[m][1] = vy * factor; if (dimension == 3) v[m][2] = vz * factor; else v[m][2] = 0.0; } } } // delete temporary atom map if (mapflag) { atom->map_delete(); atom->map_style = 0; } } else if (loop_flag == LOCAL) { random = new RanPark(lmp,seed + comm->me); for (i = 0; i < WARMUP; i++) random->uniform(); for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { if (dist_flag == 0) { vx = random->uniform(); vy = random->uniform(); vz = random->uniform(); } else { vx = random->gaussian(); vy = random->gaussian(); vz = random->gaussian(); } if (rmass) factor = 1.0/sqrt(rmass[i]); else factor = 1.0/sqrt(mass[type[i]]); v[i][0] = vx * factor; v[i][1] = vy * factor; if (dimension == 3) v[i][2] = vz * factor; else v[i][2] = 0.0; } } } else if (loop_flag == GEOM) { random = new RanPark(lmp,1); double **x = atom->x; for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { random->reset(seed,x[i]); if (dist_flag == 0) { vx = random->uniform(); vy = random->uniform(); vz = random->uniform(); } else { vx = random->gaussian(); vy = random->gaussian(); vz = random->gaussian(); } if (rmass) factor = 1.0/sqrt(rmass[i]); else factor = 1.0/sqrt(mass[type[i]]); v[i][0] = vx * factor; v[i][1] = vy * factor; if (dimension == 3) v[i][2] = vz * factor; else v[i][2] = 0.0; } } } // apply momentum and rotation zeroing if (momentum_flag) zero_momentum(); if (rotation_flag) zero_rotation(); // scale temp to desired value double t = temperature->compute_scalar(); rescale(t,t_desired); // if sum_flag set, add back in previous velocities if (sum_flag) { for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { v[i][0] += vhold[i][0]; v[i][1] += vhold[i][1]; v[i][2] += vhold[i][2]; } } } // free local memory // if temperature was created, delete it memory->destroy(vhold); delete random; if (tflag) delete temperature; } /* ---------------------------------------------------------------------- */ void Velocity::set(int narg, char **arg) { int xstyle,ystyle,zstyle,varflag; double vx,vy,vz; char *xstr,*ystr,*zstr; int xvar,yvar,zvar; // parse 3 args xstyle = ystyle = zstyle = CONSTANT; xstr = ystr = zstr = NULL; if (strstr(arg[0],"v_") == arg[0]) { int n = strlen(&arg[0][2]) + 1; xstr = new char[n]; strcpy(xstr,&arg[0][2]); } else if (strcmp(arg[0],"NULL") == 0) xstyle = NONE; else vx = atof(arg[0]); if (strstr(arg[1],"v_") == arg[1]) { int n = strlen(&arg[1][2]) + 1; ystr = new char[n]; strcpy(ystr,&arg[1][2]); } else if (strcmp(arg[1],"NULL") == 0) ystyle = NONE; else vy = atof(arg[1]); if (strstr(arg[2],"v_") == arg[2]) { int n = strlen(&arg[2][2]) + 1; zstr = new char[n]; strcpy(zstr,&arg[2][2]); } else if (strcmp(arg[2],"NULL") == 0) zstyle = NONE; else vz = atof(arg[2]); // set and apply scale factors xscale = yscale = zscale = 1.0; if (xstyle && !xstr) { if (scale_flag && domain->lattice == NULL) error->all(FLERR,"Use of velocity with undefined lattice"); if (scale_flag) xscale = domain->lattice->xlattice; vx *= xscale; } if (ystyle && !ystr) { if (scale_flag && domain->lattice == NULL) error->all(FLERR,"Use of velocity with undefined lattice"); if (scale_flag) yscale = domain->lattice->ylattice; vy *= yscale; } if (zstyle && !zstr) { if (scale_flag && domain->lattice == NULL) error->all(FLERR,"Use of velocity with undefined lattice"); if (scale_flag) zscale = domain->lattice->zlattice; vz *= zscale; } // check variables if (xstr) { xvar = input->variable->find(xstr); if (xvar < 0) error->all(FLERR,"Variable name for velocity set does not exist"); if (input->variable->equalstyle(xvar)) xstyle = EQUAL; else if (input->variable->atomstyle(xvar)) xstyle = ATOM; else error->all(FLERR,"Variable for velocity set is invalid style"); } if (ystr) { yvar = input->variable->find(ystr); if (yvar < 0) error->all(FLERR,"Variable name for velocity set does not exist"); if (input->variable->equalstyle(yvar)) ystyle = EQUAL; else if (input->variable->atomstyle(yvar)) ystyle = ATOM; else error->all(FLERR,"Variable for velocity set is invalid style"); } if (zstr) { zvar = input->variable->find(zstr); if (zvar < 0) error->all(FLERR,"Variable name for velocity set does not exist"); if (input->variable->equalstyle(zvar)) zstyle = EQUAL; else if (input->variable->atomstyle(zvar)) zstyle = ATOM; else error->all(FLERR,"Variable for velocity set is invalid style"); } if (xstyle == ATOM || ystyle == ATOM || zstyle == ATOM) varflag = ATOM; else if (xstyle == EQUAL || ystyle == EQUAL || zstyle == EQUAL) varflag = EQUAL; else varflag = CONSTANT; // error check for 2d models if (domain->dimension == 2) { if (zstyle == CONSTANT && vz != 0.0) error->all(FLERR,"Cannot set non-zero z velocity for 2d simulation"); if (zstyle == EQUAL || zstyle == ATOM) error->all(FLERR,"Cannot set variable z velocity for 2d simulation"); } // allocate vfield array if necessary double **vfield = NULL; if (varflag == ATOM) memory->create(vfield,atom->nlocal,3,"velocity:vfield"); // set velocities via constants double **v = atom->v; int *mask = atom->mask; int nlocal = atom->nlocal; if (varflag == CONSTANT) { for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { if (sum_flag == 0) { if (xstyle) v[i][0] = vx; if (ystyle) v[i][1] = vy; if (zstyle) v[i][2] = vz; } else { if (xstyle) v[i][0] += vx; if (ystyle) v[i][1] += vy; if (zstyle) v[i][2] += vz; } } } // set velocities via variables } else { if (xstyle == EQUAL) vx = input->variable->compute_equal(xvar); else if (xstyle == ATOM && vfield) input->variable->compute_atom(xvar,igroup,&vfield[0][0],3,0); if (ystyle == EQUAL) vy = input->variable->compute_equal(yvar); else if (ystyle == ATOM && vfield) input->variable->compute_atom(yvar,igroup,&vfield[0][1],3,0); if (zstyle == EQUAL) vz = input->variable->compute_equal(zvar); else if (zstyle == ATOM && vfield) input->variable->compute_atom(zvar,igroup,&vfield[0][2],3,0); for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { if (sum_flag == 0) { if (xstyle == ATOM) v[i][0] = vfield[i][0]; else if (xstyle) v[i][0] = vx; if (ystyle == ATOM) v[i][1] = vfield[i][1]; else if (ystyle) v[i][1] = vy; if (zstyle == ATOM) v[i][2] = vfield[i][2]; else if (zstyle) v[i][2] = vz; } else { if (xstyle == ATOM) v[i][0] += vfield[i][0]; else if (xstyle) v[i][0] += vx; if (ystyle == ATOM) v[i][1] += vfield[i][1]; else if (ystyle) v[i][1] += vy; if (zstyle == ATOM) v[i][2] += vfield[i][2]; else if (zstyle) v[i][2] += vz; } } } // clean up delete [] xstr; delete [] ystr; delete [] zstr; memory->destroy(vfield); } /* ---------------------------------------------------------------------- rescale velocities of a group after computing its temperature ------------------------------------------------------------------------- */ void Velocity::scale(int narg, char **arg) { double t_desired = atof(arg[0]); // if temperature = NULL, create a new ComputeTemp with the velocity group int tflag = 0; if (temperature == NULL) { char **arg = new char*[3]; arg[0] = (char *) "velocity_temp"; arg[1] = group->names[igroup]; arg[2] = (char *) "temp"; temperature = new ComputeTemp(lmp,3,arg); tflag = 1; delete [] arg; } // initialize temperature computation // warn if groups don't match if (igroup != temperature->igroup && comm->me == 0) error->warning(FLERR,"Mismatch between velocity and compute groups"); temperature->init(); + temperature->setup(); // scale temp to desired value double t = temperature->compute_scalar(); rescale(t,t_desired); // if temperature was created, delete it if (tflag) delete temperature; } /* ---------------------------------------------------------------------- apply a ramped set of velocities ------------------------------------------------------------------------- */ void Velocity::ramp(int narg, char **arg) { // set scale factors if (scale_flag && domain->lattice == NULL) error->all(FLERR,"Use of velocity with undefined lattice"); if (scale_flag) { xscale = domain->lattice->xlattice; yscale = domain->lattice->ylattice; zscale = domain->lattice->zlattice; } else xscale = yscale = zscale = 1.0; // parse args int v_dim; if (strcmp(arg[0],"vx") == 0) v_dim = 0; else if (strcmp(arg[0],"vy") == 0) v_dim = 1; else if (strcmp(arg[0],"vz") == 0) v_dim = 2; else error->all(FLERR,"Illegal velocity command"); if (v_dim == 2 && domain->dimension == 2) error->all(FLERR,"Velocity ramp in z for a 2d problem"); double v_lo,v_hi; if (v_dim == 0) { v_lo = xscale*atof(arg[1]); v_hi = xscale*atof(arg[2]); } else if (v_dim == 1) { v_lo = yscale*atof(arg[1]); v_hi = yscale*atof(arg[2]); } else if (v_dim == 2) { v_lo = zscale*atof(arg[1]); v_hi = zscale*atof(arg[2]); } int coord_dim; if (strcmp(arg[3],"x") == 0) coord_dim = 0; else if (strcmp(arg[3],"y") == 0) coord_dim = 1; else if (strcmp(arg[3],"z") == 0) coord_dim = 2; else error->all(FLERR,"Illegal velocity command"); double coord_lo,coord_hi; if (coord_dim == 0) { coord_lo = xscale*atof(arg[4]); coord_hi = xscale*atof(arg[5]); } else if (coord_dim == 1) { coord_lo = yscale*atof(arg[4]); coord_hi = yscale*atof(arg[5]); } else if (coord_dim == 2) { coord_lo = zscale*atof(arg[4]); coord_hi = zscale*atof(arg[5]); } // vramp = ramped velocity component for v_dim // add or set based on sum_flag double **x = atom->x; double **v = atom->v; int *mask = atom->mask; int nlocal = atom->nlocal; double fraction,vramp; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { fraction = (x[i][coord_dim] - coord_lo) / (coord_hi - coord_lo); fraction = MAX(fraction,0.0); fraction = MIN(fraction,1.0); vramp = v_lo + fraction*(v_hi - v_lo); if (sum_flag) v[i][v_dim] += vramp; else v[i][v_dim] = vramp; } } /* ---------------------------------------------------------------------- zero linear or angular momentum of a group ------------------------------------------------------------------------- */ void Velocity::zero(int narg, char **arg) { if (strcmp(arg[0],"linear") == 0) zero_momentum(); else if (strcmp(arg[0],"angular") == 0) zero_rotation(); else error->all(FLERR,"Illegal velocity command"); } /* ---------------------------------------------------------------------- rescale velocities of group atoms to t_new from t_old ------------------------------------------------------------------------- */ void Velocity::rescale(double t_old, double t_new) { if (t_old == 0.0) error->all(FLERR,"Attempting to rescale a 0.0 temperature"); double factor = sqrt(t_new/t_old); double **v = atom->v; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { v[i][0] *= factor; v[i][1] *= factor; v[i][2] *= factor; } } /* ---------------------------------------------------------------------- zero the linear momentum of a group of atoms by adjusting v by -Vcm ------------------------------------------------------------------------- */ void Velocity::zero_momentum() { // cannot have 0 atoms in group if (group->count(igroup) == 0) error->all(FLERR,"Cannot zero momentum of 0 atoms"); // compute velocity of center-of-mass of group double masstotal = group->mass(igroup); double vcm[3]; group->vcm(igroup,masstotal,vcm); // adjust velocities by vcm to zero linear momentum double **v = atom->v; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { v[i][0] -= vcm[0]; v[i][1] -= vcm[1]; v[i][2] -= vcm[2]; } } /* ---------------------------------------------------------------------- zero the angular momentum of a group of atoms by adjusting v by -(w x r) ------------------------------------------------------------------------- */ void Velocity::zero_rotation() { int i; // cannot have 0 atoms in group if (group->count(igroup) == 0) error->all(FLERR,"Cannot zero momentum of 0 atoms"); // compute omega (angular velocity) of group around center-of-mass double xcm[3],angmom[3],inertia[3][3],omega[3]; double masstotal = group->mass(igroup); group->xcm(igroup,masstotal,xcm); group->angmom(igroup,xcm,angmom); group->inertia(igroup,xcm,inertia); group->omega(angmom,inertia,omega); // adjust velocities to zero omega // vnew_i = v_i - w x r_i // must use unwrapped coords to compute r_i correctly double **x = atom->x; double **v = atom->v; int *mask = atom->mask; tagint *image = atom->image; int nlocal = atom->nlocal; double dx,dy,dz; double unwrap[3]; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { domain->unmap(x[i],image[i],unwrap); dx = unwrap[0]- xcm[0]; dy = unwrap[1] - xcm[1]; dz = unwrap[2] - xcm[2]; v[i][0] -= omega[1]*dz - omega[2]*dy; v[i][1] -= omega[2]*dx - omega[0]*dz; v[i][2] -= omega[0]*dy - omega[1]*dx; } } /* ---------------------------------------------------------------------- parse optional parameters at end of velocity input line ------------------------------------------------------------------------- */ void Velocity::options(int narg, char **arg) { if (narg < 0) error->all(FLERR,"Illegal velocity command"); int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"dist") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command"); if (strcmp(arg[iarg+1],"uniform") == 0) dist_flag = 0; else if (strcmp(arg[iarg+1],"gaussian") == 0) dist_flag = 1; else error->all(FLERR,"Illegal velocity command"); iarg += 2; } else if (strcmp(arg[iarg],"sum") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command"); if (strcmp(arg[iarg+1],"no") == 0) sum_flag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) sum_flag = 1; else error->all(FLERR,"Illegal velocity command"); iarg += 2; } else if (strcmp(arg[iarg],"mom") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command"); if (strcmp(arg[iarg+1],"no") == 0) momentum_flag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) momentum_flag = 1; else error->all(FLERR,"Illegal velocity command"); iarg += 2; } else if (strcmp(arg[iarg],"rot") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command"); if (strcmp(arg[iarg+1],"no") == 0) rotation_flag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) rotation_flag = 1; else error->all(FLERR,"Illegal velocity command"); iarg += 2; } else if (strcmp(arg[iarg],"temp") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command"); int icompute; for (icompute = 0; icompute < modify->ncompute; icompute++) if (strcmp(arg[iarg+1],modify->compute[icompute]->id) == 0) break; if (icompute == modify->ncompute) error->all(FLERR,"Could not find velocity temperature ID"); temperature = modify->compute[icompute]; if (temperature->tempflag == 0) error->all(FLERR, "Velocity temperature ID does not compute temperature"); iarg += 2; } else if (strcmp(arg[iarg],"loop") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command"); if (strcmp(arg[iarg+1],"all") == 0) loop_flag = ALL; else if (strcmp(arg[iarg+1],"local") == 0) loop_flag = LOCAL; else if (strcmp(arg[iarg+1],"geom") == 0) loop_flag = GEOM; else error->all(FLERR,"Illegal velocity command"); iarg += 2; } else if (strcmp(arg[iarg],"units") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command"); if (strcmp(arg[iarg+1],"box") == 0) scale_flag = 0; else if (strcmp(arg[iarg+1],"lattice") == 0) scale_flag = 1; else error->all(FLERR,"Illegal velocity command"); iarg += 2; } else error->all(FLERR,"Illegal velocity command"); } }