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
+ #
1
23
import MDAnalysis as mda
2
24
import numpy as np
3
25
import pytest
8
30
from numpy .testing import assert_allclose
9
31
from MDAnalysis .core ._get_readers import get_reader_for
10
32
from MDAnalysisTests .util import no_deprecated_call
33
+
11
34
from MDAnalysis .units import constants
12
35
13
36
37
+
14
38
def test_invalid_grouping ():
15
39
"""Invalid groupings raise AttributeError"""
16
40
universe = mda .Universe (waterPSF , waterDCD )
@@ -21,26 +45,6 @@ def test_invalid_grouping():
21
45
ld = LinearDensity (selection , grouping = "centroid" , binsize = 5 )
22
46
ld .run ()
23
47
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
- '''
44
48
45
49
### Creating the Test Universes ###
46
50
@@ -52,8 +56,8 @@ def make_Universe(coords, charges, masses, n_atoms, n_frames, atomsPerRes, resPe
52
56
n_segments = n_residues // resPerSegs # Arbitrarily 4 residues per segment
53
57
54
58
# 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 )
57
61
58
62
# Creating the universe
59
63
u = mda .Universe .empty (n_atoms = n_atoms ,
@@ -75,6 +79,14 @@ def make_Universe(coords, charges, masses, n_atoms, n_frames, atomsPerRes, resPe
75
79
76
80
return u
77
81
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
+
78
90
def neutral_Particles (n_atoms , n_frames , atomsPerRes , resPerSegs ):
79
91
charges = np .zeros (n_atoms )
80
92
masses = np .ones (n_atoms )
@@ -99,7 +111,6 @@ def charged_Dimers(n_dimers, n_frames, dimersPerRes, resPerSegs, dimerLength = 0
99
111
charges = np .random .random (n_atoms ) * 2 - np .ones (n_atoms ) # Between -1 and 1
100
112
masses = np .ones (n_atoms )
101
113
102
- # Setting each position to be random for each timestep (independent of previous timestep)
103
114
shape = (n_frames , n_dimers , 3 )
104
115
coords = np .random .random (shape ) * 0.9 + np .ones (shape ) * 0.05
105
116
# Puts in the same coordinate twice per dimer
@@ -116,6 +127,7 @@ def charged_Dimers(n_dimers, n_frames, dimersPerRes, resPerSegs, dimerLength = 0
116
127
117
128
return make_Universe (coords , charges , masses , n_atoms , n_frames , dimersPerRes * 2 , resPerSegs )
118
129
130
+
119
131
### Calculating the Expected Values ###
120
132
121
133
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'
125
137
126
138
return expected_atoms , expected_residues , expected_segments
127
139
128
- def find_Centres (groups , prop ):
140
+ def find_Centres (groups ): # Always based on Centre of Mass (NOT Centre of Charge)
129
141
centres = []
130
142
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
137
148
138
149
return np .array (centres )
139
150
@@ -153,7 +164,7 @@ def calc_Densities(u, prop = 'masses', spliceLen = 0.25): # Property can be 'mas
153
164
_ ,residue_Totals ,segment_Totals = calc_Prop (u , prop ) # Total of Charge OR Mass
154
165
### Residues
155
166
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 )
157
168
158
169
159
170
for i in range (len (residue_Centres )):
@@ -162,15 +173,14 @@ def calc_Densities(u, prop = 'masses', spliceLen = 0.25): # Property can be 'mas
162
173
163
174
### Segments
164
175
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 )
166
177
167
178
168
179
for i in range (len (segment_Centres )):
169
180
for j in range (3 ):
170
181
expected_segments [j ][int (segment_Centres [i ][j ] // spliceLen )] += segment_Totals [i ]
171
182
172
183
173
-
174
184
# Scaling based on splice volumes & converting units
175
185
for i in range (3 ):
176
186
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
181
191
expected_segments /= constants ['N_Avogadro' ] * 1e-24 # To be consistent with lineardensity.py
182
192
183
193
return expected_atoms , expected_residues , expected_segments
184
-
185
194
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 = []
186
206
187
- ####
207
+ for system in test_Systems :
188
208
209
+ universe = eval (f'{ system } (100, 1, 5, 4)' )
210
+ universes .append (universe )
189
211
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 ))]
190
226
@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 ,
222
229
)
223
230
224
231
def test_lineardensity (
225
- ## universe,
232
+ universe ,
226
233
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 ,
231
238
):
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 )
232
247
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 ])
260
248
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 ])
262
260
263
261
264
262
@pytest .fixture (scope = "module" )
@@ -362,3 +360,4 @@ def test_parallel_analysis(testing_Universe):
362
360
assert_allclose (
363
361
ld1 .results .x .mass_density , ld_whole .results .x .mass_density
364
362
)
363
+
0 commit comments