PSCF v1.1
param.py
1"""! Module for parsing param files. """
2
3
198
199
218 def __init__(self, file=None, label=None):
219 self.label = label
220 self._children = {}
221
222 if file != None:
223 if isinstance(file, str):
224 with open(file) as f:
225 firstLine = f.readline()
226 fl = firstLine.split()
227 if fl[0][-1] != '{':
228 raise Exception('This is not a valid parameter file.')
229 else:
230 self.label = fl[0][:-1]
231 self.read(f)
232 else:
233 self.read(file)
234
235
246 def read(self, file):
247 line = file.readline()
248 l = line.split()
249 while line != '':
250 if l[0][-1] == '{':
251 # Composite (nested)
252 if len(l) == 1:
253 label = l[0][:-1]
254 p = Composite(file, label)
255 #p = Composite(file, l[0][:-1])
256 else:
257 raise Exception('Invalid syntax for a Composite element')
258 elif l[0][-1] == '[':
259 # Array item
260 if len(l) == 1:
261 # Multi-line Array
262 label = l[0][:-1]
263 p = Array(label, file, None)
264 #p = Array(l[0][:-1], file, None)
265 else:
266 # Single line Array
267 val = []
268 if l[-1] == ']':
269 for i in range(1, len(l)-1):
270 val.append(getValue(l[i]))
271 p = Array(l[0][:-1], None, val)
272 else:
273 for i in range(1,len(l)):
274 val.append(getValue(l[i]))
275 p = Array(l[0][:-1], file, val)
276 elif l[0][-1] == '(':
277 # Matrix item
278 if len(l) == 1:
279 label = l[0][:-1]
280 p = Matrix(label, file)
281 #p = Matrix(l[0][:-1], file)
282 else:
283 raise Exception('Invalid syntax for Matrix parameter')
284 elif l[0] == '}':
285 # End of this Composite (closing bracket)
286 break
287 else:
288 # Parameter item
289 if len(l) == 1:
290 raise Exception('Invalid parameter file line')
291 elif len(l) == 2:
292 # Parameter with a single value
293 label = l[0]
294 p = Parameter(label, l[1])
295 #p = Parameter(l[0], l[1])
296 else:
297 # Parameter with multiple values on a single line
298 label = l[0]
299 val = []
300 for i in range(1, len(l)):
301 val.append(getValue(l[i]))
302 p = Parameter(label, val)
303 #p = Parameter(l[0], val)
304 self.addChild(p)
305 line = file.readline()
306 l = line.split()
307 # end while loop
308
309
320 def addChild(self, child):
321 label = child.label
322 if (label == 'label') or (label == '_children'):
323 raise Exception('Illegal parameter file label')
324 if label in self._children:
325 current = self._children[label]
326 if not isinstance(current, list):
327 self._children[label] = [current]
328 self._children[label].append(child)
329 else:
330 self._children[label] = child
331
332
341 def getChildren(self):
342 return self._children
343
344
351 def __str__(self):
352 return self.getString()
353
354
370 def __getattr__(self, attr):
371 if attr == '_children' :
372 # This is needed to prevent infinite recursion before
373 # self._children has been given an initial value of {}.
374 return {}
375 if attr in self._children:
376 if isinstance(self._children[attr], list):
377 return self._children[attr]
378 else:
379 return self._children[attr].returnData()
380 else:
381 raise AttributeError
382
383
393 def __setattr__(self, label, val):
394 if label in self._children:
395 self._children[label].setValue(val)
396 else:
397 super(Composite, self).__setattr__(label, val)
398
399
411 def getString(self, depth=''):
412 s = depth + self.label + '{' + '\n'
413 for item in self._children.values():
414 if isinstance(item, list):
415 for i in range(len(item)):
416 s += item[i].getString(depth+' ')
417 else:
418 s += item.getString(depth+' ')
419 s += depth + '}\n'
420 return s
421
422
433 def write(self, filename):
434 with open(filename, 'w') as f:
435 f.write(self.getString())
436
437
442 def returnData(self):
443 return self
444
445
453
454
460 def __init__(self, label, val):
461 self.label = label
462 if isinstance(val, list):
463 self.val = val
464 else:
465 self.val = getValue(val)
466
467
475 def setValue(self, val):
476 if isinstance(val, list):
477 if val[0] is list:
478 raise Exception('Not valid input for Parameter.')
479 self.val = []
480 for i in range(len(val)):
481 self.val.append(getValue(str(val[i])))
482 else:
483 self.val = getValue(str(val))
484
485
491 def __str__(self):
492 return self.getString()
493
494
504 def getString(self, depth=''):
505 s = ''
506 if isinstance(self.val, list):
507 s += depth + f'{self.label:40}'
508 s += f'{self.val[0]:>6}'
509 for i in range(1, len(self.val)):
510 s += f'{self.val[i]:>7}'
511 s += '\n'
512 else:
513 s += depth + f'{self.label:20}'
514 if isinstance(self.val, float):
515 v = f'{self.val:.12e}'
516 s += f'{v:>20}\n'
517 else:
518 s += f'{self.val:>20}\n'
519 return s
520
521
531 def returnData(self):
532 return self.val
533
534
545class Array:
546
547
554 def __init__(self, label, file, val=None):
555 self.label = label
556 if val == None:
557 self.val = []
558 else:
559 self.val = val
560 if file != None:
561 self.read(file)
562
563
575 def read(self, file):
576 line = file.readline()
577 l = line.split()
578 while l[0] != ']':
579 # Process a line
580 if len(l) == 1:
581 # Single value
582 self.val.append(getValue(l[0]))
583 else:
584 # Multiple space-separated values on one line
585 ls = []
586 for i in range(len(l)):
587 ls.append(getValue(l[i]))
588 self.val.append(ls)
589 # Read and split the next line
590 line = file.readline()
591 l = line.split()
592
593
600 def __str__(self):
601 return self.getString()
602
603
614 def getString(self, depth=''):
615 s = ''
616 s += depth + self.label + '[' + '\n'
617 if not isinstance(self.val[0], list):
618 # Elements with a single value
619 for i in range(len(self.val)):
620 v = f'{self.val[i]:.12e}'
621 s += depth + f'{v:>40}\n'
622 else:
623 # Elements with a list of values
624 if isinstance(self.val[0][0], int) & (len(self.val[0]) == 2):
625 for i in range(len(self.val)):
626 v = f'{self.val[i][1]:.12e}'
627 s += depth + f'{self.val[i][0]:>41}{v:>22}\n'
628 else:
629 for i in range(len(self.val)):
630 s += depth + f'{self.val[i][0]:^20}'
631 for j in range(1, len(self.val[0])):
632 if j == (len(self.val[0])-1):
633 if self.val[i][j] < 0:
634 v = f'{self.val[i][j]:.11e}'
635 else:
636 v = f'{self.val[i][j]:.12e}'
637 s += f'{v:>22}\n'
638 elif j == 1:
639 s += f'{self.val[i][j]}'
640 else:
641 s += f'{self.val[i][j]:>5}'
642 s += depth + ']\n'
643 return s
644
645
648 def returnData(self):
649 return self.val
650
651
659 def setValue(self, val):
660 if not isinstance(val, list):
661 raise Exception('Value of an Array must be a list')
662 else:
663 v = []
664 if isinstance(val[0], list):
665 same = True
666 for i in range(len(val)):
667 if len(val[i]) != 1:
668 same = False
669 break
670 if same == True:
671 for i in range(len(val)):
672 v.append(getValue(str(val[i][0])))
673 else:
674 for i in range(len(val)):
675 v.append([])
676 for j in range(len(val[i])):
677 v[i].append(getValue(str(val[i][j])))
678 else:
679 for i in range(len(val)):
680 v.append(getValue(str(val[i])))
681 self.val = v
682
683
693class Matrix:
694
695
701 def __init__(self, label, file):
702 self.label = label
703 self.val = []
704 self.read(file)
705
706
718 def read(self, file):
719 att = []
720 line = file.readline()
721 l = line.split()
722 while l[0] != ')':
723 att.append(l)
724 line = file.readline()
725 l = line.split()
726 rowMax = att[0][0]
727 colMax = att[0][1]
728 for i in range(1, len(att)):
729 if att[i][0] > rowMax:
730 rowMax = att[i][0]
731 if att[i][1] > colMax:
732 colMax = att[i][1]
733 size = int(max(rowMax, colMax))+1
734 for i in range(0, size):
735 self.val.append([])
736 for j in range(0, size):
737 self.val[i].append(getValue('0'))
738 for i in range(0, len(att)):
739 self.val[int(att[i][0])][int(att[i][1])] = getValue(att[i][2])
740 self.val[int(att[i][1])][int(att[i][0])] = getValue(att[i][2])
741
742
749 def __str__(self):
750 return self.getString()
751
752
761 def getString(self, depth=''):
762 s = ''
763 s += depth + self.label + '(\n'
764 for i in range(len(self.val)):
765 for j in range(i+1):
766 s += depth + f'{i:>24}{j:>5} ' + f'{self.val[i][j]:.12e}\n'
767 s += depth + ')\n'
768 return s
769
770
773 def returnData(self):
774 return self.val
775
776
784 def setValue(self, val):
785 if not isinstance(val, list):
786 raise TypeError('This is not a valid value for Matrix.')
787 else:
788 if isinstance(val[0], list):
789 # Input value is a matrix
790 if len(val) != len(val[0]):
791 raise Exception('Input Matrix should be square')
792 for i in range(len(val)):
793 for j in range(i):
794 if val[i][j] != val[j][i]:
795 raise Exception('This is not a symmetric Matrix.')
796 for i in range(len(val)):
797 if val[i][i] != 0:
798 raise Exception('The diagonal of the Matrix should all be zero.')
799 self.val = []
800 for i in range(len(val)):
801 self.val.append([])
802 for j in range(len(val[0])):
803 self.val[i].append(getValue(str(val[i][j])))
804 else:
805 # Input value is a list in format: [x-index, y-index, value]
806 if len(val) != 3:
807 raise Exception('Not valid input format for Matrix modification.')
808 elif (type(val[0]) != int) or (type(val[1]) != int) or ((type(val[-1]) != int) and (type(val[-1]) != float)):
809 raise Exception('Not valid input format for Matrix modification.')
810 self.val[val[0]][val[1]] = getValue(str(val[-1]))
811 self.val[val[1]][val[0]] = getValue(str(val[-1]))
812
813
814
827def getValue(v):
828
829 if (v.isdigit() == True) or (v[0] == '-' and v[1:].isdigit() == True):
830 val = int(v)
831 else:
832 try:
833 val = float(v)
834 except ValueError:
835 val = str(v)
836
837 return val
838
Container for data of an array in a param file.
Definition: param.py:545
def __str__(self)
String representation of this Array object.
Definition: param.py:600
def read(self, file)
Read the elements of this Array from a file.
Definition: param.py:575
def getString(self, depth='')
Indented string representation of this Array object.
Definition: param.py:614
def __init__(self, label, file, val=None)
Constructor.
Definition: param.py:554
def returnData(self)
Return the value of this Array, as a list of element values.
Definition: param.py:648
def setValue(self, val)
Set the new value to the Array object.
Definition: param.py:659
Container for data of a Composite in a param file.
Definition: param.py:197
def __str__(self)
Return an indented string representation of this Composite.
Definition: param.py:351
def __getattr__(self, attr)
Return the value of one child of this Composite.
Definition: param.py:370
def addChild(self, child)
Add a single child to this Composite.
Definition: param.py:320
def __setattr__(self, label, val)
Set a new value for a specified child or attribute.
Definition: param.py:393
def read(self, file)
Read and parse a parameter block from a file.
Definition: param.py:246
def write(self, filename)
Write the indented param file string for this to a file.
Definition: param.py:433
def getString(self, depth='')
Get an indented string representation of this Composite.
Definition: param.py:411
def returnData(self)
Return the Composite object itself.
Definition: param.py:442
def __init__(self, file=None, label=None)
Constructor.
Definition: param.py:218
def getChildren(self)
Get the dictionary of child items.
Definition: param.py:341
A Matrix represents a matrix-valued parameter in parameter file.
Definition: param.py:693
def __init__(self, label, file)
Constructor.
Definition: param.py:701
def read(self, file)
Read the a parameter block from a file.
Definition: param.py:718
def __str__(self)
String representation of this Matrix object.
Definition: param.py:749
def setValue(self, val)
Set a new value for this Matrix.
Definition: param.py:784
def getString(self, depth='')
Indented string representation of this Matrix object.
Definition: param.py:761
def returnData(self)
Return the value of this Matrix as a list of lists.
Definition: param.py:773
A Parameter represents a single parameter in a parameter file.
Definition: param.py:452
def returnData(self)
Return the stored value.
Definition: param.py:531
def getString(self, depth='')
Indented string for the Parameter object.
Definition: param.py:504
def __init__(self, label, val)
Constructor.
Definition: param.py:460
def __str__(self)
Unindented string representation of this Parameter object.
Definition: param.py:491
def setValue(self, val)
Set the new value to the Parameter object.
Definition: param.py:475
def getValue(v)
Distinguish the type of a value from its string representation.
Definition: param.py:827