325 lines
8.6 KiB
C++
325 lines
8.6 KiB
C++
/* ----------------------------------------------------------------------
|
|
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
|
http://lammps.sandia.gov, Sandia National Laboratories
|
|
Steve Plimpton, sjplimp@sandia.gov
|
|
|
|
Copyright (2003) Sandia Corporation. Under the terms of Contract
|
|
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
|
|
certain rights in this software. This software is distributed
|
|
under
|
|
the GNU General Public License.
|
|
|
|
See the README file in the top-level LAMMPS directory.
|
|
------------------------------------------------------------------------- */
|
|
|
|
/* ----------------------------------------------------------------------
|
|
Contributing author: PM Larsen (MIT)
|
|
------------------------------------------------------------------------- */
|
|
|
|
#include "compute_ptm_atom.h"
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <cstring>
|
|
#include <vector>
|
|
|
|
#include "atom.h"
|
|
#include "citeme.h"
|
|
#include "comm.h"
|
|
#include "error.h"
|
|
#include "force.h"
|
|
#include "memory.h"
|
|
#include "modify.h"
|
|
#include "neigh_list.h"
|
|
#include "neigh_request.h"
|
|
#include "neighbor.h"
|
|
#include "update.h"
|
|
|
|
#include "ptm_functions.h"
|
|
|
|
#define NUM_COLUMNS 7
|
|
#define PTM_LAMMPS_UNKNOWN -1
|
|
#define PTM_LAMMPS_OTHER 0
|
|
|
|
using namespace LAMMPS_NS;
|
|
|
|
static const char cite_user_ptm_package[] =
|
|
"USER-PTM package:\n\n"
|
|
"@Article{larsen2016ptm,\n"
|
|
" author={Larsen, Peter Mahler and Schmidt, S{\\o}ren and Schi{\\o}tz, "
|
|
"Jakob},\n"
|
|
" title={Robust structural identification via polyhedral template "
|
|
"matching},\n"
|
|
" journal={Modelling~Simul.~Mater.~Sci.~Eng.},\n"
|
|
" year={2016},\n"
|
|
" number={5},\n"
|
|
" volume={24},\n"
|
|
" pages={055007},\n"
|
|
" DOI = {10.1088/0965-0393/24/5/055007}"
|
|
"}\n\n";
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
ComputePTMAtom::ComputePTMAtom(LAMMPS *lmp, int narg, char **arg)
|
|
: Compute(lmp, narg, arg), list(NULL), output(NULL) {
|
|
if (narg != 5)
|
|
error->all(FLERR, "Illegal compute ptm/atom command");
|
|
|
|
char *structures = arg[3];
|
|
char *ptr = structures;
|
|
|
|
const char *strings[] = {"fcc", "hcp", "bcc", "ico", "sc",
|
|
"dcub", "dhex", "graphene", "all", "default"};
|
|
int num_strings = sizeof(strings) / sizeof(const char*);
|
|
|
|
int32_t flags[] = {
|
|
PTM_CHECK_FCC,
|
|
PTM_CHECK_HCP,
|
|
PTM_CHECK_BCC,
|
|
PTM_CHECK_ICO,
|
|
PTM_CHECK_SC,
|
|
PTM_CHECK_DCUB,
|
|
PTM_CHECK_DHEX,
|
|
PTM_CHECK_GRAPHENE,
|
|
PTM_CHECK_ALL,
|
|
PTM_CHECK_FCC | PTM_CHECK_HCP | PTM_CHECK_BCC | PTM_CHECK_ICO};
|
|
|
|
if (lmp->citeme)
|
|
lmp->citeme->add(cite_user_ptm_package);
|
|
|
|
input_flags = 0;
|
|
while (*ptr != '\0') {
|
|
|
|
bool found = false;
|
|
for (int i = 0; i < num_strings; i++) {
|
|
int len = strlen(strings[i]);
|
|
if (strncmp(ptr, strings[i], len) == 0) {
|
|
input_flags |= flags[i];
|
|
ptr += len;
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
error->all(FLERR,
|
|
"Illegal compute ptm/atom command (invalid structure type)");
|
|
|
|
if (*ptr == '\0')
|
|
break;
|
|
|
|
if (*ptr != '-')
|
|
error->all(FLERR,
|
|
"Illegal compute ptm/atom command (invalid structure type)");
|
|
|
|
ptr++;
|
|
}
|
|
|
|
double threshold = force->numeric(FLERR, arg[4]);
|
|
if (threshold < 0.0)
|
|
error->all(FLERR,
|
|
"Illegal compute ptm/atom command (threshold is negative)");
|
|
rmsd_threshold = threshold;
|
|
if (rmsd_threshold == 0)
|
|
rmsd_threshold = INFINITY;
|
|
|
|
peratom_flag = 1;
|
|
size_peratom_cols = NUM_COLUMNS;
|
|
create_attribute = 1;
|
|
nmax = 0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
ComputePTMAtom::~ComputePTMAtom() { memory->destroy(output); }
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void ComputePTMAtom::init() {
|
|
if (force->pair == NULL)
|
|
error->all(FLERR, "Compute ptm/atom requires a pair style be defined");
|
|
|
|
int count = 0;
|
|
for (int i = 0; i < modify->ncompute; i++)
|
|
if (strcmp(modify->compute[i]->style, "ptm/atom") == 0)
|
|
count++;
|
|
if (count > 1 && comm->me == 0)
|
|
error->warning(FLERR, "More than one compute ptm/atom defined");
|
|
|
|
// need an occasional full neighbor list
|
|
|
|
int irequest = neighbor->request(this, instance_me);
|
|
neighbor->requests[irequest]->pair = 0;
|
|
neighbor->requests[irequest]->compute = 1;
|
|
neighbor->requests[irequest]->half = 0;
|
|
neighbor->requests[irequest]->full = 1;
|
|
neighbor->requests[irequest]->occasional = 1;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void ComputePTMAtom::init_list(int /* id */, NeighList *ptr) { list = ptr; }
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
typedef struct
|
|
{
|
|
double **x;
|
|
int *numneigh;
|
|
int **firstneigh;
|
|
int *ilist;
|
|
int nlocal;
|
|
|
|
} ptmnbrdata_t;
|
|
|
|
|
|
typedef struct {
|
|
int index;
|
|
double d;
|
|
} ptmnbr_t;
|
|
|
|
static bool sorthelper_compare(ptmnbr_t const &a, ptmnbr_t const &b) {
|
|
return a.d < b.d;
|
|
}
|
|
|
|
static int get_neighbours(void* vdata, size_t central_index, size_t atom_index, int num, size_t* nbr_indices, int32_t* numbers, double (*nbr_pos)[3])
|
|
{
|
|
ptmnbrdata_t* data = (ptmnbrdata_t*)vdata;
|
|
|
|
double **x = data->x;
|
|
double *pos = x[atom_index];
|
|
|
|
int *jlist = NULL;
|
|
int jnum = 0;
|
|
if (atom_index < data->nlocal) {
|
|
jlist = data->firstneigh[atom_index];
|
|
jnum = data->numneigh[atom_index];
|
|
}
|
|
else {
|
|
jlist = data->firstneigh[central_index];
|
|
jnum = data->numneigh[central_index];
|
|
}
|
|
|
|
std::vector<ptmnbr_t> nbr_order;
|
|
|
|
for (int jj = 0; jj < jnum; jj++) {
|
|
int j = jlist[jj];
|
|
j &= NEIGHMASK;
|
|
if (j == atom_index)
|
|
continue;
|
|
|
|
double dx = pos[0] - x[j][0];
|
|
double dy = pos[1] - x[j][1];
|
|
double dz = pos[2] - x[j][2];
|
|
double rsq = dx * dx + dy * dy + dz * dz;
|
|
|
|
ptmnbr_t nbr = {j, rsq};
|
|
nbr_order.push_back(nbr);
|
|
}
|
|
|
|
std::sort(nbr_order.begin(), nbr_order.end(), &sorthelper_compare);
|
|
int num_nbrs = std::min(num - 1, (int)nbr_order.size());
|
|
|
|
nbr_pos[0][0] = nbr_pos[0][1] = nbr_pos[0][2] = 0;
|
|
nbr_indices[0] = atom_index;
|
|
numbers[0] = 0;
|
|
for (int jj = 0; jj < num_nbrs; jj++) {
|
|
|
|
int j = nbr_order[jj].index;
|
|
nbr_pos[jj + 1][0] = x[j][0] - pos[0];
|
|
nbr_pos[jj + 1][1] = x[j][1] - pos[1];
|
|
nbr_pos[jj + 1][2] = x[j][2] - pos[2];
|
|
|
|
nbr_indices[jj + 1] = j;
|
|
numbers[jj + 1] = 0;
|
|
}
|
|
|
|
return num_nbrs + 1;
|
|
}
|
|
|
|
void ComputePTMAtom::compute_peratom() {
|
|
// PTM global initialization. If already initialized this function does
|
|
// nothing.
|
|
ptm_initialize_global();
|
|
|
|
// initialize PTM local storage
|
|
ptm_local_handle_t local_handle = ptm_initialize_local();
|
|
|
|
invoked_peratom = update->ntimestep;
|
|
|
|
// grow arrays if necessary
|
|
if (atom->nmax > nmax) {
|
|
memory->destroy(output);
|
|
nmax = atom->nmax;
|
|
|
|
memory->create(output, nmax, NUM_COLUMNS, "ptm:ptm_output");
|
|
array_atom = output;
|
|
}
|
|
|
|
// invoke full neighbor list (will copy or build if necessary)
|
|
neighbor->build_one(list);
|
|
|
|
int inum = list->inum;
|
|
int *ilist = list->ilist;
|
|
int *numneigh = list->numneigh;
|
|
int **firstneigh = list->firstneigh;
|
|
|
|
double **x = atom->x;
|
|
int *mask = atom->mask;
|
|
ptmnbrdata_t nbrlist = {x, numneigh, firstneigh, ilist, atom->nlocal};
|
|
|
|
for (int ii = 0; ii < inum; ii++) {
|
|
|
|
int i = ilist[ii];
|
|
output[i][0] = PTM_LAMMPS_UNKNOWN;
|
|
if (!(mask[i] & groupbit))
|
|
continue;
|
|
|
|
int jnum = numneigh[i];
|
|
if (jnum <= 0)
|
|
continue;
|
|
|
|
|
|
// now run PTM
|
|
int32_t type, alloy_type;
|
|
double scale, rmsd, interatomic_distance;
|
|
double q[4];
|
|
bool standard_orientations = false;
|
|
ptm_index(local_handle, i, get_neighbours, (void*)&nbrlist,
|
|
input_flags, standard_orientations,
|
|
&type, &alloy_type, &scale, &rmsd, q,
|
|
NULL, NULL, NULL, NULL, &interatomic_distance, NULL, NULL);
|
|
|
|
if (rmsd > rmsd_threshold) {
|
|
type = PTM_MATCH_NONE;
|
|
}
|
|
|
|
// printf("%d type=%d rmsd=%f\n", i, type, rmsd);
|
|
|
|
if (type == PTM_MATCH_NONE) {
|
|
type = PTM_LAMMPS_OTHER;
|
|
rmsd = INFINITY;
|
|
}
|
|
|
|
output[i][0] = type;
|
|
output[i][1] = rmsd;
|
|
output[i][2] = interatomic_distance;
|
|
output[i][3] = q[0];
|
|
output[i][4] = q[1];
|
|
output[i][5] = q[2];
|
|
output[i][6] = q[3];
|
|
}
|
|
|
|
// printf("finished ptm analysis\n");
|
|
ptm_uninitialize_local(local_handle);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
memory usage of local atom-based array
|
|
------------------------------------------------------------------------- */
|
|
|
|
double ComputePTMAtom::memory_usage() {
|
|
double bytes = nmax * NUM_COLUMNS * sizeof(double);
|
|
bytes += nmax * sizeof(double);
|
|
return bytes;
|
|
}
|