Commit d413eb9e authored by jrgissing's avatar jrgissing
Browse files

faster, simpler, 'more completely random' way to do this

parent a1483989
Loading
Loading
Loading
Loading
+91 −86
Original line number Diff line number Diff line
@@ -110,11 +110,11 @@ void CreateAtoms::command(int narg, char **arg)
  remapflag = 0;
  mode = ATOM;
  int molseed;
  int nboxseed;
  int insertseed;
  varflag = 0;
  vstr = xstr = ystr = zstr = NULL;
  quatone[0] = quatone[1] = quatone[2] = 0.0;
  nlattpts = created_Nmask = nbox = nboxflag = 0;
  nlattpts = ninsert = insertflag = 0;
  Nmask = NULL;

  nbasis = domain->lattice->nbasis;
@@ -200,9 +200,9 @@ void CreateAtoms::command(int narg, char **arg)
      iarg += 5;
    } else if (strcmp(arg[iarg],"insert") == 0) {
      if (iarg+3 > narg) error->all(FLERR,"Illegal create_atoms command");
      nbox = force->inumeric(FLERR,arg[iarg+1]);
      nboxseed = force->inumeric(FLERR,arg[iarg+2]);
      nboxflag = 1;
      ninsert = force->inumeric(FLERR,arg[iarg+1]);
      insertseed = force->inumeric(FLERR,arg[iarg+2]);
      insertflag = 1;
      iarg += 3;
    } else error->all(FLERR,"Illegal create_atoms command");
  }
@@ -241,8 +241,8 @@ void CreateAtoms::command(int narg, char **arg)
    ranmol = new RanMars(lmp,molseed+comm->me);
  }

  if (nboxflag) {
    ranbox = new RanMars(lmp,nboxseed+comm->me);
  if (insertflag) {
    ranbox = new RanMars(lmp,insertseed+comm->me);
  }

  // error check and further setup for variable test
@@ -821,71 +821,78 @@ void CreateAtoms::add_lattice()
void CreateAtoms::lattice_mask()
{

  // Nmask will be used to choose which lattice points to insert
  Nmask = new int[nlattpts];
  for (int i = 0; i < nlattpts; i++) 
    Nmask[i] = 1;
  
  if (nbox == 0 && nboxflag && me == 0) error->warning(FLERR,"Specifying an 'insert' value of '0' is equivalent to no 'insert' keyword");
  if (ninsert == 0 && insertflag && me == 0)
    error->warning(FLERR,"Specifying an 'insert' value of '0' is equivalent to no 'insert' keyword");

  int nboxme = 0;
  if (nbox > 0) {
  if (ninsert > 0) {
    int nboxme;
    if (nprocs > 1) {
      int *allnlattpts = new int[nprocs]();
      int allnboxmes[nprocs];
      int cumsum_lattpts[nprocs];
      for (size_t i = 0; i < nprocs; i++)
        allnboxmes[i] = 0;

      MPI_Allgather(&nlattpts, 1, MPI_INT, allnlattpts, 1, MPI_INT, world);

      if (me == 0) {
        int total_lattpts = 0;
      for (int i = 0; i < nprocs; i++)
        for (int i = 0; i < nprocs; i++) {
          total_lattpts += allnlattpts[i];
          cumsum_lattpts[i] = total_lattpts;
        }

      if (nbox > total_lattpts) error->all(FLERR,"Attempting to insert more particles than available lattice points");
      if (nbox < 0) error->all(FLERR,"Cannot insert a negative number of particles (in this universe)");
      
      // adjust nboxme based on personal number of eligible lattice points
      
      nboxme = round(nbox*nlattpts/total_lattpts);
      
      // limit nboxme to available lattice points on this processor
      
      if (nboxme > nlattpts) nboxme = nlattpts;
      
      // readjust so that all nboxme's add to exactly nbox
      
      int sum_nboxme;
      MPI_Allreduce(&nboxme,&sum_nboxme,1,MPI_INT,MPI_SUM,world);

      if (nbox != sum_nboxme) {
        if (ninsert > total_lattpts)
          error->all(FLERR,"Attempting to insert more particles than available lattice points");
        if (ninsert < 0)
          error->all(FLERR,"Cannot insert a negative number of particles (in this universe)");

        int diff = nbox - sum_nboxme;
        int diff_sign = 1;
        if (diff < 0) {
          diff_sign = -1;
          diff = -diff;
        // using proc 0, let's insert N particles onto available lattice points by instead
        // poking [nlattpts - N] holes into the lattice, randomly
        int allNmask[total_lattpts];
        for (int i = 0; i < total_lattpts; i++)
          allNmask[i] = 1;
        int nholes = total_lattpts - ninsert;
        int noptions = total_lattpts;
        for (int i = 0; i < nholes; i++) {
          int hindex = ceil(ranbox->uniform()*noptions);
          int optcount = 0;
          for (int j = 0; j < total_lattpts; j++) {
            if (allNmask[j] == 1) {
              optcount++;
              if (optcount == hindex) {
                allNmask[j] = 0;
                noptions--;
                break;
              }
            }
          }
        }

        // go around adding or subtracting one from all processors (if there's space) until equal
        int which_proc = 0;
        int success_me = 0, success_all = 0;
        int failed_me = 0, failed_all = 0;
        while (success_all < diff && failed_all < nprocs) {
          if (me == which_proc++ && !failed_me)
            if (nboxme < nlattpts) {
              nboxme += diff_sign;
              success_me++;
            } else {
              failed_me == 1;
        // tell individual procs their nboxme (personal # to insert)
        int iproc = 0;
        while (allnlattpts[iproc] == 0 && iproc < nprocs)
          iproc++;
        for (int i = 0; i < total_lattpts; i++) {
          if (i == cumsum_lattpts[iproc]) {
            iproc++;
            while (allnlattpts[iproc] == 0 && iproc < nprocs)
              iproc++;
          }
          MPI_Allreduce(&success_me,&success_all,1,MPI_INT,MPI_SUM,world);
          MPI_Allreduce(&failed_me,&failed_all,1,MPI_INT,MPI_SUM,world);
          if (which_proc > nprocs)
            which_proc = 0;
          allnboxmes[iproc] += allNmask[i];
        }
        // should have guaranteed success at this point
        if (failed_all == nprocs) error->warning(FLERR,"This is an uncaught error. Ask developer");
      }
      MPI_Scatter(&allnboxmes, 1, MPI_INT, &nboxme, 1, MPI_INT, 0, world);
      delete [] allnlattpts;
    } else nboxme = nbox;
    } else nboxme = ninsert;

    // probably faster to have individual processors 're-choose' their random points
    // Nmask will be used to indicate which lattice points to insert
    if (nlattpts < nboxme) printf("WHOAA\n"); //debug
    Nmask = new int[nlattpts];
    for (int i = 0; i < nlattpts; i++)
      Nmask[i] = 1;

    // let's insert N particles onto available lattice points by instead
    // poking [nlattpts - N] holes into the lattice, randomly
@@ -907,8 +914,6 @@ void CreateAtoms::lattice_mask()
    }
  }

  created_Nmask = 1;
  
}

/* ----------------------------------------------------------------------
+2 −2
Original line number Diff line number Diff line
@@ -54,7 +54,7 @@ class CreateAtoms : protected Pointers {
  void add_molecule(double *, double * = NULL);
  int nlattpts;                // number of eligible lattice points
  int *Nmask;                  // used to insert N number of particles on lattice
  int created_Nmask,nbox,nboxflag; 
  int ninsert,insertflag;
  int vartest(double *);       // evaluate a variable with new atom position
};