1from io import StringIO 2 3import numpy as np 4import pytest 5 6from ase.io import read, write 7from ase.build import bulk 8from ase.calculators.calculator import compare_atoms 9from ase.io.abinit import read_abinit_out, read_eig, match_kpt_header 10from ase.units import Hartree, Bohr 11 12 13def test_abinit_inputfile_roundtrip(testdir): 14 m1 = bulk('Ti') 15 m1.set_initial_magnetic_moments(range(len(m1))) 16 write('abinit_save.in', images=m1, format='abinit-in') 17 m2 = read('abinit_save.in', format='abinit-in') 18 19 # (How many decimals?) 20 assert not compare_atoms(m1, m2, tol=1e-7) 21 22 23# "Hand-written" (reduced) abinit txt file based on v8.0.8 format: 24sample_outfile = """\ 25 26.Version 8.0.8 of ABINIT 27 28 -outvars: echo values of preprocessed input variables -------- 29 natom 2 30 ntypat 1 31 rprim 5.0 0.0 0.1 32 0.0 6.0 0.0 33 0.0 0.0 7.0 34 typat 1 1 35 znucl 8.0 36 37================================ 38 39 ----iterations are completed or convergence reached---- 40 41 cartesian coordinates (angstrom) at end: 42 1 2.5 2.5 3.7 43 2 2.5 2.5 2.5 44 45 cartesian forces (eV/Angstrom) at end: 46 1 -0.1 -0.3 0.4 47 2 -0.2 -0.4 -0.5 48 49 Components of total free energy (in Hartree) : 50 51 >>>>>>>>> Etotal= -42.5 52 53 Cartesian components of stress tensor (hartree/bohr^3) 54 sigma(1 1)= 2.3 sigma(3 2)= 3.1 55 sigma(2 2)= 2.4 sigma(3 1)= 3.2 56 sigma(3 3)= 2.5 sigma(2 1)= 3.3 57 58END DATASET(S) 59""" 60 61 62def test_read_abinit_output(): 63 fd = StringIO(sample_outfile) 64 results = read_abinit_out(fd) 65 66 assert results.pop('version') == '8.0.8' 67 68 atoms = results.pop('atoms') 69 assert all(atoms.symbols == 'OO') 70 assert atoms.positions == pytest.approx( 71 np.array([[2.5, 2.5, 3.7], [2.5, 2.5, 2.5]])) 72 assert all(atoms.pbc) 73 assert atoms.cell[:] == pytest.approx( 74 np.array([[5.0, 0.0, 0.1], [0.0, 6.0, 0.0], [0.0, 0.0, 7.0]])) 75 76 ref_stress = pytest.approx([2.3, 2.4, 2.5, 3.1, 3.2, 3.3]) 77 assert results.pop('stress') / (Hartree / Bohr**3) == ref_stress 78 assert results.pop('forces') == pytest.approx( 79 np.array([[-0.1, -0.3, 0.4], [-0.2, -0.4, -0.5]])) 80 81 for name in 'energy', 'free_energy': 82 assert results.pop(name) / Hartree == -42.5 83 84 assert not results 85 86 87eig_text = """\ 88 Fermi (or HOMO) energy (hartree) = 0.123 Average Vxc (hartree)= -0.456 89 Eigenvalues (hartree) for nkpt= 2 k points: 90 kpt# 1, nband= 3, wtk= 0.1, kpt= 0.2 0.3 0.4 (reduced coord) 91 -0.2 0.2 0.3 92 kpt# 2, nband= 3, wtk= 0.2, kpt= 0.3 0.4 0.5 (reduced coord) 93 -0.3 0.4 0.5 94""" 95 96 97def test_parse_eig_with_fermiheader(): 98 eigval_ref = np.array([ 99 [-0.2, 0.2, 0.3], 100 [-0.3, 0.4, 0.5] 101 ]).reshape(1, 2, 3) # spin x kpts x bands 102 103 kpts_ref = np.array([ 104 [0.2, 0.3, 0.4], 105 [0.3, 0.4, 0.5] 106 ]) 107 108 weights_ref = [0.1, 0.2] 109 110 eig_buf = StringIO(eig_text) 111 data = read_eig(eig_buf) 112 113 assert data['eigenvalues'] / Hartree == pytest.approx(eigval_ref) 114 assert data['ibz_kpoints'] == pytest.approx(kpts_ref) 115 assert data['kpoint_weights'] == pytest.approx(weights_ref) 116 assert data['fermilevel'] / Hartree == pytest.approx(0.123) 117 118 119def test_parse_eig_without_fermiheader(): 120 fd = StringIO(eig_text) 121 next(fd) # Header is omitted e.g. in non-selfconsistent calculations. 122 123 data = read_eig(fd) 124 assert 'fermilevel' not in data 125 assert {'eigenvalues', 'ibz_kpoints', 'kpoint_weights'} == set(data) 126 127 128def test_match_kpt_header(): 129 header_line = """\ 130kpt# 12, nband= 5, wtk= 0.02778, \ 131kpt= 0.4167 0.4167 0.0833 (reduced coord) 132""" 133 134 nbands, weight, vector = match_kpt_header(header_line) 135 assert nbands == 5 136 assert weight == pytest.approx(0.02778) 137 assert vector == pytest.approx([0.4167, 0.4167, 0.0833]) 138