Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
c41bf0f
Initial commit for inverse distance restraint
Apr 3, 2025
37f7759
fixes for wrappers, openMM potential and lambda lever
Apr 4, 2025
2d3cb19
Updates for the 2025.3.0.dev release.
lohedges Oct 8, 2025
1eec96a
Reset the GCMC water state prior to minimisation.
lohedges Oct 8, 2025
dd71c05
Remove redundant code.
lohedges Oct 8, 2025
f35baf8
Update CHANGELOG.
lohedges Oct 8, 2025
eccf9f4
Set sensible OpenMM box vectors when no periodic space is present.
lohedges Oct 10, 2025
6610a2e
Merge pull request #368 from OpenBioSim/fix_366_367
lohedges Oct 14, 2025
801b5b4
Add function to set atom coordinates of entire system.
lohedges Oct 17, 2025
4699540
Make Connectivity::findPath reproducible.
lohedges Oct 17, 2025
8f12699
Add dihedrals for all missing 1-4 paths.
lohedges Oct 17, 2025
a2f00b3
Update CHANGELOG.
lohedges Oct 17, 2025
cb46e85
Use std::stable_sort to ensure reproducibility. (qSort is obsolete.)
lohedges Oct 18, 2025
89b8c4d
Handle perturbable molecules.
lohedges Oct 20, 2025
1175ce2
Merge pull request #372 from OpenBioSim/fix_371
lohedges Oct 22, 2025
874714a
Merge branch 'devel' into feature_set_coordinates [ci skip]
lohedges Oct 22, 2025
134f8ae
Merge pull request #370 from OpenBioSim/feature_set_coordinates
lohedges Oct 22, 2025
1744f64
Add support for OpenMM MonteCarloMembraneBarostat.
lohedges Oct 23, 2025
293498c
Merge pull request #374 from OpenBioSim/feature_membrane_barostat
lohedges Oct 23, 2025
df06d02
Add support for dynamics crash reports.
lohedges Oct 28, 2025
02eaf49
Merge pull request #376 from OpenBioSim/feature_crash_report
lohedges Oct 28, 2025
b7c0706
Ignore exceptions raised during dynamics run.
lohedges Oct 29, 2025
e77ddd1
Clarify scope of save_crash_report option.
lohedges Oct 29, 2025
e2b9f62
Fix creation of trajectory frames from Gro87 data. [closes #375]
lohedges Oct 30, 2025
6c71d93
Allow trajectory frames to be written to specific file names.
lohedges Oct 30, 2025
1a02d27
Fix formatting of absolute file path.
lohedges Oct 31, 2025
7814ad5
Wrap trajectory frame naming functionality in new Python API.
lohedges Oct 31, 2025
f51d6a2
Add section on trajectory frame naming.
lohedges Oct 31, 2025
e41037b
Simplify conversion to absolute paths.
lohedges Oct 31, 2025
84b7ddd
Merge pull request #377 from OpenBioSim/fix_375
lohedges Oct 31, 2025
4eeb6b7
Merge branch 'devel' into feature_inverse_bond_restraint
lohedges Nov 3, 2025
fea7036
Update CHANGELOG.
lohedges Nov 3, 2025
6d7177a
Disable periodic boundary conditions for OpenMM bonded restraints.
lohedges Nov 3, 2025
9db288d
Allow user to specify whether OpenMM restraints use PBC.
lohedges Nov 3, 2025
cc16a78
Fix missing default use_pbc flag for positional restraints.
lohedges Nov 4, 2025
f5c8f34
Allow user to specify the OpenCL platform index.
lohedges Nov 4, 2025
3189d66
Boilerplate for handling PBC in restraints. [ci skip]
lohedges Nov 4, 2025
a1672cc
Update wrappers and restraint API calls.
lohedges Nov 4, 2025
5998a7a
Simplify API.
lohedges Nov 4, 2025
98246ff
Merge pull request #380 from OpenBioSim/feature_inverse_bond_restraint
lohedges Nov 6, 2025
83cb649
Merge branch 'main' into release_2025.3.0
lohedges Nov 6, 2025
8d2ab5c
Update version.
lohedges Nov 6, 2025
b69571c
Update CHANGELOG.
lohedges Nov 6, 2025
377e5c5
Update the null_energy value to match SOMD2. [ci skip]
lohedges Nov 6, 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
58 changes: 58 additions & 0 deletions corelib/src/libs/SireIO/biosimspace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1687,6 +1687,64 @@ namespace SireIO
return ion;
}

System setCoordinates(System &system, const QVector<QVector<float>> &coordinates, const bool is_lambda1, const PropertyMap &map)
{
// Make sure that the number of coordinates matches the number of atoms.
if (system.nAtoms() != coordinates.size())
{
throw SireError::incompatible_error(
QObject::tr("Number of coordinates (%1) does not match number of atoms in the system (%2)!")
.arg(coordinates.size())
.arg(system.nAtoms()),
CODELOC);
}

// Keep track of the current coordinate index.
unsigned coord_idx = 0;

// Loop over all molecules in the system in MolIdx order.
for (int i = 0; i < system.nMolecules(); ++i)
{
// Extract the molecule and make it editable.
auto molecule = system.molecule(MolIdx(i)).molecule().edit();

QString prop_name = "coordinates";
if (molecule.hasProperty("is_perturbable"))
{
if (is_lambda1)
prop_name = "coordinates1";
else
prop_name = "coordinates0";
}

// Get the coordinate property.
const auto coord_prop = map[prop_name];

// Loop over all atoms in the molecule.
for (int j = 0; j < molecule.nAtoms(); ++j)
{
// Construct the new coordinate.
const auto coord = Vector(coordinates[coord_idx + j][0],
coordinates[coord_idx + j][1],
coordinates[coord_idx + j][2]);

// Set the new coordinates.
molecule = molecule.edit()
.atom(AtomIdx(j))
.setProperty(coord_prop, coord)
.molecule();
}

// Update the molecule in the system.
system.update(molecule.commit());

// Update the coordinate index.
coord_idx += molecule.nAtoms();
}

return system;
}

Vector cross(const Vector &v0, const Vector &v1)
{
double nx = v0.y() * v1.z() - v0.z() * v1.y();
Expand Down
21 changes: 21 additions & 0 deletions corelib/src/libs/SireIO/biosimspace.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,26 @@ namespace SireIO
SIREIO_EXPORT Molecule createChlorineIon(
const Vector &coords, const QString model, const PropertyMap &map = PropertyMap());

//! Set the coordinates of the entire system.
/* \param system
The molecular system of interest.

\param coordinates
The new coordinates for the system.

\param is_lambda1
Whether this is for the lambda = 1 state.

\param map
A dictionary of user-defined molecular property names.

\retval system
The system with updated coordinates.
*/
SIREIO_EXPORT SireSystem::System setCoordinates(
SireSystem::System &system, const QVector<QVector<float>> &coordinates,
const bool is_lambda1 = false, const PropertyMap &map = PropertyMap());

Vector cross(const Vector &v0, const Vector &v1);
} // namespace SireIO

Expand All @@ -366,6 +386,7 @@ SIRE_EXPOSE_FUNCTION(SireIO::updateAndPreserveOrder)
SIRE_EXPOSE_FUNCTION(SireIO::updateCoordinatesAndVelocities)
SIRE_EXPOSE_FUNCTION(SireIO::createSodiumIon)
SIRE_EXPOSE_FUNCTION(SireIO::createChlorineIon)
SIRE_EXPOSE_FUNCTION(SireIO::setCoordinates)

SIRE_END_HEADER

Expand Down
209 changes: 156 additions & 53 deletions corelib/src/libs/SireIO/moleculeparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1669,7 +1669,35 @@ QStringList MoleculeParser::writeToFile(const QString &filename) const

QStringList written_files;

createDirectoryForFile(filename);
// Check whether list of trajectory frames have been specified via the map.
// If so, then the name will be prefixed with "frames_names:"
QStringList frame_names;
if (filename.contains("frames_names:"))
{
// Split the part of the string following "frames_names:" by commas to get
// individual frame names.
const QString frames_names_str = filename.section("frames_names:", 1);
frame_names = frames_names_str.split(",", Qt::SkipEmptyParts);

// Convert to absolute paths.
for (auto &frame_name : frame_names)
{
frame_name = QFileInfo(frame_name.trimmed()).absoluteFilePath();
}

if (frame_names.size() != frames_to_write.size())
{
throw SireError::program_bug(
QObject::tr("The number of frame names provided (%1) does not match the number of frames to write (%2).")
.arg(frame_names.size())
.arg(frames_to_write.size()),
CODELOC);
}
}
else
{
createDirectoryForFile(filename);
}

if (this->writingTrajectory() and this->isFrame())
{
Expand All @@ -1694,51 +1722,61 @@ QStringList MoleculeParser::writeToFile(const QString &filename) const

const int padding = QString::number(largest_frame).length();

// in this case, we are going to create a directory named after the
// filename, into which all the frames will be written
auto fileinfo = QFileInfo(filename);
QDir framedir;
QFileInfo fileinfo;
bool write_to_frame_dir = false;

if (fileinfo.exists())
if (frame_names.isEmpty())
{
// by default, we support overwriting of files - so remove this if it is a file
if (fileinfo.isDir())
{
_check_and_remove_frame_dir(fileinfo);
fileinfo = QFileInfo(filename);
write_to_frame_dir = true;

// rebuild so it is not cached
fileinfo = QFileInfo(filename);
// in this case, we are going to create a directory named after the
// filename, into which all the frames will be written
fileinfo = QFileInfo(filename);

if (fileinfo.exists())
throw SireError::file_error(QObject::tr(
"Could not write the trajectory for file '%1' as there "
"is already a directory with this name that contains "
"files that don't appear to have been created by sire.")
.arg(filename),
CODELOC);
}
else
if (fileinfo.exists())
{
auto dir = fileinfo.absoluteDir();

if (not dir.remove(fileinfo.fileName()))
throw SireError::file_error(QObject::tr(
"Could not write the trajectory for file '%1' as "
"we don't have permission to remove the existing "
"file with this name.")
.arg(filename),
CODELOC);
// by default, we support overwriting of files - so remove this if it is a file
if (fileinfo.isDir())
{
_check_and_remove_frame_dir(fileinfo);

// rebuild so it is not cached
fileinfo = QFileInfo(filename);

if (fileinfo.exists())
throw SireError::file_error(QObject::tr(
"Could not write the trajectory for file '%1' as there "
"is already a directory with this name that contains "
"files that don't appear to have been created by sire.")
.arg(filename),
CODELOC);
}
else
{
auto dir = fileinfo.absoluteDir();

if (not dir.remove(fileinfo.fileName()))
throw SireError::file_error(QObject::tr(
"Could not write the trajectory for file '%1' as "
"we don't have permission to remove the existing "
"file with this name.")
.arg(filename),
CODELOC);
}
}
}

QDir framedir(fileinfo.absoluteFilePath());
framedir = QDir(fileinfo.absoluteFilePath());

if (not framedir.mkpath("."))
throw SireError::file_error(QObject::tr(
"Could not create the directory into which to write the "
"trajectory for '%1'. Check that there is enough space "
"and you have the correct permissions.")
.arg(framedir.absolutePath()),
CODELOC);
if (not framedir.mkpath("."))
throw SireError::file_error(QObject::tr(
"Could not create the directory into which to write the "
"trajectory for '%1'. Check that there is enough space "
"and you have the correct permissions.")
.arg(framedir.absolutePath()),
CODELOC);
}

const auto suffix = fileinfo.completeSuffix();

Expand All @@ -1765,13 +1803,26 @@ QStringList MoleculeParser::writeToFile(const QString &filename) const
// construct a copy of this parser for this frame
auto parser = this->construct(thread_s, m);

// now write it to the file, numbered by the frame number and time
QString frame_filename = framedir.filePath(
"frame_" +
QString::number(i).rightJustified(padding, '0') +
"_" +
QString::number(time).replace(".", "-") +
"." + suffix);
QString frame_filename;

if (write_to_frame_dir)
{
// now write it to the file, numbered by the frame number and time
QDir framedir(fileinfo.absoluteFilePath());

frame_filename = framedir.filePath(
"frame_" +
QString::number(i).rightJustified(padding, '0') +
"_" +
QString::number(time).replace(".", "-") +
"." + suffix);
}
else
{
// write to the specified frame name
frame_filename = frame_names[i];
createDirectoryForFile(frame_filename);
}

parser.read().writeToFile(frame_filename);

Expand All @@ -1792,13 +1843,26 @@ QStringList MoleculeParser::writeToFile(const QString &filename) const
// construct a copy of this parser for this frame
auto parser = this->construct(s, m);

// now write it to the file, numbered by the frame number
QString frame_filename = framedir.filePath(
"frame_" +
QString::number(i).rightJustified(padding, '0') +
"_" +
QString::number(time).replace(".", "-") +
"." + suffix);
QString frame_filename;

if (write_to_frame_dir)
{
// now write it to the file, numbered by the frame number
QDir framedir(fileinfo.absoluteFilePath());

frame_filename = framedir.filePath(
"frame_" +
QString::number(i).rightJustified(padding, '0') +
"_" +
QString::number(time).replace(".", "-") +
"." + suffix);
}
else
{
// write to the specified frame name
frame_filename = frame_names[i];
createDirectoryForFile(frame_filename);
}

parser.read().writeToFile(frame_filename);

Expand All @@ -1810,7 +1874,14 @@ QStringList MoleculeParser::writeToFile(const QString &filename) const

// only return the directory name, as we can handle
// reading all the frames contained therein
written_files.append(framedir.absolutePath());
if (write_to_frame_dir)
{
written_files.append(framedir.absolutePath());
}
else
{
written_files.append(frame_names);
}
}
else
{
Expand Down Expand Up @@ -2452,6 +2523,38 @@ QStringList MoleculeParser::write(const System &system, const QString &filename,
}
}

// Check for a frame_names property in the map, which is used to control the naming of
// specific frames when writing trajectories.
if (map.specified("frame_names"))
{
const auto frame_names_property = map["frame_names"];

QStringList frame_names;

if (frame_names_property.hasSource())
{
frame_names = frame_names_property.source().split(",");
}
else
{
try
{
frame_names = frame_names_property.value().asA<StringProperty>().toString().split(",");
}
catch (...)
{
throw SireError::incompatible_error(
QObject::tr("The 'frame_names' property must be a StringProperty containing "
"a comma-separated list of filenames to use for each frame when "
"writing trajectories."),
CODELOC);
}
}

// add the special prefix to the first filename
filenames[0] = "frames_names:" + frame_names.join(",");
}

// now we have a list of filenames and associated formats, actually
// write the files
return ::pvt_write(system, filenames, fileformats, map);
Expand Down
2 changes: 2 additions & 0 deletions corelib/src/libs/SireMM/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ set ( SIREMM_HEADERS
intragroupff.h
intraljff.h
intrasoftcljff.h
inversebondrestraints.h
lj1264parameter.h
ljfunction.h
ljpair.h
Expand Down Expand Up @@ -167,6 +168,7 @@ set ( SIREMM_SOURCES
intragroupff.cpp
intraljff.cpp
intrasoftcljff.cpp
inversebondrestraints.cpp
lj1264parameter.cpp
ljpair.cpp
ljparameter.cpp
Expand Down
Loading