Exemple #1
0
def test_move_into_box(len_a, len_b, len_c, alpha, beta, gamma, x, y, z):
    box = struc.vectors_from_unitcell(len_a, len_b, len_c, np.deg2rad(alpha),
                                      np.deg2rad(beta), np.deg2rad(gamma))
    coord = np.array([x, y, z])

    moved_coord = struc.move_inside_box(coord, box)
    fractions = struc.coord_to_fraction(moved_coord, box)
    assert ((fractions >= 0) & (fractions <= 1)).all()
def test_index_distance_periodic_triclinic(shift, angles):
    """
    The PBC aware computation, should give the same results,
    irrespective of which atoms are centered in the box 
    """
    array = strucio.load_structure(join(data_dir("structure"), "3o5r.mmtf"))
    # Use a box based on the boundaries of the structure
    # '+1' to add a margin
    boundaries = np.max(array.coord, axis=0) - np.min(array.coord, axis=0) + 1
    angles = np.deg2rad(angles)
    array.box = struc.vectors_from_unitcell(boundaries[0], boundaries[1],
                                            boundaries[2], angles[0],
                                            angles[1], angles[2])

    length = array.array_length()
    dist_indices = np.stack([
        np.repeat(np.arange(length), length),
        np.tile(np.arange(length), length)
    ],
                            axis=1)
    # index_distance() creates a large ndarray
    try:
        ref_dist = struc.index_distance(array, dist_indices, periodic=True)
    except MemoryError:
        pytest.skip("Not enough memory")

    # Compare with MDTraj
    import mdtraj
    traj = mdtraj.load(join(data_dir("structure"), "3o5r.pdb"))
    # Angstrom to Nanometers
    traj.unitcell_vectors = array.box[np.newaxis, :, :] / 10
    # Nanometers to Angstrom
    mdtraj_dist = mdtraj.compute_distances(traj, dist_indices)[0] * 10
    ind = np.where(~np.isclose(ref_dist, mdtraj_dist, atol=1e-5, rtol=1e-3))[0]
    assert np.allclose(ref_dist, mdtraj_dist, atol=1e-5, rtol=1e-3)

    # Compare with shifted variant
    array.coord += shift
    array.coord = struc.move_inside_box(array.coord, array.box)
    # index_distance() creates a large ndarray
    try:
        test_dist = struc.index_distance(array, dist_indices, periodic=True)
    except MemoryError:
        pytest.skip("Not enough memory")
    assert np.allclose(test_dist, ref_dist, atol=1e-5)
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
Exemple #4
0
def test_index_distance_periodic_orthogonal(shift):
    """
    The PBC aware computation, should give the same results,
    irrespective of which atoms are centered in the box 
    """
    array = strucio.load_structure(join(data_dir, "3o5r.mmtf"))
    # Use a box based on the boundaries of the structure
    # '+1' to add a margin
    array.box = np.diag(
        np.max(array.coord, axis=0) - np.min(array.coord, axis=0) + 1)

    length = array.array_length()
    dist_indices = np.stack([
        np.repeat(np.arange(length), length),
        np.tile(np.arange(length), length)
    ],
                            axis=1)
    ref_dist = struc.index_distance(array, dist_indices, periodic=True)

    array.coord += shift
    array.coord = struc.move_inside_box(array.coord, array.box)
    dist = struc.index_distance(array, dist_indices, periodic=True)
    assert np.allclose(dist, ref_dist, atol=1e-5)
Exemple #5
0
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)