def matrix_is_symplectic(self, m, tolerance=1.0e-12): """ Confirm that a given matrix $M$ is symplectic to within numerical tolerance. This is done by taking the 4 submatrices: 1. $A = M[0::2, 0::2]$, i.e., configuration coordinates only, 2. $B = M[0::2, 1::2]$, i.e., configuration rows, momenta cols, 3. $C = M[1::2, 0::2]$, i.e., momenta rows, configuration cols, 4. $D = M[1::2, 1::2]$, i.e., momenta only, and verifying the following symplectic identities:- 1. $MJM^{T} = J$, the $2n\\times 2n$ sympletic matrix, 2. $AD^{T}-BC^{T} = I$, the $n\\times n$ identity, 3. $AB^{T}-BA^{T} = Z$, the $n\\times n$ zero, 4. $CD^{T}-DC^{T} = Z$. Finally, we confirm that $\\det{M} = 1$. """ det = determinant(m) j = self.skew_symmetric_matrix() approx_j = matrixmultiply(m, matrixmultiply(j, transpose(m))) a = m[0::2, 0::2] #even, even b = m[0::2, 1::2] #even, odd c = m[1::2, 0::2] #odd, even d = m[1::2, 1::2] #odd, odd i = self.identity_matrix(self.dof()) approx_i = matrixmultiply(a, transpose(d)) - matrixmultiply(b, transpose(c)) approx_z0 = matrixmultiply(a, transpose(b)) - matrixmultiply(b, transpose(a)) approx_z1 = matrixmultiply(c, transpose(d)) - matrixmultiply(d, transpose(c)) norm = self.matrix_norm logger.info('Matrix from diagonal to equilibrium coordinates:') logger.info('[output supressed]') #logger.info(m) logger.info('error in determinant: %s', abs(det-1.0)) logger.info('error in symplectic identity #1: %s', norm(approx_j - j)) logger.info('error in symplectic identity #2: %s', norm(approx_i - i)) logger.info('error in symplectic identity #3: %s', norm(approx_z0)) logger.info('error in symplectic identity #4: %s', norm(approx_z1)) okay = True if not (abs(det-1.0) < tolerance): okay = False if not (norm(approx_j - j) < tolerance): okay = False if not (norm(approx_i - i) < tolerance): okay = False if not (norm(approx_z0) < tolerance): okay = False if not (norm(approx_z1) < tolerance): okay = False return okay
def vunrot(self, v): # for use with row vectors # [bruce comment 050518: the above old comment by Josh seems to contradict # the comment about 'matrix' in __getattr__ (also old and by Josh) # that it's the transpose of the normal form so it can be used for row vectors. # See the other comment for more info.] return Numeric.matrixmultiply(v, Numeric.transpose(self.matrix))
def check_eigen_value_vector_pairs(self, mat, pairs): """ Check the accuracy of eigenvalue/eigenvector pairs for a given matrix. @param mat: a square matrix. @param pairs: an iterable of EigenValueVectorPair. """ for pair in pairs: logger.info('Eigenvalue %s', pair.val) #logger.info('Eigenvector %s', pair.vec) m_v = matrixmultiply(mat, pair.vec) e_v = pair.val * pair.vec err = self.vector_l2_norm(m_v - e_v) logger.info('Error in eigenvalue/eigenvector pair %s', err) assert err < 1.0e-12 if isinstance(pair.val, complex): err = min(abs(pair.val.real), abs(pair.val.imag)) else: err = 0.0 logger.info('Error from pure real/imag %s', err) assert err < 1.0e-12 pair.val = self.purify_eigenvalue(pair.val)
def setNormalization(self, normalization): if normalization == OrthPolyBasis.NORM_NONE: self.T = self._T0 elif normalization == OrthPolyBasis.NORM_NORM: self.T = self._T1 elif normalization == OrthPolyBasis.NORM_NORM_T0_1: self.T = self._T2 elif normalization == OrthPolyBasis.NORM_END1: self.T = self._T3 else: raise "Error: unknown normalization: " + str(normalization) self.TT = Numeric.matrixmultiply(self.T, Numeric.transpose(self.T)) self.TTinv = LinearAlgebra.inverse(self.TT) self.TTinvT = Numeric.matrixmultiply(self.TTinv, self.T) self.basisCoef = self._getBasisCoef(self.x, self.T) self._normalization = normalization self._checkOrth(self.T, self.TT, output = self._force)
def setNormalization(self, normalization): if normalization == OrthPolyBasis.NORM_NONE: self.T = self._T0 elif normalization == OrthPolyBasis.NORM_NORM: self.T = self._T1 elif normalization == OrthPolyBasis.NORM_NORM_T0_1: self.T = self._T2 elif normalization == OrthPolyBasis.NORM_END1: self.T = self._T3 else: raise "Error: unknown normalization: " + str(normalization) self.TT = Numeric.matrixmultiply(self.T, Numeric.transpose(self.T)) self.TTinv = LinearAlgebra.inverse(self.TT) self.TTinvT = Numeric.matrixmultiply(self.TTinv, self.T) self.basisCoef = self._getBasisCoef(self.x, self.T) self._normalization = normalization self._checkOrth(self.T, self.TT, output=self._force)
def __init__(self, numPoints, k): """numPoints: number of approximation points; k: number of basis functions [2,...,numPoints]""" self.numPoints = numPoints self.k = k ## assert k > 1, "Error TrigonomerticBasis: k <= 1" assert k <= numPoints, "Error TrigonomerticBasis: k > numPoints" # evaluate trigonometric basis functions on the given number of points from [-pi,pi] self.x = Numeric.arange(-1*math.pi, math.pi+0.0000001, 2*math.pi/(numPoints-1)) self.y = Numeric.ones((k, numPoints), Numeric.Float) for kk in range(1, k, 2): ## print "kk, cos %ix" % ((kk+1)/2.) self.y[kk] = MLab.cos(self.x*(kk+1)/2) for kk in range(2, k, 2): ## print "kk, sin %ix" % (kk/2.) self.y[kk] = MLab.sin(self.x*kk/2) # approx. matrix self.Ainv = LinearAlgebra.inverse(Numeric.matrixmultiply(self.y, Numeric.transpose(self.y))) self.yyTinvy = Numeric.matrixmultiply(LinearAlgebra.inverse(Numeric.matrixmultiply(self.y, Numeric.transpose(self.y))), self.y)
def linear_matrix(self, h): """ Returns the $d\\times d$ matrix that defines the linear part of Hamilton's equations for the given polynomial Hamiltonian. """ J = self.skew_symmetric_matrix() hess_h_2 = self.hessian_matrix_of_quadratic_part(h) return matrixmultiply(J, hess_h_2)
def getApproxCoeff(self, curves): """curves: 1d or 2d array where each curve in separate line, e.g. curves[curveIdx,timePoints]""" ## print "curves" ## print curves ## print ## print "Numeric.transpose(self.TTinvT)" ## print Numeric.transpose(self.TTinvT) ## print ## print "Numeric.matrixmultiply(curves, Numeric.transpose(self.TTinvT))" ## print Numeric.matrixmultiply(curves, Numeric.transpose(self.TTinvT)) return Numeric.matrixmultiply(curves, Numeric.transpose(self.TTinvT))
def evalApproxPoly(self, appxCoef, points=None): """returns (#curve, #points) an approx. polynomials calculated at points given approx. coeff in rows: - appxCoef: curves for approximation in rows, appxCoef in columns [B0, B1, ...] - points relative to self.points TODO: evaluate on a matrix of appxCoef """ if points == None: return Numeric.matrixmultiply(appxCoef, self.T) appxCoef = Numeric.asarray(appxCoef, Numeric.Float) one_curve = len(appxCoef.shape) == 1 if one_curve: appxCoef = appxCoef[Numeric.NewAxis,:] # [curveIdx, coefIdx] mappedPoints = self._map(points, self.pointsMin, self.pointsMax, self.xMin, self.xMax) # eval basis polynomials on mapped points basisEval = self._evalPolyHorner(self.basisCoef, mappedPoints) #[basisIdx == coefIdx, pointIdx] result = Numeric.matrixmultiply(appxCoef, basisEval) if one_curve: return result[0,:] else: return result
def test_example_skew(self): """Multiply the skew-symmetric matrix by a specific vector.""" dof = 3 lie = LieAlgebra(dof) diag = Diagonalizer(lie) J = diag.skew_symmetric_matrix() x = (1, 2, 3, 4, 5, 6) y = matrixmultiply(J, x) # self.assertEquals(y, (2,-1,4,-3,6,-5)) z = y == (2, -1, 4, -3, 6, -5) self.assertTrue(z.all())
def __init__(self, points, k, normalization=NORM_NORM_T0_1, force=False): """ calculate k polynomials of degree 0 to k-1 orthogonal on a set of distinct points map points to interval [-1,1] INPUT: points: array of dictinct points where polynomials are orthogonal k: number of polynomials of degree 0 to k-1 force=True creates basis even if orthogonality is not satisfied due to numerical error USES: x: array of points mapped to [-1,1] T_: matrix of values of polynomials calculated at x, shape (k,len(x)) TT_ = T_ * Numeric.transpose(T_) TTinv_ = inverse(TT_) sc_: scaling factors a, b: coefficients for calculating T (2k-4 different from 0, i.e. 6 for k=5) n: number of points = len(points) normalization = {0|1|2} """ self.k = k # number of basis polynomials of order 0 to k-1 self._force = force self.points = Numeric.asarray(points, Numeric.Float) self.pointsMin = min(points) self.pointsMax = max(points) # scaling x to [-1,1] results in smaller a and b, T is not affected; overflow is NOT a problem! self.xMin = -1 self.xMax = 1 self.x = self._map(self.points, self.pointsMin, self.pointsMax, self.xMin, self.xMax) # calculate basis polynomials self.n = len(points) # the number of approximation points t = Numeric.zeros((k,self.n),Numeric.Float) a = Numeric.zeros((k,1),Numeric.Float) b = Numeric.zeros((k,1),Numeric.Float) t[0,:] = Numeric.ones(self.n,Numeric.Float) if k > 1: t[1,:] = self.x - sum(self.x)/self.n for i in range(1,k-1): a[i+1] = Numeric.innerproduct(self.x, t[i,:] * t[i,:]) / Numeric.innerproduct(t[i,:],t[i,:]) b[i] = Numeric.innerproduct(t[i,:], t[i,:]) / Numeric.innerproduct(t[i-1,:],t[i-1,:]) t[i+1,:] = (self.x - a[i+1]) * t[i,:] - b[i] * t[i-1,:] self.a = a self.b = b # prepare for approximation self._T0 = t # orthonormal _TT0 = Numeric.matrixmultiply(self._T0, Numeric.transpose(self._T0)) self.sc1 = Numeric.sqrt(Numeric.reshape(Numeric.diagonal(_TT0),(self.k,1))) # scaling factors = sqrt sum squared self._T0 self._T1 = self._T0 / self.sc1 # orthonormal and T[0] == 1 self.sc2 = Numeric.sqrt(Numeric.reshape(Numeric.diagonal(_TT0),(self.k,1)) / self.n) # scaling factors = sqrt 1/n * sum squared self._T0 self._T2 = self._T0 / self.sc2 # T[:,-1] == 1 self.sc3 = Numeric.take(self._T0, (-1,), 1) # scaling factors = self._T0[:,-1] self._T3 = self._T0 / self.sc3 # set the variables according to the chosen normalization self.setNormalization(normalization)
def test_example_skew(self): """Multiply the skew-symmetric matrix by a specific vector.""" dof = 3 lie = LieAlgebra(dof) diag = Diagonalizer(lie) J = diag.skew_symmetric_matrix() x = (1,2,3,4,5,6) y = matrixmultiply(J, x) # self.assertEquals(y, (2,-1,4,-3,6,-5)) z = y == (2,-1,4,-3,6,-5) self.assertTrue(z.all())
def evalApproxPoly(self, appxCoef, points=None): """returns (#curve, #points) an approx. polynomials calculated at points given approx. coeff in rows: - appxCoef: curves for approximation in rows, appxCoef in columns [B0, B1, ...] - points relative to self.points TODO: evaluate on a matrix of appxCoef """ if points == None: return Numeric.matrixmultiply(appxCoef, self.T) appxCoef = Numeric.asarray(appxCoef, Numeric.Float) one_curve = len(appxCoef.shape) == 1 if one_curve: appxCoef = appxCoef[Numeric.NewAxis, :] # [curveIdx, coefIdx] mappedPoints = self._map(points, self.pointsMin, self.pointsMax, self.xMin, self.xMax) # eval basis polynomials on mapped points basisEval = self._evalPolyHorner( self.basisCoef, mappedPoints) #[basisIdx == coefIdx, pointIdx] result = Numeric.matrixmultiply(appxCoef, basisEval) if one_curve: return result[0, :] else: return result
def test(): a = SparseArray(5, 1) a[0] = 10 a[3] = 2 print str(a), ` a ` a *= 2 print str(a), ` a ` a += 2 print str(a), ` a ` a /= range(1, 6) print str(a), ` a ` b = SparseArray(5, 3, {2: 15}) a -= b print str(a), ` a ` print a.dot(b), b.dot(a) print a.as_dense_array() M = Numeric.array(range(25)).resize((5, 5)) print a.matrix_multiply(M) print Numeric.matrixmultiply(a.as_dense_array(), M) print a.matrix_multiply_transpose(M) print Numeric.matrixmultiply(M, a.as_dense_array()) c = SparseArray([1, 2, 3, 4, 5]) print c, ` c `
def __init__(self, numPoints, k): """numPoints: number of approximation points; k: number of basis functions [2,...,numPoints]""" self.numPoints = numPoints self.k = k ## assert k > 1, "Error TrigonomerticBasis: k <= 1" assert k <= numPoints, "Error TrigonomerticBasis: k > numPoints" # evaluate trigonometric basis functions on the given number of points from [-pi,pi] self.x = Numeric.arange(-1 * math.pi, math.pi + 0.0000001, 2 * math.pi / (numPoints - 1)) self.y = Numeric.ones((k, numPoints), Numeric.Float) for kk in range(1, k, 2): ## print "kk, cos %ix" % ((kk+1)/2.) self.y[kk] = MLab.cos(self.x * (kk + 1) / 2) for kk in range(2, k, 2): ## print "kk, sin %ix" % (kk/2.) self.y[kk] = MLab.sin(self.x * kk / 2) # approx. matrix self.Ainv = LinearAlgebra.inverse( Numeric.matrixmultiply(self.y, Numeric.transpose(self.y))) self.yyTinvy = Numeric.matrixmultiply( LinearAlgebra.inverse( Numeric.matrixmultiply(self.y, Numeric.transpose(self.y))), self.y)
def test_eigensystem(self): """Multiply eigenvectors and the original matrix by the eigenvalues in order to check the integrity of the eigensystem.""" dof = 3 terms = {Powers((2, 0, 0, 0, 0, 0)): -0.3, Powers((1, 1, 0, 0, 0, 0)): 0.33, Powers((0, 0, 1, 0, 1, 0)): 7.2, Powers((0, 0, 0, 0, 0, 2)): 7.2, Powers((0, 0, 0, 1, 1, 0)): 7.12 } g = Polynomial(2*dof, terms=terms) alg = LieAlgebra(dof) diag = Diagonalizer(alg) lin = diag.linear_matrix(g) val_vec_pairs = diag.eigenvalue_eigenvector_pairs(g) for p in val_vec_pairs: prod_s = p.vec*p.val prod_v = matrixmultiply(lin, p.vec) for x in prod_s-prod_v: self.assert_(abs(x)<1.0e-15)
def test_eigensystem(self): """Multiply eigenvectors and the original matrix by the eigenvalues in order to check the integrity of the eigensystem.""" dof = 3 terms = { Powers((2, 0, 0, 0, 0, 0)): -0.3, Powers((1, 1, 0, 0, 0, 0)): 0.33, Powers((0, 0, 1, 0, 1, 0)): 7.2, Powers((0, 0, 0, 0, 0, 2)): 7.2, Powers((0, 0, 0, 1, 1, 0)): 7.12 } g = Polynomial(2 * dof, terms=terms) alg = LieAlgebra(dof) diag = Diagonalizer(alg) lin = diag.linear_matrix(g) val_vec_pairs = diag.eigenvalue_eigenvector_pairs(g) for p in val_vec_pairs: prod_s = p.vec * p.val prod_v = matrixmultiply(lin, p.vec) for x in prod_s - prod_v: self.assert_(abs(x) < 1.0e-15)
def sartran(self, rho, x, force=0, precis=DELTA): n = len(x) listflag = 0 if type(x) == list: x = Numeric.array(x, Numeric.Float) listflag = 1 sarx = Numeric.zeros(n, Numeric.Float) if n > WT_SMALL or force: sarx = x wx = self.splag(x) * rho sarx += wx while max(wx) > precis: wx = self.splag(wx) * rho sarx += wx else: # small weights full matrix inverse w = self.wt2mat() w *= -rho w += Numeric.identity(n) wx = LinearAlgebra.inverse(w) sarx = Numeric.matrixmultiply(wx, x) if listflag: return sarx.tolist() else: return sarx
def sartran(self,rho,x,force=0,precis=DELTA): n = len(x) listflag = 0 if type(x) == list: x = Numeric.array(x,Numeric.Float) listflag = 1 sarx = Numeric.zeros(n,Numeric.Float) if n > WT_SMALL or force: sarx = x wx = self.splag(x) * rho sarx += wx while max(wx) > precis: wx = self.splag(wx) * rho sarx += wx else: # small weights full matrix inverse w = self.wt2mat() w *= - rho w += Numeric.identity(n) wx = LinearAlgebra.inverse(w) sarx = Numeric.matrixmultiply(wx,x) if listflag: return sarx.tolist() else: return sarx
def matrix_is_symplectic(self, m, tolerance=1.0e-12): """ Confirm that a given matrix $M$ is symplectic to within numerical tolerance. This is done by taking the 4 submatrices: 1. $A = M[0::2, 0::2]$, i.e., configuration coordinates only, 2. $B = M[0::2, 1::2]$, i.e., configuration rows, momenta cols, 3. $C = M[1::2, 0::2]$, i.e., momenta rows, configuration cols, 4. $D = M[1::2, 1::2]$, i.e., momenta only, and verifying the following symplectic identities:- 1. $MJM^{T} = J$, the $2n\\times 2n$ sympletic matrix, 2. $AD^{T}-BC^{T} = I$, the $n\\times n$ identity, 3. $AB^{T}-BA^{T} = Z$, the $n\\times n$ zero, 4. $CD^{T}-DC^{T} = Z$. Finally, we confirm that $\\det{M} = 1$. """ det = determinant(m) j = self.skew_symmetric_matrix() approx_j = matrixmultiply(m, matrixmultiply(j, transpose(m))) a = m[0::2, 0::2] #even, even b = m[0::2, 1::2] #even, odd c = m[1::2, 0::2] #odd, even d = m[1::2, 1::2] #odd, odd i = self.identity_matrix(self.dof()) approx_i = matrixmultiply(a, transpose(d)) - matrixmultiply( b, transpose(c)) approx_z0 = matrixmultiply(a, transpose(b)) - matrixmultiply( b, transpose(a)) approx_z1 = matrixmultiply(c, transpose(d)) - matrixmultiply( d, transpose(c)) norm = self.matrix_norm logger.info('Matrix from diagonal to equilibrium coordinates:') logger.info('[output supressed]') #logger.info(m) logger.info('error in determinant: %s', abs(det - 1.0)) logger.info('error in symplectic identity #1: %s', norm(approx_j - j)) logger.info('error in symplectic identity #2: %s', norm(approx_i - i)) logger.info('error in symplectic identity #3: %s', norm(approx_z0)) logger.info('error in symplectic identity #4: %s', norm(approx_z1)) okay = True if not (abs(det - 1.0) < tolerance): okay = False if not (norm(approx_j - j) < tolerance): okay = False if not (norm(approx_i - i) < tolerance): okay = False if not (norm(approx_z0) < tolerance): okay = False if not (norm(approx_z1) < tolerance): okay = False return okay
def getAppxCurve(self, appxCoef): return Numeric.matrixmultiply(appxCoef, self.y)
def compare_normal_form(dir_name1, dir_name2, grade=4): def compare_matrix(dia, mat1, mat2, comment): print dia.matrix_norm(array(mat1, Float)-array(mat2, Float)), comment print "Comparing data in Normal form files upto grade %d" %(grade) print print "Reading python data" first = NormalFormData(dir_name1, is_xxpp_format=True, degree=grade) ring = PolynomialRing(first.equi_to_tham.n_vars()) print print "Comparing python data with cpp files upto grade %d" %(grade) print "l_infinity_norm \t l1_norm \t\t polynomials" ringIO = PolynomialRingIO(ring) file_istr = open("hill_l1_18--norm_to_diag.vpol", 'r') pv_norm_to_diag = ringIO.read_sexp_vector_of_polynomials(file_istr) compare_poly_vec(first.norm_to_diag, pv_norm_to_diag, "norm_to_diag", grade=grade-1) file_istr = open("hill_l1_18--diag_to_norm.vpol", 'r') pv_diag_to_norm = ringIO.read_sexp_vector_of_polynomials(file_istr) compare_poly_vec(first.diag_to_norm, pv_diag_to_norm, "diag_to_norm", grade=grade-1) print print "Reading mathematica data" n_ints = len(first.ints_to_freq) # get the frequencies to find the order of the planes order_f=[poly((0.0,)*n_ints) for poly in first.ints_to_freq] second = NormalFormData(dir_name2, order_f=order_f, is_xxpp_format=True, degree=grade) from Diagonal import Diagonalizer lie = LieAlgebra(n_ints) dia = Diagonalizer(lie) grade_ints = grade / 2 dia.matrix_is_symplectic(array(first.diag_to_equi, Float)) dia.matrix_is_symplectic(array(second.diag_to_equi, Float)) dia.matrix_is_symplectic(array(first.equi_to_diag, Float)) dia.matrix_is_symplectic(array(second.equi_to_diag, Float)) # For the case develloped, Hill, there is a 45deg rotation between the # diagonalised coordinates in each of the centre planes. Thus: # These matrices are different #compare_matrix(dia, first.diag_to_equi, second.diag_to_equi, "diag_to_equi") #compare_matrix(dia, first.equi_to_diag, second.equi_to_diag, "equi_to_diag") # We neeed to convert between the diagonal planes and back to # compare the nonlinear normalisation plolynomials # second.diag_to_first.diag = first.diag_in_terms_of_second.diag = fd_in_sd = dia.matrix_as_vector_of_row_polynomials(matrixmultiply( array(first.equi_to_diag, Float),array(second.diag_to_equi, Float))) sd_in_fd = dia.matrix_as_vector_of_row_polynomials(matrixmultiply( array(second.equi_to_diag, Float),array(first.diag_to_equi, Float))) print print "Comparing mathematica data with cpp files upto grade %d" %(grade-1) compare_poly_vec(pv_norm_to_diag, poly_vec_substitute(fd_in_sd, poly_vec_substitute( poly_vec_isograde(second.norm_to_diag, grade-1), sd_in_fd)), "norm_to_diag", grade=grade-1) print "Comparing mathematica data with cpp files upto grade %d" %(grade-1) compare_poly_vec(pv_diag_to_norm, poly_vec_substitute(fd_in_sd, poly_vec_substitute( poly_vec_isograde(second.diag_to_norm, grade-1), sd_in_fd)), "diag_to_norm", grade=grade-1) print print "Comparing mathematica data with python upto grade %d" %(grade) compare_poly(first.equi_to_tham, second.equi_to_tham, "equi_to_tham", grade=grade) compare_poly_vec(first.ints_to_freq , second.ints_to_freq , "ints_to_freq", grade=grade_ints-1) ring_ints = PolynomialRing(second.ints_to_tham.n_vars()) poly_2 = ring_ints.isograde(second.ints_to_tham, 0, up_to=grade_ints+1) compare_poly(first.ints_to_tham , poly_2 , "ints_to_tham") compare_poly_vec(first.norm_to_ints , second.norm_to_ints , "norm_to_ints", grade=grade) second.diag_to_norm = poly_vec_isograde(second.diag_to_norm, grade) second.norm_to_diag = poly_vec_isograde(second.norm_to_diag, grade) compare_poly_vec(first.norm_to_diag, poly_vec_substitute(fd_in_sd, poly_vec_substitute( second.norm_to_diag, sd_in_fd)), "norm_to_diag", grade=grade-1) compare_poly_vec(first.diag_to_norm, poly_vec_substitute(fd_in_sd, poly_vec_substitute( second.diag_to_norm, sd_in_fd)), "diag_to_norm", grade=grade-1) compare_poly_vec(first.diag_to_norm, second.diag_to_norm,"diag_to_norm", grade=grade-1) compare_poly_vec(first.diag_to_norm, poly_vec_substitute(fd_in_sd, poly_vec_substitute( second.diag_to_norm, sd_in_fd)), "diag_to_norm", grade=grade) compare_poly_vec(first.equi_to_tvec, second.equi_to_tvec,"equi_to_tvec", grade=grade-1)
def getAppxCoef(self, curves): return Numeric.matrixmultiply(curves, Numeric.transpose(self.yyTinvy))
def DoVolBalance(self, calcStatus=CALCULATED_V): """performs a volume or stdliqvolume balance """ balanced = 0 if len(self._matIn): aPort = self._matIn[0] elif len(self._matOut): aPort = self._matOut[0] else: balanced = 1 return balanced #Keep track of std vol and vol and see which one can be solved for missingStdVol = None missingxStdVol = None sumStdVol = 0.0 canDoStdVol = True missingVol = None missingxVol = None sumVol = 0.0 canDoVol = True #Put all the mole flows in vectors moleFlows = [] compositions = [] signs = [] enthalpies = [] mode = None # do inlets for port in self._matIn: moleFlows.append(port.GetLocalValue(MOLEFLOW_VAR)) enthalpies.append(port.GetLocalValue(H_VAR)) x = port.GetCompositionValues() compositions.append(x) signs.append(1.0) if canDoStdVol: stdVolFlow = port.GetLocalValue(STDVOLFLOW_VAR) if stdVolFlow == None: if missingStdVol != None: # don't know enough to do anything canDoStdVol = False else: #Must know composition in unknown stdvol if x == None or None in x: canDoStdVol = False missingStdVol = port missingInletStdVol = 1 else: sumStdVol += stdVolFlow #Keep track of which port is missing composition if x == None or None in x: if missingxStdVol: #Can not be missing composition in more than one port canDoStdVol = False else: missingxStdVol = port if canDoVol: volFlow = port.GetLocalValue(VOLFLOW_VAR) if volFlow == None: if missingVol != None: # don't know enough to do anything canDoVol = False else: #Must know composition in unknown stdvol if x == None or None in x: canDoVol = False missingVol = port missingInletVol = 1 else: sumVol += volFlow #Keep track of which port is missing composition if x == None or None in x: if missingxVol: #Can not be missing composition in more than one port canDoVol = False else: missingxVol = port if not canDoStdVol and not canDoVol: return balanced #Nothing can be done # now the outlets for port in self._matOut: moleFlows.append(port.GetLocalValue(MOLEFLOW_VAR)) enthalpies.append(port.GetLocalValue(H_VAR)) x = port.GetCompositionValues() compositions.append(x) signs.append(-1.0) if canDoStdVol: stdVolFlow = port.GetLocalValue(STDVOLFLOW_VAR) if stdVolFlow == None: if missingStdVol != None: # don't know enough to do anything canDoStdVol = False else: #Must know composition in unknown stdvol if x == None or None in x: canDoStdVol = False missingStdVol = port missingInletStdVol = 0 else: sumStdVol -= stdVolFlow #Keep track of which port is missing composition if x == None or None in x: if missingxStdVol: #Can not be missing composition in more than one port canDoStdVol = False else: missingxStdVol = port if canDoVol: volFlow = port.GetLocalValue(VOLFLOW_VAR) if volFlow == None: if missingVol != None: # don't know enough to do anything canDoVol = False else: #Must know composition in unknown stdvol if x == None or None in x: canDoVol = False missingVol = port missingInletVol = 0 else: sumVol -= volFlow #Keep track of which port is missing composition if x == None or None in x: if missingxVol: #Can not be missing composition in more than one port canDoVol = False else: missingxVol = port if not canDoStdVol and not canDoVol: return balanced #Nothing can be done #Decide which balance can be done ##!! ##Starting here, the prefix vol will be used for vol and stdvol depending on the selected mode ##Use v to refer to the port that is missing the volume flow ##Use x to refer to the port that is missing the composition vPort = None xPort = None if canDoStdVol: mode = STDVOLFLOW_VAR vPort = missingStdVol vInlet = missingInletStdVol xPort = missingxStdVol sum = sumStdVol vMolVol = vPort.GetPropValue(STDLIQVOL_VAR) xVolFlow = xPort.GetPropValue(STDVOLFLOW_VAR) elif canDoVol: mode = VOLFLOW_VAR vPort = missingVol vInlet = missingInletVol xPort = missingxVol sum = sumVol vMolVol = vPort.GetPropValue(MOLARV_VAR) xVolFlow = xPort.GetPropValue(VOLFLOW_VAR) else: return balanced #Don't solve if already fully specified. Let the other balances #check for consistency errors if vPort == None or xPort == None: balanced = 1 return balanced #Find the indexes of the ports with the missing info vIdx = None xIdx = None cnt = 0 for port in self._matIn + self._matOut: if port is vPort: vIdx = cnt if port is xPort: xIdx = cnt cnt += 1 if vIdx == None or xIdx == None: return balanced #Get some thermo info parentOp = xPort._parentOp if parentOp == None: return balanced thCaseObj = parentOp.GetThermo() if thCaseObj == None: return balanced thAdmin, prov, case = thCaseObj.thermoAdmin, thCaseObj.provider, thCaseObj.case refT = parentOp.GetStdVolRefT() #Rearange the information in vectors if vMolVol == None: if mode == STDVOLFLOW_VAR: vMolVol = thAdmin.GetArrayProperty(prov, case, (P_VAR, 101.325), (T_VAR, refT), LIQUID_PHASE, array(compositions[vIdx], Float), STDLIQMOLVOLPERCMP_VAR) if vMolVol == None: return balanced vMolVol = Numeric.sum(array(compositions[vIdx], Float)*vMolVol) if vMolVol == None: return balanced #Remove info from port with missing composition xH = enthalpies[xIdx] vH = enthalpies[vIdx] xT = None xSign = signs[xIdx] del moleFlows[xIdx] del compositions[xIdx] del signs[xIdx] del enthalpies[xIdx] if vIdx > xIdx: vIdx -= 1 #Estimate a mole flow and convert arrays to Numeric array if vInlet: sum = -sum vVolFlow = sum vMoleFlow = vVolFlow / vMolVol moleFlows[vIdx] = vMoleFlow try: moleFlows = array(moleFlows, Float) except: return balanced compositions = array(compositions, Float) signs = array(signs, Float) if mode == VOLFLOW_VAR: xP = xPort.GetPropValue(P_VAR) if xP == None: return balanced nuSolids = parentOp.NumberSolidPhases() propsDict = MaterialPropertyDict() xList = CompoundList(None) for val in compositions[0]: xList.append(BasicProperty(FRAC_VAR)) if vH == None: #If enthalpy here is not known, then we should either know T or H in the port #that is missing the composition if xH == None: xT = xPort.GetPropValue(T_VAR) if xT == None: return balanced else: enthalpies = array(enthalpies, Float) #Preapre to iterate maxIter = 20 iter = 0 converged = False scaleFactor = PropTypes[MOLEFLOW_VAR].scaleFactor tolerance = 1.0E-6 errorOld = None while not converged and iter < maxIter: iter += 1 moleFlows[vIdx] = vMoleFlow xMoleFlows = matrixmultiply(moleFlows*signs, compositions) if xSign > 0.0: xMoleFlows *= -1.0 xMoleFlow = Numeric.sum(xMoleFlows) x = xMoleFlows/xMoleFlow if mode == STDVOLFLOW_VAR: xMolVol = thAdmin.GetArrayProperty(prov, case, (P_VAR, 101.325), (T_VAR, refT), LIQUID_PHASE, x, STDLIQMOLVOLPERCMP_VAR) if xMolVol == None: return balanced xMolVol = Numeric.sum(x*xMolVol) else: propsDict[P_VAR].SetValue(xP, FIXED_V) if xT != None: #Use the T if known propsDict[T_VAR].SetValue(xT, FIXED_V) else: #Do energy balance and backcalculate xH xH = Numeric.sum(moleFlows * signs * enthalpies) / xMoleFlow if xSign > 0.0: xH *= -1.0 propsDict[H_VAR].SetValue(xH, FIXED_V) for i in range(len(x)): xList[i].SetValue(x[i], FIXED_V) results = thAdmin.Flash(prov, case, xList, propsDict, 2, (MOLARV_VAR,), nuSolids=nuSolids) xMolVol = results.bulkProps[0] xMoleFlowTest = xVolFlow / xMolVol error = abs(xMoleFlow - xMoleFlowTest) / scaleFactor if error < tolerance: converged = True break #Do a regula falsi if errorOld == None: #Make up a reasonable step vMoleFlowNew = vMoleFlow + (xMoleFlow - xMoleFlowTest)*0.5 else: #Update dy_dx = (error - errorOld) / (vMoleFlow - vMoleFlowOld) vMoleFlowNew = vMoleFlow - error/dy_dx #Keep track of old values vMoleFlowOld = vMoleFlow vMoleFlow = vMoleFlowNew errorOld = error if converged: vPort.SetPropValue(MOLEFLOW_VAR, vMoleFlow, calcStatus) xPort.SetPropValue(MOLEFLOW_VAR, xMoleFlow, calcStatus) xPort.SetCompositionValues(x, calcStatus) if xT == None: xPort.SetPropValue(H_VAR, xH, calcStatus) vPort.CalcFlows() xPort.CalcFlows() return converged
def compare_normal_form(dir_name1, dir_name2, grade=4): def compare_matrix(dia, mat1, mat2, comment): print dia.matrix_norm(array(mat1, Float) - array(mat2, Float)), comment print "Comparing data in Normal form files upto grade %d" % (grade) print print "Reading python data" first = NormalFormData(dir_name1, is_xxpp_format=True, degree=grade) ring = PolynomialRing(first.equi_to_tham.n_vars()) print print "Comparing python data with cpp files upto grade %d" % (grade) print "l_infinity_norm \t l1_norm \t\t polynomials" ringIO = PolynomialRingIO(ring) file_istr = open("hill_l1_18--norm_to_diag.vpol", 'r') pv_norm_to_diag = ringIO.read_sexp_vector_of_polynomials(file_istr) compare_poly_vec(first.norm_to_diag, pv_norm_to_diag, "norm_to_diag", grade=grade - 1) file_istr = open("hill_l1_18--diag_to_norm.vpol", 'r') pv_diag_to_norm = ringIO.read_sexp_vector_of_polynomials(file_istr) compare_poly_vec(first.diag_to_norm, pv_diag_to_norm, "diag_to_norm", grade=grade - 1) print print "Reading mathematica data" n_ints = len(first.ints_to_freq) # get the frequencies to find the order of the planes order_f = [poly((0.0, ) * n_ints) for poly in first.ints_to_freq] second = NormalFormData(dir_name2, order_f=order_f, is_xxpp_format=True, degree=grade) from Diagonal import Diagonalizer lie = LieAlgebra(n_ints) dia = Diagonalizer(lie) grade_ints = grade / 2 dia.matrix_is_symplectic(array(first.diag_to_equi, Float)) dia.matrix_is_symplectic(array(second.diag_to_equi, Float)) dia.matrix_is_symplectic(array(first.equi_to_diag, Float)) dia.matrix_is_symplectic(array(second.equi_to_diag, Float)) # For the case develloped, Hill, there is a 45deg rotation between the # diagonalised coordinates in each of the centre planes. Thus: # These matrices are different #compare_matrix(dia, first.diag_to_equi, second.diag_to_equi, "diag_to_equi") #compare_matrix(dia, first.equi_to_diag, second.equi_to_diag, "equi_to_diag") # We neeed to convert between the diagonal planes and back to # compare the nonlinear normalisation plolynomials # second.diag_to_first.diag = first.diag_in_terms_of_second.diag = fd_in_sd = dia.matrix_as_vector_of_row_polynomials( matrixmultiply(array(first.equi_to_diag, Float), array(second.diag_to_equi, Float))) sd_in_fd = dia.matrix_as_vector_of_row_polynomials( matrixmultiply(array(second.equi_to_diag, Float), array(first.diag_to_equi, Float))) print print "Comparing mathematica data with cpp files upto grade %d" % (grade - 1) compare_poly_vec(pv_norm_to_diag, poly_vec_substitute( fd_in_sd, poly_vec_substitute( poly_vec_isograde(second.norm_to_diag, grade - 1), sd_in_fd)), "norm_to_diag", grade=grade - 1) print "Comparing mathematica data with cpp files upto grade %d" % (grade - 1) compare_poly_vec(pv_diag_to_norm, poly_vec_substitute( fd_in_sd, poly_vec_substitute( poly_vec_isograde(second.diag_to_norm, grade - 1), sd_in_fd)), "diag_to_norm", grade=grade - 1) print print "Comparing mathematica data with python upto grade %d" % (grade) compare_poly(first.equi_to_tham, second.equi_to_tham, "equi_to_tham", grade=grade) compare_poly_vec(first.ints_to_freq, second.ints_to_freq, "ints_to_freq", grade=grade_ints - 1) ring_ints = PolynomialRing(second.ints_to_tham.n_vars()) poly_2 = ring_ints.isograde(second.ints_to_tham, 0, up_to=grade_ints + 1) compare_poly(first.ints_to_tham, poly_2, "ints_to_tham") compare_poly_vec(first.norm_to_ints, second.norm_to_ints, "norm_to_ints", grade=grade) second.diag_to_norm = poly_vec_isograde(second.diag_to_norm, grade) second.norm_to_diag = poly_vec_isograde(second.norm_to_diag, grade) compare_poly_vec(first.norm_to_diag, poly_vec_substitute( fd_in_sd, poly_vec_substitute(second.norm_to_diag, sd_in_fd)), "norm_to_diag", grade=grade - 1) compare_poly_vec(first.diag_to_norm, poly_vec_substitute( fd_in_sd, poly_vec_substitute(second.diag_to_norm, sd_in_fd)), "diag_to_norm", grade=grade - 1) compare_poly_vec(first.diag_to_norm, second.diag_to_norm, "diag_to_norm", grade=grade - 1) compare_poly_vec(first.diag_to_norm, poly_vec_substitute( fd_in_sd, poly_vec_substitute(second.diag_to_norm, sd_in_fd)), "diag_to_norm", grade=grade) compare_poly_vec(first.equi_to_tvec, second.equi_to_tvec, "equi_to_tvec", grade=grade - 1)
def unrot(self, v): return Numeric.matrixmultiply(self.matrix, v)
def rot(self, v): return Numeric.matrixmultiply(v, self.matrix)
def Matrix3fMulMatrix3f (matrix_a, matrix_b): return Numeric.matrixmultiply (matrix_a, matrix_b)
def __init__(self, points, k, normalization=NORM_NORM_T0_1, force=False): """ calculate k polynomials of degree 0 to k-1 orthogonal on a set of distinct points map points to interval [-1,1] INPUT: points: array of dictinct points where polynomials are orthogonal k: number of polynomials of degree 0 to k-1 force=True creates basis even if orthogonality is not satisfied due to numerical error USES: x: array of points mapped to [-1,1] T_: matrix of values of polynomials calculated at x, shape (k,len(x)) TT_ = T_ * Numeric.transpose(T_) TTinv_ = inverse(TT_) sc_: scaling factors a, b: coefficients for calculating T (2k-4 different from 0, i.e. 6 for k=5) n: number of points = len(points) normalization = {0|1|2} """ self.k = k # number of basis polynomials of order 0 to k-1 self._force = force self.points = Numeric.asarray(points, Numeric.Float) self.pointsMin = min(points) self.pointsMax = max(points) # scaling x to [-1,1] results in smaller a and b, T is not affected; overflow is NOT a problem! self.xMin = -1 self.xMax = 1 self.x = self._map(self.points, self.pointsMin, self.pointsMax, self.xMin, self.xMax) # calculate basis polynomials self.n = len(points) # the number of approximation points t = Numeric.zeros((k, self.n), Numeric.Float) a = Numeric.zeros((k, 1), Numeric.Float) b = Numeric.zeros((k, 1), Numeric.Float) t[0, :] = Numeric.ones(self.n, Numeric.Float) if k > 1: t[1, :] = self.x - sum(self.x) / self.n for i in range(1, k - 1): a[i + 1] = Numeric.innerproduct( self.x, t[i, :] * t[i, :]) / Numeric.innerproduct( t[i, :], t[i, :]) b[i] = Numeric.innerproduct(t[i, :], t[i, :]) / Numeric.innerproduct( t[i - 1, :], t[i - 1, :]) t[i + 1, :] = (self.x - a[i + 1]) * t[i, :] - b[i] * t[i - 1, :] self.a = a self.b = b # prepare for approximation self._T0 = t # orthonormal _TT0 = Numeric.matrixmultiply(self._T0, Numeric.transpose(self._T0)) self.sc1 = Numeric.sqrt( Numeric.reshape( Numeric.diagonal(_TT0), (self.k, 1))) # scaling factors = sqrt sum squared self._T0 self._T1 = self._T0 / self.sc1 # orthonormal and T[0] == 1 self.sc2 = Numeric.sqrt( Numeric.reshape(Numeric.diagonal(_TT0), (self.k, 1)) / self.n) # scaling factors = sqrt 1/n * sum squared self._T0 self._T2 = self._T0 / self.sc2 # T[:,-1] == 1 self.sc3 = Numeric.take(self._T0, (-1, ), 1) # scaling factors = self._T0[:,-1] self._T3 = self._T0 / self.sc3 # set the variables according to the chosen normalization self.setNormalization(normalization)