-
Notifications
You must be signed in to change notification settings - Fork 20
/
io_pscf.py
297 lines (271 loc) · 9.46 KB
/
io_pscf.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
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
class IO:
"""
Provide interfaces for formatted file IO of variables.
The class IO is analogous to the io_mod module of scf. Class
methods provides generic interfaces for reading in scalars,
vectors, and matrices for several data types. Because variables
in python are not typed, only one input and one output function
is required for io of scalar variables, one for vectors, and one
for matrices. In both input and output functions, the variable
type is passed passed as a string argument 'type', which can have
values 'int', 'real', 'char' and (for scalars) 'logical'.
"""
def __init__(self):
"""
Default construct an initially empty object.
"""
self.comment = None
def input_comment(self, file, comment=None):
"""
Read the comment associated with a variable.
"""
if not self.comment:
self.comment = file.readline().strip()
if comment:
if comment == self.comment:
self.comment = None
return 1
else:
return 0
else:
self.comment = None
return 1
def input_var(self,file,type,comment=None,f='A'):
"""
Read and return a scalar variable from file.
Arguments:
file -- file object (must be opened for reading)
type -- string, 'int', 'real', 'char', or 'logic'
f -- 'A' -> comment string on line above data
-- 'N' -> no comment string
"""
if f == 'A':
if not self.input_comment(file, comment):
return None
data = file.readline().strip()
if type == 'int':
return int(data)
elif type == 'real':
return float(data)
elif type == 'char':
return strip_quotes(data)
elif type == 'logic':
if data in ['T','true', 'TRUE', 'True']:
return 1
elif data in ['F','false','FALSE','FALSE']:
return 0
else:
raise("Invalid logical variable:", data)
else:
raise 'Illegal type in input_var'
def input_vec(self,file,type,n=None, comment=None, s='R', f='A'):
"""
Read and return a vector/array of n variables from file.
Arguments:
file -- file object (must be opened for reading)
type -- string, = 'int', 'real', 'char', or 'logic'
n -- number of elements in vector
f -- 'A' -> comment on line above data
-- 'N' -> no comment
s -- 'R' -> row vector (one line)
-- 'C' -> column vector (n lines)
"""
if f == 'A':
if not self.input_comment(file,comment):
return None
if s == 'R': # Row Vector
data = file.readline().split()
if n:
data = data[:n]
elif s == 'C': # Column Vector
if not n: raise 'No n value in input_int_vec for column vector'
data = []
for i in range(n):
data.append( file.readline().split()[0] )
if type == 'int':
return [ int(x) for x in data ]
elif type == 'real':
return [ float(x) for x in data ]
elif type == 'char':
return [ strip_quotes(x) for x in data ]
else:
raise 'Illegal type in input_vec'
# Matrices
def input_mat(self, file, type, m, n=None, comment=None, s=None,f='A'):
"""
Read and return an m x n matrix from file.
Arguments:
file -- file object (must be opened for reading)
type -- string, = 'int' or 'real'
m -- number of rows in matrix
n -- number of columns (set to m by default)
f -- 'A' -> comment on line above data
-- 'N' -> no comment
s -- 'N' -> full matrix
-- 'S' -> symmetric
-- 'L' -> symmetric lower triangular (0 diagonals)
"""
if f == 'A':
if not self.input_comment(file,comment):
return None
# Emulate initialization of m x n array
if not n:
n = m
data = []
for i in range(m):
data.append([])
for j in range(n):
if type == 'int':
data[i].append(0)
elif type == 'real':
data[i].append(0.0)
# Read matrix
if s == 'N' or s == 'S':
min = 0
elif s == 'L':
min = 1
else:
raise 'Invalid style in input_mat: s=' + str(s)
for i in range(min,m) :
line = file.readline().split()
if s == 'N':
line = line[:n]
elif s == 'S':
line = line[:i+1]
elif s == 'L':
line = line[:i+1]
for j in range(len(line)):
if type == 'int':
datum = int(line[j])
elif type == 'real':
datum = float(line[j])
else:
raise 'Illegal type in input_mat'
data[i][j] = datum
if s == 'S' or s == 'L':
data[j][i] = datum
return data
def format_var(self, type, data):
"""
Returns a formatted string representation of data.
Arguments:
type -- string identifying type (int/real/char/logic)
data -- variable of specified type
"""
if type == 'int':
return '%20d' % data
elif type == 'real':
return '%20.10E' % data
elif type == 'char':
data = "'" + data + "'"
return "%20s" % data
elif type == 'logic':
if data:
data = 'T'
else:
data = 'F'
return "%20s" % data
else:
raise 'Illegal type in format_var'
def output_comment(self, file, comment, n=20):
"""
Write comment (variable name) to file.
Arguments:
file -- output file object
comment -- comment string
n -- field size (default = 20)
"""
comment = comment.strip()
comment = comment.ljust(n)
comment = file.write(comment + "\n")
def output_var(self, file, type, data, comment, f='A'):
"""
Output a scalar variable to a file
Arguments:
file -- output file object (must be opened for writing)
type -- type identifer string: 'int', 'real', 'char', or 'logic'
f -- 'A' -> comment string on line above data
-- 'N' -> no comment string
"""
if f == 'A':
self.output_comment(file,comment)
file.write(self.format_var(type,data) + "\n")
def output_vec(self, file, type, data, n=None, comment=None, s='R', f='A'):
"""
Output a vector/array to a file.
Arguments:
file -- file object (must be opened for reading)
type -- string, = 'int', 'real', 'char', or 'logic'
n -- number of elements in vector
f -- 'A' -> comment on line above data
-- 'N' -> no comment
s -- 'R' -> row vector (one line)
-- 'C' -> column vector (n lines)
"""
if not n:
n = len(data)
if f == 'A':
self.output_comment(file, comment)
for i in range(n):
file.write(self.format_var(type,data[i]))
if s == 'C':
file.write("\n")
if s == 'R':
file.write("\n")
def output_mat(self, file, type, data, m=None, n=None,
comment=None, s='L',f='A'):
"""
Output an m x n matrix to file.
Arguments:
file -- file object (must be opened for reading)
type -- string, = 'int' or 'real'
m -- number of rows in matrix
n -- number of columns (set to m by default)
f -- 'A' -> comment on line above data
-- 'N' -> no comment
s -- 'N' -> full matrix
-- 'S' -> symmetric
-- 'L' -> symmetric lower triangular (0 diagonals)
"""
if not m:
m = len(data)
if not n:
n = m
if f == 'A':
self.output_comment(file, comment)
# Write matrix element values
if s == 'N' or s == 'S':
min = 0
elif s == 'L':
min =1
for i in range(min,m) :
if s == 'N':
max = n
elif s == 'S':
max = i+1
elif s == 'L':
max = i
vec = data[i][:max]
self.output_vec(file, type, vec, max, None, s='R', f='N')
def strip_quotes(q_string):
"""
Strip quote marks from a string, if any, and return stripped string.
Argument:
q_string -- upstripped string, which may contain final and initial quotes.
"""
q_string = q_string.strip()
if q_string[0] == "'" and q_string[-1] == "'":
return q_string[1:-1]
elif q_string[0] == '"' and q_string[-1] == '"':
return q_string[1:-1]
else:
return q_string
class IoException(Exception):
"""
Exception for a file syntax error.
"""
def __init__(self, message):
"""
Constructor, which stores a comment.
"""
super(IoException, self).__init__(message)