File: nwreader_in.py

package info (click to toggle)
python-ase 3.21.1-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 13,936 kB
  • sloc: python: 122,428; xml: 946; makefile: 111; javascript: 47
file content (135 lines) | stat: -rw-r--r-- 4,511 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import re

import numpy as np

from ase import Atoms
from ase.geometry import cellpar_to_cell
from .parser import _define_pattern

# Geometry block parser
_geom = _define_pattern(
    r'^[ \t]*geometry[ \t\S]*\n'
    r'((?:^[ \t]*[\S]+[ \t\S]*\n)+)'
    r'^[ \t]*end\n\n',
    """\
geometry units angstrom nocenter noautosym noautoz
  system crystal units angstrom
    lattice_vectors
      4.0000000000000000e+00 0.0000000000000000e+00 0.0000000000000000e+00
      0.0000000000000000e+00 5.5264780000000000e+00 0.0000000000000000e+00
      0.0000000000000000e+00 0.0000000000000000e+00 4.5963089999999998e+00
  end
   O 5.0000000000000000e-01 5.0000000000000011e-01 5.6486824536818558e-01
   H 5.0000000000000000e-01 6.3810586054988372e-01 4.3513175463181430e-01
   H 5.0000000000000000e-01 3.6189413945011639e-01 4.3513175463181430e-01
end

""", re.M)

# Finds crystal specification
_crystal = _define_pattern(
    r'^[ \t]*system crystal[ \t\S]*\n'
    r'((?:[ \t]*[\S]+[ \t\S]*\n)+?)'
    r'^[ \t]*end[ \t]*\n',
    """\
  system crystal units angstrom
    lattice_vectors
      4.0000000000000000e+00 0.0000000000000000e+00 0.0000000000000000e+00
      0.0000000000000000e+00 5.5264780000000000e+00 0.0000000000000000e+00
      0.0000000000000000e+00 0.0000000000000000e+00 4.5963089999999998e+00
  end
""", re.M)

# Finds 3d-periodic unit cell
_cell_3d = _define_pattern(
    r'^[ \t]*lattice_vectors[ \t]*\n'
    r'^((?:(?:[ \t]+[\S]+){3}\n){3})',
    """\
    lattice_vectors
      4.0000000000000000e+00 0.0000000000000000e+00 0.0000000000000000e+00
      0.0000000000000000e+00 5.5264780000000000e+00 0.0000000000000000e+00
      0.0000000000000000e+00 0.0000000000000000e+00 4.5963089999999998e+00
""", re.M)

# Extracts chemical species from a geometry block
_species = _define_pattern(
    r'^[ \t]*[A-Z][a-z]?(?:[ \t]+[\S]+){3}\n',
    "   O 0.0 0.0 0.0\n", re.M,
)


def read_nwchem_in(fobj, index=-1):
    text = ''.join(fobj.readlines())
    atomslist = []
    for match in _geom.findall(text):
        symbols = []
        positions = []
        for atom in _species.findall(match):
            atom = atom.split()
            symbols.append(atom[0])
            positions.append([float(x) for x in atom[1:]])
        positions = np.array(positions)
        atoms = Atoms(symbols)
        cell, pbc = _get_cell(text)
        pos = np.zeros_like(positions)
        for dim, ipbc in enumerate(pbc):
            if ipbc:
                pos += np.outer(positions[:, dim], cell[dim, :])
            else:
                pos[:, dim] = positions[:, dim]
        atoms.set_cell(cell)
        atoms.pbc = pbc
        atoms.set_positions(pos)
        atomslist.append(atoms)
    return atomslist[index]


def _get_cell(text):
    # first check whether there is a lattice definition
    cell = np.zeros((3, 3))
    lattice = _cell_3d.findall(text)
    if lattice:
        pbc = [True, True, True]
        for i, row in enumerate(lattice[0].strip().split('\n')):
            cell[i] = [float(x) for x in row.split()]
        return cell, pbc
    pbc = [False, False, False]
    lengths = [None, None, None]
    angles = [None, None, None]
    for row in text.strip().split('\n'):
        row = row.strip().lower()
        for dim, vecname in enumerate(['a', 'b', 'c']):
            if row.startswith('lat_{}'.format(vecname)):
                pbc[dim] = True
                lengths[dim] = float(row.split()[1])
        for i, angle in enumerate(['alpha', 'beta', 'gamma']):
            if row.startswith(angle):
                angles[i] = float(row.split()[1])

    if not np.any(pbc):
        return None, pbc

    for i in range(3):
        a, b, c = np.roll(np.array([0, 1, 2]), i)
        if pbc[a] and pbc[b]:
            assert angles[c] is not None
        if angles[c] is not None:
            assert pbc[a] and pbc[b]

    # The easiest case: all three lattice vectors and angles are specified
    if np.all(pbc):
        return cellpar_to_cell(lengths + angles), pbc

    # Next easiest case: exactly one lattice vector has been specified
    if np.sum(pbc) == 1:
        dim = np.argmax(pbc)
        cell[dim, dim] = lengths[dim]
        return cell, pbc

    # Hardest case: two lattice vectors are specified.
    dim1, dim2 = [dim for dim, ipbc in enumerate(pbc) if ipbc]
    angledim = np.argmin(pbc)
    cell[dim1, dim1] = lengths[dim1]
    cell[dim2, dim2] = lengths[dim2] * np.sin(angles[angledim])
    cell[dim2, dim1] = lengths[dim2] * np.cos(angles[angledim])
    return cell, pbc