diff --git a/README.rst b/README.rst index dfb1ed92c..d0a664588 100644 --- a/README.rst +++ b/README.rst @@ -130,6 +130,10 @@ Now compile and install sire: A small word of warning, the compilation can easily take over an hour! +If `ccache `__ is on your ``PATH``, then ``setup.py`` will +use it automatically, which makes rebuilds much faster when developing. It +isn't included in the pixi environments, so install it separately if needed. + Other pixi environments are available depending on your needs: * ``pixi install -e default`` - core sire dependencies only diff --git a/corelib/src/libs/SireVol/triclinicbox.cpp b/corelib/src/libs/SireVol/triclinicbox.cpp index 9f6ddad85..98e133cd6 100644 --- a/corelib/src/libs/SireVol/triclinicbox.cpp +++ b/corelib/src/libs/SireVol/triclinicbox.cpp @@ -74,6 +74,9 @@ QDataStream &operator>>(QDataStream &ds, TriclinicBox &box) else if (v == 2) { ds >> box.v0 >> box.v1 >> box.v2 >> box.rotation_matrix >> box.cell_matrix >> box.cell_matrix_inverse >> box.dist_max >> box._alpha >> box._beta >> box._gamma >> box.vol >> box.is_rotated >> box.is_reduced >> box.invlength; + + // M and max_length aren't streamed, so recompute them. + box.setAttributes(); } else throw version_error(v, "1,2", r_box, CODELOC); @@ -269,7 +272,6 @@ void TriclinicBox::rotate(double precision) this->v1.setZ(0); } - // Now set the box attributes. this->setAttributes(); } @@ -405,6 +407,7 @@ TriclinicBox &TriclinicBox::operator=(const TriclinicBox &other) rotation_matrix = other.rotation_matrix; cell_matrix = other.cell_matrix; cell_matrix_inverse = other.cell_matrix_inverse; + M = other.M; dist_max = other.dist_max; max_length = other.max_length; _alpha = other._alpha; @@ -571,7 +574,7 @@ SireUnits::Dimension::Length TriclinicBox::maximumCutoff() const if (this->isReduced()) { QList diagonals = {this->v0.x(), this->v1.y(), this->v2.z()}; - return SireUnits::Dimension::Length(*std::min_element(diagonals.begin(), diagonals.end())/2.0); + return SireUnits::Dimension::Length(*std::min_element(diagonals.begin(), diagonals.end()) / 2.0); } // Otherwise, use half the norm of the smallest box vector. else diff --git a/doc/source/changelog.rst b/doc/source/changelog.rst index 2ac03be4c..4bcf91be9 100644 --- a/doc/source/changelog.rst +++ b/doc/source/changelog.rst @@ -58,6 +58,10 @@ organisation on `GitHub `__. bindings. Structures are now exchanged with the gemmi Python module using gemmi's own binary serialization, removing the pybind11 dependency. +* Fixed ``TriclinicBox`` losing its metric matrix when streamed or assigned, which gave + wrong minimum image distances from ``calc_dist``, e.g. for trajectory frame spaces. This + broke ``sire.restraints.boresch_search()`` for triclinic boxes. + `2026.2.0 `__ - September 2026 ---------------------------------------------------------------------------------------------- diff --git a/tests/vol/test_triclinic.py b/tests/vol/test_triclinic.py index c9e929ea5..8112a899b 100644 --- a/tests/vol/test_triclinic.py +++ b/tests/vol/test_triclinic.py @@ -143,6 +143,43 @@ def test_stream(): assert recovered_box == box +def test_stream_calc_dist(): + """ + Test that a streamed TriclinicBox gives the same minimum image distance + as the original. + """ + + tmp_dir = tempfile.TemporaryDirectory() + s3_file = f"{tmp_dir.name}/box.s3" + + box = sr.vol.TriclinicBox.truncated_octahedron(50.0, True, True) + + sr.stream.save(box, s3_file) + recovered_box = sr.stream.load(s3_file) + + p0 = sr.maths.Vector(1, 2, 3) + p1 = sr.maths.Vector(7, -2, 5) + dist = sr.maths.Vector.distance(p0, p1).value() + + assert box.calc_dist(p0, p1) == pytest.approx(dist) + assert recovered_box.calc_dist(p0, p1) == pytest.approx(dist) + + +def test_default_calc_dist(): + """ + Test that a default constructed TriclinicBox gives Cartesian distances. + """ + + box = sr.vol.TriclinicBox() + + p0 = sr.maths.Vector(1, 2, 3) + p1 = sr.maths.Vector(7, -2, 5) + + assert box.calc_dist(p0, p1) == pytest.approx( + sr.maths.Vector.distance(p0, p1).value() + ) + + def test_max_cutoff(ala_mols): """ Test that the maximum cutoff is set correctly.