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); }