Skip to content
Browse files

Add function to write RB data to disk.

- Ability to write matrices and supplementary data in RB format.
- Now depends upon fortranformat (from PyPi) instead of
  FortranFormat (from ScientificPython).
  • Loading branch information...
1 parent 17a6b80 commit c4120158ca5a4a4676639256d84f828f03ee338b @dpo committed Jun 21, 2011
Showing with 312 additions and 34 deletions.
  1. +312 −34 pyorder/tools/hrb.py
View
346 pyorder/tools/hrb.py
@@ -45,6 +45,7 @@
"""
import numpy
import FortranFormat as F
+from fortranformat import FortranRecordReader, FortranRecordWriter
class HarwellBoeingMatrix:
"""
@@ -83,18 +84,22 @@ def __init__(self, fname, **kwargs):
self.readMatrix(fp, **kwargs)
fp.close()
+ def data(self):
+ #if self.ip is None or self.ind is None: return (None,None,None)
+ return (self.ip, self.ind, self.val)
+
def find(self):
- if self.ip is None or self.ind is None: return None
+ if self.ip is None or self.ind is None: return (None,None)
row = numpy.empty(self.nnzero, numpy.int)
col = numpy.empty(self.nnzero, numpy.int)
# Adjust indices to 0-based scheme
for i in range(self.ncol):
for j in range(self.ip[i], self.ip[i+1]):
col[j] = i
row[j] = self.ind[j]
- return(row,col)
+ return (row,col)
- def readArray(self, fp, which, nelm, format):
+ def _Old_readArray(self, fp, which, nelm, format):
fmt = F.FortranFormat(str(format))
ind = 0
while ind < nelm-1:
@@ -104,11 +109,31 @@ def readArray(self, fp, which, nelm, format):
ind = ind2
return
- def fortranRead(self, stream, format):
+ def _Old_fortranRead(self, stream, format):
fmt = F.FortranFormat(format)
fdata = F.FortranLine(stream, fmt)
return fdata.data
+ def readArray(self, fp, which, nelm, format):
+ #print 'Reading %d values with format %s' % (nelm, format)
+ fmt = FortranRecordReader(format)
+ ind = 0
+ while ind < nelm-1:
+ fdata = fmt.read(fp.readline())
+ ind2 = min(ind + len(fdata), nelm)
+ which[ind:ind2] = fdata[:ind2-ind]
+ ind = ind2
+ # Read last line, if any.
+ if ind < nelm:
+ fdata = fmt.read(fp.readline())
+ which[ind:] = fdata[:nelm-ind]
+ return
+
+ def fortranRead(self, stream, format):
+ fmt = FortranRecordReader(format)
+ fdata = fmt.read(stream)
+ return fdata
+
def readMatrix(self, fp, **kwargs):
self.patternOnly = kwargs.get('patternOnly', False)
self.readRhs = kwargs.get('readRhs', False)
@@ -267,23 +292,26 @@ def readMatrix(self, fp, **kwargs):
else:
# Read supplementary data
- self.dattyp, positn, orgniz, caseid, numerf, m, nvec, nauxd = \
- fRead(buffer1, 'A3, 2A1, 1X, A8, 2X, A1, 3(2X, I13)')
+ (self.dattyp, self.positn, self.orgniz, self.caseid, numerf, m,
+ nvec, self.nauxd) = fRead(buffer1,
+ 'A3,2A1,1X,A8,2X,A1,3(2X,I13)')
auxfm1, auxfm2, auxfm3 = fRead(buffer2, '3A20')
+ self.nrow = m
+ self.nvec = self.ncol = nvec
# Read integer data
- if (self.dattyp=='rhs' and orgniz=='s') or \
+ if (self.dattyp=='rhs' and self.orgniz=='s') or \
self.dattyp in ['ipt','icv','ord']:
if self.dattyp=='ord':
- nauxd = m * nvec
+ self.nauxd = m * nvec
auxfm = auxfm1
else:
self.ip = numpy.empty(nvec+1, numpy.int)
self.readArray(fp, self.ip, nvec+1, auxfm1)
auxfm = auxfm2
self.ip -= 1 # Adjust to 0-based indexing
- self.ind = numpy.empty(nauxd, numpy.int)
- self.readArray(fp, self.ind, nauxd, auxfm)
+ self.ind = numpy.empty(self.nauxd, numpy.int)
+ self.readArray(fp, self.ind, self.nauxd, auxfm)
self.ind -= 1 # Adjust to 0-based indexing
if self.dattyp != 'rhs': return
@@ -295,17 +323,257 @@ def readMatrix(self, fp, **kwargs):
dataType = numpy.complex
elif numerf=='i':
dataType = numpy.int
- if self.dattyp != 'rhs': nauxd = m*nvec
- if self.dattyp == 'rhs' and orgniz == 's':
+ if self.dattyp != 'rhs': self.nauxd = m*nvec
+ if self.dattyp == 'rhs' and self.orgniz == 's':
auxfm = auxfm3
else:
auxfm = auxfm1
- self.val = numpy.empty(nauxd, dataType)
- self.readArray(fp, self.val, nauxd, auxfm)
+ self.val = numpy.empty(self.nauxd, dataType)
+ self.readArray(fp, self.val, self.nauxd, auxfm)
+ self.nnzero = self.nauxd
return
+# Helper functions.
+
+def get_int_fmt(n):
+ "Return appropriate format for integer arrays."
+ fmts = ['(40I2)', '(26I3)', '(20I4)', '(16I5)', '(13I6)', '(11I7)',
+ '(10I8)', '(8I9)', '(8I10)', '(7I11)', '(4I20)']
+ nlines = [40,26,20,16,13,11,10,8,8,7,4]
+ nn = n
+ for k in range(1,n+1):
+ if nn < 10: break
+ nn /= 10
+ if k <= 10: return (fmts[k+1], nlines[k+1])
+ return (fmts[10], nlines[10])
+
+def get_real_fmt(p):
+ "Return appropriate format for real array (1 <= p <= 17)."
+ fmt = ['(8E10.1E3)', '(7E11.2E3)', '(6E12.3E3)', '(6E13.4E3)',
+ '(5E14.5E3)', '(5E15.6E3)', '(5E16.7E3)', '(4E17.8E3)',
+ '(4E18.9E3)', '(4E19.10E3)', '(4E20.11E3)', '(3E21.12E3)',
+ '(3E22.13E3)', '(3E23.14E3)', '(3E24.15E3)', '(3E25.16E3)']
+ fmt1 = ['(1P,8E10.1E3)', '(1P,7E11.2E3)', '(1P,6E12.3E3)',
+ '(1P,6E13.4E3)', '(1P,5E14.5E3)', '(1P,5E15.6E3)',
+ '(1P,5E16.7E3)', '(1P,4E17.8E3)', '(1P,4E18.9E3)',
+ '(1P,4E19.10E3)', '(1P,4E20.11E3)', '(1P,3E21.12E3)',
+ '(1P,3E22.13E3)', '(1P,3E23.14E3)', '(1P,3E24.15E3)',
+ '(1P,3E25.16E3)']
+ lens = [8,7,6,6,5,5,5,4,4,4,4,3,3,3,3,3]
+ return (fmt[p-2], fmt1[p-2], lens[p-2])
+
+def fortranWriteLine(data, stream, fformat):
+ "Write `data` to `stream` according to Fortran format `fformat`."
+ fmt = FortranRecordWriter(fformat)
+ stream.write(fmt.write(data))
+ stream.write('\n')
+ return
+
+def fortranWriteArray(data, chunk_size, stream, fformat):
+ """
+ Write array `data` to `stream`, possibly using multiple lines,
+ according to Fortran format `fformat`.
+ """
+ nelts = len(data)
+ nelts_per_line = nelts/chunk_size
+ #print 'Writing %d elements %d per line...' % (nelts, chunk_size)
+ for k in range(nelts_per_line):
+ chunk = data[k*chunk_size:(k+1)*chunk_size]
+ fortranWriteLine(chunk, stream, fformat)
+ if nelts_per_line*chunk_size < nelts:
+ fortranWriteLine(data[nelts_per_line*chunk_size:], stream, fformat)
+ return
+
+# End of helper functions.
+
+
+def write_rb(fname, nrow, ncol, ip, ind,
+ val=None, precision=17, symmetric=False, skew=False,
+ title='Generic', key='Generic'):
+ """
+ Write a sparse matrix to file in Rutherford-Boeing format. The input matrix
+ must be described in compressed column format by the arrays `ip` and `ind`.
+ Rows must be ordered in each column.
+ If numerical values are to be written to file, they should be specified in
+ the array `val`.
+
+ Currently only supports assembled matrices in compressed column format.
+ """
+
+ patternOnly = (val == None)
+ rectangular = (nrow != ncol)
+ ne = len(ind)
+
+ # Check that columns are in order.
+# for j in range(ncol):
+# if ip[j+1] <= ip[j]:
+# raise ValueError, 'Columns must be ordered.'
+
+ # Check that rows are in order in each column.
+# for j in range(ncol):
+# for k in range(ip[j], ip[j+1]-1):
+# if ind[k] >= ind[k+1]:
+# raise ValueError, 'Rows must be ordered in each column.'
+
+ # Set mxtype.
+ mxtype0 = 'r'
+ if patternOnly: mxtype0 = 'p'
+ if symmetric: mxtype1 = 's'
+ if skew: mxtype1 = 'z'
+ if rectangular: mxtype1 = 'r'
+
+ mxtype = mxtype0 + mxtype1 + 'a'
+
+ # Set format and number card images for pointer array.
+ (ptrfmt, ptrn) = get_int_fmt(ne+1)
+ ptrcrd = ncol/ptrn + 1
+
+ # Set format and number card images for index array.
+ (indfmt, indn) = get_int_fmt(nrow)
+ indcrd = (ne-1)/indn + 1
+
+ # Set number of card images for numerical entries.
+ if patternOnly:
+ valcrd = 0 ; valfmi = ' '
+ else:
+ (valfmi, valfmo, valn) = get_real_fmt(precision)
+ valcrd = (ne-1)/valn + 1
+
+ totcrd = ptrcrd + indcrd + valcrd
+ neltvl = 0
+
+ fp = open(fname, 'w')
+
+ lt = len(title)
+ if lt < 72: title = title + (72-lt)*' '
+ lk = len(key)
+ if lk < 8: key = key + (8-lk)*' '
+
+ # Write header.
+ fortranWriteLine([title, key], fp, 'A72,A8')
+ fortranWriteLine([totcrd, ptrcrd, indcrd, valcrd], fp, 'I14,3(1X,I13)')
+ fortranWriteLine([mxtype, nrow, ncol, ne, neltvl], fp, 'A3,11X,4(1X,I13)')
+ fortranWriteLine([ptrfmt, indfmt, valfmi], fp, '2A16,A20')
+
+ # Write pointer and index arrays. Ajust for 1-based indexing.
+ #print 'Writing pointer array...'
+ fortranWriteArray(ip+1, ptrn, fp, ptrfmt)
+ #print 'Writing index array...'
+ fortranWriteArray(ind+1, indn, fp, indfmt)
+
+ # Write matrix entries.
+ neltvl = ne
+ if not patternOnly:
+ #print 'Writing matrix entries...'
+ fortranWriteArray(val, valn, fp, valfmo)
+
+ fp.close()
+ return
+
+
+def write_aux(fname, nrow, nvec, precision=17, title='Generic', key='Generic',
+ caseid='Generic', dattyp='rhs', positn='r', orgniz='d', nauxd=None,
+ ip=None, ind=None, val=None):
+ """
+ Write supplementary data to file in Rutherford-Boeing format.
+
+ Only real data is supported for now.
+ """
+
+ data_types = ['ord','rhs','sln','est','evl','svl','evc','svc','sbv','sbm',
+ 'sbp','ipt','icv','lvl','geo','avl']
+ organizations = ['s','d','e']
+ positions = ['r','l','s']
+
+ if dattyp not in data_types:
+ raise ValueError, 'Unknown data type: %s' % dattyp
+ if positn not in positions:
+ raise ValueError, 'Unknown position: %s' % positn
+ if orgniz not in organizations:
+ raise ValueError, 'Unknown organization: %s' % orgniz
+
+ if dattyp in ['evl','svl','lvl','sbp']: nvec = 1
+ if dattyp in ['evl','svl','lvl','sbv','sbm','sbp','avl']: positn = ' '
+ if dattyp != 'rhs': orgniz = ' '
+
+ numerf = 'r'
+ if dattyp == 'ord': numerf = 'i'
+ if dattyp in ['ipt','icv']: numerf = 'p'
+
+ if orgniz != 'e':
+ nauxd = 0
+ if orgniz == 's' or dattyp in ['icv','ipt']:
+ if ip is None:
+ raise ValueError, 'Need pointer array for data type %s' % dattyp
+ nauxd = ip(nvec)-1
+ if orgniz == 'd': nauxd = nrow*nvec
+
+ # Set data formats.
+ auxfm1 = auxfm2 = auxfm3 = ' '
+ fm1 = fm3 = ' '
+
+ if dattyp in ['ipt','icv']:
+ (auxfm1, n1) = get_int_fmt(nauxd+1)
+ (auxfm2, n2) = get_int_fmt(nrow)
+ elif dattyp == 'ord':
+ (auxfm1, n1) = get_int_fmt(nrow)
+ else:
+ if precision < 2 or precision > 17: precision = 17
+ if dattyp == 'rhs' and orgniz == 's':
+ (auxfm1, n1) = get_int_fmt(nauxd+1)
+ (auxfm2, n2) = get_int_fmt(nrow)
+ (auxfm3, fm3, n3) = get_real_fmt(precision)
+ else:
+ (auxfm1, fm1, n1) = get_real_fmt(precision)
+
+ fp = open(fname, 'w')
+
+ lt = len(title)
+ if lt < 72: title = title + (72-lt)*' '
+ lk = len(key)
+ if lk < 8: key = key + (8-lk)*' '
+
+ # Write header.
+ fortranWriteLine([title, key], fp, 'A72,A8')
+ fortranWriteLine([dattyp, positn, orgniz, caseid, numerf, nrow, nvec,
+ nauxd], fp, 'A3,2A1,1X,A8,1X,A1,3(1X,I13)')
+ fortranWriteLine([auxfm1, auxfm2, auxfm3], fp, '3A20')
+
+ # Write pointer and index arrays. Ajust for 1-based indexing.
+ if (dattyp == 'rhs' and orgniz == 's') or dattyp in ['ipt','icv']:
+ #print 'Writing pointer array...'
+ fortranWriteArray(ip+1, n1, fp, auxfm1)
+ #print 'Writing index array...'
+ fortranWriteArray(ind+1, n2, fp, auxfm2)
+
+ # Write entries.
+ #print 'Writing entries...'
+ if dattyp == 'rhs' and orgniz == 's':
+ fortranWriteArray(val, n3, fp, fm3)
+ else:
+ fortranWriteArray(val, n1, fp, fm1)
+
+ fp.close()
+ return
+
+
+def write_aux_from_rb(fname, rbdata):
+ (ip, ind, val) = rbdata.data()
+ write_aux(fname, rbdata.nrow, ip.shape[0], dattyp=rbdata.dattyp,
+ title=rbdata.title, key=rbdata.key, caseid=rbdata.caseid,
+ positn=rbdata.positn, orgniz=rbdata.orgniz, nauxd=rbdata.nauxd,
+ ip=ip, ind=ind, val=val)
+
+def write_aux_from_numpy(fname, array, **kwargs):
+ if len(array.shape) == 1:
+ nvec = 1
+ else:
+ nvec = array.shape[1]
+ write_aux(fname, array.shape[0], nvec, val=array)
+
+
if __name__ == '__main__':
# Demo the HarwellBoeingMatrix and RutherfordBoeingData classes
@@ -314,36 +582,46 @@ def readMatrix(self, fp, **kwargs):
import sys
fname = sys.argv[1]
- #M = HarwellBoeingMatrix(fname, patternOnly=False, readRhs=True)
- M = RutherfordBoeingData(fname, patternOnly=False)
- print 'Data of order (%-d,%-d) with %-d nonzeros' % (M.nrow,M.ncol,M.nnzero)
+ plot = False
numpy.set_printoptions(precision=8,
threshold=10,
edgeitems=3,
linewidth=80,
suppress=False)
+ #M = HarwellBoeingMatrix(fname, patternOnly=False, readRhs=True)
# Comment this out for Rutherford-Boeing data
#if M.readRhs:
# for i in range(M.nrhs):
# print M.rhs[:,i]
+ M = RutherfordBoeingData(fname, patternOnly=False)
+ print 'Data of order (%-d,%-d) with %-d nonzeros' % (M.nrow,M.ncol,M.nnzero)
+
# Plot sparsity pattern
- try:
- import pylab
- except:
- sys.stderr.write('Pylab is required for the demo\n')
- sys.exit(1)
-
- (row,col) = M.find()
- fig = pylab.figure()
- ax = fig.gca()
- ax.plot(col, row, 'ks', markersize=1, linestyle='None')
- if M.issym: ax.plot(row, col, 'ks', markersize=1, linestyle='None')
- ax.set_xlim(xmin=-1, xmax=M.ncol)
- ax.set_ylim(ymin=M.nrow, ymax=-1)
- if M.nrow == M.ncol:
- ax.set_aspect('equal')
- pylab.title(M.title, fontsize='small')
- pylab.show()
+ if plot:
+ try:
+ import pylab
+ except:
+ sys.stderr.write('Pylab is required for the demo\n')
+ sys.exit(1)
+
+ (row,col) = M.find()
+ fig = pylab.figure()
+ ax = fig.gca()
+ ax.plot(col, row, 'ks', markersize=1, linestyle='None')
+ if M.issym: ax.plot(row, col, 'ks', markersize=1, linestyle='None')
+ ax.set_xlim(xmin=-1, xmax=M.ncol)
+ ax.set_ylim(ymin=M.nrow, ymax=-1)
+ if M.nrow == M.ncol:
+ ax.set_aspect('equal')
+ pylab.title(M.title, fontsize='small')
+ pylab.show()
+
+ # Write data back to file
+ (ip, ind, val) = M.data()
+ print val
+ #write_rb('newmat.rb', M.nrow, M.ncol, ip, ind, val, symmetric=M.issym)
+ #x = numpy.ones(10)
+ #write_aux_from_numpy('x.rb', x)

0 comments on commit c412015

Please sign in to comment.
Something went wrong with that request. Please try again.