Пример #1
0
void Ridge::UpdateMapping()
{

        for (int i = 0; i < atom->nlocal; i++) domain->remap(atom->x[i],atom->image[i]);
        if (domain->triclinic) domain->x2lamda(atom->nlocal);
        domain->reset_box();
        Irregular *irregular = new Irregular(lmp);
        irregular->migrate_atoms(1);
        delete irregular;
        if (domain->triclinic) domain->lamda2x(atom->nlocal);

	return;
}
Пример #2
0
void ReadRestart::command(int narg, char **arg)
{
  if (narg != 1) error->all(FLERR,"Illegal read_restart command");

  if (domain->box_exist)
    error->all(FLERR,"Cannot read_restart after simulation box is defined");

  MPI_Comm_rank(world,&me);
  MPI_Comm_size(world,&nprocs);

  // if filename contains "*", search dir for latest restart file

  char *file = new char[strlen(arg[0]) + 16];
  if (strchr(arg[0],'*')) {
    int n;
    if (me == 0) {
      file_search(arg[0],file);
      n = strlen(file) + 1;
    }
    MPI_Bcast(&n,1,MPI_INT,0,world);
    MPI_Bcast(file,n,MPI_CHAR,0,world);
  } else strcpy(file,arg[0]);

  // check for multiproc files and an MPI-IO filename

  if (strchr(arg[0],'%')) multiproc = 1;
  else multiproc = 0;
  if (strstr(arg[0],".mpi")) mpiioflag = 1;
  else mpiioflag = 0;

  if (multiproc && mpiioflag) 
    error->all(FLERR,
               "Read restart MPI-IO output not allowed with '%' in filename");

  if (mpiioflag) {
    mpiio = new RestartMPIIO(lmp);
    if (!mpiio->mpiio_exists) 
      error->all(FLERR,"Reading from MPI-IO filename when "
                 "MPIIO package is not installed");
  }

  // open single restart file or base file for multiproc case

  if (me == 0) {
    if (screen) fprintf(screen,"Reading restart file ...\n");
    char *hfile;
    if (multiproc) {
      hfile = new char[strlen(file) + 16];
      char *ptr = strchr(file,'%');
      *ptr = '\0';
      sprintf(hfile,"%s%s%s",file,"base",ptr+1);
      *ptr = '%';
    } else hfile = file;
    fp = fopen(hfile,"rb");
    if (fp == NULL) {
      char str[128];
      sprintf(str,"Cannot open restart file %s",hfile);
      error->one(FLERR,str);
    }
    if (multiproc) delete [] hfile;
  }

  // read magic string, endian flag, numeric version

  magic_string();
  endian();
  int incompatible = version_numeric();

  // read header info which creates simulation box

  header(incompatible);
  domain->box_exist = 1;

  // problem setup using info from header

  int n;
  if (nprocs == 1) n = static_cast<int> (atom->natoms);
  else n = static_cast<int> (LB_FACTOR * atom->natoms / nprocs);

  atom->allocate_type_arrays();
  atom->avec->grow(n);
  n = atom->nmax;

  domain->print_box("  ");
  domain->set_initial_box();
  domain->set_global_box();
  comm->set_proc_grid();
  domain->set_local_box();

  // read groups, ntype-length arrays, force field, fix info from file
  // nextra = max # of extra quantities stored with each atom

  group->read_restart(fp);
  type_arrays();
  force_fields();

  int nextra = modify->read_restart(fp);
  atom->nextra_store = nextra;
  memory->create(atom->extra,n,nextra,"atom:extra");

  // read file layout info

  file_layout();

  // close header file if in multiproc mode

  if (multiproc && me == 0) fclose(fp);

  // read per-proc info

  AtomVec *avec = atom->avec;

  int maxbuf = 0;
  double *buf = NULL;
  int m,flag;

  // MPI-IO input from single file

  if (mpiioflag) {
    // add calls to RestartMPIIO class
    // reopen header file
    // perform reads
    // allow for different # of procs reading than wrote the file

    // mpiio->open(file);
    // mpiio->read();
    // mpiio->close();

    // then process atom info as

    //m = 0;
    //while (m < n) m += avec->unpack_restart(&buf[m]);
  }

  // input of single native file
  // nprocs_file = # of chunks in file
  // proc 0 reads a chunk and bcasts it to other procs
  // each proc unpacks the atoms, saving ones in it's sub-domain
  // check for atom in sub-domain differs for orthogonal vs triclinic box

  else if (multiproc == 0) {

    int triclinic = domain->triclinic;
    double *x,lamda[3];
    double *coord,*sublo,*subhi;
    if (triclinic == 0) {
      sublo = domain->sublo;
      subhi = domain->subhi;
    } else {
      sublo = domain->sublo_lamda;
      subhi = domain->subhi_lamda;
    }

    for (int iproc = 0; iproc < nprocs_file; iproc++) {
      if (read_int() != PERPROC) 
        error->all(FLERR,"Invalid flag in peratom section of restart file");

      n = read_int();
      if (n > maxbuf) {
        maxbuf = n;
        memory->destroy(buf);
        memory->create(buf,maxbuf,"read_restart:buf");
      }
      read_double_vec(n,buf);

      m = 0;
      while (m < n) {
        x = &buf[m+1];
        if (triclinic) {
          domain->x2lamda(x,lamda);
          coord = lamda;
        } else coord = x;

        if (coord[0] >= sublo[0] && coord[0] < subhi[0] &&
            coord[1] >= sublo[1] && coord[1] < subhi[1] &&
            coord[2] >= sublo[2] && coord[2] < subhi[2]) {
          m += avec->unpack_restart(&buf[m]);
        }
        else m += static_cast<int> (buf[m]);
      }
    }

    if (me == 0) fclose(fp);
  }

  // input of multiple native files with procs <= files
  // # of files = multiproc_file
  // each proc reads a subset of files, striding by nprocs
  // each proc keeps all atoms in all perproc chunks in its files

  else if (nprocs <= multiproc_file) {

    char *procfile = new char[strlen(file) + 16];
    char *ptr = strchr(file,'%');

    for (int iproc = me; iproc < multiproc_file; iproc += nprocs) {
      *ptr = '\0';
      sprintf(procfile,"%s%d%s",file,iproc,ptr+1);
      *ptr = '%';
      fp = fopen(procfile,"rb");
      if (fp == NULL) {
        char str[128];
        sprintf(str,"Cannot open restart file %s",procfile);
        error->one(FLERR,str);
      }

      fread(&flag,sizeof(int),1,fp);
      if (flag != PROCSPERFILE) 
        error->one(FLERR,"Invalid flag in peratom section of restart file");
      int procsperfile;
      fread(&procsperfile,sizeof(int),1,fp);

      for (int i = 0; i < procsperfile; i++) {
        fread(&flag,sizeof(int),1,fp);
        if (flag != PERPROC) 
          error->one(FLERR,"Invalid flag in peratom section of restart file");
        
        fread(&n,sizeof(int),1,fp);
        if (n > maxbuf) {
          maxbuf = n;
          memory->destroy(buf);
          memory->create(buf,maxbuf,"read_restart:buf");
        }
        fread(buf,sizeof(double),n,fp);

        m = 0;
        while (m < n) m += avec->unpack_restart(&buf[m]);
      }

      fclose(fp);
    }

    delete [] procfile;
  }

  // input of multiple native files with procs > files
  // # of files = multiproc_file
  // cluster procs based on # of files
  // 1st proc in each cluster reads per-proc chunks from file
  // sends chunks round-robin to other procs in its cluster
  // each proc keeps all atoms in its perproc chunks in file

  else {

    // nclusterprocs = # of procs in my cluster that read from one file
    // filewriter = 1 if this proc reads file, else 0
    // fileproc = ID of proc in my cluster who reads from file
    // clustercomm = MPI communicator within my cluster of procs

    int nfile = multiproc_file;
    int icluster = static_cast<int> ((bigint) me * nfile/nprocs);
    int fileproc = static_cast<int> ((bigint) icluster * nprocs/nfile);
    int fcluster = static_cast<int> ((bigint) fileproc * nfile/nprocs);
    if (fcluster < icluster) fileproc++;
    int fileprocnext = 
      static_cast<int> ((bigint) (icluster+1) * nprocs/nfile);
    fcluster = static_cast<int> ((bigint) fileprocnext * nfile/nprocs);
    if (fcluster < icluster+1) fileprocnext++;
    int nclusterprocs = fileprocnext - fileproc;
    int filereader = 0;
    if (me == fileproc) filereader = 1;
    MPI_Comm clustercomm;
    MPI_Comm_split(world,icluster,0,&clustercomm);

    if (filereader) {
      char *procfile = new char[strlen(file) + 16];
      char *ptr = strchr(file,'%');
      *ptr = '\0';
      sprintf(procfile,"%s%d%s",file,icluster,ptr+1);
      *ptr = '%';
      fp = fopen(procfile,"rb");
      if (fp == NULL) {
        char str[128];
        sprintf(str,"Cannot open restart file %s",procfile);
        error->one(FLERR,str);
      }
      delete [] procfile;
    }

    int flag,procsperfile;

    if (filereader) {
      fread(&flag,sizeof(int),1,fp);
      if (flag != PROCSPERFILE) 
        error->one(FLERR,"Invalid flag in peratom section of restart file");
      fread(&procsperfile,sizeof(int),1,fp);
    }
    MPI_Bcast(&procsperfile,1,MPI_INT,0,clustercomm);

    int tmp,iproc;
    MPI_Status status;
    MPI_Request request;

    for (int i = 0; i < procsperfile; i++) {
      if (filereader) {
        fread(&flag,sizeof(int),1,fp);
        if (flag != PERPROC) 
          error->one(FLERR,"Invalid flag in peratom section of restart file");

        fread(&n,sizeof(int),1,fp);
        if (n > maxbuf) {
          maxbuf = n;
          memory->destroy(buf);
          memory->create(buf,maxbuf,"read_restart:buf");
        }
        fread(buf,sizeof(double),n,fp);

        if (i % nclusterprocs) {
          iproc = me + (i % nclusterprocs);
          MPI_Send(&n,1,MPI_INT,iproc,0,world);
          MPI_Recv(&tmp,0,MPI_INT,iproc,0,world,&status);
          MPI_Rsend(buf,n,MPI_DOUBLE,iproc,0,world);
        }

      } else if (i % nclusterprocs == me - fileproc) {
        MPI_Recv(&n,1,MPI_INT,fileproc,0,world,&status);
        if (n > maxbuf) {
          maxbuf = n;
          memory->destroy(buf);
          memory->create(buf,maxbuf,"read_restart:buf");
        }
        MPI_Irecv(buf,n,MPI_DOUBLE,fileproc,0,world,&request);
        MPI_Send(&tmp,0,MPI_INT,fileproc,0,world);
        MPI_Wait(&request,&status);
      }

      if (i % nclusterprocs == me - fileproc) {
        m = 0;
        while (m < n) m += avec->unpack_restart(&buf[m]);
      }
    }

    if (filereader) fclose(fp);
    MPI_Comm_free(&clustercomm);
  }

  // clean-up memory

  delete [] file;
  memory->destroy(buf);

  // for multiproc or MPI-IO files:
  // perform irregular comm to migrate atoms to correct procs

  if (multiproc || mpiioflag) {

    // create a temporary fix to hold and migrate extra atom info
    // necessary b/c irregular will migrate atoms

    if (nextra) {
      char cextra[8],fixextra[8];
      sprintf(cextra,"%d",nextra);
      sprintf(fixextra,"%d",modify->nfix_restart_peratom);
      char **newarg = new char*[5];
      newarg[0] = (char *) "_read_restart";
      newarg[1] = (char *) "all";
      newarg[2] = (char *) "READ_RESTART";
      newarg[3] = cextra;
      newarg[4] = fixextra;
      modify->add_fix(5,newarg);
      delete [] newarg;
    }

    // move atoms to new processors via irregular()
    // in case read by different proc than wrote restart file
    // first do map_init() since irregular->migrate_atoms() will do map_clear()

    if (atom->map_style) atom->map_init();
    if (domain->triclinic) domain->x2lamda(atom->nlocal);
    Irregular *irregular = new Irregular(lmp);
    irregular->migrate_atoms();
    delete irregular;
    if (domain->triclinic) domain->lamda2x(atom->nlocal);

    // put extra atom info held by fix back into atom->extra
    // destroy temporary fix

    if (nextra) {
      memory->destroy(atom->extra);
      memory->create(atom->extra,atom->nmax,nextra,"atom:extra");
      int ifix = modify->find_fix("_read_restart");
      FixReadRestart *fix = (FixReadRestart *) modify->fix[ifix];
      int *count = fix->count;
      double **extra = fix->extra;
      double **atom_extra = atom->extra;
      int nlocal = atom->nlocal;
      for (int i = 0; i < nlocal; i++)
        for (int j = 0; j < count[i]; j++)
          atom_extra[i][j] = extra[i][j];
      modify->delete_fix("_read_restart");
    }
  }

  // check that all atoms were assigned to procs

  bigint natoms;
  bigint nblocal = atom->nlocal;
  MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);

  if (me == 0) {
    if (screen) fprintf(screen,"  " BIGINT_FORMAT " atoms\n",natoms);
    if (logfile) fprintf(logfile,"  " BIGINT_FORMAT " atoms\n",natoms);
  }

  if (natoms != atom->natoms)
    error->all(FLERR,"Did not assign all atoms correctly");

  if (me == 0) {
    if (atom->nbonds) {
      if (screen) fprintf(screen,"  " BIGINT_FORMAT " bonds\n",atom->nbonds);
      if (logfile) fprintf(logfile,"  " BIGINT_FORMAT " bonds\n",atom->nbonds);
    }
    if (atom->nangles) {
      if (screen) fprintf(screen,"  " BIGINT_FORMAT " angles\n",
                          atom->nangles);
      if (logfile) fprintf(logfile,"  " BIGINT_FORMAT " angles\n",
                           atom->nangles);
    }
    if (atom->ndihedrals) {
      if (screen) fprintf(screen,"  " BIGINT_FORMAT " dihedrals\n",
                          atom->ndihedrals);
      if (logfile) fprintf(logfile,"  " BIGINT_FORMAT " dihedrals\n",
                           atom->ndihedrals);
    }
    if (atom->nimpropers) {
      if (screen) fprintf(screen,"  " BIGINT_FORMAT " impropers\n",
                          atom->nimpropers);
      if (logfile) fprintf(logfile,"  " BIGINT_FORMAT " impropers\n",
                           atom->nimpropers);
    }
  }

  // check if tags are being used
  // create global mapping and bond topology now that system is defined

  flag = 0;
  for (int i = 0; i < atom->nlocal; i++)
    if (atom->tag[i] > 0) flag = 1;
  int flag_all;
  MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_MAX,world);
  if (flag_all == 0) atom->tag_enable = 0;

  if (atom->map_style) {
    atom->map_init();
    atom->map_set();
  }
  if (atom->molecular) {
    Special special(lmp);
    special.build();
  }
}
Пример #3
0
void ReadRestart::command(int narg, char **arg)
{
  if (narg != 1) error->all(FLERR,"Illegal read_restart command");

  if (domain->box_exist)
    error->all(FLERR,"Cannot read_restart after simulation box is defined");

  MPI_Comm_rank(world,&me);
  MPI_Comm_size(world,&nprocs);

  // if filename contains "*", search dir for latest restart file

  char *file = new char[strlen(arg[0]) + 16];
  if (strchr(arg[0],'*')) {
    int n;
    if (me == 0) {
      file_search(arg[0],file);
      n = strlen(file) + 1;
    }
    MPI_Bcast(&n,1,MPI_INT,0,world);
    MPI_Bcast(file,n,MPI_CHAR,0,world);
  } else strcpy(file,arg[0]);

  // check if filename contains "%"

  int multiproc;
  if (strchr(file,'%')) multiproc = 1;
  else multiproc = 0;

  // open single restart file or base file for multiproc case
  // auto-detect whether byte swapping needs to be done as file is read

  if (me == 0) {
    if (screen) fprintf(screen,"Reading restart file ...\n");
    char *hfile;
    if (multiproc) {
      hfile = new char[strlen(file) + 16];
      char *ptr = strchr(file,'%');
      *ptr = '\0';
      sprintf(hfile,"%s%s%s",file,"base",ptr+1);
      *ptr = '%';
    } else hfile = file;
    fp = fopen(hfile,"rb");
    if (fp == NULL) {
      char str[128];
      sprintf(str,"Cannot open restart file %s",hfile);
      error->one(FLERR,str);
    }
    swapflag = autodetect(&fp,hfile);
    if (multiproc) delete [] hfile;
  }

  MPI_Bcast(&swapflag,1,MPI_INT,0,world);

  // read header info and create atom style and simulation box

  header();
  domain->box_exist = 1;

  // problem setup using info from header

  int n;
  if (nprocs == 1) n = static_cast<int> (atom->natoms);
  else n = static_cast<int> (LB_FACTOR * atom->natoms / nprocs);

  atom->allocate_type_arrays();
  atom->avec->grow(n);
  n = atom->nmax;

  domain->print_box("  ");
  domain->set_initial_box();
  domain->set_global_box();
  comm->set_proc_grid();
  domain->set_local_box();

  // read groups, ntype-length arrays, force field, fix info from file
  // nextra = max # of extra quantities stored with each atom

  group->read_restart(fp);
  type_arrays();
  force_fields();

  int nextra = modify->read_restart(fp);
  atom->nextra_store = nextra;
  memory->create(atom->extra,n,nextra,"atom:extra");

  // single file:
  // nprocs_file = # of chunks in file
  // proc 0 reads chunks one at a time and bcasts it to other procs
  // each proc unpacks the atoms, saving ones in it's sub-domain
  // check for atom in sub-domain differs for orthogonal vs triclinic box
  // close restart file when done

  AtomVec *avec = atom->avec;

  int maxbuf = 0;
  double *buf = NULL;
  int m;

  if (multiproc == 0) {
    int triclinic = domain->triclinic;
    double *x,lamda[3];
    double *coord,*sublo,*subhi;
    if (triclinic == 0) {
      sublo = domain->sublo;
      subhi = domain->subhi;
    } else {
      sublo = domain->sublo_lamda;
      subhi = domain->subhi_lamda;
    }

    for (int iproc = 0; iproc < nprocs_file; iproc++) {
      n = read_int();
      if (n > maxbuf) {
        maxbuf = n;
        memory->destroy(buf);
        memory->create(buf,maxbuf,"read_restart:buf");
      }

      if (n > 0) {
        if (me == 0) nread_double(buf,n,fp);
        MPI_Bcast(buf,n,MPI_DOUBLE,0,world);
      }

      m = 0;
      while (m < n) {
        x = &buf[m+1];
        if (triclinic) {
          domain->x2lamda(x,lamda);
          coord = lamda;
        } else coord = x;

        if (coord[0] >= sublo[0] && coord[0] < subhi[0] &&
            coord[1] >= sublo[1] && coord[1] < subhi[1] &&
            coord[2] >= sublo[2] && coord[2] < subhi[2]) {
          m += avec->unpack_restart(&buf[m]);
        }
        else m += static_cast<int> (buf[m]);
      }
    }

    if (me == 0) fclose(fp);

  // one file per proc:
  // nprocs_file = # of files
  // each proc reads 1/P fraction of files, keeping all atoms in the files
  // perform irregular comm to migrate atoms to correct procs
  // close restart file when done

  } else {
    if (me == 0) fclose(fp);
    char *perproc = new char[strlen(file) + 16];
    char *ptr = strchr(file,'%');

    for (int iproc = me; iproc < nprocs_file; iproc += nprocs) {
      *ptr = '\0';
      sprintf(perproc,"%s%d%s",file,iproc,ptr+1);
      *ptr = '%';
      fp = fopen(perproc,"rb");
      if (fp == NULL) {
        char str[128];
        sprintf(str,"Cannot open restart file %s",perproc);
        error->one(FLERR,str);
      }

      nread_int(&n,1,fp);
      if (n > maxbuf) {
        maxbuf = n;
        memory->destroy(buf);
        memory->create(buf,maxbuf,"read_restart:buf");
      }
      if (n > 0) nread_double(buf,n,fp);

      m = 0;
      while (m < n) m += avec->unpack_restart(&buf[m]);
      fclose(fp);
    }

    delete [] perproc;

    // create a temporary fix to hold and migrate extra atom info
    // necessary b/c irregular will migrate atoms

    if (nextra) {
      char cextra[8],fixextra[8];
      sprintf(cextra,"%d",nextra);
      sprintf(fixextra,"%d",modify->nfix_restart_peratom);
      char **newarg = new char*[5];
      newarg[0] = (char *) "_read_restart";
      newarg[1] = (char *) "all";
      newarg[2] = (char *) "READ_RESTART";
      newarg[3] = cextra;
      newarg[4] = fixextra;
      modify->add_fix(5,newarg);
      delete [] newarg;
    }

    // move atoms to new processors via irregular()
    // in case read by different proc than wrote restart file
    // first do map_init() since irregular->migrate_atoms() will do map_clear()

    if (atom->map_style) atom->map_init();
    if (domain->triclinic) domain->x2lamda(atom->nlocal);
    Irregular *irregular = new Irregular(lmp);
    irregular->migrate_atoms();
    delete irregular;
    if (domain->triclinic) domain->lamda2x(atom->nlocal);

    // put extra atom info held by fix back into atom->extra
    // destroy temporary fix

    if (nextra) {
      memory->destroy(atom->extra);
      memory->create(atom->extra,atom->nmax,nextra,"atom:extra");
      int ifix = modify->find_fix("_read_restart");
      FixReadRestart *fix = (FixReadRestart *) modify->fix[ifix];
      int *count = fix->count;
      double **extra = fix->extra;
      double **atom_extra = atom->extra;
      int nlocal = atom->nlocal;
      for (int i = 0; i < nlocal; i++)
        for (int j = 0; j < count[i]; j++)
          atom_extra[i][j] = extra[i][j];
      modify->delete_fix("_read_restart");
    }
  }

  // clean-up memory

  delete [] file;
  memory->destroy(buf);

  // check that all atoms were assigned to procs

  bigint natoms;
  bigint nblocal = atom->nlocal;
  MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);

  if (me == 0) {
    if (screen) fprintf(screen,"  " BIGINT_FORMAT " atoms\n",natoms);
    if (logfile) fprintf(logfile,"  " BIGINT_FORMAT " atoms\n",natoms);
  }

  if (natoms != atom->natoms)
    error->all(FLERR,"Did not assign all atoms correctly");

  if (me == 0) {
    if (atom->nbonds) {
      if (screen) fprintf(screen,"  " BIGINT_FORMAT " bonds\n",atom->nbonds);
      if (logfile) fprintf(logfile,"  " BIGINT_FORMAT " bonds\n",atom->nbonds);
    }
    if (atom->nangles) {
      if (screen) fprintf(screen,"  " BIGINT_FORMAT " angles\n",
                          atom->nangles);
      if (logfile) fprintf(logfile,"  " BIGINT_FORMAT " angles\n",
                           atom->nangles);
    }
    if (atom->ndihedrals) {
      if (screen) fprintf(screen,"  " BIGINT_FORMAT " dihedrals\n",
                          atom->ndihedrals);
      if (logfile) fprintf(logfile,"  " BIGINT_FORMAT " dihedrals\n",
                           atom->ndihedrals);
    }
    if (atom->nimpropers) {
      if (screen) fprintf(screen,"  " BIGINT_FORMAT " impropers\n",
                          atom->nimpropers);
      if (logfile) fprintf(logfile,"  " BIGINT_FORMAT " impropers\n",
                           atom->nimpropers);
    }
  }

  // check if tags are being used
  // create global mapping and bond topology now that system is defined

  int flag = 0;
  for (int i = 0; i < atom->nlocal; i++)
    if (atom->tag[i] > 0) flag = 1;
  int flag_all;
  MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_MAX,world);
  if (atom->natoms > 0 && flag_all == 0) atom->tag_enable = 0;

  if (atom->map_style) {
    atom->map_init();
    atom->map_set();
  }
  if (atom->molecular) {
    Special special(lmp);
    special.build();
  }
}
Пример #4
0
void ChangeBox::command(int narg, char **arg)
{
  int i;

  if (domain->box_exist == 0)
    error->all(FLERR,"Change_box command before simulation box is defined");
  if (narg < 2) error->all(FLERR,"Illegal change_box command");
  if (modify->nfix_restart_peratom)
    error->all(FLERR,"Cannot change_box after "
               "reading restart file with per-atom info");

  if (comm->me == 0 && screen) fprintf(screen,"Changing box ...\n");

  // group

  int igroup = group->find(arg[0]);
  if (igroup == -1) error->all(FLERR,"Could not find change_box group ID");
  int groupbit = group->bitmask[igroup];

  // parse operation arguments
  // allocate ops to max possible length
  // volume option does not increment nops

  int dimension = domain->dimension;

  ops = new Operation[narg-1];
  memset(ops,0,(narg-1)*sizeof(Operation));
  nops = 0;

  int iarg = 1;
  while (iarg < narg) {
    if (strcmp(arg[iarg],"x") == 0 || strcmp(arg[iarg],"y") == 0 ||
        strcmp(arg[iarg],"z") == 0) {
      if (iarg+2 > narg) error->all(FLERR,"Illegal change_box command");
      ops[nops].style = XYZ;
      if (strcmp(arg[iarg],"x") == 0) ops[nops].dim = X;
      else if (strcmp(arg[iarg],"y") == 0) ops[nops].dim = Y;
      else if (strcmp(arg[iarg],"z") == 0) ops[nops].dim = Z;

      if (dimension == 2 && ops[nops].dim == Z)
        error->all(FLERR,"Cannot change_box in z dimension for 2d simulation");

      if (strcmp(arg[iarg+1],"final") == 0) {
        if (iarg+4 > narg) error->all(FLERR,"Illegal change_box command");
        ops[nops].flavor = FINAL;
        ops[nops].flo = force->numeric(FLERR,arg[iarg+2]);
        ops[nops].fhi = force->numeric(FLERR,arg[iarg+3]);
        ops[nops].vdim1 = ops[nops].vdim2 = -1;
        nops++;
        iarg += 4;
      } else if (strcmp(arg[iarg+1],"delta") == 0) {
        if (iarg+4 > narg) error->all(FLERR,"Illegal change_box command");
        ops[nops].flavor = DELTA;
        ops[nops].dlo = force->numeric(FLERR,arg[iarg+2]);
        ops[nops].dhi = force->numeric(FLERR,arg[iarg+3]);
        ops[nops].vdim1 = ops[nops].vdim2 = -1;
        nops++;
        iarg += 4;
      } else if (strcmp(arg[iarg+1],"scale") == 0) {
        if (iarg+3 > narg) error->all(FLERR,"Illegal change_box command");
        ops[nops].flavor = SCALE;
        ops[nops].scale = force->numeric(FLERR,arg[iarg+2]);
        ops[nops].vdim1 = ops[nops].vdim2 = -1;
        nops++;
        iarg += 3;
      } else if (strcmp(arg[iarg+1],"volume") == 0) {
        if (nops == 0 || ops[nops-1].style != XYZ ||
            ops[nops].dim == ops[nops-1].dim)
          error->all(FLERR,"Change_box volume used incorrectly");
        if (ops[nops-1].vdim2 >= 0)
          error->all(FLERR,"Change_box volume used incorrectly");
        else if (ops[nops-1].vdim1 >= 0) ops[nops-1].vdim2 = ops[nops].dim;
        else ops[nops-1].vdim1 = ops[nops].dim;
        iarg += 2;

      } else error->all(FLERR,"Illegal change_box command");

    } else if (strcmp(arg[iarg],"xy") == 0 || strcmp(arg[iarg],"xz") == 0 ||
        strcmp(arg[iarg],"yz") == 0) {
      if (iarg+2 > narg) error->all(FLERR,"Illegal change_box command");
      ops[nops].style = TILT;
      if (strcmp(arg[iarg],"xy") == 0) ops[nops].dim = XY;
      else if (strcmp(arg[iarg],"xz") == 0) ops[nops].dim = XZ;
      else if (strcmp(arg[iarg],"yz") == 0) ops[nops].dim = YZ;

      if (dimension == 2 && (ops[nops].dim == XZ || ops[nops].dim == YZ))
        error->all(FLERR,"Cannot change_box in xz or yz for 2d simulation");

      if (strcmp(arg[iarg+1],"final") == 0) {
        if (iarg+3 > narg) error->all(FLERR,"Illegal change_box command");
        ops[nops].flavor = FINAL;
        ops[nops].ftilt = force->numeric(FLERR,arg[iarg+2]);
        nops++;
        iarg += 3;
      } else if (strcmp(arg[iarg+1],"delta") == 0) {
        if (iarg+3 > narg) error->all(FLERR,"Illegal change_box command");
        ops[nops].flavor = DELTA;
        ops[nops].dtilt = force->numeric(FLERR,arg[iarg+2]);
        nops++;
        iarg += 3;
      } else error->all(FLERR,"Illegal change_box command");

    } else if (strcmp(arg[iarg],"boundary") == 0) {
      if (iarg+4 > narg) error->all(FLERR,"Illegal change_box command");
      ops[nops].style = BOUNDARY;
      ops[nops].boundindex = iarg+1;
      nops++;
      iarg += 4;

    } else if (strcmp(arg[iarg],"ortho") == 0) {
      ops[nops].style = ORTHO;
      nops++;
      iarg += 1;

    } else if (strcmp(arg[iarg],"triclinic") == 0) {
      ops[nops].style = TRICLINIC;
      nops++;
      iarg += 1;

    } else if (strcmp(arg[iarg],"set") == 0) {
      if (iarg+1 > narg) error->all(FLERR,"Illegal change_box command");
      ops[nops].style = SET;
      nops++;
      iarg += 1;

    } else if (strcmp(arg[iarg],"remap") == 0) {
      ops[nops].style = REMAP;
      nops++;
      iarg += 1;

    } else break;
  }

  if (nops == 0) error->all(FLERR,"Illegal change_box command");

  // read options from end of input line

  options(narg-iarg,&arg[iarg]);

  // compute scale factors if FINAL,DELTA used since they have distance units

  int flag = 0;
  for (int i = 0; i < nops; i++)
    if (ops[i].style == FINAL || ops[i].style == DELTA) flag = 1;

  if (flag && scaleflag) {
    scale[0] = domain->lattice->xlattice;
    scale[1] = domain->lattice->ylattice;
    scale[2] = domain->lattice->zlattice;
  }
  else scale[0] = scale[1] = scale[2] = 1.0;

  // perform sequence of operations
  // first insure atoms are in current box & update box via shrink-wrap
  // no exchange() since doesn't matter if atoms are assigned to correct procs
  // save current box state so can remap atoms from it, if requested

  if (domain->triclinic) domain->x2lamda(atom->nlocal);
  domain->pbc();
  domain->reset_box();
  if (domain->triclinic) domain->lamda2x(atom->nlocal);
  save_box_state();

  for (int m = 0; m < nops; m++) {
    if (ops[m].style == XYZ) {
      double volume;
      if (domain->dimension == 2) volume = domain->xprd * domain->yprd;
      else volume = domain->xprd * domain->yprd * domain->zprd;

      if (ops[m].flavor == FINAL) {
        domain->boxlo[ops[m].dim] = scale[ops[m].dim]*ops[m].flo;
        domain->boxhi[ops[m].dim] = scale[ops[m].dim]*ops[m].fhi;
        if (ops[m].vdim1 >= 0)
          volume_preserve(ops[m].vdim1,ops[m].vdim2,volume);
        domain->set_initial_box();
        domain->set_global_box();
        domain->set_local_box();
        domain->print_box("  ");

      } else if (ops[m].flavor == DELTA) {
        domain->boxlo[ops[m].dim] += scale[ops[m].dim]*ops[m].dlo;
        domain->boxhi[ops[m].dim] += scale[ops[m].dim]*ops[m].dhi;
        if (ops[m].vdim1 >= 0)
          volume_preserve(ops[m].vdim1,ops[m].vdim2,volume);
        domain->set_initial_box();
        domain->set_global_box();
        domain->set_local_box();
        domain->print_box("  ");

      } else if (ops[m].flavor == SCALE) {
        double mid = 0.5 *
          (domain->boxlo[ops[m].dim] + domain->boxhi[ops[m].dim]);
        double delta = domain->boxlo[ops[m].dim] - mid;
        domain->boxlo[ops[m].dim] = mid + ops[m].scale*delta;
        delta = domain->boxhi[ops[m].dim] - mid;
        domain->boxhi[ops[m].dim] = mid + ops[m].scale*delta;
        if (ops[m].vdim1 >= 0)
          volume_preserve(ops[m].vdim1,ops[m].vdim2,volume);
        domain->set_initial_box();
        domain->set_global_box();
        domain->set_local_box();
        domain->print_box("  ");
      }

    } else if (ops[m].style == TILT) {
      if (domain->triclinic == 0)
        error->all(FLERR,"Cannot change box tilt factors for orthogonal box");

      if (ops[m].flavor == FINAL) {
        if (ops[m].dim == XY) domain->xy = scale[X]*ops[m].ftilt;
        else if (ops[m].dim == XZ) domain->xz = scale[X]*ops[m].ftilt;
        else if (ops[m].dim == YZ) domain->yz = scale[Y]*ops[m].ftilt;
        domain->set_initial_box();
        domain->set_global_box();
        domain->set_local_box();
        domain->print_box("  ");

      } else if (ops[m].flavor == DELTA) {
        if (ops[m].dim == XY) domain->xy += scale[X]*ops[m].dtilt;
        else if (ops[m].dim == XZ) domain->xz += scale[X]*ops[m].dtilt;
        else if (ops[m].dim == YZ) domain->yz += scale[Y]*ops[m].dtilt;
        domain->set_initial_box();
        domain->set_global_box();
        domain->set_local_box();
        domain->print_box("  ");
      }

    } else if (ops[m].style == BOUNDARY) {
      domain->set_boundary(3,&arg[ops[m].boundindex],1);
      if (domain->dimension == 2 && domain->zperiodic == 0)
        error->all(FLERR,
                   "Cannot change box z boundary to "
                   "nonperiodic for a 2d simulation");
      domain->set_initial_box();
      domain->set_global_box();
      domain->set_local_box();

    } else if (ops[m].style == ORTHO) {
      if (domain->xy != 0.0 || domain->yz != 0.0 || domain->xz != 0.0)
        error->all(FLERR,
                   "Cannot change box to orthogonal when tilt is non-zero");
      if (output->ndump)
        error->all(FLERR,
                   "Cannot change box ortho/triclinic with dumps defined");
      for (int i = 0; i < modify->nfix; i++)
        if (modify->fix[i]->no_change_box)
          error->all(FLERR,
                     "Cannot change box ortho/triclinic with "
                     "certain fixes defined");
      domain->triclinic = 0;
      domain->set_initial_box();
      domain->set_global_box();
      domain->set_local_box();
      domain->print_box("  ");

    } else if (ops[m].style == TRICLINIC) {
      if (output->ndump)
        error->all(FLERR,
                   "Cannot change box ortho/triclinic with dumps defined");
      for (int i = 0; i < modify->nfix; i++)
        if (modify->fix[i]->no_change_box)
          error->all(FLERR,
                     "Cannot change box ortho/triclinic with "
                     "certain fixes defined");
      domain->triclinic = 1;
      domain->set_lamda_box();
      domain->set_initial_box();
      domain->set_global_box();
      domain->set_local_box();
      domain->print_box("  ");

    } else if (ops[m].style == SET) {
      save_box_state();

    } else if (ops[m].style == REMAP) {

      if (modify->check_rigid_group_overlap(groupbit))
        error->warning(FLERR,"Attempting to remap atoms in rigid bodies");

      // convert atoms to lamda coords, using last box state
      // convert atoms back to box coords, using current box state
      // save current box state

      double **x = atom->x;
      int *mask = atom->mask;
      int nlocal = atom->nlocal;

      for (i = 0; i < nlocal; i++)
        if (mask[i] & groupbit)
          domain->x2lamda(x[i],x[i],boxlo,h_inv);

      for (i = 0; i < nlocal; i++)
        if (mask[i] & groupbit)
          domain->lamda2x(x[i],x[i]);

      save_box_state();
    }
  }

  // clean up

  delete [] ops;

  // apply shrink-wrap boundary conditions

  if (domain->nonperiodic == 2) {
    if (domain->triclinic) domain->x2lamda(atom->nlocal);
    domain->reset_box();
    if (domain->triclinic) domain->lamda2x(atom->nlocal);
  }

  // move atoms back inside simulation box and to new processors
  // use remap() instead of pbc()
  //   in case box moved a long distance relative to atoms
  // use irregular() in case box moved a long distance relative to atoms

  double **x = atom->x;
  imageint *image = atom->image;
  int nlocal = atom->nlocal;
  for (i = 0; i < nlocal; i++) domain->remap(x[i],image[i]);

  if (domain->triclinic) domain->x2lamda(atom->nlocal);
  domain->reset_box();
  Irregular *irregular = new Irregular(lmp);
  irregular->migrate_atoms(1);
  delete irregular;
  if (domain->triclinic) domain->lamda2x(atom->nlocal);

  // check if any atoms were lost

  bigint natoms;
  bigint nblocal = atom->nlocal;
  MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
  if (natoms != atom->natoms && comm->me == 0) {
    char str[128];
    sprintf(str,"Lost atoms via change_box: original " BIGINT_FORMAT
            " current " BIGINT_FORMAT,atom->natoms,natoms);
    error->warning(FLERR,str);
  }
}
Пример #5
0
void DisplaceAtoms::command(int narg, char **arg)
{
  int i;

  if (domain->box_exist == 0) 
    error->all(FLERR,"Displace_atoms command before simulation box is defined");
  if (narg < 2) error->all(FLERR,"Illegal displace_atoms command");
  if (modify->nfix_restart_peratom) 
    error->all(FLERR,"Cannot displace_atoms after "
	       "reading restart file with per-atom info");

  if (comm->me == 0 && screen) fprintf(screen,"Displacing atoms ...\n");

  // group and style

  int igroup = group->find(arg[0]);
  if (igroup == -1) error->all(FLERR,"Could not find displace_atoms group ID");
  int groupbit = group->bitmask[igroup];

  int style;
  if (strcmp(arg[1],"move") == 0) style = MOVE;
  else if (strcmp(arg[1],"ramp") == 0) style = RAMP;
  else if (strcmp(arg[1],"random") == 0) style = RANDOM;
  else error->all(FLERR,"Illegal displace_atoms command");

  // set option defaults

  scaleflag = 1;

  // read options from end of input line

  if (style == MOVE) options(narg-5,&arg[5]);
  else if (style == RAMP) options(narg-8,&arg[8]);
  else if (style == RANDOM) options(narg-6,&arg[6]);

  // setup scaling

  if (scaleflag && domain->lattice == NULL)
    error->all(FLERR,"Use of displace_atoms with undefined lattice");

  double xscale,yscale,zscale;
  if (scaleflag) {
    xscale = domain->lattice->xlattice;
    yscale = domain->lattice->ylattice;
    zscale = domain->lattice->zlattice;
  }
  else xscale = yscale = zscale = 1.0;

  // move atoms by 3-vector

  if (style == MOVE) {

    double delx = xscale*atof(arg[2]);
    double dely = yscale*atof(arg[3]);
    double delz = zscale*atof(arg[4]);

    double **x = atom->x;
    int *mask = atom->mask;
    int nlocal = atom->nlocal;

    for (i = 0; i < nlocal; i++) {
      if (mask[i] & groupbit) {
	x[i][0] += delx;
	x[i][1] += dely;
	x[i][2] += delz;
      }
    }
  }

  // move atoms in ramped fashion
    
  if (style == RAMP) {

    int d_dim;
    if (strcmp(arg[2],"x") == 0) d_dim = 0;
    else if (strcmp(arg[2],"y") == 0) d_dim = 1;
    else if (strcmp(arg[2],"z") == 0) d_dim = 2;
    else error->all(FLERR,"Illegal displace_atoms ramp command");

    double d_lo,d_hi;
    if (d_dim == 0) {
      d_lo = xscale*atof(arg[3]);
      d_hi = xscale*atof(arg[4]);
    } else if (d_dim == 1) {
      d_lo = yscale*atof(arg[3]);
      d_hi = yscale*atof(arg[4]);
    } else if (d_dim == 2) {
      d_lo = zscale*atof(arg[3]);
      d_hi = zscale*atof(arg[4]);
    }

    int coord_dim;
    if (strcmp(arg[5],"x") == 0) coord_dim = 0;
    else if (strcmp(arg[5],"y") == 0) coord_dim = 1;
    else if (strcmp(arg[5],"z") == 0) coord_dim = 2;
    else error->all(FLERR,"Illegal displace_atoms ramp command");

    double coord_lo,coord_hi;
    if (coord_dim == 0) {
      coord_lo = xscale*atof(arg[6]);
      coord_hi = xscale*atof(arg[7]);
    } else if (coord_dim == 1) {
      coord_lo = yscale*atof(arg[6]);
      coord_hi = yscale*atof(arg[7]);
    } else if (coord_dim == 2) {
      coord_lo = zscale*atof(arg[6]);
      coord_hi = zscale*atof(arg[7]);
    }

    double **x = atom->x;
    int *mask = atom->mask;
    int nlocal = atom->nlocal;

    double fraction,dramp;

    for (i = 0; i < nlocal; i++) {
      if (mask[i] & groupbit) {
	fraction = (x[i][coord_dim] - coord_lo) / (coord_hi - coord_lo);
	fraction = MAX(fraction,0.0);
	fraction = MIN(fraction,1.0);
	dramp = d_lo + fraction*(d_hi - d_lo);
	x[i][d_dim] += dramp;
      }
    }
  }

  // move atoms randomly
  // makes atom result independent of what proc owns it via random->reset()
    
  if (style == RANDOM) {
    RanPark *random = new RanPark(lmp,1);

    double dx = xscale*atof(arg[2]);
    double dy = yscale*atof(arg[3]);
    double dz = zscale*atof(arg[4]);
    int seed = atoi(arg[5]);
    if (seed <= 0) error->all(FLERR,"Illegal displace_atoms random command");

    double **x = atom->x;
    int *mask = atom->mask;
    int nlocal = atom->nlocal;

    for (i = 0; i < nlocal; i++) {
      if (mask[i] & groupbit) {
	random->reset(seed,x[i]);
	x[i][0] += dx * 2.0*(random->uniform()-0.5);
	x[i][1] += dy * 2.0*(random->uniform()-0.5);
	x[i][2] += dz * 2.0*(random->uniform()-0.5);
      }
    }

    delete random;
  }

  // move atoms back inside simulation box and to new processors
  // use remap() instead of pbc() in case atoms moved a long distance
  // use irregular() in case atoms moved a long distance

  double **x = atom->x;
  int *image = atom->image;
  int nlocal = atom->nlocal;
  for (i = 0; i < nlocal; i++) domain->remap(x[i],image[i]);

  if (domain->triclinic) domain->x2lamda(atom->nlocal);
  domain->reset_box();
  Irregular *irregular = new Irregular(lmp);
  irregular->migrate_atoms();
  delete irregular;
  if (domain->triclinic) domain->lamda2x(atom->nlocal);

  // check if any atoms were lost

  bigint natoms;
  bigint nblocal = atom->nlocal;
  MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
  if (natoms != atom->natoms) {
    char str[128];
    sprintf(str,"Lost atoms via displace_atoms: original " BIGINT_FORMAT 
	    " current " BIGINT_FORMAT,atom->natoms,natoms);
    error->all(FLERR,str);
  }
}
Пример #6
0
void DisplaceAtoms::command(int narg, char **arg)
{
    int i;

    if (domain->box_exist == 0)
        error->all(FLERR,"Displace_atoms command before simulation box is defined");
    if (narg < 2) error->all(FLERR,"Illegal displace_atoms command");
    if (modify->nfix_restart_peratom)
        error->all(FLERR,"Cannot displace_atoms after "
                   "reading restart file with per-atom info");

    if (comm->me == 0 && screen) fprintf(screen,"Displacing atoms ...\n");

    // group and style

    igroup = group->find(arg[0]);
    if (igroup == -1) error->all(FLERR,"Could not find displace_atoms group ID");
    groupbit = group->bitmask[igroup];

    int style = -1;
    if (strcmp(arg[1],"move") == 0) style = MOVE;
    else if (strcmp(arg[1],"ramp") == 0) style = RAMP;
    else if (strcmp(arg[1],"random") == 0) style = RANDOM;
    else if (strcmp(arg[1],"rotate") == 0) style = ROTATE;
    else error->all(FLERR,"Illegal displace_atoms command");

    // set option defaults

    scaleflag = 1;

    // read options from end of input line

    if (style == MOVE) options(narg-5,&arg[5]);
    else if (style == RAMP) options(narg-8,&arg[8]);
    else if (style == RANDOM) options(narg-6,&arg[6]);
    else if (style == ROTATE) options(narg-9,&arg[9]);

    // setup scaling

    double xscale,yscale,zscale;
    if (scaleflag) {
        xscale = domain->lattice->xlattice;
        yscale = domain->lattice->ylattice;
        zscale = domain->lattice->zlattice;
    }
    else xscale = yscale = zscale = 1.0;

    // move atoms by 3-vector or specified variable(s)

    if (style == MOVE) {
        move(0,arg[2],xscale);
        move(1,arg[3],yscale);
        move(2,arg[4],zscale);
    }

    // move atoms in ramped fashion

    if (style == RAMP) {

        int d_dim;
        if (strcmp(arg[2],"x") == 0) d_dim = 0;
        else if (strcmp(arg[2],"y") == 0) d_dim = 1;
        else if (strcmp(arg[2],"z") == 0) d_dim = 2;
        else error->all(FLERR,"Illegal displace_atoms ramp command");

        double d_lo,d_hi;
        if (d_dim == 0) {
            d_lo = xscale*force->numeric(FLERR,arg[3]);
            d_hi = xscale*force->numeric(FLERR,arg[4]);
        } else if (d_dim == 1) {
            d_lo = yscale*force->numeric(FLERR,arg[3]);
            d_hi = yscale*force->numeric(FLERR,arg[4]);
        } else if (d_dim == 2) {
            d_lo = zscale*force->numeric(FLERR,arg[3]);
            d_hi = zscale*force->numeric(FLERR,arg[4]);
        }

        int coord_dim;
        if (strcmp(arg[5],"x") == 0) coord_dim = 0;
        else if (strcmp(arg[5],"y") == 0) coord_dim = 1;
        else if (strcmp(arg[5],"z") == 0) coord_dim = 2;
        else error->all(FLERR,"Illegal displace_atoms ramp command");

        double coord_lo,coord_hi;
        if (coord_dim == 0) {
            coord_lo = xscale*force->numeric(FLERR,arg[6]);
            coord_hi = xscale*force->numeric(FLERR,arg[7]);
        } else if (coord_dim == 1) {
            coord_lo = yscale*force->numeric(FLERR,arg[6]);
            coord_hi = yscale*force->numeric(FLERR,arg[7]);
        } else if (coord_dim == 2) {
            coord_lo = zscale*force->numeric(FLERR,arg[6]);
            coord_hi = zscale*force->numeric(FLERR,arg[7]);
        }

        double **x = atom->x;
        int *mask = atom->mask;
        int nlocal = atom->nlocal;

        double fraction,dramp;

        for (i = 0; i < nlocal; i++) {
            if (mask[i] & groupbit) {
                fraction = (x[i][coord_dim] - coord_lo) / (coord_hi - coord_lo);
                fraction = MAX(fraction,0.0);
                fraction = MIN(fraction,1.0);
                dramp = d_lo + fraction*(d_hi - d_lo);
                x[i][d_dim] += dramp;
            }
        }
    }

    // move atoms randomly
    // makes atom result independent of what proc owns it via random->reset()

    if (style == RANDOM) {
        RanPark *random = new RanPark(lmp,1);

        double dx = xscale*force->numeric(FLERR,arg[2]);
        double dy = yscale*force->numeric(FLERR,arg[3]);
        double dz = zscale*force->numeric(FLERR,arg[4]);
        int seed = force->inumeric(FLERR,arg[5]);
        if (seed <= 0) error->all(FLERR,"Illegal displace_atoms random command");

        double **x = atom->x;
        int *mask = atom->mask;
        int nlocal = atom->nlocal;

        for (i = 0; i < nlocal; i++) {
            if (mask[i] & groupbit) {
                random->reset(seed,x[i]);
                x[i][0] += dx * 2.0*(random->uniform()-0.5);
                x[i][1] += dy * 2.0*(random->uniform()-0.5);
                x[i][2] += dz * 2.0*(random->uniform()-0.5);
            }
        }

        delete random;
    }

    // rotate atoms by right-hand rule by theta around R
    // P = point = vector = point of rotation
    // R = vector = axis of rotation
    // R0 = runit = unit vector for R
    // D = X - P = vector from P to X
    // C = (D dot R0) R0 = projection of atom coord onto R line
    // A = D - C = vector from R line to X
    // B = R0 cross A = vector perp to A in plane of rotation
    // A,B define plane of circular rotation around R line
    // X = P + C + A cos(theta) + B sin(theta)

    if (style == ROTATE) {
        double theta_new;
        double axis[3],point[3],qrotate[4],qnew[4];
        double a[3],b[3],c[3],d[3],disp[3],runit[3];
        double *quat;

        int dim = domain->dimension;
        point[0] = xscale*force->numeric(FLERR,arg[2]);
        point[1] = yscale*force->numeric(FLERR,arg[3]);
        point[2] = zscale*force->numeric(FLERR,arg[4]);
        axis[0] = force->numeric(FLERR,arg[5]);
        axis[1] = force->numeric(FLERR,arg[6]);
        axis[2] = force->numeric(FLERR,arg[7]);
        double theta = force->numeric(FLERR,arg[8]);
        if (dim == 2 && (axis[0] != 0.0 || axis[1] != 0.0))
            error->all(FLERR,"Invalid displace_atoms rotate axis for 2d");

        double len = sqrt(axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]);
        if (len == 0.0)
            error->all(FLERR,"Zero length rotation vector with displace_atoms");
        runit[0] = axis[0]/len;
        runit[1] = axis[1]/len;
        runit[2] = axis[2]/len;

        double angle = MY_PI*theta/180.0;
        double sine = sin(angle);
        double cosine = cos(angle);
        double ddotr;

        // flags for additional orientation info stored by some atom styles

        int ellipsoid_flag = atom->ellipsoid_flag;
        int line_flag = atom->line_flag;
        int tri_flag = atom->tri_flag;
        int body_flag = atom->body_flag;

        int theta_flag = 0;
        int quat_flag = 0;
        if (line_flag) theta_flag = 1;
        if (ellipsoid_flag || tri_flag || body_flag) quat_flag = 1;

        // AtomVec pointers to retrieve per-atom storage of extra quantities

        AtomVecEllipsoid *avec_ellipsoid =
            (AtomVecEllipsoid *) atom->style_match("ellipsoid");
        AtomVecLine *avec_line = (AtomVecLine *) atom->style_match("line");
        AtomVecTri *avec_tri = (AtomVecTri *) atom->style_match("tri");
        AtomVecBody *avec_body = (AtomVecBody *) atom->style_match("body");

        double **x = atom->x;
        int *ellipsoid = atom->ellipsoid;
        int *line = atom->line;
        int *tri = atom->tri;
        int *body = atom->body;
        int *mask = atom->mask;
        int nlocal = atom->nlocal;

        for (i = 0; i < nlocal; i++) {
            if (mask[i] & groupbit) {
                d[0] = x[i][0] - point[0];
                d[1] = x[i][1] - point[1];
                d[2] = x[i][2] - point[2];
                ddotr = d[0]*runit[0] + d[1]*runit[1] + d[2]*runit[2];
                c[0] = ddotr*runit[0];
                c[1] = ddotr*runit[1];
                c[2] = ddotr*runit[2];
                a[0] = d[0] - c[0];
                a[1] = d[1] - c[1];
                a[2] = d[2] - c[2];
                b[0] = runit[1]*a[2] - runit[2]*a[1];
                b[1] = runit[2]*a[0] - runit[0]*a[2];
                b[2] = runit[0]*a[1] - runit[1]*a[0];
                disp[0] = a[0]*cosine  + b[0]*sine;
                disp[1] = a[1]*cosine  + b[1]*sine;
                disp[2] = a[2]*cosine  + b[2]*sine;
                x[i][0] = point[0] + c[0] + disp[0];
                x[i][1] = point[1] + c[1] + disp[1];
                if (dim == 3) x[i][2] = point[2] + c[2] + disp[2];

                // theta for lines

                if (theta_flag && line[i] >= 0.0) {
                    theta_new = fmod(avec_line->bonus[line[i]].theta+angle,MY_2PI);
                    avec_line->bonus[atom->line[i]].theta = theta_new;
                }

                // quats for ellipsoids, tris, and bodies

                if (quat_flag) {
                    quat = NULL;
                    if (ellipsoid_flag && ellipsoid[i] >= 0)
                        quat = avec_ellipsoid->bonus[ellipsoid[i]].quat;
                    else if (tri_flag && tri[i] >= 0)
                        quat = avec_tri->bonus[tri[i]].quat;
                    else if (body_flag && body[i] >= 0)
                        quat = avec_body->bonus[body[i]].quat;
                    if (quat) {
                        qrotate[0] = cosine;
                        qrotate[1] = runit[0]*sine;
                        qrotate[2] = runit[1]*sine;
                        qrotate[3] = runit[2]*sine;
                        MathExtra::quatquat(qrotate,quat,qnew);
                        quat[0] = qnew[0];
                        quat[1] = qnew[1];
                        quat[2] = qnew[2];
                        quat[3] = qnew[3];
                    }
                }
            }
        }
    }

    // move atoms back inside simulation box and to new processors
    // use remap() instead of pbc() in case atoms moved a long distance
    // use irregular() in case atoms moved a long distance

    double **x = atom->x;
    imageint *image = atom->image;
    int nlocal = atom->nlocal;
    for (i = 0; i < nlocal; i++) domain->remap(x[i],image[i]);

    if (domain->triclinic) domain->x2lamda(atom->nlocal);
    domain->reset_box();
    Irregular *irregular = new Irregular(lmp);
    irregular->migrate_atoms(1);
    delete irregular;
    if (domain->triclinic) domain->lamda2x(atom->nlocal);

    // check if any atoms were lost

    bigint natoms;
    bigint nblocal = atom->nlocal;
    MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
    if (natoms != atom->natoms && comm->me == 0) {
        char str[128];
        sprintf(str,"Lost atoms via displace_atoms: original " BIGINT_FORMAT
                " current " BIGINT_FORMAT,atom->natoms,natoms);
        error->warning(FLERR,str);
    }
}
Пример #7
0
void CreateAtoms::command(int narg, char **arg)
{
  if (domain->box_exist == 0)
    error->all(FLERR,"Create_atoms command before simulation box is defined");
  if (modify->nfix_restart_peratom)
    error->all(FLERR,"Cannot create_atoms after "
               "reading restart file with per-atom info");

  // parse arguments

  if (narg < 2) error->all(FLERR,"Illegal create_atoms command");
  ntype = force->inumeric(FLERR,arg[0]);

  int iarg;
  if (strcmp(arg[1],"box") == 0) {
    style = BOX;
    iarg = 2;
    nregion = -1;
  } else if (strcmp(arg[1],"region") == 0) {
    style = REGION;
    if (narg < 3) error->all(FLERR,"Illegal create_atoms command");
    nregion = domain->find_region(arg[2]);
    if (nregion == -1) error->all(FLERR,
                                  "Create_atoms region ID does not exist");
    domain->regions[nregion]->init();
    domain->regions[nregion]->prematch();
    iarg = 3;;
  } else if (strcmp(arg[1],"single") == 0) {
    style = SINGLE;
    if (narg < 5) error->all(FLERR,"Illegal create_atoms command");
    xone[0] = force->numeric(FLERR,arg[2]);
    xone[1] = force->numeric(FLERR,arg[3]);
    xone[2] = force->numeric(FLERR,arg[4]);
    iarg = 5;
  } else if (strcmp(arg[1],"random") == 0) {
    style = RANDOM;
    if (narg < 5) error->all(FLERR,"Illegal create_atoms command");
    nrandom = force->inumeric(FLERR,arg[2]);
    seed = force->inumeric(FLERR,arg[3]);
    if (strcmp(arg[4],"NULL") == 0) nregion = -1;
    else {
      nregion = domain->find_region(arg[4]);
      if (nregion == -1) error->all(FLERR,
                                    "Create_atoms region ID does not exist");
      domain->regions[nregion]->init();
      domain->regions[nregion]->prematch();
    }
    iarg = 5;
  } else error->all(FLERR,"Illegal create_atoms command");

  // process optional keywords

  int scaleflag = 1;
  remapflag = 0;
  mode = ATOM;
  int molseed;
  varflag = 0;
  vstr = xstr = ystr = zstr = NULL;
  quatone[0] = quatone[1] = quatone[2] = 0.0;

  nbasis = domain->lattice->nbasis;
  basistype = new int[nbasis];
  for (int i = 0; i < nbasis; i++) basistype[i] = ntype;

  while (iarg < narg) {
    if (strcmp(arg[iarg],"basis") == 0) {
      if (iarg+3 > narg) error->all(FLERR,"Illegal create_atoms command");
      int ibasis = force->inumeric(FLERR,arg[iarg+1]);
      int itype = force->inumeric(FLERR,arg[iarg+2]);
      if (ibasis <= 0 || ibasis > nbasis || itype <= 0 || itype > atom->ntypes)
        error->all(FLERR,"Invalid basis setting in create_atoms command");
      basistype[ibasis-1] = itype;
      iarg += 3;
    } else if (strcmp(arg[iarg],"remap") == 0) {
      if (iarg+2 > narg) error->all(FLERR,"Illegal create_atoms command");
      if (strcmp(arg[iarg+1],"yes") == 0) remapflag = 1;
      else if (strcmp(arg[iarg+1],"no") == 0) remapflag = 0;
      else error->all(FLERR,"Illegal create_atoms command");
      iarg += 2;
    } else if (strcmp(arg[iarg],"mol") == 0) {
      if (iarg+3 > narg) error->all(FLERR,"Illegal create_atoms command");
      int imol = atom->find_molecule(arg[iarg+1]);
      if (imol == -1) error->all(FLERR,"Molecule template ID for "
                                 "create_atoms does not exist");
      if (atom->molecules[imol]->nset > 1 && comm->me == 0)
        error->warning(FLERR,"Molecule template for "
                       "create_atoms has multiple molecules");
      mode = MOLECULE;
      onemol = atom->molecules[imol];
      molseed = force->inumeric(FLERR,arg[iarg+2]);
      iarg += 3;
    } else if (strcmp(arg[iarg],"units") == 0) {
      if (iarg+2 > narg) error->all(FLERR,"Illegal create_atoms command");
      if (strcmp(arg[iarg+1],"box") == 0) scaleflag = 0;
      else if (strcmp(arg[iarg+1],"lattice") == 0) scaleflag = 1;
      else error->all(FLERR,"Illegal create_atoms command");
      iarg += 2;
    } else if (strcmp(arg[iarg],"var") == 0) {
      if (iarg+2 > narg) error->all(FLERR,"Illegal create_atoms command");
      delete [] vstr;
      int n = strlen(arg[iarg+1]) + 1;
      vstr = new char[n];
      strcpy(vstr,arg[iarg+1]);
      varflag = 1;
      iarg += 2;
    } else if (strcmp(arg[iarg],"set") == 0) {
      if (iarg+3 > narg) error->all(FLERR,"Illegal create_atoms command");
      if (strcmp(arg[iarg+1],"x") == 0) {
        delete [] xstr;
        int n = strlen(arg[iarg+2]) + 1;
        xstr = new char[n];
        strcpy(xstr,arg[iarg+2]);
      } else if (strcmp(arg[iarg+1],"y") == 0) {
        delete [] ystr;
        int n = strlen(arg[iarg+2]) + 1;
        ystr = new char[n];
        strcpy(ystr,arg[iarg+2]);
      } else if (strcmp(arg[iarg+1],"z") == 0) {
        delete [] zstr;
        int n = strlen(arg[iarg+2]) + 1;
        zstr = new char[n];
        strcpy(zstr,arg[iarg+2]);
      } else error->all(FLERR,"Illegal create_atoms command");
      iarg += 3;
    } else if (strcmp(arg[iarg],"rotate") == 0) {
      if (style != SINGLE)
        error->all(FLERR,"Cannot use create_atoms rotate unless single style");
      if (iarg+5 > narg) error->all(FLERR,"Illegal create_atoms command");
      double thetaone;
      double axisone[3];
      thetaone = force->numeric(FLERR,arg[iarg+1]);
      axisone[0] = force->numeric(FLERR,arg[iarg+2]);
      axisone[1] = force->numeric(FLERR,arg[iarg+3]);
      axisone[2] = force->numeric(FLERR,arg[iarg+4]);
      if (axisone[0] == 0.0 && axisone[1] == 0.0 && axisone[2] == 0.0)
        error->all(FLERR,"Illegal create_atoms command");
      if (domain->dimension == 2 && (axisone[0] != 0.0 || axisone[1] != 0.0))
        error->all(FLERR,"Invalid create_atoms rotation vector for 2d model");
      MathExtra::norm3(axisone);
      MathExtra::axisangle_to_quat(axisone,thetaone,quatone);
      iarg += 5;
    } else error->all(FLERR,"Illegal create_atoms command");
  }

  // error checks

  if (mode == ATOM && (ntype <= 0 || ntype > atom->ntypes))
    error->all(FLERR,"Invalid atom type in create_atoms command");

  if (style == RANDOM) {
    if (nrandom < 0) error->all(FLERR,"Illegal create_atoms command");
    if (seed <= 0) error->all(FLERR,"Illegal create_atoms command");
  }

  // error check and further setup for mode = MOLECULE

  ranmol = NULL;
  if (mode == MOLECULE) {
    if (onemol->xflag == 0)
      error->all(FLERR,"Create_atoms molecule must have coordinates");
    if (onemol->typeflag == 0)
      error->all(FLERR,"Create_atoms molecule must have atom types");
    if (ntype+onemol->ntypes <= 0 || ntype+onemol->ntypes > atom->ntypes)
      error->all(FLERR,"Invalid atom type in create_atoms mol command");
    if (onemol->tag_require && !atom->tag_enable)
      error->all(FLERR,
                 "Create_atoms molecule has atom IDs, but system does not");
    onemol->check_attributes(0);

    // create_atoms uses geoemetric center of molecule for insertion

    onemol->compute_center();

    // molecule random number generator, different for each proc

    ranmol = new RanMars(lmp,molseed+comm->me);
  }

  // error check and further setup for variable test

  if (!vstr && (xstr || ystr || zstr))
    error->all(FLERR,"Incomplete use of variables in create_atoms command");
  if (vstr && (!xstr && !ystr && !zstr))
    error->all(FLERR,"Incomplete use of variables in create_atoms command");

  if (varflag) {
    vvar = input->variable->find(vstr);
    if (vvar < 0)
      error->all(FLERR,"Variable name for create_atoms does not exist");
    if (!input->variable->equalstyle(vvar))
      error->all(FLERR,"Variable for create_atoms is invalid style");

    if (xstr) {
      xvar = input->variable->find(xstr);
      if (xvar < 0)
        error->all(FLERR,"Variable name for create_atoms does not exist");
      if (!input->variable->internalstyle(xvar))
        error->all(FLERR,"Variable for create_atoms is invalid style");
    }
    if (ystr) {
      yvar = input->variable->find(ystr);
      if (yvar < 0)
        error->all(FLERR,"Variable name for create_atoms does not exist");
      if (!input->variable->internalstyle(yvar))
        error->all(FLERR,"Variable for create_atoms is invalid style");
    }
    if (zstr) {
      zvar = input->variable->find(zstr);
      if (zvar < 0)
        error->all(FLERR,"Variable name for create_atoms does not exist");
      if (!input->variable->internalstyle(zvar))
        error->all(FLERR,"Variable for create_atoms is invalid style");
    }
  }

  // demand non-none lattice be defined for BOX and REGION
  // else setup scaling for SINGLE and RANDOM
  // could use domain->lattice->lattice2box() to do conversion of
  //   lattice to box, but not consistent with other uses of units=lattice
  // triclinic remapping occurs in add_single()

  if (style == BOX || style == REGION) {
    if (nbasis == 0)
      error->all(FLERR,"Cannot create atoms with undefined lattice");
  } else if (scaleflag == 1) {
    xone[0] *= domain->lattice->xlattice;
    xone[1] *= domain->lattice->ylattice;
    xone[2] *= domain->lattice->zlattice;
  }

  // set bounds for my proc in sublo[3] & subhi[3]
  // if periodic and style = BOX or REGION, i.e. using lattice:
  //   should create exactly 1 atom when 2 images are both "on" the boundary
  //   either image may be slightly inside/outside true box due to round-off
  //   if I am lo proc, decrement lower bound by EPSILON
  //     this will insure lo image is created
  //   if I am hi proc, decrement upper bound by 2.0*EPSILON
  //     this will insure hi image is not created
  //   thus insertion box is EPSILON smaller than true box
  //     and is shifted away from true boundary
  //     which is where atoms are likely to be generated

  triclinic = domain->triclinic;

  double epsilon[3];
  if (triclinic) epsilon[0] = epsilon[1] = epsilon[2] = EPSILON;
  else {
    epsilon[0] = domain->prd[0] * EPSILON;
    epsilon[1] = domain->prd[1] * EPSILON;
    epsilon[2] = domain->prd[2] * EPSILON;
  }

  if (triclinic == 0) {
    sublo[0] = domain->sublo[0]; subhi[0] = domain->subhi[0];
    sublo[1] = domain->sublo[1]; subhi[1] = domain->subhi[1];
    sublo[2] = domain->sublo[2]; subhi[2] = domain->subhi[2];
  } else {
    sublo[0] = domain->sublo_lamda[0]; subhi[0] = domain->subhi_lamda[0];
    sublo[1] = domain->sublo_lamda[1]; subhi[1] = domain->subhi_lamda[1];
    sublo[2] = domain->sublo_lamda[2]; subhi[2] = domain->subhi_lamda[2];
  }

  if (style == BOX || style == REGION) {
    if (comm->layout != Comm::LAYOUT_TILED) {
      if (domain->xperiodic) {
        if (comm->myloc[0] == 0) sublo[0] -= epsilon[0];
        if (comm->myloc[0] == comm->procgrid[0]-1) subhi[0] -= 2.0*epsilon[0];
      }
      if (domain->yperiodic) {
        if (comm->myloc[1] == 0) sublo[1] -= epsilon[1];
        if (comm->myloc[1] == comm->procgrid[1]-1) subhi[1] -= 2.0*epsilon[1];
      }
      if (domain->zperiodic) {
        if (comm->myloc[2] == 0) sublo[2] -= epsilon[2];
        if (comm->myloc[2] == comm->procgrid[2]-1) subhi[2] -= 2.0*epsilon[2];
      }
    } else {
      if (domain->xperiodic) {
        if (comm->mysplit[0][0] == 0.0) sublo[0] -= epsilon[0];
        if (comm->mysplit[0][1] == 1.0) subhi[0] -= 2.0*epsilon[0];
      }
      if (domain->yperiodic) {
        if (comm->mysplit[1][0] == 0.0) sublo[1] -= epsilon[1];
        if (comm->mysplit[1][1] == 1.0) subhi[1] -= 2.0*epsilon[1];
      }
      if (domain->zperiodic) {
        if (comm->mysplit[2][0] == 0.0) sublo[2] -= epsilon[2];
        if (comm->mysplit[2][1] == 1.0) subhi[2] -= 2.0*epsilon[2];
      }
    }
  }

  // Record wall time for atom creation

  MPI_Barrier(world);
  double time1 = MPI_Wtime();

  // clear ghost count and any ghost bonus data internal to AtomVec
  // same logic as beginning of Comm::exchange()
  // do it now b/c creating atoms will overwrite ghost atoms

  atom->nghost = 0;
  atom->avec->clear_bonus();

  // add atoms/molecules in one of 3 ways

  bigint natoms_previous = atom->natoms;
  int nlocal_previous = atom->nlocal;

  if (style == SINGLE) add_single();
  else if (style == RANDOM) add_random();
  else add_lattice();

  // init per-atom fix/compute/variable values for created atoms

  atom->data_fix_compute_variable(nlocal_previous,atom->nlocal);

  // set new total # of atoms and error check

  bigint nblocal = atom->nlocal;
  MPI_Allreduce(&nblocal,&atom->natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
  if (atom->natoms < 0 || atom->natoms >= MAXBIGINT)
    error->all(FLERR,"Too many total atoms");

  // add IDs for newly created atoms
  // check that atom IDs are valid

  if (atom->tag_enable) atom->tag_extend();
  atom->tag_check();

  // if global map exists, reset it
  // invoke map_init() b/c atom count has grown

  if (atom->map_style) {
    atom->map_init();
    atom->map_set();
  }

  // for MOLECULE mode:
  // molecule can mean just a mol ID or bonds/angles/etc or mol templates
  // set molecule IDs for created atoms if atom->molecule_flag is set
  // reset new molecule bond,angle,etc and special values if defined
  // send atoms to new owning procs via irregular comm
  //   since not all atoms I created will be within my sub-domain
  // perform special list build if needed

  if (mode == MOLECULE) {

    int molecule_flag = atom->molecule_flag;
    int molecular = atom->molecular;
    tagint *molecule = atom->molecule;

    // molcreate = # of molecules I created

    int molcreate = (atom->nlocal - nlocal_previous) / onemol->natoms;

    // increment total bonds,angles,etc

    bigint nmolme = molcreate;
    bigint nmoltotal;
    MPI_Allreduce(&nmolme,&nmoltotal,1,MPI_LMP_BIGINT,MPI_SUM,world);
    atom->nbonds += nmoltotal * onemol->nbonds;
    atom->nangles += nmoltotal * onemol->nangles;
    atom->ndihedrals += nmoltotal * onemol->ndihedrals;
    atom->nimpropers += nmoltotal * onemol->nimpropers;

    // if atom style template
    // maxmol = max molecule ID across all procs, for previous atoms
    // moloffset = max molecule ID for all molecules owned by previous procs
    //             including molecules existing before this creation

    tagint moloffset;
    if (molecule_flag) {
      tagint max = 0;
      for (int i = 0; i < nlocal_previous; i++) max = MAX(max,molecule[i]);
      tagint maxmol;
      MPI_Allreduce(&max,&maxmol,1,MPI_LMP_TAGINT,MPI_MAX,world);
      MPI_Scan(&molcreate,&moloffset,1,MPI_INT,MPI_SUM,world);
      moloffset = moloffset - molcreate + maxmol;
    }

    // loop over molecules I created
    // set their molecule ID
    // reset their bond,angle,etc and special values

    int natoms = onemol->natoms;
    tagint offset = 0;

    tagint *tag = atom->tag;
    int *num_bond = atom->num_bond;
    int *num_angle = atom->num_angle;
    int *num_dihedral = atom->num_dihedral;
    int *num_improper = atom->num_improper;
    tagint **bond_atom = atom->bond_atom;
    tagint **angle_atom1 = atom->angle_atom1;
    tagint **angle_atom2 = atom->angle_atom2;
    tagint **angle_atom3 = atom->angle_atom3;
    tagint **dihedral_atom1 = atom->dihedral_atom1;
    tagint **dihedral_atom2 = atom->dihedral_atom2;
    tagint **dihedral_atom3 = atom->dihedral_atom3;
    tagint **dihedral_atom4 = atom->dihedral_atom4;
    tagint **improper_atom1 = atom->improper_atom1;
    tagint **improper_atom2 = atom->improper_atom2;
    tagint **improper_atom3 = atom->improper_atom3;
    tagint **improper_atom4 = atom->improper_atom4;
    int **nspecial = atom->nspecial;
    tagint **special = atom->special;

    int ilocal = nlocal_previous;
    for (int i = 0; i < molcreate; i++) {
      if (tag) offset = tag[ilocal]-1;
      for (int m = 0; m < natoms; m++) {
        if (molecule_flag) molecule[ilocal] = moloffset + i+1;
        if (molecular == 2) {
          atom->molindex[ilocal] = 0;
          atom->molatom[ilocal] = m;
        } else if (molecular) {
          if (onemol->bondflag)
            for (int j = 0; j < num_bond[ilocal]; j++)
              bond_atom[ilocal][j] += offset;
          if (onemol->angleflag)
            for (int j = 0; j < num_angle[ilocal]; j++) {
              angle_atom1[ilocal][j] += offset;
              angle_atom2[ilocal][j] += offset;
              angle_atom3[ilocal][j] += offset;
            }
          if (onemol->dihedralflag)
            for (int j = 0; j < num_dihedral[ilocal]; j++) {
              dihedral_atom1[ilocal][j] += offset;
              dihedral_atom2[ilocal][j] += offset;
              dihedral_atom3[ilocal][j] += offset;
              dihedral_atom4[ilocal][j] += offset;
            }
          if (onemol->improperflag)
            for (int j = 0; j < num_improper[ilocal]; j++) {
              improper_atom1[ilocal][j] += offset;
              improper_atom2[ilocal][j] += offset;
              improper_atom3[ilocal][j] += offset;
              improper_atom4[ilocal][j] += offset;
            }
          if (onemol->specialflag)
            for (int j = 0; j < nspecial[ilocal][2]; j++)
              special[ilocal][j] += offset;
        }
        ilocal++;
      }
    }

    // perform irregular comm to migrate atoms to new owning procs

    double **x = atom->x;
    imageint *image = atom->image;
    int nlocal = atom->nlocal;
    for (int i = 0; i < nlocal; i++) domain->remap(x[i],image[i]);

    if (domain->triclinic) domain->x2lamda(atom->nlocal);
    domain->reset_box();
    Irregular *irregular = new Irregular(lmp);
    irregular->migrate_atoms(1);
    delete irregular;
    if (domain->triclinic) domain->lamda2x(atom->nlocal);
  }

  // clean up

  delete ranmol;
  if (domain->lattice) delete [] basistype;
  delete [] vstr;
  delete [] xstr;
  delete [] ystr;
  delete [] zstr;

  // for MOLECULE mode:
  // create special bond lists for molecular systems,
  //   but not for atom style template
  // only if onemol added bonds but not special info

  if (mode == MOLECULE) {
    if (atom->molecular == 1 && onemol->bondflag && !onemol->specialflag) {
      Special special(lmp);
      special.build();

    }
  }

  // print status

  MPI_Barrier(world);
  double time2 = MPI_Wtime();

  if (comm->me == 0) {
    if (screen) {
      fprintf(screen,"Created " BIGINT_FORMAT " atoms\n",
              atom->natoms-natoms_previous);
      fprintf(screen,"  create_atoms CPU = %g secs\n",time2-time1);
    }
    if (logfile) {
      fprintf(logfile,"Created " BIGINT_FORMAT " atoms\n",
              atom->natoms-natoms_previous);
      fprintf(logfile,"  create_atoms CPU = %g secs\n",time2-time1);
    }
  }
}
Пример #8
0
void DisplaceAtoms::command(int narg, char **arg)
{
  int i;

  if (domain->box_exist == 0)
    error->all(FLERR,"Displace_atoms command before simulation box is defined");
  if (narg < 2) error->all(FLERR,"Illegal displace_atoms command");
  if (modify->nfix_restart_peratom)
    error->all(FLERR,"Cannot displace_atoms after "
               "reading restart file with per-atom info");

  if (comm->me == 0 && screen) fprintf(screen,"Displacing atoms ...\n");

  // group and style

  int igroup = group->find(arg[0]);
  if (igroup == -1) error->all(FLERR,"Could not find displace_atoms group ID");
  int groupbit = group->bitmask[igroup];

  int style;
  if (strcmp(arg[1],"move") == 0) style = MOVE;
  else if (strcmp(arg[1],"ramp") == 0) style = RAMP;
  else if (strcmp(arg[1],"random") == 0) style = RANDOM;
  else if (strcmp(arg[1],"rotate") == 0) style = ROTATE;
  else error->all(FLERR,"Illegal displace_atoms command");

  // set option defaults

  scaleflag = 1;

  // read options from end of input line

  if (style == MOVE) options(narg-5,&arg[5]);
  else if (style == RAMP) options(narg-8,&arg[8]);
  else if (style == RANDOM) options(narg-6,&arg[6]);
  else if (style == ROTATE) options(narg-9,&arg[9]);

  // setup scaling

  double xscale,yscale,zscale;
  if (scaleflag) {
    xscale = domain->lattice->xlattice;
    yscale = domain->lattice->ylattice;
    zscale = domain->lattice->zlattice;
  }
  else xscale = yscale = zscale = 1.0;

  // move atoms by 3-vector

  if (style == MOVE) {

    double delx = xscale*atof(arg[2]);
    double dely = yscale*atof(arg[3]);
    double delz = zscale*atof(arg[4]);

    double **x = atom->x;
    int *mask = atom->mask;
    int nlocal = atom->nlocal;

    for (i = 0; i < nlocal; i++) {
      if (mask[i] & groupbit) {
        x[i][0] += delx;
        x[i][1] += dely;
        x[i][2] += delz;
      }
    }
  }

  // move atoms in ramped fashion

  if (style == RAMP) {

    int d_dim;
    if (strcmp(arg[2],"x") == 0) d_dim = 0;
    else if (strcmp(arg[2],"y") == 0) d_dim = 1;
    else if (strcmp(arg[2],"z") == 0) d_dim = 2;
    else error->all(FLERR,"Illegal displace_atoms ramp command");

    double d_lo,d_hi;
    if (d_dim == 0) {
      d_lo = xscale*atof(arg[3]);
      d_hi = xscale*atof(arg[4]);
    } else if (d_dim == 1) {
      d_lo = yscale*atof(arg[3]);
      d_hi = yscale*atof(arg[4]);
    } else if (d_dim == 2) {
      d_lo = zscale*atof(arg[3]);
      d_hi = zscale*atof(arg[4]);
    }

    int coord_dim;
    if (strcmp(arg[5],"x") == 0) coord_dim = 0;
    else if (strcmp(arg[5],"y") == 0) coord_dim = 1;
    else if (strcmp(arg[5],"z") == 0) coord_dim = 2;
    else error->all(FLERR,"Illegal displace_atoms ramp command");

    double coord_lo,coord_hi;
    if (coord_dim == 0) {
      coord_lo = xscale*atof(arg[6]);
      coord_hi = xscale*atof(arg[7]);
    } else if (coord_dim == 1) {
      coord_lo = yscale*atof(arg[6]);
      coord_hi = yscale*atof(arg[7]);
    } else if (coord_dim == 2) {
      coord_lo = zscale*atof(arg[6]);
      coord_hi = zscale*atof(arg[7]);
    }

    double **x = atom->x;
    int *mask = atom->mask;
    int nlocal = atom->nlocal;

    double fraction,dramp;

    for (i = 0; i < nlocal; i++) {
      if (mask[i] & groupbit) {
        fraction = (x[i][coord_dim] - coord_lo) / (coord_hi - coord_lo);
        fraction = MAX(fraction,0.0);
        fraction = MIN(fraction,1.0);
        dramp = d_lo + fraction*(d_hi - d_lo);
        x[i][d_dim] += dramp;
      }
    }
  }

  // move atoms randomly
  // makes atom result independent of what proc owns it via random->reset()

  if (style == RANDOM) {
    RanPark *random = new RanPark(lmp,1);

    double dx = xscale*atof(arg[2]);
    double dy = yscale*atof(arg[3]);
    double dz = zscale*atof(arg[4]);
    int seed = atoi(arg[5]);
    if (seed <= 0) error->all(FLERR,"Illegal displace_atoms random command");

    double **x = atom->x;
    int *mask = atom->mask;
    int nlocal = atom->nlocal;

    for (i = 0; i < nlocal; i++) {
      if (mask[i] & groupbit) {
        random->reset(seed,x[i]);
        x[i][0] += dx * 2.0*(random->uniform()-0.5);
        x[i][1] += dy * 2.0*(random->uniform()-0.5);
        x[i][2] += dz * 2.0*(random->uniform()-0.5);
      }
    }

    delete random;
  }
 
  // rotate atoms by right-hand rule by theta around R
  // P = point = vector = point of rotation
  // R = vector = axis of rotation
  // R0 = runit = unit vector for R
  // D = X - P = vector from P to X
  // C = (D dot R0) R0 = projection of atom coord onto R line
  // A = D - C = vector from R line to X
  // B = R0 cross A = vector perp to A in plane of rotation
  // A,B define plane of circular rotation around R line
  // X = P + C + A cos(theta) + B sin(theta)

  if (style == ROTATE) {
    double axis[3],point[3];
    double a[3],b[3],c[3],d[3],disp[3],runit[3];
    
    int dim = domain->dimension;
    point[0] = xscale*atof(arg[2]);
    point[1] = yscale*atof(arg[3]);
    point[2] = zscale*atof(arg[4]);
    axis[0] = atof(arg[5]);
    axis[1] = atof(arg[6]);
    axis[2] = atof(arg[7]);
    double theta = atof(arg[8]);
    if (dim == 2 and (axis[0] != 0.0 || axis[1] != 0.0))
      error->all(FLERR,"Invalid displace_atoms rotate axis for 2d");

    double len = sqrt(axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]);
    if (len == 0.0)
      error->all(FLERR,"Zero length rotation vector with displace_atoms");
    runit[0] = axis[0]/len;
    runit[1] = axis[1]/len;
    runit[2] = axis[2]/len;

    double sine = sin(MY_PI*theta/180.0);
    double cosine = cos(MY_PI*theta/180.0);
    double ddotr;

    double **x = atom->x;
    int *mask = atom->mask;
    int nlocal = atom->nlocal;

    for (i = 0; i < nlocal; i++) {
      if (mask[i] & groupbit) {
        d[0] = x[i][0] - point[0];
        d[1] = x[i][1] - point[1];
        d[2] = x[i][2] - point[2];
        ddotr = d[0]*runit[0] + d[1]*runit[1] + d[2]*runit[2];
        c[0] = ddotr*runit[0];
        c[1] = ddotr*runit[1];
        c[2] = ddotr*runit[2];
        a[0] = d[0] - c[0];
        a[1] = d[1] - c[1];
        a[2] = d[2] - c[2];
        b[0] = runit[1]*a[2] - runit[2]*a[1];
        b[1] = runit[2]*a[0] - runit[0]*a[2];
        b[2] = runit[0]*a[1] - runit[1]*a[0];
        disp[0] = a[0]*cosine  + b[0]*sine;
        disp[1] = a[1]*cosine  + b[1]*sine;
        disp[2] = a[2]*cosine  + b[2]*sine;
        x[i][0] = point[0] + c[0] + disp[0];
        x[i][1] = point[1] + c[1] + disp[1];
        if (dim == 3) x[i][2] = point[2] + c[2] + disp[2];
      }
    }
  }

  // move atoms back inside simulation box and to new processors
  // use remap() instead of pbc() in case atoms moved a long distance
  // use irregular() in case atoms moved a long distance

  double **x = atom->x;
  tagint *image = atom->image;
  int nlocal = atom->nlocal;
  for (i = 0; i < nlocal; i++) domain->remap(x[i],image[i]);

  if (domain->triclinic) domain->x2lamda(atom->nlocal);
  domain->reset_box();
  Irregular *irregular = new Irregular(lmp);
  irregular->migrate_atoms();
  delete irregular;
  if (domain->triclinic) domain->lamda2x(atom->nlocal);

  // check if any atoms were lost

  bigint natoms;
  bigint nblocal = atom->nlocal;
  MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
  if (natoms != atom->natoms && comm->me == 0) {
    char str[128];
    sprintf(str,"Lost atoms via displace_atoms: original " BIGINT_FORMAT
            " current " BIGINT_FORMAT,atom->natoms,natoms);
    error->warning(FLERR,str);
  }
}
Пример #9
0
void Balance::command(int narg, char **arg)
{
  if (domain->box_exist == 0)
    error->all(FLERR,"Balance command before simulation box is defined");

  if (me == 0 && screen) fprintf(screen,"Balancing ...\n");

  // parse required arguments

  if (narg < 2) error->all(FLERR,"Illegal balance command");

  thresh = force->numeric(FLERR,arg[0]);

  int dimension = domain->dimension;
  int *procgrid = comm->procgrid;
  style = -1;
  xflag = yflag = zflag = NONE;

  int iarg = 1;
  while (iarg < narg) {
    if (strcmp(arg[iarg],"x") == 0) {
      if (style != -1 && style != XYZ)
        error->all(FLERR,"Illegal balance command");
      style = XYZ;
      if (strcmp(arg[iarg+1],"uniform") == 0) {
        if (iarg+2 > narg) error->all(FLERR,"Illegal balance command");
        xflag = UNIFORM;
        iarg += 2;
      } else {
        if (1 + procgrid[0]-1 > narg)
          error->all(FLERR,"Illegal balance command");
        xflag = USER;
        delete [] user_xsplit;
        user_xsplit = new double[procgrid[0]+1];
        user_xsplit[0] = 0.0;
        iarg++;
        for (int i = 1; i < procgrid[0]; i++)
          user_xsplit[i] = force->numeric(FLERR,arg[iarg++]);
        user_xsplit[procgrid[0]] = 1.0;
      }
    } else if (strcmp(arg[iarg],"y") == 0) {
      if (style != -1 && style != XYZ)
        error->all(FLERR,"Illegal balance command");
      style = XYZ;
      if (strcmp(arg[iarg+1],"uniform") == 0) {
        if (iarg+2 > narg) error->all(FLERR,"Illegal balance command");
        yflag = UNIFORM;
        iarg += 2;
      } else {
        if (1 + procgrid[1]-1 > narg)
          error->all(FLERR,"Illegal balance command");
        yflag = USER;
        delete [] user_ysplit;
        user_ysplit = new double[procgrid[1]+1];
        user_ysplit[0] = 0.0;
        iarg++;
        for (int i = 1; i < procgrid[1]; i++)
          user_ysplit[i] = force->numeric(FLERR,arg[iarg++]);
        user_ysplit[procgrid[1]] = 1.0;
      }
    } else if (strcmp(arg[iarg],"z") == 0) {
      if (style != -1 && style != XYZ)
        error->all(FLERR,"Illegal balance command");
      style = XYZ;
      if (strcmp(arg[iarg+1],"uniform") == 0) {
        if (iarg+2 > narg) error->all(FLERR,"Illegal balance command");
        zflag = UNIFORM;
        iarg += 2;
      } else {
        if (1 + procgrid[2]-1 > narg)
          error->all(FLERR,"Illegal balance command");
        zflag = USER;
        delete [] user_zsplit;
        user_zsplit = new double[procgrid[2]+1];
        user_zsplit[0] = 0.0;
        iarg++;
        for (int i = 1; i < procgrid[2]; i++)
          user_zsplit[i] = force->numeric(FLERR,arg[iarg++]);
        user_zsplit[procgrid[2]] = 1.0;
      }

    } else if (strcmp(arg[iarg],"shift") == 0) {
      if (style != -1) error->all(FLERR,"Illegal balance command");
      if (iarg+4 > narg) error->all(FLERR,"Illegal balance command");
      style = SHIFT;
      if (strlen(arg[iarg+1]) > 3) error->all(FLERR,"Illegal balance command");
      strcpy(bstr,arg[iarg+1]);
      nitermax = force->inumeric(FLERR,arg[iarg+2]);
      if (nitermax <= 0) error->all(FLERR,"Illegal balance command");
      stopthresh = force->numeric(FLERR,arg[iarg+3]);
      if (stopthresh < 1.0) error->all(FLERR,"Illegal balance command");
      iarg += 4;

    } else if (strcmp(arg[iarg],"rcb") == 0) {
      if (style != -1) error->all(FLERR,"Illegal balance command");
      style = BISECTION;
      iarg++;

    } else break;
  }

  // error checks

  if (style == XYZ) {
    if (zflag != NONE  && dimension == 2)
      error->all(FLERR,"Cannot balance in z dimension for 2d simulation");

    if (xflag == USER)
      for (int i = 1; i <= procgrid[0]; i++)
        if (user_xsplit[i-1] >= user_xsplit[i])
          error->all(FLERR,"Illegal balance command");
    if (yflag == USER)
      for (int i = 1; i <= procgrid[1]; i++)
        if (user_ysplit[i-1] >= user_ysplit[i])
          error->all(FLERR,"Illegal balance command");
    if (zflag == USER)
      for (int i = 1; i <= procgrid[2]; i++)
        if (user_zsplit[i-1] >= user_zsplit[i])
          error->all(FLERR,"Illegal balance command");
  }

  if (style == SHIFT) {
    const int blen=strlen(bstr);
    for (int i = 0; i < blen; i++) {
      if (bstr[i] != 'x' && bstr[i] != 'y' && bstr[i] != 'z')
        error->all(FLERR,"Balance shift string is invalid");
      if (bstr[i] == 'z' && dimension == 2)
        error->all(FLERR,"Balance shift string is invalid");
      for (int j = i+1; j < blen; j++)
        if (bstr[i] == bstr[j])
          error->all(FLERR,"Balance shift string is invalid");
    }
  }

  if (style == BISECTION && comm->style == 0)
    error->all(FLERR,"Balance rcb cannot be used with comm_style brick");

  // process remaining optional args

  options(iarg,narg,arg);
  if (wtflag) weight_storage(NULL);

  // insure particles are in current box & update box via shrink-wrap
  // init entire system since comm->setup is done
  // comm::init needs neighbor::init needs pair::init needs kspace::init, etc
  // must reset atom map after exchange() since it clears it

  MPI_Barrier(world);
  double start_time = MPI_Wtime();

  lmp->init();

  if (domain->triclinic) domain->x2lamda(atom->nlocal);
  domain->pbc();
  domain->reset_box();
  comm->setup();
  comm->exchange();
  if (atom->map_style) atom->map_set();
  if (domain->triclinic) domain->lamda2x(atom->nlocal);

  // imbinit = initial imbalance

  double maxinit;
  init_imbalance(0);
  set_weights();
  double imbinit = imbalance_factor(maxinit);

  // no load-balance if imbalance doesn't exceed threshold
  // unless switching from tiled to non tiled layout, then force rebalance

  if (comm->layout == LAYOUT_TILED && style != BISECTION) {
  } else if (imbinit < thresh) return;

  // debug output of initial state

#ifdef BALANCE_DEBUG
  if (outflag) dumpout(update->ntimestep);
#endif

  int niter = 0;

  // perform load-balance
  // style XYZ = explicit setting of cutting planes of logical 3d grid

  if (style == XYZ) {
    if (comm->layout == LAYOUT_UNIFORM) {
      if (xflag == USER || yflag == USER || zflag == USER)
        comm->layout = LAYOUT_NONUNIFORM;
    } else if (comm->layout == LAYOUT_NONUNIFORM) {
      if (xflag == UNIFORM && yflag == UNIFORM && zflag == UNIFORM)
        comm->layout = LAYOUT_UNIFORM;
    } else if (comm->layout == LAYOUT_TILED) {
      if (xflag == UNIFORM && yflag == UNIFORM && zflag == UNIFORM)
        comm->layout = LAYOUT_UNIFORM;
      else comm->layout = LAYOUT_NONUNIFORM;
    }

    if (xflag == UNIFORM) {
      for (int i = 0; i < procgrid[0]; i++)
        comm->xsplit[i] = i * 1.0/procgrid[0];
      comm->xsplit[procgrid[0]] = 1.0;
    } else if (xflag == USER)
      for (int i = 0; i <= procgrid[0]; i++) comm->xsplit[i] = user_xsplit[i];

    if (yflag == UNIFORM) {
      for (int i = 0; i < procgrid[1]; i++)
        comm->ysplit[i] = i * 1.0/procgrid[1];
      comm->ysplit[procgrid[1]] = 1.0;
    } else if (yflag == USER)
      for (int i = 0; i <= procgrid[1]; i++) comm->ysplit[i] = user_ysplit[i];

    if (zflag == UNIFORM) {
      for (int i = 0; i < procgrid[2]; i++)
        comm->zsplit[i] = i * 1.0/procgrid[2];
      comm->zsplit[procgrid[2]] = 1.0;
    } else if (zflag == USER)
      for (int i = 0; i <= procgrid[2]; i++) comm->zsplit[i] = user_zsplit[i];
  }

  // style SHIFT = adjust cutting planes of logical 3d grid

  if (style == SHIFT) {
    comm->layout = LAYOUT_NONUNIFORM;
    shift_setup_static(bstr);
    niter = shift();
  }

  // style BISECTION = recursive coordinate bisectioning

  if (style == BISECTION) {
    comm->layout = LAYOUT_TILED;
    bisection(1);
  }

  // reset proc sub-domains
  // for either brick or tiled comm style

  if (domain->triclinic) domain->set_lamda_box();
  domain->set_local_box();

  // move particles to new processors via irregular()

  if (domain->triclinic) domain->x2lamda(atom->nlocal);
  Irregular *irregular = new Irregular(lmp);
  if (wtflag) fixstore->disable = 0;
  if (style == BISECTION) irregular->migrate_atoms(1,1,rcb->sendproc);
  else irregular->migrate_atoms(1);
  if (wtflag) fixstore->disable = 1;
  delete irregular;
  if (domain->triclinic) domain->lamda2x(atom->nlocal);

  // output of final result

  if (outflag) dumpout(update->ntimestep);

  // check if any particles were lost

  bigint natoms;
  bigint nblocal = atom->nlocal;
  MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
  if (natoms != atom->natoms) {
    char str[128];
    sprintf(str,"Lost atoms via balance: original " BIGINT_FORMAT
            " current " BIGINT_FORMAT,atom->natoms,natoms);
    error->all(FLERR,str);
  }

  // imbfinal = final imbalance

  double maxfinal;
  double imbfinal = imbalance_factor(maxfinal);

  // stats output

  double stop_time = MPI_Wtime();

  if (me == 0) {
    if (screen) {
      fprintf(screen,"  rebalancing time: %g seconds\n",stop_time-start_time);
      fprintf(screen,"  iteration count = %d\n",niter);
      for (int i = 0; i < nimbalance; ++i) imbalances[i]->info(screen);
      fprintf(screen,"  initial/final max load/proc = %g %g\n",
              maxinit,maxfinal);
      fprintf(screen,"  initial/final imbalance factor = %g %g\n",
              imbinit,imbfinal);
    }
    if (logfile) {
      fprintf(logfile,"  rebalancing time: %g seconds\n",stop_time-start_time);
      fprintf(logfile,"  iteration count = %d\n",niter);
      for (int i = 0; i < nimbalance; ++i) imbalances[i]->info(logfile);
      fprintf(logfile,"  initial/final max load/proc = %g %g\n",
              maxinit,maxfinal);
      fprintf(logfile,"  initial/final imbalance factor = %g %g\n",
              imbinit,imbfinal);
    }
  }

  if (style != BISECTION) {
    if (me == 0) {
      if (screen) {
        fprintf(screen,"  x cuts:");
        for (int i = 0; i <= comm->procgrid[0]; i++)
          fprintf(screen," %g",comm->xsplit[i]);
        fprintf(screen,"\n");
        fprintf(screen,"  y cuts:");
        for (int i = 0; i <= comm->procgrid[1]; i++)
          fprintf(screen," %g",comm->ysplit[i]);
        fprintf(screen,"\n");
        fprintf(screen,"  z cuts:");
        for (int i = 0; i <= comm->procgrid[2]; i++)
          fprintf(screen," %g",comm->zsplit[i]);
        fprintf(screen,"\n");
      }
      if (logfile) {
        fprintf(logfile,"  x cuts:");
        for (int i = 0; i <= comm->procgrid[0]; i++)
          fprintf(logfile," %g",comm->xsplit[i]);
        fprintf(logfile,"\n");
        fprintf(logfile,"  y cuts:");
        for (int i = 0; i <= comm->procgrid[1]; i++)
          fprintf(logfile," %g",comm->ysplit[i]);
        fprintf(logfile,"\n");
        fprintf(logfile,"  z cuts:");
        for (int i = 0; i <= comm->procgrid[2]; i++)
          fprintf(logfile," %g",comm->zsplit[i]);
        fprintf(logfile,"\n");
      }
    }
  }
}