Objectives

Objectives evaluate a reconstruction functional and its gradient for a conductivity $\sigma$. All buffers are allocated when the objective is built; the linear solver is swappable (DirectSolver, BlockCGSolver) and the gradient representation is chosen with an AbstractRieszMap.

ModularEIT.value_and_gradient! — Function
value_and_gradient!(g, obj, σ)

Value of the objective at σ; writes the gradient (in the representation of the objective's gradient Riesz map) into g.

source

Adjoint-state least squares

Theory: wiki articles Adjoint State Method and Adjoint Method for the Dirichlet Problem.

ModularEIT.AdjointStateObjective — Type
AdjointStateObjective(fm, inputs, data; mode = :neumann, solver = DirectSolver(),
                      misfit = SquaredEuclidean(), gradient = CoefficientGradient())

Least-squares misfit J(σ) = ½ Σₛ ‖U eₛ(σ)‖² between predicted and measured data for the forward model fm, with the gradient from one adjoint solve and the Jacobian on request.

  • mode = :neumann: inputs are current patterns (n_inject × s), data the measured voltages (n_measure × s). Voltages are compared after removing their mean (the ground is arbitrary), weighted by fm.measure_weights (boundary lengths for the continuum model).
  • mode = :dirichlet: inputs are voltage patterns (n_control × s), data the measured currents (n_inject × s, in the representation of fm.P).

solver is any AbstractLinearSolver; misfit any AbstractMisfit; gradient the AbstractRieszMap applied to the coefficient gradient. All buffers are allocated here; evaluations only allocate inside the linear solvers.

Interface: objective_value, value_and_gradient!, residual!, residual_and_jacobian!, n_residual.

source
ModularEIT.residual! — Function
residual!(r, obj, σ)

Whitened residual r = vec(U e) at σ (so that J = ½ ‖r‖²); returns r.

source
ModularEIT.residual — Function
residual(obj, θ)

The residual vector of a least-squares objective (J = ½ ‖r‖²) at θ, allocating; see residual!. For an AdjointStateObjective with zero data and the plain misfit this is the vector of measured voltages, i.e. the forward map. With ChainRulesCore loaded, it has reverse (Jᵀ r̄, adjoint solves) and forward (J δθ, linearized solves) differentiation rules, as does objective_value (reverse: the adjoint-state gradient).

source
ModularEIT.residual_and_jacobian! — Function
residual_and_jacobian!(r, J, obj, σ)

Whitened residual r and its Jacobian J = ∂r/∂σ (n_residual(obj) × n_σ, coefficient representation) at σ. Costs one block solve with k right-hand sides plus k × s sparse products with the conductivity tensor, k the residual entries per pattern (n_obs, or the rows of a ProjectedMisfit).

source

Matrix-free Jacobians

For problems whose Jacobian does not fit into memory: J * v costs one linearized forward solve per pattern, J' * w one adjoint solve per pattern (both reuse the factorization of the forward problem). Column norms and the Gram matrix JᵀJ are accumulated from row blocks of the Jacobian without storing it. GaussNewton(; linear_solver = :cg) uses these.

J = jacobian_operator(obj, θ)        # AdjointStateObjective or ParametrizedObjective
y = J * v; g = J' * w
s = jacobian_column_norms(obj, θ)    # sensitivities
G, g = jacobian_gram(obj, θ)         # JᵀJ and Jᵀr
ModularEIT.jacobian_operator — Function
jacobian_operator(obj, σ)

The Jacobian J = ∂r/∂σ of the residual at σ as a matrix-free operator: J * v (one linearized forward solve per pattern) and J' * w (one adjoint solve per pattern), with mul! for both, reusing the factorization of the forward solves. Neumann (current-driven) mode. The operator re-linearizes by itself if the objective has been evaluated at another σ in the meantime. For Krylov methods, Gauss–Newton with linear_solver = :cg, and problems whose Jacobian does not fit into memory.

source
ModularEIT.jacobian_column_norms — Function
jacobian_column_norms(obj, θ)

Column norms ‖J eⱼ‖ of the Jacobian of the least-squares objective obj at θ (sensitivities), accumulated from row blocks without storing J.

source
ModularEIT.jacobian_gram — Function
jacobian_gram(obj, θ)

The Gram matrix JᵀJ (n × n) and Jᵀr of the Jacobian and residual of obj at θ, accumulated from row blocks without storing J: the Gauss–Newton Hessian and gradient, also for problems with far more residuals than parameters.

source

Automatic differentiation

With ChainRulesCore.jl loaded (e.g. through Zygote), objective_value and residual have differentiation rules, so they can be used inside differentiated programs, for instance with a conductivity produced by a neural network or when training through the forward model. The derivatives are computed by the adjoint-state and linearized solves of ModularEIT, not by differentiating through the finite element and linear solver code:

  • objective_value(obj, σ): reverse rule, J̄ ∇J(σ) (the objective must deliver coefficient gradients, gradient = CoefficientGradient());
  • residual(obj, σ): reverse rule Jᵀ r̄ (one adjoint solve per pattern) and forward rule J δσ (one linearized solve per pattern), matrix-free where jacobian_operator is available.

The residual of an AdjointStateObjective with zero data is the vector of measured voltages, so residual doubles as a differentiable forward map:

using ModularEIT, ModularEITFerrite, Zygote
forward = AdjointStateObjective(fm, currents, zero(data))
gradient(σ -> sum(abs2, residual(forward, σ)), σ)

Enzyme.jl can use the same rules through Enzyme.@import_rrule.

Kohn–Vogelius

Theory: wiki article Kohn-Vogelius Functional.

ModularEIT.KohnVogeliusObjective — Type
KohnVogeliusObjective(fm, currents, voltages; solver = DirectSolver(), gradient = CoefficientGradient())

Kohn–Vogelius functional J(σ) = ½ Σₛ ‖x_N,ₛ - x_D,ₛ‖²_{A(σ)} for the current patterns currents (n_inject × s) and the measured voltages voltages (n_control × s, at the injection sites: boundary dofs, points or all CEM electrodes). The gradient needs no adjoint solve. After an evaluation, boundary_error returns the voltage misfit of the current-driven solution and pattern_values the contribution of every pattern.

source
ModularEIT.boundary_error — Function
boundary_error(obj::KohnVogeliusObjective)

Measured minus predicted voltages of the current-driven states at the last evaluation (Q x_N - V, mean removed per pattern).

source
ModularEIT.pattern_values — Function
pattern_values(obj::KohnVogeliusObjective)

Contribution ½ ‖x_N,ₛ - x_D,ₛ‖²_A of every pattern at the last evaluation.

source

Misfit metrics

ModularEIT.WeightedSquaredEuclidean — Type
WeightedSquaredEuclidean(W)

J = ½ Σₛ eₛᵀ W eₛ for a symmetric positive definite W (n_obs × n_obs), e.g. inverse noise covariances or a boundary mass matrix. Whitened residual r = U e with UᵀU = W.

source
ModularEIT.ProjectedMisfit — Type
ProjectedMisfit(U)

J = ½ Σₛ ‖U eₛ‖² for a rectangular U (k × n_obs, k ≤ n_obs): only k combinations of the measurements enter the misfit, e.g. the leading measurement modes of pattern_svd (truncate_patterns(p, K; measurements = M), a two-sided truncation of the data with K M residuals instead of n_obs K). The residual has k entries per pattern.

source

Abstract types of the reconstruction layer

Wiki articles

Theory behind this page in the theory wiki:

Index