Skip to content

Commit 30d729d

Browse files
committed
reduce the use of hkl indices for mono/tri-clinic systems
1 parent 7b7cb0d commit 30d729d

File tree

2 files changed

+29
-77
lines changed

2 files changed

+29
-77
lines changed

pyxtal/XRD_indexer.py

Lines changed: 21 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -146,80 +146,35 @@ def get_cell_params(spg, hkls, two_thetas, wave_length=1.54184):
146146
cell_values.append((a, b, c))
147147
except np.linalg.LinAlgError:
148148
continue
149-
# Generate all possible triplets
150-
#n_hkls = len(hkls)
151-
#from itertools import combinations
152-
#triplet_indices = list(combinations(range(n_hkls), 3))
153-
#
154-
#if len(triplet_indices) == 0:
155-
# return []
156-
#
157-
## Convert to arrays for vectorized operations
158-
#triplets = np.array(triplet_indices) # Shape: (n_triplets, 3)
159-
#
160-
## Get all triplets of hkls and d-spacings
161-
#hkls_triplets = hkls[triplets] # Shape: (n_triplets, 3, 3)
162-
#d_triplets = d_spacings[triplets] # Shape: (n_triplets, 3)
163-
#
164-
## Build coefficient matrices for all triplets
165-
#A = np.zeros((len(triplets), 3, 3))
166-
#A[:, :, 0] = hkls_triplets[:, :, 0]**2 # h²
167-
#A[:, :, 1] = hkls_triplets[:, :, 1]**2 # k²
168-
#A[:, :, 2] = hkls_triplets[:, :, 2]**2 # l²
169-
#
170-
#b = 1/d_triplets**2 # Shape: (n_triplets, 3)
171-
#
172-
#try:
173-
# x = np.linalg.solve(A, b) # Shape: (n_triplets, 3)
174-
# # Filter valid solutions
175-
# valid = np.all(x > 0, axis=1)
176-
# x_valid = x[valid]
177-
#
178-
# if len(x_valid) > 0:
179-
# a_values = np.sqrt(1/x_valid[:, 0])
180-
# b_values = np.sqrt(1/x_valid[:, 1])
181-
# c_values = np.sqrt(1/x_valid[:, 2])
182-
# cell_values = list(zip(a_values, b_values, c_values))
183-
#except np.linalg.LinAlgError:
184-
# pass
185149

186150
elif 3 <= spg <= 15: # monoclinic, need a, b, c, beta
187151
# need four hkls to determine a, b, c, beta
188-
len_solutions = len(hkls) // 4
152+
N = 4
153+
len_solutions = len(hkls) // N
189154
for i in range(len_solutions):
190-
(h1, k1, l1), (h2, k2, l2), (h3, k3, l3), (h4, k4, l4) = hkls[4*i], hkls[4*i + 1], hkls[4*i + 2], hkls[4*i + 3]
191-
theta1 = np.radians(two_thetas[4*i] / 2)
192-
theta2 = np.radians(two_thetas[4*i + 1] / 2)
193-
theta3 = np.radians(two_thetas[4*i + 2] / 2)
194-
theta4 = np.radians(two_thetas[4*i + 3] / 2)
195-
d1 = wave_length / (2 * np.sin(theta1))
196-
d2 = wave_length / (2 * np.sin(theta2))
197-
d3 = wave_length / (2 * np.sin(theta3))
198-
d4 = wave_length / (2 * np.sin(theta4))
155+
hkls_sub = hkls[N*i:N*i+N]
156+
thetas_sub = np.radians(two_thetas[N*i:N*i+N]/2)
157+
d_sub = (1/wave_length / (2 * np.sin(thetas_sub)))**2
158+
199159
# Non-linear system; use numerical methods
200160
from scipy.optimize import minimize
201-
202161
def objective(params):
203-
a, b, c, beta_deg = params
204-
beta = np.radians(beta_deg)
205-
eqs = []
206-
for (h, k, l), d_obs in zip([(h1, k1, l1), (h2, k2, l2), (h3, k3, l3), (h4, k4, l4)],
207-
[d1, d2, d3, d4]):
208-
sin_beta_sq = np.sin(beta)**2
209-
d_calc_inv_sq = (h**2 / (a**2 * sin_beta_sq)) + (k**2 / b**2) + \
210-
(l**2 / (c**2 * sin_beta_sq)) - \
211-
(2 * h * l * np.cos(beta) / (a * c * sin_beta_sq))
212-
eqs.append((1/d_obs**2 - d_calc_inv_sq)**2)
213-
return sum(eqs)
214-
initial_guess = [2.0, 2.0, 2.0, 90.0]
215-
result = minimize(objective, initial_guess)#; print(result.x, result.fun)
216-
if result.success:
162+
a, b, c, beta = params
163+
sin_beta2 = np.sin(beta)**2
164+
cos_beta = np.cos(beta)
165+
h, k, l = hkls_sub[:, 0], hkls_sub[:, 1], hkls_sub[:, 2]
166+
d_inv_sq = (h**2 / (a**2 * sin_beta2)) + (k**2 / b**2) + \
167+
(l**2 / (c**2 * sin_beta2)) - \
168+
(2 * h * l * cos_beta / (a * c * sin_beta2))
169+
return np.sum((d_sub - d_inv_sq)**2)
170+
171+
initial_guess = [2.0, 2.0, 2.0, np.pi/2]
172+
bounds = [(1.8, 50), (1.8, 50), (1.8, 50), (np.pi/4, np.pi*3/4)]
173+
result = minimize(objective, initial_guess, bounds=bounds)
174+
if result.success and result.fun < 1e-5:
217175
a, b, c, beta = result.x
218-
if a > 50 or b > 50 or c > 50 or beta <= 45 or beta >= 135:
219-
continue
220-
if a < 0 or b < 0 or c < 0:
221-
continue
222-
cell_values.append((a, b, c, beta))
176+
cell_values.append((a, b, c, np.degrees(beta)))
177+
#print(result.x, result.fun, hkls_sub, thetas_sub)
223178
else:
224179
msg = "Only cubic, tetragonal, hexagonal, and orthorhombic systems are supported."
225180
raise NotImplementedError(msg)
@@ -442,7 +397,6 @@ def get_cell_from_multi_hkls(spg, hkls, two_thetas, long_thetas=None, wave_lengt
442397
# Filter out None values
443398
valid_mask = expected_thetas != None
444399
valid_thetas = expected_thetas[valid_mask]
445-
valid_hkls = test_hkls[valid_mask]
446400
# Now try to index all other peaks using this 'a'
447401

448402
if len(valid_thetas) > 0:

pyxtal/symmetry.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -696,8 +696,12 @@ def generate_possible_hkls(self, h_max, k_max=None, l_max=None, max_square=12):
696696
canonical_seen = set() # Track canonical forms to avoid duplicates
697697

698698
for h in range(0, h_max + 1):
699-
for k in range(0, k_max + 1):
700-
for l in range(0, l_max + 1):
699+
# add permutation
700+
k_min = h if self.number < 3 else 0
701+
for k in range(k_min, k_max + 1):
702+
# add additional
703+
l_min = 0 if self.number > 15 else h
704+
for l in range(l_min, l_max + 1):
701705
if h == 0 and k == 0 and l == 0: # Exclude (0,0,0)
702706
continue
703707
if h*h + k*k + l*l > max_square:
@@ -864,7 +868,7 @@ def reduce_hkl_guesses(self, hkls, total_square=None):
864868

865869
if 15 < self.number < 75:
866870
hkls = np.abs(hkls)
867-
mask1 = np.all(hkls[:, 0] >= hkls[:, 1], axis=1)#; print("mask\n", mask1, hkls[2], hkls[2,0], hkls[2,1], hkls[2,0] >= hkls[2,1])
871+
mask1 = np.all(hkls[:, 0] >= hkls[:, 1], axis=1)
868872
mask2 = np.all(hkls[:, 1] >= hkls[:, 2], axis=1)
869873
mask3 = np.all(hkls[:, 0] >= hkls[:, 2], axis=1)
870874
mask = (mask1 | mask2 | mask3)#; print("mask", len(mask), hkls[mask][:5])
@@ -4842,13 +4846,7 @@ def get_canonical_hkl(h, k, l, spg):
48424846
h_sorted = sorted([hkl[0], hkl[1]], reverse=True)
48434847
return tuple([h_sorted[0], h_sorted[1], hkl[2]])
48444848

4845-
#elif spg >= 16: # orthorhombic
4846-
# # For orthorhombic: all axes are unique, but we can still sort for canonical form
4847-
# # Sort all three in descending order to remove permutation duplicates
4848-
# hkl.sort(reverse=True)
4849-
# return tuple(hkl)
4850-
4851-
else: # monoclinic, triclinic
4849+
else: # monoclinic, triclinic
48524850
# Lower symmetry: sort to remove permutation duplicates
48534851
#hkl.sort(reverse=True)
48544852
return tuple(hkl)

0 commit comments

Comments
 (0)