MFEM v2.0
ex4.cpp
Go to the documentation of this file.
00001 //                                MFEM Example 4
00002 //
00003 // Compile with: make ex4
00004 //
00005 // Sample runs:  ex4 ../data/square-disc.mesh
00006 //               ex4 ../data/star.mesh
00007 //               ex4 ../data/beam-tet.mesh
00008 //               ex4 ../data/beam-hex.mesh
00009 //               ex4 ../data/escher.mesh
00010 //               ex4 ../data/fichera.mesh
00011 //               ex4 ../data/fichera-q2.vtk
00012 //               ex4 ../data/fichera-q3.mesh
00013 //               ex4 ../data/square-disc-nurbs.mesh
00014 //               ex4 ../data/beam-hex-nurbs.mesh
00015 //
00016 // Description:  This example code solves a simple 2D/3D H(div) diffusion
00017 //               problem corresponding to the second order definite equation
00018 //               -grad(alpha div F) + beta F = f with boundary condition F dot n
00019 //               = <given normal field>. Here, we use a given exact solution F
00020 //               and compute the corresponding r.h.s. f.  We discretize with the
00021 //               Raviart-Thomas finite elements.
00022 //
00023 //               The example demonstrates the use of H(div) finite element
00024 //               spaces with the grad-div and H(div) vector finite element mass
00025 //               bilinear form, as well as the computation of discretization
00026 //               error when the exact solution is known.
00027 //
00028 //               We recommend viewing examples 1-3 before viewing this example.
00029 
00030 #include <fstream>
00031 #include "mfem.hpp"
00032 
00033 // Exact solution, F, and r.h.s., f. See below for implementation.
00034 void F_exact(const Vector &, Vector &);
00035 void f_exact(const Vector &, Vector &);
00036 
00037 int main (int argc, char *argv[])
00038 {
00039    Mesh *mesh;
00040 
00041    if (argc == 1)
00042    {
00043       cout << "\nUsage: ex4 <mesh_file>\n" << endl;
00044       return 1;
00045    }
00046 
00047    // 1. Read the 2D or 3D mesh from the given mesh file. In this example, we
00048    //    can handle triangular, quadrilateral, tetrahedral or hexahedral meshes
00049    //    with the same code.
00050    ifstream imesh(argv[1]);
00051    if (!imesh)
00052    {
00053       cerr << "\nCan not open mesh file: " << argv[1] << '\n' << endl;
00054       return 2;
00055    }
00056    mesh = new Mesh(imesh, 1, 1);
00057    imesh.close();
00058 
00059    const int dim = mesh->Dimension();
00060 
00061    // 2. Refine the mesh to increase the resolution. In this example we do
00062    //    'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
00063    //    largest number that gives a final mesh with no more than 25,000
00064    //    elements.
00065    {
00066       int ref_levels =
00067          (int)floor(log(25000./mesh->GetNE())/log(2.)/dim);
00068       for (int l = 0; l < ref_levels; l++)
00069          mesh->UniformRefinement();
00070    }
00071 
00072    // 3. Define a finite element space on the mesh. Here we use the lowest order
00073    //    Raviart-Thomas finite elements, but we can easily swich to higher-order
00074    //    spaces by changing the value of p.
00075    int p = 1;
00076    FiniteElementCollection *fec = new RT_FECollection(p-1, mesh -> Dimension());
00077    FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
00078    cout << "Number of unknowns: " << fespace->GetVSize() << endl;
00079 
00080    // 4. Set up the linear form b(.) which corresponds to the right-hand side
00081    //    of the FEM linear system, which in this case is (f,phi_i) where f is
00082    //    given by the function f_exact and phi_i are the basis functions in the
00083    //    finite element fespace.
00084    VectorFunctionCoefficient f(dim, f_exact);
00085    LinearForm *b = new LinearForm(fespace);
00086    b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
00087    b->Assemble();
00088 
00089    // 5. Define the solution vector x as a finite element grid function
00090    //    corresponding to fespace. Initialize x by projecting the exact
00091    //    solution. Note that only values from the boundary faces will be used
00092    //    when eliminating the non-homogenious boundary condition to modify the
00093    //    r.h.s. vector b.
00094    GridFunction x(fespace);
00095    VectorFunctionCoefficient F(dim, F_exact);
00096    x.ProjectCoefficient(F);
00097 
00098    // 6. Set up the bilinear form corresponding to the H(div) diffusion operator
00099    //    grad alpha div + beta I, by adding the div-div and the mass domain
00100    //    integrators and finally imposing the non-homogeneous Dirichlet boundary
00101    //    conditions. The boundary conditions are implemented by marking all the
00102    //    boundary attributes from the mesh as essential (Dirichlet). After
00103    //    assembly and finalizing we extract the corresponding sparse matrix A.
00104    Coefficient *alpha = new ConstantCoefficient(1.0);
00105    Coefficient *beta  = new ConstantCoefficient(1.0);
00106    BilinearForm *a = new BilinearForm(fespace);
00107    a->AddDomainIntegrator(new DivDivIntegrator(*alpha));
00108    a->AddDomainIntegrator(new VectorFEMassIntegrator(*beta));
00109    a->Assemble();
00110    Array<int> ess_bdr(mesh->bdr_attributes.Max());
00111    ess_bdr = 1;
00112    a->EliminateEssentialBC(ess_bdr, x, *b);
00113    a->Finalize();
00114    const SparseMatrix &A = a->SpMat();
00115 
00116    // 7. Define a simple symmetric Gauss-Seidel preconditioner and use it to
00117    //    solve the system Ax=b with PCG.
00118    GSSmoother M(A);
00119    x = 0.0;
00120    PCG(A, M, *b, x, 1, 10000, 1e-20, 0.0);
00121 
00122    // 8. Compute and print the L^2 norm of the error.
00123    cout << "\n|| F_h - F ||_{L^2} = " << x.ComputeL2Error(F) << '\n' << endl;
00124 
00125    // 9. Save the refined mesh and the solution. This output can be viewed
00126    //    later using GLVis: "glvis -m refined.mesh -g sol.gf".
00127    {
00128       ofstream mesh_ofs("refined.mesh");
00129       mesh_ofs.precision(8);
00130       mesh->Print(mesh_ofs);
00131       ofstream sol_ofs("sol.gf");
00132       sol_ofs.precision(8);
00133       x.Save(sol_ofs);
00134    }
00135 
00136    // 11. (Optional) Send the solution by socket to a GLVis server.
00137    char vishost[] = "localhost";
00138    int  visport   = 19916;
00139    osockstream sol_sock(visport, vishost);
00140    sol_sock << "solution\n";
00141    sol_sock.precision(8);
00142    mesh->Print(sol_sock);
00143    x.Save(sol_sock);
00144    sol_sock.send();
00145 
00146    // 12. Free the used memory.
00147    delete a;
00148    delete alpha;
00149    delete beta;
00150    delete b;
00151    delete fespace;
00152    delete fec;
00153    delete mesh;
00154 
00155    return 0;
00156 }
00157 
00158 
00159 // The exact solution
00160 void F_exact(const Vector &p, Vector &F)
00161 {
00162    double x,y,z;
00163 
00164    int dim = p.Size();
00165 
00166    x = p(0);
00167    y = p(1);
00168    if(dim == 3)
00169       z = p(2);
00170 
00171    F(0) = cos(M_PI*x)*sin(M_PI*y);
00172    F(1) = cos(M_PI*y)*sin(M_PI*x);
00173    if(dim == 3)
00174       F(2) = 0.0;
00175 }
00176 
00177 // The right hand side
00178 void f_exact(const Vector &p, Vector &f)
00179 {
00180    double x,y,z;
00181 
00182    int dim = p.Size();
00183 
00184    x = p(0);
00185    y = p(1);
00186    if(dim == 3)
00187       z = p(2);
00188 
00189    double temp = 1 + 2*M_PI*M_PI;
00190 
00191    f(0) = temp*cos(M_PI*x)*sin(M_PI*y);
00192    f(1) = temp*cos(M_PI*y)*sin(M_PI*x);
00193    if(dim == 3)
00194       f(2) = 0;
00195 }
00196 
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines