• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

materialsproject / pymatgen / 4075885785

pending completion
4075885785

push

github

Shyue Ping Ong
Merge branch 'master' of github.com:materialsproject/pymatgen

96 of 96 new or added lines in 27 files covered. (100.0%)

81013 of 102710 relevant lines covered (78.88%)

0.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

2.44
/pymatgen/io/vasp/tests/test_sets.py
1
# Copyright (c) Pymatgen Development Team.
2
# Distributed under the terms of the MIT License.
3

4
from __future__ import annotations
1✔
5

6
import glob
1✔
7
import hashlib
1✔
8
import os
1✔
9
import shutil
1✔
10
import tempfile
1✔
11
import unittest
1✔
12
import warnings
1✔
13
from pathlib import Path
1✔
14
from zipfile import ZipFile
1✔
15

16
import numpy as np
1✔
17
import pytest
1✔
18
from _pytest.monkeypatch import MonkeyPatch
1✔
19
from monty.json import MontyDecoder
1✔
20
from monty.serialization import loadfn
1✔
21
from pytest import approx
1✔
22

23
from pymatgen.analysis.structure_matcher import StructureMatcher
1✔
24
from pymatgen.core import SETTINGS, Lattice, Species, Structure
1✔
25
from pymatgen.core.surface import SlabGenerator
1✔
26
from pymatgen.core.units import FloatWithUnit
1✔
27
from pymatgen.io.vasp.inputs import Kpoints, Poscar
1✔
28
from pymatgen.io.vasp.outputs import Vasprun
1✔
29
from pymatgen.io.vasp.sets import (
1✔
30
    BadInputSetWarning,
31
    LobsterSet,
32
    MITMDSet,
33
    MITNEBSet,
34
    MITRelaxSet,
35
    MPAbsorptionSet,
36
    MPHSEBSSet,
37
    MPMetalRelaxSet,
38
    MPNMRSet,
39
    MPNonSCFSet,
40
    MPRelaxSet,
41
    MPScanRelaxSet,
42
    MPScanStaticSet,
43
    MPSOCSet,
44
    MPStaticSet,
45
    MVLElasticSet,
46
    MVLGBSet,
47
    MVLGWSet,
48
    MVLNPTMDSet,
49
    MVLRelax52Set,
50
    MVLScanRelaxSet,
51
    MVLSlabSet,
52
    batch_write_input,
53
    get_structure_from_prev_run,
54
    get_valid_magmom_struct,
55
)
56
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
1✔
57
from pymatgen.util.testing import PymatgenTest
1✔
58

59
MODULE_DIR = Path(__file__).resolve().parent
1✔
60

61
dec = MontyDecoder()
1✔
62

63
if SETTINGS.get("PMG_VASP_PSP_DIR") is None:
1✔
64
    raise unittest.SkipTest(f"PMG_VASP_PSP_DIR is not set. Skipping tests in {__file__}.")
1✔
65

66

67
class SetChangeCheckTest(PymatgenTest):
×
68
    def test_sets_changed(self):
×
69
        # WARNING!
70
        # These tests will fail when you change an input set.
71
        # They are included as a sanity check: if you want to change
72
        # an input set, please make sure to notify the users for that set.
73
        # For sets starting with "MVL" this is @shyuep, for sets starting
74
        # with "MP" this is @shyuep and @mkhorton.
75
        os.chdir(MODULE_DIR / "..")
×
76
        input_sets = glob.glob("*.yaml")
×
77
        hashes = {}
×
78
        for input_set in input_sets:
×
79
            with open(input_set) as f:
×
80
                hashes[input_set] = hashlib.sha1(f.read().encode("utf-8")).hexdigest()
×
81
        known_hashes = {
×
82
            "MVLGWSet.yaml": "f4df9516cf7dd923b37281172c662a70fa32bebc",
83
            "MVLRelax52Set.yaml": "eb538ffb45c0cd13f13df48afc1e71c44d2e34b2",
84
            "MPHSERelaxSet.yaml": "2bb969e64b57ff049077c8ec10e64f94c9c97f42",
85
            "VASPIncarBase.yaml": "19762515f8deefb970f2968fca48a0d67f7964d4",
86
            "MPSCANRelaxSet.yaml": "dfa9fee19178cb38c6a121ce6096db40693478e8",
87
            "MPRelaxSet.yaml": "4ea97d776fbdc7e168036f73e9176012a56c0a45",
88
            "MITRelaxSet.yaml": "1a0970f8cad9417ec810f7ab349dc854eaa67010",
89
            "vdW_parameters.yaml": "04bb09bb563d159565bcceac6a11e8bdf0152b79",
90
            "MPAbsorptionSet.yaml": "e86e405a014a7af41490cc7b99609f99f2ddd5b0",
91
        }
92

93
        assert hashes == known_hashes, (
×
94
            "These tests will fail when you change an input set. "
95
            "They are included as a sanity check: if you want to "
96
            "change an input set, please make sure to notify the "
97
            "users for that set. "
98
            'For sets starting with "MVL" this is @shyuep, '
99
            'for sets starting with "MP" this is @shyuep and @mkhorton.'
100
        )
101

102

103
class MITMPRelaxSetTest(PymatgenTest):
×
104
    @classmethod
×
105
    def setUpClass(cls):
×
106
        cls.monkeypatch = MonkeyPatch()
×
107

108
        filepath = cls.TEST_FILES_DIR / "POSCAR"
×
109
        poscar = Poscar.from_file(filepath)
×
110
        cls.structure = poscar.structure
×
111
        cls.coords = [[0, 0, 0], [0.75, 0.5, 0.75]]
×
112
        cls.lattice = Lattice(
×
113
            [
114
                [3.8401979337, 0.00, 0.00],
115
                [1.9200989668, 3.3257101909, 0.00],
116
                [0.00, -2.2171384943, 3.1355090603],
117
            ]
118
        )
119

120
        cls.mitset = MITRelaxSet(cls.structure)
×
121
        cls.mitset_unsorted = MITRelaxSet(cls.structure, sort_structure=False)
×
122
        cls.mpset = MPRelaxSet(cls.structure)
×
123

124
    def setUp(self):
×
125
        warnings.simplefilter("ignore")
×
126

127
    def tearDown(self):
×
128
        warnings.simplefilter("default")
×
129

130
    def test_metal_check(self):
×
131
        structure = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3), ["Cu"], [[0, 0, 0]])
×
132

133
        with warnings.catch_warnings(record=True) as w:
×
134
            # Cause all warnings to always be triggered.
135
            warnings.simplefilter("always")
×
136
            # Trigger a warning.
137
            vis = MITRelaxSet(structure)
×
138
            _ = vis.incar
×
139
            # Verify some things
140
            assert "ISMEAR" in str(w[-1].message)
×
141

142
    def test_poscar(self):
×
143
        structure = Structure(self.lattice, ["Fe", "Mn"], self.coords)
×
144
        mitparamset = MITRelaxSet(structure, sort_structure=False)
×
145
        s_unsorted = mitparamset.poscar.structure
×
146
        mitparamset = MITRelaxSet(structure, sort_structure=True)
×
147
        s_sorted = mitparamset.poscar.structure
×
148
        assert s_unsorted[0].specie.symbol == "Fe"
×
149
        assert s_sorted[0].specie.symbol == "Mn"
×
150

151
    def test_potcar_symbols(self):
×
152
        coords = []
×
153
        coords.append([0, 0, 0])
×
154
        coords.append([0.75, 0.5, 0.75])
×
155
        coords.append([0.75, 0.25, 0.75])
×
156
        lattice = Lattice(
×
157
            [
158
                [3.8401979337, 0.00, 0.00],
159
                [1.9200989668, 3.3257101909, 0.00],
160
                [0.00, -2.2171384943, 3.1355090603],
161
            ]
162
        )
163
        structure = Structure(lattice, ["P", "Fe", "O"], coords)
×
164
        mitparamset = MITRelaxSet(structure)
×
165
        syms = mitparamset.potcar_symbols
×
166
        assert syms == ["Fe", "P", "O"]
×
167
        paramset = MPRelaxSet(structure, sort_structure=False)
×
168
        syms = paramset.potcar_symbols
×
169
        assert syms == ["P", "Fe_pv", "O"]
×
170

171
    def test_potcar_validation(self):
×
172
        structure = Structure(self.lattice, ["P", "Fe"], self.coords)
×
173
        # Use pytest's monkeypatch to temporarily point pymatgen to a directory
174
        # containing the wrong POTCARs (LDA potcars in a PBE directory)
175
        with self.monkeypatch.context() as m:
×
176
            m.setitem(SETTINGS, "PMG_VASP_PSP_DIR", str(self.TEST_FILES_DIR / "wrong_potcars"))
×
177
            with pytest.warns(BadInputSetWarning, match="not known by pymatgen"):
×
178
                MITRelaxSet(structure).potcar
×
179

180
    def test_lda_potcar(self):
×
181
        structure = Structure(self.lattice, ["P", "Fe"], self.coords)
×
182
        p = MITRelaxSet(structure, user_potcar_functional="LDA").potcar
×
183
        assert p.functional == "LDA"
×
184

185
    def test_nelect(self):
×
186
        coords = [[0] * 3, [0.5] * 3, [0.75] * 3]
×
187
        lattice = Lattice.cubic(4)
×
188
        s = Structure(lattice, ["Si", "Si", "Fe"], coords)
×
189
        assert MITRelaxSet(s).nelect == approx(16)
×
190

191
        # Test estimate of number of bands (function of nelect) with nmag>0
192
        assert MITRelaxSet(s).estimate_nbands() == approx(13)
×
193
        assert MPRelaxSet(s).estimate_nbands() == approx(17)
×
194

195
        # Test estimate of number of bands (function of nelect) with nmag==0
196
        s = Structure(lattice, ["Si", "Si", "Si"], coords)
×
197
        assert MITRelaxSet(s).estimate_nbands() == approx(11)
×
198
        assert MPRelaxSet(s).estimate_nbands() == approx(11)
×
199

200
        # Check that it works even when oxidation states are present. Was a bug
201
        # previously.
202
        s = Structure(lattice, ["Si4+", "Si4+", "Fe2+"], coords)
×
203
        assert MITRelaxSet(s).nelect == approx(16)
×
204
        assert MPRelaxSet(s).nelect == approx(22)
×
205

206
        # Check that it works for disordered structure. Was a bug previously
207
        s = Structure(lattice, ["Si4+", "Fe2+", "Si4+"], coords)
×
208
        assert MITRelaxSet(s).nelect == approx(16)
×
209
        assert MPRelaxSet(s).nelect == approx(22)
×
210

211
    def test_get_incar(self):
×
212
        incar = self.mpset.incar
×
213

214
        assert incar["LDAUU"] == [5.3, 0, 0]
×
215
        assert incar["EDIFF"] == approx(0.0012)
×
216

217
        incar = self.mitset.incar
×
218
        assert incar["LDAUU"] == [4.0, 0, 0]
×
219
        assert incar["EDIFF"] == approx(1e-5)
×
220

221
        si = 14
×
222
        coords = []
×
223
        coords.append(np.array([0, 0, 0]))
×
224
        coords.append(np.array([0.75, 0.5, 0.75]))
×
225

226
        # Silicon structure for testing.
227
        latt = Lattice(
×
228
            np.array(
229
                [
230
                    [3.8401979337, 0.00, 0.00],
231
                    [1.9200989668, 3.3257101909, 0.00],
232
                    [0.00, -2.2171384943, 3.1355090603],
233
                ]
234
            )
235
        )
236
        struct = Structure(latt, [si, si], coords)
×
237
        incar = MPRelaxSet(struct).incar
×
238
        assert "LDAU" not in incar
×
239

240
        coords = []
×
241
        coords.append([0, 0, 0])
×
242
        coords.append([0.75, 0.5, 0.75])
×
243
        lattice = Lattice(
×
244
            [
245
                [3.8401979337, 0.00, 0.00],
246
                [1.9200989668, 3.3257101909, 0.00],
247
                [0.00, -2.2171384943, 3.1355090603],
248
            ]
249
        )
250
        struct = Structure(lattice, ["Fe", "Mn"], coords)
×
251

252
        incar = MPRelaxSet(struct).incar
×
253
        assert "LDAU" not in incar
×
254

255
        # check fluorides
256
        struct = Structure(lattice, ["Fe", "F"], coords)
×
257
        incar = MPRelaxSet(struct).incar
×
258
        assert incar["LDAUU"] == [5.3, 0]
×
259
        assert incar["MAGMOM"] == [5, 0.6]
×
260

261
        struct = Structure(lattice, ["Fe", "F"], coords)
×
262
        incar = MITRelaxSet(struct).incar
×
263
        assert incar["LDAUU"] == [4.0, 0]
×
264

265
        # This seems counterintuitive at first, but even if the prior INCAR has a MAGMOM flag,
266
        # because the structure has no site properties, the default MAGMOM is assigned from the
267
        # config dictionary.
268
        struct = Structure(lattice, ["Fe", "F"], coords)
×
269
        incar = MPStaticSet(struct, prev_incar=os.path.join(self.TEST_FILES_DIR, "INCAR")).incar
×
270
        assert incar["MAGMOM"] == [5, 0.6]
×
271

272
        # Make sure this works with species.
273
        struct = Structure(lattice, ["Fe2+", "O2-"], coords)
×
274
        incar = MPRelaxSet(struct).incar
×
275
        assert incar["LDAUU"] == [5.3, 0]
×
276

277
        struct = Structure(lattice, ["Fe", "Mn"], coords, site_properties={"magmom": (5.2, -4.5)})
×
278
        incar = MPRelaxSet(struct).incar
×
279
        assert incar["MAGMOM"] == [-4.5, 5.2]
×
280

281
        incar = MITRelaxSet(struct, sort_structure=False).incar
×
282
        assert incar["MAGMOM"] == [5.2, -4.5]
×
283

284
        struct = Structure(lattice, [Species("Fe", 2, {"spin": 4.1}), "Mn"], coords)
×
285
        incar = MPRelaxSet(struct).incar
×
286
        assert incar["MAGMOM"] == [5, 4.1]
×
287

288
        struct = Structure(lattice, ["Mn3+", "Mn4+"], coords)
×
289
        incar = MITRelaxSet(struct).incar
×
290
        assert incar["MAGMOM"] == [4, 3]
×
291

292
        userset = MPRelaxSet(struct, user_incar_settings={"MAGMOM": {"Fe": 10, "S": -5, "Mn3+": 100}})
×
293
        assert userset.incar["MAGMOM"] == [100, 0.6]
×
294

295
        noencutset = MPRelaxSet(struct, user_incar_settings={"ENCUT": None})
×
296
        assert "ENCUT" not in noencutset.incar
×
297

298
        # sulfide vs sulfate test
299

300
        coords = []
×
301
        coords.append([0, 0, 0])
×
302
        coords.append([0.75, 0.5, 0.75])
×
303
        coords.append([0.25, 0.5, 0])
×
304

305
        struct = Structure(lattice, ["Fe", "Fe", "S"], coords)
×
306
        incar = MITRelaxSet(struct).incar
×
307
        assert incar["LDAUU"] == [1.9, 0]
×
308

309
        # Make sure Matproject sulfides are ok.
310
        assert "LDAUU" not in MPRelaxSet(struct).incar
×
311

312
        struct = Structure(lattice, ["Fe", "S", "O"], coords)
×
313
        incar = MITRelaxSet(struct).incar
×
314
        assert incar["LDAUU"] == [4.0, 0, 0]
×
315

316
        # Make sure Matproject sulfates are ok.
317
        assert MPRelaxSet(struct).incar["LDAUU"] == [5.3, 0, 0]
×
318

319
        # test for default LDAUU value
320
        userset_ldauu_fallback = MPRelaxSet(struct, user_incar_settings={"LDAUU": {"Fe": 5.0, "S": 0}})
×
321
        assert userset_ldauu_fallback.incar["LDAUU"] == [5.0, 0, 0]
×
322

323
        # Expected to be oxide (O is the most electronegative atom)
324
        s = Structure(lattice, ["Fe", "O", "S"], coords)
×
325
        incar = MITRelaxSet(s).incar
×
326
        assert incar["LDAUU"] == [4.0, 0, 0]
×
327

328
        # Expected to be chloride (Cl is the most electronegative atom)
329
        s = Structure(lattice, ["Fe", "Cl", "S"], coords)
×
330
        incar = MITRelaxSet(s, user_incar_settings={"LDAU": True}).incar
×
331
        assert "LDAUU" not in incar  # LDAU = False
×
332

333
        # User set a compound to be sulfide by specifying values of "LDAUL" etc.
334
        s = Structure(lattice, ["Fe", "Cl", "S"], coords)
×
335
        incar = MITRelaxSet(
×
336
            s,
337
            user_incar_settings={
338
                "LDAU": True,
339
                "LDAUL": {"Fe": 3},
340
                "LDAUU": {"Fe": 1.8},
341
            },
342
        ).incar
343
        assert incar["LDAUL"] == [3.0, 0, 0]
×
344
        assert incar["LDAUU"] == [1.8, 0, 0]
×
345

346
        # test that van-der-Waals parameters are parsed correctly
347
        incar = MITRelaxSet(struct, vdw="optB86b").incar
×
348
        assert incar["GGA"] == "Mk"
×
349
        assert incar["LUSE_VDW"] is True
×
350
        assert incar["PARAM1"] == 0.1234
×
351

352
        # Test that NELECT is updated when a charge is present
353
        si = 14
×
354
        coords = []
×
355
        coords.append(np.array([0, 0, 0]))
×
356
        coords.append(np.array([0.75, 0.5, 0.75]))
×
357

358
        # Silicon structure for testing.
359
        latt = Lattice(
×
360
            np.array(
361
                [
362
                    [3.8401979337, 0.00, 0.00],
363
                    [1.9200989668, 3.3257101909, 0.00],
364
                    [0.00, -2.2171384943, 3.1355090603],
365
                ]
366
            )
367
        )
368
        struct = Structure(latt, [si, si], coords, charge=1)
×
369
        mpr = MPRelaxSet(struct, use_structure_charge=True)
×
370
        assert mpr.incar["NELECT"] == 7, "NELECT not properly set for nonzero charge"
×
371

372
        # test that NELECT does not get set when use_structure_charge = False
373
        mpr = MPRelaxSet(struct, use_structure_charge=False)
×
374
        assert not ("NELECT" in mpr.incar), "NELECT should not be set when use_structure_charge is False"
×
375

376
        struct = Structure(latt, ["Co", "O"], coords)
×
377
        mpr = MPRelaxSet(struct)
×
378
        assert mpr.incar["MAGMOM"] == [0.6, 0.6]
×
379
        struct = Structure(latt, ["Co4+", "O"], coords)
×
380
        mpr = MPRelaxSet(struct)
×
381
        assert mpr.incar["MAGMOM"] == [1, 0.6]
×
382

383
        # test passing user_incar_settings and user_kpoint_settings of None
384
        sets = [
×
385
            MPRelaxSet(struct, user_incar_settings=None, user_kpoints_settings=None),
386
            MPStaticSet(struct, user_incar_settings=None, user_kpoints_settings=None),
387
            MPNonSCFSet(struct, user_incar_settings=None, user_kpoints_settings=None),
388
        ]
389
        for mp_set in sets:
×
390
            assert mp_set.kpoints is not None
×
391
            assert mp_set.incar is not None
×
392

393
    def test_get_kpoints(self):
×
394
        kpoints = MPRelaxSet(self.structure).kpoints
×
395
        assert kpoints.kpts == [[2, 4, 5]]
×
396
        assert kpoints.style == Kpoints.supported_modes.Gamma
×
397

398
        kpoints = MPRelaxSet(self.structure, user_kpoints_settings={"reciprocal_density": 1000}).kpoints
×
399
        assert kpoints.kpts == [[6, 10, 13]]
×
400
        assert kpoints.style == Kpoints.supported_modes.Gamma
×
401

402
        kpoints_obj = Kpoints(kpts=[[3, 3, 3]])
×
403
        kpoints_return = MPRelaxSet(self.structure, user_kpoints_settings=kpoints_obj).kpoints
×
404
        assert kpoints_return.kpts == [[3, 3, 3]]
×
405

406
        kpoints = self.mitset.kpoints
×
407
        assert kpoints.kpts == [[25]]
×
408
        assert kpoints.style == Kpoints.supported_modes.Automatic
×
409

410
        recip_paramset = MPRelaxSet(self.structure, force_gamma=True)
×
411
        recip_paramset.kpoints_settings = {"reciprocal_density": 40}
×
412
        kpoints = recip_paramset.kpoints
×
413
        assert kpoints.kpts == [[2, 4, 5]]
×
414
        assert kpoints.style == Kpoints.supported_modes.Gamma
×
415

416
    def test_get_vasp_input(self):
×
417
        d = self.mitset.get_vasp_input()
×
418
        assert d["INCAR"]["ISMEAR"] == -5
×
419
        s = self.structure.copy()
×
420
        s.make_supercell(4)
×
421
        paramset = MPRelaxSet(s)
×
422
        d = paramset.get_vasp_input()
×
423
        assert d["INCAR"]["ISMEAR"] == 0
×
424

425
    def test_MPMetalRelaxSet(self):
×
426
        mpmetalset = MPMetalRelaxSet(self.get_structure("Sn"))
×
427
        incar = mpmetalset.incar
×
428
        assert incar["ISMEAR"] == 1
×
429
        assert incar["SIGMA"] == 0.2
×
430
        kpoints = mpmetalset.kpoints
×
431
        self.assertArrayAlmostEqual(kpoints.kpts[0], [5, 5, 5])
×
432

433
    def test_as_from_dict(self):
×
434
        mitset = MITRelaxSet(self.structure)
×
435
        mpset = MPRelaxSet(self.structure)
×
436
        mpuserset = MPRelaxSet(
×
437
            self.structure,
438
            user_incar_settings={"MAGMOM": {"Fe": 10, "S": -5, "Mn3+": 100}},
439
        )
440

441
        d = mitset.as_dict()
×
442
        v = dec.process_decoded(d)
×
443
        assert v._config_dict["INCAR"]["LDAUU"]["O"]["Fe"] == 4
×
444

445
        d = mpset.as_dict()
×
446
        v = dec.process_decoded(d)
×
447
        assert v._config_dict["INCAR"]["LDAUU"]["O"]["Fe"] == 5.3
×
448

449
        d = mpuserset.as_dict()
×
450
        v = dec.process_decoded(d)
×
451
        # self.assertEqual(type(v), MPVaspInputSet)
452
        assert v.user_incar_settings["MAGMOM"] == {"Fe": 10, "S": -5, "Mn3+": 100}
×
453

454
    def test_hubbard_off_and_ediff_override(self):
×
455
        p = MPRelaxSet(self.structure, user_incar_settings={"LDAU": False, "EDIFF": 1e-10})
×
456
        assert "LDAUU" not in p.incar
×
457
        assert p.incar["EDIFF"] == 1e-10
×
458
        # after testing, we have determined LMAXMIX should still be 4 for d-block
459
        # even if U is turned off (thanks Andrew Rosen for reporting)
460
        assert p.incar["LMAXMIX"] == 4
×
461

462
    def test_write_input(self):
×
463
        self.mitset.write_input(".", make_dir_if_not_present=True)
×
464
        for f in ["INCAR", "KPOINTS", "POSCAR", "POTCAR"]:
×
465
            assert os.path.exists(f)
×
466
        assert not os.path.exists("Fe4P4O16.cif")
×
467

468
        self.mitset.write_input(".", make_dir_if_not_present=True, include_cif=True)
×
469
        assert os.path.exists("Fe4P4O16.cif")
×
470
        for f in ["INCAR", "KPOINTS", "POSCAR", "POTCAR", "Fe4P4O16.cif"]:
×
471
            os.remove(f)
×
472

473
        self.mitset.write_input(".", make_dir_if_not_present=True, potcar_spec=True)
×
474

475
        for f in ["INCAR", "KPOINTS", "POSCAR"]:
×
476
            assert os.path.exists(f)
×
477
        assert not os.path.exists("POTCAR")
×
478
        assert os.path.exists("POTCAR.spec")
×
479
        for f in ["INCAR", "KPOINTS", "POSCAR", "POTCAR.spec"]:
×
480
            os.remove(f)
×
481

482
    def test_user_potcar_settings(self):
×
483
        vis = MPRelaxSet(self.structure, user_potcar_settings={"Fe": "Fe"})
×
484
        potcar = vis.potcar
×
485
        assert potcar.symbols == ["Fe", "P", "O"]
×
486

487
    def test_valid_magmom_struct(self):
×
488
        # First test the helper function
489
        struct = self.structure.copy()
×
490
        get_valid_magmom_struct(structure=struct, inplace=True, spin_mode="v")
×
491
        props = [isite.properties for isite in struct.sites]
×
492
        assert props == [{"magmom": [1.0, 1.0, 1.0]}] * len(props)
×
493

494
        struct = self.structure.copy()
×
495
        get_valid_magmom_struct(structure=struct, inplace=True, spin_mode="s")
×
496
        props = [isite.properties for isite in struct.sites]
×
497
        assert props == [{"magmom": 1.0}] * len(props)
×
498
        struct.insert(0, "Li", [0, 0, 0])
×
499
        get_valid_magmom_struct(structure=struct, inplace=True, spin_mode="a")
×
500
        props = [isite.properties for isite in struct.sites]
×
501
        assert props == [{"magmom": 1.0}] * len(props)
×
502

503
        struct = self.structure.copy()
×
504
        get_valid_magmom_struct(structure=struct, inplace=True, spin_mode="v")
×
505
        struct.insert(0, "Li", [0, 0, 0], properties={"magmom": 10.0})
×
506
        with pytest.raises(TypeError) as context:
×
507
            get_valid_magmom_struct(structure=struct, inplace=True, spin_mode="a")
×
508
        assert "Magmom type conflict" in str(context.exception)
×
509

510
        # Test the behavior of MPRelaxSet to atomacically fill in the missing magmom
511
        struct = self.structure.copy()
×
512
        get_valid_magmom_struct(structure=struct, inplace=True, spin_mode="s")
×
513
        struct.insert(0, "Li", [0, 0, 0])
×
514

515
        vis = MPRelaxSet(struct, user_potcar_settings={"Fe": "Fe"}, validate_magmom=False)
×
516
        with pytest.raises(TypeError) as context:
×
517
            print(vis.get_vasp_input())
×
518

519
        assert "argument must be a string" in str(context.exception)
×
520
        vis = MPRelaxSet(struct, user_potcar_settings={"Fe": "Fe"}, validate_magmom=True)
×
521
        assert vis.get_vasp_input()["INCAR"]["MAGMOM"] == [1.0] * len(struct)
×
522

523
        # Test the behavior of constraining the net magnetic moment with a non-integer
524
        struct = self.structure.copy()
×
525
        with pytest.warns(UserWarning, match=r"constrain_total_magmom"):
×
526
            vis = MPRelaxSet(
×
527
                struct,
528
                user_incar_settings={"MAGMOM": {"Fe": 5.1}},
529
                user_potcar_settings={"Fe": "Fe"},
530
                constrain_total_magmom=True,
531
            )
532
            vis.incar.items()
×
533

534

535
class MPStaticSetTest(PymatgenTest):
×
536
    def setUp(self):
×
537
        self.tmp = tempfile.mkdtemp()
×
538
        warnings.simplefilter("ignore")
×
539

540
    def test_init(self):
×
541
        prev_run = self.TEST_FILES_DIR / "relaxation"
×
542

543
        vis = MPStaticSet.from_prev_calc(prev_calc_dir=prev_run)
×
544
        assert vis.incar["NSW"] == 0
×
545
        # Check that the ENCUT has been inherited.
546
        assert vis.incar["ENCUT"] == 600
×
547
        assert vis.kpoints.style == Kpoints.supported_modes.Monkhorst
×
548

549
        # Check as from dict.
550
        vis = MPStaticSet.from_dict(vis.as_dict())
×
551
        assert vis.incar["NSW"] == 0
×
552
        # Check that the ENCUT has been inherited.
553
        assert vis.incar["ENCUT"] == 600
×
554
        assert vis.kpoints.style == Kpoints.supported_modes.Monkhorst
×
555

556
        non_prev_vis = MPStaticSet(vis.structure, user_incar_settings={"LORBIT": 12, "LWAVE": True})
×
557
        assert non_prev_vis.incar["NSW"] == 0
×
558
        # Check that the ENCUT and Kpoints style has NOT been inherited.
559
        assert non_prev_vis.incar["ENCUT"] == 520
×
560
        # Check that user incar settings are applied.
561
        assert non_prev_vis.incar["LORBIT"] == 12
×
562
        assert non_prev_vis.incar["LWAVE"]
×
563

564
        assert non_prev_vis.kpoints.style == Kpoints.supported_modes.Gamma
×
565
        v2 = MPStaticSet.from_dict(non_prev_vis.as_dict())
×
566
        assert v2.incar["ENCUT"] == 520
×
567
        # Check that user incar settings are applied.
568
        assert v2.incar["LORBIT"] == 12
×
569
        leps_vis = MPStaticSet.from_prev_calc(prev_calc_dir=prev_run, lepsilon=True)
×
570
        assert leps_vis.incar["LEPSILON"]
×
571
        assert leps_vis.incar["IBRION"] == 8
×
572
        assert leps_vis.incar["EDIFF"] == 1e-5
×
573
        assert "NPAR" not in leps_vis.incar
×
574
        assert "NSW" not in leps_vis.incar
×
575
        assert non_prev_vis.kpoints.kpts == [[11, 10, 10]]
×
576
        non_prev_vis = MPStaticSet(vis.structure, reciprocal_density=200)
×
577
        assert non_prev_vis.kpoints.kpts == [[14, 12, 12]]
×
578
        # Check LCALCPOL flag
579
        lcalcpol_vis = MPStaticSet.from_prev_calc(prev_calc_dir=prev_run, lcalcpol=True)
×
580
        assert lcalcpol_vis.incar["LCALCPOL"]
×
581

582
        # Check warning if LASPH is set to False for meta-GGAs/hybrids/+U/vdW
583
        with pytest.warns(BadInputSetWarning, match=r"LASPH"):
×
584
            vis = MPStaticSet(vis.structure, user_incar_settings={"METAGGA": "M06L", "LASPH": False})
×
585
            vis.incar.items()
×
586
        with pytest.warns(BadInputSetWarning, match=r"LASPH"):
×
587
            vis = MPStaticSet(vis.structure, user_incar_settings={"LHFCALC": True, "LASPH": False})
×
588
            vis.incar.items()
×
589
        with pytest.warns(BadInputSetWarning, match=r"LASPH"):
×
590
            vis = MPStaticSet(vis.structure, user_incar_settings={"LUSE_VDW": True, "LASPH": False})
×
591
            vis.incar.items()
×
592
        with pytest.warns(BadInputSetWarning, match=r"LASPH"):
×
593
            dummy_struc = Structure(
×
594
                lattice=[[0, 2, 2], [2, 0, 2], [2, 2, 0]],
595
                species=["Fe", "O"],
596
                coords=[[0, 0, 0], [0.5, 0.5, 0.5]],
597
            )
598
            vis = MPStaticSet(dummy_struc, user_incar_settings={"LDAU": True, "LASPH": False})
×
599
            vis.incar.items()
×
600

601
    def test_user_incar_kspacing(self):
×
602
        # Make sure user KSPACING settings properly overrides KPOINTS.
603
        si = self.get_structure("Si")
×
604
        vis = MPRelaxSet(si, user_incar_settings={"KSPACING": 0.22})
×
605
        assert vis.incar["KSPACING"] == 0.22
×
606
        assert vis.kpoints is None
×
607

608
    def test_kspacing_override(self):
×
609
        # If KSPACING is set and user_kpoints_settings are given,
610
        # make sure the user_kpoints_settings override KSPACING
611
        si = self.get_structure("Si")
×
612
        vis = MPRelaxSet(
×
613
            si,
614
            user_incar_settings={"KSPACING": 0.22},
615
            user_kpoints_settings={"reciprocal_density": 1000},
616
        )
617
        assert vis.incar.get("KSPACING") is None
×
618
        assert isinstance(vis.kpoints, Kpoints)
×
619

620
    def test_override_from_prev_calc(self):
×
621
        # test override_from_prev
622
        prev_run = self.TEST_FILES_DIR / "relaxation"
×
623

624
        vis = MPStaticSet(_dummy_structure)
×
625
        vis.override_from_prev_calc(prev_calc_dir=prev_run)
×
626
        assert vis.incar["NSW"] == 0
×
627
        assert vis.incar["ENCUT"] == 600
×
628
        assert vis.kpoints.style == Kpoints.supported_modes.Monkhorst
×
629

630
        # Check LCALCPOL flag
631
        lcalcpol_vis = MPStaticSet(_dummy_structure, lcalcpol=True)
×
632
        lcalcpol_vis = lcalcpol_vis.override_from_prev_calc(prev_calc_dir=prev_run)
×
633
        assert lcalcpol_vis.incar["LCALCPOL"]
×
634

635
    def test_standardize_structure(self):
×
636
        sga = SpacegroupAnalyzer(self.get_structure("Si"))
×
637
        original_structure = sga.get_conventional_standard_structure()
×
638
        sm = StructureMatcher(primitive_cell=False, scale=False)
×
639

640
        vis = MPStaticSet(original_structure)
×
641
        assert sm.fit(vis.structure, original_structure)
×
642

643
        vis = MPStaticSet(original_structure, standardize=True)
×
644
        assert not sm.fit(vis.structure, original_structure)
×
645

646
    def test_write_input_zipped(self):
×
647
        vis = MPStaticSet(self.get_structure("Si"))
×
648
        vis.write_input(output_dir=".", potcar_spec=True, zip_output=True)
×
649

650
        assert os.path.exists("MPStaticSet.zip")
×
651
        with ZipFile("MPStaticSet.zip", "r") as zip:
×
652
            contents = zip.namelist()
×
653
            assert set(contents).issuperset({"INCAR", "POSCAR", "POTCAR.spec", "KPOINTS"})
×
654
            spec = zip.open("POTCAR.spec", "r").read().decode()
×
655
            assert spec == "Si"
×
656

657
        os.remove("MPStaticSet.zip")
×
658

659
    def test_conflicting_arguments(self):
×
660
        with pytest.raises(ValueError, match="deprecated"):
×
661
            si = self.get_structure("Si")
×
662
            MPStaticSet(si, potcar_functional="PBE", user_potcar_functional="PBE")
×
663

664
    def test_grid_size_from_struct(self):
×
665
        # TODO grab a bunch_of_calculations store as a list of tuples
666
        # (structure, ngx, ..., ngxf, ...) where all the grid size values are generated by vasp
667
        # check that the code produces the same grid sizes
668
        fname = self.TEST_FILES_DIR / "grid_data_files" / "vasp_inputs_for_grid_check.json"
×
669
        parsed_vasp_data = loadfn(fname)
×
670
        for tt in parsed_vasp_data:
×
671
            ng = [tt["input"]["parameters"][ik] for ik in ["NGX", "NGY", "NGZ"]]
×
672
            ngf = [tt["input"]["parameters"][ik] for ik in ["NGXF", "NGYF", "NGZF"]]
×
673
            struct = tt["input"]["structure"]
×
674
            static_set = MPStaticSet(struct)
×
675
            matched = static_set.calculate_ng() == (ng, ngf)
×
676
            assert matched
×
677

678
    def tearDown(self):
×
679
        shutil.rmtree(self.tmp)
×
680
        warnings.simplefilter("default")
×
681

682

683
class MPNonSCFSetTest(PymatgenTest):
×
684
    def setUp(self):
×
685
        self.tmp = tempfile.mkdtemp()
×
686
        warnings.simplefilter("ignore")
×
687

688
    def test_init(self):
×
689
        prev_run = self.TEST_FILES_DIR / "relaxation"
×
690
        # check boltztrap mode
691
        vis = MPNonSCFSet.from_prev_calc(prev_calc_dir=prev_run, mode="Boltztrap")
×
692
        assert vis.incar["ISMEAR"] == 0
×
693

694
        # check uniform mode
695
        vis = MPNonSCFSet.from_prev_calc(prev_calc_dir=prev_run, mode="Uniform")
×
696
        assert vis.incar["ISMEAR"] == -5
×
697
        assert vis.incar["ISYM"] == 2
×
698

699
        # check uniform mode with automatic nedos
700
        vis = MPNonSCFSet.from_prev_calc(prev_calc_dir=prev_run, mode="Uniform", nedos=0)
×
701
        assert vis.incar["NEDOS"] == 12217
×
702

703
        # test line mode
704
        vis = MPNonSCFSet.from_prev_calc(
×
705
            prev_calc_dir=prev_run,
706
            mode="Line",
707
            copy_chgcar=False,
708
            user_incar_settings={"SIGMA": 0.025},
709
        )
710

711
        assert vis.incar["NSW"] == 0
×
712
        # Check that the ENCUT has been inherited.
713
        assert vis.incar["ENCUT"] == 600
×
714
        # Check that the user_incar_settings works
715
        assert vis.incar["SIGMA"] == 0.025
×
716
        assert vis.kpoints.style == Kpoints.supported_modes.Reciprocal
×
717

718
        # Check as from dict.
719
        vis = MPNonSCFSet.from_dict(vis.as_dict())
×
720
        assert vis.incar["NSW"] == 0
×
721
        # Check that the ENCUT has been inherited.
722
        assert vis.incar["ENCUT"] == 600
×
723
        assert vis.kpoints.style == Kpoints.supported_modes.Reciprocal
×
724

725
        vis.write_input(self.tmp)
×
726
        assert not os.path.exists(os.path.join(self.tmp, "CHGCAR"))
×
727

728
        vis = MPNonSCFSet.from_prev_calc(prev_calc_dir=prev_run, mode="Line", copy_chgcar=True)
×
729
        # check ISMEAR set correctly for line mode
730
        assert vis.incar["ISMEAR"] == 0
×
731
        vis.write_input(self.tmp)
×
732
        assert os.path.exists(os.path.join(self.tmp, "CHGCAR"))
×
733
        os.remove(os.path.join(self.tmp, "CHGCAR"))
×
734

735
        vis = MPNonSCFSet.from_prev_calc(prev_calc_dir=prev_run, standardize=True, mode="Line", copy_chgcar=True)
×
736
        vis.write_input(self.tmp)
×
737
        assert not os.path.exists(os.path.join(self.tmp, "CHGCAR"))
×
738

739
    def test_override_from_prev(self):
×
740
        prev_run = self.TEST_FILES_DIR / "relaxation"
×
741

742
        # test override_from_prev
743
        vis = MPNonSCFSet(_dummy_structure, mode="Boltztrap")
×
744
        vis.override_from_prev_calc(prev_calc_dir=prev_run)
×
745
        assert vis.incar["ISMEAR"] == 0
×
746

747
        vis = MPNonSCFSet(_dummy_structure, mode="Uniform")
×
748
        vis.override_from_prev_calc(prev_calc_dir=prev_run)
×
749
        assert vis.incar["ISMEAR"] == -5
×
750
        assert vis.incar["ISYM"] == 2
×
751

752
        vis = MPNonSCFSet(_dummy_structure, mode="Uniform", nedos=0)
×
753
        vis.override_from_prev_calc(prev_calc_dir=prev_run)
×
754
        assert vis.incar["NEDOS"] == 12217
×
755

756
        # test line mode
757
        vis = MPNonSCFSet(
×
758
            _dummy_structure,
759
            mode="Line",
760
            copy_chgcar=False,
761
            user_incar_settings={"SIGMA": 0.025},
762
        )
763
        vis.override_from_prev_calc(prev_calc_dir=prev_run)
×
764

765
        assert vis.incar["NSW"] == 0
×
766
        assert vis.incar["ENCUT"] == 600
×
767
        assert vis.incar["SIGMA"] == 0.025
×
768
        assert vis.kpoints.style == Kpoints.supported_modes.Reciprocal
×
769

770
        vis = MPNonSCFSet(_dummy_structure, mode="Line", copy_chgcar=True)
×
771
        vis.override_from_prev_calc(prev_calc_dir=prev_run)
×
772
        assert vis.incar["ISMEAR"] == 0
×
773
        vis.write_input(self.tmp)
×
774
        assert os.path.exists(os.path.join(self.tmp, "CHGCAR"))
×
775
        os.remove(os.path.join(self.tmp, "CHGCAR"))
×
776

777
        vis = MPNonSCFSet(_dummy_structure, standardize=True, mode="Line", copy_chgcar=True)
×
778
        vis.override_from_prev_calc(prev_calc_dir=prev_run)
×
779
        vis.write_input(self.tmp)
×
780
        assert not os.path.exists(os.path.join(self.tmp, "CHGCAR"))
×
781

782
    def test_kpoints(self):
×
783
        # test k-points are generated in the correct format
784
        prev_run = self.TEST_FILES_DIR / "relaxation"
×
785
        vis = MPNonSCFSet.from_prev_calc(prev_calc_dir=prev_run, mode="Uniform", copy_chgcar=False)
×
786
        assert np.array(vis.kpoints.kpts).shape == (1, 3)
×
787

788
        vis = MPNonSCFSet.from_prev_calc(prev_calc_dir=prev_run, mode="Line", copy_chgcar=False)
×
789
        assert np.array(vis.kpoints.kpts).shape != (1, 3)
×
790

791
        vis = MPNonSCFSet.from_prev_calc(prev_calc_dir=prev_run, mode="Boltztrap", copy_chgcar=False)
×
792
        assert np.array(vis.kpoints.kpts).shape != (1, 3)
×
793

794
    def test_optics(self):
×
795
        prev_run = self.TEST_FILES_DIR / "relaxation"
×
796
        vis = MPNonSCFSet.from_prev_calc(
×
797
            prev_calc_dir=prev_run,
798
            copy_chgcar=False,
799
            optics=True,
800
            mode="Uniform",
801
            nedos=2001,
802
        )
803

804
        assert vis.incar["NSW"] == 0
×
805
        # Check that the ENCUT has been inherited.
806
        assert vis.incar["ENCUT"] == 600
×
807

808
        # check NEDOS and ISMEAR set correctly
809
        assert vis.incar["NEDOS"] == 2001
×
810
        assert vis.incar["ISMEAR"] == -5
×
811
        assert vis.incar["ISYM"] == 2
×
812

813
        assert vis.incar["LOPTICS"]
×
814
        assert vis.kpoints.style == Kpoints.supported_modes.Gamma
×
815

816
    def test_user_kpoint_override(self):
×
817
        user_kpoints_override = Kpoints(
×
818
            style=Kpoints.supported_modes.Gamma, kpts=((1, 1, 1),)
819
        )  # the default kpoints style is reciprocal
820

821
        prev_run = self.TEST_FILES_DIR / "relaxation"
×
822
        vis = MPNonSCFSet.from_prev_calc(
×
823
            prev_calc_dir=prev_run,
824
            copy_chgcar=False,
825
            optics=True,
826
            mode="Uniform",
827
            nedos=2001,
828
            user_kpoints_settings=user_kpoints_override,
829
        )
830
        assert vis.kpoints.style == Kpoints.supported_modes.Gamma
×
831

832
    def tearDown(self):
×
833
        shutil.rmtree(self.tmp)
×
834
        warnings.simplefilter("default")
×
835

836

837
class MagmomLdauTest(PymatgenTest):
×
838
    def setUp(self):
×
839
        warnings.simplefilter("ignore")
×
840

841
    def tearDown(self):
×
842
        warnings.simplefilter("default")
×
843

844
    def test_structure_from_prev_run(self):
×
845
        vrun = Vasprun(self.TEST_FILES_DIR / "vasprun.xml.magmom_ldau")
×
846
        structure = vrun.final_structure
×
847
        poscar = Poscar(structure)
×
848
        structure_decorated = get_structure_from_prev_run(vrun)
×
849
        ldau_ans = {"LDAUU": [5.3, 0.0], "LDAUL": [2, 0], "LDAUJ": [0.0, 0.0]}
×
850
        magmom_ans = [5.0, 5.0, 5.0, 5.0, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6]
×
851
        ldau_dict = {}
×
852
        for key in ("LDAUU", "LDAUJ", "LDAUL"):
×
853
            if hasattr(structure_decorated[0], key.lower()):
×
854
                m = {site.specie.symbol: getattr(site, key.lower()) for site in structure_decorated}
×
855
                ldau_dict[key] = [m[sym] for sym in poscar.site_symbols]
×
856
        magmom = [site.magmom for site in structure_decorated]
×
857
        assert ldau_dict == ldau_ans
×
858
        assert magmom == magmom_ans
×
859

860
    def test_ln_magmom(self):
×
861
        YAML_PATH = os.path.join(os.path.dirname(__file__), "../VASPIncarBase.yaml")
×
862
        MAGMOM_SETTING = loadfn(YAML_PATH)["INCAR"]["MAGMOM"]
×
863
        structure = Structure.from_file(self.TEST_FILES_DIR / "La4Fe4O12.cif")
×
864
        structure.add_oxidation_state_by_element({"La": +3, "Fe": +3, "O": -2})
×
865
        for ion in MAGMOM_SETTING:
×
866
            s = structure.copy()
×
867
            s.replace_species({"La3+": ion})
×
868
            vis = MPRelaxSet(s)
×
869
            fe_pos = vis.poscar.comment.index("Fe")
×
870
            if fe_pos == 0:
×
871
                magmom_ans = [5] * 4 + [MAGMOM_SETTING[ion]] * 4 + [0.6] * 12
×
872
            else:
873
                magmom_ans = [MAGMOM_SETTING[ion]] * 4 + [5] * 4 + [0.6] * 12
×
874

875
            assert vis.incar["MAGMOM"] == magmom_ans
×
876

877

878
class MITMDSetTest(PymatgenTest):
×
879
    def setUp(self):
×
880
        filepath = self.TEST_FILES_DIR / "POSCAR"
×
881
        poscar = Poscar.from_file(filepath)
×
882
        self.struct = poscar.structure
×
883
        self.mitmdparam = MITMDSet(self.struct, 300, 1200, 10000)
×
884
        warnings.simplefilter("ignore")
×
885

886
    def tearDown(self):
×
887
        warnings.simplefilter("default")
×
888

889
    def test_params(self):
×
890
        param = self.mitmdparam
×
891
        syms = param.potcar_symbols
×
892
        assert syms == ["Fe", "P", "O"]
×
893
        incar = param.incar
×
894
        assert "LDAUU" not in incar
×
895
        assert incar["EDIFF"] == approx(1e-5)
×
896
        kpoints = param.kpoints
×
897
        assert kpoints.kpts == [(1, 1, 1)]
×
898
        assert kpoints.style == Kpoints.supported_modes.Gamma
×
899

900
    def test_as_from_dict(self):
×
901
        d = self.mitmdparam.as_dict()
×
902
        v = dec.process_decoded(d)
×
903
        assert isinstance(v, MITMDSet)
×
904
        assert v._config_dict["INCAR"]["TEBEG"] == 300
×
905
        assert v._config_dict["INCAR"]["PREC"] == "Low"
×
906

907

908
class MVLNPTMDSetTest(PymatgenTest):
×
909
    def setUp(self):
×
910
        file_path = self.TEST_FILES_DIR / "POSCAR"
×
911
        poscar = Poscar.from_file(file_path)
×
912
        self.struct = poscar.structure
×
913
        self.mvl_npt_set = MVLNPTMDSet(self.struct, start_temp=0, end_temp=300, nsteps=1000)
×
914
        warnings.simplefilter("ignore")
×
915

916
    def tearDown(self):
×
917
        warnings.simplefilter("default")
×
918

919
    def test_incar(self):
×
920
        npt_set = self.mvl_npt_set
×
921

922
        syms = npt_set.potcar_symbols
×
923
        assert syms == ["Fe", "P", "O"]
×
924

925
        incar = npt_set.incar
×
926
        assert "LDAUU" not in incar
×
927
        assert incar["EDIFF"] == approx(1e-5)
×
928
        assert incar["LANGEVIN_GAMMA_L"] == 1
×
929
        assert incar["LANGEVIN_GAMMA"] == [10, 10, 10]
×
930
        enmax = max(npt_set.potcar[i].keywords["ENMAX"] for i in range(self.struct.ntypesp))
×
931
        assert incar["ENCUT"] == approx(1.5 * enmax)
×
932
        assert incar["ALGO"] == "Fast"
×
933
        assert incar["ISIF"] == 3
×
934
        assert incar["MDALGO"] == 3
×
935
        assert incar["SMASS"] == 0
×
936
        assert incar["PREC"] == "Low"
×
937

938
        kpoints = npt_set.kpoints
×
939
        assert kpoints.kpts == [(1, 1, 1)]
×
940
        assert kpoints.style == Kpoints.supported_modes.Gamma
×
941

942
    def test_as_from_dict(self):
×
943
        d = self.mvl_npt_set.as_dict()
×
944
        v = dec.process_decoded(d)
×
945
        assert isinstance(v, MVLNPTMDSet)
×
946
        assert v._config_dict["INCAR"]["NSW"] == 1000
×
947

948

949
class MITNEBSetTest(PymatgenTest):
×
950
    def setUp(self):
×
951
        c1 = [[0.5] * 3, [0.9] * 3]
×
952
        c2 = [[0.5] * 3, [0.9, 0.1, 0.1]]
×
953
        s1 = Structure(Lattice.cubic(5), ["Si", "Si"], c1)
×
954
        s2 = Structure(Lattice.cubic(5), ["Si", "Si"], c2)
×
955
        structs = []
×
956
        for s in s1.interpolate(s2, 3, pbc=True):
×
957
            structs.append(Structure.from_sites(s.sites, to_unit_cell=True))
×
958
        self.structures = structs
×
959
        self.vis = MITNEBSet(self.structures)
×
960
        warnings.simplefilter("ignore")
×
961

962
    def tearDown(self):
×
963
        warnings.simplefilter("default")
×
964

965
    def test_potcar_symbols(self):
×
966
        syms = self.vis.potcar_symbols
×
967
        assert syms == ["Si"]
×
968

969
    def test_incar(self):
×
970
        incar = self.vis.incar
×
971
        assert "LDAUU" not in incar
×
972
        assert incar["EDIFF"] == approx(0.00001)
×
973

974
    def test_kpoints(self):
×
975
        kpoints = self.vis.kpoints
×
976
        assert kpoints.kpts == [[25]]
×
977
        assert kpoints.style == Kpoints.supported_modes.Automatic
×
978

979
    def test_as_from_dict(self):
×
980
        d = self.vis.as_dict()
×
981
        v = dec.process_decoded(d)
×
982
        assert v._config_dict["INCAR"]["IMAGES"] == 2
×
983

984
    def test_write_input(self):
×
985
        self.vis.write_input(".", write_cif=True, write_endpoint_inputs=True, write_path_cif=True)
×
986
        assert os.path.exists("INCAR")
×
987
        assert os.path.exists("KPOINTS")
×
988
        assert os.path.exists("POTCAR")
×
989
        assert os.path.exists("00/POSCAR")
×
990
        assert os.path.exists("01/POSCAR")
×
991
        assert os.path.exists("02/POSCAR")
×
992
        assert os.path.exists("03/POSCAR")
×
993
        assert not os.path.exists("04/POSCAR")
×
994
        assert os.path.exists("00/INCAR")
×
995
        assert os.path.exists("path.cif")
×
996
        for d in ["00", "01", "02", "03"]:
×
997
            shutil.rmtree(d)
×
998
        for f in ["INCAR", "KPOINTS", "POTCAR", "path.cif"]:
×
999
            os.remove(f)
×
1000

1001

1002
class MPSOCSetTest(PymatgenTest):
×
1003
    def setUp(self):
×
1004
        warnings.simplefilter("ignore")
×
1005

1006
    def tearDown(self):
×
1007
        warnings.simplefilter("default")
×
1008

1009
    def test_from_prev_calc(self):
×
1010
        prev_run = self.TEST_FILES_DIR / "fe_monomer"
×
1011
        vis = MPSOCSet.from_prev_calc(
×
1012
            prev_calc_dir=prev_run,
1013
            magmom=[3],
1014
            saxis=(1, 0, 0),
1015
            user_incar_settings={"SIGMA": 0.025},
1016
        )
1017
        assert vis.incar["ISYM"] == -1
×
1018
        assert vis.incar["LSORBIT"]
×
1019
        assert vis.incar["ICHARG"] == 11
×
1020
        assert vis.incar["SAXIS"] == [1, 0, 0]
×
1021
        assert vis.incar["MAGMOM"] == [[0, 0, 3]]
×
1022
        assert vis.incar["SIGMA"] == 0.025
×
1023

1024
    def test_override_from_prev_calc(self):
×
1025
        # test override_from_prev_calc
1026
        prev_run = self.TEST_FILES_DIR / "fe_monomer"
×
1027
        vis = MPSOCSet(
×
1028
            _dummy_structure,
1029
            magmom=[3],
1030
            saxis=(1, 0, 0),
1031
            user_incar_settings={"SIGMA": 0.025},
1032
        )
1033
        vis.override_from_prev_calc(prev_calc_dir=prev_run)
×
1034
        assert vis.incar["ISYM"] == -1
×
1035
        assert vis.incar["LSORBIT"]
×
1036
        assert vis.incar["ICHARG"] == 11
×
1037
        assert vis.incar["SAXIS"] == [1, 0, 0]
×
1038
        assert vis.incar["MAGMOM"] == [[0, 0, 3]]
×
1039
        assert vis.incar["SIGMA"] == 0.025
×
1040

1041

1042
class MPNMRSetTest(PymatgenTest):
×
1043
    def setUp(self):
×
1044
        warnings.simplefilter("ignore")
×
1045

1046
    def tearDown(self):
×
1047
        warnings.simplefilter("default")
×
1048

1049
    def test_incar(self):
×
1050
        filepath = self.TEST_FILES_DIR / "Li.cif"
×
1051
        structure = Structure.from_file(filepath)
×
1052

1053
        vis = MPNMRSet(structure)
×
1054
        assert vis.incar.get("LCHIMAG", None)
×
1055
        assert vis.incar.get("QUAD_EFG", None) is None
×
1056

1057
        vis = MPNMRSet(structure, mode="efg")
×
1058
        assert not vis.incar.get("LCHIMAG", None)
×
1059
        assert vis.incar.get("QUAD_EFG", None) == [-0.808]
×
1060
        for q in vis.incar["QUAD_EFG"]:
×
1061
            assert isinstance(q, float)
×
1062
            assert not isinstance(q, FloatWithUnit)
×
1063

1064
        vis = MPNMRSet(structure, mode="efg", isotopes=["Li-7"])
×
1065
        assert not vis.incar.get("LCHIMAG", None)
×
1066
        assert vis.incar.get("QUAD_EFG", None) == [-40.1]
×
1067

1068

1069
class MVLSlabSetTest(PymatgenTest):
×
1070
    def setUp(self):
×
1071
        s = self.get_structure("Li2O")
×
1072
        gen = SlabGenerator(s, (1, 0, 0), 10, 10)
×
1073
        self.slab = gen.get_slab()
×
1074
        self.bulk = self.slab.oriented_unit_cell
×
1075

1076
        vis_bulk = MVLSlabSet(self.bulk, bulk=True)
×
1077
        vis = MVLSlabSet(self.slab)
×
1078
        vis_dipole = MVLSlabSet(self.slab, auto_dipole=True)
×
1079

1080
        self.d_bulk = vis_bulk.get_vasp_input()
×
1081
        self.d_slab = vis.get_vasp_input()
×
1082
        self.d_dipole = vis_dipole.get_vasp_input()
×
1083
        self.vis = vis
×
1084
        warnings.simplefilter("ignore")
×
1085

1086
    def tearDown(self):
×
1087
        warnings.simplefilter("default")
×
1088

1089
    def test_user_incar_settings(self):
×
1090
        # Make sure user incar settings properly override AMIX.
1091
        si = self.get_structure("Si")
×
1092
        vis = MVLSlabSet(si, user_incar_settings={"AMIX": 0.1})
×
1093
        assert vis.incar["AMIX"] == 0.1
×
1094

1095
    def test_bulk(self):
×
1096
        incar_bulk = self.d_bulk["INCAR"]
×
1097
        poscar_bulk = self.d_bulk["POSCAR"]
×
1098

1099
        assert incar_bulk["ISIF"] == 3
×
1100
        assert incar_bulk["EDIFF"] == 1e-4
×
1101
        assert incar_bulk["EDIFFG"] == -0.02
×
1102
        assert poscar_bulk.structure.formula == self.bulk.formula
×
1103

1104
    def test_slab(self):
×
1105
        incar_slab = self.d_slab["INCAR"]
×
1106
        poscar_slab = self.d_slab["POSCAR"]
×
1107
        potcar_slab = self.d_slab["POTCAR"]
×
1108

1109
        assert incar_slab["AMIN"] == 0.01
×
1110
        assert incar_slab["AMIX"] == 0.2
×
1111
        assert incar_slab["BMIX"] == 0.001
×
1112
        assert incar_slab["NELMIN"] == 8
×
1113
        # No volume relaxation during slab calculations
1114
        assert incar_slab["ISIF"] == 2
×
1115
        assert potcar_slab.functional == "PBE"
×
1116
        assert potcar_slab.symbols[1] == "O"
×
1117
        assert potcar_slab.symbols[0] == "Li_sv"
×
1118
        assert poscar_slab.structure.formula == self.slab.formula
×
1119
        # Test auto-dipole
1120
        dipole_incar = self.d_dipole["INCAR"]
×
1121
        assert dipole_incar["LDIPOL"]
×
1122
        self.assertArrayAlmostEqual(dipole_incar["DIPOL"], [0.2323, 0.2323, 0.2165], decimal=4)
×
1123
        assert dipole_incar["IDIPOL"] == 3
×
1124

1125
    def test_kpoints(self):
×
1126
        kpoints_slab = self.d_slab["KPOINTS"].kpts[0]
×
1127
        kpoints_bulk = self.d_bulk["KPOINTS"].kpts[0]
×
1128

1129
        assert kpoints_bulk[0] == kpoints_slab[0]
×
1130
        assert kpoints_bulk[1] == kpoints_slab[1]
×
1131
        assert kpoints_bulk[0] == 15
×
1132
        assert kpoints_bulk[1] == 15
×
1133
        assert kpoints_bulk[2] == 15
×
1134
        # The last kpoint in a slab should always be 1
1135
        assert kpoints_slab[2] == 1
×
1136

1137
    def test_as_dict(self):
×
1138
        vis_dict = self.vis.as_dict()
×
1139
        MVLSlabSet.from_dict(vis_dict)
×
1140

1141

1142
class MVLElasticSetTest(PymatgenTest):
×
1143
    def setUp(self):
×
1144
        warnings.simplefilter("ignore")
×
1145

1146
    def tearDown(self):
×
1147
        warnings.simplefilter("default")
×
1148

1149
    def test_incar(self):
×
1150
        mvlparam = MVLElasticSet(self.get_structure("Graphite"))
×
1151
        incar = mvlparam.incar
×
1152
        assert incar["IBRION"] == 6
×
1153
        assert incar["NFREE"] == 2
×
1154
        assert incar["POTIM"] == 0.015
×
1155
        assert "NPAR" not in incar
×
1156

1157

1158
class MVLGWSetTest(PymatgenTest):
×
1159
    def setUp(self):
×
1160
        self.tmp = tempfile.mkdtemp()
×
1161
        self.s = PymatgenTest.get_structure("Li2O")
×
1162
        warnings.simplefilter("ignore")
×
1163

1164
    def tearDown(self):
×
1165
        warnings.simplefilter("default")
×
1166
        shutil.rmtree(self.tmp)
×
1167

1168
    def test_static(self):
×
1169
        mvlgwsc = MVLGWSet(self.s)
×
1170
        incar = mvlgwsc.incar
×
1171
        assert incar["SIGMA"] == 0.01
×
1172
        kpoints = mvlgwsc.kpoints
×
1173
        assert kpoints.style == Kpoints.supported_modes.Gamma
×
1174
        symbols = mvlgwsc.potcar.symbols
×
1175
        assert symbols == ["Li_sv_GW", "O_GW"]
×
1176

1177
    def test_diag(self):
×
1178
        prev_run = self.TEST_FILES_DIR / "relaxation"
×
1179
        mvlgwdiag = MVLGWSet.from_prev_calc(prev_run, copy_wavecar=True, mode="diag")
×
1180
        mvlgwdiag.write_input(self.tmp)
×
1181
        assert os.path.exists(os.path.join(self.tmp, "WAVECAR"))
×
1182
        assert mvlgwdiag.incar["NBANDS"] == 32
×
1183
        assert mvlgwdiag.incar["ALGO"] == "Exact"
×
1184
        assert mvlgwdiag.incar["LOPTICS"]
×
1185

1186
        # test override_from_prev_calc
1187
        mvlgwdiag = MVLGWSet(_dummy_structure, copy_wavecar=True, mode="diag")
×
1188
        mvlgwdiag.override_from_prev_calc(prev_calc_dir=prev_run)
×
1189
        mvlgwdiag.write_input(self.tmp)
×
1190
        assert os.path.exists(os.path.join(self.tmp, "WAVECAR"))
×
1191
        assert mvlgwdiag.incar["NBANDS"] == 32
×
1192
        assert mvlgwdiag.incar["ALGO"] == "Exact"
×
1193
        assert mvlgwdiag.incar["LOPTICS"]
×
1194

1195
    def test_bse(self):
×
1196
        prev_run = self.TEST_FILES_DIR / "relaxation"
×
1197
        mvlgwgbse = MVLGWSet.from_prev_calc(prev_run, copy_wavecar=True, mode="BSE")
×
1198
        mvlgwgbse.write_input(self.tmp)
×
1199
        assert os.path.exists(os.path.join(self.tmp, "WAVECAR"))
×
1200
        assert os.path.exists(os.path.join(self.tmp, "WAVEDER"))
×
1201

1202
        prev_run = self.TEST_FILES_DIR / "relaxation"
×
1203
        mvlgwgbse = MVLGWSet.from_prev_calc(prev_run, copy_wavecar=False, mode="GW")
×
1204
        assert mvlgwgbse.incar["NOMEGA"] == 80
×
1205
        assert mvlgwgbse.incar["ENCUTGW"] == 250
×
1206
        assert mvlgwgbse.incar["ALGO"] == "GW0"
×
1207
        mvlgwgbse1 = MVLGWSet.from_prev_calc(prev_run, copy_wavecar=False, mode="BSE")
×
1208
        assert mvlgwgbse1.incar["ANTIRES"] == 0
×
1209
        assert mvlgwgbse1.incar["NBANDSO"] == 20
×
1210
        assert mvlgwgbse1.incar["ALGO"] == "BSE"
×
1211

1212
        # test override_from_prev_calc
1213
        prev_run = self.TEST_FILES_DIR / "relaxation"
×
1214
        mvlgwgbse = MVLGWSet(_dummy_structure, copy_wavecar=True, mode="BSE")
×
1215
        mvlgwgbse.override_from_prev_calc(prev_calc_dir=prev_run)
×
1216
        mvlgwgbse.write_input(self.tmp)
×
1217
        assert os.path.exists(os.path.join(self.tmp, "WAVECAR"))
×
1218
        assert os.path.exists(os.path.join(self.tmp, "WAVEDER"))
×
1219

1220
        prev_run = self.TEST_FILES_DIR / "relaxation"
×
1221
        mvlgwgbse = MVLGWSet(_dummy_structure, copy_wavecar=True, mode="GW")
×
1222
        mvlgwgbse.override_from_prev_calc(prev_calc_dir=prev_run)
×
1223
        assert mvlgwgbse.incar["NOMEGA"] == 80
×
1224
        assert mvlgwgbse.incar["ENCUTGW"] == 250
×
1225
        assert mvlgwgbse.incar["ALGO"] == "GW0"
×
1226

1227
        mvlgwgbse1 = MVLGWSet(_dummy_structure, copy_wavecar=False, mode="BSE")
×
1228
        mvlgwgbse1.override_from_prev_calc(prev_calc_dir=prev_run)
×
1229
        assert mvlgwgbse1.incar["ANTIRES"] == 0
×
1230
        assert mvlgwgbse1.incar["NBANDSO"] == 20
×
1231
        assert mvlgwgbse1.incar["ALGO"] == "BSE"
×
1232

1233

1234
class MPHSEBSTest(PymatgenTest):
×
1235
    def setUp(self):
×
1236
        self.tmp = tempfile.mkdtemp()
×
1237
        warnings.simplefilter("ignore")
×
1238

1239
    def tearDown(self):
×
1240
        warnings.simplefilter("default")
×
1241

1242
    def test_init(self):
×
1243
        prev_run = self.TEST_FILES_DIR / "static_silicon"
×
1244
        vis = MPHSEBSSet.from_prev_calc(prev_calc_dir=prev_run, mode="uniform")
×
1245
        assert vis.incar["LHFCALC"]
×
1246
        assert len(vis.kpoints.kpts) == 16
×
1247

1248
        vis = MPHSEBSSet.from_prev_calc(prev_calc_dir=prev_run, mode="gap")
×
1249
        assert vis.incar["LHFCALC"]
×
1250
        assert len(vis.kpoints.kpts) == 18
×
1251

1252
        vis = MPHSEBSSet.from_prev_calc(prev_calc_dir=prev_run, mode="line")
×
1253
        assert vis.incar["LHFCALC"]
×
1254
        assert vis.incar["HFSCREEN"] == 0.2
×
1255
        assert vis.incar["NSW"] == 0
×
1256
        assert vis.incar["ISYM"] == 3
×
1257
        assert len(vis.kpoints.kpts) == 180
×
1258

1259
        with pytest.warns(BadInputSetWarning, match=r"Hybrid functionals"):
×
1260
            vis = MPHSEBSSet(PymatgenTest.get_structure("Li2O"), user_incar_settings={"ALGO": "Fast"})
×
1261
            vis.incar.items()
×
1262

1263
    def test_override_from_prev_calc(self):
×
1264
        prev_run = self.TEST_FILES_DIR / "static_silicon"
×
1265
        vis = MPHSEBSSet(_dummy_structure, mode="uniform")
×
1266
        vis = vis.override_from_prev_calc(prev_calc_dir=prev_run)
×
1267
        assert vis.incar["LHFCALC"]
×
1268
        assert len(vis.kpoints.kpts) == 16
×
1269

1270
        vis = MPHSEBSSet(_dummy_structure, mode="gap")
×
1271
        vis = vis.override_from_prev_calc(prev_calc_dir=prev_run)
×
1272
        assert vis.incar["LHFCALC"]
×
1273
        assert len(vis.kpoints.kpts) == 18
×
1274

1275
        vis = MPHSEBSSet(_dummy_structure, mode="line")
×
1276
        vis = vis.override_from_prev_calc(prev_calc_dir=prev_run)
×
1277
        assert vis.incar["LHFCALC"]
×
1278
        assert vis.incar["HFSCREEN"] == 0.2
×
1279
        assert vis.incar["NSW"] == 0
×
1280
        assert vis.incar["ISYM"] == 3
×
1281
        assert len(vis.kpoints.kpts) == 180
×
1282

1283

1284
class MVLScanRelaxSetTest(PymatgenTest):
×
1285
    def setUp(self):
×
1286
        file_path = self.TEST_FILES_DIR / "POSCAR"
×
1287
        poscar = Poscar.from_file(file_path)
×
1288
        self.struct = poscar.structure
×
1289
        self.mvl_scan_set = MVLScanRelaxSet(
×
1290
            self.struct, user_potcar_functional="PBE_52", user_incar_settings={"NSW": 500}
1291
        )
1292
        warnings.simplefilter("ignore")
×
1293

1294
    def tearDown(self):
×
1295
        warnings.simplefilter("default")
×
1296

1297
    def test_incar(self):
×
1298
        incar = self.mvl_scan_set.incar
×
1299
        assert "METAGGA" in incar
×
1300
        assert "LASPH" in incar
×
1301
        assert "ADDGRID" in incar
×
1302
        assert incar["NSW"] == 500
×
1303

1304
        # Test SCAN+rVV10
1305
        scan_rvv10_set = MVLScanRelaxSet(self.struct, vdw="rVV10")
×
1306
        assert scan_rvv10_set.incar["BPARAM"] == 15.7
×
1307

1308
    def test_potcar(self):
×
1309
        assert self.mvl_scan_set.potcar.functional == "PBE_52"
×
1310

1311
        test_potcar_set_1 = MVLScanRelaxSet(self.struct, user_potcar_functional="PBE_54")
×
1312
        assert test_potcar_set_1.potcar.functional == "PBE_54"
×
1313

1314
        with pytest.raises(ValueError):
×
1315
            MVLScanRelaxSet(self.struct, user_potcar_functional="PBE")
×
1316

1317
    def test_as_from_dict(self):
×
1318
        d = self.mvl_scan_set.as_dict()
×
1319
        v = dec.process_decoded(d)
×
1320
        assert isinstance(v, MVLScanRelaxSet)
×
1321
        assert v._config_dict["INCAR"]["METAGGA"] == "SCAN"
×
1322
        assert v.user_incar_settings["NSW"] == 500
×
1323

1324

1325
class MPScanRelaxSetTest(PymatgenTest):
×
1326
    def setUp(self):
×
1327
        file_path = self.TEST_FILES_DIR / "POSCAR"
×
1328
        poscar = Poscar.from_file(file_path)
×
1329
        self.struct = poscar.structure
×
1330
        self.mp_scan_set = MPScanRelaxSet(
×
1331
            self.struct, user_potcar_functional="PBE_52", user_incar_settings={"NSW": 500}
1332
        )
1333
        warnings.simplefilter("ignore")
×
1334

1335
    def tearDown(self):
×
1336
        warnings.simplefilter("default")
×
1337

1338
    def test_incar(self):
×
1339
        incar = self.mp_scan_set.incar
×
1340
        assert incar["METAGGA"] == "R2scan"
×
1341
        assert incar["LASPH"] is True
×
1342
        assert incar["ENAUG"] == 1360
×
1343
        assert incar["ENCUT"] == 680
×
1344
        assert incar["NSW"] == 500
×
1345
        # the default POTCAR contains metals
1346
        assert incar["KSPACING"] == 0.22
×
1347
        assert incar["ISMEAR"] == 2
×
1348
        assert incar["SIGMA"] == 0.2
×
1349

1350
    def test_scan_substitute(self):
×
1351
        mp_scan_sub = MPScanRelaxSet(
×
1352
            self.struct,
1353
            user_potcar_functional="PBE_52",
1354
            user_incar_settings={"METAGGA": "SCAN"},
1355
        )
1356
        incar = mp_scan_sub.incar
×
1357
        assert incar["METAGGA"] == "Scan"
×
1358

1359
    def test_nonmetal(self):
×
1360
        # Test that KSPACING and ISMEAR change with a nonmetal structure
1361
        file_path = self.TEST_FILES_DIR / "POSCAR.O2"
×
1362
        struct = Poscar.from_file(file_path, check_for_POTCAR=False).structure
×
1363
        scan_nonmetal_set = MPScanRelaxSet(struct, bandgap=1.1)
×
1364
        incar = scan_nonmetal_set.incar
×
1365
        assert incar["KSPACING"] == approx(0.3064757, abs=1e-5)
×
1366
        assert incar["ISMEAR"] == -5
×
1367
        assert incar["SIGMA"] == 0.05
×
1368

1369
    def test_kspacing_cap(self):
×
1370
        # Test that KSPACING is capped at 0.44 for insulators
1371
        file_path = self.TEST_FILES_DIR / "POSCAR.O2"
×
1372
        struct = Poscar.from_file(file_path, check_for_POTCAR=False).structure
×
1373
        scan_nonmetal_set = MPScanRelaxSet(struct, bandgap=10)
×
1374
        incar = scan_nonmetal_set.incar
×
1375
        assert incar["KSPACING"] == approx(0.44, abs=1e-5)
×
1376
        assert incar["ISMEAR"] == -5
×
1377
        assert incar["SIGMA"] == 0.05
×
1378

1379
    def test_incar_overrides(self):
×
1380
        # use 'user_incar_settings' to override the KSPACING, ISMEAR, and SIGMA
1381
        # parameters that MPScanSet normally determines
1382
        mp_scan_set2 = MPScanRelaxSet(
×
1383
            self.struct,
1384
            user_incar_settings={"KSPACING": 0.5, "ISMEAR": 0, "SIGMA": 0.05},
1385
        )
1386
        incar = mp_scan_set2.incar
×
1387
        assert incar["KSPACING"] == 0.5
×
1388
        assert incar["ISMEAR"] == 0
×
1389
        assert incar["SIGMA"] == 0.05
×
1390

1391
    # Test SCAN+rVV10
1392
    def test_rvv10(self):
×
1393
        scan_rvv10_set = MPScanRelaxSet(self.struct, vdw="rVV10")
×
1394
        assert "LUSE_VDW" in scan_rvv10_set.incar
×
1395
        assert scan_rvv10_set.incar["BPARAM"] == 15.7
×
1396

1397
    def test_other_vdw(self):
×
1398
        # should raise a warning.
1399
        # IVDW key should not be present in the incar
1400
        with pytest.warns(UserWarning, match=r"not supported at this time"):
×
1401
            scan_vdw_set = MPScanRelaxSet(self.struct, vdw="DFTD3")
×
1402
            assert "LUSE_VDW" not in scan_vdw_set.incar
×
1403
            assert "IVDW" not in scan_vdw_set.incar
×
1404

1405
    def test_potcar(self):
×
1406
        assert self.mp_scan_set.potcar.functional == "PBE_52"
×
1407

1408
        # the default functional should be PBE_54
1409
        test_potcar_set_1 = MPScanRelaxSet(self.struct)
×
1410
        assert test_potcar_set_1.potcar.functional == "PBE_54"
×
1411

1412
        with pytest.raises(ValueError):
×
1413
            MPScanRelaxSet(self.struct, user_potcar_functional="PBE")
×
1414

1415
    def test_as_from_dict(self):
×
1416
        d = self.mp_scan_set.as_dict()
×
1417
        v = dec.process_decoded(d)
×
1418
        assert isinstance(v, MPScanRelaxSet)
×
1419
        assert v._config_dict["INCAR"]["METAGGA"] == "R2SCAN"
×
1420
        assert v.user_incar_settings["NSW"] == 500
×
1421

1422
    def test_write_input(self):
×
1423
        self.mp_scan_set.write_input(".")
×
1424
        assert os.path.exists("INCAR")
×
1425
        assert not os.path.exists("KPOINTS")
×
1426
        assert os.path.exists("POTCAR")
×
1427
        assert os.path.exists("POSCAR")
×
1428

1429
        for f in ["INCAR", "POSCAR", "POTCAR"]:
×
1430
            os.remove(f)
×
1431

1432

1433
class MPScanStaticSetTest(PymatgenTest):
×
1434
    def setUp(self):
×
1435
        self.tmp = tempfile.mkdtemp()
×
1436
        warnings.simplefilter("ignore")
×
1437

1438
    def test_init(self):
×
1439
        # test inheriting from a previous SCAN relaxation
1440
        prev_run = self.TEST_FILES_DIR / "scan_relaxation"
×
1441

1442
        vis = MPScanStaticSet.from_prev_calc(prev_calc_dir=prev_run)
×
1443
        # check that StaticSet settings were applied
1444
        assert vis.incar["NSW"] == 0
×
1445
        assert vis.incar["LREAL"] is False
×
1446
        assert vis.incar["LORBIT"] == 11
×
1447
        assert vis.incar["LVHAR"] is True
×
1448
        assert vis.incar["ISMEAR"] == -5
×
1449
        # Check that ENCUT and other INCAR settings were inherited.
1450
        assert vis.incar["ENCUT"] == 680
×
1451
        assert vis.incar["METAGGA"] == "R2scan"
×
1452
        assert vis.incar["KSPACING"] == 0.34292842
×
1453

1454
        # Check as from dict.
1455
        # check that StaticSet settings were applied
1456
        assert vis.incar["NSW"] == 0
×
1457
        assert vis.incar["LREAL"] is False
×
1458
        assert vis.incar["LORBIT"] == 11
×
1459
        assert vis.incar["LVHAR"] is True
×
1460
        # Check that ENCUT and KSPACING were inherited.
1461
        assert vis.incar["ENCUT"] == 680
×
1462
        assert vis.incar["METAGGA"] == "R2scan"
×
1463
        assert vis.incar["KSPACING"] == 0.34292842
×
1464

1465
        non_prev_vis = MPScanStaticSet(
×
1466
            vis.structure,
1467
            user_incar_settings={"ENCUT": 800, "LORBIT": 12, "LWAVE": True},
1468
        )
1469
        # check that StaticSet settings were applied
1470
        assert non_prev_vis.incar["NSW"] == 0
×
1471
        assert non_prev_vis.incar["LREAL"] is False
×
1472
        assert non_prev_vis.incar["LVHAR"] is True
×
1473
        assert vis.incar["ISMEAR"] == -5
×
1474
        # Check that ENCUT and other INCAR settings were inherited.
1475
        assert non_prev_vis.incar["METAGGA"] == "R2scan"
×
1476
        # the KSPACING will have the default value here, since no previous calc
1477
        assert non_prev_vis.incar["KSPACING"] == 0.22
×
1478
        # Check that user incar settings are applied.
1479
        assert non_prev_vis.incar["ENCUT"] == 800
×
1480
        assert non_prev_vis.incar["LORBIT"] == 12
×
1481
        assert non_prev_vis.incar["LWAVE"]
×
1482

1483
        v2 = MPScanStaticSet.from_dict(non_prev_vis.as_dict())
×
1484
        # Check that user incar settings are applied.
1485
        assert v2.incar["ENCUT"] == 800
×
1486
        assert v2.incar["LORBIT"] == 12
×
1487
        assert non_prev_vis.incar["LWAVE"]
×
1488

1489
        # Check LCALCPOL flag
1490
        lcalcpol_vis = MPScanStaticSet.from_prev_calc(prev_calc_dir=prev_run, lcalcpol=True)
×
1491
        assert lcalcpol_vis.incar["LCALCPOL"]
×
1492

1493
        # Check LEPSILON flag
1494
        lepsilon_vis = MPScanStaticSet.from_prev_calc(prev_calc_dir=prev_run, lepsilon=True)
×
1495
        assert lepsilon_vis.incar["LEPSILON"]
×
1496
        assert lepsilon_vis.incar["LPEAD"]
×
1497
        assert lepsilon_vis.incar["IBRION"] == 8
×
1498
        assert lepsilon_vis.incar.get("NSW") is None
×
1499
        assert lepsilon_vis.incar.get("NPAR") is None
×
1500

1501
    def test_override_from_prev_calc(self):
×
1502
        # test override_from_prev
1503
        prev_run = self.TEST_FILES_DIR / "scan_relaxation"
×
1504

1505
        vis = MPScanStaticSet(_dummy_structure)
×
1506
        vis.override_from_prev_calc(prev_calc_dir=prev_run)
×
1507
        # check that StaticSet settings were applied
1508
        assert vis.incar["NSW"] == 0
×
1509
        assert vis.incar["LREAL"] is False
×
1510
        assert vis.incar["LORBIT"] == 11
×
1511
        assert vis.incar["LVHAR"] is True
×
1512
        assert vis.incar["ISMEAR"] == -5
×
1513
        # Check that ENCUT and other INCAR settings were inherited.
1514
        assert vis.incar["ENCUT"] == 680
×
1515
        assert vis.incar["METAGGA"] == "R2scan"
×
1516
        assert vis.incar["KSPACING"] == 0.34292842
×
1517

1518
        # Check LCALCPOL flag
1519
        lcalcpol_vis = MPScanStaticSet(_dummy_structure, lcalcpol=True)
×
1520
        lcalcpol_vis = lcalcpol_vis.override_from_prev_calc(prev_calc_dir=prev_run)
×
1521
        assert lcalcpol_vis.incar["LCALCPOL"]
×
1522

1523
        # Check LEPSILON flag
1524
        lepsilon_vis = MPScanStaticSet(_dummy_structure, lepsilon=True)
×
1525
        lepsilon_vis = lepsilon_vis.override_from_prev_calc(prev_calc_dir=prev_run)
×
1526
        assert lepsilon_vis.incar["LEPSILON"]
×
1527
        assert lepsilon_vis.incar["LPEAD"]
×
1528
        assert lepsilon_vis.incar["IBRION"] == 8
×
1529
        assert lepsilon_vis.incar.get("NSW") is None
×
1530
        assert lepsilon_vis.incar.get("NPAR") is None
×
1531

1532
    def test_conflicting_arguments(self):
×
1533
        with pytest.raises(ValueError, match="deprecated"):
×
1534
            si = self.get_structure("Si")
×
1535
            MPScanStaticSet(si, potcar_functional="PBE", user_potcar_functional="PBE")
×
1536

1537
    def tearDown(self):
×
1538
        shutil.rmtree(self.tmp)
×
1539
        warnings.simplefilter("default")
×
1540

1541

1542
class FuncTest(PymatgenTest):
×
1543
    def test_batch_write_input(self):
×
1544
        structures = [
×
1545
            PymatgenTest.get_structure("Li2O"),
1546
            PymatgenTest.get_structure("LiFePO4"),
1547
        ]
1548
        batch_write_input(structures)
×
1549
        for d in ["Li4Fe4P4O16_1", "Li2O1_0"]:
×
1550
            for f in ["INCAR", "KPOINTS", "POSCAR", "POTCAR"]:
×
1551
                assert os.path.exists(os.path.join(d, f))
×
1552
        for d in ["Li4Fe4P4O16_1", "Li2O1_0"]:
×
1553
            shutil.rmtree(d)
×
1554

1555

1556
class MVLGBSetTest(PymatgenTest):
×
1557
    def setUp(self):
×
1558
        filepath = self.TEST_FILES_DIR / "Li.cif"
×
1559
        self.s = Structure.from_file(filepath)
×
1560

1561
        self.bulk = MVLGBSet(self.s)
×
1562
        self.slab = MVLGBSet(self.s, slab_mode=True)
×
1563

1564
        self.d_bulk = self.bulk.get_vasp_input()
×
1565
        self.d_slab = self.slab.get_vasp_input()
×
1566
        warnings.simplefilter("ignore")
×
1567

1568
    def tearDown(self):
×
1569
        warnings.simplefilter("default")
×
1570

1571
    def test_bulk(self):
×
1572
        incar_bulk = self.d_bulk["INCAR"]
×
1573
        assert incar_bulk["ISIF"] == 3
×
1574

1575
    def test_slab(self):
×
1576
        incar_slab = self.d_slab["INCAR"]
×
1577
        assert incar_slab["ISIF"] == 2
×
1578

1579
    def test_kpoints(self):
×
1580
        kpoints = self.d_slab["KPOINTS"]
×
1581
        k_a = int(40 / (self.s.lattice.abc[0]) + 0.5)
×
1582
        k_b = int(40 / (self.s.lattice.abc[1]) + 0.5)
×
1583
        assert kpoints.kpts == [[k_a, k_b, 1]]
×
1584

1585

1586
class MVLRelax52SetTest(PymatgenTest):
×
1587
    def setUp(self):
×
1588
        file_path = self.TEST_FILES_DIR / "POSCAR"
×
1589
        poscar = Poscar.from_file(file_path)
×
1590
        self.struct = poscar.structure
×
1591
        self.mvl_rlx_set = MVLRelax52Set(self.struct, user_potcar_functional="PBE_54", user_incar_settings={"NSW": 500})
×
1592
        warnings.simplefilter("ignore")
×
1593

1594
    def tearDown(self):
×
1595
        warnings.simplefilter("default")
×
1596

1597
    def test_incar(self):
×
1598
        incar = self.mvl_rlx_set.incar
×
1599
        assert "NSW" in incar
×
1600
        assert incar["LREAL"] == "Auto"
×
1601

1602
    def test_potcar(self):
×
1603
        assert self.mvl_rlx_set.potcar.functional == "PBE_54"
×
1604
        assert "Fe" in self.mvl_rlx_set.potcar.symbols
×
1605

1606
        self.struct.remove_species(["Fe"])
×
1607
        test_potcar_set_1 = MVLRelax52Set(self.struct, user_potcar_functional="PBE_52")
×
1608
        assert test_potcar_set_1.potcar.functional == "PBE_52"
×
1609

1610
        with pytest.raises(ValueError):
×
1611
            MVLRelax52Set(self.struct, user_potcar_functional="PBE")
×
1612

1613
    def test_potcar_functional_warning(self):
×
1614
        with pytest.warns(FutureWarning, match="argument is deprecated"):
×
1615
            MVLRelax52Set(self.struct, potcar_functional="PBE_52")
×
1616

1617
    def test_as_from_dict(self):
×
1618
        d = self.mvl_rlx_set.as_dict()
×
1619
        v = dec.process_decoded(d)
×
1620
        assert isinstance(v, MVLRelax52Set)
×
1621
        assert v.incar["NSW"] == 500
×
1622

1623

1624
class LobsterSetTest(PymatgenTest):
×
1625
    def setUp(self):
×
1626
        file_path = self.TEST_FILES_DIR / "POSCAR"
×
1627
        poscar = Poscar.from_file(file_path)
×
1628
        self.struct = poscar.structure
×
1629
        # test for different parameters!
1630
        self.lobsterset1 = LobsterSet(self.struct, isym=-1, ismear=-5)
×
1631
        self.lobsterset2 = LobsterSet(self.struct, isym=0, ismear=0)
×
1632
        # only allow isym=-1 and isym=0
1633
        with pytest.raises(ValueError):
×
1634
            self.lobsterset_new = LobsterSet(self.struct, isym=2, ismear=0)
×
1635
        # only allow ismear=-5 and ismear=0
1636
        with pytest.raises(ValueError):
×
1637
            self.lobsterset_new = LobsterSet(self.struct, isym=-1, ismear=2)
×
1638
        # test if one can still hand over grid density of kpoints
1639
        self.lobsterset3 = LobsterSet(self.struct, isym=0, ismear=0, user_kpoints_settings={"grid_density": 6000})
×
1640
        # check if users can overwrite settings in this class with the help of user_incar_settings
1641
        self.lobsterset4 = LobsterSet(self.struct, user_incar_settings={"ALGO": "Fast"})
×
1642
        # use basis functions supplied by user
1643
        self.lobsterset5 = LobsterSet(
×
1644
            self.struct,
1645
            user_supplied_basis={"Fe": "3d 3p 4s", "P": "3p 3s", "O": "2p 2s"},
1646
        )
1647
        with pytest.raises(ValueError):
×
1648
            self.lobsterset6 = LobsterSet(self.struct, user_supplied_basis={"Fe": "3d 3p 4s", "P": "3p 3s"})
×
1649
        self.lobsterset7 = LobsterSet(
×
1650
            self.struct,
1651
            address_basis_file=os.path.join(MODULE_DIR, "../../lobster/lobster_basis/BASIS_PBE_54_standard.yaml"),
1652
        )
1653
        with pytest.warns(BadInputSetWarning, match="Overriding the POTCAR"):
×
1654
            self.lobsterset6 = LobsterSet(self.struct)
×
1655

1656
        # test W_sw
1657
        self.lobsterset8 = LobsterSet(Structure.from_file(os.path.join(self.TEST_FILES_DIR, "cohp", "POSCAR.W")))
×
1658

1659
    def test_incar(self):
×
1660
        incar1 = self.lobsterset1.incar
×
1661
        assert "NBANDS" in incar1
×
1662
        assert incar1["NBANDS"] == 116
×
1663
        assert incar1["NSW"] == 0
×
1664
        assert incar1["ISMEAR"] == -5
×
1665
        assert incar1["ISYM"] == -1
×
1666
        assert incar1["ALGO"] == "Normal"
×
1667
        assert incar1["EDIFF"] == 1e-6
×
1668
        incar2 = self.lobsterset2.incar
×
1669
        assert incar2["ISYM"] == 0
×
1670
        assert incar2["ISMEAR"] == 0
×
1671
        incar4 = self.lobsterset4.incar
×
1672
        assert incar4["ALGO"] == "Fast"
×
1673

1674
    def test_kpoints(self):
×
1675
        kpoints1 = self.lobsterset1.kpoints
×
1676
        assert kpoints1.comment.split(" ")[6], 6138
×
1677
        kpoints2 = self.lobsterset2.kpoints
×
1678
        assert kpoints2.comment.split(" ")[6], 6138
×
1679
        kpoints3 = self.lobsterset3.kpoints
×
1680
        assert kpoints3.comment.split(" ")[6], 6000
×
1681

1682
    def test_potcar(self):
×
1683
        # PBE_54 is preferred at the moment
1684
        assert self.lobsterset1.potcar_functional == "PBE_54"
×
1685

1686
    def test_as_from_dict(self):
×
1687
        dict_here = self.lobsterset1.as_dict()
×
1688

1689
        lobsterset_new = LobsterSet.from_dict(dict_here)
×
1690
        # test relevant parts again
1691
        incar1 = lobsterset_new.incar
×
1692
        assert "NBANDS" in incar1
×
1693
        assert incar1["NBANDS"] == 116
×
1694
        assert incar1["NSW"] == 0
×
1695
        assert incar1["NSW"] == 0
×
1696
        assert incar1["ISMEAR"] == -5
×
1697
        assert incar1["ISYM"] == -1
×
1698
        assert incar1["ALGO"] == "Normal"
×
1699
        kpoints1 = lobsterset_new.kpoints
×
1700
        assert kpoints1.comment.split(" ")[6], 6138
×
1701
        assert lobsterset_new.potcar_functional == "PBE_54"
×
1702

1703

1704
class MPAbsorptionSetTest(PymatgenTest):
×
1705
    def setUp(self):
×
1706
        self.tmp = tempfile.mkdtemp()
×
1707
        file_path = self.TEST_FILES_DIR / "absorption/static/POSCAR"
×
1708
        poscar = Poscar.from_file(file_path)
×
1709
        self.structure = poscar.structure
×
1710
        warnings.simplefilter("ignore")
×
1711

1712
    def tearDown(self):
×
1713
        warnings.simplefilter("default")
×
1714
        shutil.rmtree(self.tmp)
×
1715

1716
    def test_ipa(self):
×
1717
        prev_run = self.TEST_FILES_DIR / "absorption/static"
×
1718
        absorptionipa = MPAbsorptionSet.from_prev_calc(prev_calc_dir=prev_run, copy_wavecar=True, mode="IPA")
×
1719
        absorptionipa.write_input(self.tmp)
×
1720
        assert os.path.exists(os.path.join(self.tmp, "WAVECAR"))
×
1721
        assert absorptionipa.incar["NBANDS"] == 32
×
1722
        assert absorptionipa.incar["ALGO"] == "Exact"
×
1723
        assert absorptionipa.incar["LOPTICS"]
×
1724

1725
        # test override_from_prev_calc
1726
        absorptionipa = MPAbsorptionSet(_dummy_structure, copy_wavecar=True, mode="IPA")
×
1727
        absorptionipa.override_from_prev_calc(prev_calc_dir=prev_run)
×
1728
        absorptionipa.write_input(self.tmp)
×
1729
        assert os.path.exists(os.path.join(self.tmp, "WAVECAR"))
×
1730
        assert absorptionipa.incar["NBANDS"] == 32
×
1731
        assert absorptionipa.incar["ALGO"] == "Exact"
×
1732
        assert absorptionipa.incar["LOPTICS"]
×
1733

1734
    def test_rpa(self):
×
1735
        prev_run = self.TEST_FILES_DIR / "absorption/ipa"
×
1736
        absorptionrpa = MPAbsorptionSet.from_prev_calc(prev_run, copy_wavecar=True, mode="RPA")
×
1737
        absorptionrpa.write_input(self.tmp)
×
1738
        assert os.path.exists(os.path.join(self.tmp, "WAVECAR"))
×
1739
        assert os.path.exists(os.path.join(self.tmp, "WAVEDER"))
×
1740
        assert absorptionrpa.incar["NOMEGA"] == 1000
×
1741
        assert absorptionrpa.incar["NBANDS"] == 48
×
1742
        assert absorptionrpa.incar["ALGO"] == "CHI"
×
1743

1744
        # test override_from_prev_calc
1745
        prev_run = self.TEST_FILES_DIR / "absorption/ipa"
×
1746
        absorptionrpa = MPAbsorptionSet(_dummy_structure, copy_wavecar=True, mode="RPA")
×
1747
        absorptionrpa.override_from_prev_calc(prev_calc_dir=prev_run)
×
1748
        absorptionrpa.write_input(self.tmp)
×
1749
        assert os.path.exists(os.path.join(self.tmp, "WAVECAR"))
×
1750
        assert os.path.exists(os.path.join(self.tmp, "WAVEDER"))
×
1751
        assert absorptionrpa.incar["NOMEGA"] == 1000
×
1752
        assert absorptionrpa.incar["NBANDS"] == 48
×
1753
        assert absorptionrpa.incar["ALGO"] == "CHI"
×
1754

1755

1756
_dummy_structure = Structure(
×
1757
    [1, 0, 0, 0, 1, 0, 0, 0, 1],
1758
    ["I"],
1759
    [[0, 0, 0]],
1760
    site_properties={"magmom": [[0, 0, 1]]},
1761
)
1762

1763
if __name__ == "__main__":
×
1764
    unittest.main()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc