After reading the command line arguments, we define the problem specification (domain, right-hand side, function for boundary conditions, functions for CDR equation) for the chosen benchmark problem (option –Benchmark
).
gsFunctionExpr<> sol_exact, rhs_exact, coeff_diff, coeff_conv, coeff_reac;
gsMultiPatch<> mp;
gsInfo <<
"|| Benchmark information ||\n";
switch (numBenchmark)
{
case 1:
gsInfo <<
"1) CDR-equation the unit square\n";
mp = gsMultiPatch<>(*gsNurbsCreator<>::BSplineSquare(1.0, 0.0, 0.0));
sol_exact = gsFunctionExpr<>("sin(pi*x)*sin(pi*y)",2);
rhs_exact = gsFunctionExpr<>("1.2*pi*pi*sin(pi*x)*sin(pi*y)+0.9*pi*pi*sin(pi*x)*sin(pi*y)+0.7*pi*pi*cos(pi*x)*cos(pi*y)"
" + 0.4*pi*pi*cos(pi*x)*cos(pi*y) +0.4*pi*cos(pi*x)*sin(pi*y)-0.2*pi*sin(pi*x)*cos(pi*y)+0.3*sin(pi*x)*sin(pi*y)", 2);
coeff_diff = gsFunctionExpr<>("1.2","-0.7","-0.4","0.9",2);
coeff_conv = gsFunctionExpr<>("0.4","-0.2",2);
coeff_reac = gsFunctionExpr<>("0.3",2);
break;
case 2:
gsInfo <<
"2) Poisson equation on the quarter annulus\n";
sol_exact = gsFunctionExpr<>( "-(x*x+y*y-1)*(x*x+y*y-4)*x*y*y", 2);
rhs_exact = gsFunctionExpr<>( "2*x*(22*x*x*y*y+21*y*y*y*y-45*y*y+x*x*x*x-5*x*x+4)", 2);
coeff_diff = gsFunctionExpr<>("1","0","0","1",2);
coeff_conv = gsFunctionExpr<>("0","0",2);
coeff_reac = gsFunctionExpr<>("0",2);
break;
case 3:
gsInfo <<
"3) Poisson equation on the quarter annulus\n";
sol_exact = gsFunctionExpr<>( "(x^2+y^2-3*sqrt(x^2+y^2)+2)*sin(2*atan(y/x))", 2);
rhs_exact = gsFunctionExpr<>( "(8-9*sqrt(x^2 + y^2))*sin(2*atan(y/x))/(x^2+y^2)", 2);
coeff_diff = gsFunctionExpr<>("1","0","0","1",2);
coeff_conv = gsFunctionExpr<>("0","0",2);
coeff_reac = gsFunctionExpr<>("0",2);
break;
case 4:
gsInfo <<
"4) Poisson equation on an L-shaped domain\n";
sol_exact = gsFunctionExpr<>( "if ( y>0, ( (x^2+y^2)^(1.0/3.0) )*sin( (2*atan2(y,x) - pi)/3.0 ), ( (x^2+y^2)^(1.0/3.0) )*sin( (2*atan2(y,x) +3*pi)/3.0 ) )", 2);
rhs_exact = gsFunctionExpr<>( "0", 2);
coeff_diff = gsFunctionExpr<>("1","0","0","1",2);
coeff_conv = gsFunctionExpr<>("0","0",2);
coeff_reac = gsFunctionExpr<>("0",2);
break;
case 5:
gsInfo <<
"5) Poisson equation on the unit cube\n";
sol_exact = gsFunctionExpr<>( "sin(pi*x)*sin(pi*y)*sin(pi*z)", 3);
rhs_exact = gsFunctionExpr<>( "(3*pi^2)*sin(pi*x)*sin(pi*y)*sin(pi*z)", 3);
coeff_diff = gsFunctionExpr<>("1","0","0","0","1","0","0","0","1",3);
coeff_conv = gsFunctionExpr<>("0","0","0",3);
coeff_reac = gsFunctionExpr<>("0",3);
break;
case 6:
gsInfo <<
"6) Poisson's equation on Yeti footprint\n";
sol_exact = gsFunctionExpr<>( "sin(5*pi*x)*sin(5*pi*y)", 2);
rhs_exact = gsFunctionExpr<>( "(50*pi^2)*sin(5*pi*x)*sin(5*pi*y)", 2);
coeff_diff = gsFunctionExpr<>("1","0","0","1",2);
coeff_conv = gsFunctionExpr<>("0","0",2);
coeff_reac = gsFunctionExpr<>("0",2);
break;
default:
gsInfo <<
"Unknown benchmark case chosen.\n";
return EXIT_FAILURE;
}
memory::unique_ptr< gsMultiPatch > uPtr
Unique pointer for gsMultiPatch.
Definition gsMultiPatch.h:109
#define gsInfo
Definition gsDebug.h:43
static TensorBSpline2Ptr BSplineLShape_p1(T r=(T)(1))
L-Shaped domain represented as a tensor B-spline of degree 1.
Definition gsNurbsCreator.hpp:1262
static TensorBSpline3Ptr BSplineCube(T const &r=1, T const &x=0, T const &y=0, T const &z=0)
Cube of side r, with lower left corner at (x,y,z)
Definition gsNurbsCreator.hpp:731
static TensorBSpline2Ptr BSplineFatQuarterAnnulus(T const &r0=1, T const &r1=2)
Definition gsNurbsCreator.hpp:949
We define the boundary conditions object with the function containing the corresponding Dirichlet data.
We now compute the parameters for the coarsest grid such that the finest grid is as prescribed using the parameters –Degree
and –Refinement
.
The next step is the setup of the refinement and prolongation operators. In case of h-coarsening, the prolongation is the canonical embedding matrix and the restriction is its transpose.
In case of p- and z-coarsening, the method depends on the lumping type specified by –Lumping
.
In case of lumping type 1, the restriction and the prolongation are the corresponding \(L_2\)-orthogonal projectors, given by
\[
M_{\ell-1}^{-1} M_{\ell-1,\ell}
\quad\mbox{and}\quad
M_{\ell}^{-1} M_{\ell,\ell-1}
\]
respectively. Here, \( M_{\ell} \) and \( M_{\ell-1} \) are the mass matrices on those grid levels (assembleMass). \( M_{\ell-1,\ell} = M_{\ell,\ell-1}^\top \) is obtained by deriving a mass matrix with the basis functions for the level \(\ell-1\) as trial functions and the basis functions for the level \(\ell\) as test functions (assembleMixedMass). The realization of the inverses is done by applying a conjugate gradient solver.
In case of lumping type 2, the matrices \( M_{\ell} \) and \( M_{\ell-1} \) are replaced by diagonal matrices, where the diagonal entries coincide with the row-sum of the \( M_{\ell} \) or \( M_{\ell-1} \), respectively. Using the partition-of-unity property, these diagonal entries are obtained by evaluating \( (\cdot,1)_{L_2(\Omega)} \) for the basis functions (assembleLumpedMass).
For a p-multigrid method, one has to assemble the problem for the individual levels. The assembler is used to derive the stiffness matrix for the finest level, the spline degree on the corresponding level is different to the level on the next finer level, or rediscretization is explicitly requested (using –CoarseOperator 1
). Otherwise, Galerkin projections are used.
In the first case, the stiffness matrices on the finer grids are derived automatically using a Galerkin projection.
Since we have a vector of stiffness matrices and since our restrictions and prolongations might not be just matrices, we need to use the second option.
Next, we choose the type of the cycle (1=V-cycle, 2=W-cycle). Here, we can use different options, depending if the coarsening is a h-coarsening or a coarsening which involves a change of the degree (p- or z-coarsening).
The next step is the setup of the smoothers. As smoothers, one can choose an incomplete LU smoother (–Smoother 1
), a blockwise incomplete LU smoother (–Smoother 4
), the subspace corrected mass smoother (–Smoother 3
; see multiGrid_example.cpp) the Gauss-Seidel smoother (–Smoother 2
). For the levels with spline degree 1, always the Gauss-Seidel smoother is used. For the setup, we use a for loop over the levels 1,...,numLevels. On level 0, we use a direct solver.
Moreover, we specify the number of pre and post smoothing steps (default: 1), as given via command –Smoothing
.
Next, we initialize the chosen iterative solver.
We choose a random initial guess.
Finally, we use the iterative solver to solve the problem. We use solveDetailed with an errorHistory
in order to be able to give the convergence behavior.
#include <string>
);
);
);
);
);
int main(int argc, char* argv[])
{
std::string typeCoarsening;
real_t dampingSCMS = 1;
real_t tol = 1e-8;
gsCmdLine cmd(
"This program solves the CDR-equation with a p-multigrid or h-multigrid method");
cmd.addInt("b", "Benchmark", "Number of the benchmark problem", numBenchmark);
cmd.addInt("P", "PatchSplits", "Number of patch splittings: split each patch that many times into 2^d patches", numSplits);
cmd.addInt("p", "Degree", "Spline degree for finest grid", numDegree);
cmd.addInt("r", "Refinement", "Number of global refinements to obtain finest grid", numRefine);
cmd.addInt("d", "BCHandling", "Handle Dirichlet BC's by (1) elimination or (2) Nitsche's method", typeBCHandling);
cmd.addInt("l", "Levels", "Number of levels for multigrid", numLevels);
cmd.addInt("D", "Projection", "A p or z coarsening refers to (1) changing the degree directly to 1 or (2) reducing the degree by 1", typeProjection);
cmd.addString("z", "Coarsening", "Coarsening strategy for each of the levels: (h) coarser grid, (p) reduced spline degree or (z) both", typeCoarsening);
cmd.addInt("L", "Lumping", "Restriction and prolongation performed with the (1) lumped or (2) full mass matrix", typeLumping);
cmd.addInt("G", "CoarseOperator", "Derive coarse stiffness matrix (1) by rediscretization or (2) using Galerkin projection if possible", typeCoarseOperator);
cmd.addInt("m", "Cycle_p", "Type of cycle where p or z-coarsening is applied: (1) V-cycle or (2) W-cycle", typeCycle_p);
cmd.addInt("M", "Cycle_h", "Type of cycle where h-coarsening is applied: (1) V-cycle or (2) W-cycle", typeCycle_h);
cmd.addInt("S", "Smoother", "Smoother: (1) ILUT, (2) Gauss-Seidel, (3) subspace corrected mass smoother or (4) Block ILUT", typeSmoother);
cmd.addInt("v", "Smoothing", "Number of pre and post smoothing steps", numSmoothing);
cmd.addReal("", "DampingSCMS", "Damping for subspace corrected mass smoother (otherwise ignored)", dampingSCMS);
cmd.addInt("s", "Solver", "Solver: (1) mg as stand-alone solver, (2) BiCGStab prec. with mg or (3) CG prec. with mg", typeSolver);
cmd.addReal("", "Tolerance", "Threshold for iterative solver", tol);
cmd.addInt("", "MaxIter", "Maximum number of iterations for iterative solver", maxIter);
try { cmd.getValues(argc,argv); } catch (int rv) { return rv; }
if (numDegree<=0)
{
gsInfo <<
"--Degree has to be a positive value.\n";
return EXIT_FAILURE;
}
if (numRefine<0)
{
gsInfo <<
"--Refinement has to be a non-negative value.\n";
return EXIT_FAILURE;
}
if (numSmoothing<0)
{
gsInfo <<
"--Smoothing has to be a non-negative value.\n";
return EXIT_FAILURE;
}
if (numLevels<=0)
{
gsInfo <<
"--Levels has to be a positive value.\n";
return EXIT_FAILURE;
}
if (numSplits<0)
{
gsInfo <<
"--PatchSplits has to be a non-negative value.\n";
return EXIT_FAILURE;
}
if (typeCycle_p<=0 || typeCycle_h<=0)
{
gsInfo <<
"--Cycle_p and Cycle_h have to be a positvie value.\n";
return EXIT_FAILURE;
}
switch (typeBCHandling)
{
case 1:
opt.
addInt(
"DirichletStrategy",
"",dirichlet::elimination);
break;
case 2:
opt.
addInt(
"DirichletStrategy",
"",dirichlet::nitsche );
break;
default:
gsInfo <<
"Unknown boundary condition handling type chosen.\n";
return EXIT_FAILURE;
}
if (typeLumping < 1 || typeLumping > 2)
{
gsInfo <<
"Unknown lumping type chosen.\n";
return -1;
}
if (typeProjection < 1 || typeProjection > 2)
{
gsInfo <<
"Unknown projection type chosen.\n";
return -1;
}
if (typeCoarseOperator < 1 || typeCoarseOperator > 2)
{
gsInfo <<
"Unknown coarse operator chosen.\n";
return -1;
}
gsInfo <<
"|| Benchmark information ||\n";
switch (numBenchmark)
{
case 1:
gsInfo <<
"1) CDR-equation the unit square\n";
rhs_exact =
gsFunctionExpr<>(
"1.2*pi*pi*sin(pi*x)*sin(pi*y)+0.9*pi*pi*sin(pi*x)*sin(pi*y)+0.7*pi*pi*cos(pi*x)*cos(pi*y)"
" + 0.4*pi*pi*cos(pi*x)*cos(pi*y) +0.4*pi*cos(pi*x)*sin(pi*y)-0.2*pi*sin(pi*x)*cos(pi*y)+0.3*sin(pi*x)*sin(pi*y)", 2);
break;
case 2:
gsInfo <<
"2) Poisson equation on the quarter annulus\n";
rhs_exact =
gsFunctionExpr<>(
"2*x*(22*x*x*y*y+21*y*y*y*y-45*y*y+x*x*x*x-5*x*x+4)", 2);
break;
case 3:
gsInfo <<
"3) Poisson equation on the quarter annulus\n";
sol_exact =
gsFunctionExpr<>(
"(x^2+y^2-3*sqrt(x^2+y^2)+2)*sin(2*atan(y/x))", 2);
rhs_exact =
gsFunctionExpr<>(
"(8-9*sqrt(x^2 + y^2))*sin(2*atan(y/x))/(x^2+y^2)", 2);
break;
case 4:
gsInfo <<
"4) Poisson equation on an L-shaped domain\n";
sol_exact =
gsFunctionExpr<>(
"if ( y>0, ( (x^2+y^2)^(1.0/3.0) )*sin( (2*atan2(y,x) - pi)/3.0 ), ( (x^2+y^2)^(1.0/3.0) )*sin( (2*atan2(y,x) +3*pi)/3.0 ) )", 2);
break;
case 5:
gsInfo <<
"5) Poisson equation on the unit cube\n";
break;
case 6:
gsInfo <<
"6) Poisson's equation on Yeti footprint\n";
break;
default:
gsInfo <<
"Unknown benchmark case chosen.\n";
return EXIT_FAILURE;
}
gsInfo <<
"Exact solution: " << sol_exact <<
"\n";
gsInfo <<
"Right hand side: " << rhs_exact <<
"\n";
gsInfo <<
"Handling of boundary conditions: " << (typeBCHandling==1 ?
"elimination" :
"Nitsche") <<
"\n";
for (
index_t i=0; i<numSplits; ++i)
mp = mp.uniformSplit();
gsInfo <<
"Number of patches: " << mp.nPatches() <<
"\n\n";
for (gsMultiPatch<>::const_biterator bit = mp.bBegin(); bit != mp.bEnd(); ++bit)
if (typeCoarsening.empty())
{
if (typeProjection==1)
{
typeCoarsening = std::string(numLevels-2, 'h') + "z";
}
else
{
if (numLevels>numDegree)
typeCoarsening = std::string(numLevels-numDegree, 'h') + std::string(numDegree-1, 'z');
else
typeCoarsening = std::string(numLevels-1, 'z');
}
}
if (typeCoarsening.size() != (size_t)numLevels-1)
{
gsInfo <<
"The string provided to --Coarsening should have length " << numLevels-1 <<
"\n";
return EXIT_FAILURE;
}
index_t numRefH = 0, numRefP = 0, numRefZ = 0;
for (
index_t i = 0; i < numLevels-1; ++i)
{
if ( typeCoarsening[i] == 'h')
numRefH++;
else if ( typeCoarsening[i] == 'p')
numRefP++;
else if ( typeCoarsening[i] == 'z')
numRefZ++;
else
{
gsInfo <<
"Unknown type given in --Coarsening.\n";
return EXIT_FAILURE;
}
}
if (typeProjection==1 && numRefP+numRefZ > 1)
{
gsInfo <<
"If --Projection 1, there should be only one coarsening of type p or z in --Coarsening.\n";
return EXIT_FAILURE;
}
if (numRefine - numRefH - numRefZ<0)
{
gsInfo <<
"Cannot have more h or z refinements in --Coarsening than overall number of refinement steps.\n";
return EXIT_FAILURE;
}
std::vector<gsMultiBasis<>> bases;
bases.emplace_back(mp);
const index_t degreeOffset = numDegree - (numRefP+numRefZ) * (typeProjection==1?(numDegree-1):1) - bases[0].degree();
if (degreeOffset>0)
bases[0].degreeIncrease(degreeOffset);
else if (degreeOffset<0)
bases[0].degreeReduce(-degreeOffset);
for (
index_t i = 0; i < numRefine - numRefH - numRefZ; ++i)
bases[0].uniformRefine();
for (
index_t i = 1; i < numLevels; i++)
{
bases.push_back(bases.back());
if (typeCoarsening[i-1] == 'p')
{
if (typeProjection == 1)
bases.back().degreeIncrease(numDegree-1);
else
bases.back().degreeIncrease();
}
else if (typeCoarsening[i-1] == 'h')
{
bases.back().uniformRefine();
}
else
{
bases.back().uniformRefine();
if (typeProjection == 1)
bases.back().degreeIncrease(numDegree-1);
else
bases.back().degreeIncrease();
}
}
std::vector<gsSparseMatrix<real_t,RowMajor>> prolongation_H(numLevels-1);
std::vector<gsLinearOperator<>::Ptr> restriction(numLevels-1);
std::vector<gsLinearOperator<>::Ptr> prolongation(numLevels-1);
gsInfo <<
"|| Multigrid hierarchy ||\n";
for (
index_t i=1; i<numLevels; i++)
{
if (typeCoarsening[i-1] != 'h')
{
if (typeLumping == 1)
{
gsInfo <<
"Restriction and prolongation between levels " << i <<
" and " << i-1 <<
": L2-projection with lumped mass.\n";
gsSparseMatrix<> mixedMass = assembleMixedMass(mp, bases[i], bases[i-1], bcInfo, opt);
= assembleLumpedMass(mp, bases[i], bcInfo, opt).asDiagonal().inverse()
* mixedMass;
= assembleLumpedMass(mp, bases[i-1], bcInfo, opt).asDiagonal().inverse()
* mixedMass.transpose();
prolongation[i-1] = makeMatrixOp(prolongationMatrix.
moveToPtr());
restriction[i-1] = makeMatrixOp(restrictionMatrix.
moveToPtr());
}
else
{
gsInfo <<
"Restriction and prolongation between levels " << i <<
" and " << i-1 <<
": exact L2-projection.\n";
gsSparseMatrix<> prolongationP = assembleMixedMass(mp, bases[i], bases[i-1], bcInfo, opt);
prolongation[i-1] = makeLinearOp(
[prolongationP=
give(prolongationP),prolongationM=
give(prolongationM)]
{
CGSolver.setTolerance(1e-12);
CGSolver.solve(prolongationP*Xcoarse,Xfine);
},
prolongationP.rows(), prolongationP.cols()
);
restriction[i-1] = makeLinearOp(
[restrictionP=
give(restrictionP),restrictionM=
give(restrictionM)]
{
CGSolver.setTolerance(1e-12);
CGSolver.solve(restrictionP*Xfine,Xcoarse);
},
restrictionP.rows(), restrictionP.cols()
);
}
}
else
{
gsInfo <<
"Restriction and prolongation between levels " << i <<
" and " << i-1 <<
": canonical embedding and its transpose.\n";
bases[i].clone()->uniformCoarsen_withTransfer(prolongation_H[i-1],bcInfo,opt);
prolongation[i-1] = makeMatrixOp(prolongation_H[i-1]);
restriction[i-1] = makeMatrixOp(prolongation_H[i-1].transpose());
}
}
double Time_Transfer = clock.
stop();
gsInfo <<
"\n|| Assembling ||\n";
std::vector<gsSparseMatrix<>> matrices(numLevels);
std::vector<gsLinearOperator<>::Ptr> operators(numLevels);
double Time_Assembly = 0, Time_Galerkin = 0;
for (
index_t i=numLevels-1; i>=0; --i)
{
if (typeCoarseOperator == 1 || i == numLevels-1 || typeCoarsening[i] != 'h')
{
gsInfo <<
"Assemble on level " << i <<
": ";
mp,
bases[i],
bcInfo,
rhs_exact,
coeff_diff, coeff_conv, coeff_reac,
(dirichlet::strategy)opt.
getInt(
"DirichletStrategy"),
iFace::glue
);
assembler.assemble();
matrices[i] = assembler.matrix();
if (i==numLevels-1)
rhs = assembler.rhs();
Time_Assembly += clock.
stop();
gsInfo <<
"Degree: " << bases[i].degree() <<
", Ndof: " << matrices[i].rows() <<
"\n";
}
else
{
gsInfo <<
"Apply Galerkin projection on level " << i <<
": ";
matrices[i] = prolongation_H[i].transpose() * matrices[i+1] * prolongation_H[i];
Time_Galerkin += clock.
stop();
gsInfo <<
"Ndof: " << matrices[i].rows() <<
"\n";
}
operators[i] = makeMatrixOp(matrices[i]);
}
double Time_Coarse_Solver_Setup = clock.
stop();
if (typeCycle_p == typeCycle_h)
gsInfo <<
"Multigrid cycle type: " << typeCycle_h <<
"\n";
else
gsInfo <<
"Multigrid cycle type: " << typeCycle_h <<
" for h-refinement and " << typeCycle_p <<
" for p- and z-refinement\n";
for (
index_t i=1; i<numLevels-1; i++)
{
if (typeCoarsening[i] != 'h')
else
}
gsInfo <<
"\n|| Smoother ||\n";
opt.
addReal(
"Damping",
"",dampingSCMS);
for (
index_t i=1; i<numLevels; i++)
{
if (bases[i].degree()==1)
{
gsInfo <<
"Smoother for level " << i <<
": Gauss-Seidel\n";
}
else switch (typeSmoother)
{
case 1:
gsInfo <<
"Smoother for level " << i <<
": Incomplete LU\n";
break;
case 2:
gsInfo <<
"Smoother for level " << i <<
": Gauss-Seidel\n";
break;
case 3:
mg->
setSmoother(i,setupSubspaceCorrectedMassSmoother(matrices[i], bases[i], bcInfo, opt));
gsInfo <<
"Smoother for level " << i <<
": Subspace corrected mass smoother (damping = "<<dampingSCMS<<
")\n";
break;
case 4:
mg->
setSmoother(i,setupBlockILUT(matrices[i], bases[i], bcInfo, opt));
gsInfo <<
"Smoother for level " << i <<
": Blockwise Incomplete LU\n";
break;
default:
gsInfo <<
"Unknown smoother chosen.\n";
return EXIT_FAILURE;
}
}
gsInfo <<
"Number of smoothing steps: " << numSmoothing <<
"\n";
gsInfo <<
"Post smoothing is transpose of pre smoothing: " << (typeSolver == 3?
"yes":
"no") <<
"\n";
double Time_Smoother_Setup = clock.
stop();
gsInfo <<
"\n|| Setup Timings || \n";
gsInfo <<
"Total transfer setup time: " << Time_Transfer <<
"\n";
gsInfo <<
"Total Assembly time: " << Time_Assembly <<
"\n";
gsInfo <<
"Total Galerkin projections: " << Time_Galerkin <<
"\n";
gsInfo <<
"Coarse solver setup time: " << Time_Coarse_Solver_Setup <<
"\n";
gsInfo <<
"Smoother setup time: " << Time_Smoother_Setup <<
"\n";
gsInfo <<
"Total setup time: " << Time_Assembly + Time_Galerkin + Time_Transfer
+ Time_Coarse_Solver_Setup + Time_Smoother_Setup << "\n";
gsIterativeSolver<>::Ptr solver;
switch (typeSolver)
{
case 1:
gsInfo <<
"\n|| Solver information ||\np-multigrid is applied as stand-alone solver\n";
break;
case 2:
gsInfo <<
"\n|| Solver information ||\nBiCGStab is applied as solver, p-multigrid as a preconditioner\n";
break;
case 3:
gsInfo <<
"\n|| Solver information ||\nCG is applied as solver, p-multigrid as a preconditioner\n";
break;
default:
gsInfo <<
"Unknown iterative solver chosen.\n";
return EXIT_FAILURE;
}
const real_t rhs_norm = rhs.norm();
solver->
setTolerance( tol * (rhs-matrix*x).norm() / rhs_norm );
double Time_Solve = clock.
stop();
gsInfo <<
" 0 | Residual norm: " << std::setprecision(6) << (error_history(0,0) * rhs_norm) <<
"\n";
for (
index_t i=1; i<error_history.rows(); ++i)
gsInfo << std::right << std::setw(4) << i
<< " | Residual norm: "
<< std::setprecision(6) << std::left << std::setw(15) << (error_history(i,0) * rhs_norm)
<< " reduction: 1 / "
<< std::setprecision(3) << (error_history(i-1,0)/error_history(i,0))
<< "\n";
if (success)
gsInfo <<
"Solver reached accuracy goal after " << solver->
iterations() <<
" iterations.\n";
else
gsInfo <<
"Solver did not reach accuracy goal within " << solver->
iterations() <<
" iterations.\n";
gsInfo <<
"The iteration took " << Time_Solve <<
" seconds.\n";
gsInfo <<
"Residual after solving: " << (rhs-matrix*x).norm() <<
"\n";
return success ? EXIT_SUCCESS : EXIT_FAILURE;
}
)
{
const short_t dim = mb.topology().dim();
mb.getMapper(
(dirichlet::strategy)opt.
getInt(
"DirichletStrategy"),
iFace::glue,
bc,
dm,
0
);
std::vector< std::vector<patchComponent> > components = mb.topology().allComponents(true);
const index_t nr_components = components.size();
for (
index_t ps=0; ps < 2*dim; ++ps )
std::vector< gsSparseMatrix<real_t,RowMajor> > transfers;
transfers.reserve(nr_components);
std::vector< gsLinearOperator<>::Ptr > ops;
ops.reserve(nr_components);
for (
index_t i=0; i<nr_components; ++i)
{
std::vector<gsBasis<>::uPtr> bases = mb.componentBasis_withIndices(components[i],dm,indices,true);
se.reserve(sz);
se.add(indices(l,0),l,(real_t)(1));
transfer.setFrom(se);
if (sz>0)
{
if (bases[0]->dim() == dim)
{
GISMO_ASSERT ( bases.size() == 1,
"Only one basis is expected for each patch." );
ops.push_back(
*(bases[0]),
dir_bc,
)
);
}
else
{
ops.push_back( makeSparseCholeskySolver(mat) );
}
transfers.push_back(
give(transfer));
}
}
}
)
{
const index_t nPatches = mb.nPieces();
mb.getMapper(
(dirichlet::strategy)opt.
getInt(
"DirichletStrategy"),
iFace::glue,
bc,
dm,
0
);
std::vector<index_t> sizes(nPatches+1);
std::vector<index_t> shifts(nPatches+1);
shifts[0] = 0;
{
shifts[k+1] = shifts[k] + sizes[k];
}
sizes[nPatches] = A.rows() - shifts[nPatches];
std::vector< gsEigen::PermutationMatrix<Dynamic,Dynamic,index_t> > P(nPatches+1);
std::vector< gsEigen::PermutationMatrix<Dynamic,Dynamic,index_t> > Pinv(nPatches+1);
A_aprox.setZero();
gsSparseMatrix<> S = A.block(shifts[nPatches],shifts[nPatches],sizes[nPatches],sizes[nPatches]);
for (
index_t k=0 ; k<nPatches; k++)
{
gsEigen::IncompleteLUT<real_t> ilu;
ilu.setFillfactor(1);
ilu.compute(block);
P[k] = ilu.fillReducingPermutation();
Pinv[k] = ilu.inversePermutation();
A_aprox.block(shifts[k],shifts[k],sizes[k],sizes[k]) = ilu.factors();
if (sizes[nPatches]>0)
{
gsMatrix<> ddB = A.block(shifts[nPatches],shifts[k],sizes[nPatches],sizes[k]);
gsMatrix<> ddC = A.block(shifts[k],shifts[nPatches],sizes[k],sizes[nPatches]);
gsMatrix<> ddBtilde = ilu.factors().triangularView<gsEigen::Upper>().transpose().solve((ddB*P[k]).transpose()).transpose();
gsMatrix<> ddCtilde = ilu.factors().triangularView<gsEigen::UnitLower>().solve(Pinv[k]*ddC);
S -= (ddBtilde*ddCtilde).sparseView();
A_aprox.block(shifts[k],shifts[nPatches],sizes[k],sizes[nPatches]) = ddCtilde;
A_aprox.block(shifts[nPatches],shifts[k],sizes[nPatches],sizes[k]) = ddBtilde;
}
}
if (sizes[nPatches]>0)
{
gsEigen::IncompleteLUT<real_t> ilu;
ilu.setFillfactor(1);
ilu.compute(S);
P[nPatches] = ilu.fillReducingPermutation();
Pinv[nPatches] = ilu.inversePermutation();
A_aprox.block(shifts[nPatches],shifts[nPatches],sizes[nPatches],sizes[nPatches]) = ilu.factors();
}
makeMatrixOp(A),
makeLinearOp(
{
x.setZero(rhs.rows(),rhs.cols());
for (
index_t k=0; k<=m_nPatches; ++k)
x.block(m_shifts[k],0,m_sizes[k],1) = m_Pinv[k]*rhs.block(m_shifts[k],0,m_sizes[k],1);
x = m_A_aprox.template triangularView<gsEigen::UnitLower>().solve(x);
x = m_A_aprox.template triangularView<gsEigen::Upper>().solve(x);
for (
index_t k=0; k<=m_nPatches; ++k)
x.block(m_shifts[k],0,m_sizes[k],1) = m_P[k]*x.block(m_shifts[k],0,m_sizes[k],1);
},
A.rows(),
A.cols()
)
);
}
)
{
geometryMap G = ex.getMap(mp);
space w_n = ex.getSpace(basis, 1, 0);
w_n.setInterfaceCont(0);
if ((dirichlet::strategy)opt.
getInt(
"DirichletStrategy") == dirichlet::elimination)
{
w_n.setup(bcInfo, dirichlet::interpolation, 0);
}
ex.setIntegrationElements(basis);
ex.initSystem();
ex.assemble(w_n *
meas(G));
return ex.rhs();
}
)
{
geometryMap G = ex.getMap(mp);
space w_n = ex.getSpace(basis, 1, 0);
if ((dirichlet::strategy)opt.
getInt(
"DirichletStrategy") == dirichlet::elimination)
{
w_n.setup(bcInfo, dirichlet::interpolation, 0);
}
ex.setIntegrationElements(basis);
ex.initSystem();
ex.assemble(w_n *
meas(G) * w_n.tr());
return ex.matrix();
}
)
{
geometryMap G = ex.getMap(mp);
space v_n = ex.getSpace(basisU, 1, 0);
space u_n = ex.getTestSpace(v_n, basisV);
if ((dirichlet::strategy)opt.
getInt(
"DirichletStrategy") == dirichlet::elimination)
{
v_n.setup(bcInfo, dirichlet::interpolation, 0);
u_n.setup(bcInfo, dirichlet::interpolation, 0);
}
ex.setIntegrationElements(basisU);
ex.initSystem();
ex.assemble(u_n *
meas(G) * v_n.tr());
return ex.matrix().transpose();
}
Definition gsExpressions.h:973
Definition gsExpressions.h:928
Generic preconditioner which applies an arbitrary linear operator to the residual.
Definition gsAdditiveOp.h:51
Class containing a set of boundary conditions.
Definition gsBoundaryConditions.h:342
void addCondition(int p, boxSide s, condition_type::type t, gsFunctionSet< T > *f, short_t unknown=0, bool parametric=false, int comp=-1)
Adds another boundary condition.
Definition gsBoundaryConditions.h:650
void setGeoMap(const gsFunctionSet< T > &gm)
Set the geometry map to evaluate boundary conditions.
Definition gsBoundaryConditions.h:916
Implementation of an (multiple righ-hand side) Poisson solver.
Definition gsCDRAssembler.h:50
Class for command-line argument parsing.
Definition gsCmdLine.h:57
The conjugate gradient method.
Definition gsConjugateGradient.h:30
Maintains a mapping from patch-local dofs to global dof indices and allows the elimination of individ...
Definition gsDofMapper.h:69
gsVector< index_t > findFreeUncoupled(const index_t k) const
Returns all free, not coupled dofs on patch k (local dof indices)
Definition gsDofMapper.cpp:709
index_t freeSize() const
Returns the number of free (not eliminated) dofs.
Definition gsDofMapper.h:436
Definition gsExprAssembler.h:33
gsExprHelper< T >::geometryMap geometryMap
Geometry map type.
Definition gsExprAssembler.h:65
Class defining a multivariate (real or vector) function given by a string mathematical expression.
Definition gsFunctionExpr.h:52
A Stopwatch object can be used to measure execution time of code, algorithms, etc.
Definition gsStopwatch.h:73
double stop()
Return elapsed time in seconds.
Definition gsStopwatch.h:83
void restart()
Start taking the time.
Definition gsStopwatch.h:80
index_t iterations() const
The number of iterations needed to reach the error criteria.
Definition gsIterativeSolver.h:226
void setMaxIterations(index_t max_iters)
Set the maximum number of iterations (default: 1000)
Definition gsIterativeSolver.h:220
T tolerance() const
The chosen tolerance for the error criteria on the relative residual error.
Definition gsIterativeSolver.h:235
void setTolerance(T tol)
Set the tolerance for the error criteria on the relative residual error (default: 1e-10)
Definition gsIterativeSolver.h:223
void solveDetailed(const VectorType &rhs, VectorType &x, VectorType &error_history)
Solves the linear system and stores the solution in x and records the error histroy.
Definition gsIterativeSolver.h:134
T error() const
The relative residual error of the current iterate.
Definition gsIterativeSolver.h:232
A matrix with arbitrary coefficient type and fixed or dynamic size.
Definition gsMatrix.h:41
Holds a set of patch-wise bases and their topology information.
Definition gsMultiBasis.h:37
void setNumPostSmooth(index_t n)
Set number of post-smoothing steps to perform.
Definition gsMultiGrid.h:314
void setNumCycles(index_t n)
Definition gsMultiGrid.h:328
void setSymmSmooth(bool s)
Definition gsMultiGrid.h:321
void setSmoother(index_t lvl, const PrecondPtr &sm)
Definition gsMultiGrid.hpp:284
void setCoarseSolver(const OpPtr &sol)
Set the solver for the coarsest problem (level 0)
Definition gsMultiGrid.h:302
void setNumPreSmooth(index_t n)
Set number of pre-smoothing steps to perform.
Definition gsMultiGrid.h:308
Container class for a set of geometry patches and their topology, that is, the interface connections ...
Definition gsMultiPatch.h:100
Class which holds a list of parameters/options, and provides easy access to them.
Definition gsOptionList.h:33
void addInt(const std::string &label, const std::string &desc, const index_t &value)
Adds a option named label, with description desc and value value.
Definition gsOptionList.cpp:201
const index_t & getInt(const std::string &label) const
Reads value for option label from options.
Definition gsOptionList.cpp:37
Real getReal(const std::string &label) const
Reads value for option label from options.
Definition gsOptionList.cpp:44
void addReal(const std::string &label, const std::string &desc, const Real &value)
Adds a option named label, with description desc and value value.
Definition gsOptionList.cpp:211
Provides robust preconditioners for single patch geometries.
Definition gsPatchPreconditionersCreator.h:30
static uPtr make(BasePtr underlying, BasePtr preconditioner, T tau=(T) 1)
Make function returning a smart pointer.
Definition gsPreconditioner.h:188
memory::unique_ptr< gsPreconditionerOp > uPtr
Unique pointer for gsLinearOperator.
Definition gsPreconditioner.h:50
memory::shared_ptr< gsPreconditionerOp > Ptr
Shared pointer for gsLinearOperator.
Definition gsPreconditioner.h:47
virtual void setOptions(const gsOptionList &opt)
Set options based on a gsOptionList object.
Definition gsPreconditioner.h:111
Reads an object from a data file, if such the requested object exists in the file.
Definition gsReadFile.h:43
Class that provides a container for triplets (i,j,value) to be filled in a sparse matrix.
Definition gsSparseMatrix.h:34
Sparse matrix class, based on gsEigen::SparseMatrix.
Definition gsSparseMatrix.h:139
uPtr moveToPtr()
This function returns a smart pointer to the matrix. After calling it, the matrix object becomes empt...
Definition gsSparseMatrix.h:247
Main header to be included by clients using the G+Smo library.
#define short_t
Definition gsConfig.h:35
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
EIGEN_STRONG_INLINE meas_expr< T > meas(const gsGeometryMap< T > &G)
The measure of a geometry map.
Definition gsExpressions.h:4555
The G+Smo namespace, containing all definitions for the library.
Class gsNurbsCreator provides some simple examples of Nurbs Geometries.
Definition gsNurbsCreator.h:37