From 609123a824fb64d1a5c86e7bcf7e4b82a2986378 Mon Sep 17 00:00:00 2001 From: padix-key Date: Wed, 13 Mar 2019 14:05:05 +0100 Subject: [PATCH 1/5] Using float32 for coordinates and box --- src/biotite/structure/atoms.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/biotite/structure/atoms.py b/src/biotite/structure/atoms.py index 1fa816752..dbb363705 100644 --- a/src/biotite/structure/atoms.py +++ b/src/biotite/structure/atoms.py @@ -260,13 +260,13 @@ def __setattr__(self, attr, value): if not isinstance(value, np.ndarray): raise TypeError("Value must be ndarray of floats") if isinstance(self, AtomArray): - if len(value.shape) != 2: + if value.ndim != 2: raise ValueError( "A 2-dimensional ndarray is expected " "for an AtomArray" ) elif isinstance(self, AtomArrayStack): - if len(value.shape) != 3: + if value.ndim != 3: raise ValueError( "A 3-dimensional ndarray is expected " "for an AtomArrayStack" @@ -278,7 +278,7 @@ def __setattr__(self, attr, value): ) if value.shape[-1] != 3: raise TypeError("Expected 3 coordinates for each atom") - self._coord = value + self._coord = value.astype(np.float32, copy=False) elif attr == "bonds": if isinstance(value, BondList): @@ -298,13 +298,13 @@ def __setattr__(self, attr, value): if value is None: self._box = None elif isinstance(self, AtomArray): - if len(value.shape) != 2: + if value.ndim != 2: raise ValueError( "A 2-dimensional ndarray is expected " "for an AtomArray" ) elif isinstance(self, AtomArrayStack): - if len(value.shape) != 3: + if value.ndim != 3: raise ValueError( "A 3-dimensional ndarray is expected " "for an AtomArrayStack" @@ -312,7 +312,7 @@ def __setattr__(self, attr, value): if isinstance(value, np.ndarray): if value.shape[-2:] != (3,3): raise TypeError("Box must be a 3x3 matrix (three vectors)") - self._box = value + self._box = value.astype(np.float32, copy=False) elif value is None: # Remove bond list self._box = None @@ -453,7 +453,7 @@ def __init__(self, coord, **kwargs): kwargs = kwargs["kwargs"] for name, annotation in kwargs.items(): self._annot[name] = annotation - coord = np.array(coord, dtype=float) + coord = np.array(coord, dtype=np.float32) # Check if coord contains x,y and z coordinates if coord.shape != (3,): raise ValueError("Position must be ndarray with shape (3,)") @@ -603,7 +603,7 @@ def __init__(self, length): if length is None: self._coord = None else: - self._coord = np.full((length, 3), np.nan, dtype=float) + self._coord = np.full((length, 3), np.nan, dtype=np.float32) def get_atom(self, index): """ @@ -821,7 +821,7 @@ def __init__(self, depth, length): if depth == None or length == None: self._coord = None else: - self._coord = np.full((depth, length, 3), np.nan, dtype=float) + self._coord = np.full((depth, length, 3), np.nan, dtype=np.float32) def get_array(self, index): """ @@ -1147,6 +1147,6 @@ def coord(item): if type(item) in (Atom, AtomArray, AtomArrayStack): return item.coord elif isinstance(item, np.ndarray): - return item.astype(float, copy=False) + return item.astype(np.float32, copy=False) else: - return np.array(item, dtype=float) + return np.array(item, dtype=np.float32) From 398b6b2e1d7a72fd6e33c1898945b547618e0aae Mon Sep 17 00:00:00 2001 From: padix-key Date: Fri, 15 Mar 2019 14:57:57 +0100 Subject: [PATCH 2/5] Structure file readers return 'coord' and 'box' as float32 --- src/biotite/structure/box.py | 4 ++-- src/biotite/structure/io/pdbx/convert.py | 13 ++++++++----- tests/structure/test_box.py | 2 +- tests/structure/test_superimpose.py | 4 ++-- tests/structure/test_transform.py | 2 +- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/biotite/structure/box.py b/src/biotite/structure/box.py index 35ec33cf4..70f82a259 100644 --- a/src/biotite/structure/box.py +++ b/src/biotite/structure/box.py @@ -61,11 +61,11 @@ def vectors_from_unitcell(len_a, len_b, len_c, alpha, beta, gamma): [a_x, 0, 0], [b_x, b_y, 0], [c_x, c_y, c_z] - ], dtype=float) + ], dtype=np.float32) # Fix numerical errors, as values, that are actually 0, # might not be calculated as such - tol = 1e-6 * (len_a + len_b + len_c) + tol = 1e-4 * (len_a + len_b + len_c) box[np.abs(box) < tol] = 0 return box diff --git a/src/biotite/structure/io/pdbx/convert.py b/src/biotite/structure/io/pdbx/convert.py index e5d05c45b..caf16ad44 100644 --- a/src/biotite/structure/io/pdbx/convert.py +++ b/src/biotite/structure/io/pdbx/convert.py @@ -115,7 +115,7 @@ def get_structure(pdbx_file, model=None, data_block=None, raise BadStructureError("The models in the file have unequal " "amount of atoms, give an explicit model " "instead") - stack.coord = np.zeros((model_count, model_length, 3), dtype=float) + stack.coord = np.zeros((model_count,model_length,3), dtype=np.float32) stack.coord[:,:,0] = atom_site_dict["Cartn_x"].reshape((model_count, model_length)) stack.coord[:,:,1] = atom_site_dict["Cartn_y"].reshape((model_count, @@ -135,10 +135,13 @@ def get_structure(pdbx_file, model=None, data_block=None, array = AtomArray(model_length) _fill_annotations(array, model_dict, extra_fields) model_filter = (models == str(model)) - array.coord = np.zeros((model_length, 3), dtype=float) - array.coord[:,0]= atom_site_dict["Cartn_x"][model_filter].astype(float) - array.coord[:,1]= atom_site_dict["Cartn_y"][model_filter].astype(float) - array.coord[:,2]= atom_site_dict["Cartn_z"][model_filter].astype(float) + array.coord = np.zeros((model_length, 3), dtype=np.float32) + array.coord[:,0] = atom_site_dict["Cartn_x"][model_filter] \ + .astype(np.float32) + array.coord[:,1] = atom_site_dict["Cartn_y"][model_filter] \ + .astype(np.float32) + array.coord[:,2] = atom_site_dict["Cartn_z"][model_filter] \ + .astype(np.float32) array = _filter_inscode_altloc(array, model_dict, insertion_code, altloc) array.box = _get_box(pdbx_file, data_block) diff --git a/tests/structure/test_box.py b/tests/structure/test_box.py index 83d94ad14..fa34a5e39 100644 --- a/tests/structure/test_box.py +++ b/tests/structure/test_box.py @@ -195,7 +195,7 @@ def assert_equal_matrices(array, matrix1, matrix2, periodic): 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-5) + assert distance == pytest.approx(CUTOFF, abs=1e-4) except AssertionError: print(f"Model {m}, Atoms {i} and {j}") raise diff --git a/tests/structure/test_superimpose.py b/tests/structure/test_superimpose.py index 65fe3c7bd..9586f1842 100755 --- a/tests/structure/test_superimpose.py +++ b/tests/structure/test_superimpose.py @@ -24,9 +24,9 @@ def test_superimposition_array(path): fitted, transformation = struc.superimpose( fixed, mobile, (mobile.atom_name == "CA") ) - assert struc.rmsd(fixed, fitted) == pytest.approx(0) + assert struc.rmsd(fixed, fitted) == pytest.approx(0, abs=1e-4) fitted = struc.superimpose_apply(mobile, transformation) - assert struc.rmsd(fixed, fitted) == pytest.approx(0) + assert struc.rmsd(fixed, fitted) == pytest.approx(0, abs=1e-4) @pytest.mark.parametrize("ca_only", (True, False)) def test_superimposition_stack(ca_only): diff --git a/tests/structure/test_transform.py b/tests/structure/test_transform.py index 851a8edfe..b4f86db0b 100644 --- a/tests/structure/test_transform.py +++ b/tests/structure/test_transform.py @@ -15,4 +15,4 @@ def test_rotate_centered(): file.read(join(data_dir, "1l2y.npz")) array = file.get_structure()[0] rotated = struc.rotate_centered(array, [2*np.pi, 2*np.pi, 2*np.pi]) - assert np.sum(rotated.coord-array.coord) == pytest.approx(0) \ No newline at end of file + assert np.sum(rotated.coord-array.coord) == pytest.approx(0, abs=1e-4) \ No newline at end of file From 61984fc30fb56fba8f99fe2cbd983a8ba96ca89a Mon Sep 17 00:00:00 2001 From: padix-key Date: Mon, 18 Mar 2019 14:25:59 +0100 Subject: [PATCH 3/5] Altered NumPy formatter for floats --- tests/test_doctest.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/test_doctest.py b/tests/test_doctest.py index c82b83b37..ff0b2831a 100644 --- a/tests/test_doctest.py +++ b/tests/test_doctest.py @@ -56,6 +56,7 @@ def test_doctest(package_name, context_package_names): globs = {} mod_names = [] #The package itself is also used as context + print(package_name) for name in context_package_names + [package_name]: context_package = import_module(name) mod_names += _list_modules(context_package, False) @@ -68,12 +69,14 @@ def test_doctest(package_name, context_package_names): globs["path_to_structures"] = "./tests/structure/data/" globs["path_to_sequences"] = "./tests/sequence/data/" # Add frequently used modules - globs["np"] = np + globs["np"] = np # Add frequently used objects globs["atom_array_stack"] = strucio.load_structure( "./tests/structure/data/1l2y.mmtf" ) globs["atom_array"] = globs["atom_array_stack"][0] + # Adjust NumPy print formatting + np.set_printoptions(precision=3, floatmode="maxprec_equal") # Run doctests package = import_module(package_name) @@ -97,7 +100,9 @@ def _list_modules(package, recursive): Recursively list module names. """ modnames = [] + print(package.__path__) for finder, modname, ispkg in pkgutil.walk_packages(package.__path__): + print(modname, ispkg) abs_modname = f"{package.__name__}.{modname}" if ispkg: if recursive: From d0424a30a3c992b50184f98e540e944c15f14237 Mon Sep 17 00:00:00 2001 From: padix-key Date: Mon, 18 Mar 2019 14:27:20 +0100 Subject: [PATCH 4/5] Non-recursive module finder --- tests/test_doctest.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/test_doctest.py b/tests/test_doctest.py index ff0b2831a..cf0e1f529 100644 --- a/tests/test_doctest.py +++ b/tests/test_doctest.py @@ -56,7 +56,6 @@ def test_doctest(package_name, context_package_names): globs = {} mod_names = [] #The package itself is also used as context - print(package_name) for name in context_package_names + [package_name]: context_package = import_module(name) mod_names += _list_modules(context_package, False) @@ -100,9 +99,7 @@ def _list_modules(package, recursive): Recursively list module names. """ modnames = [] - print(package.__path__) - for finder, modname, ispkg in pkgutil.walk_packages(package.__path__): - print(modname, ispkg) + for finder, modname, ispkg in pkgutil.iter_modules(package.__path__): abs_modname = f"{package.__name__}.{modname}" if ispkg: if recursive: From 69f2d60c4506cef3ee8087bddb23e7d583791b2b Mon Sep 17 00:00:00 2001 From: padix-key Date: Mon, 18 Mar 2019 14:31:04 +0100 Subject: [PATCH 5/5] Adopted doctests for new NumPy float formatter --- src/biotite/sequence/align/multiple.pyx | 8 ++--- src/biotite/structure/box.py | 8 ++--- src/biotite/structure/geometry.py | 40 ++++++++++----------- src/biotite/structure/hbond.py | 12 +++---- src/biotite/structure/residues.py | 47 ++++++++++++------------- 5 files changed, 55 insertions(+), 60 deletions(-) diff --git a/src/biotite/sequence/align/multiple.pyx b/src/biotite/sequence/align/multiple.pyx index 1e93b4350..afc02eaef 100644 --- a/src/biotite/sequence/align/multiple.pyx +++ b/src/biotite/sequence/align/multiple.pyx @@ -197,10 +197,10 @@ def align_multiple(sequences, matrix, gap_penalty=-10, terminal_penalty=True, BIQT-ITE TITANITE >>> print(distances) - [[-0. 1.0340737 0.3819849 0.5604919] - [ 1.0340737 -0. 0.9231636 1.1316341] - [ 0.3819849 0.9231636 -0. 0.6316943] - [ 0.5604919 1.1316341 0.6316943 -0. ]] + [[-0.000 1.034 0.382 0.560] + [ 1.034 -0.000 0.923 1.132] + [ 0.382 0.923 -0.000 0.632] + [ 0.560 1.132 0.632 -0.000]] >>> >>> print(tree.to_newick( ... labels=["seq1", "seq2", "seq3", "seq4"], include_distance=False diff --git a/src/biotite/structure/box.py b/src/biotite/structure/box.py index 70f82a259..b952ff982 100644 --- a/src/biotite/structure/box.py +++ b/src/biotite/structure/box.py @@ -561,10 +561,10 @@ def coord_to_fraction(coord, box): [-5. 2. 1.]] >>> fractions = coord_to_fraction(coord, box) >>> print(fractions) - [[ 0.2 0. 0.2] - [ 2. 0. 0. ] - [ 0. -2. 2. ] - [-1. 0.2 0.2]] + [[ 0.2 0.0 0.2] + [ 2.0 0.0 0.0] + [ 0.0 -2.0 2.0] + [-1.0 0.2 0.2]] """ return np.matmul(coord, linalg.inv(box)) diff --git a/src/biotite/structure/geometry.py b/src/biotite/structure/geometry.py index b72a21821..b46596201 100644 --- a/src/biotite/structure/geometry.py +++ b/src/biotite/structure/geometry.py @@ -515,26 +515,26 @@ def dihedral_backbone(atom_array, chain_id): >>> phi, psi, omega = dihedral_backbone(atom_array, "A") >>> print(np.stack([phi * 360/(2*np.pi), psi * 360/(2*np.pi)]).T) - [[ nan -56.14491122] - [ -43.98001079 -51.30875902] - [ -66.46585868 -30.89801505] - [ -65.21943089 -45.94467406] - [ -64.74659263 -30.346291 ] - [ -73.13553596 -43.42456851] - [ -64.88203916 -43.25451315] - [ -59.50867772 -25.69819463] - [ -77.98930479 -8.82307681] - [ 110.78405639 8.07924448] - [ 55.24420794 -124.37141223] - [ -57.98304696 -28.76563093] - [ -81.83404402 19.12508041] - [-124.05653736 13.40120726] - [ 67.93147348 25.21773833] - [-143.95159184 131.29701851] - [ -70.10004605 160.06790798] - [ -69.48368612 145.66883187] - [ -77.26416822 124.22289316] - [ -78.10009149 nan]] + [[ nan -56.145] + [ -43.980 -51.309] + [ -66.466 -30.898] + [ -65.219 -45.945] + [ -64.747 -30.346] + [ -73.136 -43.425] + [ -64.882 -43.255] + [ -59.509 -25.698] + [ -77.989 -8.823] + [ 110.784 8.079] + [ 55.244 -124.371] + [ -57.983 -28.766] + [ -81.834 19.125] + [-124.057 13.401] + [ 67.931 25.218] + [-143.952 131.297] + [ -70.100 160.068] + [ -69.484 145.669] + [ -77.264 124.223] + [ -78.100 nan]] """ # Filter all backbone atoms bb_coord = atom_array[..., diff --git a/src/biotite/structure/hbond.py b/src/biotite/structure/hbond.py index e5977ae42..5a6efaad1 100644 --- a/src/biotite/structure/hbond.py +++ b/src/biotite/structure/hbond.py @@ -362,13 +362,9 @@ def hbond_frequency(mask): >>> triplets, mask = hbond(atom_array_stack) >>> freq = hbond_frequency(mask) >>> print(freq) - [0.26315789 0.28947368 0.10526316 0.10526316 0.23684211 0.23684211 - 0.02631579 0.05263158 0.39473684 1. 1. 1. - 0.02631579 0.42105263 0.02631579 0.02631579 0.31578947 0.81578947 - 0.02631579 0.92105263 0.02631579 0.34210526 0.02631579 0.10526316 - 0.02631579 0.13157895 0.05263158 0.02631579 0.15789474 0.02631579 - 0.86842105 0.21052632 0.02631579 0.92105263 0.31578947 0.07894737 - 0.23684211 0.10526316 0.42105263 0.07894737 0.02631579 1. - 0.05263158 0.13157895 0.02631579 0.18421053] + [0.263 0.289 0.105 0.105 0.237 0.237 0.026 0.053 0.395 1.000 1.000 1.000 + 0.026 0.421 0.026 0.026 0.316 0.816 0.026 0.921 0.026 0.342 0.026 0.105 + 0.026 0.132 0.053 0.026 0.158 0.026 0.868 0.211 0.026 0.921 0.316 0.079 + 0.237 0.105 0.421 0.079 0.026 1.000 0.053 0.132 0.026 0.184] """ return mask.sum(axis=0)/len(mask) diff --git a/src/biotite/structure/residues.py b/src/biotite/structure/residues.py index 63fb21510..41def003f 100644 --- a/src/biotite/structure/residues.py +++ b/src/biotite/structure/residues.py @@ -121,10 +121,9 @@ def apply_residue_wise(array, data, function, axis=None): >>> print(len(sasa_per_residue)) 20 >>> print(sasa_per_residue) - [157.97867 117.136475 94.98269 115.485115 113.58283 - 23.470863 93.0127 144.17316 61.561058 38.885334 - 0.79210365 114.05285 108.56837 27.887915 83.58345 - 113.01639 114.31787 74.28113 47.810623 172.03488 ] + [157.979 117.136 94.983 115.485 113.583 23.471 93.013 144.173 61.561 + 38.885 0.792 114.053 108.568 27.888 83.583 113.016 114.318 74.281 + 47.811 172.035] Calculate the centroids of each residue for the same peptide. @@ -135,26 +134,26 @@ def apply_residue_wise(array, data, function, axis=None): >>> print(len(centroids)) 20 >>> print(centroids) - [[-9.581938 3.3778126 -2.0728126 ] - [-4.6695266 5.815737 -1.8598946 ] - [-2.4608097 3.0596666 3.0760477 ] - [-7.2108426 -0.39636838 1.0131578 ] - [-4.6978235 -1.0804706 -4.284117 ] - [ 1.1721249 0.20641668 1.038375 ] - [-2.1600525 -2.2449472 3.5405266 ] - [-3.6823182 -5.5397725 -2.8952727 ] - [ 0.71108335 -5.4094167 -2.5495 ] - [ 2.0024288 -6.321715 1.6952857 ] - [ 2.7985713 -3.1399999 2.3274286 ] - [ 5.9007144 -2.4889286 4.844571 ] - [ 6.7537274 -6.7123637 3.0941818 ] - [ 5.6992726 -5.100636 -1.2091817 ] - [ 9.295427 -2.9695716 -1.8352858 ] - [ 5.517959 -1.5212501 -3.472667 ] - [ 7.218929 3.6732144 -0.6843571 ] - [ 4.006643 4.3640003 2.673857 ] - [ 0.34114286 5.575286 -0.25428572] - [ 1.194 10.416249 1.1301666 ]] + [[-9.582 3.378 -2.073] + [-4.670 5.816 -1.860] + [-2.461 3.060 3.076] + [-7.211 -0.396 1.013] + [-4.698 -1.080 -4.284] + [ 1.172 0.206 1.038] + [-2.160 -2.245 3.541] + [-3.682 -5.540 -2.895] + [ 0.711 -5.409 -2.549] + [ 2.002 -6.322 1.695] + [ 2.799 -3.140 2.327] + [ 5.901 -2.489 4.845] + [ 6.754 -6.712 3.094] + [ 5.699 -5.101 -1.209] + [ 9.295 -2.970 -1.835] + [ 5.518 -1.521 -3.473] + [ 7.219 3.673 -0.684] + [ 4.007 4.364 2.674] + [ 0.341 5.575 -0.254] + [ 1.194 10.416 1.130]] """ # The exclusive stop is appended to the residue starts starts = np.append(get_residue_starts(array), [array.array_length()])