forked from lijiext/lammps
1421 lines
43 KiB
C++
1421 lines
43 KiB
C++
/* ----------------------------------------------------------------------
|
|
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
|
www.cs.sandia.gov/~sjplimp/lammps.html
|
|
Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories
|
|
|
|
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 "math.h"
|
|
#include "stdlib.h"
|
|
#include "string.h"
|
|
#include "limits.h"
|
|
#include "neighbor.h"
|
|
#include "atom.h"
|
|
#include "force.h"
|
|
#include "pair.h"
|
|
#include "domain.h"
|
|
#include "group.h"
|
|
#include "modify.h"
|
|
#include "fix.h"
|
|
#include "update.h"
|
|
#include "respa.h"
|
|
#include "output.h"
|
|
#include "memory.h"
|
|
#include "error.h"
|
|
|
|
#define PGDELTA 1
|
|
#define LB_FACTOR 1.5
|
|
#define SMALL 1.0e-6
|
|
#define EXDELTA 1
|
|
|
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
|
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
Neighbor::Neighbor()
|
|
{
|
|
MPI_Comm_rank(world,&me);
|
|
MPI_Comm_size(world,&nprocs);
|
|
|
|
style = 1;
|
|
every = 1;
|
|
delay = 10;
|
|
dist_check = 1;
|
|
pgsize = 10000;
|
|
oneatom = 2000;
|
|
|
|
maxlocal = 0;
|
|
|
|
cutneighsq = NULL;
|
|
fixchecklist = NULL;
|
|
|
|
// last neighbor info
|
|
|
|
maxhold = 0;
|
|
xhold = NULL;
|
|
|
|
// pair exclusion list info
|
|
|
|
nex_type = maxex_type = 0;
|
|
ex1_type = ex2_type = NULL;
|
|
ex_type = NULL;
|
|
|
|
nex_group = maxex_group = 0;
|
|
ex1_group = ex2_group = ex1_bit = ex2_bit = NULL;
|
|
|
|
nex_mol = maxex_mol = 0;
|
|
ex_mol_group = ex_mol_bit = NULL;
|
|
|
|
// bin info
|
|
|
|
maxhead = 0;
|
|
binhead = NULL;
|
|
maxbin = 0;
|
|
bins = NULL;
|
|
|
|
maxstencil = 0;
|
|
stencil = NULL;
|
|
maxstencil_full = 0;
|
|
stencil_full = NULL;
|
|
|
|
// half neighbor list info
|
|
|
|
half = half_command = 0;
|
|
maxpage = 0;
|
|
numneigh = NULL;
|
|
firstneigh = NULL;
|
|
pages = NULL;
|
|
|
|
// full neighbor list info
|
|
|
|
full = 0;
|
|
maxpage_full = 0;
|
|
numneigh_full = NULL;
|
|
firstneigh_full = NULL;
|
|
pages_full = NULL;
|
|
|
|
// shear history neighbor list info
|
|
|
|
history = -1;
|
|
firsttouch = NULL;
|
|
firstshear = NULL;
|
|
pages_touch = NULL;
|
|
pages_shear = NULL;
|
|
|
|
// multiple respa neighbor list info
|
|
|
|
respa = 0;
|
|
maxpage_inner = 0;
|
|
maxpage_middle = 0;
|
|
numneigh_inner = NULL;
|
|
firstneigh_inner = NULL;
|
|
pages_inner = NULL;
|
|
numneigh_middle = NULL;
|
|
firstneigh_middle = NULL;
|
|
pages_middle = NULL;
|
|
|
|
// bond list info
|
|
|
|
maxbond = 0;
|
|
bondlist = NULL;
|
|
maxangle = 0;
|
|
anglelist = NULL;
|
|
maxdihedral = 0;
|
|
dihedrallist = NULL;
|
|
maximproper = 0;
|
|
improperlist = NULL;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
Neighbor::~Neighbor()
|
|
{
|
|
memory->destroy_2d_double_array(cutneighsq);
|
|
delete [] fixchecklist;
|
|
memory->destroy_2d_double_array(xhold);
|
|
|
|
memory->sfree(ex1_type);
|
|
memory->sfree(ex2_type);
|
|
memory->destroy_2d_int_array(ex_type);
|
|
|
|
memory->sfree(ex1_group);
|
|
memory->sfree(ex2_group);
|
|
delete [] ex1_bit;
|
|
delete [] ex2_bit;
|
|
|
|
memory->sfree(ex_mol_group);
|
|
delete [] ex_mol_bit;
|
|
|
|
memory->sfree(binhead);
|
|
memory->sfree(bins);
|
|
memory->sfree(stencil);
|
|
memory->sfree(stencil_full);
|
|
|
|
memory->destroy_2d_int_array(bondlist);
|
|
memory->destroy_2d_int_array(anglelist);
|
|
memory->destroy_2d_int_array(dihedrallist);
|
|
memory->destroy_2d_int_array(improperlist);
|
|
|
|
memory->sfree(numneigh);
|
|
memory->sfree(firstneigh);
|
|
for (int i = 0; i < maxpage; i++) memory->sfree(pages[i]);
|
|
memory->sfree(pages);
|
|
|
|
memory->sfree(numneigh_full);
|
|
memory->sfree(firstneigh_full);
|
|
for (int i = 0; i < maxpage_full; i++) memory->sfree(pages_full[i]);
|
|
memory->sfree(pages_full);
|
|
|
|
if (history >= 0) {
|
|
memory->sfree(firsttouch);
|
|
memory->sfree(firstshear);
|
|
for (int i = 0; i < maxpage; i++) memory->sfree(pages_touch[i]);
|
|
for (int i = 0; i < maxpage; i++) memory->sfree(pages_shear[i]);
|
|
memory->sfree(pages_touch);
|
|
memory->sfree(pages_shear);
|
|
}
|
|
|
|
if (respa) {
|
|
memory->sfree(numneigh_inner);
|
|
memory->sfree(firstneigh_inner);
|
|
for (int i = 0; i < maxpage_inner; i++) memory->sfree(pages_inner[i]);
|
|
memory->sfree(pages_inner);
|
|
memory->sfree(numneigh_middle);
|
|
memory->sfree(firstneigh_middle);
|
|
for (int i = 0; i < maxpage_middle; i++) memory->sfree(pages_middle[i]);
|
|
memory->sfree(pages_middle);
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void Neighbor::init()
|
|
{
|
|
int i,j,m,n;
|
|
|
|
ncalls = ndanger = 0;
|
|
|
|
// error check
|
|
|
|
if (delay > 0 && (delay % every) != 0)
|
|
error->all("Neighbor delay must be 0 or multiple of every setting");
|
|
|
|
// ------------------------------------------------------------------
|
|
// settings
|
|
|
|
// set cutneigh and trigger distance for reneighboring
|
|
|
|
if (force->pair) cutneigh = force->pair->cutforce + skin;
|
|
else cutneigh = skin;
|
|
triggersq = 0.25*skin*skin;
|
|
if (cutneighsq == NULL)
|
|
cutneighsq = memory->create_2d_double_array(atom->ntypes+1,atom->ntypes+1,
|
|
"neigh:cutneighsq");
|
|
|
|
// set neighbor cutoffs with skin included
|
|
// if no pair defined, cutneigh is just skin
|
|
|
|
n = atom->ntypes;
|
|
|
|
if (force->pair) {
|
|
double cutoff;
|
|
double **cutsq = force->pair->cutsq;
|
|
for (i = 1; i <= n; i++)
|
|
for (j = i; j <= n; j++) {
|
|
cutoff = sqrt(cutsq[i][j]);
|
|
cutneighsq[i][j] = (cutoff+skin) * (cutoff+skin);
|
|
cutneighsq[j][i] = cutneighsq[i][j];
|
|
}
|
|
} else {
|
|
for (i = 1; i <= n; i++)
|
|
for (j = i; j <= n; j++) {
|
|
cutneighsq[i][j] = skin*skin;
|
|
cutneighsq[j][i] = cutneighsq[i][j];
|
|
}
|
|
}
|
|
|
|
// check other classes that can induce reneighboring in decide()
|
|
|
|
restart_check = 0;
|
|
if (output->restart_every) restart_check = 1;
|
|
|
|
delete [] fixchecklist;
|
|
fixchecklist = NULL;
|
|
fixchecklist = new int[modify->nfix];
|
|
|
|
fix_check = 0;
|
|
for (i = 0; i < modify->nfix; i++)
|
|
if (modify->fix[i]->force_reneighbor)
|
|
fixchecklist[fix_check++] = i;
|
|
|
|
must_check = 0;
|
|
if (restart_check || fix_check) must_check = 1;
|
|
|
|
// set special_flag for 1-2, 1-3, 1-4 neighbors
|
|
// flag[0] is not used, flag[1] = 1-2, flag[2] = 1-3, flag[3] = 1-4
|
|
// flag = 0 if both LJ/Coulomb special values are 0.0
|
|
// flag = 1 if both LJ/Coulomb special values are 1.0
|
|
// flag = 2 otherwise or if KSpace solver is enabled
|
|
// (pairwise portion of KSpace solver uses all 1-2,1-3,1-4 neighbors)
|
|
|
|
if (force->special_lj[1] == 0.0 && force->special_coul[1] == 0.0)
|
|
special_flag[1] = 0;
|
|
else if (force->special_lj[1] == 1.0 && force->special_coul[1] == 1.0)
|
|
special_flag[1] = 1;
|
|
else special_flag[1] = 2;
|
|
|
|
if (force->special_lj[2] == 0.0 && force->special_coul[2] == 0.0)
|
|
special_flag[2] = 0;
|
|
else if (force->special_lj[2] == 1.0 && force->special_coul[2] == 1.0)
|
|
special_flag[2] = 1;
|
|
else special_flag[2] = 2;
|
|
|
|
if (force->special_lj[3] == 0.0 && force->special_coul[3] == 0.0)
|
|
special_flag[3] = 0;
|
|
else if (force->special_lj[3] == 1.0 && force->special_coul[3] == 1.0)
|
|
special_flag[3] = 1;
|
|
else special_flag[3] = 2;
|
|
|
|
if (force->kspace) special_flag[1] = special_flag[2] = special_flag[3] = 2;
|
|
|
|
// ------------------------------------------------------------------
|
|
// memory management
|
|
|
|
// free xhold and bins if not needed for this run
|
|
|
|
if (dist_check == 0) {
|
|
memory->destroy_2d_double_array(xhold);
|
|
maxhold = 0;
|
|
}
|
|
|
|
if (style == 0) {
|
|
memory->sfree(bins);
|
|
memory->sfree(binhead);
|
|
memory->sfree(stencil);
|
|
memory->sfree(stencil_full);
|
|
maxbin = maxhead = maxstencil = maxstencil_full = 0;
|
|
}
|
|
|
|
// 1st time allocation of xhold and bins
|
|
|
|
if (dist_check) {
|
|
if (maxhold == 0) {
|
|
maxhold = atom->nmax;
|
|
xhold = memory->create_2d_double_array(maxhold,3,"neigh:xhold");
|
|
}
|
|
}
|
|
|
|
if (style == 1) {
|
|
if (maxbin == 0) {
|
|
maxbin = atom->nmax;
|
|
bins = (int *) memory->smalloc(maxbin*sizeof(int),"bins");
|
|
}
|
|
}
|
|
|
|
// exclusion lists for type, group, molecule settings from neigh_modify
|
|
|
|
n = atom->ntypes;
|
|
|
|
if (nex_type == 0 && nex_group == 0 && nex_mol == 0) exclude = 0;
|
|
else exclude = 1;
|
|
|
|
if (nex_type) {
|
|
memory->destroy_2d_int_array(ex_type);
|
|
ex_type = (int **) memory->create_2d_int_array(n+1,n+1,"neigh:ex_type");
|
|
|
|
for (i = 1; i <= n; i++)
|
|
for (j = 1; j <= n; j++)
|
|
ex_type[i][j] = 0;
|
|
|
|
for (i = 0; i < nex_type; i++) {
|
|
if (ex1_type[i] <= 0 || ex1_type[i] > n ||
|
|
ex2_type[i] <= 0 || ex2_type[i] > n)
|
|
error->all("Invalid atom type in neighbor exclusion list");
|
|
ex_type[ex1_type[i]][ex2_type[i]] = 1;
|
|
ex_type[ex2_type[i]][ex1_type[i]] = 1;
|
|
}
|
|
}
|
|
|
|
if (nex_group) {
|
|
delete [] ex1_bit;
|
|
delete [] ex2_bit;
|
|
ex1_bit = new int[nex_group];
|
|
ex2_bit = new int[nex_group];
|
|
|
|
for (i = 0; i < nex_group; i++) {
|
|
ex1_bit[i] = group->bitmask[ex1_group[i]];
|
|
ex2_bit[i] = group->bitmask[ex2_group[i]];
|
|
}
|
|
}
|
|
|
|
if (nex_mol) {
|
|
delete [] ex_mol_bit;
|
|
ex_mol_bit = new int[nex_mol];
|
|
|
|
for (i = 0; i < nex_mol; i++)
|
|
ex_mol_bit[i] = group->bitmask[ex_mol_group[i]];
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// half and full pairwise neighbor lists
|
|
|
|
// determine whether to build half and full lists
|
|
|
|
maxlocal = atom->nmax;
|
|
int half_previous = half;
|
|
int full_previous = full;
|
|
|
|
half_once = full_once = 0;
|
|
half_every = full_every = 0;
|
|
if (force->pair) half_every = force->pair->neigh_half_every;
|
|
if (force->pair) full_every = force->pair->neigh_full_every;
|
|
|
|
for (i = 0; i < modify->nfix; i++) {
|
|
if (modify->fix[i]->neigh_half_every) half_every = 1;
|
|
if (modify->fix[i]->neigh_full_every) full_every = 1;
|
|
if (modify->fix[i]->neigh_half_once) half_once = 1;
|
|
if (modify->fix[i]->neigh_full_once) full_once = 1;
|
|
}
|
|
|
|
half = full = 0;
|
|
if (half_every || half_once || half_command) half = 1;
|
|
if (full_every || full_once) full = 1;
|
|
half = 1;
|
|
|
|
// setup/delete memory for half and full lists
|
|
|
|
if (half == 0 && half_previous) {
|
|
memory->sfree(numneigh);
|
|
memory->sfree(firstneigh);
|
|
for (i = 0; i < maxpage; i++) memory->sfree(pages[i]);
|
|
memory->sfree(pages);
|
|
pages = NULL;
|
|
maxpage = 0;
|
|
} else if (half && half_previous == 0) {
|
|
numneigh =
|
|
(int *) memory->smalloc(maxlocal*sizeof(int),"neigh:numneigh");
|
|
firstneigh =
|
|
(int **) memory->smalloc(maxlocal*sizeof(int *),"neigh:firstneigh");
|
|
add_pages(0);
|
|
} else if (half && half_previous) {
|
|
memory->sfree(numneigh);
|
|
memory->sfree(firstneigh);
|
|
numneigh =
|
|
(int *) memory->smalloc(maxlocal*sizeof(int),"neigh:numneigh");
|
|
firstneigh =
|
|
(int **) memory->smalloc(maxlocal*sizeof(int *),"neigh:firstneigh");
|
|
}
|
|
|
|
if (full == 0 && full_previous) {
|
|
memory->sfree(numneigh_full);
|
|
memory->sfree(firstneigh_full);
|
|
for (i = 0; i < maxpage_full; i++) memory->sfree(pages_full[i]);
|
|
memory->sfree(pages_full);
|
|
pages_full = NULL;
|
|
maxpage_full = 0;
|
|
} else if (full && full_previous == 0) {
|
|
numneigh_full =
|
|
(int *) memory->smalloc(maxlocal*sizeof(int),"neigh:numneigh_full");
|
|
firstneigh_full =
|
|
(int **) memory->smalloc(maxlocal*sizeof(int *),"neigh:firstneigh_full");
|
|
add_pages_full(0);
|
|
} else if (full && full_previous) {
|
|
memory->sfree(numneigh_full);
|
|
memory->sfree(firstneigh_full);
|
|
numneigh_full =
|
|
(int *) memory->smalloc(maxlocal*sizeof(int),"neigh:numneigh_full");
|
|
firstneigh_full =
|
|
(int **) memory->smalloc(maxlocal*sizeof(int *),"neigh:firstneigh_full");
|
|
}
|
|
|
|
// setup/delete memory for shear history neighbor lists
|
|
// history = index of granular shear history fix if it exists
|
|
|
|
int history_previous = history;
|
|
history = -1;
|
|
if (force->pair_match("gran/history") || force->pair_match("gran/hertzian"))
|
|
for (i = 0; i < modify->nfix; i++)
|
|
if (strcmp(modify->fix[i]->style,"SHEAR_HISTORY") == 0) history = i;
|
|
|
|
if (history == -1 && history_previous >= 0) {
|
|
memory->sfree(firsttouch);
|
|
memory->sfree(firstshear);
|
|
for (i = 0; i < maxpage; i++) memory->sfree(pages_touch[i]);
|
|
for (i = 0; i < maxpage; i++) memory->sfree(pages_shear[i]);
|
|
memory->sfree(pages_touch);
|
|
memory->sfree(pages_shear);
|
|
pages_touch = NULL;
|
|
pages_shear = NULL;
|
|
} else if (history >= 0 && history_previous == -1) {
|
|
firsttouch = (int **) memory->smalloc(maxlocal*sizeof(int *),"firsttouch");
|
|
firstshear = (double **)
|
|
memory->smalloc(maxlocal*sizeof(double *),"firstshear");
|
|
add_pages_history(0);
|
|
} else if (history >= 0 && history_previous >= 0) {
|
|
memory->sfree(firsttouch);
|
|
memory->sfree(firstshear);
|
|
firsttouch = (int **) memory->smalloc(maxlocal*sizeof(int *),"firsttouch");
|
|
firstshear = (double **)
|
|
memory->smalloc(maxlocal*sizeof(double *),"firstshear");
|
|
}
|
|
|
|
// setup/delete memory for rRESPA neighbor lists
|
|
// respa = 1 if rRESPA requires extra neighbor lists
|
|
// set neighbor cutoffs for multiple lists
|
|
|
|
int respa_previous = respa;
|
|
respa = 0;
|
|
if (update->whichflag == 0 && strcmp(update->integrate_style,"respa") == 0) {
|
|
if (((Respa *) update->integrate)->level_inner >= 0) respa = 1;
|
|
if (((Respa *) update->integrate)->level_middle >= 0) respa = 2;
|
|
}
|
|
|
|
if (respa && half_every == 0)
|
|
error->all("Cannot use rRESPA with full neighbor lists");
|
|
|
|
if (respa == 0 && respa_previous) {
|
|
memory->sfree(numneigh_inner);
|
|
memory->sfree(firstneigh_inner);
|
|
for (i = 0; i < maxpage; i++) memory->sfree(pages_inner[i]);
|
|
memory->sfree(pages_inner);
|
|
pages_inner = NULL;
|
|
maxpage_inner = 0;
|
|
if (respa_previous == 2) {
|
|
memory->sfree(numneigh_middle);
|
|
memory->sfree(firstneigh_middle);
|
|
for (i = 0; i < maxpage; i++) memory->sfree(pages_middle[i]);
|
|
memory->sfree(pages_middle);
|
|
pages_middle = NULL;
|
|
maxpage_middle = 0;
|
|
}
|
|
} else if (respa && respa_previous == 0) {
|
|
numneigh_inner = (int *)
|
|
memory->smalloc(maxlocal*sizeof(int),"neigh:numneigh_inner");
|
|
firstneigh_inner = (int **)
|
|
memory->smalloc(maxlocal*sizeof(int *),"neigh:firstneigh_inner");
|
|
add_pages_inner(0);
|
|
if (respa == 2) {
|
|
numneigh_middle = (int *)
|
|
memory->smalloc(maxlocal*sizeof(int),"neigh:numneigh_middle");
|
|
firstneigh_middle = (int **)
|
|
memory->smalloc(maxlocal*sizeof(int *),"neigh:firstneigh_middle");
|
|
add_pages_middle(0);
|
|
}
|
|
} else if (respa && respa_previous) {
|
|
memory->sfree(numneigh_inner);
|
|
memory->sfree(firstneigh_inner);
|
|
numneigh_inner = (int *)
|
|
memory->smalloc(maxlocal*sizeof(int),"neigh:numneigh_inner");
|
|
firstneigh_inner = (int **)
|
|
memory->smalloc(maxlocal*sizeof(int *),"neigh:firstneigh_inner");
|
|
if (respa == 2) {
|
|
memory->sfree(numneigh_middle);
|
|
memory->sfree(firstneigh_middle);
|
|
numneigh_middle = (int *)
|
|
memory->smalloc(maxlocal*sizeof(int),"neigh:numneigh_middle");
|
|
firstneigh_middle = (int **)
|
|
memory->smalloc(maxlocal*sizeof(int *),"neigh:firstneigh_middle");
|
|
}
|
|
}
|
|
|
|
if (respa) {
|
|
double *cut_respa = ((Respa *) update->integrate)->cutoff;
|
|
cut_inner_sq = (cut_respa[1] + skin) * (cut_respa[1] + skin);
|
|
cut_middle_sq = (cut_respa[3] + skin) * (cut_respa[3] + skin);
|
|
cut_middle_inside_sq = (cut_respa[0] - skin) * (cut_respa[0] - skin);
|
|
}
|
|
|
|
// set ptrs to correct half and full build functions
|
|
// cannot combine granular and rRESPA
|
|
|
|
if (half) {
|
|
if (strcmp(atom->style,"granular") == 0) {
|
|
if (style == 0) {
|
|
if (force->newton_pair == 0)
|
|
half_build = &Neighbor::granular_nsq_no_newton;
|
|
else half_build = &Neighbor::granular_nsq_newton;
|
|
} else if (style == 1) {
|
|
if (force->newton_pair == 0)
|
|
half_build = &Neighbor::granular_bin_no_newton;
|
|
else half_build = &Neighbor::granular_bin_newton;
|
|
}
|
|
} else if (respa) {
|
|
if (style == 0) {
|
|
if (force->newton_pair == 0)
|
|
half_build = &Neighbor::respa_nsq_no_newton;
|
|
else half_build = &Neighbor::respa_nsq_newton;
|
|
} else if (style == 1) {
|
|
if (force->newton_pair == 0)
|
|
half_build = &Neighbor::respa_bin_no_newton;
|
|
else half_build = &Neighbor::respa_bin_newton;
|
|
}
|
|
} else {
|
|
if (style == 0) {
|
|
if (force->newton_pair == 0) {
|
|
if (full_every) half_build = &Neighbor::half_full_no_newton;
|
|
else half_build = &Neighbor::half_nsq_no_newton;
|
|
} else {
|
|
if (full_every) half_build = &Neighbor::half_full_newton;
|
|
else half_build = &Neighbor::half_nsq_newton;
|
|
}
|
|
} else if (style == 1) {
|
|
if (force->newton_pair == 0) {
|
|
if (full_every) half_build = &Neighbor::half_full_no_newton;
|
|
else half_build = &Neighbor::half_bin_no_newton;
|
|
} else {
|
|
if (full_every) half_build = &Neighbor::half_full_newton;
|
|
else half_build = &Neighbor::half_bin_newton;
|
|
}
|
|
}
|
|
}
|
|
} else half_build = NULL;
|
|
|
|
if (full) {
|
|
if (style == 0) full_build = &Neighbor::full_nsq;
|
|
else full_build = &Neighbor::full_bin;
|
|
} else full_build = NULL;
|
|
|
|
// ------------------------------------------------------------------
|
|
// bond neighbor lists
|
|
|
|
// 1st time allocation of bond lists
|
|
|
|
if (atom->molecular && atom->nbonds && maxbond == 0) {
|
|
if (nprocs == 1) maxbond = atom->nbonds;
|
|
else maxbond = static_cast<int> (LB_FACTOR * atom->nbonds / nprocs);
|
|
bondlist = memory->create_2d_int_array(maxbond,3,"neigh:bondlist");
|
|
}
|
|
|
|
if (atom->molecular && atom->nangles && maxangle == 0) {
|
|
if (nprocs == 1) maxangle = atom->nangles;
|
|
else maxangle = static_cast<int> (LB_FACTOR * atom->nangles / nprocs);
|
|
anglelist = memory->create_2d_int_array(maxangle,4,"neigh:anglelist");
|
|
}
|
|
|
|
if (atom->molecular && atom->ndihedrals && maxdihedral == 0) {
|
|
if (nprocs == 1) maxdihedral = atom->ndihedrals;
|
|
else maxdihedral = static_cast<int>
|
|
(LB_FACTOR * atom->ndihedrals / nprocs);
|
|
dihedrallist =
|
|
memory->create_2d_int_array(maxdihedral,5,"neigh:dihedrallist");
|
|
}
|
|
|
|
if (atom->molecular && atom->nimpropers && maximproper == 0) {
|
|
if (nprocs == 1) maximproper = atom->nimpropers;
|
|
else maximproper = static_cast<int>
|
|
(LB_FACTOR * atom->nimpropers / nprocs);
|
|
improperlist =
|
|
memory->create_2d_int_array(maximproper,5,"neigh:improperlist");
|
|
}
|
|
|
|
// set flags that determine which bond neighboring routines to use
|
|
// SHAKE sets bonds and angles negative
|
|
// bond_quartic sets bonds to 0
|
|
// delete_bonds sets all interactions negative
|
|
|
|
|
|
int bond_off = 0;
|
|
int angle_off = 0;
|
|
for (i = 0; i < modify->nfix; i++)
|
|
if (strcmp(modify->fix[i]->style,"shake") == 0)
|
|
bond_off = angle_off = 1;
|
|
if (force->bond && force->bond_match("quartic")) bond_off = 1;
|
|
|
|
if (atom->bonds_allow) {
|
|
for (i = 0; i < atom->nlocal; i++) {
|
|
if (bond_off) break;
|
|
for (m = 0; m < atom->num_bond[i]; m++)
|
|
if (atom->bond_type[i][m] <= 0) bond_off = 1;
|
|
}
|
|
}
|
|
|
|
if (atom->angles_allow) {
|
|
for (i = 0; i < atom->nlocal; i++) {
|
|
if (angle_off) break;
|
|
for (m = 0; m < atom->num_angle[i]; m++)
|
|
if (atom->angle_type[i][m] <= 0) angle_off = 1;
|
|
}
|
|
}
|
|
|
|
int dihedral_off = 0;
|
|
if (atom->dihedrals_allow) {
|
|
for (i = 0; i < atom->nlocal; i++) {
|
|
if (dihedral_off) break;
|
|
for (m = 0; m < atom->num_dihedral[i]; m++)
|
|
if (atom->dihedral_type[i][m] <= 0) dihedral_off = 1;
|
|
}
|
|
}
|
|
|
|
int improper_off = 0;
|
|
if (atom->impropers_allow) {
|
|
for (i = 0; i < atom->nlocal; i++) {
|
|
if (improper_off) break;
|
|
for (m = 0; m < atom->num_improper[i]; m++)
|
|
if (atom->improper_type[i][m] <= 0) improper_off = 1;
|
|
}
|
|
}
|
|
|
|
// set ptrs to correct intra-molecular build functions
|
|
|
|
if (bond_off) bond_build = &Neighbor::bond_partial;
|
|
else bond_build = &Neighbor::bond_all;
|
|
|
|
if (angle_off) angle_build = &Neighbor::angle_partial;
|
|
else angle_build = &Neighbor::angle_all;
|
|
|
|
if (dihedral_off) dihedral_build = &Neighbor::dihedral_partial;
|
|
else dihedral_build = &Neighbor::dihedral_all;
|
|
|
|
if (improper_off) improper_build = &Neighbor::improper_partial;
|
|
else improper_build = &Neighbor::improper_all;
|
|
|
|
// set intra-molecular neighbor list counts to 0
|
|
// in case all are turned off but potential is still defined
|
|
|
|
nbondlist = nanglelist = ndihedrallist = nimproperlist = 0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
int Neighbor::decide()
|
|
{
|
|
if (must_check) {
|
|
int n = update->ntimestep;
|
|
if (restart_check && n == output->next_restart) return 1;
|
|
for (int i = 0; i < fix_check; i++)
|
|
if (n == modify->fix[fixchecklist[i]]->next_reneighbor) return 1;
|
|
}
|
|
|
|
ago++;
|
|
if (ago >= delay && ago % every == 0) {
|
|
if (dist_check == 0) return 1;
|
|
else return check_distance();
|
|
} else return 0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
int Neighbor::check_distance()
|
|
{
|
|
double delx,dely,delz,rsq;
|
|
|
|
int nlocal = atom->nlocal;
|
|
double **x = atom->x;
|
|
int flag = 0;
|
|
for (int i = 0; i < nlocal; i++) {
|
|
delx = x[i][0] - xhold[i][0];
|
|
dely = x[i][1] - xhold[i][1];
|
|
delz = x[i][2] - xhold[i][2];
|
|
rsq = delx*delx + dely*dely + delz*delz;
|
|
if (rsq > triggersq) flag = 1;
|
|
}
|
|
|
|
int flagall;
|
|
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_MAX,world);
|
|
if (flagall && ago == MAX(every,delay)) ndanger++;
|
|
return flagall;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
build all needed neighbor lists every few timesteps
|
|
half, full, bond lists are created as needed
|
|
------------------------------------------------------------------------- */
|
|
|
|
void Neighbor::build()
|
|
{
|
|
ago = 0;
|
|
ncalls++;
|
|
|
|
// store current nlocal used on this build (used by fix shear/history)
|
|
|
|
nlocal_neighbor = atom->nlocal;
|
|
|
|
// store current atom positions if needed
|
|
|
|
if (dist_check) {
|
|
double **x = atom->x;
|
|
int nlocal = atom->nlocal;
|
|
if (nlocal > maxhold) {
|
|
maxhold = atom->nmax;
|
|
memory->destroy_2d_double_array(xhold);
|
|
xhold = memory->create_2d_double_array(maxhold,3,"neigh:xhold");
|
|
}
|
|
for (int i = 0; i < nlocal; i++) {
|
|
xhold[i][0] = x[i][0];
|
|
xhold[i][1] = x[i][1];
|
|
xhold[i][2] = x[i][2];
|
|
}
|
|
}
|
|
|
|
// extend atom arrays if necessary
|
|
// check half/full instead of half_every/full_every so memory will be
|
|
// allocated correctly whenever build_half() and build_full() are called
|
|
|
|
if (atom->nlocal > maxlocal) {
|
|
maxlocal = atom->nmax;
|
|
|
|
if (half) {
|
|
memory->sfree(numneigh);
|
|
memory->sfree(firstneigh);
|
|
numneigh = (int *)
|
|
memory->smalloc(maxlocal*sizeof(int),"neigh:numneigh");
|
|
firstneigh = (int **)
|
|
memory->smalloc(maxlocal*sizeof(int *),"neigh:firstneigh");
|
|
}
|
|
|
|
if (full) {
|
|
memory->sfree(numneigh_full);
|
|
memory->sfree(firstneigh_full);
|
|
numneigh_full = (int *)
|
|
memory->smalloc(maxlocal*sizeof(int),"neigh:numneigh_full");
|
|
firstneigh_full = (int **)
|
|
memory->smalloc(maxlocal*sizeof(int *),"neigh:firstneigh_full");
|
|
}
|
|
|
|
if (history >= 0) {
|
|
memory->sfree(firsttouch);
|
|
memory->sfree(firstshear);
|
|
firsttouch = (int **)
|
|
memory->smalloc(maxlocal*sizeof(int *),"neigh:firsttouch");
|
|
firstshear = (double **)
|
|
memory->smalloc(maxlocal*sizeof(double *),"neigh:firstshear");
|
|
}
|
|
|
|
if (respa) {
|
|
memory->sfree(numneigh_inner);
|
|
memory->sfree(firstneigh_inner);
|
|
numneigh_inner = (int *)
|
|
memory->smalloc(maxlocal*sizeof(int),"neigh:numneigh_inner");
|
|
firstneigh_inner = (int **)
|
|
memory->smalloc(maxlocal*sizeof(int *),"neigh:firstneigh_inner");
|
|
if (respa == 2) {
|
|
memory->sfree(numneigh_middle);
|
|
memory->sfree(firstneigh_middle);
|
|
numneigh_middle = (int *)
|
|
memory->smalloc(maxlocal*sizeof(int),"neigh:numneigh_middle");
|
|
firstneigh_middle = (int **)
|
|
memory->smalloc(maxlocal*sizeof(int *),"neigh:firstneigh_middle");
|
|
}
|
|
}
|
|
}
|
|
|
|
// extend bin list if necessary
|
|
|
|
if (style && atom->nmax > maxbin) {
|
|
maxbin = atom->nmax;
|
|
memory->sfree(bins);
|
|
bins = (int *) memory->smalloc(maxbin*sizeof(int),"bins");
|
|
}
|
|
|
|
// list construction for pairs and bonds
|
|
// full comes first in case half is built from full
|
|
|
|
if (full_every) (this->*full_build)();
|
|
if (half_every) (this->*half_build)();
|
|
|
|
if (atom->molecular) {
|
|
if (atom->nbonds) (this->*bond_build)();
|
|
if (atom->nangles) (this->*angle_build)();
|
|
if (atom->ndihedrals) (this->*dihedral_build)();
|
|
if (atom->nimpropers) (this->*improper_build)();
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
one-time call to build a half neighbor list made by other classes
|
|
------------------------------------------------------------------------- */
|
|
|
|
void Neighbor::build_half()
|
|
{
|
|
(this->*half_build)();
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
one-time call to build a full neighbor list made by other classes
|
|
------------------------------------------------------------------------- */
|
|
|
|
void Neighbor::build_full()
|
|
{
|
|
(this->*full_build)();
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
setup neighbor binning parameters
|
|
bin numbering is global: 0 = 0.0 to binsize, 1 = binsize to 2*binsize
|
|
nbin-1 = prd-binsize to binsize
|
|
nbin = prd to prd+binsize
|
|
-1 = -binsize to 0.0
|
|
code will work for any binsize
|
|
since next(xyz) and stencil extend as far as necessary
|
|
binsize = 1/2 of cutoff is roughly optimal
|
|
prd must be filled exactly by integer # of bins
|
|
so procs on both sides of PBC see same bin boundary
|
|
mbinlo = lowest global bin any of my ghost atoms could fall into
|
|
mbinhi = highest global bin any of my ghost atoms could fall into
|
|
mbin = number of bins I need in a dimension
|
|
stencil() = bin offsets in 1d sense for stencil of surrounding bins
|
|
stencil_full() = bin offsets in 1d sense for stencil for full neighbor list
|
|
------------------------------------------------------------------------- */
|
|
|
|
void Neighbor::setup_bins()
|
|
{
|
|
double cutneighinv = 1.0/cutneigh;
|
|
|
|
// test for too many global bins in any dimension due to huge domain
|
|
|
|
if (2.0*domain->xprd*cutneighinv > INT_MAX ||
|
|
2.0*domain->yprd*cutneighinv > INT_MAX ||
|
|
2.0*domain->zprd*cutneighinv > INT_MAX)
|
|
error->all("Domain too large for neighbor bins");
|
|
|
|
// divide box into bins
|
|
// optimal size is roughly 1/2 the cutoff
|
|
|
|
nbinx = static_cast<int> (2.0*domain->xprd*cutneighinv);
|
|
nbiny = static_cast<int> (2.0*domain->yprd*cutneighinv);
|
|
if (force->dimension == 3)
|
|
nbinz = static_cast<int> (2.0*domain->zprd*cutneighinv);
|
|
else nbinz = 1;
|
|
|
|
if (nbinx == 0) nbinx = 1;
|
|
if (nbiny == 0) nbiny = 1;
|
|
if (nbinz == 0) nbinz = 1;
|
|
|
|
binsizex = domain->xprd/nbinx;
|
|
binsizey = domain->yprd/nbiny;
|
|
binsizez = domain->zprd/nbinz;
|
|
|
|
bininvx = 1.0 / binsizex;
|
|
bininvy = 1.0 / binsizey;
|
|
bininvz = 1.0 / binsizez;
|
|
|
|
// mbinlo/hi = lowest and highest global bins my ghost atoms could be in
|
|
// coord = lowest and highest values of coords for my ghost atoms
|
|
// add in SMALL for round-off safety
|
|
|
|
double coord;
|
|
int mbinxhi,mbinyhi,mbinzhi;
|
|
|
|
coord = domain->subxlo - cutneigh - SMALL*domain->xprd;
|
|
mbinxlo = static_cast<int> ((coord-domain->boxxlo)*bininvx);
|
|
if (coord < 0.0) mbinxlo = mbinxlo - 1;
|
|
coord = domain->subxhi + cutneigh + SMALL*domain->xprd;
|
|
mbinxhi = static_cast<int> ((coord-domain->boxxlo)*bininvx);
|
|
|
|
coord = domain->subylo - cutneigh - SMALL*domain->yprd;
|
|
mbinylo = static_cast<int> ((coord-domain->boxylo)*bininvy);
|
|
if (coord < 0.0) mbinylo = mbinylo - 1;
|
|
coord = domain->subyhi + cutneigh + SMALL*domain->yprd;
|
|
mbinyhi = static_cast<int> ((coord-domain->boxylo)*bininvy);
|
|
|
|
coord = domain->subzlo - cutneigh - SMALL*domain->zprd;
|
|
mbinzlo = static_cast<int> ((coord-domain->boxzlo)*bininvz);
|
|
if (coord < 0.0) mbinzlo = mbinzlo - 1;
|
|
coord = domain->subzhi + cutneigh + SMALL*domain->zprd;
|
|
mbinzhi = static_cast<int> ((coord-domain->boxzlo)*bininvz);
|
|
|
|
// extend bins by 1 to insure stencil extent is included
|
|
|
|
mbinxlo = mbinxlo - 1;
|
|
mbinxhi = mbinxhi + 1;
|
|
mbinx = mbinxhi - mbinxlo + 1;
|
|
|
|
mbinylo = mbinylo - 1;
|
|
mbinyhi = mbinyhi + 1;
|
|
mbiny = mbinyhi - mbinylo + 1;
|
|
|
|
mbinzlo = mbinzlo - 1;
|
|
mbinzhi = mbinzhi + 1;
|
|
mbinz = mbinzhi - mbinzlo + 1;
|
|
|
|
// test for too many total local bins due to huge domain
|
|
|
|
if (1.0*mbinx*mbiny*mbinz > INT_MAX)
|
|
error->all("Domain too large for neighbor bins");
|
|
|
|
// memory for bin ptrs
|
|
|
|
mbins = mbinx*mbiny*mbinz;
|
|
if (mbins > maxhead) {
|
|
maxhead = mbins;
|
|
memory->sfree(binhead);
|
|
binhead = (int *) memory->smalloc(maxhead*sizeof(int),"neigh:binhead");
|
|
}
|
|
|
|
// create stencil of bins whose closest corner to central bin
|
|
// is within neighbor cutoff
|
|
// next(xyz) = how far the stencil could possibly extend
|
|
// for partial Newton (newton = 0)
|
|
// stencil is all surrounding bins including self
|
|
// for full Newton (newton = 1)
|
|
// stencil is bins to the "upper right" of central bin
|
|
// stencil does NOT include self
|
|
// for full neighbor list (full = 1)
|
|
// stencil is all surrounding bins including self, regardless of Newton
|
|
// stored in stencil_full
|
|
// 3d creates xyz stencil, 2d is only xy
|
|
|
|
int nextx = static_cast<int> (cutneigh*bininvx);
|
|
if (nextx*binsizex < cutneigh) nextx++;
|
|
int nexty = static_cast<int> (cutneigh*bininvy);
|
|
if (nexty*binsizey < cutneigh) nexty++;
|
|
int nextz = static_cast<int> (cutneigh*bininvz);
|
|
if (nextz*binsizez < cutneigh) nextz++;
|
|
|
|
int nmax = (2*nextz+1) * (2*nexty+1) * (2*nextx+1);
|
|
if (nmax > maxstencil) {
|
|
maxstencil = nmax;
|
|
memory->sfree(stencil);
|
|
stencil = (int *) memory->smalloc(maxstencil*sizeof(int),"neigh:stencil");
|
|
}
|
|
|
|
int i,j,k;
|
|
nstencil = 0;
|
|
double cutsq = cutneigh*cutneigh;
|
|
|
|
if (force->dimension == 3) {
|
|
if (force->newton_pair == 0) {
|
|
for (k = -nextz; k <= nextz; k++)
|
|
for (j = -nexty; j <= nexty; j++)
|
|
for (i = -nextx; i <= nextx; i++)
|
|
if (bin_distance(i,j,k) < cutsq)
|
|
stencil[nstencil++] = k*mbiny*mbinx + j*mbinx + i;
|
|
} else {
|
|
for (k = 0; k <= nextz; k++)
|
|
for (j = -nexty; j <= nexty; j++)
|
|
for (i = -nextx; i <= nextx; i++)
|
|
if (k > 0 || j > 0 || (j == 0 && i > 0))
|
|
if (bin_distance(i,j,k) < cutsq)
|
|
stencil[nstencil++] = k*mbiny*mbinx + j*mbinx + i;
|
|
}
|
|
} else {
|
|
if (force->newton_pair == 0) {
|
|
for (j = -nexty; j <= nexty; j++)
|
|
for (i = -nextx; i <= nextx; i++)
|
|
if (bin_distance(i,j,0) < cutsq)
|
|
stencil[nstencil++] = j*mbinx + i;
|
|
} else {
|
|
for (j = 0; j <= nexty; j++)
|
|
for (i = -nextx; i <= nextx; i++)
|
|
if (j > 0 || (j == 0 && i > 0))
|
|
if (bin_distance(i,j,0) < cutsq)
|
|
stencil[nstencil++] = j*mbinx + i;
|
|
}
|
|
}
|
|
|
|
if (full) {
|
|
if (nmax > maxstencil_full) {
|
|
maxstencil_full = nmax;
|
|
memory->sfree(stencil_full);
|
|
stencil_full = (int *) memory->smalloc(maxstencil_full*sizeof(int),
|
|
"neigh:stencil_full");
|
|
}
|
|
nstencil_full = 0;
|
|
if (force->dimension == 3) {
|
|
for (k = -nextz; k <= nextz; k++)
|
|
for (j = -nexty; j <= nexty; j++)
|
|
for (i = -nextx; i <= nextx; i++)
|
|
if (bin_distance(i,j,k) < cutsq)
|
|
stencil_full[nstencil_full++] = k*mbiny*mbinx + j*mbinx + i;
|
|
} else {
|
|
for (j = -nexty; j <= nexty; j++)
|
|
for (i = -nextx; i <= nextx; i++)
|
|
if (bin_distance(i,j,0) < cutsq)
|
|
stencil_full[nstencil_full++] = j*mbinx + i;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
compute closest distance between central bin (0,0,0) and bin (i,j,k)
|
|
------------------------------------------------------------------------- */
|
|
|
|
double Neighbor::bin_distance(int i, int j, int k)
|
|
{
|
|
double delx,dely,delz;
|
|
|
|
if (i > 0)
|
|
delx = (i-1)*binsizex;
|
|
else if (i == 0)
|
|
delx = 0.0;
|
|
else
|
|
delx = (i+1)*binsizex;
|
|
|
|
if (j > 0)
|
|
dely = (j-1)*binsizey;
|
|
else if (j == 0)
|
|
dely = 0.0;
|
|
else
|
|
dely = (j+1)*binsizey;
|
|
|
|
if (k > 0)
|
|
delz = (k-1)*binsizez;
|
|
else if (k == 0)
|
|
delz = 0.0;
|
|
else
|
|
delz = (k+1)*binsizez;
|
|
|
|
return (delx*delx + dely*dely + delz*delz);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
modify parameters of the pair-wise neighbor build
|
|
------------------------------------------------------------------------- */
|
|
|
|
void Neighbor::modify_params(int narg, char **arg)
|
|
{
|
|
int iarg = 0;
|
|
while (iarg < narg) {
|
|
if (strcmp(arg[iarg],"every") == 0) {
|
|
if (iarg+2 > narg) error->all("Illegal neigh_modify command");
|
|
every = atoi(arg[iarg+1]);
|
|
if (every <= 0) error->all("Illegal neigh_modify command");
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg],"delay") == 0) {
|
|
if (iarg+2 > narg) error->all("Illegal neigh_modify command");
|
|
delay = atoi(arg[iarg+1]);
|
|
if (delay < 0) error->all("Illegal neigh_modify command");
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg],"check") == 0) {
|
|
if (iarg+2 > narg) error->all("Illegal neigh_modify command");
|
|
if (strcmp(arg[iarg+1],"yes") == 0) dist_check = 1;
|
|
else if (strcmp(arg[iarg+1],"no") == 0) dist_check = 0;
|
|
else error->all("Illegal neigh_modify command");
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg],"page") == 0) {
|
|
if (iarg+2 > narg) error->all("Illegal neigh_modify command");
|
|
pgsize = atoi(arg[iarg+1]);
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg],"one") == 0) {
|
|
if (iarg+2 > narg) error->all("Illegal neigh_modify command");
|
|
oneatom = atoi(arg[iarg+1]);
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg],"exclude") == 0) {
|
|
if (iarg+2 > narg) error->all("Illegal neigh_modify command");
|
|
|
|
if (strcmp(arg[iarg+1],"type") == 0) {
|
|
if (iarg+4 > narg) error->all("Illegal neigh_modify command");
|
|
if (nex_type == maxex_type) {
|
|
maxex_type += EXDELTA;
|
|
ex1_type = (int *) memory->srealloc(ex1_type,maxex_type*sizeof(int),
|
|
"neigh:ex1_type");
|
|
ex2_type = (int *) memory->srealloc(ex2_type,maxex_type*sizeof(int),
|
|
"neigh:ex2_type");
|
|
}
|
|
ex1_type[nex_type] = atoi(arg[iarg+2]);
|
|
ex2_type[nex_type] = atoi(arg[iarg+3]);
|
|
nex_type++;
|
|
iarg += 4;
|
|
|
|
} else if (strcmp(arg[iarg+1],"group") == 0) {
|
|
if (iarg+4 > narg) error->all("Illegal neigh_modify command");
|
|
if (nex_group == maxex_group) {
|
|
maxex_group += EXDELTA;
|
|
ex1_group =
|
|
(int *) memory->srealloc(ex1_group,maxex_group*sizeof(int),
|
|
"neigh:ex1_group");
|
|
ex2_group =
|
|
(int *) memory->srealloc(ex2_group,maxex_group*sizeof(int),
|
|
"neigh:ex2_group");
|
|
}
|
|
ex1_group[nex_group] = group->find(arg[iarg+2]);
|
|
ex2_group[nex_group] = group->find(arg[iarg+3]);
|
|
if (ex1_group[nex_group] == -1 || ex2_group[nex_group] == -1)
|
|
error->all("Invalid group ID in neigh_modify command");
|
|
nex_group++;
|
|
iarg += 4;
|
|
|
|
} else if (strcmp(arg[iarg+1],"molecule") == 0) {
|
|
if (iarg+3 > narg) error->all("Illegal neigh_modify command");
|
|
if (atom->molecular == 0) {
|
|
char *str = "Must use molecular atom style with neigh_modify exclude molecule";
|
|
error->all(str);
|
|
}
|
|
if (nex_mol == maxex_mol) {
|
|
maxex_mol += EXDELTA;
|
|
ex_mol_group =
|
|
(int *) memory->srealloc(ex_mol_group,maxex_mol*sizeof(int),
|
|
"neigh:ex_mol_group");
|
|
}
|
|
ex_mol_group[nex_mol] = group->find(arg[iarg+2]);
|
|
if (ex_mol_group[nex_mol] == -1)
|
|
error->all("Invalid group ID in neigh_modify command");
|
|
nex_mol++;
|
|
iarg += 3;
|
|
|
|
} else if (strcmp(arg[iarg+1],"none") == 0) {
|
|
nex_type = nex_group = nex_mol = 0;
|
|
iarg += 2;
|
|
} else error->all("Illegal neigh_modify command");
|
|
|
|
} else error->all("Illegal neigh_modify command");
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
return # of bytes of allocated memory
|
|
------------------------------------------------------------------------- */
|
|
|
|
int Neighbor::memory_usage()
|
|
{
|
|
int bytes = 0;
|
|
|
|
bytes += maxhold*3 * sizeof(double);
|
|
|
|
if (style == 0) {
|
|
bytes += maxbin * sizeof(int);
|
|
bytes += maxhead * sizeof(int);
|
|
bytes += maxstencil * sizeof(int);
|
|
bytes += maxstencil_full * sizeof(int);
|
|
}
|
|
|
|
if (half) {
|
|
bytes += maxlocal * sizeof(int);
|
|
bytes += maxlocal * sizeof(int *);
|
|
bytes += maxpage*pgsize * sizeof(int);
|
|
}
|
|
|
|
if (full) {
|
|
bytes += maxlocal * sizeof(int);
|
|
bytes += maxlocal * sizeof(int *);
|
|
bytes += maxpage_full*pgsize * sizeof(int);
|
|
}
|
|
|
|
if (history >= 0) {
|
|
bytes += maxlocal * sizeof(int *);
|
|
bytes += maxlocal * sizeof(double *);
|
|
bytes += maxpage*pgsize * sizeof(int);
|
|
bytes += maxpage*pgsize*3 * sizeof(double);
|
|
}
|
|
|
|
if (respa) {
|
|
bytes += maxlocal * sizeof(int);
|
|
bytes += maxlocal * sizeof(int *);
|
|
bytes += maxpage_inner*pgsize * sizeof(int);
|
|
if (respa == 2) {
|
|
bytes += maxlocal * sizeof(int);
|
|
bytes += maxlocal * sizeof(int *);
|
|
bytes += maxpage_middle*pgsize * sizeof(int);
|
|
}
|
|
}
|
|
|
|
bytes += maxbond*3 * sizeof(int);
|
|
bytes += maxangle*4 * sizeof(int);
|
|
bytes += maxdihedral*5 * sizeof(int);
|
|
bytes += maximproper*5 * sizeof(int);
|
|
|
|
return bytes;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
add pages to half or full neighbor list, starting at npage
|
|
------------------------------------------------------------------------- */
|
|
|
|
void Neighbor::add_pages(int npage)
|
|
{
|
|
maxpage += PGDELTA;
|
|
pages = (int **)
|
|
memory->srealloc(pages,maxpage*sizeof(int *),"neigh:pages");
|
|
for (int i = npage; i < maxpage; i++)
|
|
pages[i] = (int *) memory->smalloc(pgsize*sizeof(int),"neigh:pages[i]");
|
|
}
|
|
|
|
void Neighbor::add_pages_full(int npage)
|
|
{
|
|
maxpage_full += PGDELTA;
|
|
pages_full = (int **)
|
|
memory->srealloc(pages_full,maxpage_full*sizeof(int *),"neigh:pages_full");
|
|
for (int i = npage; i < maxpage_full; i++)
|
|
pages_full[i] =
|
|
(int *) memory->smalloc(pgsize*sizeof(int),"neigh:pages_full[i]");
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
add pages to granular neighbor list, starting at npage
|
|
------------------------------------------------------------------------- */
|
|
|
|
void Neighbor::add_pages_history(int npage)
|
|
{
|
|
pages_touch = (int **)
|
|
memory->srealloc(pages_touch,maxpage*sizeof(int *),"neigh:pages_touch");
|
|
pages_shear = (double **)
|
|
memory->srealloc(pages_shear,maxpage*sizeof(double *),
|
|
"neigh:pages_shear");
|
|
for (int i = npage; i < maxpage; i++) {
|
|
pages_touch[i] = (int *)
|
|
memory->smalloc(pgsize*sizeof(int),"neigh:pages_touch[i]");
|
|
pages_shear[i] = (double *)
|
|
memory->smalloc(3*pgsize*sizeof(double),"neigh:pages_shear[i]");
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
add pages to rRESPA inner neighbor list, starting at npage_inner
|
|
------------------------------------------------------------------------- */
|
|
|
|
void Neighbor::add_pages_inner(int npage_inner)
|
|
{
|
|
maxpage_inner += PGDELTA;
|
|
pages_inner = (int **)
|
|
memory->srealloc(pages_inner,maxpage_inner*sizeof(int *),
|
|
"neigh:pages_inner");
|
|
for (int i = npage_inner; i < maxpage_inner; i++)
|
|
pages_inner[i] =
|
|
(int *) memory->smalloc(pgsize*sizeof(int),"neigh:pages_inner[i]");
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
add pages to rRESPA middle neighbor list, starting at npage_middle
|
|
------------------------------------------------------------------------- */
|
|
|
|
void Neighbor::add_pages_middle(int npage_middle)
|
|
{
|
|
maxpage_middle += PGDELTA;
|
|
pages_middle = (int **)
|
|
memory->srealloc(pages_middle,maxpage_middle*sizeof(int *),
|
|
"neigh:pages_middle");
|
|
for (int i = npage_middle; i < maxpage_middle; i++)
|
|
pages_middle[i] =
|
|
(int *) memory->smalloc(pgsize*sizeof(int),"neigh:pages_middle[i]");
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
determine if atom j is in special list of atom i
|
|
if it is not, return 0
|
|
if it is and special flag is 0 (both coeffs are 0.0), return -1
|
|
if it is and special flag is 1 (both coeffs are 1.0), return 0
|
|
if it is and special flag is 2 (otherwise), return 1,2,3
|
|
for which neighbor it is (and which coeff it maps to)
|
|
------------------------------------------------------------------------- */
|
|
|
|
int Neighbor::find_special(int i, int j)
|
|
{
|
|
int *list = atom->special[i];
|
|
int n1 = atom->nspecial[i][0];
|
|
int n2 = atom->nspecial[i][1];
|
|
int n3 = atom->nspecial[i][2];
|
|
int tag = atom->tag[j];
|
|
|
|
for (int i = 0; i < n3; i++) {
|
|
if (list[i] == tag) {
|
|
if (i < n1) {
|
|
if (special_flag[1] == 0) return -1;
|
|
else if (special_flag[1] == 1) return 0;
|
|
else return 1;
|
|
} else if (i < n2) {
|
|
if (special_flag[2] == 0) return -1;
|
|
else if (special_flag[2] == 1) return 0;
|
|
else return 2;
|
|
} else {
|
|
if (special_flag[3] == 0) return -1;
|
|
else if (special_flag[3] == 1) return 0;
|
|
else return 3;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
bin owned and ghost atoms
|
|
------------------------------------------------------------------------- */
|
|
|
|
void Neighbor::bin_atoms()
|
|
{
|
|
int i,ibin,nlocal,nall;
|
|
double **x;
|
|
|
|
nlocal = atom->nlocal;
|
|
nall = atom->nlocal + atom->nghost;
|
|
x = atom->x;
|
|
|
|
for (i = 0; i < mbins; i++) binhead[i] = -1;
|
|
|
|
// bin ghost atoms 1st, so will be at end of linked list
|
|
// then bin owned atoms
|
|
|
|
for (i = nlocal; i < nall; i++) {
|
|
ibin = coord2bin(x[i]);
|
|
bins[i] = binhead[ibin];
|
|
binhead[ibin] = i;
|
|
}
|
|
|
|
for (i = 0; i < nlocal; i++) {
|
|
ibin = coord2bin(x[i]);
|
|
bins[i] = binhead[ibin];
|
|
binhead[ibin] = i;
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
convert atom coords into local bin #
|
|
only ghost atoms will have coord >= boxhi or coord < boxlo
|
|
take special care to insure ghosts are put in correct bins
|
|
this is necessary so that both procs on either side of PBC
|
|
treat a pair of atoms straddling the PBC in a consistent way
|
|
------------------------------------------------------------------------- */
|
|
|
|
int Neighbor::coord2bin(double *x)
|
|
{
|
|
int ix,iy,iz;
|
|
|
|
if (x[0] >= domain->boxxhi)
|
|
ix = static_cast<int> ((x[0]-domain->boxxhi)*bininvx) + nbinx - mbinxlo;
|
|
else if (x[0] >= domain->boxxlo)
|
|
ix = static_cast<int> ((x[0]-domain->boxxlo)*bininvx) - mbinxlo;
|
|
else
|
|
ix = static_cast<int> ((x[0]-domain->boxxlo)*bininvx) - mbinxlo - 1;
|
|
|
|
if (x[1] >= domain->boxyhi)
|
|
iy = static_cast<int> ((x[1]-domain->boxyhi)*bininvy) + nbiny - mbinylo;
|
|
else if (x[1] >= domain->boxylo)
|
|
iy = static_cast<int> ((x[1]-domain->boxylo)*bininvy) - mbinylo;
|
|
else
|
|
iy = static_cast<int> ((x[1]-domain->boxylo)*bininvy) - mbinylo - 1;
|
|
|
|
if (x[2] >= domain->boxzhi)
|
|
iz = static_cast<int> ((x[2]-domain->boxzhi)*bininvz) + nbinz - mbinzlo;
|
|
else if (x[2] >= domain->boxzlo)
|
|
iz = static_cast<int> ((x[2]-domain->boxzlo)*bininvz) - mbinzlo;
|
|
else
|
|
iz = static_cast<int> ((x[2]-domain->boxzlo)*bininvz) - mbinzlo - 1;
|
|
|
|
return (iz*mbiny*mbinx + iy*mbinx + ix + 1);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
test if atom pair i,j is excluded from neighbor list
|
|
due to type, group, molecule settings from neigh_modify command
|
|
return 1 if should be excluded, 0 if included
|
|
------------------------------------------------------------------------- */
|
|
|
|
int Neighbor::exclusion(int i, int j, int *type, int *mask, int *molecule)
|
|
{
|
|
int m;
|
|
|
|
if (nex_type && ex_type[type[i]][type[j]]) return 1;
|
|
|
|
if (nex_group) {
|
|
for (m = 0; m < nex_group; m++) {
|
|
if (mask[i] & ex1_bit[m] && mask[j] & ex2_bit[m]) return 1;
|
|
if (mask[i] & ex2_bit[m] && mask[j] & ex1_bit[m]) return 1;
|
|
}
|
|
}
|
|
|
|
if (nex_mol) {
|
|
for (m = 0; m < nex_mol; m++)
|
|
if (mask[i] & ex_mol_bit[m] && mask[j] & ex_mol_bit[m] &&
|
|
molecule[i] == molecule[j]) return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|