Commit c705e8d0 authored by pmla's avatar pmla
Browse files

renamed files for LAMMPS build system compatibility

parent b7c75b6c
Loading
Loading
Loading
Loading
+307 −0
Original line number Diff line number Diff line
/* ----------------------------------------------------------------------
         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 <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>

#include "atom.h"
#include "comm.h"
#include "compute_ptm_atom.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 "pair.h"
#include "update.h"

#include "ptm_functions.h"

#define MAX_NEIGHBORS 30
#define NUM_COLUMNS 7
#define UNKNOWN 0
#define OTHER 8

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", "all", "default"};
  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_ALL,
      PTM_CHECK_FCC | PTM_CHECK_HCP | PTM_CHECK_BCC | PTM_CHECK_ICO};

  input_flags = 0;
  while (*ptr != '\0') {

    bool found = false;
    for (int i = 0; i < 9; 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 {
  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_neighbors(double *pos, int jnum, int *jlist, double **x,
                         double (*nbr)[3]) {

  ptmnbr_t *nbr_order = new ptmnbr_t[jnum];

  for (int jj = 0; jj < jnum; jj++) {
    int j = jlist[jj];
    j &= NEIGHMASK;

    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;

    nbr_order[jj].index = j;
    nbr_order[jj].d = rsq;
  }

  std::sort(nbr_order, nbr_order + jnum, &sorthelper_compare);
  int num_nbrs = std::min(MAX_NEIGHBORS, jnum);

  nbr[0][0] = nbr[0][1] = nbr[0][2] = 0;
  for (int jj = 0; jj < num_nbrs; jj++) {

    int j = nbr_order[jj].index;
    nbr[jj + 1][0] = x[j][0] - pos[0];
    nbr[jj + 1][1] = x[j][1] - pos[1];
    nbr[jj + 1][2] = x[j][2] - pos[2];
  }

  delete[] nbr_order;
  return num_nbrs;
}

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;
  int nlocal = atom->nlocal;

  for (int ii = 0; ii < inum; ii++) {

    int i = ilist[ii];
    output[i][0] = UNKNOWN;
    if (!(mask[i] & groupbit))
      continue;

    double *pos = x[i];

    int *jlist = firstneigh[i];
    int jnum = numneigh[i];
    if (jnum <= 0)
      continue;

    // get neighbours ordered by increasing distance
    double nbr[MAX_NEIGHBORS + 1][3];
    int num_nbrs = get_neighbors(pos, jnum, jlist, x, nbr);

    // check that we have enough neighbours for the desired structure types
    int32_t flags = 0;
    if (num_nbrs >= PTM_NUM_NBRS_SC && (input_flags & PTM_CHECK_SC))
      flags |= PTM_CHECK_SC;
    if (num_nbrs >= PTM_NUM_NBRS_FCC && (input_flags & PTM_CHECK_FCC))
      flags |= PTM_CHECK_FCC;
    if (num_nbrs >= PTM_NUM_NBRS_HCP && (input_flags & PTM_CHECK_HCP))
      flags |= PTM_CHECK_HCP;
    if (num_nbrs >= PTM_NUM_NBRS_ICO && (input_flags & PTM_CHECK_ICO))
      flags |= PTM_CHECK_ICO;
    if (num_nbrs >= PTM_NUM_NBRS_BCC && (input_flags & PTM_CHECK_BCC))
      flags |= PTM_CHECK_BCC;
    if (num_nbrs >= PTM_NUM_NBRS_DCUB && (input_flags & PTM_CHECK_DCUB))
      flags |= PTM_CHECK_DCUB;
    if (num_nbrs >= PTM_NUM_NBRS_DHEX && (input_flags & PTM_CHECK_DHEX))
      flags |= PTM_CHECK_DHEX;

    // now run PTM
    int8_t mapping[MAX_NEIGHBORS + 1];
    int32_t type, alloy_type;
    double scale, rmsd, interatomic_distance, lattice_constant;
    double q[4], F[9], F_res[3], U[9], P[9];
    ptm_index(local_handle, flags, num_nbrs + 1, nbr, NULL, true, &type,
              &alloy_type, &scale, &rmsd, q, F, F_res, U, P, mapping,
              &interatomic_distance, &lattice_constant);

    if (rmsd > rmsd_threshold) {
      type = PTM_MATCH_NONE;
    }

    // printf("%d type=%d rmsd=%f\n", i, type, rmsd);

    if (type == PTM_MATCH_NONE)
      type = OTHER;

    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;
}
+48 −0
Original line number Diff line number Diff line
/* -*- 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.
------------------------------------------------------------------------- */

#ifdef COMPUTE_CLASS

ComputeStyle(ptm/atom,ComputePTMAtom)

#else

#ifndef LMP_COMPUTE_PTM_ATOM_H
#define LMP_COMPUTE_PTM_ATOM_H

#include "compute.h"

namespace LAMMPS_NS {

class ComputePTMAtom : public Compute {
 public:
  ComputePTMAtom(class LAMMPS *, int, char **);
  ~ComputePTMAtom();
  void init();
  void init_list(int, class NeighList *);
  void compute_peratom();
  double memory_usage();

 private:
  int nmax;
  int32_t input_flags;
  double rmsd_threshold;
  class NeighList *list;
  double **output;
};

}

#endif
#endif
+101 −0
Original line number Diff line number Diff line
#include <algorithm>
#include "ptm_constants.h"
#include "ptm_initialize_data.h"


#define NUM_ALLOY_TYPES 3
static uint32_t typedata[NUM_ALLOY_TYPES][3] = {
	{PTM_MATCH_FCC, PTM_ALLOY_L10,    0x000001fe},
	{PTM_MATCH_FCC, PTM_ALLOY_L12_CU, 0x0000001e},
	{PTM_MATCH_FCC, PTM_ALLOY_L12_AU, 0x00001ffe},
};

static bool test_pure(int num_nbrs, int32_t* numbers)
{
	for (int i=1;i<num_nbrs + 1;i++)
		if (numbers[i] != numbers[0])
			return false;
	return true;
}

static bool test_binary(int num_nbrs, int32_t* numbers)
{
	int a = numbers[0], b = -1;
	for (int i=1;i<num_nbrs + 1;i++)
	{
		if (numbers[i] != a)
		{
			if (b == -1)
				b = numbers[i];
			else if (numbers[i] != b)
				return false;
		}
	}

	return true;
}

static bool test_shell_structure(const refdata_t* ref, int8_t* mapping, int32_t* numbers, int num_inner)
{
	int8_t binary[PTM_MAX_POINTS];
	for (int i=0;i<ref->num_nbrs+1;i++)
		binary[i] = numbers[mapping[i]] == numbers[0] ? 0 : 1;

	for (int i=1;i<num_inner + 1;i++)
		if (binary[i] == binary[0])
			return false;

	for (int i=num_inner+1;i<ref->num_nbrs+1;i++)
		if (binary[i] != binary[0])
			return false;

	return true;
}

static int32_t canonical_alloy_representation(const refdata_t* ref, int8_t* mapping, int32_t* numbers)
{
	int8_t binary[PTM_MAX_POINTS];
	for (int i=0;i<ref->num_nbrs+1;i++)
		binary[i] = numbers[mapping[i]] == numbers[0] ? 0 : 1;

	int8_t temp[PTM_MAX_POINTS];
	uint32_t best = 0xFFFFFFFF;
	for (int j=0;j<ref->num_mappings;j++)
	{
		for (int i=0;i<ref->num_nbrs+1;i++)
			temp[ref->mapping[j][i]] = binary[i];

		uint32_t code = 0;
		for (int i=0;i<ref->num_nbrs+1;i++)
			code |= (temp[i] << i);

		best = std::min(best, code);
	}

	return best;
}

int32_t find_alloy_type(const refdata_t* ref, int8_t* mapping, int32_t* numbers)
{
	if (test_pure(ref->num_nbrs, numbers))
		return PTM_ALLOY_PURE;

	if (!test_binary(ref->num_nbrs, numbers))
		return PTM_ALLOY_NONE;

	uint32_t code = canonical_alloy_representation(ref, mapping, numbers);
	for (int i=0;i<NUM_ALLOY_TYPES;i++)
		if ((uint32_t)ref->type == typedata[i][0] && code == typedata[i][2])
			return typedata[i][1];

	if (ref->type == PTM_MATCH_BCC)
		if (test_shell_structure(ref, mapping, numbers, 8))
			return PTM_ALLOY_B2;

	if (ref->type == PTM_MATCH_DCUB || ref->type == PTM_MATCH_DHEX)
		if (test_shell_structure(ref, mapping, numbers, 4))
			return PTM_ALLOY_SIC;

	return PTM_ALLOY_NONE;
}
+9 −0
Original line number Diff line number Diff line
#ifndef PTM_ALLOY_TYPES_H
#define PTM_ALLOY_TYPES_H

#include "ptm_initialize_data.h"

int32_t find_alloy_type(const refdata_t* ref, int8_t* mapping, int32_t* numbers);

#endif
+167 −0
Original line number Diff line number Diff line
#include <string.h>
#include <climits>
#include <algorithm>
#include "ptm_graph_tools.h"
#include "ptm_constants.h"


static bool weinberg_coloured(int num_nodes, int num_edges, int8_t common[PTM_MAX_NBRS][PTM_MAX_NBRS], int8_t* colours, int8_t* best_code, int8_t* canonical_labelling, int a, int b)
{
	bool m[PTM_MAX_NBRS][PTM_MAX_NBRS];
	memset(m, 0, sizeof(bool) * PTM_MAX_NBRS * PTM_MAX_NBRS);

	int8_t index[PTM_MAX_NBRS];
	memset(index, -1, sizeof(int8_t) * PTM_MAX_NBRS);


	int n = 0;
	index[a] = colours[a] * num_nodes + n++;
	if (index[a] > best_code[0])
		return false;

	bool winning = false;
	if (index[a] < best_code[0])
	{
		best_code[0] = index[a];
		winning = true;
	}

	int c = -1;
	for (int it=1;it<2*num_edges;it++)
	{
		bool newvertex = index[b] == -1;

		if (newvertex)
			index[b] = colours[b] * num_nodes + n++;

		if (!winning && index[b] > best_code[it])
			return false;

		if (winning || index[b] < best_code[it])
		{
			winning = true;
			best_code[it] = index[b];
		}

		if (newvertex)
		{
			//When a new vertex is reached, take the right-most edge
			//relative to the edge on which the vertex is reached.

			c = common[a][b];
		}
		else if (m[b][a] == false)
		{
			//When an old vertex is reached on a new path, go back
			//in the opposite direction.

			c = a;
		}
		else
		{
			//When an old vertex is reached on an old path, leave the
			//vertex on the right-most edge that has not previously
			//been traversed in that direction.

			c = common[a][b];
			while (m[b][c] == true)
				c = common[c][b];
		}

		m[a][b] = true;
		a = b;
		b = c;
	}

	if (winning)
	{
		memcpy(canonical_labelling, index, sizeof(int8_t) * num_nodes);
		return true;
	}

	return false;
}

int canonical_form_coloured(int num_facets, int8_t facets[][3], int num_nodes, int8_t* degree, int8_t* colours, int8_t* canonical_labelling, int8_t* best_code, uint64_t* p_hash)
{
	int8_t common[PTM_MAX_NBRS][PTM_MAX_NBRS] = {{0}};
	int num_edges = 3 * num_facets / 2;
	if (!build_facet_map(num_facets, facets, common))
		return -1;

	memset(best_code, SCHAR_MAX, sizeof(int8_t) * 2 * PTM_MAX_EDGES);

	bool equal = true;
	for (int i = 1;i<num_nodes;i++)
		if (degree[i] != degree[0] || colours[i] != colours[0])
			equal = false;

	if (equal)
	{
		weinberg_coloured(num_nodes, num_edges, common, colours, best_code, canonical_labelling, facets[0][0], facets[0][1]);
	}
	else
	{
		uint32_t best_degree = 0;
		for (int i = 0;i<num_facets;i++)
		{
			int a = facets[i][0];
			int b = facets[i][1];
			int c = facets[i][2];

			//int da = colours[a] * num_nodes + degree[a];
			//int db = colours[b] * num_nodes + degree[b];
			//int dc = colours[c] * num_nodes + degree[c];

			int da = degree[a];
			int db = degree[b];
			int dc = degree[c];

			best_degree = std::max(best_degree, ((uint32_t)da << 16) | ((uint32_t)db << 8) | ((uint32_t)dc << 0));
			best_degree = std::max(best_degree, ((uint32_t)da << 0) | ((uint32_t)db << 16) | ((uint32_t)dc << 8));
			best_degree = std::max(best_degree, ((uint32_t)da << 8) | ((uint32_t)db << 0) | ((uint32_t)dc << 16));
		}

		for (int i = 0;i<num_facets;i++)
		{
			int a = facets[i][0];
			int b = facets[i][1];
			int c = facets[i][2];

			//int da = colours[a] * num_nodes + degree[a];
			//int db = colours[b] * num_nodes + degree[b];
			//int dc = colours[c] * num_nodes + degree[c];

			int da = degree[a];
			int db = degree[b];
			int dc = degree[c];

			if (best_degree == (((uint32_t)da << 16) | ((uint32_t)db << 8) | ((uint32_t)dc << 0)))
				weinberg_coloured(num_nodes, num_edges, common, colours, best_code, canonical_labelling, a, b);

			if (best_degree == (((uint32_t)da << 0) | ((uint32_t)db << 16) | ((uint32_t)dc << 8)))
				weinberg_coloured(num_nodes, num_edges, common, colours, best_code, canonical_labelling, b, c);

			if (best_degree == (((uint32_t)da << 8) | ((uint32_t)db << 0) | ((uint32_t)dc << 16)))
				weinberg_coloured(num_nodes, num_edges, common, colours, best_code, canonical_labelling, c, a);
		}
	}

	for (int i = num_nodes-1;i>=0;i--)
		canonical_labelling[i+1] = (canonical_labelling[i] % num_nodes) + 1;
	canonical_labelling[0] = 0;

	uint64_t hash = 0;
	for (int i = 0;i<2 * num_edges;i++)
	{
		uint64_t e = best_code[i];
		e += i % 8;
		e &= 0xF;
		e <<= (4 * i) % 64;
		hash ^= e;
	}

	*p_hash = hash;
	return PTM_NO_ERROR;
}
Loading