fennol.utils.io

  1import time
  2import numpy as np
  3from . import cell_vectors_to_lengths_angles, parse_cell
  4
  5def xyz_reader(
  6    filename,
  7    has_comment_line=True,
  8    indexed=False,
  9    start=1,
 10    stop=-1,
 11    step=1,
 12    max_frames=None,
 13    stream=False,
 14    interval=2.0,
 15    sleep=time.sleep,
 16):
 17    if stop > 0 and start > stop:
 18        return
 19    pf = open(filename, "r")
 20    inside_frame = False
 21    nat_read = False
 22    iframe = 0
 23    stride = step
 24    nframes = 0
 25    if start > 1:
 26        print(f"skipping {start-1} frames")
 27    if not has_comment_line:
 28        comment_line = ""
 29    while True:
 30        line = pf.readline()
 31
 32        if not line:
 33            if stream:
 34                sleep(interval)
 35                continue
 36            elif inside_frame or nat_read:
 37                raise Exception("Error: premature end of file!")
 38            else:
 39                break
 40
 41        line = line.strip()
 42
 43        if not inside_frame:
 44            if not nat_read:
 45                if line.startswith("#") or line == "":
 46                    continue
 47                nat = int(line.split()[0])
 48                nat_read = True
 49                iat = 0
 50                at_count = 0
 51                inside_frame = not has_comment_line
 52                xyz = np.zeros((nat, 3))
 53                symbols = []
 54                continue
 55
 56            # box = np.array(line.split(), dtype="float")
 57            comment_line = line
 58            inside_frame = True
 59            continue
 60
 61        if line.startswith("#") or line == "":
 62            raise Exception("Error: premature end of frame!")
 63
 64        if not nat_read:
 65            raise Exception("Error: nat not read!")
 66        ls = line.split()
 67        at_count += 1
 68        try:
 69            iat,s = (int(ls[0]),1)
 70            indexed = True
 71        except ValueError:
 72            if indexed:
 73                raise Exception("Error: line does not start with an integer index!")
 74            iat, s = (iat+1, 0)
 75        # iat, s = (int(ls[0]), 1) if indexed else (iat + 1, 0)
 76        symbols.append(ls[s])
 77        xyz[iat - 1, :] = np.array([ls[s + 1], ls[s + 2], ls[s + 3]], dtype="float")
 78        if at_count == nat:
 79            iframe += 1
 80            inside_frame = False
 81            nat_read = False
 82            if iframe < start:
 83                continue
 84            stride += 1
 85            if stride >= step:
 86                nframes += 1
 87                stride = 0
 88                yield symbols, xyz, comment_line
 89            if (max_frames is not None and nframes >= max_frames) or (
 90                stop > 0 and iframe >= stop
 91            ):
 92                break
 93
 94
 95def read_xyz(
 96    filename,
 97    has_comment_line=True,
 98    indexed=False,
 99    start=1,
100    stop=-1,
101    step=1,
102    max_frames=None,
103):
104    return [
105        frame
106        for frame in xyz_reader(
107            filename, has_comment_line, indexed, start, stop, step, max_frames
108        )
109    ]
110
111
112def last_xyz_frame(filename, has_comment_line=True, indexed=False):
113    last_frame = None
114    for frame in xyz_reader(
115        filename, has_comment_line, indexed, start=-1, stop=-1, step=1, max_frames=1
116    ):
117        last_frame = frame
118    return last_frame
119
120
121def write_arc_frame(
122    f,
123    symbols,
124    coordinates,
125    types=None,
126    nbonds=None,
127    connectivity=None,
128    cell=None,
129    **kwargs,
130):
131    nat = len(symbols)
132    f.write(f"{nat}\n")
133    if cell is not None:
134        box = cell_vectors_to_lengths_angles(parse_cell(cell))
135        f.write(" ".join([f"{x: 15.5f}" for x in box]) + "\n")
136    # f.write(f'{axis} {axis} {axis} 90.0 90.0 90.0 \n')
137    for i in range(nat):
138        line = f"{i+1} {symbols[i]:3} {coordinates[i,0]: 15.3f} {coordinates[i,1]: 15.3f} {coordinates[i,2]: 15.3f}"
139        if types is not None:
140            line += f"   {types[i]}"
141        if connectivity is not None and nbonds is not None:
142            line += "  " + " ".join([str(x + 1) for x in connectivity[i, : nbonds[i]]])
143        f.write(line + "\n")
144    f.flush()
145
146
147def write_extxyz_frame(
148    f, symbols, coordinates, cell=None, properties={}, forces=None, **kwargs
149):
150    nat = len(symbols)
151    f.write(f"{nat}\n")
152    comment_line = ""
153    if cell is not None:
154        cell = parse_cell(cell)
155        comment_line += (
156            'Lattice="' + " ".join([f"{x:.3f}" for x in cell.flatten()]) + '" '
157        )
158    comment_line += "Properties=species:S:1:pos:R:3"
159    if forces is not None:
160        comment_line += ":forces:R:3"
161    comment_line += " "
162    for k, v in properties.items():
163        comment_line += f"{k}={v} "
164    f.write(f"{comment_line}\n")
165    for i in range(nat):
166        line = f"{symbols[i]:3} {coordinates[i,0]: 15.5e} {coordinates[i,1]: 15.5e} {coordinates[i,2]: 15.5e}"
167        if forces is not None:
168            line += f" {forces[i,0]: 15.5e} {forces[i,1]: 15.5e} {forces[i,2]: 15.5e}"
169        f.write(f"{line}\n")
170    f.flush()
171
172
173def write_xyz_frame(f, symbols, coordinates,cell=None, **kwargs):
174    nat = len(symbols)
175    f.write(f"{nat}\n")
176    if cell is not None:
177        box = cell_vectors_to_lengths_angles(parse_cell(cell))
178        f.write(" ".join([f"{x:.3f}" for x in box]))
179    f.write("\n")
180    for i in range(nat):
181        f.write(
182            f"{symbols[i]:3} {coordinates[i,0]: 15.5e} {coordinates[i,1]: 15.5e} {coordinates[i,2]: 15.5e}\n"
183        )
184    f.flush()
185
186
187def human_time_duration(seconds: float):
188    """Convert seconds (duration) to human readable string
189
190    from https://gist.github.com/borgstrom/936ca741e885a1438c374824efb038b3
191    """
192
193    if seconds < 1.0:
194        return f"{seconds*1000:.3g} ms"
195    if seconds < 10.0:
196        return f"{seconds:.3g} s"
197
198    TIME_DURATION_UNITS = (
199        ("week", "s", 60 * 60 * 24 * 7),
200        ("day", "s", 60 * 60 * 24),
201        ("h", "", 60 * 60),
202        ("min", "", 60),
203        ("s", "", 1),
204    )
205    parts = []
206    for unit, plur, div in TIME_DURATION_UNITS:
207        amount, seconds = divmod(int(seconds), div)
208        if amount > 0:
209            parts.append(f"{amount} {unit}{plur if amount > 1 else ''}")
210    return " ".join(parts)
def xyz_reader( filename, has_comment_line=True, indexed=False, start=1, stop=-1, step=1, max_frames=None, stream=False, interval=2.0, sleep=<built-in function sleep>):
 6def xyz_reader(
 7    filename,
 8    has_comment_line=True,
 9    indexed=False,
10    start=1,
11    stop=-1,
12    step=1,
13    max_frames=None,
14    stream=False,
15    interval=2.0,
16    sleep=time.sleep,
17):
18    if stop > 0 and start > stop:
19        return
20    pf = open(filename, "r")
21    inside_frame = False
22    nat_read = False
23    iframe = 0
24    stride = step
25    nframes = 0
26    if start > 1:
27        print(f"skipping {start-1} frames")
28    if not has_comment_line:
29        comment_line = ""
30    while True:
31        line = pf.readline()
32
33        if not line:
34            if stream:
35                sleep(interval)
36                continue
37            elif inside_frame or nat_read:
38                raise Exception("Error: premature end of file!")
39            else:
40                break
41
42        line = line.strip()
43
44        if not inside_frame:
45            if not nat_read:
46                if line.startswith("#") or line == "":
47                    continue
48                nat = int(line.split()[0])
49                nat_read = True
50                iat = 0
51                at_count = 0
52                inside_frame = not has_comment_line
53                xyz = np.zeros((nat, 3))
54                symbols = []
55                continue
56
57            # box = np.array(line.split(), dtype="float")
58            comment_line = line
59            inside_frame = True
60            continue
61
62        if line.startswith("#") or line == "":
63            raise Exception("Error: premature end of frame!")
64
65        if not nat_read:
66            raise Exception("Error: nat not read!")
67        ls = line.split()
68        at_count += 1
69        try:
70            iat,s = (int(ls[0]),1)
71            indexed = True
72        except ValueError:
73            if indexed:
74                raise Exception("Error: line does not start with an integer index!")
75            iat, s = (iat+1, 0)
76        # iat, s = (int(ls[0]), 1) if indexed else (iat + 1, 0)
77        symbols.append(ls[s])
78        xyz[iat - 1, :] = np.array([ls[s + 1], ls[s + 2], ls[s + 3]], dtype="float")
79        if at_count == nat:
80            iframe += 1
81            inside_frame = False
82            nat_read = False
83            if iframe < start:
84                continue
85            stride += 1
86            if stride >= step:
87                nframes += 1
88                stride = 0
89                yield symbols, xyz, comment_line
90            if (max_frames is not None and nframes >= max_frames) or (
91                stop > 0 and iframe >= stop
92            ):
93                break
def read_xyz( filename, has_comment_line=True, indexed=False, start=1, stop=-1, step=1, max_frames=None):
 96def read_xyz(
 97    filename,
 98    has_comment_line=True,
 99    indexed=False,
100    start=1,
101    stop=-1,
102    step=1,
103    max_frames=None,
104):
105    return [
106        frame
107        for frame in xyz_reader(
108            filename, has_comment_line, indexed, start, stop, step, max_frames
109        )
110    ]
def last_xyz_frame(filename, has_comment_line=True, indexed=False):
113def last_xyz_frame(filename, has_comment_line=True, indexed=False):
114    last_frame = None
115    for frame in xyz_reader(
116        filename, has_comment_line, indexed, start=-1, stop=-1, step=1, max_frames=1
117    ):
118        last_frame = frame
119    return last_frame
def write_arc_frame( f, symbols, coordinates, types=None, nbonds=None, connectivity=None, cell=None, **kwargs):
122def write_arc_frame(
123    f,
124    symbols,
125    coordinates,
126    types=None,
127    nbonds=None,
128    connectivity=None,
129    cell=None,
130    **kwargs,
131):
132    nat = len(symbols)
133    f.write(f"{nat}\n")
134    if cell is not None:
135        box = cell_vectors_to_lengths_angles(parse_cell(cell))
136        f.write(" ".join([f"{x: 15.5f}" for x in box]) + "\n")
137    # f.write(f'{axis} {axis} {axis} 90.0 90.0 90.0 \n')
138    for i in range(nat):
139        line = f"{i+1} {symbols[i]:3} {coordinates[i,0]: 15.3f} {coordinates[i,1]: 15.3f} {coordinates[i,2]: 15.3f}"
140        if types is not None:
141            line += f"   {types[i]}"
142        if connectivity is not None and nbonds is not None:
143            line += "  " + " ".join([str(x + 1) for x in connectivity[i, : nbonds[i]]])
144        f.write(line + "\n")
145    f.flush()
def write_extxyz_frame( f, symbols, coordinates, cell=None, properties={}, forces=None, **kwargs):
148def write_extxyz_frame(
149    f, symbols, coordinates, cell=None, properties={}, forces=None, **kwargs
150):
151    nat = len(symbols)
152    f.write(f"{nat}\n")
153    comment_line = ""
154    if cell is not None:
155        cell = parse_cell(cell)
156        comment_line += (
157            'Lattice="' + " ".join([f"{x:.3f}" for x in cell.flatten()]) + '" '
158        )
159    comment_line += "Properties=species:S:1:pos:R:3"
160    if forces is not None:
161        comment_line += ":forces:R:3"
162    comment_line += " "
163    for k, v in properties.items():
164        comment_line += f"{k}={v} "
165    f.write(f"{comment_line}\n")
166    for i in range(nat):
167        line = f"{symbols[i]:3} {coordinates[i,0]: 15.5e} {coordinates[i,1]: 15.5e} {coordinates[i,2]: 15.5e}"
168        if forces is not None:
169            line += f" {forces[i,0]: 15.5e} {forces[i,1]: 15.5e} {forces[i,2]: 15.5e}"
170        f.write(f"{line}\n")
171    f.flush()
def write_xyz_frame(f, symbols, coordinates, cell=None, **kwargs):
174def write_xyz_frame(f, symbols, coordinates,cell=None, **kwargs):
175    nat = len(symbols)
176    f.write(f"{nat}\n")
177    if cell is not None:
178        box = cell_vectors_to_lengths_angles(parse_cell(cell))
179        f.write(" ".join([f"{x:.3f}" for x in box]))
180    f.write("\n")
181    for i in range(nat):
182        f.write(
183            f"{symbols[i]:3} {coordinates[i,0]: 15.5e} {coordinates[i,1]: 15.5e} {coordinates[i,2]: 15.5e}\n"
184        )
185    f.flush()
def human_time_duration(seconds: float):
188def human_time_duration(seconds: float):
189    """Convert seconds (duration) to human readable string
190
191    from https://gist.github.com/borgstrom/936ca741e885a1438c374824efb038b3
192    """
193
194    if seconds < 1.0:
195        return f"{seconds*1000:.3g} ms"
196    if seconds < 10.0:
197        return f"{seconds:.3g} s"
198
199    TIME_DURATION_UNITS = (
200        ("week", "s", 60 * 60 * 24 * 7),
201        ("day", "s", 60 * 60 * 24),
202        ("h", "", 60 * 60),
203        ("min", "", 60),
204        ("s", "", 1),
205    )
206    parts = []
207    for unit, plur, div in TIME_DURATION_UNITS:
208        amount, seconds = divmod(int(seconds), div)
209        if amount > 0:
210            parts.append(f"{amount} {unit}{plur if amount > 1 else ''}")
211    return " ".join(parts)

Convert seconds (duration) to human readable string

from https://gist.github.com/borgstrom/936ca741e885a1438c374824efb038b3