Skip to content

Commit 0d2a100

Browse files
committed
add more debugs on SO3
1 parent 821ef26 commit 0d2a100

File tree

2 files changed

+75
-57
lines changed

2 files changed

+75
-57
lines changed

pyxtal/lego/SO3.py

Lines changed: 57 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -191,48 +191,49 @@ def compute_dpdr(self, atoms, atom_ids=None):
191191
p_list = np.zeros((self.natoms, self.ncoefs), dtype=np.float64)
192192
dp_list = np.zeros((self.natoms, self.natoms, self.ncoefs, 3), dtype=np.float64)
193193

194-
# get expansion coefficients and derivatives
195-
cs, dcs = compute_dcs(self.neighborlist, self.nmax, self.lmax, self.rcut, self.alpha, self._cutoff_function)
194+
if len(self.neighborlist) > 0:
195+
# get expansion coefficients and derivatives
196+
cs, dcs = compute_dcs(self.neighborlist, self.nmax, self.lmax, self.rcut, self.alpha, self._cutoff_function)
196197

197-
# weight cs and dcs
198-
cs *= self.atomic_weights[:, np.newaxis, np.newaxis, np.newaxis]
199-
dcs *= self.atomic_weights[:, np.newaxis, np.newaxis, np.newaxis, np.newaxis]
200-
cs = np.einsum('inlm,l->inlm', cs, self.norm)
201-
dcs = np.einsum('inlmj,l->inlmj', dcs, self.norm)
202-
#print('cs, dcs', self.neighbor_indices, cs.shape, dcs.shape)
198+
# weight cs and dcs
199+
cs *= self.atomic_weights[:, np.newaxis, np.newaxis, np.newaxis]
200+
dcs *= self.atomic_weights[:, np.newaxis, np.newaxis, np.newaxis, np.newaxis]
201+
cs = np.einsum('inlm,l->inlm', cs, self.norm)
202+
dcs = np.einsum('inlmj,l->inlmj', dcs, self.norm)
203+
#print('cs, dcs', self.neighbor_indices, cs.shape, dcs.shape)
203204

204-
# Assign cs and dcs to P and dP
205-
# cs: (N_ij, n, l, m) => P (N_i, N_des)
206-
# dcs: (N_ij, n, l, m, 3) => dP (N_i, N_j, N_des, 3)
207-
# (n, l, m) needs to be merged to 1 dimension
205+
# Assign cs and dcs to P and dP
206+
# cs: (N_ij, n, l, m) => P (N_i, N_des)
207+
# dcs: (N_ij, n, l, m, 3) => dP (N_i, N_j, N_des, 3)
208+
# (n, l, m) needs to be merged to 1 dimension
208209

209-
for i in range(len(atoms)):
210-
# find atoms for which i is the center
211-
centers = self.neighbor_indices[:, 0] == i
210+
for i in range(len(atoms)):
211+
# find atoms for which i is the center
212+
centers = self.neighbor_indices[:, 0] == i
212213

213-
if len(self.neighbor_indices[centers]) > 0:
214-
# total up the c array for the center atom
215-
ctot = cs[centers].sum(axis=0) #(n, l, m)
214+
if len(self.neighbor_indices[centers]) > 0:
215+
# total up the c array for the center atom
216+
ctot = cs[centers].sum(axis=0) #(n, l, m)
216217

217-
# power spectrum P = c*c_conj
218-
# eq_3 (n, n', l) eliminate m
219-
P = np.einsum('ijk, ljk->ilj', ctot, np.conj(ctot)).real
220-
p_list[i] = P[self.tril_indices].flatten()
218+
# power spectrum P = c*c_conj
219+
# eq_3 (n, n', l) eliminate m
220+
P = np.einsum('ijk, ljk->ilj', ctot, np.conj(ctot)).real
221+
p_list[i] += P[self.tril_indices].flatten()
221222

222-
# gradient of P for each neighbor, eq_26
223-
# (N_ijs, n, n', l, 3)
224-
# dc * c_conj + c * dc_conj
225-
dP = np.einsum('wijkn,ljk->wiljn', dcs[centers], np.conj(ctot))
226-
dP += np.conj(np.transpose(dP, axes=[0, 2, 1, 3, 4]))
227-
dP = dP.real
223+
# gradient of P for each neighbor, eq_26
224+
# (N_ijs, n, n', l, 3)
225+
# dc * c_conj + c * dc_conj
226+
dP = np.einsum('wijkn,ljk->wiljn', dcs[centers], np.conj(ctot))
227+
dP += np.conj(np.transpose(dP, axes=[0, 2, 1, 3, 4]))
228+
dP = dP.real
228229

229-
#print("shape of P/dP", P.shape, dP.shape)#; import sys; sys.exit()
230+
#print("shape of P/dP", P.shape, dP.shape)#; import sys; sys.exit()
230231

231-
# QZ: to check
232-
ijs = self.neighbor_indices[centers]
233-
for _id, j in enumerate(ijs[:, 1]):
234-
dp_list[i, j, :, :] += dP[_id][self.tril_indices].flatten().reshape(self.ncoefs, 3)
235-
dp_list[i, i, :, :] -= dP[_id][self.tril_indices].flatten().reshape(self.ncoefs, 3)
232+
# QZ: to check
233+
ijs = self.neighbor_indices[centers]
234+
for _id, j in enumerate(ijs[:, 1]):
235+
dp_list[i, j, :, :] += dP[_id][self.tril_indices].flatten().reshape(self.ncoefs, 3)
236+
dp_list[i, i, :, :] -= dP[_id][self.tril_indices].flatten().reshape(self.ncoefs, 3)
236237

237238
return dp_list, p_list
238239

@@ -242,7 +243,6 @@ def compute_dpdr_5d(self, atoms):
242243
243244
Args:
244245
atoms: ase atoms object
245-
atom_ids: optional list of atomic indices
246246
247247
Returns:
248248
dpdr array (N, N, M, 3, 27) and p array (N, M)
@@ -270,31 +270,31 @@ def compute_dpdr_5d(self, atoms):
270270
for i in range(len(atoms)):
271271
# find atoms for which i is the center
272272
pair_ids = neigh_ids[self.neighbor_indices[:, 0] == i]
273-
274-
# loop over each pair
275-
for pair_id in pair_ids:
276-
(_, j, x, y, z) = self.neighbor_indices[pair_id]
277-
# map from (x, y, z) to (0, 27)
278-
cell_id = (x+1) * 9 + (y+1) * 3 + z + 1
279-
273+
if len(pair_ids) > 0:
274+
ctot = cs[pair_ids].sum(axis=0) #(n, l, m)
280275
# power spectrum P = c*c_conj
281276
# eq_3 (n, n', l) eliminate m
282-
P = np.einsum('ijk, ljk->ilj', cs[pair_id], np.conj(cs[pair_id])).real
283-
p_list[i] = P[self.tril_indices].flatten()
277+
P = np.einsum('ijk, ljk->ilj', ctot, np.conj(ctot)).real
278+
p_list[i] += P[self.tril_indices].flatten()
284279

285-
# gradient of P for each neighbor, eq_26
286-
# (N_ijs, n, n', l, 3)
287-
# dc * c_conj + c * dc_conj
288-
dP = np.einsum('ijkn, ljk->iljn', dcs[pair_id], np.conj(cs[pair_id]))
289-
dP += np.conj(np.transpose(dP, axes=[1, 0, 2, 3]))
290-
dP = dP.real[self.tril_indices].flatten().reshape(self.ncoefs, 3)
291-
#print(cs[pair_id].shape, dcs[pair_id].shape, dP.shape)
280+
# loop over each pair
281+
for pair_id in pair_ids:
282+
(_, j, x, y, z) = self.neighbor_indices[pair_id]
283+
# map from (x, y, z) to (0, 27)
284+
cell_id = (x+1) * 9 + (y+1) * 3 + z + 1
292285

293-
dp_list[i, j, :, :, cell_id] += dP
294-
dp_list[i, i, :, :, cell_id] -= dP
286+
# gradient of P for each neighbor, eq_26
287+
# (N_ijs, n, n', l, 3)
288+
# dc * c_conj + c * dc_conj
289+
dP = np.einsum('ijkn, ljk->iljn', dcs[pair_id], np.conj(ctot))
290+
dP += np.conj(np.transpose(dP, axes=[1, 0, 2, 3]))
291+
dP = dP.real[self.tril_indices].flatten().reshape(self.ncoefs, 3)
292+
#print(cs[pair_id].shape, dcs[pair_id].shape, dP.shape)
295293

296-
return dp_list, p_list
294+
dp_list[i, j, :, :, cell_id] += dP
295+
dp_list[i, i, :, :, cell_id] -= dP
297296

297+
return dp_list, p_list
298298

299299

300300
def calculate(self, atoms, atom_ids=None, derivative=False):
@@ -696,5 +696,6 @@ def compute_dcs(pos, nmax, lmax, rcut, alpha, cutoff):
696696
print(f)
697697
print('x', x['x'])
698698
#print('dxdr', x['dxdr'])
699-
print('calculation time {}'.format(start2-start1))
700-
print(f.compute_p(test))
699+
p = f.compute_p(test); print('from P', p)
700+
dp, p = f.compute_dpdr(test); print('from dP', p)
701+
dp, p = f.compute_dpdr_5d(test); print('from dP5d', p)

tests/test_SO3.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def get_dPdR_xtal(xtal, nmax, lmax, rc, eps):
4545

4646
# Descriptors Parameters
4747
eps = 1e-8
48-
rc = 4.00
48+
rc = 2.80
4949
nmax, lmax = 2, 2
5050

5151
# NaCl cluster
@@ -89,6 +89,23 @@ def test_dPdR_graphite(self):
8989
c.from_prototype('graphite')
9090
get_dPdR_xtal(c.to_ase(), nmax, lmax, rc, eps)
9191

92+
def test_dPdR_random(self):
93+
x = [ 7.952, 2.606, 0.592, 0.926, 0.608, 0.307]
94+
c = pyxtal()
95+
c.from_spg_wps_rep(179, ['6a', '6a', '6a', '6a'], x)
96+
get_dPdR_xtal(c.to_ase(), nmax, lmax, rc, eps)
97+
98+
def test_dPdR_random_P(self):
99+
x = [ 7.952, 2.606, 0.592, 0.926, 0.608, 0.307]
100+
c = pyxtal()
101+
c.from_spg_wps_rep(179, ['6a', '6a', '6a', '6a'], x)
102+
atoms = c.to_ase()
103+
f = SO3(nmax=nmax, lmax=lmax, rcut=rc)
104+
p0 = f.compute_p(atoms)
105+
_, p1 = f.compute_dpdr(atoms)
106+
_, p2 = f.compute_dpdr_5d(atoms)
107+
assert(np.allclose(p0, p1, atol=1e-3))
108+
assert(np.allclose(p0, p2, atol=1e-3))
92109

93110
if __name__ == "__main__":
94111
unittest.main()

0 commit comments

Comments
 (0)