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_box_vector_calculation(len_a, len_b, len_c, alpha, beta, gamma): box = struc.vectors_from_unitcell(len_a, len_b, len_c, np.deg2rad(alpha), np.deg2rad(beta), np.deg2rad(gamma)) from mdtraj.utils import lengths_and_angles_to_box_vectors ref_box = np.stack( lengths_and_angles_to_box_vectors(len_a, len_b, len_c, alpha, beta, gamma)) assert np.allclose(box, ref_box) assert struc.unitcell_from_vectors(box) == pytest.approx( (len_a, len_b, len_c, alpha * 2 * np.pi / 360, beta * 2 * np.pi / 360, gamma * 2 * np.pi / 360))
def test_conversion_to_fraction(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]) fractions = struc.coord_to_fraction(coord, box) if struc.is_orthogonal(box): assert fractions.tolist() == pytest.approx(coord / np.diagonal(box)) new_coord = struc.fraction_to_coord(fractions, box) assert np.allclose(coord, new_coord) coords = np.stack([coord, coord]) boxes = np.stack([box, box]) fractions = struc.coord_to_fraction(coords, boxes) new_coords = struc.fraction_to_coord(fractions, boxes) assert np.allclose(coords, new_coords)
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)
# # Simulation boxes and unit cells # ------------------------------- # # Depending on the source of the macromolecular structure, there might # be an associated unit cell or simulation box. # In this package such boxes are represented by *(3,3)*-shaped # :class:`ndarray` objects, where each element in the array is one of # the three vectors spanning the box or unit cell. # Let's create an orthorhombic box from the vector lengths and the # angles between the vectors. import numpy as np import biotite.structure as struc # The function uses angles in radians box = struc.vectors_from_unitcell(10, 20, 30, np.pi / 2, np.pi / 2, np.pi / 2) print("Box:") print(box) print("Box volume:", struc.box_volume(box)) print("Is orthogonal?:", struc.is_orthogonal(box)) cell = struc.unitcell_from_vectors(box) print("Cell:") print(cell) ######################################################################## # An atom array can have an associated box, which is used in functions, # that consider periodic boundary conditions. # Atom array stacks require a *(m,3,3)*-shaped :class:`ndarray`, # that contains the box vectors for each model. # The box is accessed via the `box` attribute, which is ``None`` by # default.