65 if (dot_prod_type == 0)
79 int print_level_ = print_lvl;
82 if (dot_prod_type != 0)
85 MPI_Comm_rank(comm, &rank);
104 if (dot_prod_type != 0)
107 MPI_Comm_rank(comm, &rank);
110 derived_print_level = -1;
124 if (comm != MPI_COMM_NULL)
126 MPI_Comm_rank(comm, &rank);
130 switch (print_level_)
147 MFEM_WARNING(
"Unknown print level " << print_level_ <<
148 ". Defaulting to level 0.");
164 else if (print_options_.
summary)
196 const Vector& x,
bool final)
const
200 if (it == 0 && !
final)
232 d_xr[i] = d_x[idx[i]];
233 d_yr[i] = d_y[idx[i]];
250 d_y[i] = d_x[idx[i]];
259 "Incompatible operator heights in WeightedInnerProduct");
286 "Weighting operator not set; set using ::SetOperator")
307 "Weighting operator not set; set using ::SetOperator")
326 ess_tdof_list(nullptr),
335 Solver(
a.FESpace()->GetTrueVSize()),
338 ess_tdof_list(&ess_tdofs),
343 a.AssembleDiagonal(diag);
357 ess_tdof_list(&ess_tdofs),
390 MFEM_VERIFY(
height ==
width,
"not a square matrix!");
392 ess_tdof_list =
nullptr;
405 auto D = diag.
Read();
406 auto DI = dinv.
Write();
407 const bool use_abs_diag_ = use_abs_diag;
412 MFEM_ABORT_KERNEL(
"Zero diagonal entry in OperatorJacobiSmoother");
414 if (!use_abs_diag_) { DI[i] =
delta / D[i]; }
415 else { DI[i] =
delta / std::abs(D[i]); }
417 if (ess_tdof_list && ess_tdof_list->
Size() > 0)
419 auto I = ess_tdof_list->
Read();
431 MFEM_VERIFY(x.
Size() ==
Width(),
"invalid input vector");
432 MFEM_VERIFY(y.
Size() ==
Height(),
"invalid output vector");
436 MFEM_VERIFY(oper,
"iterative_mode == true requires the forward operator");
437 oper->
Mult(y, residual);
446 auto DI = dinv.
Read();
447 auto R = residual.
Read();
451 Y[i] += DI[i] * R[i];
458 int order_,
real_t max_eig_estimate_)
462 max_eig_estimate(max_eig_estimate_),
467 ess_tdof_list(ess_tdofs),
469 oper(&oper_) {
Setup(); }
475 int order_, MPI_Comm comm,
476 int power_iterations,
484 int power_iterations,
494 ess_tdof_list(ess_tdofs),
507 MFEM_VERIFY(power_seed != 0,
"invalid seed!");
519 int order_,
real_t max_eig_estimate_)
526 int order_, MPI_Comm comm,
int power_iterations,
real_t power_tolerance)
528 power_iterations, power_tolerance) { }
533 int order_,
int power_iterations,
real_t power_tolerance)
543 auto D = diag.
Read();
544 auto X = dinv.
Write();
545 mfem::forall(N, [=] MFEM_HOST_DEVICE (
int i) { X[i] = 1.0 / D[i]; });
546 auto I = ess_tdof_list.
Read();
555 real_t upper_bound = 1.2 * max_eig_estimate;
556 real_t lower_bound = 0.3 * max_eig_estimate;
557 real_t theta = 0.5 * (upper_bound + lower_bound);
564 coeffs[0] = 1.0 / theta;
569 real_t tmp_0 = 1.0/(pow(
delta, 2) - 2*pow(theta, 2));
570 coeffs[0] = -4*theta*tmp_0;
577 real_t tmp_1 = pow(theta, 2);
578 real_t tmp_2 = 1.0/(-4*pow(theta, 3) + theta*tmp_0);
579 coeffs[0] = tmp_2*(tmp_0 - 12*tmp_1);
580 coeffs[1] = 12/(tmp_0 - 4*tmp_1);
581 coeffs[2] = -4*tmp_2;
587 real_t tmp_1 = pow(theta, 2);
589 real_t tmp_3 = 1.0/(pow(
delta, 4) + 8*pow(theta, 4) - tmp_1*tmp_2);
590 coeffs[0] = tmp_3*(32*pow(theta, 3) - 16*theta*tmp_0);
591 coeffs[1] = tmp_3*(-48*tmp_1 + tmp_2);
592 coeffs[2] = 32*theta*tmp_3;
593 coeffs[3] = -8*tmp_3;
599 real_t tmp_1 = pow(theta, 4);
600 real_t tmp_2 = pow(theta, 2);
604 real_t tmp_6 = 1.0/(16*pow(theta, 5) - pow(theta, 3)*tmp_5 + theta*tmp_0);
606 real_t tmp_8 = 1.0/(tmp_0 + 16*tmp_1 - tmp_2*tmp_5);
607 coeffs[0] = tmp_6*(tmp_0 + 80*tmp_1 - tmp_2*tmp_4);
608 coeffs[1] = tmp_8*(tmp_4 - tmp_7);
609 coeffs[2] = tmp_6*(-tmp_5 + tmp_7);
610 coeffs[3] = -80*tmp_8;
611 coeffs[4] = 16*tmp_6;
615 MFEM_ABORT(
"Chebyshev smoother not implemented for order = " << order);
623 MFEM_ABORT(
"Chebyshev smoother not implemented for iterative mode");
628 MFEM_ABORT(
"Chebyshev smoother requires operator");
638 for (
int k = 0; k < order; ++k)
643 oper->
Mult(residual, helperVector);
644 residual = helperVector;
649 auto Dinv = dinv.
Read();
651 mfem::forall(n, [=] MFEM_HOST_DEVICE (
int i) { R[i] *= Dinv[i]; });
655 auto C = coeffs.
Read();
656 mfem::forall(n, [=] MFEM_HOST_DEVICE (
int i) { Y[i] += C[k] * R[i]; });
671 const bool zero_b = (
b.Size() == 0);
675 "empty 'b' can be used only in iterative mode!");
686 if (!zero_b) { x +=
z; }
713 real_t r0, nom, nom0, nomold = 1, cf;
729 nom0 = nom = sqrt(
Dot(
z,
z));
733 nom0 = nom = sqrt(
Dot(
r,
r));
739 mfem::out <<
" Iteration : " << setw(3) << right << 0 <<
" ||Br|| = "
744 if (
Monitor(0, nom,
r, x) || nom <= r0)
759 if (!zero_b) { x +=
z; }
764 if (!zero_b) { x +=
r; }
774 nom = sqrt(
Dot(
z,
z));
778 nom = sqrt(
Dot(
r,
r));
785 if (
Monitor(i, nom,
r, x) || nom < r0)
794 mfem::out <<
" Iteration : " << setw(3) << right << (i-1)
795 <<
" ||Br|| = " << setw(11) << left << nom
796 <<
"\tConv. rate: " << cf <<
'\n';
809 const auto rf = pow (nom/nom0, 1.0/
final_iter);
811 <<
"Conv. rate: " << cf <<
'\n'
812 <<
"Average reduction factor: "<< rf <<
'\n';
816 mfem::out <<
"SLI: No convergence!" <<
'\n';
824 int print_iter,
int max_num_iter,
839 int print_iter,
int max_num_iter,
895 nom0 = nom =
Dot(
d,
r);
897 MFEM_VERIFY(
IsFinite(nom),
"nom = " << nom);
900 mfem::out <<
" Iteration : " << setw(3) << 0 <<
" (B r, r) = "
908 mfem::out <<
"PCG: The preconditioner is not positive definite. (Br, r) = "
920 if (
Monitor(0, nom,
r, x) || nom <= r0)
932 MFEM_VERIFY(
IsFinite(den),
"den = " << den);
937 mfem::out <<
"PCG: The operator is not positive definite. (Ad, d) = "
969 MFEM_VERIFY(
IsFinite(betanom),
"betanom = " << betanom);
974 mfem::out <<
"PCG: The preconditioner is not positive definite. (Br, r) = "
984 mfem::out <<
" Iteration : " << setw(3) << i <<
" (B r, r) = "
985 << betanom << std::endl;
988 if (
Monitor(i, betanom,
r, x) || betanom <= r0)
1011 MFEM_VERIFY(
IsFinite(den),
"den = " << den);
1016 mfem::out <<
"PCG: The operator is not positive definite. (Ad, d) = "
1039 const auto arf = pow (betanom/nom0, 0.5/
final_iter);
1040 mfem::out <<
"Average reduction factor = " << arf <<
'\n';
1044 mfem::out <<
"PCG: No convergence!" <<
'\n';
1053 int print_iter,
int max_num_iter,
1068 int print_iter,
int max_num_iter,
1092 else if (fabs(dy) > fabs(dx))
1095 sn = 1.0 / sqrt( 1.0 + temp*temp );
1101 cs = 1.0 / sqrt( 1.0 + temp*temp );
1108 real_t temp = cs * dx + sn * dy;
1109 dy = -sn * dx + cs * dy;
1119 for (
int i = k; i >= 0; i--)
1122 for (
int j = i - 1; j >= 0; j--)
1124 y(j) -= h(j,i) * y(i);
1128 for (
int j = 0; j <= k; j++)
1143 Vector r(n), w(n), x_monitor;
1196 MFEM_VERIFY(
IsFinite(beta),
"beta = " << beta);
1212 <<
" Iteration : " << setw(3) << 0
1213 <<
" ||B r|| = " << beta
1226 v[0]->Set(1.0/beta, r);
1227 s = 0.0; s(0) = beta;
1229 for (i = 0; i <
m && j <=
max_iter; i++, j++)
1241 for (k = 0; k <= i; k++)
1243 H(k,i) =
Dot(w, *v[k]);
1244 w.Add(-H(k,i), *v[k]);
1248 MFEM_VERIFY(
IsFinite(H(i+1,i)),
"Norm(w) = " << H(i+1,i));
1249 if (v[i+1] == NULL) { v[i+1] =
new Vector(n); }
1250 v[i+1]->Set(1.0/H(i+1,i), w);
1252 for (k = 0; k < i; k++)
1261 const real_t resid = fabs(s(i+1));
1262 MFEM_VERIFY(
IsFinite(resid),
"resid = " << resid);
1267 Update(x_monitor, i, H, s, v);
1281 mfem::out <<
" Pass : " << setw(2) << (j-1)/
m+1
1282 <<
" Iteration : " << setw(3) << j
1283 <<
" ||B r|| = " << resid <<
'\n';
1305 MFEM_VERIFY(
IsFinite(beta),
"beta = " << beta);
1322 mfem::out <<
" Pass : " << setw(2) << (j-1)/
m+1
1332 mfem::out <<
"GMRES: No convergence!\n";
1337 for (i = 0; i < v.
Size(); i++)
1347 Vector r(
b.Size()), x_monitor;
1376 MFEM_VERIFY(
IsFinite(beta),
"beta = " << beta);
1396 <<
" Iteration : " << setw(3) << 0
1397 <<
" || r || = " << beta
1403 for (i= 0; i<=
m; i++)
1418 v[0] ->
Add (1.0/beta, r);
1419 s = 0.0; s(0) = beta;
1421 for (i = 0; i <
m && j <=
max_iter; i++, j++)
1441 for (k = 0; k <= i; k++)
1443 H(k,i) =
Dot( r, *v[k]);
1444 r.Add(-H(k,i), (*v[k]));
1450 v[i+1] =
new Vector(
b.Size());
1454 v[i+1] ->
Add (1.0/H(i+1,i), r);
1456 for (k = 0; k < i; k++)
1465 const real_t resid = fabs(s(i+1));
1466 MFEM_VERIFY(
IsFinite(resid),
"resid = " << resid);
1470 mfem::out <<
" Pass : " << setw(2) << (j-1)/
m+1
1471 <<
" Iteration : " << setw(3) << j
1472 <<
" || r || = " << resid << endl;
1478 Update(x_monitor, i, H, s, z);
1493 for (i= 0; i<=
m; i++)
1495 if (v[i]) {
delete v[i]; }
1496 if (z[i]) {
delete z[i]; }
1499 Monitor(j, resid, r, x,
true);
1514 MFEM_VERIFY(
IsFinite(beta),
"beta = " << beta);
1524 for (i = 0; i <=
m; i++)
1526 if (v[i]) {
delete v[i]; }
1527 if (z[i]) {
delete z[i]; }
1536 mfem::out <<
" Pass : " << setw(2) << (j-1)/
m+1
1537 <<
" Iteration : " << setw(3) << j-1
1546 mfem::out <<
"FGMRES: No convergence!\n";
1554 int &max_iter,
int m,
real_t &tol,
real_t atol,
int printit)
1573 int print_iter,
int max_num_iter,
int m,
real_t rtol,
real_t atol)
1575 GMRES(A, x,
b, B, max_num_iter, m, rtol, atol, print_iter);
1631 MFEM_VERIFY(
IsFinite(resid),
"resid = " << resid);
1634 mfem::out <<
" Iteration : " << setw(3) << 0
1640 if (
Monitor(0, resid,
r, x) || resid <= tol_goal)
1657 mfem::out <<
" Iteration : " << setw(3) << i
1658 <<
" ||r|| = " << resid <<
'\n';
1670 mfem::out <<
"BiCGStab: No convergence!\n";
1698 MFEM_VERIFY(
IsFinite(resid),
"resid = " << resid);
1699 if (
Monitor(i, resid,
r, x) || resid < tol_goal)
1704 mfem::out <<
" Iteration : " << setw(3) << i
1705 <<
" ||s|| = " << resid <<
'\n';
1720 mfem::out <<
" Iteration : " << setw(3) << i
1721 <<
" ||s|| = " << resid;
1739 MFEM_VERIFY(
IsFinite(resid),
"resid = " << resid);
1742 mfem::out <<
" ||r|| = " << resid <<
'\n';
1744 if (
Monitor(i, resid,
r, x) || resid < tol_goal)
1751 mfem::out <<
" Iteration : " << setw(3) << i
1752 <<
" ||r|| = " << resid <<
'\n';
1769 mfem::out <<
" Iteration : " << setw(3) << i
1770 <<
" ||r|| = " << resid <<
'\n';
1778 mfem::out <<
"BiCGStab: No convergence!\n";
1793 <<
" ||r|| = " << resid <<
'\n';
1801 mfem::out <<
"BiCGStab: No convergence!\n";
1817 bicgstab.
Mult(
b, x);
1824 int print_iter,
int max_num_iter,
real_t rtol,
real_t atol)
1826 BiCGSTAB(A, x,
b, B, max_num_iter, rtol, atol, print_iter);
1866 real_t beta, eta, gamma0, gamma1, sigma0, sigma1;
1888 MFEM_VERIFY(
IsFinite(eta),
"eta = " << eta);
1889 gamma0 = gamma1 = 1.;
1890 sigma0 = sigma1 = 0.;
1894 if (
Monitor(0, eta, *z, x) || eta <= norm_goal)
1902 mfem::out <<
"MINRES: iteration " << setw(3) << 0 <<
": ||r||_B = "
1924 rho2 = sigma1*
alpha + gamma0*gamma1*beta;
1934 MFEM_VERIFY(
IsFinite(beta),
"beta = " << beta);
1935 rho1 = std::hypot(
delta, beta);
1939 w0.
Set(1./rho1, *z);
1943 add(1./rho1, *z, -rho2/rho1,
w1,
w0);
1947 add(-rho3/rho1,
w0, -rho2/rho1,
w1,
w0);
1948 w0.
Add(1./rho1, *z);
1952 gamma1 =
delta/rho1;
1954 x.
Add(gamma1*eta,
w0);
1960 MFEM_VERIFY(
IsFinite(eta),
"eta = " << eta);
1962 if (fabs(eta) <= norm_goal)
1969 mfem::out <<
"MINRES: iteration " << setw(3) << it <<
": ||r||_B = "
1970 << fabs(eta) <<
'\n';
1972 if (
Monitor(it, fabs(eta), *z, x)) {
goto loop_end; }
1990 mfem::out <<
"MINRES: iteration " << setw(3) << it <<
": ||r||_B = "
1991 << fabs(eta) <<
'\n';
2016 mfem::out <<
"MINRES: No convergence!\n";
2053 MFEM_VERIFY(
height ==
width,
"square Operator is required.");
2064 MFEM_VERIFY(
oper != NULL,
"the Operator is not set (use SetOperator).");
2065 MFEM_VERIFY(
prec != NULL,
"the Solver is not set (use SetSolver).");
2069 const bool have_b = (
b.Size() ==
Height());
2087 mfem::out <<
"Newton iteration " << setw(2) << 0
2088 <<
" : ||r|| = " <<
norm <<
"...\n";
2095 for (it = 0;
true; it++)
2100 mfem::out <<
"Newton iteration " << setw(2) << it
2101 <<
" : ||r|| = " <<
norm;
2142 add(x, -c_scale,
c, x);
2162 <<
", ||r||/||r_0|| = " <<
final_norm/norm0 <<
'\n';
2166 mfem::out <<
"Newton: No convergence!\n";
2181 this->
alpha = alpha_;
2182 this->
gamma = gamma_;
2187 const real_t fnorm)
const
2195 real_t sg_threshold = 0.1;
2215 MFEM_ABORT(
"Unknown adaptive linear solver rtol version");
2220 if (sg_eta > sg_threshold) { eta = std::max(eta, sg_eta); }
2224 iterative_solver->SetRelTol(eta);
2228 mfem::out <<
"Eisenstat-Walker rtol = " << eta <<
"\n";
2235 const real_t fnorm)
const
2255 MFEM_VERIFY(
oper != NULL,
"the Operator is not set (use SetOperator).");
2277 alpha.UseDevice(
true);
2279 int last_saved_id = -1;
2283 const bool have_b = (
b.Size() ==
Height());
2294 if (have_b) {
r -=
b; }
2301 mfem::out <<
"LBFGS iteration " << setw(2) << 0
2302 <<
" : ||r|| = " <<
norm <<
"...\n";
2305 for (it = 0;
true; it++)
2311 <<
" : ||r|| = " <<
norm;
2319 if (
norm <= norm_goal)
2338 add(x, -c_scale,
c, x);
2350 sk =
c; sk *= -c_scale;
2354 last_saved_id = (last_saved_id ==
m-1) ? 0 : last_saved_id+1;
2359 for (
int i = last_saved_id; i > -1; i--)
2367 for (
int i =
m-1; i > last_saved_id; i--)
2378 for (
int i = last_saved_id+1; i <
m ; i++)
2384 for (
int i = 0; i < last_saved_id+1 ; i++)
2401 <<
", ||r||/||r_0|| = " <<
final_norm/norm0 <<
'\n';
2405 mfem::out <<
"LBFGS: No convergence!\n";
2411 int m_max,
int m_min,
int m_step,
real_t cf,
2419 Vector s(m+1), cs(m+1), sn(m+1);
2431 real_t normb = w.Norml2();
2444 resid = beta / normb;
2446 if (resid * resid <= tol)
2448 tol = resid * resid;
2456 <<
" Iteration : " << setw(3) << 0
2457 <<
" (r, r) = " << beta*beta <<
'\n';
2460 tol *= (normb*normb);
2461 tol = (atol > tol) ? atol : tol;
2465 for (i= 0; i<=m; i++)
2473 while (j <= max_iter)
2476 v[0] ->
Add (1.0/beta, r);
2477 s = 0.0; s(0) = beta;
2481 for (i = 0; i < m && j <= max_iter; i++)
2486 for (k = 0; k <= i; k++)
2488 H(k,i) = w * (*v[k]);
2489 w.
Add(-H(k,i), (*v[k]));
2492 H(i+1,i) = w.Norml2();
2494 v[i+1] ->
Add (1.0/H(i+1,i), w);
2496 for (k = 0; k < i; k++)
2505 resid = fabs(s(i+1));
2509 <<
" Iteration : " << setw(3) << i+1
2510 <<
" (r, r) = " << resid*resid <<
'\n';
2513 if ( resid*resid < tol)
2516 tol = resid * resid;
2518 for (i= 0; i<=m; i++)
2537 if ( resid*resid < tol)
2539 tol = resid * resid;
2541 for (i= 0; i<=m; i++)
2550 if (m - m_step >= m_min)
2563 tol = resid * resid;
2564 for (i= 0; i<=m; i++)
2574 : C(C_), D(D_), c_e(NULL), d_lo(NULL), d_hi(NULL), x_lo(NULL), x_hi(NULL),
2583 MFEM_VERIFY(
C,
"The C operator is unspecified -- can't set constraints.");
2584 MFEM_VERIFY(c.
Size() ==
C->
Height(),
"Wrong size of the constraint.");
2592 MFEM_VERIFY(
D,
"The D operator is unspecified -- can't set constraints.");
2594 "Wrong size of the constraint.");
2602 "Wrong size of the constraint.");
2619 MFEM_WARNING(
"Objective functional is ignored as SLBQP always minimizes"
2620 "the l2 norm of (x - x_target).");
2622 MFEM_VERIFY(
prob.GetC(),
"Linear constraint is not set.");
2623 MFEM_VERIFY(
prob.GetC()->Height() == 1,
"Solver expects scalar constraint.");
2644 mfem::out <<
"SLBQP iteration " << it <<
": residual = " << r
2645 <<
", lambda = " << l <<
'\n';
2675 mfem::out <<
"SLBQP bracketing phase" <<
'\n';
2693 llow = l; rlow = r; l = l + dl;
2696 r =
solve(l,xt,x,nclip);
2699 while ((r < 0) && (nclip <
max_iter))
2703 if (s < smin) { s = smin; }
2708 r =
solve(l,xt,x,nclip);
2716 lupp = l; rupp = r; l = l - dl;
2719 r =
solve(l,xt,x,nclip);
2722 while ((r > 0) && (nclip <
max_iter))
2726 if (s < smin) { s = smin; }
2731 r =
solve(l,xt,x,nclip);
2744 mfem::out <<
"SLBQP secant phase" <<
'\n';
2747 s = 1.0 - rlow/rupp; dl = dl/s; l = lupp - dl;
2750 r =
solve(l,xt,x,nclip);
2753 while ( (fabs(r) > tol) && (nclip <
max_iter) )
2759 lupp = l; rupp = r; s = 1.0 - rlow/rupp;
2760 dl = (lupp - llow)/s; l = lupp - dl;
2765 if (s < smin) { s = smin; }
2767 lnew = 0.75*llow + 0.25*l;
2768 if (lnew < l-dl) { lnew = l-dl; }
2769 lupp = l; rupp = r; l = lnew;
2770 s = (lupp - llow)/(lupp - l);
2778 llow = l; rlow = r; s = 1.0 - rlow/rupp;
2779 dl = (lupp - llow)/s; l = lupp - dl;
2784 if (s < smin) { s = smin; }
2786 lnew = 0.75*lupp + 0.25*l;
2787 if (lnew < l+dl) { lnew = l+dl; }
2788 llow = l; rlow = r; l = lnew;
2789 s = (lupp - llow)/(lupp - l);
2794 r =
solve(l,xt,x,nclip);
2810 <<
" lambda = " << l <<
'\n'
2815 mfem::out <<
"SLBQP: No convergence!" <<
'\n';
2821 const std::vector<real_t> &w;
2822 std::vector<size_t> c;
2823 std::vector<int> loc;
2825 WeightMinHeap(
const std::vector<real_t> &w_) : w(w_)
2827 c.reserve(w.size());
2828 loc.resize(w.size());
2829 for (
size_t i=0; i<w.size(); ++i) { push(i); }
2832 size_t percolate_up(
size_t pos,
real_t val)
2834 for (; pos > 0 && w[c[(pos-1)/2]] > val; pos = (pos-1)/2)
2836 c[pos] = c[(pos-1)/2];
2837 loc[c[(pos-1)/2]] =
static_cast<int>(pos);
2842 size_t percolate_down(
size_t pos,
real_t val)
2844 while (2*pos+1 < c.size())
2846 size_t left = 2*pos+1;
2847 size_t right = left+1;
2849 if (right < c.size() && w[c[right]] < w[c[left]]) { tgt = right; }
2850 else { tgt = left; }
2851 if (w[c[tgt]] < val)
2854 loc[c[tgt]] =
static_cast<int>(pos);
2869 size_t pos = c.size()-1;
2870 pos = percolate_up(pos, val);
2872 loc[i] =
static_cast<int>(pos);
2878 size_t j = c.back();
2882 if (c.empty()) {
return static_cast<int>(i); }
2885 pos = percolate_down(pos, val);
2887 loc[j] =
static_cast<int>(pos);
2888 return static_cast<int>(i);
2891 void update(
size_t i)
2893 size_t pos = loc[i];
2895 pos = percolate_up(pos, val);
2896 pos = percolate_down(pos, val);
2898 loc[i] =
static_cast<int>(pos);
2901 bool picked(
size_t i)
2917 for (
int i=0; i<n; ++i)
2919 for (
int j=I[i]; j<I[i+1]; ++j)
2921 V[j] =
abs(V[j]/D[i]);
2925 std::vector<real_t> w(n, 0.0);
2926 for (
int k=0; k<n; ++k)
2929 for (
int ii=I[k]; ii<I[k+1]; ++ii)
2934 for (
int kk=I[i]; kk<I[i+1]; ++kk)
2942 for (
int jj=I[k]; jj<I[k+1]; ++jj)
2945 if (j == k) {
continue; }
2947 bool ij_exists =
false;
2948 for (
int jj2=I[i]; jj2<I[i+1]; ++jj2)
2956 if (!ij_exists) { w[k] += pow(C_ik*C_kj,2); }
2962 WeightMinHeap w_heap(w);
2966 for (
int ii=0; ii<n; ++ii)
2968 int pi = w_heap.pop();
2971 for (
int kk=I[pi]; kk<I[pi+1]; ++kk)
2974 if (w_heap.picked(k)) {
continue; }
2978 for (
int ii2=I[k]; ii2<I[k+1]; ++ii2)
2981 if (w_heap.picked(i)) {
continue; }
2984 for (
int kk2=I[i]; kk2<I[i+1]; ++kk2)
2992 for (
int jj=I[k]; jj<I[k+1]; ++jj)
2995 if (j == k || w_heap.picked(j)) {
continue; }
2997 bool ij_exists =
false;
2998 for (
int jj2=I[i]; jj2<I[i+1]; ++jj2)
3006 if (!ij_exists) { w[k] += pow(C_ik*C_kj,2); }
3019 block_size(block_size_),
3021 reordering(reordering_)
3028 :
BlockILU(block_size_, reordering_, k_fill_)
3050 MFEM_ABORT(
"BlockILU must be created with a SparseMatrix or HypreParMatrix");
3055 MFEM_VERIFY(A->
Finalized(),
"Matrix must be finalized.");
3056 CreateBlockPattern(*A);
3060void BlockILU::CreateBlockPattern(
const SparseMatrix &A)
3062 MFEM_VERIFY(k_fill == 0,
"Only block ILU(0) is currently supported.");
3063 if (A.
Height() % block_size != 0)
3065 MFEM_ABORT(
"BlockILU: block size must evenly divide the matrix size");
3073 int nblockrows = nrows / block_size;
3075 std::vector<std::set<int>> unique_block_cols(nblockrows);
3077 for (
int iblock = 0; iblock < nblockrows; ++iblock)
3079 for (
int bi = 0; bi < block_size; ++bi)
3081 int i = iblock * block_size + bi;
3082 for (
int k = I[i]; k < I[i + 1]; ++k)
3084 unique_block_cols[iblock].insert(J[k] / block_size);
3087 nnz +=
static_cast<int>(unique_block_cols[iblock].size());
3092 SparseMatrix C(nblockrows, nblockrows);
3093 for (
int iblock = 0; iblock < nblockrows; ++iblock)
3095 for (
int jblock : unique_block_cols[iblock])
3097 for (
int bi = 0; bi < block_size; ++bi)
3099 int i = iblock * block_size + bi;
3100 for (
int k = I[i]; k < I[i + 1]; ++k)
3103 if (j >= jblock * block_size && j < (jblock + 1) * block_size)
3105 C.Add(iblock, jblock, V[k]*V[k]);
3112 real_t *CV = C.GetData();
3113 for (
int i=0; i<C.NumNonZeroElems(); ++i)
3115 CV[i] =
sqrt(CV[i]);
3124 MFEM_ABORT(
"BlockILU: unknown reordering")
3131 for (
int i=0; i<nblockrows; ++i)
3139 for (
int i=0; i<nblockrows; ++i)
3145 std::vector<std::vector<int>> unique_block_cols_perminv(nblockrows);
3146 for (
int i=0; i<nblockrows; ++i)
3148 std::vector<int> &cols = unique_block_cols_perminv[i];
3149 for (
int j : unique_block_cols[P[i]])
3151 cols.push_back(Pinv[j]);
3153 std::sort(cols.begin(), cols.end());
3160 AB.
SetSize(block_size, block_size, nnz);
3161 DB.
SetSize(block_size, block_size, nblockrows);
3164 ipiv.
SetSize(block_size*nblockrows);
3167 for (
int iblock = 0; iblock < nblockrows; ++iblock)
3169 int iblock_perm = P[iblock];
3170 for (
int jblock : unique_block_cols_perminv[iblock])
3172 int jblock_perm = P[jblock];
3173 if (iblock == jblock)
3175 ID[iblock] = counter;
3177 JB[counter] = jblock;
3178 for (
int bi = 0; bi < block_size; ++bi)
3180 int i = iblock_perm*block_size + bi;
3181 for (
int k = I[i]; k < I[i + 1]; ++k)
3184 if (j >= jblock_perm*block_size && j < (jblock_perm + 1)*block_size)
3186 int bj = j - jblock_perm*block_size;
3188 AB(bi, bj, counter) = val;
3190 if (iblock == jblock)
3192 DB(bi, bj, iblock) = val;
3199 IB[iblock + 1] = counter;
3203void BlockILU::Factorize()
3205 int nblockrows =
Height()/block_size;
3208 for (
int i=0; i<nblockrows; ++i)
3210 LUFactors factorization(DB.
GetData(i), &ipiv[i*block_size]);
3211 factorization.Factor(block_size);
3217 DenseMatrix A_ik, A_ij, A_kj;
3219 for (
int i=1; i<nblockrows; ++i)
3222 for (
int kk=IB[i]; kk<IB[i+1]; ++kk)
3226 if (k == i) {
break; }
3229 MFEM_ABORT(
"Matrix must be sorted with nonzero diagonal");
3231 LUFactors A_kk_inv(DB.
GetData(k), &ipiv[k*block_size]);
3232 A_ik.UseExternalData(&AB(0,0,kk), block_size, block_size);
3234 A_kk_inv.RightSolve(block_size, block_size, A_ik.GetData());
3236 for (
int jj=kk+1; jj<IB[i+1]; ++jj)
3239 if (j <= k) {
continue; }
3240 A_ij.UseExternalData(&AB(0,0,jj), block_size, block_size);
3241 for (
int ll=IB[k]; ll<IB[k+1]; ++ll)
3246 A_kj.UseExternalData(&AB(0,0,ll), block_size, block_size);
3253 LUFactors factorization(DB.
GetData(i), &ipiv[i*block_size]);
3254 factorization.Factor(block_size);
3266 MFEM_VERIFY(
height > 0,
"BlockILU(0) preconditioner is not constructed");
3267 int nblockrows =
Height()/block_size;
3276 for (
int i=0; i<nblockrows; ++i)
3279 for (
int ib=0; ib<block_size; ++ib)
3281 yi[ib] =
b[ib + P[i]*block_size];
3283 for (
int k=IB[i]; k<ID[i]; ++k)
3293 for (
int i=nblockrows-1; i >= 0; --i)
3296 for (
int ib=0; ib<block_size; ++ib)
3298 xi[ib] = y[ib + i*block_size];
3300 for (
int k=ID[i]+1; k<IB[i+1]; ++k)
3308 LUFactors A_ii_inv(&DB(0,0,i), &ipiv[i*block_size]);
3320 real_t bc_norm_squared = 0.0;
3326 bc_norm_squared += r_entry*r_entry;
3331 if (comm != MPI_COMM_NULL)
3333 double glob_bc_norm_squared = 0.0;
3334 MPI_Reduce(&bc_norm_squared, &glob_bc_norm_squared, 1,
3337 bc_norm_squared = glob_bc_norm_squared;
3339 MPI_Comm_rank(comm, &rank);
3340 print = (rank == 0);
3343 if ((it == 0 ||
final || bc_norm_squared > 0.0) && print)
3345 mfem::out <<
" ResidualBCMonitor : b.c. residual norm = "
3346 << sqrt(bc_norm_squared) << endl;
3351#ifdef MFEM_USE_SUITESPARSE
3376 umfpack_di_free_numeric(&
Numeric);
3380 umfpack_dl_free_numeric(&
Numeric);
3385 MFEM_VERIFY(
mat,
"not a SparseMatrix");
3394 MFEM_VERIFY(
width ==
height,
"not a square matrix");
3407 umfpack_di_report_status(
Control, status);
3409 " umfpack_di_symbolic() failed!");
3417 umfpack_di_report_status(
Control, status);
3419 " umfpack_di_numeric() failed!");
3421 umfpack_di_free_symbolic(&
Symbolic);
3425 SuiteSparse_long status;
3429 AI =
new SuiteSparse_long[
width + 1];
3430 AJ =
new SuiteSparse_long[Ap[
width]];
3431 for (
int i = 0; i <=
width; i++)
3433 AI[i] = (SuiteSparse_long)(Ap[i]);
3435 for (
int i = 0; i < Ap[
width]; i++)
3437 AJ[i] = (SuiteSparse_long)(Ai[i]);
3445 umfpack_dl_report_status(
Control, status);
3447 " umfpack_dl_symbolic() failed!");
3455 umfpack_dl_report_status(
Control, status);
3457 " umfpack_dl_numeric() failed!");
3459 umfpack_dl_free_symbolic(&
Symbolic);
3466 mfem_error(
"UMFPackSolver::Mult : matrix is not set!"
3467 " Call SetOperator first!");
3479 umfpack_di_report_status(
Control, status);
3480 mfem_error(
"UMFPackSolver::Mult : umfpack_di_solve() failed!");
3485 SuiteSparse_long status =
3492 umfpack_dl_report_status(
Control, status);
3493 mfem_error(
"UMFPackSolver::Mult : umfpack_dl_solve() failed!");
3501 mfem_error(
"UMFPackSolver::MultTranspose : matrix is not set!"
3502 " Call SetOperator first!");
3514 umfpack_di_report_status(
Control, status);
3516 " umfpack_di_solve() failed!");
3521 SuiteSparse_long status =
3528 umfpack_dl_report_status(
Control, status);
3530 " umfpack_dl_solve() failed!");
3543 umfpack_di_free_numeric(&
Numeric);
3547 umfpack_dl_free_numeric(&
Numeric);
3562 "Had Numeric pointer in KLU, but not Symbolic");
3570 MFEM_VERIFY(
mat != NULL,
"not a SparseMatrix");
3578 MFEM_VERIFY(
width ==
height,
"not a square matrix");
3590 MFEM_VERIFY(
mat != NULL,
3591 "KLUSolver::Mult : matrix is not set! Call SetOperator first!");
3604 MFEM_VERIFY(
mat != NULL,
3605 "KLUSolver::Mult : matrix is not set! Call SetOperator first!");
3632 for (
int i = 0; i < block_dof.
NumRows(); ++i)
3637 block_solvers[i].SetOperator(sub_A);
3646 for (
int i = 0; i < block_dof.
NumRows(); ++i)
3651 block_solvers[i].Mult(sub_rhs, sub_sol);
3665 add(-1.0, z, 1.0, x, z);
3682 add(-1.0, z, 1.0, x, z);
3691 :
Solver(0, false), global_size(-1)
3699 :
Solver(0, false), mycomm(mycomm_), global_size(-1), parallel(true) { }
3707 MFEM_VERIFY(
height ==
width,
"Solver must be a square Operator!");
3713 MFEM_VERIFY(solver,
"Solver hasn't been set, call SetSolver() first.");
3717 MFEM_VERIFY(
height ==
width,
"Solver must be a square Operator!");
3723 MFEM_VERIFY(solver,
"Solver hasn't been set, call SetSolver() first.");
3725 "solver was modified externally! call SetSolver() again!");
3726 MFEM_VERIFY(
height ==
b.Size(),
"incompatible input Vector size!");
3727 MFEM_VERIFY(
height == x.
Size(),
"incompatible output Vector size!");
3730 Orthogonalize(
b, b_ortho);
3736 solver->
Mult(b_ortho, x);
3739 Orthogonalize(x, x);
3742void OrthoSolver::Orthogonalize(
const Vector &v,
Vector &v_ortho)
const
3744 if (global_size == -1)
3750 MPI_Allreduce(MPI_IN_PLACE, &global_size, 1, HYPRE_MPI_BIG_INT,
3763 MPI_Allreduce(MPI_IN_PLACE, &global_sum, 1, MPITypeMap<real_t>::mpi_type,
3768 real_t ratio = global_sum /
static_cast<real_t>(global_size);
3773 for (
int i = 0; i < v_ortho.
Size(); ++i)
3775 v_ortho(i) = v(i) - ratio;
3782 bool op_is_symmetric,
3784 :
Solver(op.NumRows()), aux_map_(aux_map, own_aux_map)
3786 aux_system_.
Reset(
RAP(&op, aux_map));
3789 aux_smoother_.
As<
HypreSmoother>()->SetOperatorSymmetry(op_is_symmetric);
3792void AuxSpaceSmoother::Mult(
const Vector &x,
Vector &y,
bool transpose)
const
3797 Vector aux_sol(aux_rhs.Size());
3804 aux_smoother_->
Mult(aux_rhs, aux_sol);
3808 aux_map_->
Mult(aux_sol, y);
3812#ifdef MFEM_USE_LAPACK
3815 :
Solver(0), mat(nullptr), const_tol_(1.0e-14), min_nnz_(0),
3816 max_nnz_(0), verbosity_(0), res_change_termination_tol_(1.0e-4),
3817 zero_tol_(1.0e-14), rhs_delta_(1.0e-11), n_outer_(100000),
3818 n_inner_(100000), nStallCheck_(100), normalize_(true),
3825 MFEM_VERIFY(mat,
"NNLSSolver operator must be of type DenseMatrix");
3838 qr_residual_mode_ = qr_residual_mode;
3841 NNLS_qrres_on_ =
true;
3850 MFEM_VERIFY(rhs_lb.
Size() == m && rhs_ub.
Size() == m,
"");
3856 Vector rhs_halfgap = rhs_ub;
3857 rhs_halfgap -= rhs_lb;
3860 Vector rhs_avg_glob = rhs_avg;
3861 Vector rhs_halfgap_glob = rhs_halfgap;
3862 Vector halfgap_target(m);
3863 halfgap_target = 1.0e3 * const_tol_;
3868 for (
int i=0; i<m; ++i)
3870 const real_t s = halfgap_target(i) / rhs_halfgap_glob(i);
3871 row_scaling_[i] = s;
3873 rhs_lb(i) = (rhs_avg(i) * s) - halfgap_target(i);
3874 rhs_ub(i) = (rhs_avg(i) * s) + halfgap_target(i);
3880 MFEM_VERIFY(mat,
"NNLSSolver operator must be of type DenseMatrix");
3882 mat->
Mult(w, rhs_ub);
3883 rhs_ub *= row_scaling_;
3888 for (
int i=0; i<rhs_ub.
Size(); ++i)
3890 rhs_lb(i) -= rhs_delta_;
3891 rhs_ub(i) += rhs_delta_;
3895 Solve(rhs_lb, rhs_ub, sol);
3900 for (
int i=0; i<sol.
Size(); ++i)
3908 mfem::out <<
"Number of nonzeros in NNLSSolver solution: " << nnz
3909 <<
", out of " << sol.
Size() << endl;
3913 mat->
Mult(sol, res);
3914 res *= row_scaling_;
3920 const real_t relNorm = res.
Norml2() / std::max(normGsol, normRHS);
3921 mfem::out <<
"Relative residual norm for NNLSSolver solution of Gs = Gw: "
3932 MFEM_VERIFY(rhs_lb.
Size() == m && rhs_lb.
Size() == m && soln.
Size() == n,
"");
3933 MFEM_VERIFY(n >= m,
"NNLSSolver system cannot be over-determined.");
3945 Vector rhs_halfgap(rhs_ub);
3946 rhs_halfgap -= rhs_lb;
3949 Vector rhs_avg_glob(rhs_avg);
3950 Vector rhs_halfgap_glob(rhs_halfgap);
3959 std::vector<unsigned int> nz_ind(m);
3966 int min_nnz_cap = std::min(
static_cast<int>(min_nnz_), std::min(m,n));
3968 std::vector<real_t> l2_res_hist;
3969 std::vector<unsigned int> stalled_indices;
3970 int stalledFlag = 0;
3971 int num_stalled = 0;
3972 int nz_ind_zero = 0;
3975 Vector soln_nz_glob_up(m);
3978 Vector mat_0_data(m * n);
3979 Vector mat_qr_data(m * n);
3980 Vector submat_data(m * n);
3988 std::vector<real_t> work;
3989 int n_outer_iter = 0;
3990 int n_total_inner_iter = 0;
3997 res_glob = rhs_avg_glob;
3998 Vector qt_rhs_glob = rhs_avg_glob;
3999 Vector qqt_rhs_glob = qt_rhs_glob;
4000 Vector sub_qt = rhs_avg_glob;
4006 Vector rhs_scaled(rhs_halfgap_glob);
4008 rhs_scaled *= row_scaling_;
4011 mu_tol = 1.0e-15 * tmp.
Max();
4017 for (
int oiter = 0; oiter < n_outer_; ++oiter)
4021 rmax = fabs(res_glob(0)) - rhs_halfgap_glob(0);
4022 for (
int i=1; i<m; ++i)
4024 rmax = std::max(rmax, fabs(res_glob(i)) - rhs_halfgap_glob(i));
4027 l2_res_hist.push_back(res_glob.
Norml2());
4031 mfem::out <<
"NNLS " << oiter <<
" " << n_total_inner_iter <<
" " << m
4032 <<
" " << n <<
" " << n_glob <<
" " << rmax <<
" "
4033 << l2_res_hist[oiter] << endl;
4035 if (rmax <= const_tol_ && n_glob >= min_nnz_cap)
4039 mfem::out <<
"NNLS target tolerance met" << endl;
4045 if (n_glob >= max_nnz_)
4049 mfem::out <<
"NNLS target nnz met" << endl;
4059 mfem::out <<
"NNLS system is square... exiting" << endl;
4066 if (oiter > nStallCheck_)
4070 for (
int i=0; i<nStallCheck_/2; ++i)
4072 mean0 += l2_res_hist[oiter - i];
4073 mean1 += l2_res_hist[oiter - (nStallCheck_) - i];
4076 real_t mean_res_change = (mean1 / mean0) - 1.0;
4077 if (std::abs(mean_res_change) < res_change_termination_tol_)
4081 mfem::out <<
"NNLSSolver stall detected... exiting" << endl;
4089 res_glob *= row_scaling_;
4092 for (
int i = 0; i < n_nz_ind; ++i)
4094 mu(nz_ind[i]) = 0.0;
4096 for (
unsigned int i = 0; i < stalled_indices.size(); ++i)
4098 mu(stalled_indices[i]) = 0.0;
4105 num_stalled = stalled_indices.size();
4106 if (num_stalled > 0)
4110 mfem::out <<
"NNLS Lagrange multiplier is below the minimum "
4111 <<
"threshold: mumax = " << mumax <<
", mutol = "
4112 << mu_tol <<
"\n" <<
" Resetting stalled indices "
4113 <<
"vector of size " << num_stalled <<
"\n";
4115 stalled_indices.resize(0);
4119 for (
int i = 0; i < n_nz_ind; ++i)
4121 mu(nz_ind[i]) = 0.0;
4131 for (
int i=1; i<n; ++i)
4142 nz_ind[n_nz_ind] = imax;
4147 mfem::out <<
"Found next index: " << imax <<
" " << mumax << endl;
4150 for (
int i=0; i<m; ++i)
4152 mat_0_data(i + (n_glob*m)) = (*mat)(i,imax) * row_scaling_[i];
4153 mat_qr_data(i + (n_glob*m)) = mat_0_data(i + (n_glob*m));
4156 i_qr_start = n_glob;
4161 mfem::out <<
"Updated matrix with new index" << endl;
4164 for (
int iiter = 0; iiter < n_inner_; ++iiter)
4166 ++n_total_inner_iter;
4169 const bool incremental_update =
true;
4170 n_update = n_glob - i_qr_start;
4171 m_update = m - i_qr_start;
4172 if (incremental_update)
4178 MFEM_LAPACK_PREFIX(ormqr_)(&lside, &
trans, &m, &n_update,
4179 &i_qr_start, mat_qr_data.
GetData(), &m,
4181 mat_qr_data.
GetData() + (i_qr_start * m),
4182 &m, work.data(), &lwork, &info);
4183 MFEM_VERIFY(info == 0,
"");
4184 lwork =
static_cast<int>(work[0]);
4186 MFEM_LAPACK_PREFIX(ormqr_)(&lside, &
trans, &m, &n_update,
4187 &i_qr_start, mat_qr_data.
GetData(), &m,
4189 mat_qr_data.
GetData() + (i_qr_start * m),
4190 &m, work.data(), &lwork, &info);
4191 MFEM_VERIFY(info == 0,
"");
4198 for (
int i=0; i<m_update; ++i)
4199 for (
int j=0; j<n_update; ++j)
4201 submat_data[i + (j * m_update)] =
4202 mat_qr_data[i + i_qr_start + ((j + i_qr_start) * m)];
4206 for (
int j=0; j<n_update; ++j)
4208 sub_tau[j] = tau[i_qr_start + j];
4211 MFEM_LAPACK_PREFIX(geqrf_)(&m_update, &n_update, submat_data.
GetData(),
4212 &m_update, sub_tau.
GetData(), work.data(),
4214 MFEM_VERIFY(info == 0,
"");
4215 lwork =
static_cast<int>(work[0]);
4216 if (lwork == 0) { lwork = 1; }
4218 MFEM_LAPACK_PREFIX(geqrf_)(&m_update, &n_update, submat_data.
GetData(),
4219 &m_update, sub_tau.
GetData(), work.data(),
4221 MFEM_VERIFY(info == 0,
"");
4224 for (
int i=0; i<m_update; ++i)
4225 for (
int j=0; j<n_update; ++j)
4227 mat_qr_data[i + i_qr_start + ((j + i_qr_start)* m)] =
4228 submat_data[i + (j * m_update)];
4231 for (
int j=0; j<n_update; ++j)
4233 tau[i_qr_start + j] = sub_tau[j];
4239 for (
int i=0; i<m; ++i)
4240 for (
int j=0; j<n_glob; ++j)
4242 mat_qr_data(i + (j*m)) = mat_0_data(i + (j*m));
4249 MFEM_LAPACK_PREFIX(geqrf_)(&m, &n_glob, mat_qr_data.
GetData(), &m,
4250 tau.
GetData(), work.data(), &lwork, &info);
4251 MFEM_VERIFY(info == 0,
"");
4252 lwork =
static_cast<int>(work[0]);
4254 MFEM_LAPACK_PREFIX(geqrf_)(&m, &n_glob, mat_qr_data.
GetData(), &m,
4255 tau.
GetData(), work.data(), &lwork, &info);
4256 MFEM_VERIFY(info == 0,
"");
4261 mfem::out <<
"Updated QR " << iiter << endl;
4265 if (incremental_update && iiter == 0)
4275 for (
int i=0; i<m_update; ++i)
4277 submat_data[i] = mat_qr_data[i + i_qr_start + (i_qr_start * m)];
4278 sub_qt[i] = qt_rhs_glob[i + i_qr_start];
4281 sub_tau[0] = tau[i_qr_start];
4283 MFEM_LAPACK_PREFIX(ormqr_)(&lside, &
trans, &m_update, &ione, &ione,
4284 submat_data.
GetData(), &m_update,
4286 &m_update, work.data(), &lwork, &info);
4287 MFEM_VERIFY(info == 0,
"");
4288 lwork =
static_cast<int>(work[0]);
4290 MFEM_LAPACK_PREFIX(ormqr_)(&lside, &
trans, &m_update, &ione, &ione,
4291 submat_data.
GetData(), &m_update,
4293 &m_update, work.data(), &lwork, &info);
4294 MFEM_VERIFY(info == 0,
"");
4296 for (
int i=0; i<m_update; ++i)
4298 qt_rhs_glob[i + i_qr_start] = sub_qt[i];
4304 qt_rhs_glob = rhs_avg_glob;
4307 MFEM_LAPACK_PREFIX(ormqr_)(&lside, &
trans, &m, &ione, &n_glob,
4310 work.data(), &lwork, &info);
4311 MFEM_VERIFY(info == 0,
"");
4312 lwork =
static_cast<int>(work[0]);
4314 MFEM_LAPACK_PREFIX(ormqr_)(&lside, &
trans, &m, &ione, &n_glob,
4317 work.data(), &lwork, &info);
4318 MFEM_VERIFY(info == 0,
"");
4323 mfem::out <<
"Updated rhs " << iiter << endl;
4330 MFEM_LAPACK_PREFIX(trsm_)(&lside, &upper, ¬rans, &nounit,
4331 &n_glob, &ione, &fone,
4337 mfem::out <<
"Solved triangular system " << iiter << endl;
4342 real_t smin = n_glob > 0 ? vec1(0) : 0.0;
4343 for (
int i=0; i<n_glob; ++i)
4345 soln_nz_glob_up(i) = vec1(i);
4346 smin = std::min(smin, soln_nz_glob_up(i));
4349 if (smin > zero_tol_)
4352 for (
int i=0; i<n_glob; ++i)
4354 soln_nz_glob(i) = soln_nz_glob_up(i);
4365 mfem::out <<
"Start pruning " << iiter << endl;
4366 for (
int i = 0; i < n_glob; ++i)
4368 if (soln_nz_glob_up(i) <= zero_tol_)
4370 mfem::out << i <<
" " << n_glob <<
" " << soln_nz_glob_up(i) << endl;
4375 if (soln_nz_glob_up(n_glob - 1) <= zero_tol_)
4382 mfem::out <<
"Detected stall due to adding and removing same "
4383 <<
"column. Switching to QR residual calculation "
4384 <<
"method." << endl;
4388 mfem::out <<
"Detected stall due to adding and removing same"
4389 <<
" column. Exiting now." << endl;
4396 NNLS_qrres_on_ =
true;
4403 for (
int i = 0; i < n_glob; ++i)
4405 if (soln_nz_glob_up(i) <= zero_tol_)
4407 alpha = std::min(
alpha, soln_nz_glob(i)/(soln_nz_glob(i) - soln_nz_glob_up(i)));
4412 for (
int i = 0; i < n_glob; ++i)
4414 soln_nz_glob(i) +=
alpha*(soln_nz_glob_up(i) - soln_nz_glob(i));
4415 if (i == 0 || soln_nz_glob(i) < smin)
4417 smin = soln_nz_glob(i);
4421 while (smin > zero_tol_)
4429 smin = soln_nz_glob(0);
4430 for (
int i = 1; i < n_glob; ++i)
4432 if (soln_nz_glob(i) < smin)
4434 smin = soln_nz_glob(i);
4439 alpha = soln_nz_glob(index_min)/(soln_nz_glob(index_min)
4440 - soln_nz_glob_up(index_min));
4443 for (
int i = 0; i < n_glob; ++i)
4445 soln_nz_glob(i) +=
alpha*(soln_nz_glob_up(i) - soln_nz_glob(i));
4450 i_qr_start = n_glob+1;
4456 smin = n_glob > 0 ? soln_nz_glob(0) : 0.0;
4457 for (
int i=1; i<n_glob; ++i)
4459 smin = std::min(smin, soln_nz_glob(i));
4462 if (smin < zero_tol_)
4471 if (zero_ibool == 0)
4480 for (
int i = 0; i < n_glob; ++i)
4482 if (soln_nz_glob(i) < zero_tol_)
4488 MFEM_VERIFY(ind_zero != -1,
"");
4491 for (
int i = 0; i < ind_zero; ++i)
4498 for (
int i=0; i<m; ++i)
4499 for (
int j=ind_zero; j<n_glob-1; ++j)
4501 mat_qr_data(i + (j*m)) = mat_0_data(i + ((j+1)*m));
4506 for (
int i=0; i<m; ++i)
4507 for (
int j=ind_zero; j<n_glob-1; ++j)
4509 mat_0_data(i + (j*m)) = mat_qr_data(i + (j*m));
4514 for (
int i = nz_ind_zero; i < n_nz_ind-1; ++i)
4516 nz_ind[i] = nz_ind[i+1];
4521 for (
int i = ind_zero; i < n_glob-1; ++i)
4523 soln_nz_glob(i) = soln_nz_glob(i+1);
4526 i_qr_start = std::min(i_qr_start, ind_zero);
4532 mfem::out <<
"Finished pruning " << iiter << endl;
4537 if (stalledFlag == 1)
4541 num_stalled = stalled_indices.size();
4542 stalled_indices.resize(num_stalled + 1);
4543 stalled_indices[num_stalled] = imax;
4546 mfem::out <<
"Adding index " << imax <<
" to stalled index list "
4547 <<
"of size " << num_stalled << endl;
4552 if (!NNLS_qrres_on_)
4554 res_glob = rhs_avg_glob;
4556 MFEM_LAPACK_PREFIX(gemv_)(¬rans, &m, &n_glob, &fmone,
4558 soln_nz_glob.
GetData(), &ione, &fone,
4568 for (
int i=0; i<n_glob; ++i)
4570 qqt_rhs_glob(i) = qt_rhs_glob(i);
4573 MFEM_LAPACK_PREFIX(ormqr_)(&lside, ¬rans, &m, &ione, &n_glob,
4576 work.data(), &lwork, &info);
4578 MFEM_VERIFY(info == 0,
"");
4579 lwork =
static_cast<int>(work[0]);
4581 MFEM_LAPACK_PREFIX(ormqr_)(&lside, ¬rans, &m, &ione, &n_glob,
4584 work.data(), &lwork, &info);
4585 MFEM_VERIFY(info == 0,
"");
4586 res_glob = rhs_avg_glob;
4587 res_glob -= qqt_rhs_glob;
4592 mfem::out <<
"Computed residual" << endl;
4599 MFEM_VERIFY(n_glob == n_nz_ind,
"");
4601 for (
int i = 0; i < n_glob; ++i)
4603 soln(nz_ind[i]) = soln_nz_glob(i);
4608 mfem::out <<
"NNLS solver: m = " << m <<
", n = " << n
4609 <<
", outer_iter = " << n_outer_iter <<
", inner_iter = "
4610 << n_total_inner_iter;
4618 mfem::out << endl <<
"Warning, NNLS convergence stalled: "
4619 << (exit_flag == 2) << endl;
4620 mfem::out <<
"resErr = " << rmax <<
" vs tol = " << const_tol_
4621 <<
"; mumax = " << mumax <<
" vs tol = " << mu_tol << endl;
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
int Size() const
Return the logical size of the array.
bool UseDevice() const
Return the device flag of the Memory object used by the Array.
void MakeRef(T *data_, int size_, bool own_data=false)
Make this Array a reference to a pointer.
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
AuxSpaceSmoother(const HypreParMatrix &op, HypreParMatrix *aux_map, bool op_is_symmetric=true, bool own_aux_map=false)
void Mult(const Vector &b, Vector &x) const override
Iterative solution of the linear system using the BiCGSTAB method.
void SetOperator(const Operator &op) override
Set/update the solver for the given operator.
Reordering
The reordering method used by the BlockILU factorization.
BlockILU(int block_size_, Reordering reordering_=Reordering::MINIMUM_DISCARDED_FILL, int k_fill_=0)
void Mult(const Vector &b, Vector &x) const
Solve the system LUx = b, where L and U are the block ILU factors.
void SetOperator(const Operator &op)
Conjugate gradient method.
void Mult(const Vector &b, Vector &x) const override
Iterative solution of the linear system using the Conjugate Gradient method.
void SetOperator(const Operator &op) override
Set/update the solver for the given operator.
virtual real_t Eval(const Vector &x, const Vector &y) override
Compute the inner product (x,y) of vectors x and y, only on the constrained entries.
Vector xr
List of constrained indices.
Array< int > constraint_list
virtual void Mult(const Vector &x, Vector &y) const override
Apply the constraint to vector x and return in y.
void SetIndices(const Array< int > &list)
Set/update the list of constraint indices.
Data type dense matrix using column-major storage.
void AddMult_a(real_t a, const Vector &x, Vector &y) const
y += a * A.x
void Mult(const real_t *x, real_t *y) const
Matrix vector multiplication.
void MultTranspose(const real_t *x, real_t *y) const
Multiply a vector with the transpose matrix.
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
void Add(const real_t c, const DenseMatrix &A)
Adds the matrix A multiplied by the number c to the matrix.
void SetSize(int i, int j, int k, MemoryType mt_=MemoryType::PRESERVE)
static MemoryClass GetMemoryClass()
(DEPRECATED) Equivalent to GetDeviceMemoryClass().
void Mult(const Vector &x, Vector &y) const override
Direct solution of the block diagonal linear system.
DirectSubBlockSolver(const SparseMatrix &A, const SparseMatrix &block_dof)
void Mult(const Vector &b, Vector &x) const override
Iterative solution of the linear system using the FGMRES method.
virtual int GetTrueVSize() const
Return the number of vector true (conforming) dofs.
void SetKDim(int dim)
Set the number of iteration to perform between restarts, default is 50.
void Mult(const Vector &b, Vector &x) const override
Iterative solution of the linear system using the GMRES method.
Wrapper for hypre's ParCSR matrix class.
void GetDiag(Vector &diag) const
Get the local diagonal of the matrix.
Parallel smoothers in hypre.
virtual real_t Eval(const Vector &x, const Vector &y)=0
Compute the inner product (x,y) of vectors x and y. This is an abstract method that must be implement...
virtual real_t Dot(const Vector &x, const Vector &y) const
Standard global/local inner product.
virtual void MonitorSolution(int it, real_t norm, const Vector &x, bool final)
Monitor the solution vector x.
const class IterativeSolver * iter_solver
The last IterativeSolver to which this controller was attached.
virtual void MonitorResidual(int it, real_t norm, const Vector &r, bool final)
Monitor the solution vector r.
Abstract base class for iterative solver.
real_t abs_tol
Absolute tolerance.
InnerProductOperator * dot_oper
real_t rel_tol
Relative tolerance.
PrintLevel print_options
Output behavior for the iterative solver.
real_t GetFinalNorm() const
Returns the final residual norm after termination of the solver during the last call to Mult().
void SetOperator(const Operator &op) override
Also calls SetOperator for the preconditioner if there is one.
virtual real_t Dot(const Vector &x, const Vector &y) const
Return the standard (l2, i.e., Euclidean) inner product of x and y.
void SetRelTol(real_t rtol)
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
bool ControllerRequiresUpdate() const
Indicated if the controller requires an update of the solution.
int print_level
(DEPRECATED) Legacy print level definition, which is left for compatibility with custom iterative sol...
int GetNumIterations() const
Returns the number of iterations taken during the last call to Mult()
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
int max_iter
Limit for the number of iterations the solver is allowed to do.
void SetMaxIter(int max_it)
bool Monitor(int it, real_t norm, const Vector &r, const Vector &x, bool final=false) const
Monitor both the residual r and the solution x.
IterativeSolverController * controller
MPI_Comm GetComm() const
Return the associated MPI communicator, or MPI_COMM_NULL if no communicator is set.
static int GuessLegacyPrintLevel(PrintLevel)
Use some heuristics to guess a legacy print level corresponding to the given PrintLevel.
bool GetConverged() const
Returns true if the last call to Mult() converged successfully.
PrintLevel FromLegacyPrintLevel(int)
Convert a legacy print level integer to a PrintLevel object.
void SetAbsTol(real_t atol)
real_t Norm(const Vector &x) const
Return the inner product norm of x, using the inner product defined by Dot()
void MultTranspose(const Vector &b, Vector &x) const override
Direct solution of the transposed linear system using KLU.
void Mult(const Vector &b, Vector &x) const override
Direct solution of the linear system using KLU.
void SetOperator(const Operator &op) override
Set/update the solver for the given operator.
Array< Vector * > skArray
void Mult(const Vector &b, Vector &x) const override
Solve the nonlinear system with right-hand side b.
Array< Vector * > ykArray
void Solve(int m, int n, real_t *X) const override
void Mult(const Vector &b, Vector &x) const override
Iterative solution of the linear system using the MINRES method.
void SetOperator(const Operator &op) override
Also calls SetOperator for the preconditioner if there is one.
void SetPreconditioner(Solver &pr) override
This should be called before SetOperator.
void Solve(const Vector &rhs_lb, const Vector &rhs_ub, Vector &soln) const
Solve the NNLS problem. Specifically, we find a vector soln, such that rhs_lb < mat*soln < rhs_ub is ...
QRresidualMode
Enumerated types of QRresidual mode. Options are 'off': the residual is calculated normally,...
void Mult(const Vector &w, Vector &sol) const override
Compute the non-negative least squares solution to the underdetermined system.
void SetQRResidualMode(const QRresidualMode qr_residual_mode)
Set the residual calculation mode for the NNLS solver. See QRresidualMode enum above for details.
void SetOperator(const Operator &op) override
The operator must be a DenseMatrix.
void NormalizeConstraints(Vector &rhs_lb, Vector &rhs_ub) const
Normalize the constraints such that the tolerances for each constraint (i.e. (UB - LB)/2) are equal....
void SetAdaptiveLinRtol(const int type=2, const real_t rtol0=0.5, const real_t rtol_max=0.9, const real_t alpha=0.5 *(1.0+sqrt(5.0)), const real_t gamma=1.0)
Enable adaptive linear solver relative tolerance algorithm.
void AdaptiveLinRtolPreSolve(const Vector &x, const int it, const real_t fnorm) const
Method for the adaptive linear solver rtol invoked before the linear solve.
virtual real_t ComputeScalingFactor(const Vector &x, const Vector &b) const
This method can be overloaded in derived classes to implement line search algorithms.
void Mult(const Vector &b, Vector &x) const override
Solve the nonlinear system with right-hand side b.
void AdaptiveLinRtolPostSolve(const Vector &x, const Vector &b, const int it, const real_t fnorm) const
Method for the adaptive linear solver rtol invoked after the linear solve.
virtual void ProcessNewState(const Vector &x) const
This method can be overloaded in derived classes to perform computations that need knowledge of the n...
void SetOperator(const Operator &op) override
Also calls SetOperator for the preconditioner if there is one.
Chebyshev accelerated smoothing with given vector, no matrix necessary.
void Mult(const Vector &x, Vector &y) const
Approach the solution of the linear system by applying Chebyshev smoothing.
OperatorChebyshevSmoother(const Operator &oper_, const Vector &d, const Array< int > &ess_tdof_list, int order, real_t max_eig_estimate)
OpType * As() const
Return the Operator pointer statically cast to a specified OpType. Similar to the method Get().
void Reset(OpType *A, bool own_A=true)
Reset the OperatorHandle to the given OpType pointer, A.
Jacobi smoothing for a given bilinear form (no matrix necessary).
void Setup(const Vector &diag)
OperatorJacobiSmoother(const real_t damping=1.0)
Default constructor: the diagonal will be computed by subsequent calls to SetOperator() using the Ope...
void SetOperator(const Operator &op)
Recompute the diagonal using the method AssembleDiagonal of the given new Operator,...
void Mult(const Vector &x, Vector &y) const
Approach the solution of the linear system by applying Jacobi smoothing.
virtual MemoryClass GetMemoryClass() const
Return the MemoryClass preferred by the Operator.
int width
Dimension of the input / number of columns in the matrix.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
int height
Dimension of the output / number of rows in the matrix.
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
int NumCols() const
Get the number of columns (size of input) of the Operator. Synonym with Width().
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
virtual void AssembleDiagonal(Vector &diag) const
Computes the diagonal entries into diag. Typically, this operation only makes sense for linear Operat...
int NumRows() const
Get the number of rows (size of output) of the Operator. Synonym with Height().
virtual void MultTranspose(const Vector &x, Vector &y) const
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
virtual Operator & GetGradient(const Vector &x) const
Evaluate the gradient operator at the point x. The default behavior in class Operator is to generate ...
const Operator * C
Not owned, some can remain unused (NULL).
void SetSolutionBounds(const Vector &xl, const Vector &xh)
void SetEqualityConstraint(const Vector &c)
int GetNumConstraints() const
OptimizationProblem(int insize, const Operator *C_, const Operator *D_)
In parallel, insize is the number of the local true dofs.
void SetInequalityConstraint(const Vector &dl, const Vector &dh)
const OptimizationProblem * problem
void SetOperator(const Operator &op) override
Set the Operator that is the OrthoSolver is to invert (approximately).
void SetSolver(Solver &s)
Set the solver used by the OrthoSolver.
void Mult(const Vector &b, Vector &x) const override
Perform the action of the OrthoSolver: P * solver * P where P is the projection to the subspace of ve...
PowerMethod helper class to estimate the largest eigenvalue of an operator using the iterative power ...
real_t EstimateLargestEigenvalue(Operator &opr, Vector &v0, int numSteps=10, real_t tolerance=1e-8, int seed=12345)
Returns an estimate of the largest eigenvalue of the operator opr using the iterative power method.
General product operator: x -> (A*B)(x) = A(B(x)).
void Mult(const Vector &x, Vector &y) const override
Solution of the linear system using a product of subsolvers.
void MultTranspose(const Vector &x, Vector &y) const override
Solution of the transposed linear system using a product of subsolvers.
void MonitorResidual(int it, real_t norm, const Vector &r, bool final) override
Monitor the solution vector r.
const Array< int > * ess_dofs_list
Not owned.
void Mult(const Vector &xt, Vector &x) const override
void SetBounds(const Vector &lo_, const Vector &hi_)
void SetLinearConstraint(const Vector &w_, real_t a_)
void print_iteration(int it, real_t r, real_t l) const
void SetOptimizationProblem(const OptimizationProblem &prob) override
real_t solve(real_t l, const Vector &xt, Vector &x, int &nclip) const
Solve QP at fixed lambda.
Stationary linear iteration: x <- x + B (b - A x)
void Mult(const Vector &b, Vector &x) const override
Iterative solution of the linear system using Stationary Linear Iteration.
void SetOperator(const Operator &op) override
Also calls SetOperator for the preconditioner if there is one.
bool iterative_mode
If true, use the second argument of Mult() as an initial guess.
virtual void SetOperator(const Operator &op)=0
Set/update the solver for the given operator.
const int * HostReadJ() const
void GetDiag(Vector &d) const
Returns the Diagonal of A.
void MultTranspose(const Vector &x, Vector &y) const override
Multiply a vector with the transposed matrix. y = At * x.
void GetSubMatrix(const Array< int > &rows, const Array< int > &cols, DenseMatrix &subm) const
bool Finalized() const
Returns whether or not CSR format has been finalized.
const real_t * HostReadData() const
int * GetRowColumns(const int row)
Return a pointer to the column indices in a row.
int RowSize(const int i) const
Returns the number of elements in row i.
real_t * HostReadWriteData()
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication.
real_t * GetData()
Return the element data, i.e. the array A.
void SortColumnIndices()
Sort the column indices corresponding to each row.
int * GetJ()
Return the array J.
int * GetI()
Return the array I.
const int * HostReadI() const
real_t Control[UMFPACK_CONTROL]
void SetOperator(const Operator &op) override
Factorize the given Operator op which must be a SparseMatrix.
void MultTranspose(const Vector &b, Vector &x) const override
Direct solution of the transposed linear system using UMFPACK.
real_t Info[UMFPACK_INFO]
void Mult(const Vector &b, Vector &x) const override
Direct solution of the linear system using UMFPACK.
virtual const real_t * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
virtual const real_t * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
virtual real_t * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
void SetDataAndSize(real_t *d, int s)
Set the Vector data and size.
void AddElementVector(const Array< int > &dofs, const Vector &elemvect)
Add elements of the elemvect Vector to the entries listed in dofs. Negative dof values cause the -dof...
real_t Norml2() const
Returns the l2 norm of the vector.
Vector & Set(const real_t a, const Vector &x)
(*this) = a * x
real_t Max() const
Returns the maximal element of the vector.
int Size() const
Returns the size of the vector.
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
real_t Sum() const
Return the sum of the vector entries.
void SetSize(int s)
Resize the vector to size s.
virtual real_t * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
virtual real_t * HostReadWrite()
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
virtual real_t * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
Vector & Add(const real_t a, const Vector &Va)
(*this) += a * Va
void MakeRef(Vector &base, int offset, int size)
Reset the Vector to be a reference to a sub-vector of base.
Vector wx
Weighting operator for y.
virtual real_t Eval(const Vector &x, const Vector &y) override
Compute the inner product (Y(y),X(x)) of vectors x and y, weighted by the operators X and Y.
MemoryClass mem_class
Weighted vectors.
virtual void Mult(const Vector &x, Vector &y) const override
Apply the weighting operator to vector x and return in y=Y(X(x)).
void SetOperator(Operator *X, Operator *Y)
Set/update the weighting operators (not owned) for each term.
Operator * operY
Weighting operator for x.
void trans(const Vector &u, Vector &x)
MFEM_HOST_DEVICE dual< value_type, gradient_type > sqrt(dual< value_type, gradient_type > x)
implementation of square root for dual numbers
int BiCGSTAB(const Operator &A, Vector &x, const Vector &b, Solver &M, int &max_iter, real_t &tol, real_t atol, int printit)
BiCGSTAB method. (tolerances are squared)
void mfem_error(const char *msg)
void AddMult_a(real_t alpha, const DenseMatrix &b, const DenseMatrix &c, DenseMatrix &a)
Matrix matrix multiplication. A += alpha * B * C.
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
void add(const Vector &v1, const Vector &v2, Vector &v)
bool IsFinite(const real_t &val)
real_t InnerProduct(HypreParVector *x, HypreParVector *y)
int GMRES(const Operator &A, Vector &x, const Vector &b, Solver &M, int &max_iter, int m, real_t &tol, real_t atol, int printit)
GMRES method. (tolerances are squared)
void ApplyPlaneRotation(real_t &dx, real_t &dy, real_t &cs, real_t &sn)
void RAP(const DenseMatrix &A, const DenseMatrix &P, DenseMatrix &RAP)
void Swap(T &a, T &b)
Swap objects of type T. The operation is performed using the most specialized swap function from the ...
MemoryType GetMemoryType(MemoryClass mc)
Return a suitable MemoryType for a given MemoryClass.
int aGMRES(const Operator &A, Vector &x, const Vector &b, const Operator &M, int &max_iter, int m_max, int m_min, int m_step, real_t cf, real_t &tol, real_t &atol, int printit)
void SLI(const Operator &A, const Vector &b, Vector &x, int print_iter, int max_num_iter, real_t RTOLERANCE, real_t ATOLERANCE)
Stationary linear iteration. (tolerances are squared)
void PCG(const Operator &A, Solver &B, const Vector &b, Vector &x, int print_iter, int max_num_iter, real_t RTOLERANCE, real_t ATOLERANCE)
Preconditioned conjugate gradient method. (tolerances are squared)
void CG(const Operator &A, const Vector &b, Vector &x, int print_iter, int max_num_iter, real_t RTOLERANCE, real_t ATOLERANCE)
Conjugate gradient method. (tolerances are squared)
void GeneratePlaneRotation(real_t &dx, real_t &dy, real_t &cs, real_t &sn)
void MINRES(const Operator &A, const Vector &b, Vector &x, int print_it, int max_it, real_t rtol, real_t atol)
MINRES method without preconditioner. (tolerances are squared)
void subtract(const Vector &x, const Vector &y, Vector &z)
MemoryType
Memory types supported by MFEM.
void MinimumDiscardedFillOrdering(SparseMatrix &C, Array< int > &p)
void forall(int N, lambda &&body)
void Update(Vector &x, int k, DenseMatrix &h, Vector &s, Array< Vector * > &v)
void Add(const DenseMatrix &A, const DenseMatrix &B, real_t alpha, DenseMatrix &C)
C = A + alpha*B.
real_t p(const Vector &x, real_t t)
MFEM_HOST_DEVICE real_t norm(const Complex &z)
MFEM_HOST_DEVICE real_t abs(const Complex &z)
Settings for the output behavior of the IterativeSolver.
PrintLevel & Iterations()
bool errors
If a fatal problem has been detected the failure will be reported to mfem::err.
bool iterations
Detailed information about each iteration will be reported to mfem::out.
PrintLevel & FirstAndLast()
bool warnings
If a non-fatal problem has been detected some context-specific information will be reported to mfem::...
bool first_and_last
Information about the first and last iteration will be printed to mfem::out.
bool summary
A summary of the solver process will be reported after the last iteration to mfem::out.
Helper struct to convert a C++ type to an MPI type.