Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Radau II A Solver #3

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open
Changes from 22 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1029f09
Add radau solver
YingboMa Jul 5, 2016
adb4857
Small changes
YingboMa Jul 5, 2016
08fdd57
optional order
obiajulu Jul 5, 2016
9627da7
updated done()
obiajulu Jul 5, 2016
8db6176
change unwrap to unpack
obiajulu Jul 5, 2016
ace77bf
added setting up state and trialstep function
obiajulu Jul 5, 2016
68567c7
added types to radau state
obiajulu Jul 5, 2016
05b0e33
outline comments for trialstep
obiajulu Jul 5, 2016
60b5df6
add basic errorcontrol! function
YingboMa Jul 5, 2016
23a3d09
fix conflict
obiajulu Jul 6, 2016
4ca32e3
Fix the conflicts
YingboMa Jul 6, 2016
7ab6965
return structure for errorcontrol
obiajulu Jul 6, 2016
5882320
added framework for tableau
obiajulu Jul 6, 2016
8ac9f13
Add ordercontrol
YingboMa Jul 6, 2016
a8e155e
more modifications to tableau
obiajulu Jul 6, 2016
3283b8e
more organization in structure
obiajulu Jul 6, 2016
fc04524
Add using Polynomials
YingboMa Jul 6, 2016
a76a14f
Add b in raduaTable
YingboMa Jul 6, 2016
361831e
removed conflict
obiajulu Jul 6, 2016
41f4f5f
Add prototype of constRadauTableau function
YingboMa Jul 6, 2016
333d62a
Fix bugs and optimize constRadauTableau function
YingboMa Jul 7, 2016
db9a8f3
further progress in trialstep
obiajulu Jul 7, 2016
4b5f62d
Add some documents
YingboMa Jul 8, 2016
9fdeed5
Improve constRadauTableau() function and add bt_radau5 table
YingboMa Jul 8, 2016
a846d88
Netwon iteration framework working
obiajulu Jul 8, 2016
0a39b32
radau state working, tableau as well. Also done() and constRadauTable…
obiajulu Jul 8, 2016
b8a898c
a working, though incorrect, Netwon iteration
obiajulu Jul 8, 2016
8b503c8
Add .gitignore and avoid deprecated warnings
YingboMa Jul 25, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
351 changes: 351 additions & 0 deletions src/radau.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,351 @@
#=
(1) done()
(2) trialstep!()
(3) errorcontol!()
(4) odercontrol!()
(5) rollback!()
(6) status()
=#

###########################################
# Tableaus for implicit Runge-Kutta methods
###########################################
using Polynomials
using ForwardDiff

immutable TableauRKImplicit{Name, S, T} <: Tableau{Name, S, T}
order::Integer # the order of the method
a::Matrix{T}
# one or several row vectors. First row is used for the step,
# second for error calc.
b::Matrix{T}
c::Vector{T}
function TableauRKImplicit(order,a,b,c)
@assert isa(S,Integer)
@assert isa(Name,Symbol)
@assert c[1]==0
@assert istril(a)
@assert S==length(c)==size(a,1)==size(a,2)==size(b,2)
@assert size(b,1)==length(order)
@assert norm(sum(a,2)-c'',Inf)<1e-10 # consistency.
new(order,a,b,c)
end
end

function TableauRKImplicit{T}(name::Symbol, order::Integer,
a::Matrix{T}, b::Matrix{T}, c::Vector{T})
TableauRKImplicit{name,length(c),T}(order, a, b, c)
end
function TableauRKImplicit(name::Symbol, order::Integer, T::Type,
a::Matrix, b::Matrix, c::Vector)
TableauRKImplicit{name,length(c),T}(order, convert(Matrix{T},a),
convert(Matrix{T},b), convert(Vector{T},c) )
end

## Tableaus for implicit RK methods
const bt_radau3 = TableauRKImplicit(:radau3,3, Rational{Int64},
[5//12 -1//12
3//4 1//4],
[3//4, 1//4]',
[1//3, 1])

const bt_radau5 = TableauRKImplicit(:radau5,5, Rational{Int64},
[11/45 - 4*sqrt(6)/360 37/225 - 169*sqrt(6)/1800 -2/225 + sqrt(6)/75
11/45 - 4*sqrt(6)/360 37/225 - 169*sqrt(6)/1800 -2/225 + sqrt(6)/75
11/45 - 4*sqrt(6)/360 37/225 - 169*sqrt(6)/1800 -2/225 + sqrt(6)/75]',
[2//5- sqrt(6)/10, 1])

const bt_radau9 = TableauRKImplicit(:radau9,9, Rational{Int64},
[0 0
1 0],
[1//2, 1//2]',
[0, 1])


###########################################
# State for Radau Solver
###########################################
type RadauState{T,Y}
h::T # (proposed) next time step

t::T # current time
y::Y # current solution
dy::Y # current derivative

tpre::T # time t-1
ypre::Y # solution at t-1
dypre::Y # derivative at t-1

step::Int # current step number
finished::Bool # true if last step was taken

btab::TableauRKImplicit # tableau according to stage number

# work arrays
end

###########################################
# Radau Solver
###########################################
function ode_radau(f, y0, tspan, stageNum ::Integer = 5)
# Set up
T = eltype(tspan)
Y = typeof(y0)
EY = eltype(Y)
N = length(tsteps)
dof = length(y0)
h = hinit
t = ode.tspan[1]
y = deepcopy(y0)
dy = f(t, y)
# get right tableau for stage number
if stageNum ==3
btab = bt_radau3
elseif stageNum ==5
btab = bt_radau5
elseif stageNum == 9
btab = bt_radau9
else
btab = constRadauTableau(stageNum)
end

## previous data set to null to begin
tpre = NaN
ypre = zeros(y0)
dypre = zeros(y0)
step = 1
stageNum = stageNum
finished = false


## intialize state
st = RadauState{T,Y}(h,
t, y, dy,
tpre, ypre, dypre,
step, finished,
btab)

# Time stepping loop
while !done()
stats = trialstep!(st)
err, stats, st = errorcontrol!(st) # (1) adaptive stepsize (2) error
if err < 1
stats, st = ordercontrol!()
accept = true
else
rollback!()
end

return = status()
end
end

###########################################
# iterator like helper functions
###########################################

function done(st)
@unpack st: h, t, tfinal
if h < minstep || t = tfinal
return true
else
return false
end
end

"trial step for ODE with mass matrix"
function trialstep!(st)
@unpack st: h, t,y, tfinal


# Calculate simplified Jacobian if My' = f(t,y)
# _ _
# |M - h*a[11]*h*f(tn,yn) ... -h*a[1s]*f(tn,yn) |
# G= | ⋮ ⋱ ⋮ |
# | - h*a[1s]*h*f(tn,yn) ... M-h*a[ss]*f(tn,yn) |
# |_ _|
#
g(z) = f(t,z)
J = ForwardDiff.jacobian(g, y)
I = eye(stageNum,stageNum)

#AoplusJ = [btab.a[i,j]*J for i=1:stageNum, j=1:stageNum]
AoplusJ=zeros(stageNum*dof,stageNum*dof)
for i=1:stageNum
for j = 1:stageNum
for l = 1:dof
for k = 1:dof
AoplusJ[(i-1)*stageNum+l,(j-1)*stageNum+k] =btab.a[i,j]*J[l,k]
end
end
end
end

AoplusI = [btab.a[i,j]*I for i=1:stageNum, j=1:stageNum]
AoplusI2=zeros(stageNum*dof,stageNum*dof)
for i=1:stageNum
for j = 1:stageNum
for l = 1:dof
for k = 1:dof
AoplusI2[(i-1)*stageNum+l,(j-1)*stageNum+k] =btab.a[i,j]*I[l,k]
end
end
end
end

#IoplusM = [I[i,j]*M for i=1:stageNum, j=1:stageNum]
IoplusM=zeros(stageNum*dof,stageNum*dof)
for i=1:stageNum
for j = 1:stageNum
for l = 1:dof
for k = 1:dof
IoplusM[(i-1)*stageNum+l,(j-1)*stageNum+k] =I[i,j]*M[l,k]
end
end
end
end

G = IoplusM-h*AoplusJ
Ginv = inv(G)

# Use Netwon interation
#
# ⃗z^(k+1) = ⃗z ^ (k) - Δ⃗z^(k)
#TODO: use the transformation T^(-1)A^(-1)T = Λ, W^k = (T^-1 ⊕ I)Z^k
Copy link
Collaborator

@YingboMa YingboMa Jul 8, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a function in Julia Base called "kron" which is Kronecker tensor product. Maybe this function is helpful to you.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes indeed, this is very very helpful!!! Saves me from having to implement tensor product myself. Thanks.

## initial variables iteration
#TODO: use better initial values for zpre
#w = hnew/hpre
#zpre = q(w)+ypre-y
zpre = zeros(dof)
Δzpre
κ

iterate = true
count = 0
while iterate
Δz = reshape(Ginv*[(-zpre + h*AoplusI2*F(f,z,y,t,c,h))...],dof,stageNum)
z = zpre + Δz

# Stop condition for the Netwon iteration
if (count >=1)
Θ = norm(Δz)/norm(Δzpre)
η = Θ/(1-Θ)
if η*norm(Δz) <= κ*min(reltol,abstol)
iterate = false
break
end
end

zpre = z
Δzpre = Δz

count+=1
end

# Once Netwon method converges after some m steps, estimated next step size
#
# y = ypre + h ∑b_i*k_i^{m}
#

d = b*inv(A)
ynext = ypre
for i = 1 : stageNum
ynext += z[i]*d[i]
end
end

function errorcontrol!(st)
@unpack st:M, h, A, J, tpre, ypre, b̂, b, c, g, order_number, fac
γ0 = filter(λ -> imag(λ)==0, eig(inv(A)))

for i = 1:order_number
sum_part += (b̂[i] - b[i]) * h *f(xpre + c[i] * h, g[i])
end

yhat_y = γ0 * h * f(tpre, ypre) + sum_part
err = norm( inv(M - h * λ * J) * (yhat_y) )

hnew = fac * h * err_norm^(-1/4)

# Update state
st.hnew = hnew

return err, Nothing, st
end

function ordercontrol!(st)
@unpack st:W, step, order

if step < 10
# update state
st.order = 5

else
θk = norm(W[ ]) / norm(W[ ])
θk_1 = norm(W[ ]) / norm(W[ ])

Φ_k = √(θk * θk_1)
end

end
###########################################
# Other help functions
###########################################
function constRadauTableau(stageNum)
# Calculate c_i, which are the zeros of
# s-1
# d s-1 s
# --- (x * (x-1) )
# s-1
# dx
roots = Array(Float64, stageNum - 1)
append!(roots, [1 for i= 1:stageNum])
poly = Polynomials.poly([roots;])
for i = 1 : stageNum-1
poly = Polynomials.polyder(poly)
end
C = Polynomials.roots(poly)
Copy link
Collaborator

@YingboMa YingboMa Jul 8, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Polynomials package has been 3 years didn't update, and Polynomials package has serious performance and the returning type issues. Maybe need to rewrite this part.


################# Calculate b_i #################

# Construct a matrix C_meta to calculate B
C_meta = Array(Float64, stageNum, stageNum)
for i = 1:stageNum
C_meta[i, :] = C .^ (i - 1)
end

# Construct a matrix 1 / stageNum
B_meta = Array(Float64, stageNum, 1)
for i = 1:stageNum
B_meta[i, 1] = 1 / i
end

# Calculate b_i
C_big = inv( C_meta )
B = C_big * B_meta

################# Calculate a_ij ################

# Construct matrix A
A = Array(Float64, stageNum, stageNum)

# Construct matrix A_meta
A_meta = Array(Float64, stageNum, stageNum)
for i = 1:stageNum
for j = 1:stageNum
A_meta[i,j] = B_meta[i] * C[j]^i
end
end

# Calculate a_ij
for i = 1:stageNum
A[i,:] = C_big * A_meta[:,i]
end

return TableauRKImplicit(order, A, B, C)
end

" Calculates the array of derivative values between t and tnext"
function F(f,z,y,t,c,h)
return [f(t+c[i]*h, y+z[i]) for i=1:length(z)]
end