diff --git a/dpgen/auto_test/Interstitial.py b/dpgen/auto_test/Interstitial.py index a4b06ae1c..b3b6db911 100644 --- a/dpgen/auto_test/Interstitial.py +++ b/dpgen/auto_test/Interstitial.py @@ -13,6 +13,20 @@ from dpgen.auto_test.reproduce import make_repro, post_repro +def _smallest_nonzero_distance(distance_matrix): + """Return the minimum distance between two distinct atoms. + + Selecting by matrix index, instead of by value, keeps a real zero distance + caused by coincident atoms while excluding the zero-valued diagonal. + """ + distances = np.asarray(distance_matrix) + atom_pairs = np.triu_indices_from(distances, k=1) + pair_distances = distances[atom_pairs] + if pair_distances.size == 0: + raise ValueError("distance matrix does not contain a pair of atoms") + return float(np.min(pair_distances)) + + class Interstitial(Property): def __init__(self, parameter, inter_param=None): parameter["reproduce"] = parameter.get("reproduce", False) @@ -191,7 +205,9 @@ def make_confs(self, path_to_work, path_to_equi, refine=False): temp = jj.get_supercell_structure( sc_mat=np.diag(self.supercell, k=0) ) - smallest_distance = list(set(temp.distance_matrix.ravel()))[1] + smallest_distance = _smallest_nonzero_distance( + temp.distance_matrix + ) if ( "conf_filters" in self.parameter and "min_dist" in self.parameter["conf_filters"] diff --git a/tests/auto_test/test_interstitial_distance.py b/tests/auto_test/test_interstitial_distance.py new file mode 100644 index 000000000..ef661c618 --- /dev/null +++ b/tests/auto_test/test_interstitial_distance.py @@ -0,0 +1,32 @@ +import unittest + +import numpy as np + +from dpgen.auto_test.Interstitial import _smallest_nonzero_distance + + +class TestInterstitialDistance(unittest.TestCase): + def test_smallest_nonzero_distance(self): + distance_matrix = np.array( + [ + [0.0, 2.5, 1.25], + [2.5, 0.0, 3.0], + [1.25, 3.0, 0.0], + ] + ) + self.assertEqual(_smallest_nonzero_distance(distance_matrix), 1.25) + + def test_exact_overlap_is_retained(self): + """An off-diagonal zero represents an invalid atomic overlap.""" + distance_matrix = np.array( + [ + [0.0, 0.0, 1.25], + [0.0, 0.0, 2.5], + [1.25, 2.5, 0.0], + ] + ) + self.assertEqual(_smallest_nonzero_distance(distance_matrix), 0.0) + + +if __name__ == "__main__": + unittest.main()