Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def test_get_angle_cartesian(vec_a, vec_b, expected_angle):
angle = get_angle_cartesian(vec_a, vec_b)
assert np.isclose(angle, expected_angle)
for i, (theta_b, theta_c) in enumerate(
zip(np.linspace(0, angle_a_to_b, theta_count),
np.linspace(0, angle_a_to_c, theta_count))):
# Define the corner local_b at a rotation theta_b from corner_a toward
# corner_b on the circle surface. Similarly, define the corner local_c
# at a rotation theta_c from corner_a toward corner_c.
rotation_a_to_b = axangle2mat(axis_a_to_b, theta_b)
rotation_a_to_c = axangle2mat(axis_a_to_c, theta_c)
local_b = np.dot(rotation_a_to_b, corner_a)
local_c = np.dot(rotation_a_to_c, corner_a)
# Then define an axis and a maximum rotation to create a great cicle
# arc between local_b and local_c. Ensure that this is not a degenerate
# case where local_b and local_c are coincident.
angle_local_b_to_c = get_angle_cartesian(local_b, local_c)
axis_local_b_to_c = np.cross(local_b, local_c)
if np.count_nonzero(axis_local_b_to_c) == 0:
# Theta rotation ended at the same position. First position, might
# be other cases?
axis_local_b_to_c = corner_a
axis_local_b_to_c /= np.linalg.norm(axis_local_b_to_c)
# Generate points along the great circle arc with a distance defined by
# resolution.
phi_count_local = max(math.ceil(angle_local_b_to_c / resolution), 1)
for j, phi in enumerate(
np.linspace(0, angle_local_b_to_c, phi_count_local)):
rotation_phi = axangle2mat(axis_local_b_to_c, phi)
for k, psi in enumerate(inplane_rotations):
# Combine the rotations. Order is important. The matrix is
# TODO: Inline after choosing the best, and possibly require external sorting (if using sorted)?
unindexed_peak_ids = _choose_peak_ids(peaks, n_peaks_to_index)
# Find possible solutions for each pair of peaks.
for vector_pair_index, peak_pair_indices in enumerate(list(combinations(unindexed_peak_ids, 2))):
# Consider a pair of experimental scattering vectors.
q1, q2 = peaks[peak_pair_indices, :]
q1_len, q2_len = np.linalg.norm(q1), np.linalg.norm(q2)
# Ensure q1 is longer than q2 for consistent order.
if q1_len < q2_len:
q1, q2 = q2, q1
q1_len, q2_len = q2_len, q1_len
# Calculate the angle between experimental scattering vectors.
angle = get_angle_cartesian(q1, q2)
# Get library indices for hkls matching peaks within tolerances.
# TODO: phase are object arrays. Test performance of direct float arrays
tolerance_mask = np.abs(phase_measurements[:, 0] - q1_len) < mag_tol
tolerance_mask[tolerance_mask] &= np.abs(phase_measurements[tolerance_mask, 1] - q2_len) < mag_tol
tolerance_mask[tolerance_mask] &= np.abs(phase_measurements[tolerance_mask, 2] - angle) < angle_tol
# Iterate over matched library vectors determining the error in the
# associated indexation.
if np.count_nonzero(tolerance_mask) == 0:
continue
# Reference vectors are cartesian coordinates of hkls
reference_vectors = lattice_recip.cartesian(phase_indices[tolerance_mask])
# Rotation from experimental to reference frame
if len(corner_c) == 4:
corner_c = uvtw_to_uvw(corner_c)
lattice = structure.lattice
corner_a = np.dot(corner_a, lattice.stdbase)
corner_b = np.dot(corner_b, lattice.stdbase)
corner_c = np.dot(corner_c, lattice.stdbase)
corner_a /= np.linalg.norm(corner_a)
corner_b /= np.linalg.norm(corner_b)
corner_c /= np.linalg.norm(corner_c)
angle_a_to_b = get_angle_cartesian(corner_a, corner_b)
angle_a_to_c = get_angle_cartesian(corner_a, corner_c)
angle_b_to_c = get_angle_cartesian(corner_b, corner_c)
axis_a_to_b = np.cross(corner_a, corner_b)
axis_a_to_c = np.cross(corner_a, corner_c)
# Input validation. The corners have to define a non-degenerate triangle
if np.count_nonzero(axis_a_to_b) == 0:
raise ValueError('Directions a and b are parallel')
if np.count_nonzero(axis_a_to_c) == 0:
raise ValueError('Directions a and c are parallel')
rotations = []
# Generate a list of theta_count evenly spaced angles theta_b in the range
# [0, angle_a_to_b] and an equally long list of evenly spaced angles
# theta_c in the range[0, angle_a_to_c].
# Ensure that we keep the resolution also along the direction to the corner
# b or c farthest away from a.
corner_b = uvtw_to_uvw(corner_b)
if len(corner_c) == 4:
corner_c = uvtw_to_uvw(corner_c)
lattice = structure.lattice
corner_a = np.dot(corner_a, lattice.stdbase)
corner_b = np.dot(corner_b, lattice.stdbase)
corner_c = np.dot(corner_c, lattice.stdbase)
corner_a /= np.linalg.norm(corner_a)
corner_b /= np.linalg.norm(corner_b)
corner_c /= np.linalg.norm(corner_c)
angle_a_to_b = get_angle_cartesian(corner_a, corner_b)
angle_a_to_c = get_angle_cartesian(corner_a, corner_c)
angle_b_to_c = get_angle_cartesian(corner_b, corner_c)
axis_a_to_b = np.cross(corner_a, corner_b)
axis_a_to_c = np.cross(corner_a, corner_c)
# Input validation. The corners have to define a non-degenerate triangle
if np.count_nonzero(axis_a_to_b) == 0:
raise ValueError('Directions a and b are parallel')
if np.count_nonzero(axis_a_to_c) == 0:
raise ValueError('Directions a and c are parallel')
rotations = []
# Generate a list of theta_count evenly spaced angles theta_b in the range
# [0, angle_a_to_b] and an equally long list of evenly spaced angles
# theta_c in the range[0, angle_a_to_c].
# Ensure that we keep the resolution also along the direction to the corner
if len(corner_b) == 4:
corner_b = uvtw_to_uvw(corner_b)
if len(corner_c) == 4:
corner_c = uvtw_to_uvw(corner_c)
lattice = structure.lattice
corner_a = np.dot(corner_a, lattice.stdbase)
corner_b = np.dot(corner_b, lattice.stdbase)
corner_c = np.dot(corner_c, lattice.stdbase)
corner_a /= np.linalg.norm(corner_a)
corner_b /= np.linalg.norm(corner_b)
corner_c /= np.linalg.norm(corner_c)
angle_a_to_b = get_angle_cartesian(corner_a, corner_b)
angle_a_to_c = get_angle_cartesian(corner_a, corner_c)
angle_b_to_c = get_angle_cartesian(corner_b, corner_c)
axis_a_to_b = np.cross(corner_a, corner_b)
axis_a_to_c = np.cross(corner_a, corner_c)
# Input validation. The corners have to define a non-degenerate triangle
if np.count_nonzero(axis_a_to_b) == 0:
raise ValueError('Directions a and b are parallel')
if np.count_nonzero(axis_a_to_c) == 0:
raise ValueError('Directions a and c are parallel')
rotations = []
# Generate a list of theta_count evenly spaced angles theta_b in the range
# [0, angle_a_to_b] and an equally long list of evenly spaced angles
# theta_c in the range[0, angle_a_to_c].
# Iterate through all pairs calculating interplanar angle
phase_vector_pairs = []
for comb in itertools.combinations(np.arange(len(indices)), 2):
i, j = comb[0], comb[1]
# Specify hkls and lengths associated with the crystal structure.
# TODO: This should be updated to reflect systematic absences
if np.count_nonzero(coordinates[i]) == 0 or np.count_nonzero(coordinates[j]) == 0:
continue # Ignore combinations including [000]
hkl1 = indices[i]
hkl2 = indices[j]
len1 = distances[i]
len2 = distances[j]
if len1 < len2: # Keep the longest first
hkl1, hkl2 = hkl2, hkl1
len1, len2 = len1, len2
angle = get_angle_cartesian(coordinates[i], coordinates[j])
phase_vector_pairs.append(np.array([hkl1, hkl2, len1, len2, angle]))
vector_library[phase_name] = np.array(phase_vector_pairs)
# Pass attributes to diffraction library from structure library.
vector_library.identifiers = self.structures.identifiers
vector_library.structures = self.structures.structures
return vector_library