Derivative of complex cost function

Hello,

I am a newbie trying to use Fenics (dolfinx) in order to study the sensitivity of Maxwell stresses for a magneto static problem.

I solve the planar case, as it is performed in the tutorial.

Then, I define my cost function the following way

normals = FacetNormal(mesh)
dArm = Measure("dS", domain=mesh, subdomain_data=facet_tags, subdomain_id=42)
maxwell = Function(W)
maxwell.interpolate( Expression(as_vector((B[0]*B[0]-B[1]*B[1], 2.*B[0]*B[1])), W.element.interpolation_points()) )
cost = 1./(2.*mu0)*inner(maxwell("-"), normals("-"))*dArm

I aim to use the adjoint method in order to compute the sensitivity of the Maxwell stresses, which in my case is a contour integral over a defined subdomain (tag, 42) of the following expression

\oint_{Gamma} \left[ (B_x^2 - B_y^2) \cdot n^x + 2 B_x B_y \cdot n^y\right] d\Gamma

However, when I compute the derivative of my cost w.r.t. the non trivial component of the vector potential A^z, dolfinx yields a zero vector

dCdAz = derivative(cost, A_z) # assembling it yield zeros

I guess I am doing something wrong.
Maybe is it related to the way I define my cost function? (which is constant per element, hence the (-)).

I would appreciate any help coming from an advanced Fenics user :slight_smile:

There appears to be no A_z in cost, hence FEniCS righfully concludes dCdAz=0. I assume you used A_z in the definition of B? Yet this ‘connection’ is lost with the interpolation. Interpolation really just determines the (numerical) values of the degrees of freedom of the associated function, without retaining knowledge on how those values are retained/relate to other functions.

I assume you want something like:

normals = FacetNormal(mesh)
dArm = Measure("dS", domain=mesh, subdomain_data=facet_tags, subdomain_id=42)
maxwell = as_vector((B[0]*B[0]-B[1]*B[1], 2.*B[0]*B[1] )
cost = 1./(2.*mu0)*inner(maxwell("-"), normals("-"))*dArm

dCdAz = derivative(cost, A_z) # assembling it yield zeros

Hello Stein. Thanks for your reply.

Indeed, B is a Function(functionspace(mesh, ("DG", 0, (mesh.geometry.dim, )))) that interpolates the A_z obtained by solving the weak form

\int_{\Omega} \frac{1}{\mu} \nabla A^z \cdot \nabla v ~ d\Omega = \int_\Omega J ~v ~ d\Omega

A_zis a a Function(functionspace(mesh, ("Lagrange", 1))).
The interpolation is performed as follows

B_expr = Expression(as_vector((A_z.dx(1), -A_z.dx(0))), W.element.interpolation_points())
B.interpolate(B_expr) # W = functionspace(mesh, ("DG", 0, (mesh.geometry.dim, )))

(since B = \nabla \times A)

Do I have to express my cost function as an explicit function of A_z?

Yes, you do have to use the explicit variable.

Yes, for FEniCS to be able to carry out the derivative of Cost w.r.t. Az, it must know the explicit dependency. That explicit dependency is lost when you interpolate onto a space.

Augmenting my earlier snippet, I’d expect something like:

normals = FacetNormal(mesh)
dArm = Measure("dS", domain=mesh, subdomain_data=facet_tags, subdomain_id=42)
B = as_vector((A_z.dx(1), -A_z.dx(0))
maxwell = as_vector((B[0]*B[0]-B[1]*B[1], 2.*B[0]*B[1] )
cost = 1./(2.*mu0)*inner(maxwell("-"), normals("-"))*dArm

dCdAz = derivative(cost, A_z) # assembling it yield zeros

Thanks to the both of you.

Indeed, Stein’s snippet works.