Nonlinear Solver Lab
On the criterion to stop the W4 iteration (I)
- Using the Lane-Emden equation solved by the W4LH method, we compare the criteria to stop the W4 iteration.
Comparison among different criteria to stop W4 iteration¶
- A criterion to stop the iteration is necessary.
- From the point of view of implementation, possible criteria will be compared.
Package Inclusion¶
- Sympy :: To define the set of nonlinear equations
- Numpy :: For iterative solver
- Scipy :: To use Linear solver
- Matplotlib :: For figure
In [1]:
import sympy as sy;
import numpy as np;
from numpy import cos,sin,pi;
from scipy import linalg;
import matplotlib.pyplot as plt;
Parameter Setup¶
For the W4 method, we define
- dim : dimension of system (It determines the resolution)
- dtau : $\Delta\tau$ for evolution
- errmax : Criterion of error to stop iteration
- itermax : Maximum iteration.
In [2]:
dim=10;
In [3]:
dtau=0.8;
errmax = pow(10,-8);
itermax = pow(10,3);
In [4]:
### Variables
### x[1], x[2], x[3], ... , x[dim]
###
x = []
for i in range(0,dim):
vname = 'x[' + str(i) +']';
x.append(sy.symbols(vname));
Definition of Source in the Sympy style¶
- F(x) : System of nonlinear equations
- |F(x)| : Absolute components
- J : Jacobian matrix $\partial$ F / $\partial$ x
$\frac{d^2\theta}{d\xi^2}+\frac{2}{\xi}\frac{d\theta}{d\xi}+r_{*}^2\theta^{n}=0$¶
In [5]:
### Source
### f[0], f[1], f[2], ... , f[dim-1]
n = 1;
f = [];
### Coordinate xi
dx = 1.0/dim;
xi = [];
for i in range(dim+1):
xi.append( dx*i );
### Source for Eigenvalue x[0]
f.append( 6*(x[1] -1)/dx**2 +x[0] );
### Source for x[1] (theta(dx)) with boundary condition theta(0)=1
f.append( (x[2] -2*x[1] +1)/dx**2 +(x[2]-1)/xi[1]/dx +x[1]**n*x[0] );
for i in range(2,dim-1):
f.append( (x[i+1] -2*x[i] +x[i-1])/dx**2 +(x[i+1]-x[i-1])/xi[i]/dx +x[i]**n*x[0] );
### Source for x[dim-1] (theta(1-dx)) with boundary condition theta(1)=0
f.append( (0 -2*x[dim-1] +x[dim-2])/dx**2 +(0-x[dim-2])/xi[dim-1]/dx +x[dim-1]**n*x[0] );
#f
tmp = f[0];
#norm = 0.0;
for i in range(1,dim):
tmp = tmp +f[i]*x[i];
# norm = norm +x[i]**n*x[i];
f[0] = tmp;
In [6]:
# input source
def calc_source(x,f):
### Summation of absolute values of all terms in each equation
### to compare the error with the typical value of each equation
fa1 = [];
for j in range(dim):
tmp = 0;
for i in range(len(f[j].args)):
tmp = tmp + abs(f[j].args[i]);
fa1.append(tmp);
### Definition of variables, sources, absolute sources(x, F, |F|) as vector
v = sy.Matrix([x]).transpose();
F = sy.Matrix([f]).transpose();
fa3 = [];
for j in range(dim):
tmp = abs(v[j]);
fa3.append(tmp);
### Analytic calculation of Jacobian(dim x dim Matrix)
J = sy.Matrix();
for i in range(dim):
J = J.col_insert(i,F.diff(x[i]));
fa2 = [];
for j in range(dim):
tmp = 0;
for i in range(dim):
tmp = tmp + abs(J[j,i]*v[i]);
fa2.append(tmp);
Fa1 = sy.Matrix([fa1]).transpose();
Fa2 = sy.Matrix([fa2]).transpose();
Fa3 = sy.Matrix([fa3]).transpose();
### From Sympy to Numpy
arg = v.transpose();
vn = sy.lambdify(arg, v, "numpy")
Fn = sy.lambdify(arg, F, "numpy")
Fa1n = sy.lambdify(arg, Fa1, "numpy")
Fa2n = sy.lambdify(arg, Fa2, "numpy")
Fa3n = sy.lambdify(arg, Fa3, "numpy")
Jacn = sy.lambdify(arg, J, "numpy")
return vn,Fn,Fa1n,Jacn,Fa2n,Fa3n;
In [7]:
vn, Fn, Fa1n, Jacn, Fa2n, Fa3n = calc_source(x,f);
Definition :: W4LH method¶
In [8]:
### Analysis by the W4 method with the LH decomposition
def w4analysis2(v,F,Fa1,Fa2,Fa3,J,ini,dt,itermax,errmax):
### Initialization for x and p as v0 and p0
p0 = np.zeros(dim);
v0 = v(*ini).transpose()[0];
evot = [];
# evot = np.append(evot,0);
evox = np.array([v0]).reshape(1,dim);
evop = np.array([p0]).reshape(1,dim);
evolam = [];
J0=J(*v0);
lam = linalg.eigvals(J0)
lmin=abs(lam[0]);
lmax=abs(lam[0]);
for d in range(dim):
if lmin > abs(lam[d]):
lmin = abs(lam[d]);
if lmax < abs(lam[d]):
lmax = abs(lam[d]);
evolam = np.append(evolam,lmax/lmin);
F0=F(*v0).transpose()[0].transpose();
evof = np.array([F0]).reshape(1,dim);
F0a1=Fa1(*v0).transpose()[0].transpose();
F0a2=Fa2(*v0).transpose()[0].transpose();
F0a3=Fa3(*v0).transpose()[0].transpose();
evoa1 = np.array([F0a1]).reshape(1,dim);
evoa2 = np.array([F0a2]).reshape(1,dim);
evoa3 = np.array([F0a3]).reshape(1,dim);
### Main Iteration Loop
for i in range(itermax):
J0=J(*v0);
F0=F(*v0).transpose()[0].transpose();
F0a1=Fa1(*v0).transpose()[0].transpose();
F0a2=Fa2(*v0).transpose()[0].transpose();
F0a3=Fa3(*v0).transpose()[0].transpose();
### Criterion to stop the iteration
### Evaluation of Source F
err = 0.0;
for k in range(dim):
err = max(err,abs(F0[k]/F0a1[k]));
if err < errmax:
# evoa1 = np.append(evoa1,np.array([F0a1]),axis=0);
# evoa2 = np.append(evoa2,np.array([F0a2]),axis=0);
# evoa3 = np.append(evoa3,np.array([F0a3]),axis=0);
break;
### Decomposition of Jacobian into L and H
Q, R = linalg.qr(J0.transpose());
srcp = -2*p0 -linalg.solve(R.transpose(),F0);
srcx = Q.dot(p0);
v0 = v0 +srcx*dt;
p0 = p0 +srcp*dt;
evot = np.append(evot,i);
evox = np.append(evox,np.array([v0]),axis=0);
evop = np.append(evop,np.array([p0]),axis=0);
evof = np.append(evof,np.array([F0]),axis=0);
evoa1 = np.append(evoa1,np.array([F0a1]),axis=0);
evoa2 = np.append(evoa2,np.array([F0a2]),axis=0);
evoa3 = np.append(evoa3,np.array([F0a3]),axis=0);
lam = linalg.eigvals(J0)
lmin=abs(lam[0]);
lmax=abs(lam[0]);
for d in range(dim):
if lmin > abs(lam[d]):
lmin = abs(lam[d]);
if lmax < abs(lam[d]):
lmax = abs(lam[d]);
evolam = np.append(evolam,lmax/lmin);
return v0, i, err, evolam, evot, evox, evop, evoa1, evoa2, evoa3, evof
In [9]:
### Initial guess
vini = np.array([]);
vini = np.append(vini, 1.);
for i in range(1,dim):
vini = np.append(vini, (1.0 -dx*i));
### Nonlinear Solver by the W4 method
vans, iter, err, lam, t, xr, pr, a1, a2, a3, a0 = w4analysis2(vn,Fn,Fa1n,Fa2n,Fa3n,Jacn,vini,dtau,itermax,errmax);
### Basic information
print("Dimension : ",dim);
print("Initial Condition number : ",lam[1]);
print("Iteration : ",iter,", error : ", err);
if iter < itermax-1:
print("< Solved. >");
else:
print("< Failed. >");
In [10]:
### Solution
sol = [];
sol = np.append(sol,1.0);
for i in range(1,dim):
sol = np.append(sol,xr[iter][i]);
sol = np.append(sol,0.0);
r = [];
for i in range(dim+1):
r = np.append(r,xi[i]*xr[iter][0]**0.5);
### Initial guess
sola = [];
sola = np.append(sola,1.0);
for i in range(1,dim):
sola = np.append(sola,vini[i]);
sola = np.append(sola,0.0);
ra = [];
for i in range(dim+1):
ra = np.append(ra,xi[i]*vini[0]**0.5);
In [11]:
### Figures
fig = plt.figure(figsize=(12,5));
ax1 = fig.add_subplot(1,1,1);
ax1.plot(ra,sola,marker='x',label='Initial guess');
ax1.plot(r,sol,marker='o',label='Solution');
ax1.set_xlabel("$r$");
ax1.set_ylabel("Solution $\Theta$");
ax1.legend();
fig.tight_layout();
In [12]:
f1a0 = [];
for i in range(0,iter):
f1a0 = np.append(f1a0,a0[i][1]);
f1a1 = [];
for i in range(0,iter):
f1a1 = np.append(f1a1,a1[i][1]);
f1a2 = [];
for i in range(0,iter):
f1a2 = np.append(f1a2,a2[i][1]);
f1a3 = [];
for i in range(0,iter):
f1a3 = np.append(f1a3,a3[i][1]);
In [13]:
f2a0 = [];
for i in range(0,iter):
f2a0 = np.append(f2a0,a0[i][dim//2]);
f2a1 = [];
for i in range(0,iter):
f2a1 = np.append(f2a1,a1[i][dim//2]);
f2a2 = [];
for i in range(0,iter):
f2a2 = np.append(f2a2,a2[i][dim//2]);
f2a3 = [];
for i in range(0,iter):
f2a3 = np.append(f2a3,a3[i][dim//2]);
In [14]:
f3a0 = [];
for i in range(0,iter):
f3a0 = np.append(f3a0,a0[i][dim-1]);
f3a1 = [];
for i in range(0,iter):
f3a1 = np.append(f3a1,a1[i][dim-1]);
f3a2 = [];
for i in range(0,iter):
f3a2 = np.append(f3a2,a2[i][dim-1]);
f3a3 = [];
for i in range(0,iter):
f3a3 = np.append(f3a3,a3[i][dim-1]);
In [15]:
### Figures
fig = plt.figure(figsize=(12,3));
ax1 = fig.add_subplot(1,3,1);
ax1.plot(t,(abs(f1a0)/f1a1),marker='o',label='Definition 1');
ax1.plot(t,(abs(f1a0)/f1a2),marker='x',label='Definition 2');
ax1.plot(t,(abs(f1a0)/f1a3),marker='d',label='Definition 3');
ax1.set_xlabel("$Iteration$");
ax1.set_ylabel("$|F_1|/|F_1|_{crit}$");
ax1.set_yscale('log');
ax1.set_title('Error evolution at $\Theta_{1}$')
ax1.legend();
ax2 = fig.add_subplot(1,3,2);
ax2.plot(t,(abs(f2a0)/f2a1),marker='o',label='Definition 1');
ax2.plot(t,(abs(f2a0)/f2a2),marker='x',label='Definition 2');
ax2.plot(t,(abs(f2a0)/f2a3),marker='d',label='Definition 3');
ax2.set_xlabel("$Iteration$");
ax2.set_ylabel("$|F_{N/2}|/|F_{N/2}|_{crit}$");
ax2.set_yscale('log');
ax2.set_title('Error evolution at $\Theta_{N/2}$')
ax2.legend();
ax3 = fig.add_subplot(1,3,3);
ax3.plot(t,(abs(f3a0)/f3a1),marker='o',label='Definition 1');
ax3.plot(t,(abs(f3a0)/f3a2),marker='x',label='Definition 2');
ax3.plot(t,(abs(f3a0)/f3a3),marker='d',label='Definition 3');
ax3.set_xlabel("$Iteration$");
ax3.set_ylabel("$|F_{N}|/|F_{N}|_{crit}$");
ax3.set_yscale('log');
ax3.set_title('Error evolution at $\Theta_{N}$')
ax3.legend();
fig.tight_layout();
Comments on the criteria of W4 iteration for LE equation¶
How to see the figures¶
- Each figure shows the evolution of error defined as $|F_i|/|F_i|_{crit}$, which is the absolute value of the discretized equation divided by a typical value of equation.
- $i$ denotes the number of grid points.
- $|F_i|_{crit}$ is defined in the three ways:
- the sum of absolute values of all terms,
- the sum of Jacobian times variable, $J_{ij}x_{j}$
- the absolute value of $x_{i}$
- From this example, the definition $2$ seems working well, but it is noted that the definition $3$ is not so bad.
In [ ]: