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