0
# Analysis Tools
1
2
MDAnalysis provides a comprehensive suite of analysis tools for studying molecular dynamics trajectories. These tools follow a consistent interface based on the `AnalysisBase` class and provide standardized results storage.
3
4
## Analysis Framework
5
6
### AnalysisBase Class
7
8
All analysis classes inherit from `AnalysisBase`, providing a consistent workflow:
9
10
```python { .api }
11
from MDAnalysis.analysis.base import AnalysisBase
12
13
class AnalysisBase:
14
"""
15
Base class for trajectory analysis with standardized workflow.
16
17
Provides common functionality for frame iteration, progress reporting,
18
and results storage.
19
"""
20
21
def __init__(self, trajectory, verbose=False, **kwargs):
22
"""
23
Initialize analysis base.
24
25
Parameters
26
----------
27
trajectory : Universe or AtomGroup
28
MDAnalysis Universe or AtomGroup with trajectory information.
29
verbose : bool, optional
30
Whether to show progress bar during analysis (default False).
31
**kwargs
32
Additional arguments for specific analysis.
33
"""
34
35
def run(self, start=None, stop=None, step=None, frames=None, verbose=None):
36
"""
37
Execute the analysis over specified trajectory frames.
38
39
Parameters
40
----------
41
start : int, optional
42
First frame to analyze (default None for beginning).
43
stop : int, optional
44
Last frame to analyze (default None for end).
45
step : int, optional
46
Step size for frame iteration (default None for 1).
47
frames : array-like, optional
48
Specific frame indices to analyze.
49
verbose : bool, optional
50
Override verbose setting for this run.
51
52
Returns
53
-------
54
self
55
Returns self to allow method chaining.
56
57
Examples
58
--------
59
>>> analysis = SomeAnalysis(u, selection1, selection2)
60
>>> analysis.run(start=100, stop=500, step=10)
61
>>> results = analysis.results
62
"""
63
64
def _prepare(self):
65
"""
66
Prepare analysis before trajectory iteration.
67
68
Override in subclasses to initialize data structures
69
and validate input parameters.
70
"""
71
72
def _single_frame(self):
73
"""
74
Analyze a single trajectory frame.
75
76
Override in subclasses to implement per-frame calculations.
77
This method is called for each frame during run().
78
"""
79
80
def _conclude(self):
81
"""
82
Finalize analysis after trajectory iteration.
83
84
Override in subclasses to perform post-processing
85
and populate final results.
86
"""
87
88
# Standard usage pattern
89
analysis = SomeAnalysis(universe, parameters...)
90
analysis.run()
91
results = analysis.results
92
```
93
94
### Results Storage
95
96
```python { .api }
97
from MDAnalysis.analysis.results import Results
98
99
class Results:
100
"""
101
Container for analysis results with attribute access.
102
103
Provides dictionary-like access to results with additional
104
functionality for data management.
105
"""
106
107
def __init__(self, *args, **kwargs):
108
"""
109
Create results container.
110
111
Parameters can be provided as dictionaries or keyword arguments.
112
"""
113
114
def __getattr__(self, name):
115
"""
116
Access results as attributes.
117
118
Examples
119
--------
120
>>> results.rmsd # Access RMSD array
121
>>> results.times # Access time points
122
"""
123
124
def __setattr__(self, name, value):
125
"""
126
Set result values as attributes.
127
"""
128
129
def __contains__(self, name):
130
"""
131
Check if result exists.
132
"""
133
```
134
135
## Structural Analysis
136
137
### Alignment and RMSD
138
139
```python { .api }
140
from MDAnalysis.analysis import align, rms
141
142
# Structural alignment
143
def alignto(mobile, reference, select="all", weights=None, subsetA=None,
144
subsetB=None, **kwargs):
145
"""
146
Align mobile AtomGroup to reference AtomGroup.
147
148
Parameters
149
----------
150
mobile : Universe or AtomGroup
151
Structure to be aligned (modified in place).
152
reference : Universe or AtomGroup
153
Reference structure for alignment.
154
select : str, optional
155
Selection string for atoms to use in alignment (default "all").
156
weights : str or array-like, optional
157
Weights for alignment fitting. Can be "mass" or array of weights.
158
subsetA : AtomGroup, optional
159
Specific atoms from mobile to use for fitting.
160
subsetB : AtomGroup, optional
161
Specific atoms from reference to use for fitting.
162
**kwargs
163
Additional arguments for fitting algorithm.
164
165
Returns
166
-------
167
dict
168
Dictionary containing transformation matrix and RMSD.
169
170
Examples
171
--------
172
>>> # Align protein backbone
173
>>> align.alignto(mobile_u, reference_u, select="backbone")
174
175
>>> # Mass-weighted alignment
176
>>> align.alignto(mobile_u, reference_u, select="name CA", weights="mass")
177
"""
178
179
class AlignTraj:
180
"""
181
Align trajectory to reference structure.
182
183
Performs structural alignment of each trajectory frame to a reference,
184
optionally writing aligned trajectory to file.
185
"""
186
187
def __init__(self, mobile, reference, select="all", filename=None,
188
weights=None, **kwargs):
189
"""
190
Initialize trajectory alignment.
191
192
Parameters
193
----------
194
mobile : Universe
195
Universe with trajectory to align.
196
reference : Universe or AtomGroup
197
Reference structure for alignment.
198
select : str, optional
199
Selection for alignment atoms (default "all").
200
filename : str, optional
201
Output file for aligned trajectory.
202
weights : str or array-like, optional
203
Weights for alignment ("mass" or custom weights).
204
**kwargs
205
Additional parameters.
206
207
Examples
208
--------
209
>>> aligner = align.AlignTraj(u, reference, select="backbone",
210
... filename="aligned.xtc")
211
>>> aligner.run()
212
"""
213
214
class RMSD:
215
"""
216
Calculate RMSD between trajectory and reference structure.
217
"""
218
219
def __init__(self, atomgroup, reference=None, select="all",
220
groupselections=None, **kwargs):
221
"""
222
Initialize RMSD calculation.
223
224
Parameters
225
----------
226
atomgroup : AtomGroup or Universe
227
Atoms for RMSD calculation.
228
reference : AtomGroup or Universe, optional
229
Reference structure (default first frame).
230
select : str, optional
231
Selection string for RMSD atoms (default "all").
232
groupselections : list, optional
233
List of selection strings for multiple group RMSD.
234
**kwargs
235
Additional parameters including mass weighting options.
236
237
Examples
238
--------
239
>>> R = rms.RMSD(u, select="backbone")
240
>>> R.run()
241
>>> rmsd_data = R.results.rmsd # Shape: (n_frames, 3) [frame, time, RMSD]
242
243
>>> # Multiple group RMSD
244
>>> R = rms.RMSD(u, groupselections=["backbone", "sidechain"])
245
>>> R.run()
246
>>> backbone_rmsd = R.results.rmsd[:, 2] # Backbone RMSD values
247
"""
248
249
@property
250
def results(self):
251
"""
252
RMSD results after running analysis.
253
254
Returns
255
-------
256
Results
257
Results object with rmsd attribute containing array of
258
shape (n_frames, 3 + n_groups) with columns:
259
[frame, time, rmsd_total, rmsd_group1, rmsd_group2, ...]
260
"""
261
```
262
263
### Root Mean Square Fluctuation
264
265
```python { .api }
266
class RMSF:
267
"""
268
Calculate root mean square fluctuation (RMSF) of atoms.
269
270
RMSF measures atomic positional fluctuations around average positions.
271
"""
272
273
def __init__(self, atomgroup, **kwargs):
274
"""
275
Initialize RMSF calculation.
276
277
Parameters
278
----------
279
atomgroup : AtomGroup
280
Atoms for RMSF calculation.
281
**kwargs
282
Additional parameters for analysis setup.
283
284
Examples
285
--------
286
>>> ca_atoms = u.select_atoms("name CA")
287
>>> rmsf_analysis = rms.RMSF(ca_atoms)
288
>>> rmsf_analysis.run()
289
>>> rmsf_values = rmsf_analysis.results.rmsf
290
"""
291
292
@property
293
def results(self):
294
"""
295
RMSF results after running analysis.
296
297
Returns
298
-------
299
Results
300
Results object with rmsf attribute containing per-atom
301
RMSF values in Angstrom units.
302
"""
303
```
304
305
## Distance Analysis
306
307
### Distance Calculations
308
309
```python { .api }
310
from MDAnalysis.analysis import distances
311
312
def distance_array(reference, configuration, box=None, result=None, backend="serial"):
313
"""
314
Calculate distance array between two coordinate sets.
315
316
Parameters
317
----------
318
reference : array-like
319
Reference coordinates of shape (n, 3).
320
configuration : array-like
321
Configuration coordinates of shape (m, 3).
322
box : array-like, optional
323
Unit cell dimensions for periodic boundary conditions.
324
result : numpy.ndarray, optional
325
Pre-allocated result array of shape (n, m).
326
backend : str, optional
327
Computation backend ("serial" or "OpenMP").
328
329
Returns
330
-------
331
numpy.ndarray
332
Distance array of shape (n, m) containing all pairwise distances.
333
334
Examples
335
--------
336
>>> protein_pos = protein.positions
337
>>> water_pos = waters.positions
338
>>> dist_array = distances.distance_array(protein_pos, water_pos,
339
... box=u.dimensions)
340
"""
341
342
def self_distance_array(reference, box=None, result=None, backend="serial"):
343
"""
344
Calculate self-distance array (all pairwise distances within one set).
345
346
Parameters
347
----------
348
reference : array-like
349
Coordinates of shape (n, 3).
350
box : array-like, optional
351
Unit cell dimensions for periodic boundary conditions.
352
result : numpy.ndarray, optional
353
Pre-allocated result array of shape (n, n).
354
backend : str, optional
355
Computation backend ("serial" or "OpenMP").
356
357
Returns
358
-------
359
numpy.ndarray
360
Symmetric distance matrix of shape (n, n).
361
362
Examples
363
--------
364
>>> ca_positions = ca_atoms.positions
365
>>> ca_distances = distances.self_distance_array(ca_positions,
366
... box=u.dimensions)
367
"""
368
369
def contact_matrix(coordinates, cutoff=8.0, returntype="numpy", box=None):
370
"""
371
Calculate contact matrix based on distance cutoff.
372
373
Parameters
374
----------
375
coordinates : array-like
376
Atomic coordinates of shape (n, 3).
377
cutoff : float, optional
378
Distance cutoff for contacts in Angstrom (default 8.0).
379
returntype : str, optional
380
Return type ("numpy" for dense array, "sparse" for sparse matrix).
381
box : array-like, optional
382
Unit cell dimensions.
383
384
Returns
385
-------
386
numpy.ndarray or sparse matrix
387
Contact matrix where 1 indicates contact, 0 indicates no contact.
388
389
Examples
390
--------
391
>>> contacts = distances.contact_matrix(protein.positions, cutoff=6.0)
392
>>> contact_count = np.sum(contacts)
393
"""
394
395
class InterRDF:
396
"""
397
Calculate intermolecular radial distribution function (RDF).
398
399
Computes g(r) between two atom groups, measuring probability of
400
finding atoms at distance r.
401
"""
402
403
def __init__(self, g1, g2, nbins=75, range=(0.0, 15.0), norm="rdf",
404
exclusion_block=None, **kwargs):
405
"""
406
Initialize RDF calculation.
407
408
Parameters
409
----------
410
g1 : AtomGroup
411
First atom group.
412
g2 : AtomGroup
413
Second atom group.
414
nbins : int, optional
415
Number of histogram bins (default 75).
416
range : tuple, optional
417
Distance range for RDF as (min, max) in Angstrom (default (0, 15)).
418
norm : str, optional
419
Normalization method ("rdf" or "density").
420
exclusion_block : tuple, optional
421
Exclude distances between atoms (n, m) apart in topology.
422
**kwargs
423
Additional parameters.
424
425
Examples
426
--------
427
>>> water_O = u.select_atoms("name OH2")
428
>>> protein = u.select_atoms("protein")
429
>>> rdf = distances.InterRDF(water_O, protein, range=(0, 10))
430
>>> rdf.run()
431
>>> r = rdf.results.bins # Distance bins
432
>>> gr = rdf.results.rdf # RDF values
433
"""
434
435
@property
436
def results(self):
437
"""
438
RDF results after running analysis.
439
440
Returns
441
-------
442
Results
443
Results object with:
444
- bins: distance bin centers
445
- rdf: radial distribution function g(r)
446
- count: raw histogram counts
447
"""
448
```
449
450
### Contact Analysis
451
452
```python { .api }
453
from MDAnalysis.analysis import contacts
454
455
class Contacts:
456
"""
457
Calculate contacts between two atom groups over trajectory.
458
459
Monitors formation and breaking of contacts based on distance cutoff.
460
"""
461
462
def __init__(self, selection_one, selection_two, radius=4.5,
463
method="hard_cut", **kwargs):
464
"""
465
Initialize contact analysis.
466
467
Parameters
468
----------
469
selection_one : AtomGroup
470
First group of atoms.
471
selection_two : AtomGroup
472
Second group of atoms.
473
radius : float, optional
474
Contact distance cutoff in Angstrom (default 4.5).
475
method : str, optional
476
Contact detection method ("hard_cut" or "soft_cut").
477
**kwargs
478
Additional parameters for contact detection.
479
480
Examples
481
--------
482
>>> protein = u.select_atoms("protein")
483
>>> ligand = u.select_atoms("resname LIG")
484
>>> contacts_analysis = contacts.Contacts(protein, ligand, radius=3.5)
485
>>> contacts_analysis.run()
486
>>> contact_matrix = contacts_analysis.results.contact_matrix
487
"""
488
489
@property
490
def results(self):
491
"""
492
Contact analysis results.
493
494
Returns
495
-------
496
Results
497
Results object with:
498
- contact_matrix: binary matrix indicating contacts per frame
499
- timeseries: contact time series data
500
"""
501
```
502
503
## Hydrogen Bond Analysis
504
505
### Modern Hydrogen Bond Analysis
506
507
```python { .api }
508
from MDAnalysis.analysis.hydrogenbonds import HydrogenBondAnalysis
509
510
class HydrogenBondAnalysis:
511
"""
512
Analyze hydrogen bonds in molecular dynamics trajectories.
513
514
Identifies hydrogen bonds based on geometric criteria and tracks
515
their formation/breaking over time.
516
"""
517
518
def __init__(self, universe, donors_sel=None, hydrogens_sel=None,
519
acceptors_sel=None, d_h_cutoff=1.2, d_a_cutoff=3.0,
520
d_h_a_angle_cutoff=150, **kwargs):
521
"""
522
Initialize hydrogen bond analysis.
523
524
Parameters
525
----------
526
universe : Universe
527
MDAnalysis Universe object.
528
donors_sel : str, optional
529
Selection string for hydrogen bond donor atoms.
530
hydrogens_sel : str, optional
531
Selection string for hydrogen atoms.
532
acceptors_sel : str, optional
533
Selection string for hydrogen bond acceptor atoms.
534
d_h_cutoff : float, optional
535
Maximum donor-hydrogen distance in Angstrom (default 1.2).
536
d_a_cutoff : float, optional
537
Maximum donor-acceptor distance in Angstrom (default 3.0).
538
d_h_a_angle_cutoff : float, optional
539
Minimum donor-hydrogen-acceptor angle in degrees (default 150).
540
**kwargs
541
Additional parameters.
542
543
Examples
544
--------
545
>>> # Analyze protein-water hydrogen bonds
546
>>> hbond_analysis = HydrogenBondAnalysis(
547
... universe=u,
548
... donors_sel="protein",
549
... acceptors_sel="resname SOL"
550
... )
551
>>> hbond_analysis.run()
552
>>> hbond_data = hbond_analysis.results.hbonds
553
"""
554
555
def guess_donors(self, selection="protein", max_missing=1):
556
"""
557
Automatically identify hydrogen bond donors.
558
559
Parameters
560
----------
561
selection : str, optional
562
Selection string for donor search (default "protein").
563
max_missing : int, optional
564
Maximum missing hydrogen atoms per donor (default 1).
565
566
Returns
567
-------
568
str
569
Selection string for identified donors.
570
"""
571
572
def guess_acceptors(self, selection="protein"):
573
"""
574
Automatically identify hydrogen bond acceptors.
575
576
Parameters
577
----------
578
selection : str, optional
579
Selection string for acceptor search (default "protein").
580
581
Returns
582
-------
583
str
584
Selection string for identified acceptors.
585
"""
586
587
@property
588
def results(self):
589
"""
590
Hydrogen bond analysis results.
591
592
Returns
593
-------
594
Results
595
Results object with:
596
- hbonds: array of hydrogen bond data per frame
597
- pairs: unique donor-acceptor pairs
598
- times: time points for each frame
599
"""
600
601
class WaterBridgeAnalysis:
602
"""
603
Analyze water-mediated hydrogen bonds between two selections.
604
605
Identifies hydrogen bonds where water molecules bridge interactions
606
between two molecular groups.
607
"""
608
609
def __init__(self, universe, selection1, selection2, water_selection="resname SOL",
610
order=1, **kwargs):
611
"""
612
Initialize water bridge analysis.
613
614
Parameters
615
----------
616
universe : Universe
617
MDAnalysis Universe object.
618
selection1 : str
619
First selection (e.g., "protein").
620
selection2 : str
621
Second selection (e.g., "resname LIG").
622
water_selection : str, optional
623
Selection for water molecules (default "resname SOL").
624
order : int, optional
625
Maximum number of water molecules in bridge (default 1).
626
**kwargs
627
Additional hydrogen bond criteria.
628
629
Examples
630
--------
631
>>> wb_analysis = WaterBridgeAnalysis(
632
... universe=u,
633
... selection1="protein",
634
... selection2="resname LIG",
635
... order=2 # Up to 2 water molecules
636
... )
637
>>> wb_analysis.run()
638
>>> bridges = wb_analysis.results.water_bridges
639
"""
640
```
641
642
## Principal Component Analysis
643
644
```python { .api }
645
from MDAnalysis.analysis import pca
646
647
class PCA:
648
"""
649
Principal Component Analysis of atomic coordinate fluctuations.
650
651
Performs PCA on coordinate data to identify principal modes of motion.
652
"""
653
654
def __init__(self, universe, select="all", align=False, mean=None,
655
n_components=None, **kwargs):
656
"""
657
Initialize PCA calculation.
658
659
Parameters
660
----------
661
universe : Universe or AtomGroup
662
System for PCA analysis.
663
select : str, optional
664
Selection string for atoms (default "all").
665
align : bool, optional
666
Whether to align structures before PCA (default False).
667
mean : array-like, optional
668
Pre-computed mean structure for centering.
669
n_components : int, optional
670
Number of principal components to compute.
671
**kwargs
672
Additional parameters.
673
674
Examples
675
--------
676
>>> # PCA of backbone motion
677
>>> pca_analysis = pca.PCA(u, select="backbone", align=True)
678
>>> pca_analysis.run()
679
>>> eigenvalues = pca_analysis.results.variance
680
>>> eigenvectors = pca_analysis.results.p_components
681
"""
682
683
def transform(self, atomgroup, n_components=None):
684
"""
685
Project coordinates onto principal components.
686
687
Parameters
688
----------
689
atomgroup : AtomGroup
690
Atoms to project (must match PCA selection).
691
n_components : int, optional
692
Number of components for projection.
693
694
Returns
695
-------
696
numpy.ndarray
697
Projected coordinates in PC space.
698
"""
699
700
@property
701
def results(self):
702
"""
703
PCA analysis results.
704
705
Returns
706
-------
707
Results
708
Results object with:
709
- variance: eigenvalues (variance explained by each PC)
710
- p_components: principal component vectors
711
- variance_ratio: fraction of variance explained
712
"""
713
```
714
715
## Specialized Analysis Tools
716
717
### Membrane Analysis
718
719
```python { .api }
720
from MDAnalysis.analysis import leaflet
721
722
class LeafletFinder:
723
"""
724
Identify membrane leaflets in lipid bilayer systems.
725
726
Uses phosphate positions and connectivity to determine upper
727
and lower leaflets of lipid bilayers.
728
"""
729
730
def __init__(self, universe, select="name P*", cutoff=15.0, pbc=True):
731
"""
732
Initialize leaflet identification.
733
734
Parameters
735
----------
736
universe : Universe
737
Universe containing membrane system.
738
select : str, optional
739
Selection for phosphate atoms (default "name P*").
740
cutoff : float, optional
741
Distance cutoff for leaflet assignment (default 15.0).
742
pbc : bool, optional
743
Whether to use periodic boundary conditions (default True).
744
745
Examples
746
--------
747
>>> leaflets = leaflet.LeafletFinder(u, select="name P", cutoff=12.0)
748
>>> upper_leaflet = leaflets.groups(0)
749
>>> lower_leaflet = leaflets.groups(1)
750
"""
751
752
def groups(self, leaflet_id=None):
753
"""
754
Get atoms belonging to specified leaflet.
755
756
Parameters
757
----------
758
leaflet_id : int, optional
759
Leaflet identifier. If None, returns list of all leaflets.
760
761
Returns
762
-------
763
AtomGroup or list
764
Atoms in specified leaflet or list of leaflet AtomGroups.
765
"""
766
```
767
768
### Polymer Analysis
769
770
```python { .api }
771
from MDAnalysis.analysis import polymer
772
773
class PersistenceLength:
774
"""
775
Calculate persistence length of polymer chains.
776
777
Measures the characteristic length scale over which chain
778
correlations decay exponentially.
779
"""
780
781
def __init__(self, atomgroups, **kwargs):
782
"""
783
Initialize persistence length calculation.
784
785
Parameters
786
----------
787
atomgroups : list of AtomGroup
788
List of AtomGroups representing polymer backbone atoms.
789
**kwargs
790
Additional parameters for calculation.
791
792
Examples
793
--------
794
>>> # DNA backbone analysis
795
>>> backbone_atoms = [u.select_atoms(f"segid {seg} and name P")
796
... for seg in ["DNA1", "DNA2"]]
797
>>> lp_analysis = polymer.PersistenceLength(backbone_atoms)
798
>>> lp_analysis.run()
799
>>> persistence_length = lp_analysis.results.lp
800
"""
801
```
802
803
### Mean Squared Displacement
804
805
```python { .api }
806
from MDAnalysis.analysis import msd
807
808
class MeanSquaredDisplacement:
809
"""
810
Calculate mean squared displacement for diffusion analysis.
811
812
Computes MSD as a function of lag time to analyze diffusive motion.
813
"""
814
815
def __init__(self, universe, select="all", msd_type="xyz", fft=True, **kwargs):
816
"""
817
Initialize MSD calculation.
818
819
Parameters
820
----------
821
universe : Universe
822
Universe with trajectory for MSD analysis.
823
select : str, optional
824
Selection string for atoms (default "all").
825
msd_type : str, optional
826
Type of MSD calculation ("xyz", "xy", "yz", "xz", "x", "y", "z").
827
fft : bool, optional
828
Whether to use FFT-based algorithm for efficiency (default True).
829
**kwargs
830
Additional parameters.
831
832
Examples
833
--------
834
>>> # Water diffusion analysis
835
>>> water_O = u.select_atoms("name OH2")
836
>>> msd_analysis = msd.MeanSquaredDisplacement(u, select="name OH2")
837
>>> msd_analysis.run()
838
>>> msd_data = msd_analysis.results.msd
839
>>> lag_times = msd_analysis.results.lagtimes
840
"""
841
842
@property
843
def results(self):
844
"""
845
MSD analysis results.
846
847
Returns
848
-------
849
Results
850
Results object with:
851
- msd: mean squared displacement values
852
- lagtimes: lag time values
853
"""
854
```
855
856
## Usage Patterns
857
858
### Analysis Workflow
859
860
```python { .api }
861
# Standard analysis workflow
862
def analyze_trajectory(universe, output_prefix="analysis"):
863
"""
864
Comprehensive trajectory analysis example.
865
"""
866
# Structural analysis
867
protein = universe.select_atoms("protein")
868
869
# RMSD analysis
870
rmsd_analysis = rms.RMSD(protein, select="backbone")
871
rmsd_analysis.run()
872
873
# RMSF analysis
874
ca_atoms = protein.select_atoms("name CA")
875
rmsf_analysis = rms.RMSF(ca_atoms)
876
rmsf_analysis.run()
877
878
# Hydrogen bond analysis
879
hb_analysis = HydrogenBondAnalysis(universe)
880
hb_analysis.run()
881
882
# Save results
883
np.savetxt(f"{output_prefix}_rmsd.dat", rmsd_analysis.results.rmsd)
884
np.savetxt(f"{output_prefix}_rmsf.dat", rmsf_analysis.results.rmsf)
885
886
return {
887
'rmsd': rmsd_analysis.results,
888
'rmsf': rmsf_analysis.results,
889
'hbonds': hb_analysis.results
890
}
891
892
# Run analysis
893
results = analyze_trajectory(u, "protein_analysis")
894
```
895
896
### Parallel Analysis
897
898
```python { .api }
899
# Parallel analysis using multiprocessing
900
from MDAnalysis.analysis.base import AnalysisFromFunction
901
import multiprocessing as mp
902
903
def frame_analysis(ag):
904
"""Per-frame analysis function."""
905
return {
906
'rgyr': ag.radius_of_gyration(),
907
'com': ag.center_of_mass()
908
}
909
910
# Run in parallel
911
protein = u.select_atoms("protein")
912
parallel_analysis = AnalysisFromFunction(frame_analysis, protein)
913
parallel_analysis.run(n_jobs=mp.cpu_count())
914
915
results = parallel_analysis.results
916
```