int main (int argc, char *argv[]) { Mesh *mesh; SightInit(argc, argv, "ex1", "dbg.MFEM.ex2"); if (argc == 1) { cout << "\nUsage: ex2 <mesh_file>\n" << endl; return 1; } // 1. Read the mesh from the given mesh file. We can handle triangular, // quadrilateral, tetrahedral or hexahedral elements with the same code. ifstream imesh(argv[1]); if (!imesh) { cerr << "\nCan not open mesh file: " << argv[1] << '\n' << endl; return 2; } mesh = new Mesh(imesh, 1, 1); imesh.close(); if (mesh->attributes.Max() < 2 || mesh->bdr_attributes.Max() < 2) { cerr << "\nInput mesh should have at least two materials and " << "two boundary attributes! (See schematic in ex2.cpp)\n" << endl; return 3; } int dim = mesh->Dimension(); // 2. Select the order of the finite element discretization space. For NURBS // meshes, we increase the order by degree elevation. int p; if(argc==3) p = atoi(argv[2]); else { cout << "Enter finite element space order --> " << flush; cin >> p; } if (mesh->NURBSext && p > mesh->NURBSext->GetOrder()) mesh->DegreeElevate(p - mesh->NURBSext->GetOrder()); // 3. Refine the mesh to increase the resolution. In this example we do // 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the // largest number that gives a final mesh with no more than 5,000 // elements. { int ref_levels = (int)floor(log(5000./mesh->GetNE())/log(2.)/dim); for (int l = 0; l < ref_levels; l++) mesh->UniformRefinement(); } // 4. Define a finite element space on the mesh. Here we use vector finite // elements, i.e. dim copies of a scalar finite element space. The vector // dimension is specified by the last argument of the FiniteElementSpace // constructor. For NURBS meshes, we use the (degree elevated) NURBS space // associated with the mesh nodes. FiniteElementCollection *fec; FiniteElementSpace *fespace; if (mesh->NURBSext) { fec = NULL; fespace = mesh->GetNodes()->FESpace(); } else { fec = new H1_FECollection(p, dim); fespace = new FiniteElementSpace(mesh, fec, dim); } dbg << "Number of unknowns: " << fespace->GetVSize() << endl << "Assembling: " << flush; // 5. Set up the linear form b(.) which corresponds to the right-hand side of // the FEM linear system. In this case, b_i equals the boundary integral // of f*phi_i where f represents a "pull down" force on the Neumann part // of the boundary and phi_i are the basis functions in the finite element // fespace. The force is defined by the VectorArrayCoefficient object f, // which is a vector of Coefficient objects. The fact that f is non-zero // on boundary attribute 2 is indicated by the use of piece-wise constants // coefficient for its last component. VectorArrayCoefficient f(dim); for (int i = 0; i < dim-1; i++) f.Set(i, new ConstantCoefficient(0.0)); { Vector pull_force(mesh->bdr_attributes.Max()); pull_force = 0.0; pull_force(1) = -1.0e-2; f.Set(dim-1, new PWConstCoefficient(pull_force)); } LinearForm *b = new LinearForm(fespace); b->AddBoundaryIntegrator(new VectorBoundaryLFIntegrator(f)); dbg << "r.h.s. ... " << flush; b->Assemble(); // 6. Define the solution vector x as a finite element grid function // corresponding to fespace. Initialize x with initial guess of zero, // which satisfies the boundary conditions. GridFunction x(fespace); x = 0.0; // 7. Set up the bilinear form a(.,.) on the finite element space // corresponding to the linear elasticity integrator with piece-wise // constants coefficient lambda and mu. The boundary conditions are // implemented by marking only boundary attribute 1 as essential. After // assembly and finalizing we extract the corresponding sparse matrix A. Vector lambda(mesh->attributes.Max()); lambda = 1.0; lambda(0) = lambda(1)*50; PWConstCoefficient lambda_func(lambda); Vector mu(mesh->attributes.Max()); mu = 1.0; mu(0) = mu(1)*50; PWConstCoefficient mu_func(mu); BilinearForm *a = new BilinearForm(fespace); a->AddDomainIntegrator(new ElasticityIntegrator(lambda_func,mu_func)); dbg << "matrix ... " << flush; a->Assemble(); Array<int> ess_bdr(mesh->bdr_attributes.Max()); ess_bdr = 0; ess_bdr[0] = 1; a->EliminateEssentialBC(ess_bdr, x, *b); a->Finalize(); dbg << "done." << endl; const SparseMatrix &A = a->SpMat(); // 8. Define a simple symmetric Gauss-Seidel preconditioner and use it to // solve the system Ax=b with PCG. GSSmoother M(A); PCG(A, M, *b, x, 1, 500, 1e-8, 0.0); // 9. For non-NURBS meshes, make the mesh curved based on the finite element // space. This means that we define the mesh elements through a fespace // based transformation of the reference element. This allows us to save // the displaced mesh as a curved mesh when using high-order finite // element displacement field. We assume that the initial mesh (read from // the file) is not higher order curved mesh compared to the chosen FE // space. if (!mesh->NURBSext) mesh->SetNodalFESpace(fespace); // 10. Save the displaced mesh and the inverted solution (which gives the // backward displacements to the original grid). This output can be // viewed later using GLVis: "glvis -m displaced.mesh -g sol.gf". { GridFunction *nodes = mesh->GetNodes(); *nodes += x; x *= -1; ofstream mesh_ofs("displaced.mesh"); mesh_ofs.precision(8); mesh->Print(mesh_ofs); ofstream sol_ofs("sol.gf"); sol_ofs.precision(8); x.Save(sol_ofs); } // 11. (Optional) Send the above data by socket to a GLVis server. Use the // "n" and "b" keys in GLVis to visualize the displacements. /*char vishost[] = "localhost"; int visport = 19916; osockstream sol_sock(visport, vishost); sol_sock << "solution\n"; sol_sock.precision(8); mesh->Print(sol_sock); x.Save(sol_sock); sol_sock.send();*/ #if defined(VNC_ENABLED) mfem::emitMesh(mesh, &x); #endif // 12. Free the used memory. delete a; delete b; if (fec) { delete fespace; delete fec; } delete mesh; return 0; }
int main (int argc, char *argv[]) { SightInit(argc, argv, "ex3", "dbg.MFEM.ex3"); Mesh *mesh; if (argc == 1) { cerr << "\nUsage: ex3 <mesh_file>\n" << endl; return 1; } // 1. Read the mesh from the given mesh file. In this 3D example, we can // handle tetrahedral or hexahedral meshes with the same code. ifstream imesh(argv[1]); if (!imesh) { cerr << "\nCan not open mesh file: " << argv[1] << '\n' << endl; return 2; } mesh = new Mesh(imesh, 1, 1); imesh.close(); if (mesh -> Dimension() != 3) { cerr << "\nThis example requires a 3D mesh\n" << endl; return 3; } // 2. Refine the mesh to increase the resolution. In this example we do // 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the // largest number that gives a final mesh with no more than 50,000 // elements. { int ref_levels = (int)floor(log(50000./mesh->GetNE())/log(2.)/mesh->Dimension()); for (int l = 0; l < ref_levels; l++) mesh->UniformRefinement(); } // 3. Define a finite element space on the mesh. Here we use the lowest order // Nedelec finite elements, but we can easily swich to higher-order spaces // by changing the value of p. int p = 1; FiniteElementCollection *fec = new ND_FECollection(p, mesh -> Dimension()); FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec); dbg << "Number of unknowns: " << fespace->GetVSize() << endl; // 4. Set up the linear form b(.) which corresponds to the right-hand side // of the FEM linear system, which in this case is (f,phi_i) where f is // given by the function f_exact and phi_i are the basis functions in the // finite element fespace. VectorFunctionCoefficient f(3, f_exact); LinearForm *b = new LinearForm(fespace); b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f)); b->Assemble(); // 5. Define the solution vector x as a finite element grid function // corresponding to fespace. Initialize x by projecting the exact // solution. Note that only values from the boundary edges will be used // when eliminating the non-homogenious boundary condition to modify the // r.h.s. vector b. GridFunction x(fespace); VectorFunctionCoefficient E(3, E_exact); x.ProjectCoefficient(E); // 6. Set up the bilinear form corresponding to the EM diffusion operator // curl muinv curl + sigma I, by adding the curl-curl and the mass domain // integrators and finally imposing the non-homogeneous Dirichlet boundary // conditions. The boundary conditions are implemented by marking all the // boundary attributes from the mesh as essential (Dirichlet). After // assembly and finalizing we extract the corresponding sparse matrix A. Coefficient *muinv = new ConstantCoefficient(1.0); Coefficient *sigma = new ConstantCoefficient(1.0); BilinearForm *a = new BilinearForm(fespace); a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv)); a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma)); a->Assemble(); Array<int> ess_bdr(mesh->bdr_attributes.Max()); ess_bdr = 1; a->EliminateEssentialBC(ess_bdr, x, *b); a->Finalize(); const SparseMatrix &A = a->SpMat(); // 7. Define a simple symmetric Gauss-Seidel preconditioner and use it to // solve the system Ax=b with PCG. GSSmoother M(A); x = 0.0; PCG(A, M, *b, x, 1, 500, 1e-12, 0.0); // 8. Compute and print the L^2 norm of the error. dbg << "\n|| E_h - E ||_{L^2} = " << x.ComputeL2Error(E) << '\n' << endl; // 9. Save the refined mesh and the solution. This output can be viewed // later using GLVis: "glvis -m refined.mesh -g sol.gf". { ofstream mesh_ofs("refined.mesh"); mesh_ofs.precision(8); mesh->Print(mesh_ofs); ofstream sol_ofs("sol.gf"); sol_ofs.precision(8); x.Save(sol_ofs); } // 10. (Optional) Send the solution by socket to a GLVis server. /*char vishost[] = "localhost"; int visport = 19916; osockstream sol_sock(visport, vishost); sol_sock << "solution\n"; sol_sock.precision(8); mesh->Print(sol_sock); x.Save(sol_sock); sol_sock.send();*/ #if defined(VNC_ENABLED) mfem::emitMesh(mesh, &x); #endif // 11. Free the used memory. delete a; delete sigma; delete muinv; delete b; delete fespace; delete fec; delete mesh; return 0; }