Beispiel #1
0
    def project_vector_field(self, vel_split, vel, name):
        """
        Project the initial conditions to remove any divergence
        """
        sim = self.simulation
        sim.log.info('Projecting %s to remove divergence' % name)
        p = sim.data['p'].copy()
        p.vector().zero()
        self.assigner_merge.assign(vel, list(vel_split))

        def mk_rhs():
            rhs = self.C * vel.vector()
            # If there is no flux (Dirichlet type) across the boundaries then e is None
            if self.eqE is not None:
                self.E = assemble_into(self.eqE, self.E)
                rhs.axpy(-1.0, self.E)
            rhs.apply('insert')
            return rhs

        # Assemble RHS
        sim.log.info('    Assembling projection matrices')
        self.B = assemble_into(self.eqB, self.B)
        self.C = assemble_into(self.eqC, self.C)
        MinvB = matmul(self.M_unscaled_inv, self.B)
        rhs = mk_rhs()

        # Check if projection is needed
        norm_before = rhs.norm('l2')
        sim.log.info('    Divergence norm before %.6e' % norm_before)
        if norm_before < 1e-15:
            sim.log.info('    Skipping this one, there is no divergence')
            return

        # Assemble LHS
        CMinvB = matmul(self.C, MinvB)
        lhs = CMinvB

        sim.log.info('    Solving elliptic problem')
        # niter = self.pressure_solver.inner_solve(lhs, p.vector(), rhs, 0, 0)
        niter = dolfin.solve(lhs, p.vector(), rhs)
        vel.vector().axpy(-1.0, MinvB * p.vector())
        vel.vector().apply('insert')

        self.assigner_split.assign(list(vel_split), vel)
        for d in range(sim.ndim):
            sim.data['u'][d].assign(vel_split[d])
        self.velocity_postprocessor.run()
        for d in range(sim.ndim):
            vel_split[d].assign(sim.data['u'][d])
        self.assigner_merge.assign(vel, list(vel_split))

        rhs = mk_rhs()
        norm_after = rhs.norm('l2')
        sim.log.info('    Done in %d iterations' % niter)
        sim.log.info('    Divergence norm after %.6e' % norm_after)
Beispiel #2
0
def test_matmul(use_block_matrix):
    indices = numpy.array([1, 2, 4], numpy.intc)
    blockA = numpy.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], float)
    blockB = numpy.identity(3, float)

    A = mk_mat(block=use_block_matrix)
    B = mk_mat(block=use_block_matrix)

    A.set(blockA, indices, indices)
    B.set(blockB, indices, indices)
    A.apply('insert')
    B.apply('insert')

    dolfin.parameters['linear_algebra_backend'] = 'PETSc'
    A = dolfin.as_backend_type(A)
    B = dolfin.as_backend_type(B)
    print('A:\n', A.array())
    print('B:\n', B.array())

    C = matmul(A, B)
    print('C:\n', C.array())

    assert A.rank() == B.rank() == C.rank()
    assert A.size(0) == B.size(0) == C.size(0)
    assert A.size(1) == B.size(1) == C.size(1)

    Carr = C.array()
    Cnpy = numpy.dot(A.array(), B.array())
    assert (abs(Carr - Cnpy) < 1e-10).all()
Beispiel #3
0
    def pressure_correction(self, reassemble, last_piso_iter):
        """
        PIMPLE pressure correction
        """
        sim = self.simulation
        u_star = sim.data['uvw_star']
        p_star = sim.data['p']
        minus_p_hat = self.simulation.data['p_hat']

        # Assemble only once per time step
        if reassemble:
            self.E = dolfin.as_backend_type(self.matrices.assemble_E())

            # Compute LHS
            self.AtinvB = matmul(self.A_tilde_inv, self.B, self.AtinvB)
            self.CAtinvB = matmul(self.C, self.AtinvB, self.CAtinvB)

            # Needed for RHS
            self.AtinvA = matmul(self.A_tilde_inv, self.A, self.AtinvA)
            self.CAtinvA = matmul(self.C, self.AtinvA, self.CAtinvA)

        # Compute the residual divergence
        U = u_star.vector()
        div = self.C * U - self.E
        div_err = div.norm('l2')

        # The equation system
        lhs = self.CAtinvB
        rhs = div - self.CAtinvA * U + self.C * (self.A_tilde_inv * self.D)

        if DEBUG_RHS:
            # Quantify RHS contributions
            c0 = (self.C * U).norm('l2')
            c1 = (self.E).norm('l2')
            c2 = (self.CAtinvA * U).norm('l2')
            c3 = (self.C * (self.A_tilde_inv * self.D)).norm('l2')
            cT = max([c0, c1, c2, c3])
            sim.log.info(
                '                              Pressure RHS contributions:'
                '  %5.2f  %5.2f  %.2e    %5.2f  %5.2f    %.2e' %
                (c0 / cT, c1 / cT, div_err / cT, c2 / cT, c3 / cT, cT))

        # Inform PETSc about the pressure null space
        if self.remove_null_space:
            if self.pressure_null_space is None:
                # Create vector that spans the null space
                null_vec = dolfin.Vector(p_star.vector())
                null_vec[:] = 1
                null_vec *= 1 / null_vec.norm("l2")

                # Create null space basis object
                self.pressure_null_space = dolfin.VectorSpaceBasis([null_vec])

            # Make sure the null space is set on the matrix
            if self.inner_iteration == 1:
                lhs.set_nullspace(self.pressure_null_space)

            # Orthogonalize b with respect to the null space
            self.pressure_null_space.orthogonalize(rhs)

        # Solve for the new pressure correction
        minus_p_hat.assign(p_star)
        self.niters_p = self.pressure_solver.inner_solve(
            lhs,
            p_star.vector(),
            rhs,
            in_iter=self.inner_iteration,
            co_iter=self.co_inner_iter)

        # Compute change from last iteration
        minus_p_hat.vector().axpy(-1.0, p_star.vector())
        minus_p_hat.vector().apply('insert')

        # Removing the null space of the matrix system is not strictly the same as removing
        # the null space of the equation, so we correct for this here
        if self.remove_null_space:
            dx2 = dolfin.dx(domain=p_star.function_space().mesh())
            vol = dolfin.assemble(dolfin.Constant(1) * dx2)
            pavg = dolfin.assemble(p_star * dx2) / vol
            p_star.vector()[:] -= pavg

        # Explicit relaxation
        if self.last_inner_iter and last_piso_iter:
            alpha = sim.input.get_value('solver/relaxation_p_last_iter',
                                        ALPHA_P_LAST, 'float')
        else:
            alpha = sim.input.get_value('solver/relaxation_p', ALPHA_P,
                                        'float')
        if alpha != 1:
            p_star.vector().axpy(1 - alpha, minus_p_hat.vector())
            p_star.vector().apply('insert')

        return minus_p_hat.vector().norm('l2'), div_err
Beispiel #4
0
    def pressure_correction(self, piso_rhs=False):
        """
        Solve the Navier-Stokes equations on SIMPLE form
        (Semi-Implicit Method for Pressure-Linked Equations)
        """
        sim = self.simulation
        p_hat = sim.data['p_hat']
        if self.solver_type == SOLVER_SIMPLE:
            alpha = sim.input.get_value('solver/relaxation_p', ALPHA_P,
                                        'float')
        else:
            alpha = 1.0

        # Compute the LHS = C⋅Ãinv⋅B
        if self.inner_iteration == 1:
            C, Ainv, B = self.C, self.A_tilde_inv, self.B
            self.mat_AinvB = matmul(Ainv, B, self.mat_AinvB)
            self.mat_CAinvB = matmul(C, self.mat_AinvB, self.mat_CAinvB)
            self.LHS_pressure = dolfin.as_backend_type(self.mat_CAinvB.copy())
        LHS = self.LHS_pressure

        # Compute the RHS
        if not piso_rhs:
            # Standard SIMPLE pressure correction
            # Compute the divergence of u* and the rest of the right hand side
            uvw_star = sim.data['uvw_star']
            RHS = self.matrices.assemble_E_star(uvw_star)
            self.niters_p = 0
        else:
            # PISO pressure correction (the second pressure correction)
            # Compute the RHS = - C⋅Ãinv⋅(Ãinv - A)⋅û
            C, Ainv, A = self.C, self.A_tilde_inv, self.A
            if self.inner_iteration == 1:
                self.mat_AinvA = matmul(Ainv, A, self.mat_AinvA)
                self.mat_CAinvA = matmul(C, self.mat_AinvA, self.mat_CAinvA)
            RHS = self.mat_CAinvA * self.minus_uvw_hat - C * self.minus_uvw_hat

        # Inform PETSc about the null space
        if self.remove_null_space:
            if self.pressure_null_space is None:
                # Create vector that spans the null space
                null_vec = dolfin.Vector(p_hat.vector())
                null_vec[:] = 1
                null_vec *= 1 / null_vec.norm("l2")

                # Create null space basis object
                self.pressure_null_space = dolfin.VectorSpaceBasis([null_vec])

            # Make sure the null space is set on the matrix
            if self.inner_iteration == 1:
                LHS.set_nullspace(self.pressure_null_space)

            # Orthogonalize b with respect to the null space
            self.pressure_null_space.orthogonalize(RHS)

        # Solve for the new pressure correction
        self.niters_p += self.pressure_solver.inner_solve(
            LHS,
            p_hat.vector(),
            RHS,
            in_iter=self.inner_iteration,
            co_iter=self.co_inner_iter,
        )

        # Removing the null space of the matrix system is not strictly the same as removing
        # the null space of the equation, so we correct for this here
        if self.remove_null_space:
            dx2 = dolfin.dx(domain=p_hat.function_space().mesh())
            vol = dolfin.assemble(dolfin.Constant(1) * dx2)
            pavg = dolfin.assemble(p_hat * dx2) / vol
            p_hat.vector()[:] -= pavg

        # Calculate p = p* + α p^
        sim.data['p'].vector().axpy(alpha, p_hat.vector())
        sim.data['p'].vector().apply('insert')

        return p_hat.vector().norm('l2')
Beispiel #5
0
    def pressure_correction(self):
        """
        Solve the Navier-Stokes equations on SIMPLE form
        (Semi-Implicit Method for Pressure-Linked Equations)
        """
        sim = self.simulation
        u_star = sim.data['uvw_star']
        p_star = sim.data['p']
        p_hat = self.simulation.data['p_hat']

        # Assemble only once per time step
        if self.inner_iteration == 1:
            self.C = assemble_into(self.eqC, self.C)
            self.Minv = dolfin.as_backend_type(self.compute_M_inverse())
            if self.eqE is not None:
                self.E = assemble_into(self.eqE, self.E)

            # Compute LHS
            self.MinvB = matmul(self.Minv, self.B, self.MinvB)
            self.CMinvB = matmul(self.C, self.MinvB, self.CMinvB)

        # The equation system
        lhs = self.CMinvB
        rhs = self.CMinvB * p_star.vector()
        rhs.axpy(1, self.C * u_star.vector())
        if self.eqE is not None:
            rhs.axpy(-1, self.E)
        rhs.apply('insert')

        # Inform PETSc about the pressure null space
        if self.remove_null_space:
            if self.pressure_null_space is None:
                # Create vector that spans the null space
                null_vec = dolfin.Vector(p_star.vector())
                null_vec[:] = 1
                null_vec *= 1 / null_vec.norm("l2")

                # Create null space basis object
                self.pressure_null_space = dolfin.VectorSpaceBasis([null_vec])

            # Make sure the null space is set on the matrix
            if self.inner_iteration == 1:
                lhs.set_nullspace(self.pressure_null_space)

            # Orthogonalize b with respect to the null space
            self.pressure_null_space.orthogonalize(rhs)

        # Temporarily store the old pressure
        p_hat.vector().zero()
        p_hat.vector().axpy(-1, p_star.vector())

        # Solve for the new pressure correction
        self.niters_p = self.pressure_solver.inner_solve(
            lhs,
            p_star.vector(),
            rhs,
            in_iter=self.inner_iteration,
            co_iter=self.co_inner_iter)

        # Removing the null space of the matrix system is not strictly the same as removing
        # the null space of the equation, so we correct for this here
        if self.remove_null_space:
            dx2 = dolfin.dx(domain=p_star.function_space().mesh())
            vol = dolfin.assemble(dolfin.Constant(1) * dx2)
            pavg = dolfin.assemble(p_star * dx2) / vol
            p_star.vector()[:] -= pavg

        # Calculate p_hat = p_new - p_old
        p_hat.vector().axpy(1, p_star.vector())

        return p_hat.vector().norm('l2')