from pathlib import Path
import pytest
import readcon
def _hwm_kib() -> int:
for line in Path("/proc/self/status").read_text(encoding="utf-8").splitlines():
if line.startswith("VmHWM:"):
return int(line.split()[1])
raise AssertionError("VmHWM")
def _trajectory(path: Path, n_frames: int, n_atoms: int, velocities: bool) -> None:
lines = []
for frame in range(n_frames):
lines.append(f"Frame {frame}")
lines.append("stream")
lines.append("8.0 8.0 4.0")
lines.append("90.0 90.0 90.0")
lines.append("0 0")
lines.append("0 0")
lines.append("1")
lines.append(str(n_atoms))
lines.append("63.546")
lines.append("Cu")
lines.append("Coordinates of Component 1")
for atom in range(n_atoms):
lines.append(f"{atom}.0 {frame}.0 0.0 0 {atom}")
if velocities:
lines.append("")
lines.append("Cu")
lines.append("Velocities of Component 1")
for atom in range(n_atoms):
lines.append(f"0.{atom % 10} 0.2 0.3 0 {atom}")
path.write_text("\n".join(lines) + "\n", encoding="utf-8")
def test_write_con_does_not_materialise_a_second_trajectory(tmp_path):
n_frames = 2000
n_atoms = 32
src = tmp_path / "in.con"
_trajectory(src, n_frames, n_atoms, velocities=False)
loaded = readcon.read_con(str(src))
assert len(loaded) == n_frames
before = _hwm_kib()
out = tmp_path / "out.con"
readcon.write_con(str(out), loaded)
growth = (_hwm_kib() - before) * 1024
coords = n_frames * n_atoms * 3 * 8
file_size = out.stat().st_size
assert growth < file_size + coords // 2, (growth, file_size, coords)
again = readcon.read_con(str(out))
assert len(again) == n_frames
assert again[3].atoms[4].x == pytest.approx(4.0)
assert again[3].atoms[4].y == pytest.approx(3.0)
vel_src = tmp_path / "in.convel"
_trajectory(vel_src, 4, n_atoms, velocities=True)
vel_out = tmp_path / "out.convel"
readcon.write_con(str(vel_out), readcon.read_con(str(vel_src)))
restored = readcon.read_con(str(vel_out))
assert restored[0].atoms[1].vx == pytest.approx(0.1)
assert restored[2].atoms[0].y == pytest.approx(2.0)
def test_multicomponent_read_write_keeps_coordinates(tmp_path):
src = Path(__file__).resolve().parents[2] / "resources/test/tiny_multi_cuh2.con"
many = tmp_path / "many.con"
many.write_text(src.read_text(encoding="utf-8") * 40, encoding="utf-8")
loaded = readcon.read_con(str(many))
out = tmp_path / "out.con"
readcon.write_con(str(out), loaded)
first = out.read_text(encoding="utf-8").splitlines()[11]
assert "0.6394" in first
assert "0.9045" in first
again = readcon.read_con(str(out))
assert again[0].atoms[0].x == pytest.approx(0.6394)
assert again[0].atoms[0].y == pytest.approx(0.9045)
assert again[0].atoms[0].z == pytest.approx(6.9753)
assert again[1].atoms[2].x == pytest.approx(8.8549)
assert again[1].atoms[2].z == pytest.approx(11.165)