Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .github/actions/setup-deps/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ inputs:
default: 'networkx'
openmm:
default: 'openmm'
pooch:
default: 'pooch'
pytng:
default: 'pytng>=0.2.3'
rdkit:
Expand Down Expand Up @@ -145,6 +147,7 @@ runs:
${{ inputs.netcdf4 }}
${{ inputs.networkx }}
${{ inputs.openmm }}
${{ inputs.pooch }}
${{ inputs.pytng }}
${{ inputs.rdkit }}
${{ inputs.scikit-learn }}
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't know if we should be adding these - at the very least please add descriptions about what is being ignored & why like the rest of the file.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing that out!
I'll add proper descriptions explaining what is being ignored and why, to match the style used in the rest of the .gitignore file. I'll update the PR shortly.

Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,5 @@ benchmarks/results
.idea
.vscode
*.lock
venv/
package/doc/sphinx/_build/
1 change: 1 addition & 0 deletions benchmarks/benchmarks/ag_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ def time_wrap_compound(self, num_atoms):
"""
self.ag.wrap(compound="residues")


class AtomGroupAttrsBench(object):
"""Benchmarks for the various MDAnalysis
atomgroup attributes.
Expand Down
85 changes: 85 additions & 0 deletions benchmarks/benchmarks/analysis/msd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
"""
Benchmarks for the EinsteinMSD analysis module.
"""

import numpy as np
import MDAnalysis as mda
from MDAnalysis.analysis import msd
from MDAnalysis.tests.datafiles import RANDOM_WALK_TOPO, RANDOM_WALK


class EinsteinMSDCustom:
"""
Benchmark for Mean-Squared Displacement (EinsteinMSD).

The trajectory is created by using random forces
that are generated from a normal distribution
and then cumulatively summed to simulate a real random walk.
"""

unit = "ms"
description = (
"Performance of EinsteinMSD calculation using "
"custom n_atoms and range of n_frames."
)

timeout = 300.0

param_names = ["n_frames", "fft"]
params = ([100, 1000, 5000], [True, False])

def setup(self, n_frames, fft):
"""Setup method for MSD benchmark with custom number of frames."""
n_atoms = 100

rng = np.random.default_rng(42)

# Random forces are sampled from a normal distribution
steps = rng.standard_normal((n_frames, n_atoms, 3), dtype=np.float32)

# Cumulative sum is taken to simulate positions over time
res = np.cumsum(steps, axis=0)

self.u = mda.Universe.empty(n_atoms, n_frames=n_frames, trajectory=True)
self.u.trajectory.set_array(res)

def time_msd_run_custom(self, n_frames, fft):
"""
Benchmark calculation of Mean-Squared Displacement
using a custom trajectory.
"""
msd_var = msd.EinsteinMSD(self.u, select="all", fft=fft)
msd_var.run()


class EinsteinMSDExample:
"""
Benchmark for Mean-Squared Displacement (EinsteinMSD)
using the RANDOM_WALK example trajectory provided in the MDAnalysis testsuite.

The files for the trajectory can be found in the library at :
RANDOM_WALK - mdanalysis/testsuite/xyz_random_walk.xtc
RANDOM_WALK_TOPO - mdanalysis/testsuite/RANDOM_WALK_TOPO.pdb
"""

unit = "ms"
description = (
"Performance of EinsteinMSD calculation using RANDOM_WALK_TOPO and RANDOM_WALK"
)

timeout = 300.0

param_names = ["fft"]
params = [True, False]

def setup(self, fft):
"""Setup method for MSD benchmark with RANDOM_WALK example."""
self.u = mda.Universe(RANDOM_WALK_TOPO, RANDOM_WALK)

def time_msd_run_simple(self, fft):
"""
Benchmark calculation of Mean-Squared Displacement
using the example trajectory RANDOM_WALK.
"""
msd_var = msd.EinsteinMSD(self.u, fft=fft)
msd_var.run()
4 changes: 2 additions & 2 deletions benchmarks/benchmarks/analysis/rdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def time_interrdf(self, nbins, range_val, natoms):
"""
self.rdf.run()


class SimpleRdfsBench(object):
"""Benchmarks for MDAnalysis.analysis.rdf.InterRDF_s"""

Expand All @@ -61,9 +62,8 @@ def setup(self, nbins, range_val, natoms, npairs):
ags = [[self.sel, self.sel]] * npairs
self.rdf_s = InterRDF_s(self.u, ags, nbins=nbins, range=range_val)


def time_interrdfs(self, nbins, range_val, natoms, npairs):
"""Benchmark a full trajectory parse
by MDAnalysis.analysis.rdf.InterRDF_s
"""
self.rdf_s.run()
self.rdf_s.run()
4 changes: 3 additions & 1 deletion benchmarks/benchmarks/analysis/rms.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ def setup(self, num_atoms, use_weights, center, superposition):
self.u.trajectory[-1]
self.B = self.u.atoms.positions.copy()[:num_atoms]
self.atoms = self.u.atoms[:num_atoms]
self.weights = self.atoms.masses/np.sum(self.atoms.masses) if use_weights else None
self.weights = (
self.atoms.masses / np.sum(self.atoms.masses) if use_weights else None
)

def time_rmsd(self, num_atoms, weights, center, superposition):
"""Benchmark rmsd function using a setup similar to
Expand Down
6 changes: 2 additions & 4 deletions maintainer/update_json_stubs_sitemap.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,13 @@ def write_redirect(file, version="", outfile=None):
if outfile is None:
outfile = file
url = os.path.join(URL, version, file)
REDIRECT = textwrap.dedent(
f"""
REDIRECT = textwrap.dedent(f"""
<!DOCTYPE html>
<meta charset="utf-8">
<title>Redirecting to {url}</title>
<meta http-equiv="refresh" content="0; URL={url}">
<link rel="canonical" href="{url}">
"""
)
""")
with open(outfile, "w") as f:
f.write(REDIRECT)
print(f"Wrote redirect from {url} to {outfile}")
Expand Down
2 changes: 2 additions & 0 deletions package/AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ Chronological list of authors
- Kushagar Garg
- Jeremy M. G. Leung
- Harshit Gajjela
- Kunj Sinha
- Ayush Agarwal

External code
-------------
Expand Down
7 changes: 6 additions & 1 deletion package/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ The rules for this file:
-------------------------------------------------------------------------------
??/??/?? IAlibay, orbeckst, marinegor, tylerjereddy, ljwoods2, marinegor,
spyke7, talagayev, tanii1125, BradyAJohnston, hejamu, jeremyleung521,
harshitgajjela-droid
harshitgajjela-droid, kunjsinha, aygarwal, jauy123

* 2.11.0

Fixes
* Fixes TypeError with np.int64 indexing in GSD Reader (Issue #5224)
* Fixed bug in add_transformations allowing non-callable transformations
(Issue #2558, PR #2558)
* Drop/Replace lock file test in test_xdr (Issue #5236, PR #5237)
Expand All @@ -41,6 +42,10 @@ Fixes
DSSP by porting upstream PyDSSP 0.9.1 fix (Issue #4913)

Enhancements
* Added new top-level `MDAnalysis.fetch` module (PR #4943)
* Added new function `MDAnalysis.fetch.from_PDB` to download structure files from wwPDB
using `pooch` as optional dependency (Issue #4907, PR #4943)
* Added benchmarks for package.MDAnalysis.analysis.msd.EinsteinMSD (PR #5277)
* Improved performance of `AtomGroup.wrap()` with compounds (PR #5220)
* Adds support for parsing `.tpr` files produced by GROMACS 2026.0
* Enables parallelization for analysis.diffusionmap.DistanceMatrix
Expand Down
17 changes: 6 additions & 11 deletions package/MDAnalysis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@
When using MDAnalysis in published work, please cite

R. J. Gowers, M. Linke, J. Barnoud, T. J. E. Reddy, M. N. Melo, S. L. Seyler,
D. L. Dotson, J. Domanski, S. Buchoux, I. M. Kenney, and O. Beckstein.
MDAnalysis: A Python package for the rapid analysis of molecular dynamics
simulations. In S. Benthall and S. Rostrup, editors, Proceedings of the 15th
Python in Science Conference, pages 98-105, Austin, TX, 2016. SciPy,
D. L. Dotson, J. Domanski, S. Buchoux, I. M. Kenney, and O. Beckstein.
MDAnalysis: A Python package for the rapid analysis of molecular dynamics
simulations. In S. Benthall and S. Rostrup, editors, Proceedings of the 15th
Python in Science Conference, pages 98-105, Austin, TX, 2016. SciPy,
doi:10.25080/majora-629e541a-00e

N. Michaud-Agrawal, E. J. Denning, T. B. Woolf, and
Expand Down Expand Up @@ -156,7 +156,6 @@
import warnings
from typing import Dict


logger = logging.getLogger("MDAnalysis.__init__")

from .version import __version__
Expand All @@ -179,9 +178,7 @@
_CONVERTERS: Dict = {}
# Registry of TopologyAttributes
_TOPOLOGY_ATTRS: Dict = {} # {attrname: cls}
_TOPOLOGY_TRANSPLANTS: Dict = (
{}
) # {name: [attrname, method, transplant class]}
_TOPOLOGY_TRANSPLANTS: Dict = {} # {name: [attrname, method, transplant class]}
_TOPOLOGY_ATTRNAMES: Dict = {} # {lower case name w/o _ : name}
_GUESSERS: Dict = {}

Expand All @@ -204,9 +201,7 @@
del logging

# only MDAnalysis DeprecationWarnings are loud by default
warnings.filterwarnings(
action="once", category=DeprecationWarning, module="MDAnalysis"
)
warnings.filterwarnings(action="once", category=DeprecationWarning, module="MDAnalysis")


from . import units
Expand Down
44 changes: 13 additions & 31 deletions package/MDAnalysis/analysis/align.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
rotational superposition use the superposition keyword. This will calculate a
minimized RMSD between the reference and mobile structure::

>>> rmsd(mobile.select_atoms('name CA').positions, ref.select_atoms('name CA').positions,
>>> rmsd(mobile.select_atoms('name CA').positions, ref.select_atoms('name CA').positions,
... superposition=True)
6.809396586471815

Expand Down Expand Up @@ -138,7 +138,7 @@
>>> trj = mda.Universe(PSF, DCD) # trajectory of change 1AKE->4AKE
>>> alignment = align.AlignTraj(trj, ref, filename='rmsfit.dcd')
>>> alignment.run()
<MDAnalysis.analysis.align.AlignTraj object at ...>
<MDAnalysis.analysis.align.AlignTraj object at ...>

It is also possible to align two arbitrary structures by providing a
mapping between atoms based on a sequence alignment. This allows
Expand Down Expand Up @@ -190,6 +190,7 @@
.. autofunction:: get_matching_atoms

"""

import os.path
import warnings
import logging
Expand Down Expand Up @@ -361,9 +362,7 @@ def _fit_to(
where :math:`\bar{X}` is the center.

"""
R, min_rmsd = rotation_matrix(
mobile_coordinates, ref_coordinates, weights=weights
)
R, min_rmsd = rotation_matrix(mobile_coordinates, ref_coordinates, weights=weights)

mobile_atoms.translate(-mobile_com)
mobile_atoms.rotate(R)
Expand Down Expand Up @@ -845,8 +844,7 @@ def __init__(

if os.path.exists(filename) and not force:
raise IOError(
"Filename already exists in path and force is not set"
" to True"
"Filename already exists in path and force is not set" " to True"
)

# do this after setting the memory reader to have a reference to the
Expand Down Expand Up @@ -1092,9 +1090,7 @@ def __init__(
)
logger.exception(err)
raise SelectionError(err)
logger.info(
"RMS calculation " "for {0:d} atoms.".format(len(self.ref_atoms))
)
logger.info("RMS calculation " "for {0:d} atoms.".format(len(self.ref_atoms)))

# store reference to mobile atoms
self.mobile = mobile.atoms
Expand Down Expand Up @@ -1155,9 +1151,7 @@ def _single_frame(self):
def _conclude(self):
self.results.positions /= self.n_frames
self.results.rmsd /= self.n_frames
self.results.universe.load_new(
self.results.positions.reshape((1, -1, 3))
)
self.results.universe.load_new(self.results.positions.reshape((1, -1, 3)))
self._writer.write(self.results.universe.atoms)
self._writer.close()
if not self._verbose:
Expand Down Expand Up @@ -1465,26 +1459,18 @@ def fasta2select(
stdout, stderr = run_clustalw()
except:
logger.exception("ClustalW %(clustalw)r failed", vars())
logger.info(
"(You can get clustalw2 from http://www.clustal.org/clustal2/)"
)
logger.info("(You can get clustalw2 from http://www.clustal.org/clustal2/)")
raise
with open(alnfilename) as aln:
alignment = Bio.AlignIO.read(aln, "clustal")
logger.info("Using clustalw sequence alignment {0!r}".format(alnfilename))
logger.info(
"Using clustalw sequence alignment {0!r}".format(alnfilename)
)
logger.info(
"ClustalW Newick guide tree was also produced: {0!r}".format(
treefilename
)
"ClustalW Newick guide tree was also produced: {0!r}".format(treefilename)
)

nseq = len(alignment)
if nseq != 2:
raise ValueError(
"Only two sequences in the alignment can be processed."
)
raise ValueError("Only two sequences in the alignment can be processed.")

# implict assertion that we only have two sequences in the alignment
orig_resids = [ref_resids, target_resids]
Expand All @@ -1500,9 +1486,7 @@ def fasta2select(
else:
orig_resids[iseq] = np.asarray(orig_resids[iseq])
# add offsets to the sequence <--> resid translation table
seq2resids = [
resids + offset for resids, offset in zip(orig_resids, offsets)
]
seq2resids = [resids + offset for resids, offset in zip(orig_resids, offsets)]
del orig_resids
del offsets

Expand Down Expand Up @@ -1773,9 +1757,7 @@ def get_atoms_byres(g, match_mask=None):
warnings.warn(msg, category=SelectionWarning)
else:
try:
mass_mismatches = (
np.absolute(ag1.masses - ag2.masses) > tol_mass
)
mass_mismatches = np.absolute(ag1.masses - ag2.masses) > tol_mass
except ValueError:
errmsg = (
"Failed to find matching atoms: len(reference) = {}, len(mobile) = {} "
Expand Down
8 changes: 2 additions & 6 deletions package/MDAnalysis/analysis/atomicdistances.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,16 +150,12 @@ class AtomicDistances(AnalysisBase):
def __init__(self, ag1, ag2, pbc=True, **kwargs):
# check ag1 and ag2 have the same number of atoms
if ag1.atoms.n_atoms != ag2.atoms.n_atoms:
raise ValueError(
"AtomGroups do not " "have the same number of atoms"
)
raise ValueError("AtomGroups do not " "have the same number of atoms")
# check ag1 and ag2 are from the same trajectory
elif ag1.universe.trajectory != ag2.universe.trajectory:
raise ValueError("AtomGroups are not " "from the same trajectory")

super(AtomicDistances, self).__init__(
ag1.universe.trajectory, **kwargs
)
super(AtomicDistances, self).__init__(ag1.universe.trajectory, **kwargs)

self._ag1 = ag1
self._ag2 = ag2
Expand Down
Loading