Skip to content
Snippets Groups Projects
neighbor.cpp 54.5 KiB
Newer Older
sjplimp's avatar
sjplimp committed
/* ----------------------------------------------------------------------
   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
sjplimp's avatar
 
sjplimp committed
   http://lammps.sandia.gov, Sandia National Laboratories
   Steve Plimpton, sjplimp@sandia.gov
sjplimp's avatar
sjplimp committed

   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.
------------------------------------------------------------------------- */

sjplimp's avatar
 
sjplimp committed
/* ----------------------------------------------------------------------
   Contributing author (triclinic and multi-neigh) : Pieter in 't Veld (SNL)
------------------------------------------------------------------------- */

sjplimp's avatar
 
sjplimp committed
#include "lmptype.h"
sjplimp's avatar
sjplimp committed
#include "mpi.h"
#include "math.h"
#include "stdlib.h"
#include "string.h"
#include "neighbor.h"
sjplimp's avatar
 
sjplimp committed
#include "neigh_list.h"
#include "neigh_request.h"
sjplimp's avatar
sjplimp committed
#include "atom.h"
sjplimp's avatar
 
sjplimp committed
#include "atom_vec.h"
sjplimp's avatar
 
sjplimp committed
#include "comm.h"
sjplimp's avatar
sjplimp committed
#include "force.h"
#include "pair.h"
#include "domain.h"
#include "group.h"
#include "modify.h"
#include "fix.h"
sjplimp's avatar
 
sjplimp committed
#include "compute.h"
sjplimp's avatar
sjplimp committed
#include "update.h"
#include "respa.h"
#include "output.h"
#include "memory.h"
#include "error.h"

sjplimp's avatar
 
sjplimp committed
using namespace LAMMPS_NS;

sjplimp's avatar
 
sjplimp committed
#define RQDELTA 1
#define EXDELTA 1

sjplimp's avatar
sjplimp committed
#define LB_FACTOR 1.5
#define SMALL 1.0e-6
sjplimp's avatar
 
sjplimp committed
#define BIG 1.0e20
sjplimp's avatar
 
sjplimp committed
#define CUT2BIN_RATIO 100
sjplimp's avatar
sjplimp committed

#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) > (b) ? (a) : (b))

sjplimp's avatar
 
sjplimp committed
enum{NSQ,BIN,MULTI};     // also in neigh_list.cpp
sjplimp's avatar
 
sjplimp committed

sjplimp's avatar
 
sjplimp committed
//#define NEIGH_LIST_DEBUG 1
sjplimp's avatar
 
sjplimp committed

sjplimp's avatar
sjplimp committed
/* ---------------------------------------------------------------------- */

sjplimp's avatar
 
sjplimp committed
Neighbor::Neighbor(LAMMPS *lmp) : Pointers(lmp)
sjplimp's avatar
sjplimp committed
{
  MPI_Comm_rank(world,&me);
  MPI_Comm_size(world,&nprocs);

sjplimp's avatar
 
sjplimp committed
  style = BIN;
sjplimp's avatar
sjplimp committed
  every = 1;
  delay = 10;
  dist_check = 1;
sjplimp's avatar
 
sjplimp committed
  pgsize = 100000;
sjplimp's avatar
sjplimp committed
  oneatom = 2000;
sjplimp's avatar
 
sjplimp committed
  binsizeflag = 0;
  build_once = 0;
sjplimp's avatar
sjplimp committed

  cutneighsq = NULL;
sjplimp's avatar
 
sjplimp committed
  cutneighghostsq = NULL;
sjplimp's avatar
 
sjplimp committed
  cuttype = NULL;
  cuttypesq = NULL;
sjplimp's avatar
sjplimp committed
  fixchecklist = NULL;

sjplimp's avatar
 
sjplimp committed
  // coords at last neighboring
sjplimp's avatar
sjplimp committed

  maxhold = 0;
  xhold = NULL;

sjplimp's avatar
 
sjplimp committed
  // binning

  maxhead = 0;
  binhead = NULL;
  maxbin = 0;
  bins = NULL;

sjplimp's avatar
sjplimp committed
  // pair exclusion list info

sjplimp's avatar
 
sjplimp committed
  includegroup = 0;
sjplimp's avatar
 
sjplimp committed

sjplimp's avatar
sjplimp committed
  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;

sjplimp's avatar
 
sjplimp committed
  // pair lists
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
  maxatom = 0;
sjplimp's avatar
 
sjplimp committed
  nblist = nglist = nslist = 0;
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
  nlist = 0;
  lists = NULL;
  pair_build = NULL;
  stencil_create = NULL;
  blist = glist = slist = NULL;
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
  nrequest = maxrequest = 0;
  requests = NULL;
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
  old_style = BIN;
sjplimp's avatar
 
sjplimp committed
  old_triclinic = 0;
sjplimp's avatar
 
sjplimp committed
  old_nrequest = 0;
  old_requests = NULL;
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
  // bond lists
sjplimp's avatar
sjplimp committed

  maxbond = 0;
  bondlist = NULL;
  maxangle = 0;
  anglelist = NULL;
  maxdihedral = 0;
  dihedrallist = NULL;
  maximproper = 0;
  improperlist = NULL;
}

/* ---------------------------------------------------------------------- */

Neighbor::~Neighbor()
{
sjplimp's avatar
 
sjplimp committed
  memory->destroy(cutneighsq);
sjplimp's avatar
 
sjplimp committed
  memory->destroy(cutneighghostsq);
sjplimp's avatar
 
sjplimp committed
  delete [] cuttype;
  delete [] cuttypesq;
sjplimp's avatar
sjplimp committed
  delete [] fixchecklist;
sjplimp's avatar
 
sjplimp committed

sjplimp's avatar
 
sjplimp committed
  memory->destroy(xhold);
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
  memory->destroy(binhead);
  memory->destroy(bins);
sjplimp's avatar
 
sjplimp committed

sjplimp's avatar
 
sjplimp committed
  memory->destroy(ex1_type);
  memory->destroy(ex2_type);
  memory->destroy(ex_type);
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
  memory->destroy(ex1_group);
  memory->destroy(ex2_group);
sjplimp's avatar
sjplimp committed
  delete [] ex1_bit;
  delete [] ex2_bit;

sjplimp's avatar
 
sjplimp committed
  memory->destroy(ex_mol_group);
sjplimp's avatar
sjplimp committed
  delete [] ex_mol_bit;

sjplimp's avatar
 
sjplimp committed
  for (int i = 0; i < nlist; i++) delete lists[i];
  delete [] lists;
  delete [] pair_build;
  delete [] stencil_create;
  delete [] blist;
  delete [] glist;
  delete [] slist;
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
  for (int i = 0; i < nrequest; i++) delete requests[i];
  memory->sfree(requests);
  for (int i = 0; i < old_nrequest; i++) delete old_requests[i];
  memory->sfree(old_requests);
sjplimp's avatar
 
sjplimp committed

sjplimp's avatar
 
sjplimp committed
  memory->destroy(bondlist);
  memory->destroy(anglelist);
  memory->destroy(dihedrallist);
  memory->destroy(improperlist);
sjplimp's avatar
sjplimp committed
}

/* ---------------------------------------------------------------------- */

void Neighbor::init()
{
  int i,j,m,n;

  ncalls = ndanger = 0;
sjplimp's avatar
 
sjplimp committed
  dimension = domain->dimension;
sjplimp's avatar
 
sjplimp committed
  triclinic = domain->triclinic;
sjplimp's avatar
 
sjplimp committed
  newton_pair = force->newton_pair;
sjplimp's avatar
sjplimp committed

  // error check

  if (delay > 0 && (delay % every) != 0)
    error->all("Neighbor delay must be 0 or multiple of every setting");

sjplimp's avatar
 
sjplimp committed
  if (pgsize < 10*oneatom)
    error->all("Neighbor page size must be >= 10x the one atom setting");

sjplimp's avatar
sjplimp committed
  // ------------------------------------------------------------------
  // settings

sjplimp's avatar
 
sjplimp committed
  // bbox lo/hi = bounding box of entire domain, stored by Domain

  if (triclinic == 0) {
    bboxlo = domain->boxlo;
    bboxhi = domain->boxhi;
  } else {
    bboxlo = domain->boxlo_bound;
    bboxhi = domain->boxhi_bound;
  }

sjplimp's avatar
 
sjplimp committed
  // set neighbor cutoffs (force cutoff + skin)
  // trigger determines when atoms migrate and neighbor lists are rebuilt
sjplimp's avatar
 
sjplimp committed
  //   needs to be non-zero for migration distance check
  //   even if pair = NULL and no neighbor lists are used
  // cutneigh = force cutoff + skin if cutforce > 0, else cutneigh = 0
sjplimp's avatar
sjplimp committed

  triggersq = 0.25*skin*skin;
sjplimp's avatar
 
sjplimp committed
  boxcheck = 0;
sjplimp's avatar
 
sjplimp committed
  if (domain->box_change && (domain->xperiodic || domain->yperiodic || 
			     (dimension == 3 && domain->zperiodic)))
sjplimp's avatar
 
sjplimp committed
      boxcheck = 1;
sjplimp's avatar
 
sjplimp committed
      
sjplimp's avatar
sjplimp committed
  n = atom->ntypes;
sjplimp's avatar
 
sjplimp committed
  if (cutneighsq == NULL) {
sjplimp's avatar
 
sjplimp committed
    memory->create(cutneighsq,n+1,n+1,"neigh:cutneighsq");
sjplimp's avatar
 
sjplimp committed
    memory->create(cutneighghostsq,n+1,n+1,"neigh:cutneighghostsq");
sjplimp's avatar
 
sjplimp committed
    cuttype = new double[n+1];
    cuttypesq = new double[n+1];
sjplimp's avatar
sjplimp committed
  }

sjplimp's avatar
 
sjplimp committed
  double cutoff,delta,cut;
  cutneighmin = BIG;
  cutneighmax = 0.0;

  for (i = 1; i <= n; i++) {
    cuttype[i] = cuttypesq[i] = 0.0;
    for (j = 1; j <= n; j++) {
sjplimp's avatar
 
sjplimp committed
      if (force->pair) cutoff = sqrt(force->pair->cutsq[i][j]);
      else cutoff = 0.0;
      if (cutoff > 0.0) delta = skin;
      else delta = 0.0;
sjplimp's avatar
 
sjplimp committed
      cut = cutoff + delta;
sjplimp's avatar
 
sjplimp committed

sjplimp's avatar
 
sjplimp committed
      cutneighsq[i][j] = cut*cut;
      cuttype[i] = MAX(cuttype[i],cut);
      cuttypesq[i] = MAX(cuttypesq[i],cut*cut);
      cutneighmin = MIN(cutneighmin,cut);
      cutneighmax = MAX(cutneighmax,cut);
sjplimp's avatar
 
sjplimp committed

      if (force->pair && force->pair->ghostneigh) {
	cut = force->pair->cutghost[i][j] + skin;
	cutneighghostsq[i][j] = cut*cut;
      }
sjplimp's avatar
 
sjplimp committed
    }
sjplimp's avatar
 
sjplimp committed
  }
  cutneighmaxsq = cutneighmax * cutneighmax;
sjplimp's avatar
 
sjplimp committed

sjplimp's avatar
sjplimp committed
  // check other classes that can induce reneighboring in decide()
sjplimp's avatar
 
sjplimp committed
  // don't check if build_once is set
sjplimp's avatar
sjplimp committed

  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;
sjplimp's avatar
 
sjplimp committed
  if (build_once) must_check = 0;
sjplimp's avatar
sjplimp committed

  // 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
sjplimp's avatar
 
sjplimp committed
  // pairwise portion of KSpace solver uses all 1-2,1-3,1-4 neighbors
sjplimp's avatar
sjplimp committed

  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;

sjplimp's avatar
 
sjplimp committed
  // maxwt = max multiplicative factor on atom indices stored in neigh list

  maxwt = 0;
  if (special_flag[1] == 2) maxwt = 2;
  if (special_flag[2] == 2) maxwt = 3;
  if (special_flag[3] == 2) maxwt = 4;

sjplimp's avatar
 
sjplimp committed
  // rRESPA cutoffs

  int respa = 0;
sjplimp's avatar
 
sjplimp committed
  if (update->whichflag == 1 && strcmp(update->integrate_style,"respa") == 0) {
sjplimp's avatar
 
sjplimp committed
    if (((Respa *) update->integrate)->level_inner >= 0) respa = 1;
    if (((Respa *) update->integrate)->level_middle >= 0) respa = 2;
  }

  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);
  }

sjplimp's avatar
sjplimp committed
  // ------------------------------------------------------------------
sjplimp's avatar
 
sjplimp committed
  // xhold, bins, exclusion lists
sjplimp's avatar
sjplimp committed

  // free xhold and bins if not needed for this run

  if (dist_check == 0) {
sjplimp's avatar
 
sjplimp committed
    memory->destroy(xhold);
sjplimp's avatar
sjplimp committed
    maxhold = 0;
sjplimp's avatar
 
sjplimp committed
    xhold = NULL;
sjplimp's avatar
sjplimp committed
  }

sjplimp's avatar
 
sjplimp committed
  if (style == NSQ) {
sjplimp's avatar
 
sjplimp committed
    memory->destroy(bins);
    memory->destroy(binhead);
sjplimp's avatar
 
sjplimp committed
    maxbin = maxhead = 0;
sjplimp's avatar
 
sjplimp committed
    binhead = NULL;
    bins = NULL;
sjplimp's avatar
sjplimp committed
  }

  // 1st time allocation of xhold and bins

  if (dist_check) {
    if (maxhold == 0) {
      maxhold = atom->nmax;
sjplimp's avatar
 
sjplimp committed
      memory->create(xhold,maxhold,3,"neigh:xhold");
sjplimp's avatar
sjplimp committed
    }
  }

sjplimp's avatar
 
sjplimp committed
  if (style != NSQ) {
sjplimp's avatar
sjplimp committed
    if (maxbin == 0) {
      maxbin = atom->nmax;
sjplimp's avatar
 
sjplimp committed
      memory->create(bins,maxbin,"bins");
sjplimp's avatar
sjplimp committed
    }
  }
    
  // 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) {
sjplimp's avatar
 
sjplimp committed
    memory->destroy(ex_type);
    memory->create(ex_type,n+1,n+1,"neigh:ex_type");
sjplimp's avatar
sjplimp committed

    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]];
  }

  // ------------------------------------------------------------------
sjplimp's avatar
 
sjplimp committed
  // pairwise lists
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
  // test if pairwise lists need to be re-created
  // no need to re-create if:
sjplimp's avatar
 
sjplimp committed
  //   neigh style and triclinic has not changed and
  //   current requests = old requests
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
  int same = 1;
  if (style != old_style) same = 0;
sjplimp's avatar
 
sjplimp committed
  if (triclinic != old_triclinic) same = 0;
sjplimp's avatar
 
sjplimp committed
  if (nrequest != old_nrequest) same = 0;
  else
    for (i = 0; i < nrequest; i++)
      if (requests[i]->identical(old_requests[i]) == 0) same = 0;
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
#ifdef NEIGH_LIST_DEBUG
  if (comm->me == 0) printf("SAME flag %d\n",same);
#endif
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
  // if old and new are not the same, create new pairwise lists
sjplimp's avatar
 
sjplimp committed

sjplimp's avatar
 
sjplimp committed
  if (!same) {
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
    // delete old lists and create new ones
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
    for (i = 0; i < nlist; i++) delete lists[i];
    delete [] lists;
    delete [] pair_build;
    delete [] stencil_create;
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
    nlist = nrequest;
    lists = new NeighList*[nlist];
    pair_build = new PairPtr[nlist];
    stencil_create = new StencilPtr[nlist];
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
    // create individual lists, one per request
    // copy dnum setting from request to list
    // pass list ptr back to requestor (except for Command class)
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
    for (i = 0; i < nlist; i++) {
      lists[i] = new NeighList(lmp,pgsize);
      lists[i]->index = i;
      lists[i]->dnum = requests[i]->dnum;

      if (requests[i]->pair) {
	Pair *pair = (Pair *) requests[i]->requestor;
	pair->init_list(requests[i]->id,lists[i]);
      } else if (requests[i]->fix) {
	Fix *fix = (Fix *) requests[i]->requestor;
	fix->init_list(requests[i]->id,lists[i]);
      } else if (requests[i]->compute) {
	Compute *compute = (Compute *) requests[i]->requestor;
	compute->init_list(requests[i]->id,lists[i]);
      }
    }
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
    // detect lists that are connected to other lists
sjplimp's avatar
 
sjplimp committed
    // if-then-else sequence is important
sjplimp's avatar
 
sjplimp committed
    //   since don't want to re-process skip or copy lists further down
sjplimp's avatar
 
sjplimp committed
    // copy: point this list at request->otherlist, could be a skip list
sjplimp's avatar
 
sjplimp committed
    // skip: point this list at request->otherlist, copy skip info from request
sjplimp's avatar
 
sjplimp committed
    // half_from_full: point this list at preceeding full list
    // granhistory: set preceeding list's listgranhistory to this list
sjplimp's avatar
 
sjplimp committed
    //   also set preceeding list's ptr to FixShearHistory
sjplimp's avatar
 
sjplimp committed
    // respaouter: point this list at preceeding 1/2 inner/middle lists
sjplimp's avatar
 
sjplimp committed
    // pair and half: if there is a full non-occasional non-skip list
sjplimp's avatar
 
sjplimp committed
    //   change this list to half_from_full and point at the full list
sjplimp's avatar
 
sjplimp committed
    //   parent could be copy list or pair or fix
sjplimp's avatar
 
sjplimp committed
    // fix/compute requests:
sjplimp's avatar
 
sjplimp committed
    //   kind of request = half or full, occasional or not doesn't matter
    //   if request = half and non-skip pair half/respaouter exists,
    //     become copy of that list
    //   if request = full and non-skip pair full exists,
    //     become copy of that list
    //   if request = half and non-skip pair full exists,
sjplimp's avatar
 
sjplimp committed
    //     become half_from_full of that list
sjplimp's avatar
 
sjplimp committed
    //   if no matches, do nothing, fix/compute list will be built directly
    //   ok if parent is copy list
sjplimp's avatar
 
sjplimp committed

    for (i = 0; i < nlist; i++) {
sjplimp's avatar
 
sjplimp committed
      if (requests[i]->copy)
	lists[i]->listcopy = lists[requests[i]->otherlist];

      else if (requests[i]->skip) {
sjplimp's avatar
 
sjplimp committed
	lists[i]->listskip = lists[requests[i]->otherlist];
sjplimp's avatar
 
sjplimp committed
	lists[i]->copy_skip_info(requests[i]->iskip,requests[i]->ijskip);
sjplimp's avatar
 
sjplimp committed

sjplimp's avatar
 
sjplimp committed
      } else if (requests[i]->half_from_full)
sjplimp's avatar
 
sjplimp committed
	lists[i]->listfull = lists[i-1];
sjplimp's avatar
 
sjplimp committed

sjplimp's avatar
 
sjplimp committed
      else if (requests[i]->granhistory) {
sjplimp's avatar
 
sjplimp committed
	lists[i-1]->listgranhistory = lists[i];
	for (int ifix = 0; ifix < modify->nfix; ifix++)
	  if (strcmp(modify->fix[ifix]->style,"SHEAR_HISTORY") == 0) 
	    lists[i-1]->fix_history = (FixShearHistory *) modify->fix[ifix];
sjplimp's avatar
 
sjplimp committed
 
      } else if (requests[i]->respaouter) {
sjplimp's avatar
 
sjplimp committed
	if (requests[i-1]->respainner) {
	  lists[i]->respamiddle = 0;
	  lists[i]->listinner = lists[i-1];
sjplimp's avatar
 
sjplimp committed
	} else {
sjplimp's avatar
 
sjplimp committed
	  lists[i]->respamiddle = 1;
	  lists[i]->listmiddle = lists[i-1];
	  lists[i]->listinner = lists[i-2];
sjplimp's avatar
 
sjplimp committed
	}
sjplimp's avatar
 
sjplimp committed

sjplimp's avatar
 
sjplimp committed
      } else if (requests[i]->pair && requests[i]->half) {
sjplimp's avatar
 
sjplimp committed
	for (j = 0; j < nlist; j++)
sjplimp's avatar
 
sjplimp committed
	  if (requests[j]->full && requests[j]->occasional == 0 &&
sjplimp's avatar
 
sjplimp committed
	      requests[j]->skip == 0) break;
	if (j < nlist) {
	  requests[i]->half = 0;
	  requests[i]->half_from_full = 1;
	  lists[i]->listfull = lists[j];
sjplimp's avatar
 
sjplimp committed
	}

sjplimp's avatar
 
sjplimp committed
      } else if (requests[i]->fix || requests[i]->compute) {
sjplimp's avatar
 
sjplimp committed
	for (j = 0; j < nlist; j++) {
sjplimp's avatar
 
sjplimp committed
	  if (requests[i]->half && requests[j]->pair &&
	      requests[j]->skip == 0 && requests[j]->half) break;
	  if (requests[i]->full && requests[j]->pair &&
	      requests[j]->skip == 0 && requests[j]->full) break;
	  if (requests[i]->half && requests[j]->pair &&
	      requests[j]->skip == 0 && requests[j]->respaouter) break;
sjplimp's avatar
sjplimp committed
	}
sjplimp's avatar
 
sjplimp committed
	if (j < nlist) {
	  requests[i]->copy = 1;
	  lists[i]->listcopy = lists[j];
sjplimp's avatar
sjplimp committed
	} else {
sjplimp's avatar
 
sjplimp committed
	  for (j = 0; j < nlist; j++) {
sjplimp's avatar
 
sjplimp committed
	    if (requests[i]->half && requests[j]->pair &&
		requests[j]->skip == 0 && requests[j]->full) break;
sjplimp's avatar
 
sjplimp committed
	  }
sjplimp's avatar
 
sjplimp committed
	  if (j < nlist) {
	    requests[i]->half = 0;
	    requests[i]->half_from_full = 1;
	    lists[i]->listfull = lists[j];
sjplimp's avatar
 
sjplimp committed
	  }
sjplimp's avatar
 
sjplimp committed
	}
sjplimp's avatar
sjplimp committed
      }
    }
sjplimp's avatar
 
sjplimp committed

sjplimp's avatar
 
sjplimp committed
    // set ptrs to pair_build and stencil_create functions for each list
    // ptrs set to NULL if not set explicitly

    for (i = 0; i < nlist; i++) {
      choose_build(i,requests[i]);
      if (style != NSQ) choose_stencil(i,requests[i]);
      else stencil_create[i] = NULL;
    }

sjplimp's avatar
 
sjplimp committed
    // set each list's build/grow/stencil/ghost flags based on neigh request
sjplimp's avatar
 
sjplimp committed
    // buildflag = 1 if its pair_build() invoked every reneighbor
    // growflag = 1 if it stores atom-based arrays and pages
    // stencilflag = 1 if it stores stencil arrays
sjplimp's avatar
 
sjplimp committed
    // ghostflag = 1 if it stores neighbors of ghosts
    // anyghostlist = 1 if any non-occasional list stores neighbors of ghosts
sjplimp's avatar
 
sjplimp committed

sjplimp's avatar
 
sjplimp committed
    anyghostlist = 0;
sjplimp's avatar
 
sjplimp committed
    for (i = 0; i < nlist; i++) {
      lists[i]->buildflag = 1;
      if (pair_build[i] == NULL) lists[i]->buildflag = 0;
      if (requests[i]->occasional) lists[i]->buildflag = 0;

      lists[i]->growflag = 1;
      if (requests[i]->copy) lists[i]->growflag = 0;

      lists[i]->stencilflag = 1;
      if (style == NSQ) lists[i]->stencilflag = 0;
      if (stencil_create[i] == NULL) lists[i]->stencilflag = 0;
sjplimp's avatar
 
sjplimp committed

      lists[i]->ghostflag = 0;
      if (requests[i]->ghost) lists[i]->ghostflag = 1;
      if (requests[i]->ghost && !requests[i]->occasional) anyghostlist = 1;
sjplimp's avatar
 
sjplimp committed
    }

sjplimp's avatar
 
sjplimp committed
#ifdef NEIGH_LIST_DEBUG
sjplimp's avatar
 
sjplimp committed
    for (i = 0; i < nlist; i++) lists[i]->print_attributes();
sjplimp's avatar
 
sjplimp committed
#endif

sjplimp's avatar
 
sjplimp committed
    // allocate atom arrays and 1st pages of lists that store them

sjplimp's avatar
 
sjplimp committed
    maxatom = atom->nmax;
sjplimp's avatar
 
sjplimp committed
    for (i = 0; i < nlist; i++)
      if (lists[i]->growflag) {
sjplimp's avatar
 
sjplimp committed
	lists[i]->grow(maxatom);
sjplimp's avatar
 
sjplimp committed
	lists[i]->add_pages();
      }

    // setup 3 vectors of pairwise neighbor lists
    // blist = lists whose pair_build() is invoked every reneighbor
    // glist = lists who store atom arrays which are used every reneighbor
    // slist = lists who store stencil arrays which are used every reneighbor
    // blist and glist vectors are used by neighbor::build()
    // slist vector is used by neighbor::setup_bins()

    nblist = nglist = nslist = 0;
    delete [] blist;
    delete [] glist;
    delete [] slist;
    blist = new int[nlist];
    glist = new int[nlist];
    slist = new int[nlist];

    for (i = 0; i < nlist; i++) {
      if (lists[i]->buildflag) blist[nblist++] = i;
      if (lists[i]->growflag && requests[i]->occasional == 0)
	glist[nglist++] = i;
      if (lists[i]->stencilflag && requests[i]->occasional == 0)
	slist[nslist++] = i;
    }

sjplimp's avatar
 
sjplimp committed
#ifdef NEIGH_LIST_DEBUG
    print_lists_of_lists();
#endif
sjplimp's avatar
 
sjplimp committed

    // reorder build vector if necessary
    // relevant for lists that copy/skip/half-full from parent
sjplimp's avatar
 
sjplimp committed
    // the derived list must appear in blist after the parent list
sjplimp's avatar
 
sjplimp committed
    // no occasional lists are in build vector
    // swap two lists within blist when dependency is mis-ordered
    // done when entire pass thru blist results in no swaps

    int done = 0;
    while (!done) {
      done = 1;
      for (i = 0; i < nblist; i++) {
	NeighList *ptr = NULL;
	if (lists[blist[i]]->listfull) ptr = lists[blist[i]]->listfull;
	if (lists[blist[i]]->listcopy) ptr = lists[blist[i]]->listcopy;
	if (lists[blist[i]]->listskip) ptr = lists[blist[i]]->listskip;
	if (ptr == NULL) continue;
	for (m = 0; m < nlist; m++)
	  if (ptr == lists[m]) break;
	for (j = 0; j < nblist; j++)
	  if (m == blist[j]) break;
	if (j < i) continue;
	int tmp = blist[i];
	blist[i] = blist[j];
	blist[j] = tmp;
	done = 0;
	break;
      }
    }

sjplimp's avatar
 
sjplimp committed
#ifdef NEIGH_LIST_DEBUG
    print_lists_of_lists();
#endif
sjplimp's avatar
 
sjplimp committed
  }

  // delete old requests
  // copy current requests and style to old for next run
  
  for (i = 0; i < old_nrequest; i++) delete old_requests[i];
sjplimp's avatar
 
sjplimp committed
  memory->sfree(old_requests);
sjplimp's avatar
 
sjplimp committed
  old_nrequest = nrequest;
  old_requests = requests;
  nrequest = maxrequest = 0;
  requests = NULL;
  old_style = style;
sjplimp's avatar
 
sjplimp committed
  old_triclinic = triclinic;
sjplimp's avatar
sjplimp committed

  // ------------------------------------------------------------------
sjplimp's avatar
 
sjplimp committed
  // topology lists
sjplimp's avatar
sjplimp committed

sjplimp's avatar
 
sjplimp committed
  // 1st time allocation of topology lists
sjplimp's avatar
sjplimp committed

  if (atom->molecular && atom->nbonds && maxbond == 0) {
    if (nprocs == 1) maxbond = atom->nbonds;
    else maxbond = static_cast<int> (LB_FACTOR * atom->nbonds / nprocs);
sjplimp's avatar
 
sjplimp committed
    memory->create(bondlist,maxbond,3,"neigh:bondlist");
sjplimp's avatar
sjplimp committed
  }

  if (atom->molecular && atom->nangles && maxangle == 0) {
    if (nprocs == 1) maxangle = atom->nangles;
    else maxangle = static_cast<int> (LB_FACTOR * atom->nangles / nprocs);
sjplimp's avatar
 
sjplimp committed
    memory->create(anglelist,maxangle,4,"neigh:anglelist");
sjplimp's avatar
sjplimp committed
  }

  if (atom->molecular && atom->ndihedrals && maxdihedral == 0) {
    if (nprocs == 1) maxdihedral = atom->ndihedrals;
    else maxdihedral = static_cast<int> 
	   (LB_FACTOR * atom->ndihedrals / nprocs);
sjplimp's avatar
 
sjplimp committed
    memory->create(dihedrallist,maxdihedral,5,"neigh:dihedrallist");
sjplimp's avatar
sjplimp committed
  }

  if (atom->molecular && atom->nimpropers && maximproper == 0) {
    if (nprocs == 1) maximproper = atom->nimpropers;
    else maximproper = static_cast<int>
	   (LB_FACTOR * atom->nimpropers / nprocs);
sjplimp's avatar
 
sjplimp committed
    memory->create(improperlist,maximproper,5,"neigh:improperlist");
sjplimp's avatar
sjplimp committed
  }

sjplimp's avatar
 
sjplimp committed
  // set flags that determine which topology neighboring routines to use
sjplimp's avatar
sjplimp committed
  // 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;

sjplimp's avatar
 
sjplimp committed
  if (atom->avec->bonds_allow) {
sjplimp's avatar
sjplimp committed
    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;
    }
  }

sjplimp's avatar
 
sjplimp committed
  if (atom->avec->angles_allow) {
sjplimp's avatar
sjplimp committed
    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;
sjplimp's avatar
 
sjplimp committed
  if (atom->avec->dihedrals_allow) {
sjplimp's avatar
sjplimp committed
    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;
sjplimp's avatar
 
sjplimp committed
  if (atom->avec->impropers_allow) {
sjplimp's avatar
sjplimp committed
    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;
    }
  }

sjplimp's avatar
 
sjplimp committed
  // set ptrs to topology build functions
sjplimp's avatar
sjplimp committed

  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;

sjplimp's avatar
 
sjplimp committed
  // set topology neighbor list counts to 0
sjplimp's avatar
sjplimp committed
  // in case all are turned off but potential is still defined

  nbondlist = nanglelist = ndihedrallist = nimproperlist = 0;
}

/* ---------------------------------------------------------------------- */

sjplimp's avatar
 
sjplimp committed
int Neighbor::request(void *requestor)
{
  if (nrequest == maxrequest) {
    maxrequest += RQDELTA;
    requests = (NeighRequest **) 
      memory->srealloc(requests,maxrequest*sizeof(NeighRequest *),
		       "neighbor:requests");
  }

  requests[nrequest] = new NeighRequest(lmp);
  requests[nrequest]->requestor = requestor;
  nrequest++;
  return nrequest-1;
}

/* ----------------------------------------------------------------------
   determine which pair_build function each neigh list needs
   based on settings of neigh request
sjplimp's avatar
 
sjplimp committed
   copy -> copy_from function
sjplimp's avatar
 
sjplimp committed
   skip -> granular function if gran with granhistory,
           respa function if respaouter,
sjplimp's avatar
 
sjplimp committed
	   skip_from function for everything else
sjplimp's avatar
 
sjplimp committed
   half_from_full, half, full, gran, respaouter ->
     choose by newton and rq->newton and tri settings
sjplimp's avatar
 
sjplimp committed
     style NSQ options = newton off, newton on
     style BIN options = newton off, newton on and not tri, newton on and tri
     stlye MULTI options = same options as BIN
   if none of these, ptr = NULL since pair_build is not invoked for this list
   use "else if" b/c skip,copy can be set in addition to half,full,etc
------------------------------------------------------------------------- */

void Neighbor::choose_build(int index, NeighRequest *rq)
{
  PairPtr pb = NULL;

sjplimp's avatar
 
sjplimp committed
  if (rq->copy) pb = &Neighbor::copy_from;
sjplimp's avatar
 
sjplimp committed

sjplimp's avatar
 
sjplimp committed
  else if (rq->skip) {
    if (rq->gran && lists[index]->listgranhistory)
      pb = &Neighbor::skip_from_granular;
    else if (rq->respaouter) pb = &Neighbor::skip_from_respa;
    else pb = &Neighbor::skip_from;
sjplimp's avatar
 
sjplimp committed

sjplimp's avatar
 
sjplimp committed
  } else if (rq->half_from_full) {
    if (newton_pair == 0) pb = &Neighbor::half_from_full_no_newton;
    else if (newton_pair == 1) pb = &Neighbor::half_from_full_newton;
sjplimp's avatar
 
sjplimp committed

  } else if (rq->half) {
    if (style == NSQ) {
sjplimp's avatar
 
sjplimp committed
      if (rq->newton == 0) {
sjplimp's avatar
 
sjplimp committed
	if (newton_pair == 0) pb = &Neighbor::half_nsq_no_newton;
	else if (newton_pair == 1) pb = &Neighbor::half_nsq_newton;
sjplimp's avatar
 
sjplimp committed
      } else if (rq->newton == 1) {
	pb = &Neighbor::half_nsq_newton;
      } else if (rq->newton == 2) {
	pb = &Neighbor::half_nsq_no_newton;
      }
sjplimp's avatar
 
sjplimp committed
    } else if (style == BIN) {
sjplimp's avatar
 
sjplimp committed
      if (rq->newton == 0) {
	if (newton_pair == 0) pb = &Neighbor::half_bin_no_newton;
	else if (triclinic == 0) pb = &Neighbor::half_bin_newton;
	else if (triclinic == 1) pb = &Neighbor::half_bin_newton_tri;
      } else if (rq->newton == 1) {
	if (triclinic == 0) pb = &Neighbor::half_bin_newton;
	else if (triclinic == 1) pb = &Neighbor::half_bin_newton_tri;
sjplimp's avatar
 
sjplimp committed
      } else if (rq->newton == 2) pb = &Neighbor::half_bin_no_newton;
sjplimp's avatar
 
sjplimp committed
    } else if (style == MULTI) {
sjplimp's avatar
 
sjplimp committed
      if (rq->newton == 0) {
	if (newton_pair == 0) pb = &Neighbor::half_multi_no_newton;
	else if (triclinic == 0) pb = &Neighbor::half_multi_newton;
	else if (triclinic == 1) pb = &Neighbor::half_multi_newton_tri;
      } else if (rq->newton == 1) {
	if (triclinic == 0) pb = &Neighbor::half_multi_newton;
	else if (triclinic == 1) pb = &Neighbor::half_multi_newton_tri;
sjplimp's avatar
 
sjplimp committed
      } else if (rq->newton == 2) pb = &Neighbor::half_multi_no_newton;
sjplimp's avatar
 
sjplimp committed
    }

  } else if (rq->full) {
sjplimp's avatar
 
sjplimp committed
    if (style == NSQ) {
      if (rq->ghost == 0) pb = &Neighbor::full_nsq;
sjplimp's avatar
 
sjplimp committed
      else if (includegroup) 
	error->all("Neighbor include group not allowed with ghost neighbors");
sjplimp's avatar
 
sjplimp committed
      else if (rq->ghost == 1) pb = &Neighbor::full_nsq_ghost;
    } else if (style == BIN) {
      if (rq->ghost == 0) pb = &Neighbor::full_bin;
sjplimp's avatar
 
sjplimp committed
      else if (includegroup) 
	error->all("Neighbor include group not allowed with ghost neighbors");
sjplimp's avatar
 
sjplimp committed
      else if (rq->ghost == 1) pb = &Neighbor::full_bin_ghost;
    } else if (style == MULTI) {
      if (rq->ghost == 0) pb = &Neighbor::full_multi;
      else error->all("Neighbor multi not yet enabled for ghost neighbors");
    }
sjplimp's avatar
 
sjplimp committed

  } else if (rq->gran) {
    if (style == NSQ) {
      if (newton_pair == 0) pb = &Neighbor::granular_nsq_no_newton;
      else if (newton_pair == 1) pb = &Neighbor::granular_nsq_newton;
    } else if (style == BIN) {
      if (newton_pair == 0) pb = &Neighbor::granular_bin_no_newton;
      else if (triclinic == 0) pb = &Neighbor::granular_bin_newton;
      else if (triclinic == 1) pb = &Neighbor::granular_bin_newton_tri;
    } else if (style == MULTI)
      error->all("Neighbor multi not yet enabled for granular");

  } else if (rq->respaouter) {
    if (style == NSQ) {
      if (newton_pair == 0) pb = &Neighbor::respa_nsq_no_newton;
      else if (newton_pair == 1) pb = &Neighbor::respa_nsq_newton;
    } else if (style == BIN) {
      if (newton_pair == 0) pb = &Neighbor::respa_bin_no_newton;
      else if (triclinic == 0) pb = &Neighbor::respa_bin_newton;
      else if (triclinic == 1) pb = &Neighbor::respa_bin_newton_tri;
    } else if (style == MULTI)
      error->all("Neighbor multi not yet enabled for rRESPA");
  }

sjplimp's avatar
 
sjplimp committed
  // general error check

  if (rq->ghost && !rq->full)
    error->all("Neighbors of ghost atoms only allowed for full neighbor lists");

sjplimp's avatar
 
sjplimp committed
  pair_build[index] = pb;
}

/* ----------------------------------------------------------------------
   determine which stencil_create function each neigh list needs
   based on settings of neigh request, only called if style != NSQ
   skip or copy or half_from_full -> no stencil
   half, gran, respaouter, full -> choose by newton and tri and dimension
   if none of these, ptr = NULL since this list needs no stencils
   use "else if" b/c skip,copy can be set in addition to half,full,etc
------------------------------------------------------------------------- */

void Neighbor::choose_stencil(int index, NeighRequest *rq)
{
  StencilPtr sc = NULL;

  if (rq->skip || rq->copy || rq->half_from_full) sc = NULL;

  else if (rq->half || rq->gran || rq->respaouter) {
    if (style == BIN) {
sjplimp's avatar
 
sjplimp committed
      if (rq->newton == 0) {
	if (newton_pair == 0) {
	  if (dimension == 2)
	    sc = &Neighbor::stencil_half_bin_2d_no_newton;
	  else if (dimension == 3)
	    sc = &Neighbor::stencil_half_bin_3d_no_newton;
	} else if (triclinic == 0) {
	  if (dimension == 2)
	    sc = &Neighbor::stencil_half_bin_2d_newton;
	  else if (dimension == 3)
	    sc = &Neighbor::stencil_half_bin_3d_newton;
	} else if (triclinic == 1) {
	  if (dimension == 2)
	    sc = &Neighbor::stencil_half_bin_2d_newton_tri;
	  else if (dimension == 3) 
	    sc = &Neighbor::stencil_half_bin_3d_newton_tri;
	}
      } else if (rq->newton == 1) {
	if (triclinic == 0) {
	  if (dimension == 2)
	    sc = &Neighbor::stencil_half_bin_2d_newton;
	  else if (dimension == 3)
	    sc = &Neighbor::stencil_half_bin_3d_newton;
	} else if (triclinic == 1) {
	  if (dimension == 2)
	    sc = &Neighbor::stencil_half_bin_2d_newton_tri;
	  else if (dimension == 3) 
	    sc = &Neighbor::stencil_half_bin_3d_newton_tri;
	}
      } else if (rq->newton == 2) {
	if (dimension == 2)
	  sc = &Neighbor::stencil_half_bin_2d_no_newton;
	else if (dimension == 3)
	  sc = &Neighbor::stencil_half_bin_3d_no_newton;
sjplimp's avatar
 
sjplimp committed
      }
sjplimp's avatar
 
sjplimp committed

sjplimp's avatar
 
sjplimp committed
    } else if (style == MULTI) {
sjplimp's avatar
 
sjplimp committed
      if (rq->newton == 0) {
	if (newton_pair == 0) {
	  if (dimension == 2) 
	    sc = &Neighbor::stencil_half_multi_2d_no_newton;
	  else if (dimension == 3)
	    sc = &Neighbor::stencil_half_multi_3d_no_newton;
	} else if (triclinic == 0) {
	  if (dimension == 2) 
	    sc = &Neighbor::stencil_half_multi_2d_newton;
	  else if (dimension == 3)
	    sc = &Neighbor::stencil_half_multi_3d_newton;
	} else if (triclinic == 1) {
	  if (dimension == 2)
	    sc = &Neighbor::stencil_half_multi_2d_newton_tri;
	  else if (dimension == 3) 
	    sc = &Neighbor::stencil_half_multi_3d_newton_tri;
	}
      } else if (rq->newton == 1) {
	if (triclinic == 0) {
	  if (dimension == 2) 
	    sc = &Neighbor::stencil_half_multi_2d_newton;
	  else if (dimension == 3)
	    sc = &Neighbor::stencil_half_multi_3d_newton;
	} else if (triclinic == 1) {
	  if (dimension == 2)
	    sc = &Neighbor::stencil_half_multi_2d_newton_tri;
	  else if (dimension == 3) 
	    sc = &Neighbor::stencil_half_multi_3d_newton_tri;
	}
      } else if (rq->newton == 2) {
	if (dimension == 2) 
	  sc = &Neighbor::stencil_half_multi_2d_no_newton;
sjplimp's avatar
 
sjplimp committed
	else if (dimension == 3)
	  sc = &Neighbor::stencil_half_multi_3d_no_newton;
      }
    }

  } else if (rq->full) {
    if (style == BIN) {
sjplimp's avatar
 
sjplimp committed
      if (dimension == 2) {
	if (rq->ghost) sc = &Neighbor::stencil_full_ghost_bin_2d;
	else sc = &Neighbor::stencil_full_bin_2d;
      }
      else if (dimension == 3) {
	if (rq->ghost) sc = &Neighbor::stencil_full_ghost_bin_3d;
	else sc = &Neighbor::stencil_full_bin_3d;
      }
sjplimp's avatar
 
sjplimp committed
    } else if (style == MULTI) {
      if (dimension == 2) sc = &Neighbor::stencil_full_multi_2d;
      else if (dimension == 3) sc = &Neighbor::stencil_full_multi_3d;
    }