Finite Element Analysis with Gridap.jl; how to define external forces? - julia

I'm following this tutorial in order to try and do an FEA of a model.msh that I have to see how it would deform given different external forces in different places.
There they define the weak form as
a(u,v) = ∫( ε(v) ⊙ (σ∘ε(u)) )*dΩ
l(v) = 0
and they state "The linear form is simply l(v) = 0 since there are not external forces in this example."
As mentioned, I would like to analyse the different deformation that different external forces would cause on my model, but I can't seem to find anywhere an example of this. Could someone help me on defining this linear form for external forces different than 0?
Thanks.

Maybe this helps you out. It was written in a hurry, so please do not mind if you encounter spelling mistakes or other beauty issues :)
# define where the output shall go
output_Path ="Output/3_Gridap/1_Lin_FEA/FE_8"
mkpath(output_Path)
output_Name ="pde_6"
using Gridap
# please load the model that is shown in: https://gridap.github.io/Tutorials/dev/pages/t001_poisson/
model = DiscreteModelFromFile("Code/Meshes/Data/possion.json")
# just in case you want to see the model using paraview
writevtk(model,"$(output_Path)/md")
order = 1
reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order)
V0 = TestFESpace(model,reffe;
conformity=:H1,
# to see which elements belongs to "bottom" open the model which is saved through "writevtk(model,"$(output_Path)/md")"
dirichlet_tags=["bottom"],
# activate/deactivate the boundary conditions
dirichlet_masks=[
(true, true, true), # clamp the bottom
])
# define displacement
clamping(x) = VectorValue(0.0,0.0,0.0)
U = TrialFESpace(V0,[clamping])
const E = 7e+7
const ν = 0.33
const λ = (E*ν)/((1+ν)*(1-2*ν))
const μ = E/(2*(1+ν))
σ(ε) = λ*tr(ε)*one(ε) + 2*μ*ε
degree = 2*order
Ω = Triangulation(model)
dΩ = Measure(Ω,degree)
# Neumann boundary conditions
# here we define the surface on which we want an external force
Γ_Tr = BoundaryTriangulation(model,tags=["triangle"])
dΓ_Tr = Measure(Γ_Tr,degree)
# a force shall be applied on the y-direction
f_Tr(x) = VectorValue(0.0, 1e+6, 0.0)
# mass forces due to gravity, the value is set quite high, such that an impact can be seen
mass_Forces(x) = VectorValue(0.0, -1e+7, 0.0)
# Weak form
a(u,v) = ∫( ε(v) ⊙ (σ∘ε(u)) )*dΩ
l(v) = ∫( v ⋅ mass_Forces )* dΩ + ∫( v ⋅ f_Tr )* dΓ_Tr
op = AffineFEOperator(a,l,U,V0)
uh = solve(op)
writevtk(Ω,"$(output_Path)/$(output_Name)",
cellfields=[
"uh" => uh,
"epsi" => ε(uh),
"sigma" => σ∘ε(uh)])

Related

How can I make a inf-Matrix in Julia?

I want to set up the lowest boundary of my Problem as a -inf also without a limit and here comes the codes
#time begin
using COSMO, SparseArrays, LinearAlgebra
using NPZ
Matrix10 = npzread("C:/Users/skqkr/Desktop/Semesterarbeit/Chiwan_Q1.npz")
q = Matrix10["p"];
P = sparse(Matrix10["Q"]);
A = sparse(Matrix10["G"]);
h = Matrix10["h"];
l = Matrix10["l"];
# First, we decide to solve the problem with two one-sided constraints using `COSMO.Nonnegatives` as the convex set:
Aa = [-A; A]
ba = [h; -l]
constraint1 = COSMO.Constraint(Aa, ba, COSMO.Nonnegatives);
# Next, we define the settings object, the model and then assemble everything:
settings = COSMO.Settings(verbose=true);
model = COSMO.Model();
assemble!(model, P, q, constraint1, settings = settings);
res = COSMO.optimize!(model);
# Alternatively, we can also use two-sided constraints with `COSMO.Box`:
constraint1 = COSMO.Constraint(A, zeros(3), COSMO.Box(-l, h));
model = COSMO.Model();
assemble!(model, P, q, constraint1, settings = settings);
res_box = COSMO.optimize!(model);
end
so I want
l = Matrix10["l"];
here ll as a Matrix without a limit so, the constraints of the qp would be this form.
A*X<h
How should I do in order to make the limits minus infinits.
thank you!!

Improve plots quality in log scale in Julia

I have a function solving two ODEs and joining the solution which gives a really nice plot in linear scales, but which has a high drop in quality in log scale depending on the parameters I use. In the code below, I plot the solution for two sets of parameters, in which you can see the first set is not smooth, while the second one is kind of okay. If I try to obtain a smoother visualisation using the saveat option in the second ODEs, solclass = solve(probclass,Tsit5(),saveat=0.001), I get an error when plotting the second set: ArgumentError: range step cannot be zero. Is there a way to obtain smooth linear-log other than manually changing the saveat option? Also, I have tried using a few other backends, but they gave an error at ploting the solution.
using DifferentialEquations, Plots, RecursiveArrayTools
function alpha_of_phi!(s2,d,a0,ϕ₀)
# α in the quantum phase
function quantum!(dv,v,p,ϕ)
s2,d=p
α = v[1]
dv[1] = (ϕ*s2*sin(2*d*α)+2*d*sinh(s2*α*ϕ))/(-α*s2*sin(2*d*α)+2*d*cos(2*d*α)+2*d*cosh(s2*α*ϕ))
end
# When dα/dϕ = 1, we reach the classical regime, and stop the integration
condition(v,ϕ,integrator) = (ϕ*s2*sin(2*d*v[1])+2*d*sinh(s2*v[1]*ϕ))/(-v[1]*s2*sin(2*d*v[1])+2*d*cos(2*d*v[1])+2*d*cosh(s2*v[1]*ϕ))==1.0
affect!(integrator) = terminate!(integrator)
cb = DiscreteCallback(condition,affect!)
# Initial Condition at the bounce
α₀ = [a0]
classspan = (0,ϕ₀)
probquant = ODEProblem(quantum!,α₀,classspan,(s2,d))
solquant = solve(probquant,Tsit5(),callback=cb)
# α in the classical phase
function classic!(du,u,p,ϕ)
αc = u[1]
dαc = u[2]
du[1] = dαc
du[2] = 3*(-dαc^3/sqrt(2)+dαc^2+dαc/sqrt(2)-1)
end
# IC retrieved from end of quantum phase
init = [last(solquant);1.0]
classspan = (last(solquant.t),ϕ₀)
probclass = ODEProblem(classic!,init,classspan)
solclass = solve(probclass,Tsit5())
# α(ϕ) for ϕ>0
solu = append!(solquant[1,:],solclass[1,:]) # α
solt = append!(solquant.t,solclass.t) # ϕ
# α(ϕ) for ϕ<0
soloppu = reverse(solu)
soloppt = -reverse(solt)
pop!(soloppu)
pop!(soloppt)
# Join the two solutions
soltotu = append!(soloppu,solu)
soltott = append!(soloppt,solt)
soltot = DiffEqArray(soltotu,soltott)
end
plot(alpha_of_phi!(10000.0,-0.0009,0.0074847,2.0),yaxis=:log)
plot!(alpha_of_phi!(16.0,-0.1,0.00001,2.0))
```
If you were plotting a solution returned by solve directly, then the Plots recipes for DifferentialEquations enable an optional keyword argument for plot entitled plotdensity, which would let you choose the number of points plotted, and thus smoothness, as described in the docs, e.g.:
plot(sol,plotdensity=10000)
However, this keyword appears to require a solution object, rather than a DiffEqArray. Consequently, your best bet will indeed be manually setting saveat. For this approach, saveat = 0.01 would seem to be plenty to obtain fully smooth lines. However, this still gives the "range step cannot be zero" error you describe.
While I have no deep understanding of the system you are solving, an inspection of the results revealed duplicate timesteps in the results for alpha_of_phi!(16.0,-0.1,0.00001,2.0) run without saveat, suggesting that the classical simulation was being run with over a range of no time. In other words, this hints that last(solquant.t) may well be equal to or greater than ϕ₀ with these parameters, resulting in a timespan of zero. If so, this will quite understandably fail when you request to saveat some finite time within that timespan (last(solquant.t), ϕ₀).
Consequently, working on this hypothesis, if we just rewrite your function to check for this condition
using DifferentialEquations, Plots
function alpha_of_phi!(s2,d,a0,ϕ₀)
# α in the quantum phase
function quantum!(dv,v,p,ϕ)
s2,d=p
α = v[1]
dv[1] = (ϕ*s2*sin(2*d*α)+2*d*sinh(s2*α*ϕ))/(-α*s2*sin(2*d*α)+2*d*cos(2*d*α)+2*d*cosh(s2*α*ϕ))
end
# When dα/dϕ = 1, we reach the classical regime, and stop the integration
condition(v,ϕ,integrator) = (ϕ*s2*sin(2*d*v[1])+2*d*sinh(s2*v[1]*ϕ))/(-v[1]*s2*sin(2*d*v[1])+2*d*cos(2*d*v[1])+2*d*cosh(s2*v[1]*ϕ))==1.0
affect!(integrator) = terminate!(integrator)
cb = DiscreteCallback(condition,affect!)
# Initial Condition at the bounce
α₀ = [a0]
classspan = (0,ϕ₀)
probquant = ODEProblem(quantum!,α₀,classspan,(s2,d))
solquant = solve(probquant,Tsit5(),callback=cb,saveat=0.01)
# α in the classical phase
function classic!(du,u,p,ϕ)
αc = u[1]
dαc = u[2]
du[1] = dαc
du[2] = 3*(-dαc^3/sqrt(2)+dαc^2+dαc/sqrt(2)-1)
end
if last(solquant.t) < ϕ₀
# IC retrieved from end of quantum phase
init = [last(solquant);1.0]
classspan = (last(solquant.t),ϕ₀)
probclass = ODEProblem(classic!,init,classspan)
solclass = solve(probclass,Tsit5(),saveat=0.01)
# α(ϕ) for ϕ>0
solu = append!(solquant[1,:],solclass[1,:]) # α
solt = append!(solquant.t,solclass.t) # ϕ
else
solu = solquant[1,:] # α
solt = solquant.t # ϕ
end
# α(ϕ) for ϕ<0
soloppu = reverse(solu)
soloppt = -reverse(solt)
pop!(soloppu)
pop!(soloppt)
# Join the two solutions
soltotu = append!(soloppu,solu)
soltott = append!(soloppt,solt)
soltot = DiffEqArray(soltotu,soltott)
end
plot(alpha_of_phi!(10000.0,-0.0009,0.0074847,2.0),yaxis=:log)
plot!(alpha_of_phi!(16.0,-0.1,0.00001,2.0))
then we would seem to be in business!

Second order delay differential equation in Julia

I'm new to Julia programming I managed to solve some 1st order DDE (Delay Differential Equations) and ODE. I now need to solve a second order delay differential equation but I didn't manage to find documentation about that (I previously used DifferentialEquations.jl).
The equation (where F is a function and τ the delay):
How can I do this?
Here is my code using the given information, it seems that the system stay at rest which is incorrect. I probably did something wrong.
function bc_model(du,u,h,p,t)
# [ u'(t), u''(t) ] = [ u[1], -u[1] + F(ud[0],u[0]) ] // off by one in julia A[0] -> A[1]
γ,σ,Q = p
ud = h(p, t-σ)[1]
du = [u[2], + Q^2*(γ/Q*tanh(ud)-u[1]) - u[2]]
end
u0 = [0.1, 0]
h(p, t) = u0
lags = [σ,0]
tspan = (0.0,σ*100.0)
alg = MethodOfSteps(Tsit5())
p = (γ,σ,Q,ω0)
prob = DDEProblem(bc_model,u0,h,tspan,p; constant_lags=lags)
sol = solve(prob,alg)
plot(sol)
The code is in fact working! It seems that it is my normalization constants that are not consistent. Thank you!
You get a state space of dimension 2, containing u = [u(t),u'(t)]. Consequently the return vector of the right-side function is [u'(t),u''(t)]. Then if ud is the delayed state [u(t-τ),u'(t-τ)] the right side function can be formulated as
[ u'(t), u''(t) ] = [ u[1], -u[1] + F(ud[0],u[0]) ]

Stochastic differential equation sensitivity analysis with specified noise

I am trying to calculate the gradient of a functional of a stochastic differential equation (SDE) solution given a specific realization of the noise. I can successfully calculate these gradients if I leave the noise unspecified, as shown in DiffEqFlux.jl: Using Other Differential Equations. I can also successfully obtain the solution to my SDE for a specific noise realization, like shown in DifferentialEquations.jl: NoiseWrapper Example. When I try and put the two together, though, the code returns an error.
Here is a minimal working example adapted from the two separate examples referenced above:
using StochasticDiffEq, DiffEqBase, DiffEqNoiseProcess, DiffEqSensitivity, Zygote
function lotka_volterra(du,u,p,t)
x, y = u
α, β, δ, γ = p
du[1] = dx = α*x - β*x*y
du[2] = dy = -δ*y + γ*x*y
end
function lotka_volterra_noise(du,u,p,t)
du[1] = 0.1u[1]
du[2] = 0.1u[2]
end
dt = 1//2^(4)
u0 = [1.0,1.0]
p = [2.2, 1.0, 2.0, 0.4]
prob1 = SDEProblem(lotka_volterra,lotka_volterra_noise,u0,(0.0,10.0),p)
sol1 = solve(prob1,EM(),dt=dt,save_noise=true)
W2 = NoiseWrapper(sol1.W)
prob2 = SDEProblem(lotka_volterra,lotka_volterra_noise,u0,(0.0,10.0),p,noise=W2)
sol2 = solve(prob2,EM(),dt=dt)
function predict_sde1(p)
Array(concrete_solve(remake(prob1,p=p),EM(),dt=dt,sensealg=ForwardDiffSensitivity(),saveat=0.1))
end
loss_sde1(p) = sum(abs2,x-1 for x in predict_sde1(p))
loss_sde1(p)
# This gradient is successfully calculated
Zygote.gradient(loss_sde1,p)
function predict_sde2(p)
W2 = NoiseWrapper(sol1.W)
Array(concrete_solve(remake(prob2,p=p,noise=W2),EM(),dt=dt,sensealg=ForwardDiffSensitivity(),saveat=0.1))
end
loss_sde2(p) = sum(abs2,x-1 for x in predict_sde2(p))
# This loss is successfully calculated
loss_sde2(p)
# This gradient calculation raises and error
Zygote.gradient(loss_sde2,p)
The error I get at the end of running this code is
TypeError: in setfield!, expected Float64, got ForwardDiff.Dual{Nothing,Float64,4}
Stacktrace:
[1] setproperty! at ./Base.jl:21 [inlined]
...
followed by an interminable conclusion to the stacktrace (I can post it if you think it would be helpful, but since it's longer than the rest of this question I'd rather not clutter things up off the bat).
Is calculating gradients for SDE problems with specified noise realizations not currently supported, or am I just not making the appropriate function calls? I could easily believe the latter, since it was a bit of a struggle just to get to the point where the working parts of the above code worked, but I couldn't find any clue as to what I had incorrectly supplied after stepping through this code with the Juno debugger.
As a StackOverflow solution, you can use ForwardDiffSensitivity(convert_tspan=false) to work around this. Working code:
using StochasticDiffEq, DiffEqBase, DiffEqNoiseProcess, DiffEqSensitivity, Zygote
function lotka_volterra(du,u,p,t)
x, y = u
α, β, δ, γ = p
du[1] = dx = α*x - β*x*y
du[2] = dy = -δ*y + γ*x*y
end
function lotka_volterra_noise(du,u,p,t)
du[1] = 0.1u[1]
du[2] = 0.1u[2]
end
dt = 1//2^(4)
u0 = [1.0,1.0]
p = [2.2, 1.0, 2.0, 0.4]
prob1 = SDEProblem(lotka_volterra,lotka_volterra_noise,u0,(0.0,10.0),p)
sol1 = solve(prob1,EM(),dt=dt,save_noise=true)
W2 = NoiseWrapper(sol1.W)
prob2 = SDEProblem(lotka_volterra,lotka_volterra_noise,u0,(0.0,10.0),p,noise=W2)
sol2 = solve(prob2,EM(),dt=dt)
function predict_sde1(p)
Array(concrete_solve(remake(prob1,p=p),EM(),dt=dt,sensealg=ForwardDiffSensitivity(convert_tspan=false),saveat=0.1))
end
loss_sde1(p) = sum(abs2,x-1 for x in predict_sde1(p))
loss_sde1(p)
# This gradient is successfully calculated
Zygote.gradient(loss_sde1,p)
function predict_sde2(p)
Array(concrete_solve(prob2,EM(),prob2.u0,p,dt=dt,sensealg=ForwardDiffSensitivity(convert_tspan=false),saveat=0.1))
end
loss_sde2(p) = sum(abs2,x-1 for x in predict_sde2(p))
# This loss is successfully calculated
loss_sde2(p)
# This gradient calculation raises and error
Zygote.gradient(loss_sde2,p)
As a developer... this isn't a nice solution and our default should be better here. I'll work on this. You can track the development here https://github.com/JuliaDiffEq/DiffEqSensitivity.jl/issues/204. It'll probably get solved in an hour or so.
Edit: The fix is released and your original code works.

Complex PDE (Ginzburg Landau) in Julia with Pseudo-Spectral method

I want to teach myself about solving PDEs with Julia and I am trying to solve the complex Ginzburg Landau equation (CGLE) with a pseudospectral method in Julia now. However, I struggle with it and I am a bit of ideas what to try.
The CGLE reads:
With Fourier transform and its inverse , I can transform into the spectral form:
This is for example also given in this old script I found (https://www.uni-muenster.de/Physik.TP/archive/fileadmin/lehre/NumMethoden/SoSe2009/Skript/script.pdf) From the same source I know, that alpha=1, beta=2 and initial conditions with small noise of order 0.01 around 0 should result in plane waves as solutions. Thats what I want to test first.
Following the very nice tutorial from Chris Rackauckas (https://youtu.be/okGybBmihOE), I tried to use ApproxFun and DifferentialEquations in the following way to solve this problem:
EDIT: I corrected two mistakes from the original post, a missing dot and minus sign, but the code is still not giving the correct results
EDIT2: Figured out that I computed the wavenumber k completely wrong
using ApproxFun
using DifferentialEquations
F = Fourier()
n = 512
L = 100
T = ApproxFun.plan_transform(F, n)
Ti = ApproxFun.plan_itransform(F, n)
x = collect(range(-L/2,stop=L/2, length=n))
k = points(F, n)
alpha = 1im
beta = 2im
u0 = 0.01*(rand(ComplexF64, n) .- 0.5)
Fu0 = T*u0
function cgle!(du, u, p, t)
a, b, k, T, Ti = p
invu = Ti*u
du .= (1.0 .- k.^2*(1.0 .+a)).*u .- T*( (1.0 .+b) .* (abs.(invu)).^2 .* invu)
end
pars = alpha, beta, k, T, Ti
prob = ODEProblem(cgle!, Fu0, (0.,50.), pars)
u = solve(prob, Rodas5(autodiff=false))
# plotting on a equidistant time stepping
t = collect(range(0, stop=50, length=1000))
sol = zeros(eltype(u),(n, length(t)))
for it in eachindex(t)
sol[:,it] = Ti*u(t[it])
end
IM = PyPlot.imshow(real.(sol))
cb = PyPlot.colorbar(IM, orientation="horizontal")
gcf()
(edited) I tried different solvers, as also recommended in the video, some apparently wont work for complex numbers, some do, but when I run this code it does not give the expected results. The solution remain very small in value and it wont result in the plane waves that actually should be the result. I also tested other intial conditions that should result in chaos, but those result in the same very small solutions as well. I also alternativly used an explicit Laplace Operator with ApproxFun, but the results are the same. My problem here, is that I am neither really an expert with PDE mathemitacaly, nor with their numerical treatment, so far I mainly worked with ODEs.
EDIT2 This now seems to work more or less. I am still wondering about some things though
How can I compute this on a specified domain like , I am seriously confused about how this works with ApproxFun, as far as I can see the wavenumbers k should be (2pi/L)*[-N/2+1 ; N/2 -1], but I am not so sure about how to do this with ApproxFun
https://codeinthehole.com/tutorial/coherent.html shows the different dynamic regimes / phase portrait of the equation. While I can reproduce some of them, some don't seem to work, like the Spatio-temporal intermittency
EDIT 3: I solved these issues by using FFTW directly instead of ApproxFun. In case somebody knows how to this with ApproxFun, I would still be interessted though. Below follows the code with FFTW (it is also a bit more optimized for performance)
begin
using FFTW
using DifferentialEquations
using PyPlot
end
begin
n = 512
L = 200
n2 = Int(n/2)
alpha = 2im
beta = 1im
x = range(-L/2,stop=L/2,length=n)
u0 = 0.01*(rand(ComplexF64, n) .- 0.5)
k = [0:n/2-1; 0; -n/2+1:-1] .*(2*pi/L);
k2 = k.*k
k2[n2 + 1] = (n2*(2*pi/L))^2
T = plan_fft(u0)
Ti = plan_ifft(T*u0)
LinOp = (1.0 .- k2.*(1.0 .+alpha))
Fu0 = T*u0
end
function cgle!(du, u, p, t)
LinOp, b, T, Ti = p
invu = Ti*u
du .= LinOp.*u .- T*( (1.0 .+b) .* (abs.(invu)).^2 .* invu)
end
pars = LinOp, beta, T, Ti
prob = ODEProblem(cgle!, Fu0, (0.,100.), pars)
#time u = solve(prob)
t = collect(range(0, stop=50, length=1000))
sol = zeros(eltype(u),(n, length(t)))
for it in eachindex(t)
sol[:,it] = Ti*u(t[it])
end
IM = PyPlot.imshow(abs.(sol))
cb = PyPlot.colorbar(IM, orientation="horizontal")
gcf()
EDIT 4: Rodas turned out to be a extremly slow solver for this case, just using the default works out nicely for me.
Any help is appreciated.
du = (1. .- k.^2*(1. .+(im*a))).*u + T*( (1. .+(im*b)) .* abs.(invu).^2 .* invu)
Notice that is replacing the pointer to du, not updating it. Use something like .= instead:
du .= (1. .- k.^2*(1. .+(im*a))).*u + T*( (1. .+(im*b)) .* abs.(invu).^2 .* invu)
Otherwise your derivative is just 0.

Resources