PDE Parameter Estimation

To get an interface as close as possible to DiffEqParamEstim.jl I overloaded L2Loss for PDETimeSeriesSolution

import ModelingToolkit.SciMLBase: PDETimeSeriesSolution
function (f::L2Loss)(sol::PDETimeSeriesSolution)
    xidx, data = f.data
    weight = f.data_weight
    diff_weight = f.differ_weight
    colloc_grad = f.colloc_grad
    dudt = f.dudt

    if sol isa DiffEqBase.AbstractEnsembleSolution
        failure = any(!SciMLBase.successful_retcode(s.retcode) for s in sol)
    else
        failure = !SciMLBase.successful_retcode(sol.retcode)
    end
    failure && return Inf

    sum(abs2, data - sol[c(x, t)][x_idx, :])
end

It looks a bit hacky (maybe suboptimal somewhere?) as I have to provided observed points indexes. However, it works here

x_obs = 0:0.05:L
x_idx = findall(x -> x ∈ x_obs, sol[x])

cost_function = build_loss_objective(prob, Tsit5(), L2Loss(sol.t, (x_idx, data)),
                                     Optimization.AutoForwardDiff(),
                                     maxiters = 1000000, verbose = true)

cost_function(0.2)
cost_function(0.1) # = 0 as expected
optprob = Optimization.OptimizationProblem(cost_function, [0.3])
using OptimizationOptimJL
@time "optimization" optsol = solve(optprob, BFGS())

Here is complete code

##### Define PDE problem #####
using ModelingToolkit: Interval
using ModelingToolkit 
using DifferentialEquations
using MethodOfLines
# Variables
@variables x 
@independent_variables t 
@variables c(..) 
∂t = Differential(t)
∂²x = Differential(x)^2
# Parameters
@parameters D
# PDE
eqn = ∂t(c(x, t)) ~ D * ∂²x(c(x, t))
# Space and time domains
L=3.0 
T=3.0 
dom = [x ∈ Interval(0, L), t ∈ Interval(0, T)]
# Initial and boundary conditions
bcs = [
       c(0,t) ~ 1.0, 
       c(x,0) ~ 0.0,
       ] 
# Define PDE system
@named sys = PDESystem(eqn,
                       bcs,
                       dom,
                       [x, t],
                       [c(x, t)],
                       [D];
                       defaults=Dict(D => 0.1)
                       )

# Define ODE problem
prob = discretize(sys, 
                  MOLFiniteDifference([x => 0.05],
                                      t,
                                      advection_scheme=scheme=UpwindScheme(2)
                                      )             
                  );
##### Generate synthetic data #####
@time "PDE Solve" sol = solve(prob, Tsit5(), saveat=0.1)

key=collect(keys(sol.u))[1]
data=sol.u[key]

##### Parameter estimation using DiffEqParamEstim ######
using Optimization
using DiffEqParamEstim
# # Create cost function
# cost_function = build_loss_objective(prob, Tsit5(), L2Loss(sol.t, data),
#                                      Optimization.AutoForwardDiff(),
#                                      maxiters = 1000000, verbose = true)
# # Test cost function
# cost_function(0.2)

import ModelingToolkit.SciMLBase: PDETimeSeriesSolution
function (f::L2Loss)(sol::PDETimeSeriesSolution)
    xidx, data = f.data
    weight = f.data_weight
    diff_weight = f.differ_weight
    colloc_grad = f.colloc_grad
    dudt = f.dudt

    if sol isa DiffEqBase.AbstractEnsembleSolution
        failure = any(!SciMLBase.successful_retcode(s.retcode) for s in sol)
    else
        failure = !SciMLBase.successful_retcode(sol.retcode)
    end
    failure && return Inf

    sum(abs2, data - sol[c(x, t)][x_idx, :])
end

x_obs = 0:0.05:L
x_idx = findall(x -> x ∈ x_obs, sol[x])

cost_function = build_loss_objective(prob, Tsit5(), L2Loss(sol.t, (x_idx, data)),
                                     Optimization.AutoForwardDiff(),
                                     maxiters = 1000000, verbose = true)

cost_function(0.2)
optprob = Optimization.OptimizationProblem(cost_function, [0.3])
using OptimizationOptimJL
@time "optimization" optsol = solve(optprob, BFGS())

Notice I get a few warning (that I don’t understand all) during last solve.
Plus I changed compare to original @cartiery code the PDESystem definition according to latest notation, see Discretization failed (no method matching getmetadata(...)) · Issue #427 · SciML/MethodOfLines.jl · GitHub