Esempio n. 1
0
    void TestReadMeshes(void) throw(Exception)
    {
        {
            READER_2D reader("mesh/test/data/square_4_elements_gmsh.msh");
            TetrahedralMesh<2,2> mesh;
            mesh.ConstructFromMeshReader(reader);
            TS_ASSERT_EQUALS(mesh.GetNumNodes(), 5u);
            TS_ASSERT_EQUALS(mesh.GetNumElements(), 4u);
            TS_ASSERT_EQUALS(mesh.GetNumBoundaryElements(), 4u);
        }

        {
            READER_3D reader("mesh/test/data/simple_cube_gmsh.msh");
            TetrahedralMesh<3,3> mesh;
            mesh.ConstructFromMeshReader(reader);
            TS_ASSERT_EQUALS(mesh.GetNumNodes(), 14u);
            TS_ASSERT_EQUALS(mesh.GetNumElements(), 24u);
            TS_ASSERT_EQUALS(mesh.GetNumBoundaryElements(), 24u);
        }

        {
           READER_2D reader("mesh/test/data/quad_square_4_elements_gmsh.msh",2,2);
           QuadraticMesh<2> mesh;
           mesh.ConstructFromMeshReader(reader);
           TS_ASSERT_EQUALS(mesh.GetNumNodes(), 13u);
           TS_ASSERT_EQUALS(mesh.GetNumElements(), 4u);
           TS_ASSERT_EQUALS(mesh.GetNumBoundaryElements(), 4u);
        }

        {
           READER_3D reader("mesh/test/data/quad_cube_gmsh.msh",2,2);
           QuadraticMesh<3> mesh;
           mesh.ConstructFromMeshReader(reader);
           TS_ASSERT_EQUALS(mesh.GetNumNodes(), 63u);
           TS_ASSERT_EQUALS(mesh.GetNumElements(), 24u);
           TS_ASSERT_EQUALS(mesh.GetNumBoundaryElements(), 24u);
        }
    }
    void TestAssembler2d() throw (Exception)
    {
        QuadraticMesh<2> mesh;
        TrianglesMeshReader<2,2> mesh_reader("mesh/test/data/canonical_triangle_quadratic", 2, 2, false);
        mesh.ConstructFromMeshReader(mesh_reader);

        ContinuumMechanicsProblemDefinition<2> problem_defn(mesh);

        double t1 = 2.6854233;
        double t2 = 3.2574578;

        // for the boundary element on the y=0 surface, create a traction
        std::vector<BoundaryElement<1,2>*> boundary_elems;
        std::vector<c_vector<double,2> > tractions;
        c_vector<double,2> traction;
        traction(0) = t1;
        traction(1) = t2;
        for (TetrahedralMesh<2,2>::BoundaryElementIterator iter
              = mesh.GetBoundaryElementIteratorBegin();
             iter != mesh.GetBoundaryElementIteratorEnd();
             ++iter)
        {
            if (fabs((*iter)->CalculateCentroid()[1])<1e-4)
            {
                BoundaryElement<1,2>* p_element = *iter;
                boundary_elems.push_back(p_element);
                tractions.push_back(traction);
            }
        }
        assert(boundary_elems.size()==1);
        problem_defn.SetTractionBoundaryConditions(boundary_elems, tractions);


        ContinuumMechanicsNeumannBcsAssembler<2> assembler(&mesh, &problem_defn);

        TS_ASSERT_THROWS_THIS(assembler.AssembleVector(), "Vector to be assembled has not been set");
        Vec bad_sized_vec = PetscTools::CreateVec(2);
        assembler.SetVectorToAssemble(bad_sized_vec, true);
        TS_ASSERT_THROWS_THIS(assembler.AssembleVector(), "Vector provided to be assembled has size 2, not expected size of 18 ((dim+1)*num_nodes)");


        Vec vec = PetscTools::CreateVec(3*mesh.GetNumNodes());

        assembler.SetVectorToAssemble(vec, true);
        assembler.AssembleVector();

        ReplicatableVector vec_repl(vec);

        // Note: on a 1d boundary element,  intgl phi_i dx = 1/6 for the bases on the vertices
        // and intgl phi_i dx = 4/6 for the basis at the interior node. (Here the integrals
        // are over the canonical 1d element, [0,1], which is also the physical element for this
        // mesh.

        // node 0 is on the surface, and is a vertex
        TS_ASSERT_DELTA(vec_repl[0], t1/6.0, 1e-8);
        TS_ASSERT_DELTA(vec_repl[1], t2/6.0, 1e-8);

        // node 1 is on the surface, and is a vertex
        TS_ASSERT_DELTA(vec_repl[3], t1/6.0, 1e-8);
        TS_ASSERT_DELTA(vec_repl[4], t2/6.0, 1e-8);

        // nodes 2, 3, 4 are not on the surface
        for(unsigned i=2; i<5; i++)
        {
            TS_ASSERT_DELTA(vec_repl[3*i], 0.0, 1e-8);
            TS_ASSERT_DELTA(vec_repl[3*i], 0.0, 1e-8);
        }

        // node 5 is on the surface, and is an interior node
        TS_ASSERT_DELTA(vec_repl[15], 4*t1/6.0, 1e-8);
        TS_ASSERT_DELTA(vec_repl[16], 4*t2/6.0, 1e-8);


        // the rest of the vector is the pressure block and should be zero.
        TS_ASSERT_DELTA(vec_repl[2], 0.0, 1e-8);
        TS_ASSERT_DELTA(vec_repl[5], 0.0, 1e-8);
        TS_ASSERT_DELTA(vec_repl[8], 0.0, 1e-8);
        TS_ASSERT_DELTA(vec_repl[11], 0.0, 1e-8);
        TS_ASSERT_DELTA(vec_repl[14], 0.0, 1e-8);
        TS_ASSERT_DELTA(vec_repl[17], 0.0, 1e-8);

        PetscTools::Destroy(vec);
        PetscTools::Destroy(bad_sized_vec);
    }
    /*
     * Test that the matrix is calculated correctly on the cannonical triangle.
     * Tests against the analytical solution calculated by hand.
     */
    void TestAssembler()  throw(Exception)
    {
        QuadraticMesh<2> mesh;
        TrianglesMeshReader<2,2> mesh_reader("mesh/test/data/canonical_triangle_quadratic", 2, 2, false);
        mesh.ConstructFromMeshReader(mesh_reader);

        double mu = 2.0;
        c_vector<double,2> body_force;
        double g1 = 1.34254;
        double g2 = 75.3422;
        body_force(0) = g1;
        body_force(1) = g2;

        StokesFlowProblemDefinition<2> problem_defn(mesh);
        problem_defn.SetViscosity(mu);
        problem_defn.SetBodyForce(body_force);

        StokesFlowAssembler<2> assembler(&mesh, &problem_defn);

        // The tests below test the assembler against hand-calculated variables for
        // an OLD weak form (corresponding to different boundary conditions), not the
        // current Stokes weak form. This factor converts the assembler to use the old
        // weak form. See documentation for this variable for more details.
        assembler.mScaleFactor = 0.0;

        Vec vec = PetscTools::CreateVec(18);
        Mat mat;
        PetscTools::SetupMat(mat, 18, 18, 18);

        assembler.SetVectorToAssemble(vec, true);
        assembler.SetMatrixToAssemble(mat, true);
        assembler.Assemble();
        PetscMatTools::Finalise(mat);

        double A[6][6] = {
            {      1.0,  1.0/6.0,  1.0/6.0,      0.0, -2.0/3.0, -2.0/3.0},
            {  1.0/6.0,  1.0/2.0,      0.0,      0.0,      0.0, -2.0/3.0},
            {  1.0/6.0,      0.0,  1.0/2.0,      0.0, -2.0/3.0,      0.0},
            {      0.0,      0.0,      0.0,  8.0/3.0, -4.0/3.0, -4.0/3.0},
            { -2.0/3.0,      0.0, -2.0/3.0, -4.0/3.0,  8.0/3.0,      0.0},
            { -2.0/3.0, -2.0/3.0,      0.0, -4.0/3.0,      0.0,  8.0/3.0}
        };

        double Bx[6][3] = {
            { -1.0/6.0,      0.0,      0.0},
            {      0.0,  1.0/6.0,      0.0},
            {      0.0,      0.0,      0.0},
            {  1.0/6.0,  1.0/6.0,  1.0/3.0},
            { -1.0/6.0, -1.0/6.0, -1.0/3.0},
            {  1.0/6.0, -1.0/6.0,      0.0},
        };

        double By[6][3] = {
            { -1.0/6.0,      0.0,      0.0},
            {      0.0,      0.0,      0.0},
            {      0.0,      0.0,  1.0/6.0},
            {  1.0/6.0,  1.0/3.0,  1.0/6.0},
            {  1.0/6.0,      0.0, -1.0/6.0},
            { -1.0/6.0, -1.0/3.0, -1.0/6.0},
        };

        c_matrix<double,18,18> exact_A = zero_matrix<double>(18);

        // The diagonal 6x6 blocks
        for (unsigned i=0; i<6; i++)
        {
            for (unsigned j=0; j<6; j++)
            {
                exact_A(3*i,  3*j)   = mu*A[i][j];
                exact_A(3*i+1,3*j+1) = mu*A[i][j];
            }
        }


        // The 6x3 Blocks
        for (unsigned i=0; i<6; i++)
        {
            for (unsigned j=0; j<3; j++)
            {
                exact_A(3*i,3*j+2)   = -Bx[i][j];
                exact_A(3*i+1,3*j+2) = -By[i][j];
                //- as -Div(U)=0
                exact_A(3*j+2,3*i)   = -Bx[i][j];
                exact_A(3*j+2,3*i+1) = -By[i][j];
            }
        }

        int lo, hi;
        MatGetOwnershipRange(mat, &lo, &hi);
        for (unsigned i=lo; i<(unsigned)hi; i++)
        {
            for (unsigned j=0; j<18; j++)
            {
                TS_ASSERT_DELTA(PetscMatTools::GetElement(mat,i,j), exact_A(i,j), 1e-9);
            }
        }
        ReplicatableVector vec_repl(vec);

        // The first 6 entries in the vector correspond to nodes 0, 1, 2, i.e. the vertices.
        // For these nodes, it can be shown that the integral of the corresponding
        // basis function is zero, i.e. \intgl_{canonical element} \phi_i dV = 0.0  for i=0,1,2, phi_i the
        // i-th QUADRATIC basis.
        for(unsigned i=0; i<3; i++)
        {
            TS_ASSERT_DELTA(vec_repl[3*i],   g1*0.0, 1e-8);
            TS_ASSERT_DELTA(vec_repl[3*i+1], g2*0.0, 1e-8);
        }

        // The next 6 entries in the vector correspond to nodes 3, 4, 5, i.e. the internal edges.
        // For these nodes, it can be shown that the integral of the corresponding
        // basis function is 1/6, i.e. \intgl_{canonical element} \phi_i dV = 1/6  for i=3,4,5, phi_i the
        // i-th QUADRATIC basis.
        for(unsigned i=3; i<6; i++)
        {
            TS_ASSERT_DELTA(vec_repl[3*i],   g1/6.0, 1e-8);
            TS_ASSERT_DELTA(vec_repl[3*i+1], g2/6.0, 1e-8);
        }

        // The pressure-block of the RHS vector should be zero.
        TS_ASSERT_DELTA(vec_repl[2], 0.0, 1e-9);
        TS_ASSERT_DELTA(vec_repl[5], 0.0, 1e-9);
        TS_ASSERT_DELTA(vec_repl[8], 0.0, 1e-9);
        TS_ASSERT_DELTA(vec_repl[11], 0.0, 1e-9);
        TS_ASSERT_DELTA(vec_repl[14], 0.0, 1e-9);
        TS_ASSERT_DELTA(vec_repl[17], 0.0, 1e-9);

        // Replace the body force with a functional body force (see MyBodyForce) above, and
        // assemble the vector again. This bit isn't so much to test the vector, but
        // to test the physical location being integrated at is interpolated correctly
        // and passed into the force function - see asserts in MyBodyForce.
        mesh.Translate(0.5, 0.8);

        Vec vec2 = PetscTools::CreateVec(18);
        assembler.SetVectorToAssemble(vec2, true);
        problem_defn.SetBodyForce(MyBodyForce);
        assembler.Assemble();

        ReplicatableVector vec_repl2(vec2);
        for(unsigned i=3; i<6; i++)
        {
            TS_ASSERT_DELTA(vec_repl2[3*i],   10.0/6.0, 1e-8);
            TS_ASSERT_DELTA(vec_repl2[3*i+1], 20.0/6.0, 1e-8);
        }

        PetscTools::Destroy(vec);
        PetscTools::Destroy(vec2);
        PetscTools::Destroy(mat);
    }