Added compute snap descriptor gradient example.
This commit is contained in:
9
examples/snap/README.md
Normal file
9
examples/snap/README.md
Normal file
@ -0,0 +1,9 @@
|
||||
See `compute_snap_dgrad.py` for a test that compares the dBi/dRj from compute snap (`dbirjflag=1`) to the sum of dBi/dRj from usual compute snap (`dbirjflag=0`).
|
||||
|
||||
The format of the global array from `dbirjflag=1` is as follows.
|
||||
|
||||
The first N rows belong to bispectrum components for each atom, if we use `bikflag=1`. The first `K` columns correspond to each bispectrum coefficient. The final 3 columns contain reference force components for each atom.
|
||||
|
||||
The rows after the first N rows contain dBi/dRj values for all pairs. These values are arranged in row chunks for each atom `j`, where all the rows in a chunk are associated with the neighbors `i` of `j`, as well as the self-terms where `i=j`. So for atom `j`, the number of rows is equal to the number of atoms within the SNAP cutoff, plus 1 for the `i=j` terms, times 3 for each Cartesian component. The total number of dBi/dRj rows is therefore equal to `N*(Nneigh+1)*3`, and `Nneigh` may be different for each atom. To facilitate with determining which row belong to which atom pair `ij`, the last 3 columns contain indices; the 3rd to last column contains global indices of atoms `i` (the neighbors), the 2nd to last column contains global indices of atoms `j`, and the last column contains an index 0,1,2 for the Cartesian component. Like the `bik` rows, the first `K` columns correspond to each bispectrum coefficient.
|
||||
|
||||
Finally, the first column of the last row contains the reference energy.
|
||||
130
examples/snap/compute_snap_dgrad.py
Normal file
130
examples/snap/compute_snap_dgrad.py
Normal file
@ -0,0 +1,130 @@
|
||||
"""
|
||||
compute_snap_dgrad.py
|
||||
Purpose: Demonstrate extraction of descriptor gradient (dB/dR) array from compute snap.
|
||||
Show that dBi/dRj components summed over neighbors i yields same output as regular compute snap with dbirjflag=0.
|
||||
This shows that the dBi/dRj components extracted with dbirjflag=1 are correct.
|
||||
Serial syntax:
|
||||
python compute_snap_dgrad.py
|
||||
Parallel syntax:
|
||||
mpirun -np 2 python compute_snap_dgrad.py
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
import ctypes
|
||||
import numpy as np
|
||||
|
||||
# uncomment this if running in parallel via mpi4py
|
||||
#me = 0
|
||||
#from mpi4py import MPI
|
||||
#me = MPI.COMM_WORLD.Get_rank()
|
||||
#nprocs = MPI.COMM_WORLD.Get_size()
|
||||
|
||||
from lammps import lammps, LMP_TYPE_ARRAY, LMP_STYLE_GLOBAL
|
||||
cmds = ["-screen", "none", "-log", "none"]
|
||||
lmp = lammps(cmdargs=cmds)
|
||||
|
||||
def run_lammps(dbirjflag):
|
||||
lmp.command("clear")
|
||||
lmp.command("units metal")
|
||||
lmp.command("boundary p p p")
|
||||
lmp.command("atom_modify map hash")
|
||||
lmp.command(f"lattice bcc {latparam}")
|
||||
lmp.command(f"region box block 0 {nx} 0 {ny} 0 {nz}")
|
||||
lmp.command(f"create_box {ntypes} box")
|
||||
lmp.command(f"create_atoms {ntypes} box")
|
||||
lmp.command("mass * 180.88")
|
||||
lmp.command("displace_atoms all random 0.01 0.01 0.01 123456")
|
||||
# Pair style
|
||||
snap_options=f'{rcutfac} {rfac0} {twojmax} {radelem1} {radelem2} {wj1} {wj2} rmin0 {rmin0} quadraticflag {quadratic} bzeroflag {bzero} switchflag {switch} bikflag {bikflag} dbirjflag {dbirjflag}'
|
||||
lmp.command(f"pair_style zero {rcutfac}")
|
||||
lmp.command(f"pair_coeff * *")
|
||||
lmp.command(f"pair_style zbl {zblcutinner} {zblcutouter}")
|
||||
lmp.command(f"pair_coeff * * {zblz} {zblz}")
|
||||
# set up compute snap generating global array
|
||||
lmp.command(f"compute snap all snap {snap_options}")
|
||||
# Run
|
||||
lmp.command(f"thermo 100")
|
||||
lmp.command(f"run {nsteps}")
|
||||
|
||||
# Declare simulation/structure variables
|
||||
nsteps=0
|
||||
nrep=2
|
||||
latparam=2.0
|
||||
ntypes=2
|
||||
nx=nrep
|
||||
ny=nrep
|
||||
nz=nrep
|
||||
|
||||
# Declare compute snap variables
|
||||
twojmax=8
|
||||
m = (twojmax/2)+1
|
||||
rcutfac=1.0
|
||||
rfac0=0.99363
|
||||
rmin0=0
|
||||
radelem1=2.3
|
||||
radelem2=2.0
|
||||
wj1=1.0
|
||||
wj2=0.96
|
||||
quadratic=0
|
||||
bzero=0
|
||||
switch=0
|
||||
bikflag=1
|
||||
dbirjflag=1
|
||||
|
||||
# Declare reference potential variables
|
||||
zblcutinner=4.0
|
||||
zblcutouter=4.8
|
||||
zblz=73
|
||||
|
||||
# Number of descriptors
|
||||
if (twojmax % 2 == 0):
|
||||
nd = int(m*(m+1)*(2*m+1)/6)
|
||||
else:
|
||||
nd = int(m*(m+1)*(m+2)/3)
|
||||
print(f"Number of descriptors based on twojmax : {nd}")
|
||||
|
||||
# Run lammps with dbirjflag on
|
||||
run_lammps(1)
|
||||
|
||||
# Get global snap array
|
||||
lmp_snap = lmp.numpy.extract_compute("snap",0, 2)
|
||||
|
||||
# Extract dBj/dRi (includes dBi/dRi)
|
||||
natoms = lmp.get_natoms()
|
||||
fref1 = lmp_snap[0:natoms,-3:].flatten()
|
||||
eref1 = lmp_snap[-6,0]
|
||||
dbdr_length = np.shape(lmp_snap)[0]-(natoms)-6 # Length of neighborlist pruned dbdr array
|
||||
dBdR = lmp_snap[natoms:(natoms+dbdr_length),:]
|
||||
force_indices = lmp_snap[natoms:(natoms+dbdr_length),-3:].astype(np.int32)
|
||||
|
||||
# Sum over neighbors j for each atom i, like dbirjflag=0 does.
|
||||
array1 = np.zeros((3*natoms,nd))
|
||||
a = 0
|
||||
for k in range(0,nd):
|
||||
for l in range(0,dbdr_length):
|
||||
j = force_indices[l,0]
|
||||
i = force_indices[l,1]
|
||||
#array1[3*(i-1)+a,k] += dBdR[l,k]
|
||||
array1[3*(i)+a,k] += dBdR[l,k]
|
||||
a = a+1
|
||||
if (a>2):
|
||||
a=0
|
||||
|
||||
# Run lammps with dbirjflag off
|
||||
run_lammps(0)
|
||||
|
||||
# Get global snap array
|
||||
lmp_snap = lmp.numpy.extract_compute("snap",0, 2)
|
||||
natoms = lmp.get_natoms()
|
||||
fref2 = lmp_snap[natoms:(natoms+3*natoms),-1]
|
||||
eref2 = lmp_snap[0,-1]
|
||||
array2 = lmp_snap[natoms:natoms+(3*natoms), nd:-1]
|
||||
|
||||
# Sum the arrays obtained from dbirjflag on and off.
|
||||
summ = array1 + array2
|
||||
#np.savetxt("sum.dat", summ)
|
||||
|
||||
print(f"Maximum difference in descriptor sums: {np.max(summ)}")
|
||||
print(f"Maximum difference in reference forces: {np.max(fref1-fref2)}")
|
||||
print(f"Difference in reference energy: {np.max(eref1-eref2)}")
|
||||
Reference in New Issue
Block a user