-
-
Notifications
You must be signed in to change notification settings - Fork 214
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
Newmark beta method #2187
base: master
Are you sure you want to change the base?
Newmark beta method #2187
Changes from 3 commits
6dbdcd1
8e1a1e3
b3634dc
d7d479e
1380a6c
7b41813
2e65db7
9bb2401
f67ae0c
c2c7db3
68498e9
302903d
b07101b
ff5c291
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
@cache struct NewmarkBetaCache{uType, rateType, parameterType, N} <: OrdinaryDiffEqMutableCache | ||
u::uType # Current solution | ||
uprev::uType # Previous solution | ||
upred::uType # Predictor solution | ||
fsalfirst::rateType | ||
β::parameterType # newmark parameter 1 | ||
γ::parameterType # newmark parameter 2 | ||
nlsolver::N # Inner solver | ||
tmp::uType # temporary, because it is required. | ||
end | ||
|
||
function alg_cache(alg::NewmarkBeta, u, rate_prototype, ::Type{uEltypeNoUnits}, | ||
::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, | ||
dt, reltol, p, calck, | ||
::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} | ||
|
||
β = alg.β | ||
γ = alg.γ | ||
upred = zero(u) | ||
fsalfirst = zero(rate_prototype) | ||
|
||
@assert 0.0 ≤ β ≤ 0.5 | ||
@assert 0.0 ≤ γ ≤ 1.0 | ||
|
||
c = 1.0 | ||
γ̂ = ArrayPartitionNLSolveHelper(1.0,1.0) | ||
nlsolver = build_nlsolver(alg, u.x[1], uprev.x[1], p, t, dt, f.f1, rate_prototype.x[1], uEltypeNoUnits, | ||
uBottomEltypeNoUnits, tTypeNoUnits, γ̂, c, Val(true)) | ||
|
||
tmp = zero(u) | ||
NewmarkBetaCache(u, uprev, upred, fsalfirst, β, γ, nlsolver, tmp) | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
function initialize!(integrator, cache::NewmarkBetaCache) | ||
duprev, uprev = integrator.uprev.x | ||
integrator.f(cache.fsalfirst, integrator.uprev, integrator.p, integrator.t) | ||
integrator.fsalfirst = cache.fsalfirst | ||
integrator.fsallast = du_alias_or_new(cache.nlsolver, integrator.fsalfirst) | ||
integrator.stats.nf += 1 | ||
return | ||
end | ||
|
||
@muladd function perform_step!(integrator, cache::NewmarkBetaCache, repeat_step = false) | ||
@unpack t, dt, f, p = integrator | ||
@unpack upred, β, γ, nlsolver = cache | ||
|
||
# Given Mu'' = f(u,u',t) we need to solve the non-linear problem | ||
# Mu(tₙ₊₁)'' - f(ũ(tₙ₊₁) + u(tₙ₊₁)'' β Δtₙ²,ũ(tₙ₊₁)' + u(tₙ₊₁)'' γ Δtₙ,t) = 0 | ||
# for u(tₙ₊₁)''. | ||
# The predictors ũ(tₙ₊₁) are computed as | ||
# ũ(tₙ₊₁) = u(tₙ) + u(tₙ)' Δtₙ + u(tₙ)'' (0.5 - β) Δtₙ² | ||
# ũ(tₙ₊₁)' = u(tₙ)' + u(tₙ)'' (1.0 - γ) Δtₙ | ||
# such that we can compute the solution with the correctors | ||
# u(tₙ₊₁) = ũ(tₙ₊₁) + u(tₙ₊₁)'' β Δtₙ² | ||
# u(tₙ₊₁)' = ũ(tₙ₊₁)' + u(tₙ₊₁)'' γ Δtₙ | ||
|
||
mass_matrix = f.mass_matrix | ||
|
||
# Evaluate predictor | ||
dduprev = integrator.fsalfirst.x[1] | ||
duprev, uprev = integrator.uprev.x | ||
oscardssmith marked this conversation as resolved.
Show resolved
Hide resolved
|
||
upred_full = ArrayPartition( | ||
duprev + dt*(1.0 - γ)*dduprev, | ||
uprev + dt*dt*(0.5 - β)*dduprev + dt*duprev | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this seems like it will allocate a bunch, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed. As also pointed out below by you during review we might be able to use |
||
|
||
# _tmp = mass_matrix * @.. broadcast=false (α₁ * uprev+α₂ * uprev2) | ||
# nlsolver.tmp = @.. broadcast=false _tmp/(dt * β₀) | ||
|
||
# nlsolve!(...) solves for | ||
# dt⋅f(innertmp + γ̂⋅z, p, t + c⋅dt) + outertmp = z | ||
# So we rewrite the problem | ||
# u(tₙ₊₁)'' - f(ũ(tₙ₊₁) + u(tₙ₊₁)'' β Δtₙ², ũ(tₙ₊₁)' + u(tₙ₊₁)'' γ Δtₙ,t) = 0 | ||
# z = Δtₙ u(tₙ₊₁)'': | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we generally put the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh. that's awful. |
||
# z - Δtₙ f(ũ(tₙ₊₁) + z β Δtₙ, ũ(tₙ₊₁)' + z γ,t) = 0 | ||
# Δtₙ f(ũ(tₙ₊₁) + z β Δtₙ, ũ(tₙ₊₁)' + z γ,t) = z | ||
# γ̂ = [γ, β Δtₙ]: | ||
# Δtₙ f(ũ(tₙ₊₁) + z γ̂₂ , ũ(tₙ₊₁)' + z γ̂₁ ,t) = z | ||
# innertmp = [ũ(tₙ₊₁)', ũ(tₙ₊₁)]: | ||
# Δtₙ f(innertmp₂ + z β Δtₙ², innertmp₁ + z γ Δtₙ,t) = z | ||
# Note: innertmp = nlsolve.tmp | ||
nlsolver.γ = ArrayPartitionNLSolveHelper(γ, β * dt) # = γ̂ | ||
nlsolver.tmp .= upred_full # TODO check f tmp is potentially modified and if not elimiate the allocation of upred_full | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe |
||
|
||
# Use the linear extrapolation Δtₙ u(tₙ)'' as initial guess for the nonlinear solve | ||
nlsolver.z .= dt*dduprev | ||
ddu = nlsolve!(nlsolver, integrator, cache, repeat_step) / dt | ||
nlsolvefail(nlsolver) && return | ||
|
||
# Apply corrector | ||
u .= ArrayPartition( | ||
upred_full.x[1] + ddu*β*dt*dt, | ||
upred_full.x[2] + ddu*γ*dt | ||
) | ||
|
||
# | ||
if integrator.opts.adaptive | ||
if integrator.success_iter == 0 | ||
integrator.EEst = one(integrator.EEst) | ||
else | ||
# Zienkiewicz and Xie (1991) Eq. 21 | ||
δddu = (ddu - dduprev) | ||
integrator.EEst = dt*dt/2 * (2*β - 1/3) * integrator.opts.internalnorm(δddu, t) | ||
end | ||
end | ||
|
||
f(integrator.fsallast, u, p, t + dt) | ||
integrator.stats.nf += 1 | ||
|
||
return | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the coefficients are part of the algorithm, can you calculate the order here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
similar to FBDF, you can just set this to 1 I think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for taking a look Hendrik! Yes, I could compute them here. I will fix such stuff after I get a pendulum example working. I just opened the PR to discuss the progress and possibly better design choices for the new class of solvers.