Complex Expressions with sympy operations

What is the best way to translate the process below to play nice with dolfin_adjoint?
In short, I have a sympy nsolve, and some symbolic computations.

My class ParametricGeometry generates three Expression objects that together describe a parametric surface (an extruded circular arc) and its tangent basis. This surface is parametrized by the cross sectional length l and a scalar c (relating the cross sectional width to the length). I would like to use one or both of these parameters as controls in an optimization problem.

The final Expression objects receive a bunch of arbitrarily complex formatted cpp code snippets. Ideally, I would like to rely on sympy’s symbolic differentiation as much as possible because I expect to work with more complex geometries. I.e, I know I can manually type out the final C++ code for the surface and derivatives in terms of several variables, but would like to avoid this. And this doesn’t get around the sp.nsolve.

import sympy as sp
from dolfin import Expression, pi, Constant
from dolfin_adjoint import Expression, Constant

DEGREE = 3

def ccode(z):
    return sp.printing.ccode(z)

class ParametricGeometry(object):
    def __init__(self, c=None, length=1):
        eta, L = sp.symbols('eta, length')
        eta = sp.nsolve(c**2 * eta**2 - 2*(1-sp.cos(eta)), eta, -5)

        W = c*L

        A = -0.5*W
        B = 0.5*W * (sp.sin(eta)/(1-sp.cos(eta)))
        C = 0.5*W
        D = 0.5*W * (sp.sin(eta)/(1-sp.cos(eta)))

        # center at -cL/2,
        R = L/eta
        cx = A
        cy = W*sp.sin(eta)/(2*(1-sp.cos(eta)))
        self.eta = eta
        self.radius = R.evalf(subs={L: 1})
        self.center = [cx.evalf(subs={L: length}), cy.evalf(subs={L: length})]

        x1, x2 = sp.symbols('x[0], x[1]')
        gamma_sp = [None, None, None]
        gamma_sp[0] = A*sp.cos(x1*L/R) + B*sp.sin(x1*L/R) + C
        gamma_sp[1] = x2
        gamma_sp[2] = A*sp.sin(x1*L/R) - B*sp.cos(x1*L/R) + D
        self._build_geo(gamma_sp, length, x1, x2)

    def _build_geo(self, gamma_sp, length, x1, x2):

        # Construct the actual fenics map X = gamma(xi)
        self.gamma = Expression((ccode(gamma_sp[0]).replace('M_PI', 'pi'),
                                 ccode(gamma_sp[1]).replace('M_PI', 'pi'),
                                 ccode(gamma_sp[2]).replace('M_PI', 'pi')),
                                pi=pi,
                                length=length,
                                degree=DEGREE,
                                name="gamma")

        # Get the induced base from the mapping to the referential geometry
        # G_i = ∂X/xi_i^2
        self.Gsub1 = Expression((ccode(gamma_sp[0].diff(x1)).replace('M_PI', 'pi'),
                                 ccode(gamma_sp[1].diff(x1)).replace('M_PI', 'pi'),
                                 ccode(gamma_sp[2].diff(x1)).replace('M_PI', 'pi')),
                                pi=pi,
                                length=length,
                                degree=DEGREE,
                                name="Gsub1")

        self.Gsub2 = Expression((ccode(gamma_sp[0].diff(x2)).replace('M_PI', 'pi'),
                                 ccode(gamma_sp[1].diff(x2)).replace('M_PI', 'pi'),
                                 ccode(gamma_sp[2].diff(x2)).replace('M_PI', 'pi')),
                                pi=pi,
                                length=length,
                                degree=DEGREE,
                                name="Gsub2")