示例#1
0
    def __init__(self,
                 fem,
                 source,
                 fields,
                 Mn=None,
                 Mf1=None,
                 Mf2=None,
                 abs_du_tol=1e-8,
                 rel_du_tol=1e-8,
                 abs_res_tol=1e-10,
                 rel_res_tol=1e-10,
                 max_iter=100,
                 criterion='residual',
                 norm_change='linf',
                 norm_res='linf'):
        """The constructor"""

        Solver.__init__(self, fem, source, fields, Mn, abs_du_tol, rel_du_tol,
                        abs_res_tol, rel_res_tol, max_iter, criterion,
                        norm_change, norm_res)

        # vector finite element and function space for rescaled (phi, h, y, z)
        self.E = d.MixedElement(
            [self.fem.Pn, self.fem.Pn, self.fem.Pn, self.fem.Pn])
        self.V = d.FunctionSpace(self.fem.mesh.mesh, self.E)
        # (discontinuous) vector finite element and function space for the four strong residuals
        self.dE = d.MixedElement(
            [self.fem.dPn, self.fem.dPn, self.fem.dPn, self.fem.dPn])
        self.dV = d.FunctionSpace(self.fem.mesh.mesh, self.dE)

        # fields' rescalings
        if Mf1 is None:
            self.Mf1 = self.source.Ms * self.Mn / self.fields.Mp
        else:
            self.Mf1 = Mf1

        if Mf2 is None:
            if (self.fields.alpha != 0.):
                self.Mf2 = abs(self.fields.alpha) * self.Mf1
            else:
                self.Mf2 = self.Mf1
        else:
            self.Mf2 = Mf2

        # solution and field profiles (computed by the solver)
        self.u = None
        self.phi, self.h, self.y, self.z = None, None, None, None
        self.Phi, self.H, self.Y, self.Z = None, None, None, None

        # gradients of the scalar fields
        self.grad_phi = None  # rescaled
        self.grad_Phi = None  # physical
        self.grad_h = None
        self.grad_H = None

        # phi scalar force (physical units)
        self.force = None
示例#2
0
    def __init__(self,
                 fem,
                 source,
                 fields,
                 Mn=None,
                 Mf1='NL',
                 guess_choice='NL',
                 abs_du_tol=1e-8,
                 rel_du_tol=1e-8,
                 abs_res_tol=1e-10,
                 rel_res_tol=1e-10,
                 max_iter=100,
                 criterion='residual',
                 norm_change='linf',
                 norm_res='linf'):
        """The constructor"""

        Solver.__init__(self, fem, source, fields, Mn, abs_du_tol, rel_du_tol,
                        abs_res_tol, rel_res_tol, max_iter, criterion,
                        norm_change, norm_res)

        # vector finite element and function space for rescaled (pi, w, y)
        self.E = d.MixedElement([self.fem.Pn, self.fem.Pn, self.fem.Pn])
        self.V = d.FunctionSpace(self.fem.mesh.mesh, self.E)
        # (discontinuous) vector finite element and function space for the three strong residuals
        self.dE = d.MixedElement([self.fem.dPn, self.fem.dPn, self.fem.dPn])
        self.dV = d.FunctionSpace(self.fem.mesh.mesh, self.dE)

        # field rescaling
        if Mf1 == 'NL':
            self.Mf1 = ( self.fields.Lambda / self.Mn )**(3.-1./self.fields.n) * \
            ( self.source.Ms / self.fields.Mp )**(1./self.fields.n) * self.fields.m
        elif Mf1 == 'source':
            self.Mf1 = self.source.Ms / self.fields.Mp * self.Mn
        else:
            self.Mf1 = Mf1

        # choice of initial guess
        self.guess_choice = guess_choice

        # solution and field profiles (computed by the solver)
        self.u = None
        self.pi, self.w, self.y = None, None, None  # rescaled
        self.Pi, self.W, self.Y = None, None, None  # physical

        # gradient of the scalar field
        self.grad_pi = None  # rescaled
        self.grad_Pi = None  # physical

        # scalar force (physical units)
        self.force = None
示例#3
0
def extension_element(elm):
    '''
    Produce an intermerdiate element for computing with extension of 
    functions in FEM space over elm
    '''
    # Want exact match here; otherwise VectorElement is MixedElement and while
    # it works I don't find it pretty
    if type(elm) == df.MixedElement:
        return df.MixedElement(map(extension_element, elm.sub_elements()))

    family = elm.family()

    family_map = {'Lagrange': 'Lagrange'}
    # This seems like a reasonable fall back option
    family = family_map.get(family, 'Discontinuous Lagrange')

    degree = elm.degree()  # Preserve degree
    cell = extension_cell(elm)

    # How to construct:
    # There is an issue here where e.g. Hdiv are not scalars, their
    # element is FiniteElement but we want trace space from VectorElement
    elmtype_map = {
        0: df.FiniteElement,
        1: df.VectorElement,
        2: df.TensorElement
    }
    # So let's check first for elements where scalar = FiniteElm, vector == VectorElm
    rank = len(elm.value_shape())
    if elmtype_map[rank] == type(elm):
        elm = type(elm)  # i.e. vector element stays vector element
    else:
        elm = elmtype_map[rank]

    return elm(family, cell, degree)
示例#4
0
    def generate_function_spaces(self, order=1, use_periodic=False):
        r"""
		Generates the finite-element function spaces used with topological dimension :math:`d` set by variable ``self.top_dim``.

		:param order:        order :math:`k` of the shape function, currently only supported are Lagrange :math:`P_1` elements.
		:param use_periodic: use periodic boundaries along lateral boundary (currently not supported).
		:type use_periodic:  bool

		The element shape-functions available from this method are :

		* ``self.Q``  -- :math:`\mathcal{H}^k(\Omega)`
		* ``self.Q3`` -- :math:`[\mathcal{H}^k(\Omega)]^3`
		* ``self.V``  -- :math:`[\mathcal{H}^k(\Omega)]^d`  formed using :func:`~dolfin.functions.functionspace.VectorFunctionSpace`
		* ``self.T``  -- :math:`[\mathcal{H}^k(\Omega)]^{d \times d}` formed using :func:`~dolfin.functions.functionspace.TensorFunctionSpace`
		"""
        s = "::: generating fundamental function spaces of order %i :::" % order
        print_text(s, cls=self.this)

        if use_periodic:
            self.generate_pbc()
        else:
            self.pBC = None

        order = 1
        space = 'CG'
        Qe = dl.FiniteElement("CG", self.mesh.ufl_cell(), order)
        self.Q3 = dl.FunctionSpace(self.mesh, dl.MixedElement([Qe] * 3))
        self.Q = dl.FunctionSpace(self.mesh, space, order)
        self.V = dl.VectorFunctionSpace(self.mesh, space, order)
        self.T = dl.TensorFunctionSpace(self.mesh, space, order)

        s = "    - fundamental function spaces created - "
        print_text(s, cls=self.this)
示例#5
0
def computeVelocityField(mesh):
    Xh = dl.VectorFunctionSpace(mesh,'Lagrange', 2)
    Wh = dl.FunctionSpace(mesh, 'Lagrange', 1)

    mixed_element = dl.MixedElement([Xh.ufl_element(), Wh.ufl_element()])
    XW = dl.FunctionSpace(mesh, mixed_element)

    
    Re = 1e2
    
    g = dl.Expression(('0.0','(x[0] < 1e-14) - (x[0] > 1 - 1e-14)'), element=Xh.ufl_element())
    bc1 = dl.DirichletBC(XW.sub(0), g, v_boundary)
    bc2 = dl.DirichletBC(XW.sub(1), dl.Constant(0), q_boundary, 'pointwise')
    bcs = [bc1, bc2]
    
    vq = dl.Function(XW)
    (v,q) = ufl.split(vq)
    (v_test, q_test) = dl.TestFunctions (XW)
    
    def strain(v):
        return ufl.sym(ufl.grad(v))
    
    F = ( (2./Re)*ufl.inner(strain(v),strain(v_test))+ ufl.inner (ufl.nabla_grad(v)*v, v_test)
           - (q * ufl.div(v_test)) + ( ufl.div(v) * q_test) ) * ufl.dx
           
    dl.solve(F == 0, vq, bcs, solver_parameters={"newton_solver":
                                         {"relative_tolerance":1e-4, "maximum_iterations":100,
                                          "linear_solver":"default"}})
        
    return v
    def __init__(self, parameters, mesh, parser):
        super().__init__(parameters, mesh, parser)
        V = df.FunctionSpace(
            self.mesh,
            df.MixedElement(
                df.VectorElement('CG', self.mesh.ufl_cell(),
                                 parameters["fe degree solid"]),
                df.VectorElement('CG', self.mesh.ufl_cell(),
                                 parameters["fe degree fluid"]),
                df.FiniteElement('CG', self.mesh.ufl_cell(),
                                 parameters["fe degree pressure"])))
        self.V = V
        self.two_way = True
        self.three_way = False
        if "3-way" in self.parameters["pc type"]:
            self.two_way = False
            self.three_way = True

        parprint("---- Problem dofs={}, h={}, solving with {} procs".format(
            V.dim(), mesh.hmin(), MPI.COMM_WORLD.size))
        self.assembler = PoromechanicsAssembler(parameters, V, self.three_way)

        self.index_map = IndexSet(V, self.two_way)
        # Start by assembling system matrices
        self.assembler.assemble()

        self.sol = df.Function(V)
        self.us_nm1, self.uf_nm1, self.p_nm1 = self.sol.split(True)
        self.us_nm2 = self.us_nm1.copy(True)

        self.first_timestep = True
示例#7
0
    def test_dirichlet_boundary(self):
        frequency=50
        omega = 2.*np.pi*frequency
        c1,c2 = [343.4,6320]
        gamma=8.4e-4
        
        kappa = omega/c1

        Nx, Ny = [21,21]
        Lx,Ly=[1,1]

        # create function space
        mesh = dl.RectangleMesh(dl.Point(0., 0.), dl.Point(Lx, Ly), Nx, Ny)
        degree=1
        P1=dl.FiniteElement('Lagrange',mesh.ufl_cell(),degree)
        element=dl.MixedElement([P1,P1])
        function_space=dl.FunctionSpace(mesh,element)
        
        boundary_conditions=None
        kappa=dl.Constant(kappa)
        # do not pass element=function_space.ufl_element()
        # as want forcing to be a scalar pass degree instead
        forcing=[
            Forcing(kappa,'real',degree=function_space.ufl_element().degree()),
            Forcing(kappa,'imag',degree=function_space.ufl_element().degree())]

        p=run_model(kappa,forcing,function_space,boundary_conditions)
        error = dl.errornorm(
            ExactSolution(kappa,element=function_space.ufl_element()),p)
        print('Error',error)
        assert error<=3e-2
示例#8
0
    def test_robin_boundary(self):
        frequency=50
        omega = 2.*np.pi*frequency
        c1,c2 = [343.4,6320]
        gamma=8.4e-4
        
        kappa = omega/c1
        alpha=kappa*gamma

        Nx, Ny = 21,21; Lx, Ly = 1,1

        mesh = dl.RectangleMesh(dl.Point(0., 0.), dl.Point(Lx, Ly), Nx, Ny)
        degree=1
        P1=dl.FiniteElement('Lagrange',mesh.ufl_cell(),degree)
        element=dl.MixedElement([P1,P1])
        function_space=dl.FunctionSpace(mesh,element)
        
        boundary_conditions=get_robin_bndry_conditions(
            kappa,alpha,function_space)
        kappa=dl.Constant(kappa)
        forcing=[
            Forcing(kappa,'real',degree=function_space.ufl_element().degree()),
            Forcing(kappa,'imag',degree=function_space.ufl_element().degree())]
        
        p=run_model(kappa,forcing,function_space,boundary_conditions)
        error = dl.errornorm(
            ExactSolution(kappa,element=function_space.ufl_element()),p,)
        print('Error',error)
        assert error<=3e-2
 def _setup_function_spaces(self):
     assert hasattr(self, "_mesh")
     # element and function space definition
     cell = self._mesh.ufl_cell()
     # taylor-hood element
     self._elemV = dlfn.VectorElement("CG", cell,
                                      self._parameters.velocity_degree)
     self._elemP = dlfn.FiniteElement("CG", cell,
                                      self._parameters.pressure_degree)
     self._elemT = dlfn.FiniteElement("CG", cell,
                                      self._parameters.temperature_degree)
     self._mixedElem = dlfn.MixedElement(
         [self._elemV, self._elemP, self._elemT])
     self._Wh = dlfn.FunctionSpace(self._mesh, self._mixedElem)
     # print info message
     ndofs_velocity = self._Wh.sub(0).dim()
     ndofs_pressure = self._Wh.sub(1).dim()
     ndofs_temperature = self._Wh.sub(2).dim()
     print "DOFs velocity : ", ndofs_velocity, "\n" \
             "DOFs pressure : ", ndofs_pressure, "\n" \
             "DOFs temperature : ", ndofs_temperature
     # functions
     self._sol = dlfn.Function(self._Wh)
     self._sol0 = dlfn.Function(self._Wh)
     self._sol00 = dlfn.Function(self._Wh)
     self._v0, _, self._T0 = dlfn.split(self._sol0)
     self._v00, _, self._T00 = dlfn.split(self._sol00)
示例#10
0
def main():
    fsr = FunctionSubspaceRegistry()

    deg = 2
    mesh = dolfin.UnitSquareMesh(100, 3)
    muc = mesh.ufl_cell()
    el_w = dolfin.FiniteElement('DG', muc, deg - 1)
    el_j = dolfin.FiniteElement('BDM', muc, deg)
    el_DG0 = dolfin.FiniteElement('DG', muc, 0)
    el = dolfin.MixedElement([el_w, el_j])
    space = dolfin.FunctionSpace(mesh, el)
    DG0 = dolfin.FunctionSpace(mesh, el_DG0)
    fsr.register(space)
    facet_normal = dolfin.FacetNormal(mesh)
    xyz = dolfin.SpatialCoordinate(mesh)

    trial = dolfin.Function(space)
    test = dolfin.TestFunction(space)

    w, c = dolfin.split(trial)
    v, phi = dolfin.split(test)

    sympy_exprs = derive_exprs()
    exprs = {
        k: sympy_dolfin_printer.to_ufl(sympy_exprs['R'], mesh, v)
        for k, v in sympy_exprs['quantities'].items()
    }

    f = exprs['f']
    w0 = dolfin.project(dolfin.conditional(dolfin.gt(xyz[0], 0.5), 1.0, 0.3),
                        DG0)
    w_BC = exprs['w']

    dx = dolfin.dx()
    form = (+v * dolfin.div(c) * dx - v * f * dx +
            dolfin.exp(w + w0) * dolfin.dot(phi, c) * dx +
            dolfin.div(phi) * w * dx -
            (w_BC - w0) * dolfin.dot(phi, facet_normal) * dolfin.ds() -
            (w0('-') - w0('+')) * dolfin.dot(phi('+'), facet_normal('+')) *
            dolfin.dS())

    solver = NewtonSolver(form,
                          trial, [],
                          parameters=dict(relaxation_parameter=1.0,
                                          maximum_iterations=15,
                                          extra_iterations=10,
                                          relative_tolerance=1e-6,
                                          absolute_tolerance=1e-7))

    solver.solve()

    with closing(XdmfPlot("out/qflop_test.xdmf", fsr)) as X:
        CG1 = dolfin.FunctionSpace(mesh, dolfin.FiniteElement('CG', muc, 1))
        X.add('w0', 1, w0, CG1)
        X.add('w_c', 1, w + w0, CG1)
        X.add('w_e', 1, exprs['w'], CG1)
        X.add('f', 1, f, CG1)
        X.add('cx_c', 1, c[0], CG1)
        X.add('cx_e', 1, exprs['c'][0], CG1)
示例#11
0
 def _element(s):
     elements = [
         s[k + '/element'] for k in s[key + '/subfunctions_keys']
     ]
     if len(elements) == 0:
         raise AssertionError()
     elif len(elements) == 1:
         return elements[0]
     else:
         return dolfin.MixedElement(elements)
示例#12
0
 def get_element(self):
     ''' use `element` property instead '''
     descs = self.subspace_descriptors
     elements = [desc['element'] for desc in descs]
     n = len(elements)
     if n == 0: raise AssertionError()
     elif n == 1:
         return elements[0]
     else:
         return dolfin.MixedElement(elements)
示例#13
0
    def create_functions(self):
        """
        Create functions to hold solutions
        """
        sim = self.simulation

        # Function spaces
        Vu = sim.data['Vu']
        Vp = sim.data['Vp']
        cd = sim.data['constrained_domain']

        # Create coupled mixed function space and mixed function to hold results
        func_spaces = [Vu] * sim.ndim + [Vp]
        self.subspace_names = ['u%d' % d for d in range(sim.ndim)] + ['p']

        # Create stress tensor space
        P = Vu.ufl_element().degree()
        Vs = dolfin.FunctionSpace(sim.data['mesh'],
                                  'DG',
                                  P,
                                  constrained_domain=cd)
        for i in range(sim.ndim**2):
            stress_name = 'stress_%d' % i
            sim.data[stress_name] = dolfin.Function(Vs)
            func_spaces.append(Vs)
            self.subspace_names.append(stress_name)

        # Create mixed space
        e_mixed = dolfin.MixedElement([fs.ufl_element() for fs in func_spaces])
        Vcoupled = dolfin.FunctionSpace(sim.data['mesh'], e_mixed)
        sim.data['Vcoupled'] = Vcoupled

        # Create function assigner
        Nspace = len(func_spaces)
        self.subspaces = [Vcoupled.sub(i) for i in range(Nspace)]
        sim.data['coupled'] = self.coupled_func = dolfin.Function(Vcoupled)
        self.assigner = dolfin.FunctionAssigner(func_spaces, Vcoupled)

        # Create segregated functions on component and vector form
        u_list, up_list, upp_list, u_conv = [], [], [], []
        for d in range(sim.ndim):
            sim.data['u%d' % d] = u = dolfin.Function(Vu)
            sim.data['up%d' % d] = up = dolfin.Function(Vu)
            sim.data['upp%d' % d] = upp = dolfin.Function(Vu)
            sim.data['u_conv%d' % d] = uc = dolfin.Function(Vu)
            u_list.append(u)
            up_list.append(up)
            upp_list.append(upp)
            u_conv.append(uc)
        sim.data['u'] = dolfin.as_vector(u_list)
        sim.data['up'] = dolfin.as_vector(up_list)
        sim.data['upp'] = dolfin.as_vector(upp_list)
        sim.data['u_conv'] = dolfin.as_vector(u_conv)
        sim.data['p'] = dolfin.Function(Vp)
示例#14
0
    def _init_spaces(self):

        mesh = self.geometry.mesh

        P1 = dolfin.FiniteElement("Lagrange", mesh.ufl_cell(), 1)
        P2 = dolfin.VectorElement("Lagrange", mesh.ufl_cell(), 2)
        P3 = dolfin.VectorElement("Real", mesh.ufl_cell(), 0, 6)

        self.state_space = dolfin.FunctionSpace(mesh, dolfin.MixedElement([P1, P2, P3]))

        self.state = Function(self.state_space, name="state")
        self.state_test = dolfin.TestFunction(self.state_space)
示例#15
0
    def computeVelocityField(self):
        """
        The steady-state Navier-Stokes equation for velocity v:
        -1/Re laplace v + nabla q + v dot nabla v = 0  in Omega
        nabla dot v = 0                                in Omega
        v = g                                          on partial Omega
        """
        Xh = dl.VectorFunctionSpace(self.mesh, 'Lagrange', self.eldeg)
        Wh = dl.FunctionSpace(self.mesh, 'Lagrange', 1)

        mixed_element = dl.MixedElement([Xh.ufl_element(), Wh.ufl_element()])
        XW = dl.FunctionSpace(self.mesh, mixed_element)

        Re = dl.Constant(self.Re)

        def v_boundary(x, on_boundary):
            return on_boundary

        def q_boundary(x, on_boundary):
            return x[0] < dl.DOLFIN_EPS and x[1] < dl.DOLFIN_EPS

        g = dl.Expression(('0.0', '(x[0] < 1e-14) - (x[0] > 1 - 1e-14)'),
                          element=Xh.ufl_element())
        bc1 = dl.DirichletBC(XW.sub(0), g, v_boundary)
        bc2 = dl.DirichletBC(XW.sub(1), dl.Constant(0), q_boundary,
                             'pointwise')
        bcs = [bc1, bc2]

        vq = dl.Function(XW)
        (v, q) = ufl.split(vq)
        (v_test, q_test) = dl.TestFunctions(XW)

        def strain(v):
            return ufl.sym(ufl.grad(v))

        F = ((2. / Re) * ufl.inner(strain(v), strain(v_test)) +
             ufl.inner(ufl.nabla_grad(v) * v, v_test) - (q * ufl.div(v_test)) +
             (ufl.div(v) * q_test)) * ufl.dx

        dl.solve(F == 0,
                 vq,
                 bcs,
                 solver_parameters={
                     "newton_solver": {
                         "relative_tolerance": 1e-4,
                         "maximum_iterations": 100,
                         "linear_solver": "default"
                     }
                 })

        return v
示例#16
0
    def _generate_function_spaces(self, **kwargs):
        """
        Generates a dolfin FunctionSpace of either single Finite Element (if only one Space is provided)
        or Mixed Elements (if more the one Space provided).
        """
        elements = [
            self._generate_finite_element(space, **kwargs)
            for space in self.spaces
        ]
        if len(elements) == 1:
            return dolf.FunctionSpace(self.domain.mesh, elements[0], **kwargs)

        mixed_element = dolf.MixedElement(elements)
        return dolf.FunctionSpace(self.domain.mesh, mixed_element, **kwargs)
    def __init__(self, t_end = None, func = None, para_stiff = None, adjoint = False):
        Problem_Basic.__init__(self, t_end = t_end, func = func, para_stiff = para_stiff)
        
        self.k = dol.Constant(self.k)
        self.u0_expr = dol.Constant(self.u0) # initial value
        
        mesh = dol.UnitIntervalMesh(1)
        R_elem = dol.FiniteElement("R", mesh.ufl_cell(), 0)
        V_elem = dol.MixedElement([R_elem, R_elem])
        self.V = dol.FunctionSpace(mesh, V_elem)
        
        if adjoint:
            self.z0_expr = dol.Constant(np.array([0., 0.])) # initial value adj
            
        Problem_FE.__init__(self, adjoint)
        
        (self.v1     , self.v2)      = dol.split(self.v)
        (self.u1trial, self.u2trial) = dol.split(self.utrial)
        (self.u1old  , self.u2old)   = dol.split(self.uold)
        (self.u1low  , self.u2low)   = dol.split(self.ulow)
        
        ## Crank nicolson weak formulation
        F = (dol.inner(self.v1, self.u1trial - self.u1old + self.dt * (0.5 * (self.u1old + self.u1trial) - 0.5 * (self.u2old + self.u2trial)))*dol.dx
           + dol.inner(self.v2, self.u2trial - self.u2old - self.k * self.dt * 0.5 * (self.u2old + self.u2trial))*dol.dx)
        prob = dol.LinearVariationalProblem(dol.lhs(F), dol.rhs(F), self.unew)
        self.solver = dol.LinearVariationalSolver(prob)
        ## Implicit Euler weak formulation for error estimation
        Flow = (dol.inner(self.v1, self.u1trial - self.u1old + self.dt * (self.u1trial - self.u2trial))*dol.dx
              + dol.inner(self.v2, self.u2trial - self.u2old - self.k * self.dt * self.u2trial)*dol.dx)
        problow = dol.LinearVariationalProblem(dol.lhs(Flow), dol.rhs(Flow), self.ulow)
        self.solver_low = dol.LinearVariationalSolver(problow)

        if adjoint:
            (self.z1old  , self.z2old)   = dol.split(self.zold)
            (self.z1trial, self.z2trial) = dol.split(self.ztrial)
            
            if self.func not in [1, 2]:
                raise ValueError('DWR not (yet) implemented for this functional')
                
            adj_src = dol.Function(self.V)
            if   self.func == 1:    adj_src.interpolate(dol.Constant((1, 0)))
            elif self.func == 2:    adj_src.interpolate(dol.Constant((0, 1)))
            
            src1, src2 = dol.split(adj_src)
 
            Fadj = (dol.inner(self.z1trial - self.z1old + 0.5 * self.dt * (-self.z1trial - self.z1old + 2*src1), self.v1)*dol.dx +
                    dol.inner(self.z2trial - self.z2old + 0.5 * self.dt * ( self.z1trial + self.z1old + self.k*(self.z2trial + self.z2old) + 2*src2), self.v2)*dol.dx)
            prob_adj = dol.LinearVariationalProblem(dol.lhs(Fadj), dol.rhs(Fadj), self.znew)
            self.solver_adj = dol.LinearVariationalSolver(prob_adj)
示例#18
0
def ode_test_form(request):
    Model = eval(request.param)
    model = Model()
    mesh = df.UnitSquareMesh(10, 10)
    V = df.FunctionSpace(mesh, "CG", 1)
    S = state_space(mesh, model.num_states())
    Mx = df.MixedElement((V.ufl_element(), S.ufl_element()))
    VS = df.FunctionSpace(mesh, Mx)
    vs = df.Function(VS)
    vs.assign(df.project(model.initial_conditions(), VS))
    (v, s) = df.split(vs)
    (w, r) = df.TestFunctions(VS)
    rhs = df.inner(model.F(v, s), r) + df.inner(- model.I(v, s), w)
    form = rhs*df.dP
    return form
示例#19
0
    def _init_spaces(self):

        mesh = self.geometry.mesh

        V = dolfin.VectorElement("P", mesh.ufl_cell(), 2)
        Q = dolfin.FiniteElement("P", mesh.ufl_cell(), 1)
        R = dolfin.FiniteElement("Real", mesh.ufl_cell(), 0)

        el = dolfin.MixedElement([V, Q, R])
        self.state_space = dolfin.FunctionSpace(mesh, el)
        self.state = dolfin.Function(self.state_space)
        self.state_test = dolfin.TestFunction(self.state_space)

        self._Vu = get_cavity_volume_form(self.geometry.mesh,
                                          u=dolfin.split(self.state)[0],
                                          xshift=self.geometry.xshift)
        self._V0 = dolfin.Constant(self.geometry.cavity_volume())
示例#20
0
def create_mixed_space(mesh, k=1, augmentedTH=False, periodic_boundary=None):
    Pk = df.FiniteElement("CG", mesh.ufl_cell(), k)
    Pk1 = df.FiniteElement("CG", mesh.ufl_cell(), k + 1)

    FE_v = df.VectorElement(Pk1, dim=mesh.geometry().dim())
    FE_p = Pk
    if augmentedTH:
        # Use enriched element for p -> augmented TH, see Boffi et al. (2011)
        P0 = df.FiniteElement("DG", mesh.ufl_cell(), 0)
        gdim = mesh.geometry().dim()
        assert k >= gdim - 1  # see Boffi et al. (2011, Eq. (3.1))
        FE_p = df.EnrichedElement(Pk, P0)

    W = df.FunctionSpace(mesh,
                         df.MixedElement([FE_v, FE_p]),
                         constrained_domain=periodic_boundary)

    return W
示例#21
0
    def create_functions(self):
        """
        Create functions to hold solutions
        """
        sim = self.simulation

        # Function spaces
        Vu = sim.data['Vu']
        Vp = sim.data['Vp']
        cd = sim.data['constrained_domain']

        # Create coupled mixed function space and mixed function to hold results
        func_spaces = [Vu] * sim.ndim + [Vp]
        self.subspace_names = ['u%d' % d for d in range(sim.ndim)] + ['p']

        if self.use_lagrange_multiplicator:
            Vl = dolfin.FunctionSpace(sim.data['mesh'],
                                      "R",
                                      0,
                                      constrained_domain=cd)
            sim.data['l'] = dolfin.Function(Vl)
            func_spaces.append(Vl)
            self.subspace_names.append('l')

        e_mixed = dolfin.MixedElement([fs.ufl_element() for fs in func_spaces])
        Vcoupled = dolfin.FunctionSpace(sim.data['mesh'], e_mixed)
        sim.data['Vcoupled'] = Vcoupled
        sim.ndofs += Vcoupled.dim()

        Nspace = len(func_spaces)
        self.subspaces = [Vcoupled.sub(i) for i in range(Nspace)]
        sim.data['coupled'] = self.coupled_func = dolfin.Function(Vcoupled)
        self.assigner = dolfin.FunctionAssigner(func_spaces, Vcoupled)

        # Create segregated functions on component and vector form
        create_vector_functions(sim, 'u', 'u%d', Vu)
        create_vector_functions(sim, 'up', 'up%d', Vu)
        create_vector_functions(sim, 'upp', 'upp%d', Vu)
        create_vector_functions(sim, 'u_conv', 'u_conv%d', Vu)
        create_vector_functions(sim, 'up_conv', 'up_conv%d', Vu)
        create_vector_functions(sim, 'upp_conv', 'upp_conv%d', Vu)
        create_vector_functions(sim, 'u_unlim', 'u_unlim%d', Vu)
        sim.data['p'] = dolfin.Function(Vp)
        sim.data['ui_tmp'] = dolfin.Function(Vu)
示例#22
0
    def test_variable_kappa(self):
        frequency = 50
        omega = 2. * np.pi * frequency
        c1, c2 = [343.4, 6320 * 100]
        gamma = 8.4e-4

        kappa1 = omega / c1
        kappa2 = omega / c2

        Nx, Ny = 21, 21
        Lx, Ly = 1, 1

        #mesh = RectangleMesh(Point(0., 0.), Point(Lx, Ly), Nx, Ny)
        mesh = generate_mesh_with_cicular_subdomain(15, 0.25, False)
        degree = 1
        P1 = dl.FiniteElement('Lagrange', mesh.ufl_cell(), degree)
        element = dl.MixedElement([P1, P1])
        function_space = dl.FunctionSpace(mesh, element)

        boundary_conditions = None
        forcing = [
            ForcingVariableKappa(kappa1,
                                 kappa2,
                                 'real',
                                 degree=function_space.ufl_element().degree()),
            ForcingVariableKappa(kappa1,
                                 kappa2,
                                 'imag',
                                 degree=function_space.ufl_element().degree())
        ]
        kappa = dl.Expression('x[1] <= 0.5 + tol ? k_0 : k_1',
                              degree=0,
                              tol=1e-14,
                              k_0=kappa1,
                              k_1=kappa2)
        # use mesh with circular subdomain as this should not effect result
        # significantly but will test if subdomain mesh works correctly
        p = run_model(kappa, forcing, function_space, boundary_conditions)
        error = dl.errornorm(
            ExactSolution(kappa, element=function_space.ufl_element()), p)
        print('Error', error)
        assert error <= 3e-2
示例#23
0
    def create_functions(self):
        """
        Create functions to hold solutions
        """
        sim = self.simulation

        # Function spaces
        Vu = sim.data['Vu']
        Vp = sim.data['Vp']

        # Create velocity functions on component and vector form
        create_vector_functions(sim, 'u', 'u%d', Vu)
        create_vector_functions(sim, 'up', 'up%d', Vu)
        create_vector_functions(sim, 'upp', 'upp%d', Vu)
        create_vector_functions(sim, 'u_conv', 'u_conv%d', Vu)
        create_vector_functions(sim, 'up_conv', 'up_conv%d', Vu)
        create_vector_functions(sim, 'upp_conv', 'upp_conv%d', Vu)
        create_vector_functions(sim, 'u_unlim', 'u_unlim%d', Vu)
        sim.data['ui_tmp'] = dolfin.Function(Vu)

        # Create coupled vector function
        ue = Vu.ufl_element()
        e_mixed = dolfin.MixedElement([ue] * sim.ndim)
        Vcoupled = dolfin.FunctionSpace(Vu.mesh(), e_mixed)
        sim.data['uvw_star'] = dolfin.Function(Vcoupled)
        sim.data['uvw_temp'] = dolfin.Function(Vcoupled)
        sim.ndofs += Vcoupled.dim() + Vp.dim()

        # Create assigner to extract split function from uvw and vice versa
        self.assigner_split = dolfin.FunctionAssigner([Vu] * sim.ndim,
                                                      Vcoupled)
        self.assigner_merge = dolfin.FunctionAssigner(Vcoupled,
                                                      [Vu] * sim.ndim)

        # Create pressure function
        sim.data['p'] = dolfin.Function(Vp)
        sim.data['p_hat'] = dolfin.Function(Vp)
示例#24
0
    def __init__(
            self,
            energy,
            state,
            bcs,
            # rayleigh=None,
            Hessian=None,
            nullspace=None,
            parameters=None):
        """Solves second order stability problem
            - computes inertia
            - solves full eigenvalue problem

            * Parameters:
                - energy (form)
                - state (tuple)
                - bcs (list)

            Optional arguments: rayleigh (form), Hessian (form), 
            nullspace, parameters
        """
        OptDB = PETSc.Options()
        OptDB.view()

        self.i = 0

        self.u = state['u']
        self.alpha = state['alpha']
        self._u = dolfin.Vector(self.u.vector())
        self._alpha = dolfin.Vector(self.alpha.vector())
        self.mesh = state['alpha'].function_space().mesh()

        self.Z = dolfin.FunctionSpace(
            self.mesh,
            dolfin.MixedElement(
                [self.u.ufl_element(),
                 self.alpha.ufl_element()]))
        self.z = dolfin.Function(self.Z)
        self.z_old = dolfin.Function(self.Z)
        zeta = dolfin.TestFunction(self.Z)
        v, beta = dolfin.split(zeta)

        self.dm = self.Z.dofmap()
        self.ownership = self.Z.dofmap().ownership_range()

        Zu = self.Z.extract_sub_space([0])
        Za = self.Z.extract_sub_space([1])

        self.Xa = Za.collapse().tabulate_dof_coordinates()
        self.Xu = Zu.collapse().tabulate_dof_coordinates()

        (_, self.mapa) = Za.collapse(collapsed_dofs=True)
        (_, self.mapu) = Zu.collapse(collapsed_dofs=True)

        self.assigner = dolfin.FunctionAssigner(
            self.Z,  # receiving space
            [self.u.function_space(),
             self.alpha.function_space()])  # assigning spaces

        self.parameters = self.setParameters(parameters)

        self.ownership = self.Z.dofmap().ownership_range()

        self.assigner = dolfin.FunctionAssigner(
            self.Z,  # receiving space
            [self.u.function_space(),
             self.alpha.function_space()])  # assigning space

        dim = self.u.function_space().ufl_element().value_size()

        self.stable = ''
        self.negev = -1
        self.mineig = 1.

        self.Ealpha = derivative(
            energy, self.alpha,
            dolfin.TestFunction(self.alpha.ufl_function_space()))
        self.energy = energy

        (z_u, z_a) = dolfin.split(self.z)
        energy = ufl.replace(energy, {self.u: z_u, self.alpha: z_a})
        self.J = derivative(energy, self.z, dolfin.TestFunction(self.Z))
        self.H = derivative(self.J, self.z, dolfin.TrialFunction(self.Z))

        self.nullspace = nullspace

        if Hessian:
            self.Hessian = Hessian

        self.ownership_range = self.Z.dofmap().ownership_range()
        if len(bcs) > 0:
            self.bcs = bcs
            self.bc_dofs = self.get_bc_dofs(bcs)
        else:
            self.bcs = None
            self.bc_dofs = set()

        self.perturbation_v = dolfin.Function(self.Z.sub(0).collapse())
        self.perturbation_beta = dolfin.Function(self.Z.sub(1).collapse())

        self._Hessian = Hessian if Hessian.__class__ == ufl.form.Form else self.H
示例#25
0
def comp_axisymmetric_pure_neumann(mat_obj, mesh_obj, bc, omega, save_path):
    E = mat_obj.E
    rho = mat_obj.rho
    nu = mat_obj.nu

    mesh = mesh_obj.create()
    Rext = mesh_obj.Rext
    Rint = mesh_obj.Rint

    # rename x[0], x[1] by x, y
    x, y = df.SpatialCoordinate(mesh)

    dim = mesh.topology().dim()

    cell_markers = df.MeshFunction("size_t", mesh, dim)
    facet_markers = df.MeshFunction("size_t", mesh, dim - 1)

    coord = mesh.coordinates()

    class OuterRadius(df.SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and x[0]**2 + x[1]**2 >= Rext**2 - 1e-3

    class InnerRadius(df.SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and x[0]**2 + x[1]**2 <= Rint**2 + 1e-3

    OuterRadius().mark(facet_markers, 1)
    InnerRadius().mark(facet_markers, 2)

    df.File(save_path + 'cell_markers.pvd') << cell_markers
    df.File(save_path + 'facet_markers.pvd') << facet_markers

    # Create mesh and define function space
    V = df.FunctionSpace(mesh, "CG", 1)
    # =========================== Define Finite Element ===========================
    degree = 1  #P1 table of periodic
    # CG: Continuous Galerkin
    V_ele = df.FiniteElement("CG", mesh.ufl_cell(), degree)  # scalar, Ex: u
    R_ele = df.FiniteElement("R", mesh.ufl_cell(), 0)  # scalar, Ex: u
    # Vector element # akternative : manually define vector function : better for 3D adaptation than above
    total_ele = df.MixedElement([V_ele, R_ele])
    W = df.FunctionSpace(mesh, total_ele)

    # Define trial function
    dunks = df.TrialFunction(W)
    (du, dc) = df.split(dunks)

    # Define variational problem
    tunks = df.TestFunction(W)
    (tu, tc) = df.split(tunks)

    # displacement in radial direction u(x,y)
    unks = df.Function(W)

    #(u, c) = df.split(unks)

    class THETA(df.UserExpression):
        def eval(self, values, x):
            values[0] = math.atan2(x[1], x[0])

        def value_shape(self):
            #return (1,) # vector
            return ()  # scalar

    theta = THETA(degree=1)

    #theta_int = df.interpolate(theta, df.FunctionSpace(mesh, "DG", 0))
    #df.File(save_path + 'theta.pvd') << theta_int

    class RADIUS(df.UserExpression):
        def eval(self, values, x):
            values[0] = df.sqrt(x[0] * x[0] + x[1] * x[1])

        def value_shape(self):
            return ()  # scalar

    r = RADIUS(degree=1)

    # strain radial
    def epsilon_r(du):
        return 1.0 / r * (x * df.Dx(du, 0) + y * df.Dx(du, 1))

    # strain circumferential
    def epsilon_theta(du):
        return du / df.sqrt(x**2 + y**2)

    # radial stress # train-stress relation
    def sigma_r(du):
        return E / (1.0 - nu**2) * (epsilon_r(du) + nu * epsilon_theta(du))

    # circumferential stress
    def sigma_theta(du):
        return E / (1.0 - nu**2) * (nu * epsilon_r(du) + epsilon_theta(du))

    # Weak form
    dFu = r * sigma_r(du) * epsilon_r(tu) * df.dx(0)
    dFu = dFu + sigma_theta(du) * tu * df.dx(0)
    dFu = dFu + dc * tu * df.dx(0)
    dFu = dFu - rho * omega**2 * r**2 * tu * df.dx(0)
    dFc = du * tc * df.dx(1)

    dFu = r * sigma_r(du) * epsilon_r(tu) * df.dx
    dFu = dFu + sigma_theta(du) * tu * df.dx
    dFu = dFu + dc * tu * df.dx
    dFu = dFu - rho * omega**2 * r**2 * tu * df.dx
    dFc = du * tc * df.dx

    dF = dFu + dFc

    # residual
    #F = df.action(dF, unks)

    a = df.lhs(dF)
    L = df.rhs(dF)

    df.solve(a == L, unks)

    (_u, _c) = unks.split(True)

    u_pro = df.project(_u, V)
    u_pro.rename('dis u [m]', 'dis u [m]')

    # displacement
    df.File(save_path + 'displacement.pvd') << u_pro

    # compute stresses
    sigma_r_pro = df.project(sigma_r(_u), V)
    sigma_r_pro.rename('sigma_r [Pa]', 'sigma_r [Pa]')
    df.File(save_path + 'sigma_r.pvd') << sigma_r_pro

    sigma_theta_pro = df.project(sigma_theta(_u), V)
    sigma_theta_pro.rename('sigma_theta [Pa]', 'sigma_theta [Pa]')
    df.File(save_path + 'sigma_theta.pvd') << sigma_theta_pro

    # compute von Mises stress
    def von_mises_stress(sigma_r, sigma_theta):
        return df.sqrt(sigma_r**2 + sigma_theta**2 - sigma_r * sigma_theta)

    von_stress_pro = df.project(von_mises_stress(sigma_r(_u), sigma_theta(_u)),
                                V)
    von_stress_pro.rename('von Mises Stress [Pa]', 'von Mises Stress [Pa]')
    df.File(save_path + 'von_mises_stress.pvd') << von_stress_pro
示例#26
0
'''
# name = 'density', function = density_function (function is the solution vector here)
density_function_space = df.FunctionSpace(mesh, 'DG', 0)
density_function = df.Function(density_function_space)
pde_problem.add_input('density', density_function)
'''
4. 2. Add states
'''
# Define mixed function space-split into temperature and displacement FS
d = mesh.geometry().dim()
cell = mesh.ufl_cell()
displacement_fe = df.VectorElement("CG", cell, 1)
temperature_fe = df.FiniteElement("CG", cell, 1)

mixed_fs = df.FunctionSpace(mesh,
                            df.MixedElement([displacement_fe, temperature_fe]))
mixed_fs.sub(1).dofmap().dofs()
mixed_function = df.Function(mixed_fs)
displacements_function, temperature_function = df.split(mixed_function)
# displacements_function,temperature_function = mixed_function.split()

v, T_hat = df.TestFunctions(mixed_fs)

residual_form = get_residual_form(displacements_function, v, density_function,
                                  temperature_function, T_hat, KAPPA, K, ALPHA)

residual_form -=  (df.dot(f_r, v) * dss(10) + df.dot(f_t, v) * dss(14)  + \
                    q*T_hat*dss(5) + q_half*T_hat*dss(6) + q_quart*T_hat*dss(7))
print("get residual_form-------")
# print('ssssssss',df.assemble(T_hat*df.dx).get_local())
pde_problem.add_state('mixed_states', mixed_function, residual_form, 'density')
示例#27
0
# Declare finite elements
elements = dict()
for name, (family, degree, is_vector) in base_elements.items():
    if is_vector:
        elements[name] = df.VectorElement(family, mesh.ufl_cell(), degree)
    else:
        elements[name] = df.FiniteElement(family, mesh.ufl_cell(), degree)

# Declare function spaces
spaces = dict()
for name, subproblem in subproblems.items():
    if len(subproblem) > 1:
        spaces[name] = df.FunctionSpace(
            mesh,
            df.MixedElement([elements[s["element"]] for s in subproblem]),
            constrained_domain=constrained_domain(**vars()))
    # If there is only one field in the subproblem, don't bother with
    # the MixedElement.
    elif len(subproblem) == 1:
        spaces[name] = df.FunctionSpace(
            mesh,
            elements[subproblem[0]["element"]],
            constrained_domain=constrained_domain(**vars()))
    else:
        info_on_red("Something went wrong here!")
        exit("")

# dim = mesh.topology().dim()  # In case the velocity fields should be
#                              # segregated at some point
fields = []
示例#28
0
    def __init__(self, fenics_2d_rve, **kwargs):
        """[summary]

        Parameters
        ----------
        object : [type]
            [description]
        fenics_2d_rve : [type]
            [description]
        element : tuple or dict
            Type and degree of element for displacement FunctionSpace
            Ex: ('CG', 2) or {'family':'Lagrange', degree:2}
        solver : dict
            Choose the type of the solver, its method and the preconditioner.
            An up-to-date list of the available solvers and preconditioners
            can be obtained with dolfin.list_linear_solver_methods() and
            dolfin.list_krylov_solver_preconditioners().

        """
        self.rve = fenics_2d_rve
        self.topo_dim = topo_dim = fenics_2d_rve.dim
        try:
            bottom_left_corner = fenics_2d_rve.bottom_left_corner
        except AttributeError:
            logger.warning(
                "For the definition of the periodicity boundary conditions,"
                "the bottom left corner of the RVE is assumed to be on (0.,0.)"
            )
            bottom_left_corner = np.zeros(shape=(topo_dim, ))
        self.pbc = periodicity.PeriodicDomain.pbc_dual_base(
            fenics_2d_rve.gen_vect, "XY", bottom_left_corner, topo_dim)

        solver = kwargs.pop("solver", {})
        # {'type': solver_type, 'method': solver_method, 'preconditioner': preconditioner}
        s_type = solver.pop("type", None)
        s_method = solver.pop("method", SOLVER_METHOD)
        s_precond = solver.pop("preconditioner", None)
        if s_type is None:
            if s_method in DOLFIN_KRYLOV_METHODS.keys():
                s_type = "Krylov"
            elif s_method in DOLFIN_LU_METHODS.keys():
                s_type = "LU"
            else:
                raise RuntimeError("The indicated solver method is unknown.")
        self._solver = dict(type=s_type, method=s_method)
        if s_precond:
            self._solver["preconditioner"] = s_precond

        element = kwargs.pop("element", ("Lagrange", 2))
        if isinstance(element, dict):
            element = (element["family"], element["degree"])
        self._element = element

        # * Function spaces
        cell = self.rve.mesh.ufl_cell()
        self.scalar_FE = fe.FiniteElement(element[0], cell, element[1])
        self.displ_FE = fe.VectorElement(element[0], cell, element[1])
        strain_deg = element[1] - 1 if element[1] >= 1 else 0
        strain_dim = int(topo_dim * (topo_dim + 1) / 2)
        self.strain_FE = fe.VectorElement("DG",
                                          cell,
                                          strain_deg,
                                          dim=strain_dim)
        # Espace fonctionel scalaire
        self.X = fe.FunctionSpace(self.rve.mesh,
                                  self.scalar_FE,
                                  constrained_domain=self.pbc)
        # Espace fonctionnel 3D : deformations, notations de Voigt
        self.W = fe.FunctionSpace(self.rve.mesh, self.strain_FE)
        # Espace fonctionel 2D pour les champs de deplacement
        # TODO : reprendre le Ve défini pour l'espace fonctionnel mixte. Par ex: V = FunctionSpace(mesh, Ve)
        self.V = fe.VectorFunctionSpace(self.rve.mesh,
                                        element[0],
                                        element[1],
                                        constrained_domain=self.pbc)

        # * Espace fonctionel mixte pour la résolution :
        # * 2D pour les champs + scalaire pour multiplicateur de Lagrange

        # "R" : Real element with one global degree of freedom
        self.real_FE = fe.VectorElement("R", cell, 0)
        self.M = fe.FunctionSpace(
            self.rve.mesh,
            fe.MixedElement([self.displ_FE, self.real_FE]),
            constrained_domain=self.pbc,
        )

        # Define variational problem
        self.v, self.lamb_ = fe.TestFunctions(self.M)
        self.u, self.lamb = fe.TrialFunctions(self.M)
        self.w = fe.Function(self.M)

        # bilinear form
        self.a = (
            fe.inner(sigma(self.rve.C_per, epsilon(self.u)), epsilon(self.v)) *
            fe.dx + fe.dot(self.lamb_, self.u) * fe.dx +
            fe.dot(self.lamb, self.v) * fe.dx)
        self.K = fe.assemble(self.a)
        if self._solver["type"] == "Krylov":
            self.solver = fe.KrylovSolver(self.K, self._solver["method"])
        elif self._solver["type"] == "LU":
            self.solver = fe.LUSolver(self.K, self._solver["method"])
            self.solver.parameters["symmetric"] = True
        try:
            self.solver.parameters.preconditioner = self._solver[
                "preconditioner"]
        except KeyError:
            pass
        # fe.info(self.solver.parameters, True)

        self.localization = dict()
        # dictionary of localization field objects,
        # will be filled up when calling auxiliary problems (lazy evaluation)
        self.ConstitutiveTensors = dict()
示例#29
0
    def __init__(self,
                 mesh: df.Mesh,
                 time: df.Constant,
                 M_i: tp.Union[df.Expression, tp.Dict[int, df.Expression]],
                 M_e: tp.Union[df.Expression, tp.Dict[int, df.Expression]],
                 I_s: tp.Union[df.Expression, tp.Dict[int,
                                                      df.Expression]] = None,
                 I_a: tp.Union[df.Expression, tp.Dict[int,
                                                      df.Expression]] = None,
                 ect_current: tp.Dict[int, df.Expression] = None,
                 v_: df.Function = None,
                 cell_domains: df.MeshFunction = None,
                 facet_domains: df.MeshFunction = None,
                 dirichlet_bc: tp.List[tp.Tuple[df.Expression, int]] = None,
                 dirichlet_bc_v: tp.List[tp.Tuple[df.Expression, int]] = None,
                 periodic_domain: df.SubDomain = None,
                 parameters: df.Parameters = None) -> None:
        """Initialise solverand check all parametersare correct.

        NB! The periodic domain has to be set in the cellsolver too.
        """
        self._timestep = None

        comm = df.MPI.comm_world
        rank = df.MPI.rank(comm)

        msg = "Expecting mesh to be a Mesh instance, not {}".format(mesh)
        assert isinstance(mesh, df.Mesh), msg

        msg = "Expecting time to be a Constant instance (or None)."
        assert isinstance(time, df.Constant) or time is None, msg

        msg = "Expecting parameters to be a Parameters instance (or None)"
        assert isinstance(parameters, df.Parameters) or parameters is None, msg

        self._nullspace_basis = None

        # Store input
        self._mesh = mesh
        self._time = time

        # Initialize and update parameters if given
        self._parameters = self.default_parameters()
        if parameters is not None:
            self._parameters.update(parameters)

        if self._parameters["Chi"] == -1 or self._parameters["Cm"] == -1:
            raise ValueError(
                "Need Chi and Cm to be specified explicitly throug the parameters."
            )

        # Set-up function spaces
        k = self._parameters["polynomial_degree"]
        Ve = df.FiniteElement("CG", self._mesh.ufl_cell(), k)
        V = df.FunctionSpace(self._mesh,
                             "CG",
                             k,
                             constrained_domain=periodic_domain)
        Ue = df.FiniteElement("CG", self._mesh.ufl_cell(), k)

        if self._parameters["linear_solver_type"] == "direct":
            Re = df.FiniteElement("R", self._mesh.ufl_cell(), 0)
            _element = df.MixedElement((Ve, Ue, Re))
            self.VUR = df.FunctionSpace(mesh,
                                        _element,
                                        constrained_domain=periodic_domain)
        else:
            _element = df.MixedElement((Ve, Ue))
            self.VUR = df.FunctionSpace(mesh,
                                        _element,
                                        constrained_domain=periodic_domain)

        self.V = V

        if cell_domains is None:
            cell_domains = df.MeshFunction("size_t", mesh,
                                           self._mesh.geometry().dim())
            cell_domains.set_all(0)

        # Chech that it is indeed a cell function.
        cell_dim = cell_domains.dim()
        mesh_dim = self._mesh.geometry().dim()
        msg = "Got {cell_dim}, expected {mesh_dim}.".format(cell_dim=cell_dim,
                                                            mesh_dim=mesh_dim)
        assert cell_dim == mesh_dim, msg
        self._cell_domains = cell_domains

        if facet_domains is None:
            facet_domains = df.MeshFunction("size_t", mesh,
                                            self._mesh.geometry().dim() - 1)
            facet_domains.set_all(0)

        # Check that it is indeed a facet function.
        facet_dim = facet_domains.dim()
        msg = "Got {facet_dim}, expected {mesh_dim}.".format(
            facet_dim=facet_dim, mesh_dim=mesh_dim - 1)
        assert facet_dim == mesh_dim - 1, msg
        self._facet_domains = facet_domains

        # Gather all cell keys on all processes. Greatly simplifies things
        cell_keys = set(self._cell_domains.array())
        all_cell_keys = comm.allgather(cell_keys)
        all_cell_keys = reduce(or_, all_cell_keys)

        # If Mi is not dict, make dict
        if not isinstance(M_i, dict):
            M_i = {int(i): M_i for i in all_cell_keys}
        else:  # Check that the keys match the cell function
            M_i_keys = set(M_i.keys())
            msg = "Got {M_i_keys}, expected {cell_keys}.".format(
                M_i_keys=M_i_keys, cell_keys=all_cell_keys)
            assert M_i_keys == all_cell_keys, msg

        # If Me is not dict, make dict
        if not isinstance(M_e, dict):
            M_e = {int(i): M_e for i in all_cell_keys}
        else:  # Check that the keys match the cell function
            M_e_keys = set(M_e.keys())
            msg = "Got {M_e_keys}, expected {cell_keys}.".format(
                M_e_keys=M_e_keys, cell_keys=all_cell_keys)
            assert M_e_keys == all_cell_keys, msg
        self._M_i = M_i
        self._M_e = M_e

        # Store source terms
        if I_s is not None and not isinstance(I_s, dict):
            I_s = {key: I_s for key in all_cell_keys}
        self._I_s = I_s

        if I_a is not None and not isinstance(I_a, dict):
            I_a = {key: I_a for key in all_cell_keys}
        self._I_a = I_a

        # Set the ECT current, Note, it myst depend on `time` to be updated
        if ect_current is not None:
            ect_tags = set(ect_current.keys())
            facet_tags = set(self._facet_domains.array())
            msg = "{} not in facet domains ({}).".format(ect_tags, facet_tags)
            assert ect_tags <= facet_tags, msg
        self._ect_current = ect_current

        # Set-up solution fields:
        if v_ is None:
            self.merger = df.FunctionAssigner(V, self.VUR.sub(0))
            self.v_ = df.Function(V, name="v_")
        else:
            # df.debug("Experimental: v_ shipped from elsewhere.")
            self.merger = None
            self.v_ = v_
        self.vur = df.Function(self.VUR, name="vur")

        # Set Dirichlet bcs for the transmembrane potential
        self._bcs = []
        if dirichlet_bc_v is not None:
            for function, marker in dirichlet_bc_v:
                self._bcs.append(
                    df.DirichletBC(self.VUR.sub(0), function,
                                   self._facet_domains, marker))

        # Set Dirichlet bcs for the extra cellular potential
        if dirichlet_bc is not None:
            for function, marker in dirichlet_bc:
                self._bcs.append(
                    df.DirichletBC(self.VUR.sub(1), function,
                                   self._facet_domains, marker))
def traction_test(ell=0.05,
                  ell_e=.1,
                  degree=1,
                  n=3,
                  nu=0.,
                  load_min=0,
                  load_max=2,
                  loads=None,
                  nsteps=20,
                  Lx=1.,
                  Ly=0.1,
                  outdir="outdir",
                  postfix='',
                  savelag=1,
                  sigma_D0=1.,
                  periodic=False,
                  continuation=False,
                  checkstability=True,
                  configString='',
                  test=True):
    # constants
    # ell = ell
    Lx = Lx
    load_min = load_min
    load_max = load_max
    nsteps = nsteps
    outdir = outdir
    loads = loads

    savelag = 1
    nu = dolfin.Constant(nu)
    ell = dolfin.Constant(ell)
    ell_e = ell_e
    E = dolfin.Constant(1.0)
    K = E.values()[0] / ell_e**2.
    sigma_D0 = E
    n = n
    # h = ell.values()[0]/n
    h = max(ell.values()[0] / n, .005)
    cell_size = h
    continuation = continuation
    isPeriodic = periodic
    config = json.loads(configString) if configString != '' else ''

    cmd_parameters = {
        'material': {
            "ell": ell.values()[0],
            "ell_e": ell_e,
            "K": K,
            "E": E.values()[0],
            "nu": nu.values()[0],
            "sigma_D0": sigma_D0.values()[0]
        },
        'geometry': {
            'Lx': Lx,
            'Ly': Ly,
            'n': n,
        },
        'experiment': {
            'test': test,
            'periodic': isPeriodic,
            'signature': ''
        },
        'stability': {
            'checkstability': checkstability,
            'continuation': continuation
        },
        'time_stepping': {
            'load_min': load_min,
            'load_max': load_max,
            'nsteps': nsteps,
            'outdir': outdir,
            'postfix': postfix,
            'savelag': savelag
        },
        'alt_min': {},
        "code": {}
    }

    # --------------------

    for par in parameters:
        parameters[par].update(cmd_parameters[par])

    if config:
        for par in config:
            parameters[par].update(config[par])
    # else:

    # parameters['material']['ell_e'] =

    Lx = parameters['geometry']['Lx']
    Ly = parameters['geometry']['Ly']
    ell = parameters['material']['ell']
    ell_e = parameters['material']['ell_e']

    BASE_DIR = os.path.dirname(os.path.realpath(__file__))
    fname = "film"
    print(BASE_DIR)
    os.path.isfile(fname)

    signature = hashlib.md5(str(parameters).encode('utf-8')).hexdigest()

    if parameters['experiment']['test'] == True:
        outdir += '-{}'.format(cmd_parameters['time_stepping']['postfix'])
    else:
        outdir += '-{}{}'.format(signature,
                                 cmd_parameters['time_stepping']['postfix'])
    outdir = outdir + '-cont'
    parameters['time_stepping']['outdir'] = outdir
    Path(outdir).mkdir(parents=True, exist_ok=True)
    print('Outdir is: ' + outdir)

    with open(os.path.join(outdir, 'rerun.sh'), 'w') as f:
        configuration = deepcopy(parameters)
        configuration['time_stepping'].pop('outdir')
        str(configuration).replace("\'True\'",
                                   "True").replace("\'False\'", "False")
        rerun_cmd = 'python3 {} --config="{}"'.format(
            os.path.basename(__file__), configuration)
        f.write(rerun_cmd)

    with open(os.path.join(outdir, 'parameters.pkl'), 'w') as f:
        json.dump(parameters, f)

    with open(os.path.join(outdir, 'signature.md5'), 'w') as f:
        f.write(signature)
    print(parameters)

    # boundary_meshfunction = dolfin.MeshFunction("size_t", mesh, "meshes/%s-%s_facet_region.xml"%(fname, signature))
    # cells_meshfunction = dolfin.MeshFunction("size_t", mesh, "meshes/%s-%s_physical_region.xml"%(fname, signature))

    # ------------------
    geometry_parameters = parameters['geometry']

    geom_signature = hashlib.md5(
        str(geometry_parameters).encode('utf-8')).hexdigest()
    meshfile = "%s/meshes/%s-%s.xml" % (BASE_DIR, fname, geom_signature)
    # cmd_parameters['experiment']['signature']=signature

    if os.path.isfile(meshfile):
        print("Meshfile %s exists" % meshfile)
        mesh = dolfin.Mesh("meshes/%s-%s.xml" % (fname, geom_signature))
    else:
        print("Creating meshfile: %s" % meshfile)
        print(('DEBUG: (-Lx/2. ={} , -Ly/2.={})'.format(Lx / 2., -Ly / 2.)))
        geom = mshr.Rectangle(dolfin.Point(-Lx / 2., -Ly / 2.),
                              dolfin.Point(Lx / 2., Ly / 2.))
        mesh = mshr.generate_mesh(geom, n * int(float(Lx / ell)))
    print(meshfile)

    mesh_xdmf = dolfin.XDMFFile("meshes/%s-%s.xdmf" % (fname, geom_signature))
    mesh_xdmf.write(mesh)
    if rank == 0:
        meshf = dolfin.File(os.path.join(outdir, "mesh.xml"))
        meshf << mesh

    V_u = dolfin.VectorFunctionSpace(mesh, "CG", 1)
    V_alpha = dolfin.FunctionSpace(mesh, "CG", 1)
    u = dolfin.Function(V_u, name="Total displacement")
    alpha = dolfin.Function(V_alpha, name="Damage")

    bcs_alpha = []
    bcs_u = [
        DirichletBC(V_u, Constant((0., 0)),
                    '(near(x[0], %f) or near(x[0], %f))' % (-Lx / 2., Lx / 2.))
    ]

    left = dolfin.CompiledSubDomain("near(x[0], -Lx/2.)", Lx=Lx)
    right = dolfin.CompiledSubDomain("near(x[0], Lx/2.)", Lx=Lx)
    bottom = dolfin.CompiledSubDomain("near(x[1],-Ly/2.)", Ly=Ly)
    top = dolfin.CompiledSubDomain("near(x[1],Ly/2.)", Ly=Ly)

    mf = dolfin.MeshFunction("size_t", mesh, 1, 0)
    right.mark(mf, 1)
    left.mark(mf, 2)
    bottom.mark(mf, 3)

    state = [u, alpha]

    Z = dolfin.FunctionSpace(
        mesh, dolfin.MixedElement([u.ufl_element(),
                                   alpha.ufl_element()]))
    z = dolfin.Function(Z)

    v, beta = dolfin.split(z)
    dx = dolfin.Measure("dx", metadata=form_compiler_parameters, domain=mesh)
    ds = dolfin.Measure("ds", subdomain_data=mf)

    # Files for output
    file_out = dolfin.XDMFFile(os.path.join(outdir, "output.xdmf"))
    file_eig = dolfin.XDMFFile(os.path.join(outdir, "perturbations.xdmf"))
    file_con = dolfin.XDMFFile(os.path.join(outdir, "continuation.xdmf"))
    file_bif = dolfin.XDMFFile(
        os.path.join(outdir, "bifurcation_postproc.xdmf"))

    for f in [file_out, file_eig, file_con, file_bif]:
        f.parameters["functions_share_mesh"] = True
        f.parameters["flush_output"] = True

    # Problem definition

    foundation_density = 1. / 2. * 1. / ell_e**2. * dot(u, u)
    model = DamagePrestrainedElasticityModel(
        state,
        E,
        nu,
        ell,
        sigma_D0,
        user_functional=foundation_density,
        eps0t=Expression([['t', 0.], [0., 0.]], t=0., degree=0))
    # import pdb; .set_trace()
    model.dx = dx
    model.ds = ds
    energy = model.total_energy_density(u, alpha) * dx
    # Alternate minimization solver
    solver = solvers.AlternateMinimizationSolver(
        energy, [u, alpha], [bcs_u, bcs_alpha],
        parameters=parameters['alt_min'])

    rP = model.rP(u, alpha, v, beta) * dx + 1 / ell_e**2. * dot(v, v) * dx
    rN = model.rN(u, alpha, beta) * dx

    stability = StabilitySolver(mesh,
                                energy, [u, alpha], [bcs_u, bcs_alpha],
                                z,
                                parameters=parameters['stability'])
    # stability = StabilitySolver(mesh, energy, [u, alpha], [bcs_u, bcs_alpha], z, parameters = parameters['stability'], rayleigh=[rP, rN])

    # if isPeriodic:
    #     stability = StabilitySolver(mesh, energy, [u, alpha], [bcs_u, bcs_alpha], z,
    #         parameters = stability_parameters,
    #         constrained_domain = PeriodicBoundary(Lx))
    # else:
    #     stability = StabilitySolver(mesh, energy, [u, alpha], [bcs_u, bcs_alpha], z, parameters = parameters['stability'])

    load_steps = np.linspace(load_min, load_max,
                             parameters['time_stepping']['nsteps'])
    if loads:
        load_steps = loads

    time_data = []

    linesearch = LineSearch(energy, [u, alpha])
    alpha_old = dolfin.Function(alpha.function_space())
    lmbda_min_prev = 0.000001
    bifurcated = False
    bifurcation_loads = []
    save_current_bifurcation = False
    bifurc_count = 0
    alpha_bif = dolfin.Function(V_alpha)
    alpha_bif_old = dolfin.Function(V_alpha)
    bifurcation_loads = []

    tot_energy = model.elastic_energy_density(model.eps(u), alpha)*dx + \
            1./2.*1/ell_e**2. * dot(u, u)*dx             + \
            model.damage_dissipation_density(alpha)*dx
    cont_atol = 1e-3

    for it, load in enumerate(load_steps):
        model.eps0t.t = load
        alpha_old.assign(alpha)
        ColorPrint.print_warn('Solving load t = {:.2f}'.format(load))

        # First order stability conditions
        (time_data_i, am_iter) = solver.solve()

        # Second order stability conditions
        (stable, negev) = stability.solve(solver.problem_alpha.lb)
        ColorPrint.print_pass(
            'Current state is{}stable'.format(' ' if stable else ' un'))
        # import pdb; pdb.set_trace()

        mineig = stability.mineig if hasattr(stability, 'mineig') else 0.0
        # print('DEBUG: lmbda min', lmbda_min_prev)
        # print('DEBUG: mineig', mineig)
        Deltav = (mineig - lmbda_min_prev) if hasattr(stability, 'eigs') else 0

        if (mineig + Deltav) * (lmbda_min_prev +
                                dolfin.DOLFIN_EPS) < 0 and not bifurcated:
            bifurcated = True
            # save 3 bif modes
            print('DEBUG: About to bifurcate load ', load, 'step', it)
            bifurcation_loads.append(load)
            bifurc_count += 1

        lmbda_min_prev = mineig if hasattr(stability, 'mineig') else 0.
        if stable:
            solver.update()
        else:
            # Continuation
            iteration = 1
            energy_pre = dolfin.assemble(tot_energy)
            alpha_bif.assign(alpha)
            alpha_bif_old.assign(alpha_old)

            while stable == False and iteration < 30:
                # linesearch
                perturbation_v = stability.perturbation_v
                perturbation_beta = stability.perturbation_beta

                h_opt, (hmin, hmax), energy_perturbations = linesearch.search(
                    [u, alpha, alpha_old], perturbation_v, perturbation_beta)

                # import pdb; pdb.set_trace()
                # if h_opt != 0:
                if h_opt > cont_atol:

                    save_current_bifurcation = True

                    # admissible
                    uval = u.vector()[:] + h_opt * perturbation_v.vector()[:]
                    aval = alpha.vector(
                    )[:] + h_opt * perturbation_beta.vector()[:]

                    u.vector()[:] = uval
                    alpha.vector()[:] = aval

                    u.vector().vec().ghostUpdate()
                    alpha.vector().vec().ghostUpdate()

                    (time_data_i, am_iter) = solver.solve()
                    (stable, negev) = stability.solve(alpha_old)
                    ColorPrint.print_pass(
                        '    Continuation iteration #{}, current state is{}stable'
                        .format(iteration, ' ' if stable else ' un'))
                    energy_post = dolfin.assemble(tot_energy)
                    ener_diff = energy_post - energy_pre
                    ColorPrint.print_warn(
                        'DEBUG: step {}, iteration {}, En_post - En_pre ={}'.
                        format(it, iteration, energy_post - energy_pre))

                    iteration += 1
                    if ener_diff < 0: bifurcated = False
                else:
                    # warn
                    ColorPrint.print_warn(
                        'DEBUG: Found (almost) zero increment, we are stuck in the matrix'
                    )
                    ColorPrint.print_warn('DEBUG:   h_opt = {}'.format(h_opt))
                    ColorPrint.print_warn('DEBUG: Continuing load program')
                    break

            solver.update()
            # stable == True
            # modes = np.where(stability.eigs < 0)[0]
            # with file_bif as file:
            #     leneigs = len(modes)
            #     maxmodes = min(3, leneigs)
            #     for n in range(maxmodes):
            #         mode = dolfin.project(stability.linsearch[n]['beta_n'], V_alpha)
            #         modename = 'beta-%d'%n
            #         print(modename)
            #         file.write_checkpoint(mode, modename, 0, append=True)

            # bifurc_count += 1
        time_data_i["load"] = load
        time_data_i["stable"] = stable
        time_data_i["dissipated_energy"] = dolfin.assemble(
            model.damage_dissipation_density(alpha) * dx)
        time_data_i["foundation_energy"] = dolfin.assemble(
            1. / 2. * 1 / ell_e**2. * dot(u, u) * dx)
        time_data_i["membrane_energy"] = dolfin.assemble(
            model.elastic_energy_density(model.eps(u), alpha) * dx)
        time_data_i["elastic_energy"] = time_data_i[
            "membrane_energy"] + time_data_i["foundation_energy"]
        time_data_i["eigs"] = stability.eigs if hasattr(stability,
                                                        'eigs') else np.inf
        time_data_i["stable"] = stability.stable
        time_data_i["# neg ev"] = stability.negev
        # import pdb; pdb.set_trace()

        _sigma = model.stress(model.eps(u), alpha)
        e1 = dolfin.Constant([1, 0])
        _snn = dolfin.dot(dolfin.dot(_sigma, e1), e1)
        time_data_i["sigma"] = 1 / Ly * dolfin.assemble(_snn * model.ds(1))

        time_data_i["S(alpha)"] = dolfin.assemble(1. / (model.a(alpha)) *
                                                  model.dx)
        time_data_i["A(alpha)"] = dolfin.assemble((model.a(alpha)) * model.dx)
        time_data_i["avg_alpha"] = dolfin.assemble(alpha * model.dx)

        ColorPrint.print_pass(
            "Time step {:.4g}: it {:3d}, err_alpha={:.4g}".format(
                time_data_i["load"], time_data_i["iterations"],
                time_data_i["alpha_error"]))

        time_data.append(time_data_i)
        time_data_pd = pd.DataFrame(time_data)

        if np.mod(it, savelag) == 0:
            with file_out as f:
                f.write(alpha, load)
                f.write(u, load)
                f.write_checkpoint(alpha,
                                   "alpha-{}".format(it),
                                   0,
                                   append=True)
                # with file_bif as f:
                print('DEBUG: written step ', it)

        if save_current_bifurcation:
            # modes = np.where(stability.eigs < 0)[0]

            time_data_i['h_opt'] = h_opt
            time_data_i['max_h'] = hmax
            time_data_i['min_h'] = hmin

            with file_bif as file:
                beta0v = dolfin.project(stability.perturbation_beta, V_alpha)
                file.write_checkpoint(beta0v,
                                      'beta0',
                                      bifurc_count - 1,
                                      append=True)
                file.write_checkpoint(alpha_bif_old,
                                      'alpha-old',
                                      bifurc_count - 1,
                                      append=True)
                file.write_checkpoint(alpha_bif,
                                      'alpha-bif',
                                      bifurc_count - 1,
                                      append=True)
                file.write_checkpoint(alpha,
                                      'alpha',
                                      bifurc_count - 1,
                                      append=True)

                np.save(os.path.join(outdir, 'energy_perturbations'),
                        energy_perturbations,
                        allow_pickle=True,
                        fix_imports=True)

            with file_eig as file:
                _v = dolfin.project(
                    dolfin.Constant(h_opt) * perturbation_v, V_u)
                _beta = dolfin.project(
                    dolfin.Constant(h_opt) * perturbation_beta, V_alpha)
                _v.rename('perturbation displacement',
                          'perturbation displacement')
                _beta.rename('perturbation damage', 'perturbation damage')
                # import pdb; pdb.set_trace()
                f.write(_v, load)
                f.write(_beta, load)
                file.write_checkpoint(_v,
                                      'perturbation_v',
                                      bifurc_count - 1,
                                      append=True)
                file.write_checkpoint(_beta,
                                      'perturbation_beta',
                                      bifurc_count - 1,
                                      append=True)

            save_current_bifurcation = False

        time_data_pd.to_json(os.path.join(outdir, "time_data.json"))

    plt.figure()
    plt.plot(time_data_pd["load"].values(),
             time_data_pd["iterations"].values(),
             label='its')
    plt.semilogy()
    ax = plt.gca()
    ax2 = ax.twinx()
    ax2.plot(time_data_pd["load"].values(),
             time_data_pd["alpha_error"].values(),
             'o',
             c='C1',
             label='alpha error')
    plt.savefig(os.path.join(outdir, 'am.pdf'))
    plt.legend()
    plt.close()
    # user_postprocess_timestep(alpha, parameters, load, xresol = 100)

    plt.figure()
    dolfin.plot(alpha)
    plt.savefig(os.path.join(outdir, "alpha.png"))
    plt.figure()
    dolfin.plot(u, mode="displacement")
    plt.savefig(os.path.join(outdir, "u.png"))
    _nu = parameters['material']['nu']
    _E = parameters['material']['E']
    _w1 = parameters['material']['sigma_D0']**2. / parameters['material']['E']

    tc = np.sqrt(2 * _w1 / (_E * (1. - 2. * _nu) * (1. + _nu)))
    if parameters['stability']['checkstability'] == 'True':
        pp.plot_spectrum(parameters, outdir, time_data_pd.sort_values('load'),
                         tc)
    # plt.show()
    print(time_data_pd)
    print()
    print('Output in: ' + outdir)

    return time_data_pd