Hi everyone,
I’m relatively new to Julia and I’m trying to solve a crowd control Mean Field Game (MFG) problem (inspired by Yves Achdou’s work " Mean Field Games for Modeling Crowd Motion") consisting of:
- A Hamilton–Jacobi–Bellman (HJB) equation
- A Fokker–Planck (FP) equation
The domain is 2D with a somewhat complex geometry – a room with rectangular obstacles inside. The boundary includes two “doors” (for outflow) with Dirichlet=0, and walls with no-flux (Neumann=0) conditions.
I’ve managed to:
- Generate the mesh with Gmsh and import it into Gridap.jl,
- Set up and solve the HJB part successfully (with some standard boundary conditions: Dirichlet=0 on doors, Neumann=0 on walls).
However, in the FP equation, I need the density ρ to remain nonnegative. A standard FEM approach in Gridap doesn’t inherently enforce positivity. I tried transformations like ϕ=log(1+ρ) to handle the positivity, but end up hitting singularity errors.
Questions:
- Should I remain in Gridap (with a specialized approach for positivity)?
- Or switch to another FEM/FVM package (like Ferrite.jl, VoronoiFVM.jl, etc.) that might better handle positivity constraints?
- Any recommended techniques for the MFG context?
My ultimate goal is to run a standard fixed‐point iteration (Achdou style) in which HJB at iteration n yields a drift used in the FP at iteration n+1, and vice versa, until convergence.
I really like Gridap’s high‐level interface for PDE operators, but am open to alternatives if there’s a more robust way to ensure ρ≥0. For instance, I tried code like this:
a_ρ(t, dtρ, v) = ∫(v *dtρ)dΩ
f_ρ(t, ρ) = ρ/(1+ρ).^(3/4)
b_ρ(t, ρ, v) = 0.05*∫( ∇(ρ)⋅∇(v) )dΩ + ∫(v*(16*(∇(u(t))⋅∇(v))*f_ρ(t, ρ)))dΩ
jac_ρ_t(t, ρ, dtρ, v) = ∫(v * dtρ)dΩ
∂f_ρ(t,ρ) = (1-ρ/4)/(1+ρ).^(7/4)
jac_ρ(t, ρ, dρ, v) = 0.05*∫( ∇(dρ)⋅∇(v) )dΩ + ∫(16*(∇(u(t))⋅∇(v))*∂f_ρ(t,ρ)*dρ)dΩ
res_ρ(t, ρ, v) = b_ρ(t, ρ, v)
op_ρ = TransientSemilinearFEOperator( a_ρ, res_ρ, (jac_ρ, jac_ρ_t), U, V; constant_mass=true)
lin_solver = LUSolver()
nl_solver = NLSolver(lin_solver, method=:newton, iterations=10, show_trace=false)
Δt = 0.05
θ = 0.5
solver = ThetaMethod(nl_solver, Δt, θ)
t0, T = 0.0, 10.0
ρh0 = interpolate_everywhere(m_0, V)
ρh =@pipe solve(solver, op_ρ, t0, T, ρh0) |> collect(_)
…and it fails due to ρ going negative.
Furthermore, I tried studying the PDE solved by ϕ=log(1+ρ) with
e=exp(1.0)
a_ϕ(t, ϕ, dtϕ, v) = ∫(v *dtϕ*e.^ϕ)dΩ
f_ϕ(t, ϕ) = e.^(ϕ/4)-e.^(-ϕ*3/4)
b_ϕ(t, ϕ, v) = 0.05*∫( ∇(ϕ)⋅∇(v)*e.^ϕ )dΩ + ∫(v*(16*(∇(u(t))⋅∇(v))*f_ϕ(t, ϕ)))dΩ
jac_ϕ_t(t, ϕ, dtϕ, v) = ∫(v * dtϕ * e.^ϕ)dΩ
∂f_ϕ(t, ϕ) = e.^(ϕ/4)/4+e.^(-ϕ*3/4)*3/4
jac_ϕ(t, ϕ, dϕ, v) = 0.05*∫( ∇(dϕ)⋅∇(v)*e.^ϕ )dΩ + 0.05*∫( ∇(ϕ)⋅∇(v)*e.^ϕ*dϕ )dΩ + ∫(16*(∇(u(t))⋅∇(v))*∂f_ϕ(t, ϕ)*dϕ)dΩ
res_ϕ(t, ϕ, v) = b_ϕ(t, ϕ, v)
op_ϕ = TransientQuasilinearFEOperator( a_ϕ, res_ϕ, (jac_ϕ, jac_ϕ_t), U, V)
lin_solver = LUSolver()
nl_solver = NLSolver(lin_solver, method=:newton, iterations=10, show_trace=false)
Δt = 0.05
θ = 0.5
solver = ThetaMethod(nl_solver, Δt, θ)
t0, T = 0.0, 10.0
ϕh0 = interpolate_everywhere(x -> log(m_0(x)+1), V)
ϕh =@pipe solve(solver, op_ϕ, t0, T, ϕh0) |> collect(_)
…and it fails due to a raising SingularException.
Any advice or suggested approach? Thanks!