Hi Julia community,
I have been trying to add a constraint to my inversion process:
using Optimization, Optim, OptimizationOptimJL
# Objective function
function objfun(x, simulation, realsol)
simulation.model.iceflow.A[]=x[1]*1e-17 #scaling for optimization
iceflow_prob = ODEProblem{false}(Huginn.SIA2D, model.iceflow.H, params.simulation.tspan, tstops=params.solver.tstops, simulation)
iceflow_sol = solve(iceflow_prob,
params.solver.solver,
callback=cb_MB,
tstops=params.solver.tstops,
reltol=params.solver.reltol,
abstol=params.solver.reltol,
save_everystep=params.solver.save_everystep,
progress=params.solver.progress,
progress_steps=params.solver.progress_steps)
H_obs = realsol[1]
V_obs = realsol[2]
H_pred = iceflow_sol.u[end]
map!(x -> ifelse(x>0.0,x,0.0), H_pred, H_pred)
V_pred = Huginn.avg_surface_V(H_pred, simulation)[3]
ofv = 0.0
if any((s.retcode != :Success for s in iceflow_sol))
ofv = 1e12
else
mask_H = H_obs .!= 0
mask_V = V_pred .!= 0
ofv_H = mean((H_pred[mask_H] .- H_obs[mask_H]) .^ 2)
ofv_V = mean((V_obs[mask_V] .- V_pred[mask_V]) .^ 2)
ofv = x[2] * ofv_H + x[3] * ofv_V
end
println("A = $x")
println("MSE = $ofv")
return ofv
end
# Optimization
fn(x, p) = objfun(x, p[1], p[2])
cons(res, x, p) = (res .= x[2] + x[3] - 1.0)
realsol = (glacier.H_glathida, glacier.V[1:end-1, 1:end-1])
# Bounds for parameters
lower_bound = [0.0085,0.0, 0.0] #A, weight_H, weight_V
upper_bound = [8.0, 1.0, 1.0]
optfun = OptimizationFunction(fn, Optimization.AutoForwardDiff(), cons=cons)
optprob = OptimizationProblem(optfun, [4.0,0.5,0.5], (simulation, realsol), lb =
lower_bound,ub = upper_bound, lcons = [0.0], ucons = [0.0])
sol = solve(optprob, IPNewton(), x_tol=1.0e-2, f_tol = 1e-1)
The problem is when I add the constraint (x[2]+x[3] = 1.0
) as above I get that the parameters become NAN’s:
┌ Warning: First function call produced NaNs. Exiting. Double check that none of the initial conditions, parameters, or timespan values are NaN.
└ @ OrdinaryDiffEq ~/.julia/packages/OrdinaryDiffEq/Y6bIX/src/initdt.jl:250
┌ Warning: Automatic dt set the starting dt as NaN, causing instability. Exiting.
└ @ OrdinaryDiffEq ~/.julia/packages/OrdinaryDiffEq/Y6bIX/src/solve.jl:572
┌ Warning: NaN dt detected. Likely a NaN value in the state, parameters, or derivative value caused this outcome.
└ @ SciMLBase ~/.julia/packages/SciMLBase/8XHkk/src/integrator_interface.jl:574
A = [NaN, NaN, NaN]
Note that without the constraint the inversion works perfectly fine.
The only changes I made are the following:
cons(res, x, p) = (res .= x[2] + x[3] - 1.0)
optfun = OptimizationFunction(fn, Optimization.AutoForwardDiff(), cons=cons)
optprob = OptimizationProblem(optfun, [4.0,0.5,0.5], (simulation, realsol), lb =
lower_bound,ub = upper_bound, lcons = [0.0], ucons = [0.0])
sol = solve(optprob, IPNewton(), x_tol=1.0e-2, f_tol = 1e-1) #solver was BFGS() before
Does someone has a clue on how to solve this (or properly apply constraints for my case)?
Any help is appreciated, thanks in advance!