// MFEM Example 33 // // Compile with: make ex33p // // Sample runs: mpirun -np 4 ex33p -m ../data/square-disc.mesh -alpha 0.33 -o 2 // mpirun -np 4 ex33p -m ../data/star.mesh -alpha 0.99 -o 3 // mpirun -np 4 ex33p -m ../data/inline-quad.mesh -alpha 0.2 -o 3 // mpirun -np 4 ex33p -m ../data/disc-nurbs.mesh -alpha 0.33 -o 3 // mpirun -np 4 ex33p -m ../data/l-shape.mesh -alpha 0.33 -o 3 -r 4 // // // Description: // // In this example we solve the following fractional PDE with MFEM: // // ( - Δ )^α u = f in Ω, u = 0 on ∂Ω, 0 < α < 1, // // To solve this FPDE, we rely on a rational approximation [2] of the normal // linear operator A^{-α}, where A = - Δ (with associated homogenous // boundary conditions). Namely, we first approximate the operator // // A^{-α} ≈ Σ_{i=0}^N c_i (A + d_i I)^{-1}, d_0 = 0, d_i > 0, // // where I is the L2-identity operator and the coefficients c_i and d_i // are generated offline to a prescribed accuracy in a pre-processing step. // We use the triple-A algorithm [1] to generate the rational approximation // that this partial fractional expansion derives from. We then solve N+1 // independent integer-order PDEs, // // A u_i + d_i u_i = c_i f in Ω, u_i = 0 on ∂Ω, i=0,...,N, // // using MFEM and sum u_i to arrive at an approximate solution of the FPDE // // u ≈ Σ_{i=0}^N u_i. // // // References: // // [1] Nakatsukasa, Y., Sète, O., & Trefethen, L. N. (2018). The AAA algorithm // for rational approximation. SIAM Journal on Scientific Computing, 40(3), // A1494-A1522. // // [2] Harizanov, S., Lazarov, R., Margenov, S., Marinov, P., & Pasciak, J. // (2020). Analysis of numerical methods for spectral fractional elliptic // equations based on the best uniform rational approximation. Journal of // Computational Physics, 408, 109285. // #include "mfem.hpp" #include #include #include "ex33.hpp" using namespace std; using namespace mfem; int main(int argc, char *argv[]) { // 0. Initialize MPI. Mpi::Init(argc, argv); int num_procs = Mpi::WorldSize(); int myid = Mpi::WorldRank(); Hypre::Init(); // 1. Parse command-line options. const char *mesh_file = "../data/star.mesh"; int order = 1; int num_refs = 3; bool visualization = true; bool visualize_x = false; double alpha = 0.5; OptionsParser args(argc, argv); args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use."); args.AddOption(&order, "-o", "--order", "Finite element order (polynomial degree) or -1 for" " isoparametric space."); args.AddOption(&num_refs, "-r", "--refs", "Number of uniform refinements"); args.AddOption(&alpha, "-alpha", "--alpha", "Fractional exponent"); args.AddOption(&visualize_x, "-vis_x", "--visualize_x", "-no-vis_x", "--no-visualization_x", "Enable or disable GLVis visualization of each integer-order PDE solution."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization of the fractional PDE solution."); args.Parse(); if (!args.Good()) { args.PrintUsage(cout); return 1; } if (Mpi::Root()) { args.PrintOptions(cout); } Array coeffs, poles; // 2. Compute the coefficients that define the integer-order PDEs. ComputePartialFractionApproximation(alpha,coeffs,poles); int num_par_solves; int max_par_solves = max(1,num_procs/2); for (num_par_solves=max_par_solves; num_par_solves>0; num_par_solves--) { if (num_procs%num_par_solves==0 && num_par_solves ess_tdof_list; if (pmesh.bdr_attributes.Size()) { Array ess_bdr(pmesh.bdr_attributes.Max()); ess_bdr = 1; fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list); } // 8. Define diffusion coefficient, load, and solution GridFunction. ConstantCoefficient f(1.0); ConstantCoefficient one(1.0); ParGridFunction u(&fespace); ParGridFunction x(&fespace); u = 0.0; // 9. Set up the linear form b(.) for integer-order PDE solves. ParLinearForm b(&fespace); b.AddDomainIntegrator(new DomainLFIntegrator(f)); b.Assemble(); int my_coeff_size = max(coeffs.Size()/col_size,1); int ibeg = col_rank*my_coeff_size; if (ibeg + 2*my_coeff_size > coeffs.Size()) { my_coeff_size = coeffs.Size()-col_rank*my_coeff_size; } else if (ibeg > coeffs.Size() - 1) { my_coeff_size = 0; } int iend = ibeg+my_coeff_size; for (int i = ibeg; iSetPrintLevel(-1); int print_level = (col_rank==0) ? 3 : 0; if (Mpi::Root()) { mfem::out<< "\nMPI rank " << myid <<": Solving PDE -Δ u + "<<-poles[i]<< " u = " << coeffs[i] << " f " << endl; } CGSolver cg(row_comm); cg.SetRelTol(1e-12); cg.SetMaxIter(2000); cg.SetPrintLevel(print_level); cg.SetPreconditioner(*prec); cg.SetOperator(*A); cg.Mult(B, X); delete prec; // 14. Recover the solution as a finite element grid function. a.RecoverFEMSolution(X, b, x); // 15. Accumulate integer-order PDE solutions. x*=coeffs[i]; u+=x; // 16. Send integer-order PDE solutions to a GLVis server. if (visualize_x) { if (col_rank > 0 && i