I am trying to find the determinant of the matrix M which is constructed using 12 equations. But when I took determinat. It is coming as zero. The matrix is symbolic in nature. I have used sympy package to construct the matrix M. The possible out is an analytical expression which is a function of a,b,z1,z2,l,L,g
from sympy import *
from numpy.linalg import matrix_rank
b,g,l,a,L,z1,z2,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,d1,d2,d3,d4,x,y = var('b g l a L z1 z2
c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 d1 d2 d3 d4 x y')
#beam equation
W1= c1*cos(b*x) + c2*sin(b*x) + c3*cosh(b*x) + c4*sinh(b*x)
W2= c5*cos(b*(x - z1)) + c6*sin(b*(x - z1)) + c7*cosh(b*(x - z1)) + c8*sinh(b*(x - z1))
W3=c10*sin(b*(x - z2)) + c11*cosh(b*(x - z2)) + c12*sinh(b*(x - z2)) + c9*cos(b*(x - z2))
#Boundary conditions on beam
e1=W1.subs(x,0)
e2=diff(W1, x).subs(x,0)
e3=diff(W1, x,2).subs(x,1)
e4=diff(W1, x,3).subs(x,1)
#bar equation
U1=d1*cos(L*y) + d2*sin(L*y)
U2=d3*cos(L*y) + d4*sin(L*y)
print(U2)
# Boundary conditions on bar*)
e5 = U1 .subs( y, 0);
e6 = (U1 .subs( y, g)) - (W1 .subs( x, z1));
e7 = U2 .subs( y, 0);
e8 = (U2 .subs( y, g)) - (W2 .subs( x, z2));
eqns = [e5,e6, e7, e8]
ss=linsolve(eqns, [d1,d2, d3, d4])
ss=list(ss)[0]
dd1=ss[0]
dd2=ss[1]
dd3=ss[2]
dd4=ss[3]
U1=U1.subs([(d1,dd1),(d2,dd2)])
U2=U2.subs([(d3,dd3),(d4,dd4)])
#Compatability conditions
e9= (W1.subs( x, z1)) - (W2.subs(x, z1))
e10=(diff(W1, x).subs(x,z1))-(diff(W2, x).subs(x,z1))
e11=(W2.subs( x, z2)) - (W3.subs(x, z2))
e12=(diff(W2, x).subs(x,z2))-(diff(W3, x).subs(x,z2))
#equlibrium equation
e13=(diff(W1, x,3).subs(x,z1))+(a*(diff(U1, y).subs(y,g)))-(diff(W2, x,3).subs(x,z1))
e14=(diff(W1, x,2).subs(x,z1)) + (diff(W2, x,2).subs(x,z1))
e15 =(diff(W2, x,3).subs(x,z2))+(a*(diff(U2, y).subs(y,g)))-(diff(W3, x,3).subs(x,z2))
e16 =(diff(W2, x,2).subs(x,z2)) + (diff(W3, x,2).subs(x,z2))
eqnlist=[e1,e2,e3,e4,e9,e10,e11,e12,e13,e14,e15,e16]
varibles=[c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12]
M, B = linear_eq_to_matrix(eqnlist,varibles)
M.det()
Related
I have this function for solve_ivp, which solves a series of differential equations.
For every time step, the variable position [Pos] should be updated depending on a probability of it jumping. However, solve_ivp is not remembering the previous variable.
def jump_fun(t, Y, P, flux = 670):
global Pos_list
k1, k2 , k3, k4, k5, k6 , k , kay, q , K1, c5_tot, c6_tot, phi, Nc, V, qs, Cx, Ks, F, Cs0, flux, Pos, Pos_list = P
c1, c2, c3, c4, c5 ,c6, c4ex1, c4ex2, Cs1, Cs2= Y.reshape([10,-1])
#print(c1, c2, c3, c4, c5 ,c6, c4ex, Cs, Pos)
print(f'Pos: {Pos}')
# function heterogeneous_environment
prob = heterogeneous_environment(Nc, flux, V, 10, 10)
print(f'prob: {prob}')
#These arrays keep track of where the cells are
R1 = np.where(Pos == 1, 1, 0 )
R2 = np.where(Pos == 2, 1, 0 )
# We need to know the external concentrations of each reactor
rs1 = (Cx*qs*Cs1/ (Ks+Cs1))
dCs1 = F/V + flux*Cs2/V - flux*Cs1/V - rs1 # Position of cell is reactor 1, C1 = Cs
rs2 = (Cx*qs*Cs2/ (Ks+Cs2))
dCs2 = flux*Cs1/V - flux*Cs2/V - rs2 # Position of cell is reactor 2, C2 = Cs
j0 = rs1*R1 + rs2*R2
jm1 = kay * (c4 - c4ex1)*R1
jm2 = kay * (c4 - c4ex2)*R2
dc1= j0 - (k1 * c1 * c6 * (1/( 1 + ((c6/K1 )**q))))
dc2 = 2* k1 * c1 * c6 * (1/( 1 + ((c6/K1 )**q))) - k2 * c2 * (c5_tot - c5) - k6 *c2 *c5
dc3 = k2 * c2 * (c5_tot - c5) - k3 * c3* (c6_tot - c6)
dc4 = k3 * c3* (c6_tot - c6) - k4 * c4 *c5 - (jm1*R1 + jm2*R2)
dc5= k2 * c2 * (c5_tot - c5) - k4 * c4 *c5 - k6 *c2 *c5
dc6 = -2 * k1 * c1 * c6 * (1/( 1 + ((c6/K1 )**q))) + 2 * k3 * c3* (c6_tot - c6) - k5 * c6
cell1 = np.count_nonzero(R1 == 1)
cell2 = np.count_nonzero(R2 == 1)
dc4ex1= - k * c4ex1 + (phi / cell1) * np.sum(jm1) - (flux*c4ex1)/V + (flux*c4ex2)/V
dc4ex2= - k * c4ex2 + (phi / cell2) * np.sum(jm2) + (flux*c4ex1)/V - (flux*c4ex2)/V
#print('1')
#print(Pos)
#print('2')
Pos = Pos + prob*R1
Pos = Pos - prob*R2
#print(Pos)
Pos_list.append(Pos)
#iterate through the Pos vector, if Pos =1 do the balances for reactor 1 and then if the probability says to change
#reactor, change the position of the cell. Same for POS=2
#UPDATE THE MASS BALANCE FOR EACH REACTOR
return dc1, dc2, dc3, dc4, dc5 , dc6, dc4ex1, dc4ex2, dCs1, dCs2
I tried passing Pos as a return of the function, but it also didn't seem to work. Please help.
I compared results of rotating a vector with scipy.spatial.transform.Rotation, pyquaternion.Quaternion and my own implementation.
My own and pyquaternion and pretty similar, but Rotation is quite different.
import numpy as np
from pyquaternion import Quaternion
from scipy.spatial.transform import Rotation
def ham(q1, q2):
a1, b1, c1, d1 = q1
a2, b2, c2, d2 = q2
return np.array(
[
a1 * a2 - b1 * b2 - c1 * c2 - d1 * d2,
a1 * b2 + b1 * a2 + c1 * d2 - d1 * c2,
a1 * c2 - b1 * d2 + c1 * a2 + d1 * b2,
a1 * d2 + b1 * c2 - c1 * b2 + d1 * a2,
]
)
vector = np.array([-9.86411084, 0.10916063, -0.68953008])
purequat = np.array([0, -9.86411084, 0.10916063, -0.68953008])
# order: w, i, j, k
quat = np.array([-0.54312134, 0.42388916, -0.45617676, 0.5632019])
conj = np.array([1, -1, -1, -1])
quatconj = quat * conj # hand conjugate
Q = Quaternion(quat)
R = Rotation.from_quat(quat)
print("manual:", ham(quat, ham(purequat, quatconj))[1:])
print("Quaternion:", Q.rotate(vector))
print("Rotation:", R.apply(vector))
print("Rotation inv:", R.inv().apply(vector))
manual: [-0.14691211 9.88691296 -0.08305227]
Quaternion: [-0.14691852 9.88734378 -0.08305589]
Rotation: [-2.87868815 9.45502779 -0.32195404]
Rotation inv: [-2.33238602 0.16116154 -9.60843655]
I think the result of scipy is wrong, but maybe I'm misunderstanding something. Am I misunderstanding something or should I open an issue on the scipy bugtracker?
The answer was of course, very obvious. Given a quaternion w + xi + yj + zk then pyquaternion treats an array of four numbers as [w,x,y,z] while scipy as [x,y,z,w].
I have wrote a code for Runge-Kutta 4th order, which works perfectly fine for a system of differential equations:
import numpy as np
import matplotlib.pyplot as plt
import numba
import time
start_time = time.clock()
#numba.jit()
def V(u,t):
x1,dx1, x2, dx2=u
ddx1=-w**2 * x1 -b * dx1
ddx2=-(w+0.5)**2 * x2 -(b+0.1) * dx2
return np.array([dx1,ddx1,dx2,ddx2])
#numba.jit()
def rk4(f, u0, t0, tf , n):
t = np.linspace(t0, tf, n+1)
u = np.array((n+1)*[u0])
h = t[1]-t[0]
for i in range(n):
k1 = h * f(u[i], t[i])
k2 = h * f(u[i] + 0.5 * k1, t[i] + 0.5*h)
k3 = h * f(u[i] + 0.5 * k2, t[i] + 0.5*h)
k4 = h * f(u[i] + k3, t[i] + h)
u[i+1] = u[i] + (k1 + 2*(k2 + k3) + k4) / 6
return u, t
u, t = rk4(V,np.array([0,0.2,0,0.3]) ,0,100, 20000)
print("Execution time:",time.clock() - start_time, "seconds")
x1,dx1,x2,dx2 = u.T
plt.plot(x1,x2)
plt.xlabel('X1')
plt.ylabel('X2')
plt.show()
The above code, returns the desired result:
And thanks to Numba JIT, this code works really fast. However, this method doesn't use adaptive step size and hence, it is not very suitable for a system of stiff differential equations. Runge Kutta Fehlberg method, solves this problem by using a straight forward algorithm. Based on the algorithm (https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta%E2%80%93Fehlberg_method) I wrote this code which works for only one differential equation :
import numpy as np
def rkf( f, a, b, x0, tol, hmax, hmin ):
a2 = 2.500000000000000e-01 # 1/4
a3 = 3.750000000000000e-01 # 3/8
a4 = 9.230769230769231e-01 # 12/13
a5 = 1.000000000000000e+00 # 1
a6 = 5.000000000000000e-01 # 1/2
b21 = 2.500000000000000e-01 # 1/4
b31 = 9.375000000000000e-02 # 3/32
b32 = 2.812500000000000e-01 # 9/32
b41 = 8.793809740555303e-01 # 1932/2197
b42 = -3.277196176604461e+00 # -7200/2197
b43 = 3.320892125625853e+00 # 7296/2197
b51 = 2.032407407407407e+00 # 439/216
b52 = -8.000000000000000e+00 # -8
b53 = 7.173489278752436e+00 # 3680/513
b54 = -2.058966861598441e-01 # -845/4104
b61 = -2.962962962962963e-01 # -8/27
b62 = 2.000000000000000e+00 # 2
b63 = -1.381676413255361e+00 # -3544/2565
b64 = 4.529727095516569e-01 # 1859/4104
b65 = -2.750000000000000e-01 # -11/40
r1 = 2.777777777777778e-03 # 1/360
r3 = -2.994152046783626e-02 # -128/4275
r4 = -2.919989367357789e-02 # -2197/75240
r5 = 2.000000000000000e-02 # 1/50
r6 = 3.636363636363636e-02 # 2/55
c1 = 1.157407407407407e-01 # 25/216
c3 = 5.489278752436647e-01 # 1408/2565
c4 = 5.353313840155945e-01 # 2197/4104
c5 = -2.000000000000000e-01 # -1/5
t = a
x = np.array(x0)
h = hmax
T = np.array( [t] )
X = np.array( [x] )
while t < b:
if t + h > b:
h = b - t
k1 = h * f( x, t )
k2 = h * f( x + b21 * k1, t + a2 * h )
k3 = h * f( x + b31 * k1 + b32 * k2, t + a3 * h )
k4 = h * f( x + b41 * k1 + b42 * k2 + b43 * k3, t + a4 * h )
k5 = h * f( x + b51 * k1 + b52 * k2 + b53 * k3 + b54 * k4, t + a5 * h )
k6 = h * f( x + b61 * k1 + b62 * k2 + b63 * k3 + b64 * k4 + b65 * k5, \
t + a6 * h )
r = abs( r1 * k1 + r3 * k3 + r4 * k4 + r5 * k5 + r6 * k6 ) / h
if len( np.shape( r ) ) > 0:
r = max( r )
if r <= tol:
t = t + h
x = x + c1 * k1 + c3 * k3 + c4 * k4 + c5 * k5
T = np.append( T, t )
X = np.append( X, [x], 0 )
h = h * min( max( 0.84 * ( tol / r )**0.25, 0.1 ), 4.0 )
if h > hmax:
h = hmax
elif h < hmin:
raise RuntimeError("Error: Could not converge to the required tolerance %e with minimum stepsize %e." % (tol,hmin))
break
return ( T, X )
but I'm struggling to convert it to a function like the first code, where I can input a system of differential equations. The most confusing part for me, is how can I vectorize everything in the second code without messing things up. In other words, I cannot reproduce the first result using the RKF algorithm. Can anyone point me in the right direction?
I'm not really sure where your problem lies. Setting the not given parameters to w=1; b=0.1 and calling, without changing anything
T, X = rkf( f=V, a=0, b=100, x0=[0,0.2,0,0.3], tol=1e-6, hmax=1e1, hmin=1e-16 )
gives the phase plot
The step sizes grow as the system slows down as
which is the expected behavior for an unfiltered step size controller.
For the differential equation mx'' + kx = 0 (where x'' is double derivative of x with respect to t), how to solve this for x(t)? I mean how to get this equation:
x(t) = c1*cos(sqrt(k/m)*t) + c2*sin(sqrt(k/m)*t)
What I tried:
t, g, k, m, w0, a_0, b_0, c1, c2 = symbols('t g k m w0 a_0 b_0 c1 c2')
x = symbols('x', cls=Function)
w0 = sqrt(k/m)
diffeq = Eq(x(t).diff(t, t) + k*x, 0)
but the statement diffeq = Eq(x(t).diff(t, t) + k*x, 0) throws an error:
TypeError: unbound method as_base_exp() must be called with x instance as first argument (got nothing instead)
I made it work and able to solve the equation for coefficients C1 and C2. Here is the code:
t, a0, b0, k, m, g = symbols('t a0 b0 k m g')
x = Function('f')
diffeq = m*Derivative(x(t), t, t) + k*x(t) + m*g
# print(diffeq)
x_sl30 = dsolve(diffeq, x(t)).rhs
print(x_sl30)
# Initial condition, x(0) = a0 and x'(0) = b0
c_0 = Eq(x_sl30.subs(t, 0), a0)
c_1 = Eq(x_sl30.diff(t).subs(t, 0), b0)
# print(c_0)
# print(c_1)
C1, C2 = symbols("C1, C2")
C1C2_sl = solve([c_0, c_1], (C1, C2))
#Substitute the value of C1 and C2 in the original equation
x_sl31 = x_sl30.subs(C1C2_sl)
print(x_sl31)
I get a NameError when using SymPy nonlinsolve. After reading a lot of posts I think can be related to type and/or syntax, but I cannot find the exact cause, I just installed sympy a few days ago and my python version is Python 3.5.3 (default, Jan 19 2017, 14:11:04)
[GCC 6.3.0 20170118] on linux
thanks in advance
Vilbjorg
# Python 3 script , using SymPy library, parametrizatrion of the 3-sphere and rotations using quaternion multiplication
# python3 three_sphere.py
from sympy import *
def qmul(x0, x1, x2, x3, y0, y1, y2, y3):
z0 = x0*y0 - x1*y1 - x2*y2 - x3*y3
z1 = x0*y1 + x1*y0 + x2*y3 - x3*y2
z2 = x0*y2 - x1*y3 + x2*y0 + x3*y1
z3 = x0*y3 + x1*y2 - x2*y1 + x3*y0
return z0, z1, z2, z3
r1, s1, t1, r2, s2, t2 = symbols('r1, s1, t1, r2, s2, t2')
a0 = 2*r1/(1 + r1*r1 + s1*s1 + t1*t1)
a1 = 2*s1/(1 + r1*r1 + s1*s1 + t1*t1)
a2 = 2*t1/(1 + r1*r1 + s1*s1 + t1*t1)
a3 = (1 - r1*r1 - s1*s1 - t1*t1)/(1 + r1*r1 + s1*s1 + t1*t1)
b0 = 2*r2/(1 + r2*r2 + s2*s2 + t2*t2)
b1 = 2*s2/(1 + r2*r2 + s2*s2 + t2*t2)
b2 = 2*t2/(1 + r2*r2 + s2*s2 + t2*t2)
b3 = (1 - r2*r2 - s2*s2 - t2*t2)/(1 + r2*r2 + s2*s2 + t2*t2)
c0, c1, c2, c3 = qmul(a0, a1, a2, a3, b0, b1, b2, b3)
c0 = simplify(c0)
c1 = simplify(c1)
c2 = simplify(c2)
c3 = simplify(c3)
print(c0)
print(" ")
print(c1)
print(" ")
print(c2)
print(" ")
print(c3)
print(" ")
print(" ")
r3, s3, t3 = symbols('r3, s3, t3')
q0 = 2*r3/(1 + r3*r3 + s3*s3 + t3*t3)
q1 = 2*s3/(1 + r3*r3 + s3*s3 + t3*t3)
q2 = 2*t3/(1 + r3*r3 + s3*s3 + t3*t3)
q3 = (1 - r3*r3 - s3*s3 - t3*t3)/(1 + r3*r3 + s3*s3 + t3*t3)
#possibly syntax error here which causes NameError ??
soln = nonlinsolve([q0-c0, q1-c1, q2-c2, q3-c3], (r3, s3, t3))
# the idea is to have 4 equations : q0=c0, q1=c1. q2=c2. q3=c3 ; and solve for r3, s3 and t3 in terms of r1, s1, t1, r2, s2, t2
print(soln)
# http://docs.sympy.org/dev/tutorial/solvers.html
You are using a version of SymPy which does not have nonlinsolve. One way to fix this is to update SymPy (versions starting with 1.1 have it). The other is to replace nonlinsolve with solve.
Unfortunately, neither will produce a solution of your system. This is because in general, a system of several algebraic equations has no explicit solution, unless you are really lucky. So neither nonlinsolve nor solve get anywhere with it, despite trying for a long time.