def test_translate(input_atoms, ndim, as_list, random_seed): """ Translate and translate back and check if the coordinates are still the same. """ if ndim > len(input_atoms.shape): # Cannot run tests if translation vector has more dimensions # as input coordinates/atoms return np.random.seed(random_seed) vectors = np.random.rand(*struc.coord(input_atoms).shape[-ndim:]) vectors *= 10 neg_vectors = -vectors if as_list: vectors = vectors.tolist() neg_vectors = neg_vectors.tolist() translated = struc.translate(input_atoms, vectors) restored = struc.translate(translated, neg_vectors) assert type(restored) == type(input_atoms) assert struc.coord(restored).shape == struc.coord(input_atoms).shape assert np.allclose( struc.coord(restored), struc.coord(input_atoms), atol=1e-5 )
def test_superimposition_array(path): pdbx_file = pdbx.PDBxFile() pdbx_file.read(path) fixed = pdbx.get_structure(pdbx_file, model=1) mobile = fixed.copy() mobile = struc.rotate(mobile, (1, 2, 3)) mobile = struc.translate(mobile, (1, 2, 3)) fitted, transformation = struc.superimpose(fixed, mobile, (mobile.atom_name == "CA")) assert struc.rmsd(fixed, fitted) == pytest.approx(0) fitted = struc.superimpose_apply(mobile, transformation) assert struc.rmsd(fixed, fitted) == pytest.approx(0)
def test_remove_pbc_unsegmented(): """ `remove_pbc()` should not alter unsegmented structures, when the structure is entirely in the box. Exclude the solvent, due to high distances between each atom. """ ref_array = load_structure(join(data_dir("structure"), "3o5r.mmtf")) # Center structure in box centroid = struc.centroid(ref_array) box_center = np.diag(ref_array.box) / 2 ref_array = struc.translate(ref_array, box_center - centroid) # Remove solvent ref_array = ref_array[~struc.filter_solvent(ref_array)] array = struc.remove_pbc(ref_array) assert ref_array.equal_annotation_categories(array) assert np.allclose(ref_array.coord, array.coord)
def test_superimposition_array(path): """ Take a structure and rotate and translate a copy of it, so that they are not superimposed anymore. Then superimpose these structure onto each other and expect an almost perfect match. """ fixed = strucio.load_structure(path, model=1) mobile = fixed.copy() mobile = struc.rotate(mobile, (1, 2, 3)) mobile = struc.translate(mobile, (1, 2, 3)) fitted, transformation = struc.superimpose(fixed, mobile) assert struc.rmsd(fixed, fitted) == pytest.approx(0, abs=6e-4) fitted = struc.superimpose_apply(mobile, transformation) assert struc.rmsd(fixed, fitted) == pytest.approx(0, abs=6e-4)
def test_hbond_periodicity(translation_vector): """ Test whether hydrogen bond identification uses periodic boundary conditions correctly. For this purpose a structure containing water is loaded and the hydrogen bonds are identified. Then the position of the periodic boundary is changed and it is expected that all hydrogen bonds are still the same """ stack = load_structure(join(data_dir("structure"), "waterbox.gro")) array = stack[0] ref_hbonds = struc.hbond(array, periodic=True) # Put H-bond triplets into as stack for faster comparison with # set for moved atoms ref_hbonds = set([tuple(triplet) for triplet in ref_hbonds]) # Move system and put back into box # -> Equal to move of periodic boundary array = struc.translate(array, translation_vector) array.coord = struc.move_inside_box(array.coord, array.box) hbonds = struc.hbond(array, periodic=True) hbonds = set([tuple(triplet) for triplet in hbonds]) assert ref_hbonds == hbonds
def test_remove_pbc_restore(multi_model, translation_vector): CUTOFF = 5.0 def get_matrices(array): """ Create a periodic and non-periodic adjacency matrix. """ nonlocal CUTOFF if isinstance(array, struc.AtomArray): matrix = struc.CellList(array, CUTOFF, periodic=False) \ .create_adjacency_matrix(CUTOFF) matrix_pbc = struc.CellList(array, CUTOFF, periodic=True) \ .create_adjacency_matrix(CUTOFF) elif isinstance(array, struc.AtomArrayStack): matrix = np.array([ struc.CellList(model, CUTOFF, periodic=False).create_adjacency_matrix(CUTOFF) for model in array ]) matrix_pbc = np.array([ struc.CellList(model, CUTOFF, periodic=True).create_adjacency_matrix(CUTOFF) for model in array ]) return matrix, matrix_pbc def assert_equal_matrices(array, matrix1, matrix2, periodic): """ Due to numerical instability, entries in both matrices might be different, when the distance of atoms is almost equal to the cutoff distance of the matrix. This function checks, whether two atoms with unequal entries in the matrices are near the cutoff distance. """ nonlocal CUTOFF indices = np.where(matrix1 != matrix2) for index in range(len(indices[0])): if len(indices) == 2: # multi_model = False -> AtomArray m = None i = indices[0][index] j = indices[1][index] box = array.box if periodic else None distance = struc.distance(array[i], array[j], box=box) if len(indices) == 3: # multi_model = True -> AtomArrayStack m = indices[0][index] i = indices[1][index] j = indices[2][index] box = array.box[m] if periodic else None distance = struc.distance(array[m, i], array[m, j], box=box) try: assert distance == pytest.approx(CUTOFF, abs=1e-4) except AssertionError: print(f"Model {m}, Atoms {i} and {j}") raise stack = load_structure(join(data_dir("structure"), "1gya.mmtf")) stack.box = np.array([ np.diag(np.max(coord, axis=0) - np.min(coord, axis=0) + 10) for coord in stack.coord ]) stack.coord -= np.min(stack.coord, axis=-2)[:, np.newaxis, :] - 5 if multi_model: array = stack else: array = stack[0] # Use adjacency matrices instead of pairwise distances # for compuational efficiency ref_matrix, ref_matrix_pbc = get_matrices(array) array = struc.translate(array, translation_vector) array.coord = struc.move_inside_box(array.coord, array.box) moved_matrix, moved_matrix_pbc = get_matrices(array) # The translation and the periodic move should not # alter PBC-aware pairwise distances assert_equal_matrices(array, ref_matrix_pbc, moved_matrix_pbc, True) # Non-PBC-aware distances should change, # otherwise the atoms do not go over the periodic boundary # and the test does not make sense with pytest.raises(AssertionError): assert_equal_matrices(array, ref_matrix, moved_matrix, False) array = struc.remove_pbc(array) restored_matrix, restored_matrix_pbc = get_matrices(array) # Both adjacency matrices should be equal to the original ones, # as the structure should be completely restored assert_equal_matrices(array, ref_matrix_pbc, restored_matrix_pbc, True) assert_equal_matrices(array, ref_matrix, restored_matrix, False)