Skip to content

Refactor RMSD analyses into MDAnalysis AnaysisBase classes#90

Open
hannahbaumann wants to merge 5 commits intomainfrom
rmsd_refactor_analysisbase
Open

Refactor RMSD analyses into MDAnalysis AnaysisBase classes#90
hannahbaumann wants to merge 5 commits intomainfrom
rmsd_refactor_analysisbase

Conversation

@hannahbaumann
Copy link
Contributor

@hannahbaumann hannahbaumann commented Feb 20, 2026

Refactor the rmsd analysis using this example: https://docs.mdanalysis.org/2.7.0/documentation_pages/analysis/base.html

  • Longer term we may not want to have the gather_rms_data function but access the individual analysis classes directly in the openfe Protocol
  • Should the make_Universe function go into utils?

@codecov
Copy link

codecov bot commented Feb 20, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.37%. Comparing base (5260e3b) to head (d824ab6).
⚠️ Report is 12 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #90      +/-   ##
==========================================
+ Coverage   88.16%   96.37%   +8.21%     
==========================================
  Files           7        6       -1     
  Lines         338      359      +21     
==========================================
+ Hits          298      346      +48     
+ Misses         40       13      -27     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@hannahbaumann
Copy link
Contributor Author

@talagayev and @jthorton : This is a first go at the refactor into the individual RMSD classes, based on the MDAnalysis AnalysisBase. Please let me know what you think!

@hannahbaumann hannahbaumann changed the title Refactor RMSD analyses into MDAnalysis AnaysisBase classes Refactor RMSD analyses into MDAnalysis AnaysisBase classes Feb 20, 2026
Comment on lines +177 to +203
class LigandRMSD(AnalysisBase):
"""
1D RMSD time series for a ligand AtomGroup.
"""

def __init__(self, atomgroup, **kwargs):
super(LigandRMSD, self).__init__(atomgroup.universe.trajectory, **kwargs)

self._ag = atomgroup

def _prepare(self):
self.results.rmsd = []
self._reference = self._ag.positions
self._weights = self._ag.masses / np.mean(self._ag.masses)

def _single_frame(self):
rmsd = rms.rmsd(
self._ag.positions,
self._reference,
self._weights,
center=False,
superposition=False,
)
self.results.rmsd.append(rmsd)

def _conclude(self):
self.results.rmsd = np.asarray(self.results.rmsd)
Copy link
Contributor

Choose a reason for hiding this comment

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

2 initial thoughts:

  • Can we make a more general RMSD class that can be reused for protein and ligand analysis, basically it should work on any atom group and does this not already exist in MDAnalysis?
  • Do we not want to switch to use the symmetry RMSD (spyrmsd I think its called)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jthorton : There's a difference between the RMSD class in MDAnalysis in what we've been doing, and I'm not sure yet what we want. In MDAnalysis, by default they are doing a superposition (rotational and translational), while we didn't do that. Now I'm not sure, what are we actually interested in, esp. for the ligand RMSD. Should this be the RMSD of the internal conformation of the ligand, or the RMSD of the ligand in the binding pocket/ligand pose? I think in the solvent we would definitely be more interested in the internal conformation of the ligand. In the binding pocket, I'm not sure. We also calculate the ligand COM displacement as a measure of stability in the pocket, but I'm not sure what we would want for the RMSD. What do you think?

Copy link
Collaborator

@talagayev talagayev left a comment

Choose a reason for hiding this comment

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

@hannahbaumann I like it, looks very good to me :) also the structure is like for the MDAnalysis AnalysisBase classes, which is I think @IAlibay wanted to have and also adressing it that it takes any atom group adressing @jthorton comment is good.

Overall Looks good to me :)

prot2d[ts_i, :, :] = prot.positions
this_protein_rmsd.append(
rms.rmsd(
prot.positions,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This means that this is the RMSD of the protein backbone. Do we also want to provide the RMSD of the whole protein?

prot_rmsd = RMSDAnalysis(prot).run(step=skip)
output["protein_RMSD"].append(prot_rmsd.results.rmsd)
# # Using the MDAnalysis RMSD class instead
# gs = ["protein and name CA", "protein"]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here is an example of how we could do the same analysis using the MDAnalysis RMSD class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants