-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathplumed_header.py
105 lines (84 loc) · 3.51 KB
/
plumed_header.py
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
#!/usr/bin/env python3
"""Parse and create headers of plumed data files"""
class PlumedHeader:
"""
Stores plumed style header in list
Can parse and create similar headers for usage in python tools
:param fields: list of strings containing the column descriptions
:type fields: list
:param constants: dictionary of constants for the data
:type fields: dict {name: val}
:param delim: comment delimiter to set for the comment lines when printing to file
:type delim: str
"""
def __init__(self, fields=None, constants=None, delim=None):
"""Instantiate header
:param fields: list holding description of the data columns, optional
:param constants: dictionary with additional constants, optional
:param delim: comment delimiter to use, defaults to '#!'
:type delim: str, optional
"""
self.fields = fields or []
self.constants = constants or {}
self.delim = delim or "#!"
def __repr__(self):
"""
Returns header as string with newlines to be printed to file.
Can be used directly as header argument to numpys savetxt.
"""
lines = []
lines.append(self.delim + " FIELDS " + " ".join(self.fields))
for name, value in self.constants.items():
lines.append(f"{self.delim} SET {name} {value}")
return "\n".join(lines)
def parse_file(self, filename, delim=None):
"""
Parse header of plumed file.
The header is assumed to be the first lines of the file that start with the set delimiter.
This overwrites the existing fields and constants of the class instance.
If no custom delimiter is specified the one of the class instance is used.
:param filename: file to parse
:param delim: comment delimiter of file, optional
"""
if not delim:
delim = self.delim
header = []
with open(filename, "r") as f:
for line in f:
if line.startswith(delim):
header.append(line.lstrip(delim).rstrip("\n").strip())
if not header:
raise ValueError(f"No header was found in specified file {filename}")
# first line contains description of columns
if header[0].startswith("FIELDS"):
self.fields = header[0].split()[1:]
else:
raise ValueError(f"No FIELDS found in specified file {filename}")
# (optional) remaining lines contain constants
for line in header[1:]:
if line.startswith("SET"):
name, val = line.split()[1:3]
self.constants[name] = val
def set_constant(self, name, val):
"""
Add constant to header. Will overwrite existing value of same name
:param name: Name of constant
:param val: Value of constant (will be cast to str)
"""
self.constants[name] = str(val)
def add_field(self, name):
"""
Append field to header
:param name: name of field
"""
self.fields.append(name)
def create_from_file(filename, delim=None):
"""Create header instance and directly parse given file
If the file has a special delimiter for header lines it can also be specified
:param filename: path to file to parse
:param delim: custom delimiter of header lines, optional
:returns header: PlumedHeader instance with fields and constants from file
"""
header = PlumedHeader(delim=delim)
header.parse_file(filename)
return header