Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

atomate2 / OpenMM OPLS-AA Enhancements #1111

Open
wants to merge 28 commits into
base: main
Choose a base branch
from

Conversation

shehan807
Copy link

@shehan807 shehan807 commented Jan 25, 2025

Summary

This PR resolves the first two enhancements proposed in Issue #1102:

  • Feature 1: Implements the correct geometric combination rules for OPLS MD simulations via opls_lj()

I've changed create_system_from_xml to create_ff_from_xml in src/atomate2/openmm/jobs/generate.py. Why? The OPLS geometric combination rules have two requirements, (1) a CustomNonbondedForce in OpenMM that combines the sigma and eps parameters geometrically, and (2) the coulomb14scale and lj14scale attributes of the ForceField are both 0.5. The latter was enough justification for raising an error if not the case--to do so, the ForceField object would need to be accessible in generate_openmm_interchange (instead of adding unsuitable arguments to create_system_from_xml). Originally, create_system_from_xml created both the ForceField and System within the same function; now, system and ff are separate variables in generate_openmm_interchange.

  • Feature 2: Allows users to create OPLS forcefield files via generate_opls_xml() via LigParGen and BOSS source code directly. To do so, users would need to follow the steps in the docs from this fork.

Currently, generate_opls_xml is only functional so long as the user has a local installation of Docker and created a private (for now, pending approval for pushing to public registries approval received to save on public registries) image of LigParGen. The documentation is provided to completion in docs/user/codes/openmm.md.

EDIT: We've received written approval from Dr. William Jorgensen to host the LigParGen image on a public registry, i.e., the user no longer has to build this themself.

Additional dependencies introduced

  • defusedxml, resolves ruff failures for safely loading XML files, e.g.,

  • textwrap, enables easier text wrapping of long warnings/errors printed for the user, e.g.,

Checklist

  • Code is in the standard Python style.
    The easiest way to handle this is to run the following in the correct sequence on
    your local machine. Start with running ruff and ruff format on your new code. This will
    automatically reformat your code to PEP8 conventions and fix many linting issues.
  • Doc strings have been added in the Numpy docstring format.
    Run ruff on your code.
  • Type annotations are highly encouraged. Run mypy to
    type check your code.
  • Tests have been added for any new functionality or bug fixes.
  • All linting and tests pass.

CC'ing @utf, @orionarcher

Shehan M Parmar and others added 14 commits January 16, 2025 14:27
…haps this is fine? and (2) usused eps14 variable (need to check that eps == eps14)
…tead; solution: comment out eps14 line to match original ligpargen code
… 14 interaction scale values (i.e., 0.5); changed create_system_from_xml to create_ff_from_xml to enable generate_openmm_interchange to have access to combination rules only available via the forcefield...still experiencing NoneType error when creating OpenMMInterchange object which prohibits inspection of OpenMMInterchange in generate_openmm_interchange
… to convert xml to string, leaving this commented for now before checking other cases
…to cutoff; incorporated diffusedxml to follow linter guidelines
… and solution was to .split() command into a list of strings
Copy link
Contributor

@orionarcher orionarcher left a comment

Choose a reason for hiding this comment

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

Couple comments but generally looks good!

import warnings
import xml.etree.ElementTree as ET
from pathlib import Path
from xml.etree.ElementTree import tostring

import defusedxml.ElementTree as DiffET
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need defusedxml in particular? Best to avoid adding a dependency if possible

Copy link
Author

@shehan807 shehan807 Mar 6, 2025

Choose a reason for hiding this comment

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

ruff gave me the following error for ET.parse,

S314 Using `xml` to parse untrusted data is known to be vulnerable to XML attacks; use `defusedxml` equivalents

I now see that # noqa: S314 was there in the original version to suppress this error, so I've updated the try/except statement, now without defusedxml. I also removed the textwrap dependency.

lj14 = gen.lj14scale

system = ff.createSystem(topology.to_openmm(), nonbondedMethod=PME)
if "opls" in tags:
Copy link
Contributor

Choose a reason for hiding this comment

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

tags should just be metadata, not core logic. You can add another mixing related kwarg as needed

Copy link
Author

Choose a reason for hiding this comment

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

Good point--I've replaced this behavior with an ff_kwargs argument to generate_openmm_interchange.

Comment on lines -26 to +35
names_smiles: dict[str, str], output_dir: str | Path, overwrite_files: bool = False
names_params: dict[str, dict[str, str]],
Copy link
Contributor

Choose a reason for hiding this comment

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

can you document what params are allowed?

Copy link
Author

Choose a reason for hiding this comment

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

Done.

@@ -19,7 +19,7 @@
from openff.units import unit


def test_create_system_from_xml(openmm_data):
def test_ff_system_from_xml(openmm_data):
Copy link
Contributor

Choose a reason for hiding this comment

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

-> test_create_ff_from_xml

@orionarcher
Copy link
Contributor

@janosh or @utf could you get the tests running here?

@shehan807 shehan807 requested a review from orionarcher March 8, 2025 20:04
@shehan807
Copy link
Author

@janosh all pre-commit/pytests are working on my end as of my last commit, could you try running the tests again? Thanks @orionarcher for the comments!

@shehan807
Copy link
Author

@janosh The last failed test is due to an environment variable dependence introduced by the generate_opls_xml function. The function requires the user to follow the OPLS docs to create a CONTAINER_SOFTWARE and LPG_IMAGE_NAME environment variable:

export LPG_IMAGE_NAME="USERNAME/ligpargen:latest"
export CONTAINER_SOFTWARE="podman-hpc" # e.g.

Based on what I've observed from the VASP/AIMS tests, I just updated test_generate_opls_xml so it monkeypatches environment variables. The new tests are now broken up into test_generate_opls_xml_no_container and test_generate_opls_xml_success. The latter is skipped since, even if the env variables were set, it would fail because success depends on whether podman-hpc or docker are available.

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.

2 participants