def stability_matrix(self, z): r""" Constructs the stability matrix of a two-step Runge-Kutta method. Right now just for a specific value of z. We ought to use Sage to do it symbolically. **Output**: M -- stability matrix evaluated at z WARNING: This only works for Type I & Type II methods right now!!! """ s = self.Ahat.shape[1] if self.type == 'General': # J Y^n = K Y^{n-1} K1 = np.column_stack((z * self.Ahat, self.d, 1 - self.d)) K2 = snp.zeros(s + 2) K2[-1] = 1 K3 = np.concatenate( (z * self.bhat, np.array((self.theta, 1 - self.theta)))) K = np.vstack((K1, K2, K3)) J = snp.eye(s + 2) J[:s, :s] = J[:s, :s] - z * self.A J[-1, :s] = z * self.b M = snp.solve(J.astype('complex64'), K.astype('complex64')) #M = snp.solve(J, K) # This version is slower else: D = np.hstack([1. - self.d, self.d]) thet = np.hstack([1. - self.theta, self.theta]) A, b = self.A, self.b if self.type == 'Type II': ahat = np.zeros([self.s, 1]) ahat[:, 0] = self.Ahat[:, 0] bh = np.zeros([1, 1]) bh[0, 0] = self.bhat[0] A = np.hstack([ahat, self.A]) A = np.vstack([np.zeros([1, self.s + 1]), A]) b = np.vstack([bh, self.b]) M1 = np.linalg.solve(np.eye(self.s) - z * self.A, D) L1 = thet + z * np.dot(self.b.T, M1) M = np.vstack([L1, [1., 0.]]) return M
def stability_matrix(self,z): r""" Constructs the stability matrix of a two-step Runge-Kutta method. Right now just for a specific value of z. We ought to use Sage to do it symbolically. **Output**: M -- stability matrix evaluated at z WARNING: This only works for Type I & Type II methods right now!!! """ s = self.Ahat.shape[1] if self.type == 'General': # J Y^n = K Y^{n-1} K1 = np.column_stack((z*self.Ahat,self.d,1-self.d)) K2 = snp.zeros(s+2); K2[-1] = 1 K3 = np.concatenate((z*self.bhat,np.array((self.theta,1-self.theta)))) K = np.vstack((K1,K2,K3)) J = snp.eye(s+2) J[:s,:s] = J[:s,:s] - z*self.A J[-1,:s] = z*self.b M = snp.solve(J.astype('complex64'),K.astype('complex64')) #M = snp.solve(J, K) # This version is slower else: D=np.hstack([1.-self.d,self.d]) thet=np.hstack([1.-self.theta,self.theta]) A,b=self.A,self.b if self.type=='Type II': ahat = np.zeros([self.s,1]); ahat[:,0] = self.Ahat[:,0] bh = np.zeros([1,1]); bh[0,0]=self.bhat[0] A = np.hstack([ahat,self.A]) A = np.vstack([np.zeros([1,self.s+1]),A]) b = np.vstack([bh,self.b]) M1=np.linalg.solve(np.eye(self.s)-z*self.A,D) L1=thet+z*np.dot(self.b.T,M1) M=np.vstack([L1,[1.,0.]]) return M
def downwind_shu_osher_to_butcher(alpha, alphat, beta, betat): r""" Accepts a Shu-Osher representation of a downwind Runge-Kutta method and returns the Butcher coefficients \\begin{align*} A = & (I-\\alpha_0-\\alphat_0)^{-1} \\beta_0 \\\\ At = & (I-\\alpha_0-\\alphat_0)^{-1} \\betat_0 \\\\ b = & \\beta_1 + (\\alpha_1 + \\alphat_1) * A \\end{align*} **References**: #. [gottlieb2009]_ """ m = np.size(alpha, 1) if not np.all([np.size(alpha, 0), np.size(beta, 0), np.size(beta, 1)] == [m + 1, m + 1, m]): raise Exception("Inconsistent dimensions of Shu-Osher arrays") X = snp.eye(m) - alpha[0:m, :] - alphat[0:m, :] A = snp.solve(X, beta[0:m, :]) At = snp.solve(X, betat[0:m, :]) b = beta[m, :] + np.dot(alpha[m, :] + alphat[m, :], A) bt = betat[m, :] + np.dot(alpha[m, :] + alphat[m, :], At) return A, At, b, bt
def downwind_shu_osher_to_butcher(alpha, alphat, beta, betat): r""" Accepts a Shu-Osher representation of a downwind Runge-Kutta method and returns the Butcher coefficients \\begin{align*} A = & (I-\\alpha_0-\\alphat_0)^{-1} \\beta_0 \\\\ At = & (I-\\alpha_0-\\alphat_0)^{-1} \\betat_0 \\\\ b = & \\beta_1 + (\\alpha_1 + \\alphat_1) * A \\end{align*} **References**: #. [gottlieb2009]_ """ m = np.size(alpha, 1) if not np.all([np.size(alpha, 0), np.size(beta, 0), np.size(beta, 1)] == [m + 1, m + 1, m]): raise Exception('Inconsistent dimensions of Shu-Osher arrays') X = snp.eye(m) - alpha[0:m, :] - alphat[0:m, :] A = snp.solve(X, beta[0:m, :]) At = snp.solve(X, betat[0:m, :]) b = beta[m, :] + np.dot(alpha[m, :] + alphat[m, :], A) bt = betat[m, :] + np.dot(alpha[m, :] + alphat[m, :], At) return A, At, b, bt