|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
3 | 3 | import io |
| 4 | +import os |
| 5 | +import shutil |
| 6 | +import tempfile |
4 | 7 | import unittest |
5 | 8 | import warnings |
6 | 9 |
|
@@ -202,6 +205,52 @@ def test(self): |
202 | 205 | self.assertEqual(ss.get_nframes(), 2) |
203 | 206 |
|
204 | 207 |
|
| 208 | +class TestVaspOUTCARMultiSystems(unittest.TestCase): |
| 209 | + def test_loads_outcars_recursively_from_nested_directories(self): |
| 210 | + """The CLI ``-m`` path must discover OUTCAR files, not parse directories.""" |
| 211 | + |
| 212 | + def nonzero_composition(system): |
| 213 | + """Normalize away MultiSystems' shared zero-count type entries.""" |
| 214 | + return frozenset( |
| 215 | + (name, count) |
| 216 | + for name, count in zip( |
| 217 | + system["atom_names"], system["atom_numbs"], strict=True |
| 218 | + ) |
| 219 | + if count |
| 220 | + ) |
| 221 | + |
| 222 | + with tempfile.TemporaryDirectory() as tmpdir: |
| 223 | + calculation_dirs = [ |
| 224 | + os.path.join(tmpdir, "Bond_calc", "calculation-000"), |
| 225 | + os.path.join(tmpdir, "heating", "temperature-300", "calculation-000"), |
| 226 | + ] |
| 227 | + source_outcars = [ |
| 228 | + os.path.join("poscars", "OUTCAR.Ge.vdw"), |
| 229 | + os.path.join("poscars", "Ti-O-Ti-v6", "OUTCAR"), |
| 230 | + ] |
| 231 | + expected_compositions = { |
| 232 | + nonzero_composition(dpdata.LabeledSystem(source, fmt="vasp/outcar")) |
| 233 | + for source in source_outcars |
| 234 | + } |
| 235 | + for calculation_dir, source_outcar in zip( |
| 236 | + calculation_dirs, source_outcars, strict=True |
| 237 | + ): |
| 238 | + os.makedirs(calculation_dir) |
| 239 | + shutil.copy(source_outcar, os.path.join(calculation_dir, "OUTCAR")) |
| 240 | + |
| 241 | + systems = dpdata.MultiSystems.from_file(tmpdir, fmt="vasp/outcar") |
| 242 | + |
| 243 | + self.assertEqual(len(systems), 2) |
| 244 | + self.assertEqual(systems.get_nframes(), 2) |
| 245 | + self.assertEqual({system.get_nframes() for system in systems}, {1}) |
| 246 | + # MultiSystems aligns type maps and element order across systems, so |
| 247 | + # compare the non-zero compositions rather than display formulas. |
| 248 | + self.assertEqual( |
| 249 | + {nonzero_composition(system) for system in systems}, |
| 250 | + expected_compositions, |
| 251 | + ) |
| 252 | + |
| 253 | + |
205 | 254 | class TestVaspAtomNamesV6(unittest.TestCase): |
206 | 255 | def test(self): |
207 | 256 | # in vasp v6, the key TITEL is removed. check if the atom names |
|
0 commit comments