Help me outperform Matlab in numerical solution of semidiscretized PDE system as much as possible

You didn’t supply initial conditions.

Are you sure this is the problem? As it seems, I don’t need to give the initial conditions explicity when defining the ODEProblem probDAE_MTK1 either. And this is in line with the following tutorial:
https://mtk.sciml.ai/stable/mtkitize_tutorials/modelingtoolkitize/

Nevertheless, I tried the following:

# Now try to structural_simplify the system before solving it
de2 = structural_simplify(de)

u0reduced = [u0[1:200]; u0[202:end]]
probDAE_MTK2 = ODEProblem(de2,u0reduced,(0.0,1500),p_noDualCache,jac=true,sparse=true)

sol_MTK2 = solve(probDAE_MTK2,QBDF())

This still gives the same error, which I find relieving, because defining u0reduced forced me to make assumptions about state / equation ordering in system de2 after structural_simplify, which can very well be wrong.

So, what is my problem?

Can you share what the error is?

I get the following error: UndefVarError: x_{201} not defined

Complete code to reproduce:

using DifferentialEquations
using DifferentialEquations.DiffEqBase: dualcache
using LinearAlgebra
using ModelingToolkit
using SparseArrays
using BenchmarkTools

# Generate the constants
const N = 100
dx = 0.5 / N
q = dualcache(zeros(N,1))
rR = dualcache(zeros(N,1))
ϱu = 0
dp = 100e2
Tin = 200

# generate index lists to find the solution variables easily in solution vector
const indices_Tgas = 1:N
const indices_Tsol = indices_Tgas .+ N
const indices_mflux = indices_Tsol[end] + 1
const indices_RConcentrationSolid = indices_mflux[end] .+ (1:N)

# indices = (indices_Tgas, indices_Tsol, indices_mflux, indices_RConcentrationSolid)

p_noDualCache = (dx, # control volume length
    dp, # boundary condition: pressure differential across domain
    Tin, # boundary condition: Gas inlet temperature
    q, # caching variable for q
    rR, # caching variable for rR
    ϱu)

function DiscretizedSystemMassMatrixForm_noDualcache!(du,u,p,t)
  # N,dx, dp, Tin, q, rR, ϱu, indices_Tgas, indices_Tsol, indices_mflux, indices_RConcentrationSolid = p
  dx, dp, Tin, q, rR, ϱu = p
  Tgas = @view u[indices_Tgas]
  Tsol = @view u[indices_Tsol]
  dTgas = @view du[indices_Tgas]
  dTsol = @view du[indices_Tsol]
  mflux = @view u[indices_mflux]
  dmflux = @view du[indices_mflux]
  RConcsol  = @view u[indices_RConcentrationSolid]
  dRConcsol  = @view du[indices_RConcentrationSolid]

  q = 1e4 * (Tgas - Tsol)
  ϱu = mflux[1]

  rR = 5.5e6 .* exp.(.-5680 ./(273 .+ Tsol)) .* (1 .- exp.(.-RConcsol./50))

  # gas energy balance
  @inbounds begin
    dTgas[1] =  ϱu * 1000 * (Tin - Tgas[1]) - q[1] * dx
  end
  @inbounds for k in 2:N
    dTgas[k] = ϱu * 1000 * (Tgas[k-1] - Tgas[k]) - q[k] * dx
  end


  # solids energy balance
  @inbounds for k in 1:N
    dTsol[k] = q[k] / (1000 * 2000)
  end

  # gas momentum balance
  @inbounds begin
    dmflux[1] = - mflux[1] + 5e-3 * sqrt(dp)
  end

  # reactant concentration equations
  @inbounds for k in 1:N
    dRConcsol[k] = -rR[k]
  end


end



# build initial conditions
u0 = zeros(N*3 + 1)
u0[indices_Tgas] .= Tin
u0[indices_Tsol] .= 20
u0[indices_mflux] = 0.5
u0[indices_RConcentrationSolid] .= 3000

# build mass matrix
Ii = [indices_Tsol; indices_RConcentrationSolid];
Jj = [indices_Tsol; indices_RConcentrationSolid];
V = ones(length(Ii));
Msparse = sparse(Ii,Jj,V, 3*N+1, 3*N+1)


f_DAE = ODEFunction(DiscretizedSystemMassMatrixForm_noDualcache!, mass_matrix=Msparse)
probDAE = ODEProblem(f_DAE,u0,(0.0,1500),p_noDualCache)
de = modelingtoolkitize(probDAE)

# MTKized system back to numerical problem:
probDAE_MTK1 = ODEProblem(de,[],(0.0,1500),p_noDualCache,jac=true,sparse=true)

# solve the numerical problem - works
sol_MTK1 = solve(probDAE_MTK1,QBDF())

# pretty much as fast as solving non-MTKized system with Jacobian sparsity, as in above posts.
@benchmark solve(probDAE_MTK1,QBDF()) 




# Now try to structural_simplify the system before solving it
de2 = structural_simplify(de)

# system de2 only has 200 states after structural simplification
probDAE_MTK2 = ODEProblem(de2,[],(0.0,1500),p_noDualCache,jac=true,sparse=true)

# Error thrown: UndefVarError: x_{201} not defined 
sol_MTK2 = solve(probDAE_MTK2,QBDF())

Thanks, solution and tests here: https://github.com/SciML/ModelingToolkit.jl/pull/1479

1 Like

If simplicity of syntax and ease of use are what you are after, check out MethodOfLines.jl, with which you can specify, discretize and solve PDE systems in close to purely mathematical syntax.

Compile times are quite high right now, but the solves themselves are comparable to manual semidiscretization, so still useful for parameter sweeps, ensembles and optimization problems.

Changes are coming which will improve compile times by a lot.

Thank you, I am more or less aware of the beauty the usage of MethodOfLines and ModelingToolkit offers, and I will definitely make use of them, when (if) I make the decision to use Julia in professional and productive settings. I am currently evaluating this.
For that reason, I wanted to get a feeling how much the performance of above codes can be pushed with some effort in coding.