Exemple #1
0
 def set_default_values(self):
     self._alpha_mult = df.Function(self.S1)
     self._alpha_mult.assign(df.Constant(1.0))
     self._beta_mult = df.Function(self.S1)
     self._beta_mult.assign(df.Constant(1.0))
     
     self.alpha = 0.5 # alpha for solve: alpha * _alpha_mult
     self.beta=0
     
     self.t = 0.0 # s
     self.do_precession = True
     
     u3 = df.TrialFunction(self.S3)
     v3 = df.TestFunction(self.S3)
     self.K = df.PETScMatrix()
     df.assemble(1.0/self.unit_length**2*df.inner(df.grad(u3),df.grad(v3))*df.dx, tensor=self.K)
     self.H_laplace = df.PETScVector()
     self.H_eff_vec = df.PETScVector(len(self.M))
     
     self.vol = df.assemble(df.dot(df.TestFunction(self.S3), df.Constant([1, 1, 1])) * df.dx).array()
    
     self.gamma =  consts.gamma
     #source for gamma:  OOMMF manual, and in Werner Scholz thesis, 
     #after (3.7), llg_gamma_G = m/(As).
     self.c = 1e11 # 1/s numerical scaling correction \
     #               0.1e12 1/s is the value used by default in nmag 0.2
     self.M0 = 8.6e5 # A/m saturation magnetisation
     self.t = 0.0 # s
     self._pins=np.zeros(self.S1.mesh().num_vertices(),dtype="int")
     self._pre_rhs_callables=[]
     self._post_rhs_callables=[]
     self.interactions = []
Exemple #2
0
    def set_parameters(self,
                       J_profile=(1e10, 0, 0),
                       P=0.5,
                       D=2.5e-4,
                       lambda_sf=5e-9,
                       lambda_J=1e-9,
                       speedup=1):

        self._J = helpers.vector_valued_function(J_profile, self.S3)
        self.J = self._J.vector().array()
        self.compute_gradient_matrix()
        self.H_gradm = df.PETScVector()

        self.P = P

        self.D = D / speedup
        self.lambda_sf = lambda_sf
        self.lambda_J = lambda_J

        self.tau_sf = lambda_sf**2 / D * speedup
        self.tau_sd = lambda_J**2 / D * speedup

        self.compute_laplace_matrix()
        self.H_laplace = df.PETScVector()

        self.nodal_volume_S3 = nodal_volume(self.S3)
Exemple #3
0
    def setup(self, DG3, m, Ms, unit_length=1.0):
        self.DG3 = DG3
        self.m = m
        self.Ms = Ms
        self.unit_length = unit_length

        mesh = DG3.mesh()
        self.mesh = mesh

        DG = df.FunctionSpace(mesh, "DG", 0)
        BDM = df.FunctionSpace(mesh, "BDM", 1)

        #deal with three components simultaneously, each represents a vector
        W1 = df.MixedFunctionSpace([BDM, BDM, BDM])
        (sigma0, sigma1, sigma2) = df.TrialFunctions(W1)
        (tau0, tau1, tau2) = df.TestFunctions(W1)

        W2 = df.MixedFunctionSpace([DG, DG, DG])
        (u0, u1, u2) = df.TrialFunctions(W2)
        (v0, v1, v2) = df.TestFunction(W2)

        # what we need is A x = K1 m
        a0 = (df.dot(sigma0, tau0) + df.dot(sigma1, tau1) +
              df.dot(sigma2, tau2)) * df.dx
        self.A = df.assemble(a0)

        a1 = -(df.div(tau0) * u0 + df.div(tau1) * u1 +
               df.div(tau2) * u2) * df.dx
        self.K1 = df.assemble(a1)

        def boundary(x, on_boundary):
            return on_boundary

        # actually, we need to apply the Neumann boundary conditions.
        # we need a tensor here
        zero = df.Constant((0, 0, 0, 0, 0, 0, 0, 0, 0))
        self.bc = df.DirichletBC(W1, zero, boundary)
        self.bc.apply(self.A)

        a2 = (df.div(sigma0) * v0 + df.div(sigma1) * v1 +
              df.div(sigma2) * v2) * df.dx
        self.K2 = df.assemble(a2)
        self.L = df.assemble((v0 + v1 + v2) * df.dx).array()

        self.mu0 = mu0
        self.exchange_factor = 2.0 * self.C / (self.mu0 * Ms *
                                               self.unit_length**2)

        self.coeff = self.exchange_factor / self.L

        # b = K m
        self.b = df.PETScVector()

        # the vector in BDM space
        self.sigma_v = df.PETScVector(self.K2.size(1))

        # to store the exchange fields
        self.H = df.PETScVector()
Exemple #4
0
    def use_zhangli(self,
                    J_profile=(1e10, 0, 0),
                    P=0.5,
                    beta=0.01,
                    using_u0=False,
                    with_time_update=None):

        self.zhangli_stt = True
        self.fun_zhangli_time_update = with_time_update
        self.P = P
        self.beta = beta

        self._J = helpers.vector_valued_function(J_profile, self.S3)
        self.J = self._J.vector().array()
        self.compute_gradient_matrix()
        self.H_gradm = df.PETScVector()

        self.integrator = native_llb.StochasticLLGIntegratorSTT(
            self.m, self.m_pred, self._Ms, self._T, self.real_volumes,
            self._alpha, self.P, self.beta, self.stochastic_update_field,
            self.method)

        # seems that in the presence of current, the time step have to very
        # small
        self.dt = 1e-14
Exemple #5
0
    def is_elastic(self):

        Ealpha = assemble(self.Ealpha)
        vec = dolfin.PETScVector(MPI.comm_self)
        Ealpha.gather(vec, np.array(range(self.Z.sub(1).dim()), "intc"))

        return np.all(vec[:] > 0)
Exemple #6
0
    def use_zhangli(self, J_profile=(1e10, 0, 0), P=0.5, beta=0.01, using_u0=False, with_time_update=None):
        """
        if using_u0 = True, the factor of 1/(1+beta^2) will be dropped.

        With with_time_update should be a function like:
        def f(t):
            return (0, 0, J*g(t))

        We do not use a position dependent function for performance reasons.
        """

        self.do_zhangli = True
        self.fun_zhangli_time_update = with_time_update
        self._J = helpers.vector_valued_function(J_profile, self.S3)
        self.J = self._J.vector().array()
        self.compute_gradient_matrix()
        self.H_gradm = df.PETScVector()

        const_e = 1.602176565e-19
        # elementary charge in As
        mu_B = 9.27400968e-24
        # Bohr magneton

        self.P = P
        self.beta = beta

        u0 = P * mu_B / const_e  # P g mu_B/(2 e Ms) and g=2 for electrons

        if using_u0:
            self.u0 = u0
        else:
            self.u0 = u0 / (1 + beta ** 2)
    def soln_adj2(self, obj):
        """
        Solve the 2nd order adjoint equation.
        < adj_dFdstates, states_adj2 > = < d2Jdstates, states_fwd2 >
        """
        self.states_adj2 = df.Function(self.W)  # 2nd forward states
        # Solve 2nd adjoint PDE < adj_dFdstates, states_adj2 > = < d2Jdstates, states_fwd2 >
        #         df.solve(self.adj_dFdstates == df.action(self.d2Jdstates, self.states_fwd2), self.states_adj2, self.adj_bcs)
        #         A,b = df.assemble_system(self.adj_dFdstates, df.action(self.d2Jdstates, self.states_fwd2), self.adj_bcs)
        #         df.solve(A, self.states_adj2.vector(), b)

        #         rhs_adj2 = df.PETScVector()
        #         df.assemble(df.action(self.d2Jdstates, self.states_fwd2), tensor=rhs_adj2)

        u_fwd2, _ = df.split(self.states_fwd2)
        if not df.has_petsc4py():
            warnings.warn('Configure dolfin with petsc4py to run faster!')
            self.dirac_2 = obj.ptsrc(u_fwd2, ord=2)
            rhs_adj2 = df.Vector(self.mpi_comm, self.W.dim())
            [delta.apply(rhs_adj2) for delta in self.dirac_2]
        else:
            rhs_adj2 = df.PETScVector(self.mpi_comm, self.W.dim())
            val_dirac_2, idx_dirac_2 = obj.dirac(u_fwd2, ord=2)
            rhs_adj2.vec()[idx_dirac_2] = val_dirac_2
#             np.allclose(rhs_adj2.array(),rhs_adj12.vec())

        [bc.apply(rhs_adj2) for bc in self.adj_bcs]

        df.solve(self.adj_dFdstates_assemb, self.states_adj2.vector(),
                 rhs_adj2)
        self.soln_count[3] += 1
        u_adj2, l_adj2 = df.split(self.states_adj2)
        return u_adj2, l_adj2
    def soln_adj(self, obj):
        """
        Solve the adjoint equation.
        < adj_dFdstates, states_adj > = dJdstates
        """
        self.states_adj = df.Function(self.W)  # adjoint states
        # Solve adjoint PDE < adj_dFdstates, states_adj > = dJdstates
        #         df.solve(self.adj_dFdstates == self.dJdstates , self.states_adj, self.adj_bcs)
        #         A,b = df.assemble_system(self.adj_dFdstates, self.dJdstates, self.adj_bcs)
        #         df.solve(A, self.states_adj.vector(), b)
        #         error: assemble (solve) point integral (J) has supported underlying FunctionSpace no more than CG1; have to use PointSource? Yuk!

        u_fwd, _ = df.split(self.states_fwd)
        if not df.has_petsc4py():
            warnings.warn('Configure dolfin with petsc4py to run faster!')
            self.dirac_1 = obj.ptsrc(u_fwd, ord=1)
            rhs_adj = df.Vector(self.mpi_comm, self.W.dim())
            [delta.apply(rhs_adj) for delta in self.dirac_1]
        else:
            rhs_adj = df.PETScVector(self.mpi_comm, self.W.dim())
            val_dirac_1, idx_dirac_1 = obj.dirac(u_fwd, ord=1)
            rhs_adj.vec()[idx_dirac_1] = val_dirac_1
#             np.allclose(rhs_adj.array(),rhs_adj1.vec())

        [bc.apply(self.adj_dFdstates_assemb, rhs_adj) for bc in self.adj_bcs]

        df.solve(self.adj_dFdstates_assemb, self.states_adj.vector(), rhs_adj)
        self.soln_count[1] += 1
        u_adj, l_adj = df.split(self.states_adj)
        return u_adj, l_adj
Exemple #9
0
 def __init__(self, solver, u_=None):
     self.solver = solver
     W = solver.W
     self.u_ = u_ if u_ else dolfin.Function(W)  # current solution
     self.u = dolfin.Function(W)  # next solution
     self.du = dolfin.Function(W)  # change to current solution
     self.Qdu = dolfin.PETScVector()
def define_solver_clamped(k_form, l_form, m_form, Dbc):
    K = df.PETScMatrix()  # stiffness matrix
    b = df.PETScVector()
    df.assemble_system(k_form, l_form, Dbc, A_tensor=K, b_tensor=b)
    M = df.PETScMatrix()  # mass matrix
    df.assemble(m_form, tensor=M)
    eigensolver = set_pmr_solver(K, M)
    return eigensolver, K, M
Exemple #11
0
 def b(self):
     b = dolfin.PETScVector()
     self.solver.assembler.assemble(b, self.u_.vector())  # <---- (*)
     # (*) If you're wondering how we can just apply nonzero Dirichlet BC's
     # despite du being required to be equal to zero on u's Dirichlet
     # boundaries, then look no further. The answer is that second argument
     # to SystemAssembler::assemble().
     return b
Exemple #12
0
    def __setup_field_petsc(self):
        """
        Same as __setup_field_numpy but with a petsc backend.

        """
        g_form = df.derivative(self.dE_dm, self.m.f)
        self.g_petsc = df.PETScMatrix()
        df.assemble(g_form, tensor=self.g_petsc)
        self.H_petsc = df.PETScVector()
Exemple #13
0
    def __init__(self, vbp, options_prefix="", solver={}, ctx={}):

        super(LinearBlockSolver, self).__init__(vbp, options_prefix, solver,
                                                ctx)

        self.A = df.PETScMatrix()
        self.b = df.PETScVector()

        self.log_level = vbp.log_level

        if self.aP is not None:
            self.P = df.PETScMatrix()
Exemple #14
0
    def __setup_field_direct(self):
        dofmap = self.m.mesh_dofmap()
        S3 = df.VectorFunctionSpace(
            self.m.mesh(),
            "CG",
            1,
            dim=3,
            constrained_domain=dofmap.constrained_domain)

        u3 = df.TrialFunction(S3)
        v3 = df.TestFunction(S3)
        self.g_petsc = df.PETScMatrix()
        df.assemble(-2 * self.dmi_factor * self.D.f *
                    df.inner(v3, df.curl(u3)) * df.dx,
                    tensor=self.g_petsc)
        self.H_petsc = df.PETScVector()
Exemple #15
0
    def setup(self, S3, M, Ms0, unit_length=1):
        self.S3 = S3
        self.M = M
        v3 = df.TestFunction(S3)

        E = -df.Constant(self.K1 / Ms0**2) * (
            (df.dot(self.axis, self.M))**2) * df.dx

        # Gradient
        self.dE_dM = df.Constant(-1.0 / mu0) * df.derivative(E, self.M)
        self.vol = df.assemble(df.dot(v3, df.Constant([1, 1, 1])) *
                               df.dx).array()

        self.K = df.PETScMatrix()
        self.H = df.PETScVector()
        g_form = df.derivative(self.dE_dM, self.M)

        df.assemble(g_form, tensor=self.K)
Exemple #16
0
    def setup(self, S3, m, Ms0, unit_length=1.0):
        self.S3 = S3
        self.m = m
        self.Ms0 = Ms0
        self.unit_length = unit_length

        self.mu0 = mu0
        self.exchange_factor = 2.0 / (self.mu0 * Ms0 * self.unit_length**2)

        u3 = df.TrialFunction(S3)
        v3 = df.TestFunction(S3)
        self.K = df.PETScMatrix()
        df.assemble(self.C * df.inner(df.grad(u3), df.grad(v3)) * df.dx,
                    tensor=self.K)
        self.H = df.PETScVector()

        self.vol = df.assemble(df.dot(v3, df.Constant([1, 1, 1])) *
                               df.dx).array()

        self.coeff = -self.exchange_factor / (self.vol * self.me**2)
    def soln_fwd2(self, u_actedon):
        """
        Solve the 2nd order forward equation.
        < dFdstates, states_fwd2 > = < dFdunknown, u_actedon >
        """
        self.states_fwd2 = df.Function(self.W)  # 2nd forward states
        # Solve 2nd forward PDE < dFdstates, states_fwd2 > = < dFdunknown, u_actedon >
        #         df.solve(self.dFdstates == df.action(self.dFdunknown, u_actedon), self.states_fwd2, self.adj_bcs) # ToDo: check the boundary for fwd2
        #         A,b = df.assemble_system(self.dFdstates, df.action(self.dFdunknown, u_actedon), self.adj_bcs)
        #         df.solve(A, self.states_fwd2.vector(), b)

        rhs_fwd2 = df.PETScVector()
        #         df.assemble(df.action(self.dFdunknown, u_actedon), tensor=rhs_fwd2)
        self.dFdunknown_assemb.mult(u_actedon.vector(), rhs_fwd2)

        [bc.apply(rhs_fwd2) for bc in self.adj_bcs]

        df.solve(self.dFdstates_assemb, self.states_fwd2.vector(), rhs_fwd2)
        self.soln_count[2] += 1
        u_fwd2, l_fwd2 = df.split(self.states_fwd2)
        return u_fwd2, l_fwd2
Exemple #18
0
    def setup(self, S3, M, M0, unit_length=1.0):
        self.S3 = S3
        self.M = M
        self.M0 = M0
        self.unit_length = unit_length
        self.Ms2 = np.array(self.M.vector().array())

        self.mu0 = mu0
        self.exchange_factor = 2.0 * self.C / (self.mu0 * M0**2 *
                                               self.unit_length**2)

        u3 = df.TrialFunction(S3)
        v3 = df.TestFunction(S3)
        self.K = df.PETScMatrix()
        df.assemble(df.inner(df.grad(u3), df.grad(v3)) * df.dx, tensor=self.K)
        self.H = df.PETScVector()

        self.vol = df.assemble(df.dot(v3, df.Constant([1, 1, 1])) *
                               df.dx).array()

        self.coeff1 = -self.exchange_factor / (self.vol)
        self.coeff2 = -0.5 / (self.chi * M0**2)
Exemple #19
0
    def load_la_objects(self, file_name):
        """
        Load a dictionary of named PETScMatrix and PETScVector objects
        from a file
        """
        assert self.simulation.ncpu == 1, 'Not supported in parallel'

        import pickle

        with open(file_name, 'rb') as inp:
            data = pickle.load(inp)

        ret = {}
        for key, value in data.items():
            value_type = value[0]
            # Vectors
            if value_type == 'dolfin.PETScVector':
                arr = value[1]
                dolf_vec = dolfin.PETScVector(dolfin.MPI.comm_world, arr.size)
                dolf_vec.set_local(arr)
                dolf_vec.apply('insert')
                ret[key] = dolf_vec
            # Matrices
            elif value_type == 'dolfin.PETScMatrix':
                shape, rows, cols, values = value[1:]
                from petsc4py import PETSc

                mat = PETSc.Mat().createAIJ(size=shape,
                                            csr=(rows, cols, values))
                mat.assemble()
                dolf_mat = dolfin.PETScMatrix(mat)
                ret[key] = dolf_mat

            else:
                raise ValueError('Cannot save object of type %r' % value_type)

        self.simulation.log.info('Loaded LA objects from %r (%r)' %
                                 (file_name, data.keys()))
        return ret
Exemple #20
0
    def get_inactive_set(self):
        tol = self.parameters['inactiveset_atol']
        debug = False

        Ealpha = dolfin.assemble(self.Ealpha)
        vec = dolfin.PETScVector(MPI.comm_self)
        Ealpha.gather(vec, np.array(range(self.Z.sub(1).dim()), "intc"))

        if debug:
            print('len vec grad', len(vec[:]))

        mask = Ealpha[:] / self.cellarea.vector() < tol

        inactive_set_alpha = set(np.where(mask == True)[0])

        # from subspace to global numbering
        global_inactive_set_alpha = [self.mapa[k] for k in inactive_set_alpha]

        # add displacement dofs
        inactive_set = set(global_inactive_set_alpha) | set(
            self.Z.sub(0).dofmap().dofs())

        return inactive_set
Exemple #21
0
    def evalFunction(self, ts, t, x, xdot, b):
        """The callback that the TS executes to compute the residual."""
        self.update(t)
        self.update_x(x)
        self.update_xdot(xdot)

        b1 = df.Vector()
        b2 = df.Vector()
        #self.assembler.assemble(self.F_fluid_form, tensor = b1)
        df.assemble(self.F_fluid_form, tensor=b1)
        [bc.apply(b1) for bc in self.bcs_mesh]

        #self.assembler.assemble(self.F_solid_form, tensor = b2)
        df.assemble(self.F_solid_form, tensor=b2)

        b_wrap = df.PETScVector(b)
        # zero all entries
        b_wrap.zero()
        #df.assemble(b_wrap, self.x)

        b_wrap.axpy(1, b1)
        b_wrap.axpy(1, b2)
        [bc.apply(b_wrap, self.x) for bc in self.bcs]
Exemple #22
0
    def setup(self, DG3, m, Ms, unit_length=1.0):
        self.DG3 = DG3
        self.m = m
        self.Ms = Ms
        self.unit_length = unit_length

        mesh = DG3.mesh()
        self.mesh = mesh

        DG = df.FunctionSpace(mesh, "DG", 0)
        BDM = df.FunctionSpace(mesh, "BDM", 1)

        #deal with three components simultaneously, each represents a vector

        sigma = df.TrialFunction(BDM)
        tau = df.TestFunction(BDM)

        u = df.TrialFunction(DG)
        v = df.TestFunction(DG)

        # what we need is A x = K1 m
        #a0 = (df.dot(sigma0, tau0) + df.dot(sigma1, tau1) + df.dot(sigma2, tau2)) * df.dx
        a0 = df.dot(sigma, tau) * df.dx
        self.A = df.assemble(a0)

        a1 = -(df.div(tau) * u) * df.dx
        self.K1 = df.assemble(a1)

        C = sp.lil_matrix(self.K1.array())
        self.KK1 = C.tocsr()

        def boundary(x, on_boundary):
            return on_boundary

        # actually, we need to apply the Neumann boundary conditions.

        zero = df.Constant((0, 0, 0))
        self.bc = df.DirichletBC(BDM, zero, boundary)
        #print 'before',self.A.array()

        self.bc.apply(self.A)

        #print 'after',self.A.array()

        #AA = sp.lil_matrix(self.A.array())
        AA = copy_petsc_to_csc(self.A)

        self.solver = sp.linalg.factorized(AA.tocsc())

        #LU = sp.linalg.spilu(AA)
        #self.solver = LU.solve

        a2 = (df.div(sigma) * v) * df.dx
        self.K2 = df.assemble(a2)
        self.L = df.assemble(v * df.dx).array()

        self.mu0 = mu0
        self.exchange_factor = 2.0 * self.C / (self.mu0 * Ms *
                                               self.unit_length**2)

        self.coeff = self.exchange_factor / self.L

        self.K2 = copy_petsc_to_csr(self.K2)

        # b = K m
        self.b = df.PETScVector()
        # the vector in BDM space
        self.sigma_v = df.PETScVector()

        # to store the exchange fields
        #self.H = df.PETScVector()
        self.H_eff = m.vector().array()

        self.m_x = df.PETScVector(self.m.vector().size() / 3)
    drdz = df.Measure("dx")[domains]
    r = df.Expression("x[0]")

    # Confining potential
    potential = df.Constant(100)

    # Partial derivatives of trial and test functions
    u_r = u.dx(0)
    v_r = v.dx(0)
    u_z = u.dx(1)
    v_z = v.dx(1)

    # Initial guess of ground state is 1 inside dot, 0 outside dot
    psi0 = v * r * drdz(1)
    Psi0 = df.PETScVector()
    df.assemble(psi0, tensor=Psi0)

    # Hamiltonian and mass matrix forms
    h = (u_r * v_r + u_z * v_z) * r * (
        drdz(0) + drdz(1)) + potential * r * u * v * r * drdz(0)
    m = (u * v * r) * (drdz(0) + drdz(1))

    # Mass matrix
    M = df.PETScMatrix()
    df.assemble(m, tensor=M)

    # Hamiltonian matrix
    H = df.PETScMatrix()
    df.assemble(h, tensor=H)
p_in = dolfin.Constant(1.0)  # pressure inlet
p_out = dolfin.Constant(0.0)  # pressure outlet
noslip = dolfin.Constant([0.0] * mesh.geometry().dim())  # no-slip wall

#Boundary conditions
gN1 = (-p_out * dolfin.Identity(mesh.geometry().dim())) * n
Neumann_outlet = dg.DGNeumannBC(ds(mark["outlet"]), gN1)
gN2 = (-p_in * dolfin.Identity(mesh.geometry().dim())) * n
Neumann_inlet = dg.DGNeumannBC(ds(mark["inlet"]), gN2)
Dirichlet_wall = dg.DGDirichletBC(ds(mark["wall"]), noslip)

weak_bcs = [Dirichlet_wall, Neumann_inlet, Neumann_outlet]

#Body force term
f = dolfin.Constant([0.0] * mesh.geometry().dim())
model = geopart.stokes.StokesModel(eta=mu, f=f)

#Form and solve Stokes
A, b = dolfin.PETScMatrix(), dolfin.PETScVector()
element_cls.solve_stokes(W, U, (A, b), weak_bcs, model)
uh, ph = element_cls.get_velocity(U), element_cls.get_pressure(U)

#Output solution p,u to paraview
dolfin.XDMFFile("pressure.xdmf").write_checkpoint(ph, "p")
dolfin.XDMFFile("velocity.xdmf").write_checkpoint(uh, "u")

flux = [dolfin.assemble(dolfin.dot(uh, n) * ds(i)) for i in range(len(mark))]

if comm.Get_rank() == 0:
    for key, value in mark.items():
        print("Flux_%s= %.15lf" % (key, flux[value]))
Exemple #25
0
    def nonlinear_solve(self,
                        lhs,
                        rhs,
                        bcs,
                        nonlinear_tol=1e-10,
                        iter_tol=1e-8,
                        maxNonlinIters=50,
                        maxLinIters=200,
                        show=0,
                        print_norm=True,
                        lin_solver="mumps"):
        """
        Solve the nonlinear system of equations using Newton's method.


        Parameters
        ----------

        lhs : ufl.Form, list
            The definition of the left-hand side of the resulting linear
            system of equations.
        rhs : ufl.Form, list
            The definition of the right-hand side of the resulting linear
            system of equations.
        bcs : dolfin.DirichletBC, list
            Object specifying the Dirichlet boundary conditions of the
            system.
        nonlinear_tol : float (default 1e-10)
            Tolerance used to terminate Newton's method.
        iter_tol : float (default 1e-8)
            Tolerance used to terminate the iterative linear solver.
        maxNonlinIters : int (default 50)
            Maximum number of iterations for Newton's method.
        maxLinIters : int (default 200)
            Maximum number of iterations for iterative linear solver.
        show : int (default 0)
            Amount of information for iterative.LGMRES to show. See
            documentation of this class for different log levels.
        print_norm : bool (default True)
            True if user wishes to see the norm at every linear iteration
            and False otherwise.
        lin_solver : str (default "mumps")
            Name of the linear solver to be used for steady compressible elastic
            problems. See the dolfin.solve documentation for a list of available
            linear solvers.


        Returns
        -------

        None

        """

        norm = 1.0
        count = 0
        rank = dlf.MPI.rank(MPI_COMM_WORLD)

        # Determine if we can use dolfin's assemble_system function or
        # if we need to assemble a block system.
        if isinstance(lhs, Form):
            assemble_system = dlf.assemble_system
            is_block = False
            du = dlf.PETScVector()
        else:
            assemble_system = block.block_assemble
            is_block = True

        while norm >= nonlinear_tol:

            if count >= maxNonlinIters:
                raise StopIteration('Maximum number of iterations reached.')

            # Assemble system with Dirichlet BCs applied symmetrically.
            A, b = assemble_system(lhs, rhs, bcs)

            # Decide between a dolfin direct solver or a block iterative solver.
            if is_block:
                Ainv = iterative.LGMRES(
                    A,
                    show=show,
                    tolerance=iter_tol,
                    # nonconvergence_is_fatal=True,
                    maxiter=maxLinIters)
                du = Ainv * b
            else:
                dlf.solve(A, du, b, lin_solver)

            self.update_soln(du)

            norm = du.norm('l2')
            if not rank and print_norm:
                print('(iter %2i) norm %.3e' % (count, norm))

            count += 1

        return None