Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
c25b56b
Update Sire version.
lohedges Feb 5, 2025
c649536
Upgrade to Black 25.
lohedges Feb 5, 2025
a24e3a8
Allow user to force stereo inference. [ref OpenBioSim/sire#287]
lohedges Feb 10, 2025
a97cc19
Need to wrap boolean property map option.
lohedges Feb 12, 2025
b12baa4
Merge pull request #388 from OpenBioSim/fix_sire_287
lohedges Feb 12, 2025
8a323fc
Update Exscientia Sandpit SOMD config settings
Feb 12, 2025
de6629c
Merge pull request #390 from fjclark/devel
lohedges Feb 13, 2025
5c05464
Make formal charge calculation more robust. [closes #392]
lohedges Feb 17, 2025
a8185e3
Always try both PDB and SDF format, i.e. only the order changes.
lohedges Feb 18, 2025
faee4ff
Blacken.
lohedges Feb 18, 2025
5fec8d7
Add unit test for fallback for failed formal charge calculation.
lohedges Feb 18, 2025
974cdd1
Merge pull request #393 from OpenBioSim/fix_392
lohedges Feb 19, 2025
f56b6bc
Add support for ff19SB.
lohedges Mar 14, 2025
b1cb6ba
Fix for issue #397, also adds utility function to get name of node di…
Mar 21, 2025
bba6729
Allow Gromacs Process to store density information (#7)
xiki-tempula Feb 21, 2025
08e514b
Hang killer (#8)
xiki-tempula Apr 9, 2025
d32e415
Allow pert file without modifications to dummy bonded terms.
lohedges May 27, 2025
75e9549
Remove AnteChamber check. No version is reported for AmberTools 24.
lohedges May 28, 2025
de9db8a
Skip test until we can get version info or work out reason for failure.
lohedges May 28, 2025
8ba863f
Merge pull request #400 from OpenBioSim/sync_recursion2
lohedges May 28, 2025
e2dcacf
Merge branch 'devel' into feature_no_ghost_mods
lohedges May 28, 2025
41534e6
Fix for is_lambda1 in Somd1 processes
May 30, 2025
6c63b6d
Add link to survey. [ci skip]
lohedges May 30, 2025
9ed2d1f
Highlight survey. [ci skip]
lohedges May 30, 2025
db03a53
Import proper errors in somd config
Jun 2, 2025
5d748ce
Typo. [ci skip]
lohedges Jun 2, 2025
44eeb7c
Amber config typo fix [ci skip]
Jun 3, 2025
580c91b
Fix for AMBER runs on perturbable systems with restraints
Jun 3, 2025
8fe807a
Fix for previous commit - removes old file save [ci skip]
Jun 3, 2025
82877ed
Return unsquashed system from getFrame(). [closes #402]
lohedges Jun 11, 2025
40c588c
Merge pull request #403 from OpenBioSim/fix_402
lohedges Jun 12, 2025
baad606
Move sandpit test file to the correct path. [ci skip]
lohedges Jun 12, 2025
754d7f0
Return full data frame, not just lambda array.
lohedges Jun 13, 2025
93fc038
Parquet lambda_array metadata is no longer needed.
lohedges Jun 13, 2025
5ce173b
Merge branch 'devel' into feature_ff19sb
lohedges Jun 20, 2025
e4abd56
Merge branch 'devel' into feature_no_ghost_mods
lohedges Jun 20, 2025
2e5f4fa
Test that we can parameterise with ff19SB, which includes CMAP terms.
lohedges Jun 20, 2025
71145d4
Simplify finite difference calculation. [ci skip]
lohedges Jun 21, 2025
e657eab
Add support for OPC water model. [ci skip]
lohedges Jun 25, 2025
59b512f
Don't duplicate the defaults directive. [ci skip]
lohedges Jun 25, 2025
10187b3
Allow user to disable data preprocessing.
lohedges Jun 26, 2025
98b26d3
Distinguish OPC and TIP4P water. [ci skip]
lohedges Jun 26, 2025
e6af7ab
Merge remote-tracking branch 'origin/fix_397' into feature_ff19sb
lohedges Jun 27, 2025
9ad668c
Allow node to be run in a specified working directory.
lohedges Jun 27, 2025
eb9ff4a
Merge branch 'feature_no_ghost_mods' into feature_ff19sb
lohedges Jun 30, 2025
88b02bc
Merge branch 'feature_focused_sampling' into feature_ff19sb
lohedges Jun 30, 2025
5b0c565
Handle different boolean property types.
lohedges Jun 30, 2025
f9e890f
Merge pull request #406 from OpenBioSim/feature_ff19sb
lohedges Jun 30, 2025
1050a69
Merge branch 'main' into release_2025.1.0
lohedges Jul 1, 2025
bf3f5b0
Update CHANGELOG for the 2025.1.0 release.
lohedges Jul 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@
:target: https://joss.theoj.org/papers/4ba84ad443693b5dded90e35bf5f8225
:alt: Paper

Survey
------

We are currently conducting a
`survey <https://docs.google.com/forms/d/1zY0i3lLR9MhmohKjcu0wJp_CXJvBwcWoj6iG4p9LNKk/edit?ts=6836f566>`__
to help us understand how BioSimSpace is being used and how we can improve it.
The survey explores your molecular simulation tools and practices, identifies workflow challenges, and
gathers feedback on the BioSimSpace simulation framework to guide its future development. If you have
a few minutes, please fill it out!

About
-----

Expand Down
9 changes: 9 additions & 0 deletions doc/source/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ company supporting open-source development of fostering academic/industrial coll
within the biomolecular simulation community. Our software is hosted via the `OpenBioSim`
`GitHub <https://github.com/OpenBioSim/biosimspace>`__ organisation.

`2025.1.0 <https://github.com/openbiosim/biosimspace/compare/2024.4.1...2025.1.0>`_ - Jul 01 2025
-------------------------------------------------------------------------------------------------

* Improved robustness of formal charge inference when reading molecules from PDB or SDF files (`#393 <https://github.com/OpenBioSim/biosimspace/pull/393>`__).
* Make sure the system extracted from AMBER trajectory frames during free-energy perturbation simulations are in the original, unsquashed format (`#403 <https://github.com/OpenBioSim/biosimspace/pull/403>`__).
* Add support for the ``ff19SB`` force field and OPC water (`#406 <https://github.com/OpenBioSim/biosimspace/pull/406>`__).
* Allow creation of ``SOMD`` perturbation files without modification to ghost atom bonded terms (`#407 <https://github.com/OpenBioSim/biosimspace/pull/407>`__).
* Support analysis of ``SOMD2`` energy trajectories with time varying lambda sampling (`#408 <https://github.com/OpenBioSim/biosimspace/pull/408>`__).

`2024.4.1 <https://github.com/openbiosim/biosimspace/compare/2024.4.0...2024.4.1>`_ - Feb 14 2025
-------------------------------------------------------------------------------------------------

Expand Down
40 changes: 26 additions & 14 deletions python/BioSimSpace/FreeEnergy/_relative.py
Original file line number Diff line number Diff line change
Expand Up @@ -1064,15 +1064,16 @@ def _somd2_extract(parquet_file, T=None, estimator="MBAR"):
lam = float(metadata["lambda"])
except:
raise ValueError("Parquet metadata does not contain 'lambda'.")
try:
lambda_array = metadata["lambda_array"]
except:
raise ValueError("Parquet metadata does not contain 'lambda array'")
if not is_mbar:
try:
lambda_grad = metadata["lambda_grad"]
except:
raise ValueError("Parquet metadata does not contain 'lambda grad'")
else:
try:
lambda_grad = metadata["lambda_grad"]
except:
lambda_grad = []

# Make sure that the temperature is correct.
if not T == temperature:
Expand All @@ -1085,8 +1086,8 @@ def _somd2_extract(parquet_file, T=None, estimator="MBAR"):
df = table.to_pandas()

if is_mbar:
# Extract the columns correspodning to the lambda array.
df = df[[x for x in lambda_array]]
# Extract all columns other than those used for the gradient.
df = df[[x for x in df.columns if x not in lambda_grad]]

# Subtract the potential at the simulated lambda.
df = df.subtract(df[lam], axis=0)
Expand All @@ -1103,13 +1104,13 @@ def _somd2_extract(parquet_file, T=None, estimator="MBAR"):

# Forward difference.
if lam_delta > lam:
double_incr = (lam_delta - lam) * 2
grad = (df[lam_delta] - df[lam]) * 2 / double_incr
incr = lam_delta - lam
grad = (df[lam_delta] - df[lam]) / incr

# Backward difference.
else:
double_incr = (lam - lam_delta) * 2
grad = (df[lam] - df[lam_delta]) * 2 / double_incr
incr = lam - lam_delta
grad = (df[lam] - df[lam_delta]) / incr

# Central difference.
else:
Expand Down Expand Up @@ -1311,10 +1312,21 @@ def _analyse_internal(files, temperatures, lambdas, engine, estimator, **kwargs)

# Preprocess the data.
try:
processed_data = Relative._preprocess_data(data, estimator, **kwargs)
processed_data = _alchemlyb.concat(processed_data)
except:
_warnings.warn("Could not preprocess the data!")
preprocess = kwargs.pop("preprocess", True)
except KeyError:
preprocess = True

if not isinstance(preprocess, bool):
raise TypeError("'preprocess' must be of type 'bool'.")

if preprocess:
try:
processed_data = Relative._preprocess_data(data, estimator, **kwargs)
processed_data = _alchemlyb.concat(processed_data)
except:
_warnings.warn("Could not preprocess the data!")
processed_data = _alchemlyb.concat(data)
else:
processed_data = _alchemlyb.concat(data)

mbar_method = None
Expand Down
91 changes: 61 additions & 30 deletions python/BioSimSpace/Node/_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
# Set the default node directory.
_node_dir = _os.path.dirname(__file__) + "/_nodes"

__all__ = ["list", "help", "run", "setNodeDirectory"]
__all__ = ["list", "help", "run", "setNodeDirectory", "getNodeDirectory"]


def list():
Expand Down Expand Up @@ -90,7 +90,7 @@ def help(name):
print(proc.stdout)


def run(name, args={}):
def run(name, args={}, work_dir=None):
"""
Run a node.

Expand All @@ -103,6 +103,10 @@ def run(name, args={}):
args : dict
A dictionary of arguments to be passed to the node.

work_dir : str, optional
The working directory in which to run the node. If not specified,
the current working directory is used.

Returns
-------

Expand All @@ -112,9 +116,18 @@ def run(name, args={}):

# Validate the input.

if not isinstance(name, str):
raise TypeError("'name' must be of type 'str'.")

if not isinstance(args, dict):
raise TypeError("'args' must be of type 'dict'.")

if work_dir is not None:
if not isinstance(work_dir, str):
raise TypeError("'work_dir' must be of type 'str'.")
else:
work_dir = _os.getcwd()

# Apped the node directory name.
full_name = _node_dir + "/" + name

Expand All @@ -123,45 +136,50 @@ def run(name, args={}):
if not _os.path.isfile(full_name + ".py"):
raise ValueError(
"Cannot find node: '%s'. " % name
+ "in directory '%s'. " % _node_dir
+ "Run 'Node.list()' to see available nodes!"
)
else:
full_name += ".py"

# Write a YAML configuration file for the BioSimSpace node.
if len(args) > 0:
with open("input.yaml", "w") as file:
_yaml.dump(args, file, default_flow_style=False)

# Create the command.
command = "%s/python %s --config input.yaml" % (
_SireBase.getBinDir(),
full_name,
)
with _Utils.chdir(work_dir):
# Write a YAML configuration file for the BioSimSpace node.
if len(args) > 0:
with open("input.yaml", "w") as file:
_yaml.dump(args, file, default_flow_style=False)

# No arguments.
else:
command = "%s/python %s" % (_SireBase.getBinDir(), full_name)
# Create the command.
command = "%s/python %s --config input.yaml" % (
_SireBase.getBinDir(),
full_name,
)

# Run the node as a subprocess.
proc = _subprocess.run(
_Utils.command_split(command), shell=False, text=True, stderr=_subprocess.PIPE
)
# No arguments.
else:
command = "%s/python %s" % (_SireBase.getBinDir(), full_name)

# Run the node as a subprocess.
proc = _subprocess.run(
_Utils.command_split(command),
shell=False,
text=True,
stderr=_subprocess.PIPE,
)

if proc.returncode == 0:
# Read the output YAML file into a dictionary.
with open("output.yaml", "r") as file:
output = _yaml.safe_load(file)
if proc.returncode == 0:
# Read the output YAML file into a dictionary.
with open("output.yaml", "r") as file:
output = _yaml.safe_load(file)

# Delete the redundant YAML files.
_os.remove("input.yaml")
_os.remove("output.yaml")
# Delete the redundant YAML files.
_os.remove("input.yaml")
_os.remove("output.yaml")

return output
return output

else:
# Print the standard error, decoded as UTF-8.
print(proc.stderr)
else:
# Print the standard error, decoded as UTF-8.
print(proc.stderr)


def setNodeDirectory(dir):
Expand All @@ -180,3 +198,16 @@ def setNodeDirectory(dir):

global _node_dir
_node_dir = dir


def getNodeDirectory():
"""
Get the directory of the node library.

Returns
-------

dir : str
The path to the node library.
"""
return _node_dir
6 changes: 2 additions & 4 deletions python/BioSimSpace/Parameters/_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,14 @@

# A dictionary mapping AMBER protein force field names to their pdb2gmx
# compatibility. Note that the names specified below will be used for the
# parameterisation functions, so they should be suitably formatted. Once we
# have CMAP support we should be able to determine the available force fields
# by scanning the AmberTools installation directory, as we do for those from
# OpenFF.
# parameterisation functions, so they should be suitably formatted.
_amber_protein_forcefields = {
"ff03": True,
"ff99": True,
"ff99SB": False,
"ff99SBildn": False,
"ff14SB": False,
"ff19SB": False,
}

from .. import _amber_home, _gmx_exe, _gmx_path, _isVerbose
Expand Down
23 changes: 18 additions & 5 deletions python/BioSimSpace/Process/_amber.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,13 @@ def __init__(
# Flag to indicate whether the original system has a box.
self._has_box = _AmberConfig.hasBox(self._system, self._property_map)

# Take note of whether the original reference system was None
# This will be used later to avoid duplication
if reference_system is not None:
self._is_real_reference = True
else:
self._is_real_reference = False

# If the path to the executable wasn't specified, then search
# for it in AMBERHOME and the PATH.
if exe is None:
Expand Down Expand Up @@ -333,7 +340,6 @@ def _setup(self, **kwargs):
else:
# Check for perturbable molecules and convert to the chosen end state.
system = self._checkPerturbable(system)
reference_system = self._checkPerturbable(reference_system)

# RST file (coordinates).
try:
Expand All @@ -348,10 +354,17 @@ def _setup(self, **kwargs):

# Reference file for position restraints.
try:
file = _os.path.splitext(self._ref_file)[0]
_IO.saveMolecules(
file, reference_system, "rst7", property_map=self._property_map
)
if self._is_real_reference:
reference_system, _ = _squash(
system, explicit_dummies=self._explicit_dummies
)
reference_system = self._checkPerturbable(reference_system)
file = _os.path.splitext(self._ref_file)[0]
_IO.saveMolecules(
file, reference_system, "rst7", property_map=self._property_map
)
else:
_shutil.copy(self._rst_file, self._ref_file)
except Exception as e:
msg = "Failed to write reference system to 'RST7' format."
if _isVerbose():
Expand Down
5 changes: 4 additions & 1 deletion python/BioSimSpace/Process/_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,10 @@ def _checkPerturbable(self, system):
"in the 'property_map' argument."
)
else:
is_lambda1 = self._property_map["is_lambda1"].value()
try:
is_lambda1 = self._property_map["is_lambda1"].value()
except:
is_lambda1 = self._property_map["is_lambda1"]
self._property_map.pop("is_lambda1")

# Loop over all perturbable molecules in the system and replace them
Expand Down
Loading
Loading