Skip to content

Commit 09a9f60

Browse files
Echo FiaEcho Fia
Echo Fia
authored and
Echo Fia
committed
Fixed pytest and Centre of Mass for issue MDAnalysis#3603
1 parent 86462f8 commit 09a9f60

File tree

1 file changed

+98
-99
lines changed

1 file changed

+98
-99
lines changed

Diff for: testsuite/MDAnalysisTests/analysis/test_lineardensity.py

+98-99
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,25 @@
1+
# -*- Mode: python; tab-width: 4; indent-tabs-mode:nil; coding:utf-8 -*-
2+
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 fileencoding=utf-8
3+
#
4+
# MDAnalysis --- https://www.mdanalysis.org
5+
# Copyright (c) 2006-2017 The MDAnalysis Development Team and contributors
6+
# (see the file AUTHORS for the full list of names)
7+
#
8+
# Released under the Lesser GNU Public Licence, v2.1 or any higher version
9+
#
10+
# Please cite your use of MDAnalysis in published work:
11+
#
12+
# R. J. Gowers, M. Linke, J. Barnoud, T. J. E. Reddy, M. N. Melo, S. L. Seyler,
13+
# D. L. Dotson, J. Domanski, S. Buchoux, I. M. Kenney, and O. Beckstein.
14+
# MDAnalysis: A Python package for the rapid analysis of molecular dynamics
15+
# simulations. In S. Benthall and S. Rostrup editors, Proceedings of the 15th
16+
# Python in Science Conference, pages 102-109, Austin, TX, 2016. SciPy.
17+
# doi: 10.25080/majora-629e541a-00e
18+
#
19+
# N. Michaud-Agrawal, E. J. Denning, T. B. Woolf, and O. Beckstein.
20+
# MDAnalysis: A Toolkit for the Analysis of Molecular Dynamics Simulations.
21+
# J. Comput. Chem. 32 (2011), 2319--2327, doi:10.1002/jcc.21787
22+
#
123
import MDAnalysis as mda
224
import numpy as np
325
import pytest
@@ -8,9 +30,11 @@
830
from numpy.testing import assert_allclose
931
from MDAnalysis.core._get_readers import get_reader_for
1032
from MDAnalysisTests.util import no_deprecated_call
33+
1134
from MDAnalysis.units import constants
1235

1336

37+
1438
def test_invalid_grouping():
1539
"""Invalid groupings raise AttributeError"""
1640
universe = mda.Universe(waterPSF, waterDCD)
@@ -21,26 +45,6 @@ def test_invalid_grouping():
2145
ld = LinearDensity(selection, grouping="centroid", binsize=5)
2246
ld.run()
2347

24-
### Initialising Variables ###
25-
26-
expected_masses_atoms = None
27-
expected_charges_atoms = None
28-
expected_xmass_atoms = None
29-
expected_xcharge_atoms = None
30-
31-
expected_masses_residues = None
32-
expected_charges_residues = None
33-
expected_xmass_residues = None
34-
expected_xcharge_residues = None
35-
36-
expected_masses_segments = None
37-
expected_charges_segments = None
38-
expected_xmass_segments = None
39-
expected_xcharge_segments = None
40-
41-
'''
42-
FRAGMENTS!!!! Can't find the documentation for Fragment
43-
'''
4448

4549
### Creating the Test Universes ###
4650

@@ -52,8 +56,8 @@ def make_Universe(coords, charges, masses, n_atoms, n_frames, atomsPerRes, resPe
5256
n_segments = n_residues // resPerSegs # Arbitrarily 4 residues per segment
5357

5458
# Indexing atoms into residues & residues into segments
55-
atom_resindex = np.array([[i] * (n_atoms // n_residues) for i in range(n_residues)]).flatten()
56-
residue_segindex=np.array([[i] * (n_residues // n_segments) for i in range(n_segments)]).flatten()
59+
atom_resindex = np.repeat(np.arange(n_residues), atomsPerRes)
60+
residue_segindex = np.repeat(np.arange(n_segments), resPerSegs)
5761

5862
# Creating the universe
5963
u = mda.Universe.empty(n_atoms=n_atoms,
@@ -75,6 +79,14 @@ def make_Universe(coords, charges, masses, n_atoms, n_frames, atomsPerRes, resPe
7579

7680
return u
7781

82+
83+
### Defining the Systems ###
84+
85+
# The masses are all set to 1
86+
# The charges are dependent on each system
87+
# The positions are randomly taken from a uniform distribution between 0 and 1
88+
# NOTE: The positions at each time frame are independent on the previous time step
89+
7890
def neutral_Particles(n_atoms, n_frames, atomsPerRes, resPerSegs):
7991
charges = np.zeros(n_atoms)
8092
masses = np.ones(n_atoms)
@@ -99,7 +111,6 @@ def charged_Dimers(n_dimers, n_frames, dimersPerRes, resPerSegs, dimerLength = 0
99111
charges = np.random.random(n_atoms) * 2 - np.ones(n_atoms) # Between -1 and 1
100112
masses = np.ones(n_atoms)
101113

102-
# Setting each position to be random for each timestep (independent of previous timestep)
103114
shape = (n_frames, n_dimers, 3)
104115
coords = np.random.random(shape) * 0.9 + np.ones(shape) * 0.05
105116
# Puts in the same coordinate twice per dimer
@@ -116,6 +127,7 @@ def charged_Dimers(n_dimers, n_frames, dimersPerRes, resPerSegs, dimerLength = 0
116127

117128
return make_Universe(coords, charges, masses, n_atoms, n_frames, dimersPerRes * 2, resPerSegs)
118129

130+
119131
### Calculating the Expected Values ###
120132

121133
def calc_Prop(u, prop = 'masses'): # Property can be 'masses' or 'charges'
@@ -125,15 +137,14 @@ def calc_Prop(u, prop = 'masses'): # Property can be 'masses' or 'charges'
125137

126138
return expected_atoms, expected_residues, expected_segments
127139

128-
def find_Centres(groups, prop):
140+
def find_Centres(groups): # Always based on Centre of Mass (NOT Centre of Charge)
129141
centres = []
130142
for group in groups:
131-
# NOTE: Absolute is taken for charges
132-
total_Prop = sum(abs(eval(f'group.atoms.{prop}')))
133-
if total_Prop != 0:
134-
centres.append(np.sum(group.atoms.positions.transpose() * abs(eval(f'group.atoms.{prop}')), axis = 1) / total_Prop)
135-
elif total_Prop == 0:
136-
centres.append(np.sum(group.atoms.positions.transpose() * abs(eval(f'group.atoms.{prop}')), axis = 1) / len(group.atoms))
143+
total_Mass = sum(group.atoms.masses)
144+
if total_Mass != 0:
145+
centres.append(np.sum(group.atoms.positions.transpose() * abs(group.atoms.masses), axis = 1) / total_Mass)
146+
elif total_Mass == 0:
147+
centres.append(np.sum(group.atoms.positions.transpose() * abs(group.atoms.masses), axis = 1) / len(group.atoms)) ############## NOT NEDEDEDDED
137148

138149
return np.array(centres)
139150

@@ -153,7 +164,7 @@ def calc_Densities(u, prop = 'masses', spliceLen = 0.25): # Property can be 'mas
153164
_,residue_Totals,segment_Totals = calc_Prop(u, prop) # Total of Charge OR Mass
154165
### Residues
155166
expected_residues = np.zeros((3, int(u.dimensions[0] // spliceLen))).astype(float)
156-
residue_Centres = find_Centres(u.residues, prop = prop)
167+
residue_Centres = find_Centres(u.residues)
157168

158169

159170
for i in range(len(residue_Centres)):
@@ -162,15 +173,14 @@ def calc_Densities(u, prop = 'masses', spliceLen = 0.25): # Property can be 'mas
162173

163174
### Segments
164175
expected_segments = np.zeros((3, int(u.dimensions[0] // spliceLen))).astype(float)
165-
segment_Centres = find_Centres(u.segments, prop = prop)
176+
segment_Centres = find_Centres(u.segments)
166177

167178

168179
for i in range(len(segment_Centres)):
169180
for j in range(3):
170181
expected_segments[j][int(segment_Centres[i][j] // spliceLen)] += segment_Totals[i]
171182

172183

173-
174184
# Scaling based on splice volumes & converting units
175185
for i in range(3):
176186
expected_atoms[i,:] /= spliceLen * u.dimensions[(i + 1) % 3] * u.dimensions[(i + 2) % 3]
@@ -181,84 +191,72 @@ def calc_Densities(u, prop = 'masses', spliceLen = 0.25): # Property can be 'mas
181191
expected_segments /= constants['N_Avogadro'] * 1e-24 # To be consistent with lineardensity.py
182192

183193
return expected_atoms, expected_residues, expected_segments
184-
185194

195+
### Creating the Expected Values ###
196+
197+
spliceLen = 0.25
198+
199+
universes = []
200+
groupings = ['atoms', 'residues', 'segments']
201+
# Will be [[Atoms, Residues, Segments (of Universe 1)], [... of Universe 2], ...]
202+
expected_masses = []
203+
expected_charges = []
204+
expected_xmass = []
205+
expected_xcharge = []
186206

187-
####
207+
for system in test_Systems:
188208

209+
universe = eval(f'{system}(100, 1, 5, 4)')
210+
universes.append(universe)
189211

212+
## expected_masses_atoms, expected_masses_residues, expected_masses_segments = calc_Prop(universe, 'masses')
213+
## expected_charges_atoms, expected_charges_residues, expected_charges_segments = calc_Prop(universe, 'charges')
214+
## expected_xmass_atoms, expected_xmass_residues, expected_xmass_segments = calc_Densities(universe, 'masses', spliceLen)
215+
## expected_xcharge_atoms, expected_xcharge_residues, expected_xcharge_segments = calc_Densities(universe, 'charges', spliceLen)
216+
217+
expected_masses.append(calc_Prop(universe, 'masses'))
218+
expected_charges.append(calc_Prop(universe, 'charges'))
219+
expected_xmass.append(calc_Densities(universe, 'masses', spliceLen))
220+
expected_xcharge.append(calc_Densities(universe, 'charges', spliceLen))
221+
222+
### Parametrizing for Pytest ###
223+
224+
# NOTE: There is an extra [0] after the expected_xmass and expected_xcharge as the original data has all 3 co-ords, but only comparing to x here
225+
params = [(universes[i], groupings[j], expected_masses[i][j], expected_charges[i][j], expected_xmass[i][j][0], expected_xcharge[i][j][0]) for j in range(len(groupings)) for i in range(len(universes))]
190226
@pytest.mark.parametrize(
191-
"grouping, expected_masses, expected_charges, expected_xmass, expected_xcharge",
192-
[
193-
(
194-
"atoms",
195-
expected_masses_atoms,
196-
expected_charges_atoms,
197-
expected_xmass_atoms,
198-
expected_xcharge_atoms,
199-
),
200-
(
201-
"residues",
202-
expected_masses_residues,
203-
expected_charges_residues,
204-
expected_xmass_residues,
205-
expected_xcharge_residues,
206-
),
207-
(
208-
"segments",
209-
expected_masses_segments,
210-
expected_charges_segments,
211-
expected_xmass_segments,
212-
expected_xcharge_segments,
213-
),
214-
## (
215-
## "fragments",
216-
## expected_masses_fragments,
217-
## expected_charges_fragments,
218-
## expected_xmass_fragments,
219-
## expected_xcharge_fragments,
220-
## ),
221-
],
227+
"universe, grouping, expected_masses, expected_charges, expected_xmass, expected_xcharge",
228+
params,
222229
)
223230

224231
def test_lineardensity(
225-
## universe,
232+
universe,
226233
grouping,
227-
## expected_masses,
228-
## expected_charges,
229-
## expected_xmass,
230-
## expected_xcharge,
234+
expected_masses,
235+
expected_charges,
236+
expected_xmass,
237+
expected_xcharge,
231238
):
239+
sel_string = "all"
240+
selection = universe.select_atoms(sel_string)
241+
ld = LinearDensity(selection, grouping, binsize=0.25).run()
242+
assert_allclose(ld.masses, expected_masses)
243+
assert_allclose(ld.charges, expected_charges)
244+
# rtol changed here due to floating point imprecision
245+
assert_allclose(ld.results.x.mass_density, expected_xmass, rtol=1e-06)
246+
assert_allclose(ld.results.x.charge_density, expected_xcharge)
232247

233-
spliceLen = 0.25
234-
for system in test_Systems:
235-
universe = eval(f'{system}(100, 1, 1, 1)')
236-
237-
expected_masses_atoms, expected_masses_residues, expected_masses_segments = calc_Prop(universe, 'masses')
238-
expected_charges_atoms, expected_charges_residues, expected_charges_segments = calc_Prop(universe, 'charges')
239-
expected_xmass_atoms, expected_xmass_residues, expected_xmass_segments = calc_Densities(universe, 'masses', spliceLen)
240-
expected_xcharge_atoms, expected_xcharge_residues, expected_xcharge_segments = calc_Densities(universe, 'charges', spliceLen)
241-
242-
if grouping == 'atoms':
243-
expected_masses, expected_charges, expected_xmass, expected_xcharge = expected_masses_atoms, expected_charges_atoms, expected_xmass_atoms, expected_xcharge_atoms
244-
245-
elif grouping == 'residues':
246-
expected_masses, expected_charges, expected_xmass, expected_xcharge = expected_masses_residues, expected_charges_residues, expected_xmass_residues, expected_xcharge_residues
247-
248-
elif grouping == 'segments':
249-
expected_masses, expected_charges, expected_xmass, expected_xcharge = expected_masses_segments, expected_charges_segments, expected_xmass_segments, expected_xcharge_segments
250-
251-
252-
sel_string = "all"
253-
selection = universe.select_atoms(sel_string)
254-
ld = LinearDensity(selection, grouping, binsize=spliceLen).run()
255-
assert_allclose(ld.masses, expected_masses)
256-
assert_allclose(ld.charges, expected_charges)
257-
# rtol changed here due to floating point imprecision
258-
assert_allclose(ld.results.x.mass_density, expected_xmass[0], rtol=1e-06)
259-
assert_allclose(ld.results.x.charge_density, expected_xcharge[0])
260248

261-
##test_lineardensity('atoms')
249+
for i in range(len(params)):
250+
print(i)
251+
universe = params[i][0]
252+
sel_string = "all"
253+
selection = universe.select_atoms(sel_string)
254+
ld = LinearDensity(selection, params[i][1], binsize=0.25).run()
255+
assert_allclose(ld.masses, params[i][2])
256+
assert_allclose(ld.charges, params[i][3])
257+
# rtol changed here due to floating point imprecision
258+
assert_allclose(ld.results.x.mass_density, params[i][4], rtol=1e-06)
259+
assert_allclose(ld.results.x.charge_density, params[i][5])
262260

263261

264262
@pytest.fixture(scope="module")
@@ -362,3 +360,4 @@ def test_parallel_analysis(testing_Universe):
362360
assert_allclose(
363361
ld1.results.x.mass_density, ld_whole.results.x.mass_density
364362
)
363+

0 commit comments

Comments
 (0)