60 if (dot_prod_type == 0)
74 int print_level_ = print_lvl;
77 if (dot_prod_type != 0)
80 MPI_Comm_rank(comm, &rank);
99 if (dot_prod_type != 0)
102 MPI_Comm_rank(comm, &rank);
105 derived_print_level = -1;
119 if (comm != MPI_COMM_NULL)
121 MPI_Comm_rank(comm, &rank);
125 switch (print_level_)
142 MFEM_WARNING(
"Unknown print level " << print_level_ <<
143 ". Defaulting to level 0.");
159 else if (print_options_.
summary)
191 const Vector& x,
bool final)
const
202 ess_tdof_list(nullptr),
211 Solver(
a.FESpace()->GetTrueVSize()),
214 ess_tdof_list(&ess_tdofs),
219 a.AssembleDiagonal(diag);
233 ess_tdof_list(&ess_tdofs),
266 MFEM_ASSERT(
height ==
width,
"not a square matrix!");
268 ess_tdof_list =
nullptr;
281 auto D = diag.
Read();
282 auto DI = dinv.
Write();
283 const bool use_abs_diag_ = use_abs_diag;
288 MFEM_ABORT_KERNEL(
"Zero diagonal entry in OperatorJacobiSmoother");
290 if (!use_abs_diag_) { DI[i] =
delta / D[i]; }
291 else { DI[i] =
delta / std::abs(D[i]); }
293 if (ess_tdof_list && ess_tdof_list->
Size() > 0)
295 auto I = ess_tdof_list->
Read();
307 MFEM_ASSERT(x.
Size() ==
Width(),
"invalid input vector");
308 MFEM_ASSERT(y.
Size() ==
Height(),
"invalid output vector");
312 MFEM_VERIFY(oper,
"iterative_mode == true requires the forward operator");
313 oper->
Mult(y, residual);
322 auto DI = dinv.
Read();
323 auto R = residual.
Read();
327 Y[i] += DI[i] * R[i];
334 int order_,
real_t max_eig_estimate_)
338 max_eig_estimate(max_eig_estimate_),
343 ess_tdof_list(ess_tdofs),
345 oper(&oper_) {
Setup(); }
351 int order_, MPI_Comm comm,
int power_iterations,
real_t power_tolerance)
356 int order_,
int power_iterations,
real_t power_tolerance)
364 ess_tdof_list(ess_tdofs),
378 power_iterations, power_tolerance);
386 int order_,
real_t max_eig_estimate_)
393 int order_, MPI_Comm comm,
int power_iterations,
real_t power_tolerance)
395 power_iterations, power_tolerance) { }
400 int order_,
int power_iterations,
real_t power_tolerance)
409 auto D = diag.
Read();
410 auto X = dinv.
Write();
411 mfem::forall(N, [=] MFEM_HOST_DEVICE (
int i) { X[i] = 1.0 / D[i]; });
412 auto I = ess_tdof_list.
Read();
421 real_t upper_bound = 1.2 * max_eig_estimate;
422 real_t lower_bound = 0.3 * max_eig_estimate;
423 real_t theta = 0.5 * (upper_bound + lower_bound);
430 coeffs[0] = 1.0 / theta;
435 real_t tmp_0 = 1.0/(pow(
delta, 2) - 2*pow(theta, 2));
436 coeffs[0] = -4*theta*tmp_0;
443 real_t tmp_1 = pow(theta, 2);
444 real_t tmp_2 = 1.0/(-4*pow(theta, 3) + theta*tmp_0);
445 coeffs[0] = tmp_2*(tmp_0 - 12*tmp_1);
446 coeffs[1] = 12/(tmp_0 - 4*tmp_1);
447 coeffs[2] = -4*tmp_2;
453 real_t tmp_1 = pow(theta, 2);
455 real_t tmp_3 = 1.0/(pow(
delta, 4) + 8*pow(theta, 4) - tmp_1*tmp_2);
456 coeffs[0] = tmp_3*(32*pow(theta, 3) - 16*theta*tmp_0);
457 coeffs[1] = tmp_3*(-48*tmp_1 + tmp_2);
458 coeffs[2] = 32*theta*tmp_3;
459 coeffs[3] = -8*tmp_3;
465 real_t tmp_1 = pow(theta, 4);
466 real_t tmp_2 = pow(theta, 2);
470 real_t tmp_6 = 1.0/(16*pow(theta, 5) - pow(theta, 3)*tmp_5 + theta*tmp_0);
472 real_t tmp_8 = 1.0/(tmp_0 + 16*tmp_1 - tmp_2*tmp_5);
473 coeffs[0] = tmp_6*(tmp_0 + 80*tmp_1 - tmp_2*tmp_4);
474 coeffs[1] = tmp_8*(tmp_4 - tmp_7);
475 coeffs[2] = tmp_6*(-tmp_5 + tmp_7);
476 coeffs[3] = -80*tmp_8;
477 coeffs[4] = 16*tmp_6;
481 MFEM_ABORT(
"Chebyshev smoother not implemented for order = " << order);
489 MFEM_ABORT(
"Chebyshev smoother not implemented for iterative mode");
494 MFEM_ABORT(
"Chebyshev smoother requires operator");
503 for (
int k = 0; k < order; ++k)
508 oper->
Mult(residual, helperVector);
509 residual = helperVector;
514 auto Dinv = dinv.
Read();
516 mfem::forall(n, [=] MFEM_HOST_DEVICE (
int i) { R[i] *= Dinv[i]; });
520 auto C = coeffs.
Read();
521 mfem::forall(n, [=] MFEM_HOST_DEVICE (
int i) { Y[i] += C[k] * R[i]; });
570 real_t r0, nom, nom0, nomold = 1, cf;
586 nom0 = nom = sqrt(
Dot(
z,
z));
590 nom0 = nom = sqrt(
Dot(
r,
r));
596 mfem::out <<
" Iteration : " << setw(3) << right << 0 <<
" ||Br|| = "
629 nom = sqrt(
Dot(
z,
z));
633 nom = sqrt(
Dot(
r,
r));
654 mfem::out <<
" Iteration : " << setw(3) << right << (i-1)
655 <<
" ||Br|| = " << setw(11) << left << nom
656 <<
"\tConv. rate: " << cf <<
'\n';
664 const auto rf = pow (nom/nom0, 1.0/
final_iter);
666 <<
"Conv. rate: " << cf <<
'\n'
667 <<
"Average reduction factor: "<< rf <<
'\n';
671 mfem::out <<
"SLI: No convergence!" <<
'\n';
678 int print_iter,
int max_num_iter,
693 int print_iter,
int max_num_iter,
744 nom0 = nom =
Dot(
d,
r);
746 MFEM_ASSERT(
IsFinite(nom),
"nom = " << nom);
749 mfem::out <<
" Iteration : " << setw(3) << 0 <<
" (B r, r) = "
758 mfem::out <<
"PCG: The preconditioner is not positive definite. (Br, r) = "
778 MFEM_ASSERT(
IsFinite(den),
"den = " << den);
783 mfem::out <<
"PCG: The operator is not positive definite. (Ad, d) = "
813 MFEM_ASSERT(
IsFinite(betanom),
"betanom = " << betanom);
818 mfem::out <<
"PCG: The preconditioner is not positive definite. (Br, r) = "
828 mfem::out <<
" Iteration : " << setw(3) << i <<
" (B r, r) = "
829 << betanom << std::endl;
857 MFEM_ASSERT(
IsFinite(den),
"den = " << den);
862 mfem::out <<
"PCG: The operator is not positive definite. (Ad, d) = "
885 const auto arf = pow (betanom/nom0, 0.5/
final_iter);
886 mfem::out <<
"Average reduction factor = " << arf <<
'\n';
890 mfem::out <<
"PCG: No convergence!" <<
'\n';
899 int print_iter,
int max_num_iter,
914 int print_iter,
int max_num_iter,
938 else if (fabs(dy) > fabs(dx))
941 sn = 1.0 / sqrt( 1.0 + temp*temp );
947 cs = 1.0 / sqrt( 1.0 + temp*temp );
954 real_t temp = cs * dx + sn * dy;
955 dy = -sn * dx + cs * dy;
965 for (
int i = k; i >= 0; i--)
968 for (
int j = i - 1; j >= 0; j--)
970 y(j) -= h(j,i) * y(i);
974 for (
int j = 0; j <= k; j++)
1043 <<
" Iteration : " << setw(3) << 0
1044 <<
" ||B r|| = " <<
beta
1054 if (v[0] == NULL) { v[0] =
new Vector(n); }
1055 v[0]->Set(1.0/
beta, r);
1058 for (i = 0; i <
m && j <=
max_iter; i++, j++)
1070 for (k = 0; k <= i; k++)
1072 H(k,i) =
Dot(w, *v[k]);
1073 w.
Add(-H(k,i), *v[k]);
1077 MFEM_ASSERT(
IsFinite(H(i+1,i)),
"Norm(w) = " << H(i+1,i));
1078 if (v[i+1] == NULL) { v[i+1] =
new Vector(n); }
1079 v[i+1]->Set(1.0/H(i+1,i), w);
1081 for (k = 0; k < i; k++)
1090 const real_t resid = fabs(
s(i+1));
1091 MFEM_ASSERT(
IsFinite(resid),
"resid = " << resid);
1104 mfem::out <<
" Pass : " << setw(2) << (j-1)/
m+1
1105 <<
" Iteration : " << setw(3) << j
1106 <<
" ||B r|| = " << resid <<
'\n';
1147 mfem::out <<
" Pass : " << setw(2) << (j-1)/
m+1
1157 mfem::out <<
"GMRES: No convergence!\n";
1162 for (i = 0; i < v.
Size(); i++)
1204 <<
" Iteration : " << setw(3) << 0
1205 <<
" || r || = " <<
beta
1213 for (i= 0; i<=
m; i++)
1222 if (v[0] == NULL) { v[0] =
new Vector(
b.Size()); }
1227 for (i = 0; i <
m && j <=
max_iter; i++, j++)
1230 if (z[i] == NULL) { z[i] =
new Vector(
b.Size()); }
1243 for (k = 0; k <= i; k++)
1245 H(k,i) =
Dot( r, *v[k]);
1246 r.
Add(-H(k,i), (*v[k]));
1250 if (v[i+1] == NULL) { v[i+1] =
new Vector(
b.Size()); }
1252 v[i+1] ->
Add (1.0/H(i+1,i), r);
1254 for (k = 0; k < i; k++)
1263 const real_t resid = fabs(
s(i+1));
1264 MFEM_ASSERT(
IsFinite(resid),
"resid = " << resid);
1268 mfem::out <<
" Pass : " << setw(2) << (j-1)/
m+1
1269 <<
" Iteration : " << setw(3) << j
1270 <<
" || r || = " << resid << endl;
1286 for (i= 0; i<=
m; i++)
1288 if (v[i]) {
delete v[i]; }
1289 if (z[i]) {
delete z[i]; }
1315 for (i = 0; i <=
m; i++)
1317 if (v[i]) {
delete v[i]; }
1318 if (z[i]) {
delete z[i]; }
1327 mfem::out <<
" Pass : " << setw(2) << (j-1)/
m+1
1328 <<
" Iteration : " << setw(3) << j-1
1337 mfem::out <<
"FGMRES: No convergence!\n";
1343 int &max_iter,
int m,
real_t &tol,
real_t atol,
int printit)
1362 int print_iter,
int max_num_iter,
int m,
real_t rtol,
real_t atol)
1364 GMRES(A, x,
b, B, max_num_iter, m, rtol, atol, print_iter);
1402 MFEM_ASSERT(
IsFinite(resid),
"resid = " << resid);
1405 mfem::out <<
" Iteration : " << setw(3) << 0
1413 if (resid <= tol_goal)
1428 mfem::out <<
" Iteration : " << setw(3) << i
1429 <<
" ||r|| = " << resid <<
'\n';
1443 mfem::out <<
"BiCGStab: No convergence!\n";
1469 MFEM_ASSERT(
IsFinite(resid),
"resid = " << resid);
1470 if (resid < tol_goal)
1475 mfem::out <<
" Iteration : " << setw(3) << i
1476 <<
" ||s|| = " << resid <<
'\n';
1489 mfem::out <<
" Iteration : " << setw(3) << i
1490 <<
" ||s|| = " << resid;
1509 MFEM_ASSERT(
IsFinite(resid),
"resid = " << resid);
1512 mfem::out <<
" ||r|| = " << resid <<
'\n';
1515 if (resid < tol_goal)
1522 mfem::out <<
" Iteration : " << setw(3) << i
1523 <<
" ||r|| = " << resid <<
'\n';
1538 mfem::out <<
" Iteration : " << setw(3) << i
1539 <<
" ||r|| = " << resid <<
'\n';
1547 mfem::out <<
"BiCGStab: No convergence!\n";
1560 <<
" ||r|| = " << resid <<
'\n';
1568 mfem::out <<
"BiCGStab: No convergence!\n";
1582 bicgstab.
Mult(
b, x);
1589 int print_iter,
int max_num_iter,
real_t rtol,
real_t atol)
1591 BiCGSTAB(A, x,
b, B, max_num_iter, rtol, atol, print_iter);
1627 real_t beta, eta, gamma0, gamma1, sigma0, sigma1;
1649 MFEM_ASSERT(
IsFinite(eta),
"eta = " << eta);
1650 gamma0 = gamma1 = 1.;
1651 sigma0 = sigma1 = 0.;
1655 if (eta <= norm_goal)
1663 mfem::out <<
"MINRES: iteration " << setw(3) << 0 <<
": ||r||_B = "
1686 rho2 = sigma1*
alpha + gamma0*gamma1*
beta;
1701 w0.
Set(1./rho1, *z);
1705 add(1./rho1, *z, -rho2/rho1,
w1,
w0);
1709 add(-rho3/rho1,
w0, -rho2/rho1,
w1,
w0);
1710 w0.
Add(1./rho1, *z);
1714 gamma1 =
delta/rho1;
1716 x.
Add(gamma1*eta,
w0);
1722 MFEM_ASSERT(
IsFinite(eta),
"eta = " << eta);
1724 if (fabs(eta) <= norm_goal)
1731 mfem::out <<
"MINRES: iteration " << setw(3) << it <<
": ||r||_B = "
1732 << fabs(eta) <<
'\n';
1734 Monitor(it, fabs(eta), *z, x);
1752 mfem::out <<
"MINRES: iteration " << setw(3) << it <<
": ||r||_B = "
1753 << fabs(eta) <<
'\n';
1778 mfem::out <<
"MINRES: No convergence!\n";
1815 MFEM_ASSERT(
height ==
width,
"square Operator is required.");
1823 MFEM_ASSERT(
oper != NULL,
"the Operator is not set (use SetOperator).");
1824 MFEM_ASSERT(
prec != NULL,
"the Solver is not set (use SetSolver).");
1827 real_t norm0, norm, norm_goal;
1828 const bool have_b = (
b.Size() ==
Height());
1846 mfem::out <<
"Newton iteration " << setw(2) << 0
1847 <<
" : ||r|| = " << norm <<
"...\n";
1854 for (it = 0;
true; it++)
1856 MFEM_ASSERT(
IsFinite(norm),
"norm = " << norm);
1859 mfem::out <<
"Newton iteration " << setw(2) << it
1860 <<
" : ||r|| = " << norm;
1863 mfem::out <<
", ||r||/||r_0|| = " << norm/norm0;
1869 if (norm <= norm_goal)
1902 add(x, -c_scale,
c, x);
1925 mfem::out <<
"Newton: No convergence!\n";
1938 this->
alpha = alpha_;
1939 this->
gamma = gamma_;
1944 const real_t fnorm)
const
1952 real_t sg_threshold = 0.1;
1972 MFEM_ABORT(
"Unknown adaptive linear solver rtol version");
1977 if (sg_eta > sg_threshold) { eta = std::max(eta, sg_eta); }
1981 iterative_solver->SetRelTol(eta);
1985 mfem::out <<
"Eisenstat-Walker rtol = " << eta <<
"\n";
1992 const real_t fnorm)
const
2011 MFEM_VERIFY(
oper != NULL,
"the Operator is not set (use SetOperator).");
2022 int last_saved_id = -1;
2025 real_t norm0, norm, norm_goal;
2026 const bool have_b = (
b.Size() ==
Height());
2037 if (have_b) {
r -=
b; }
2044 mfem::out <<
"LBFGS iteration " << setw(2) << 0
2045 <<
" : ||r|| = " << norm <<
"...\n";
2048 for (it = 0;
true; it++)
2050 MFEM_ASSERT(
IsFinite(norm),
"norm = " << norm);
2054 <<
" : ||r|| = " << norm;
2057 mfem::out <<
", ||r||/||r_0|| = " << norm/norm0;
2062 if (norm <= norm_goal)
2081 add(x, -c_scale,
c, x);
2093 sk =
c; sk *= -c_scale;
2097 last_saved_id = (last_saved_id ==
m-1) ? 0 : last_saved_id+1;
2102 for (
int i = last_saved_id; i > -1; i--)
2110 for (
int i =
m-1; i > last_saved_id; i--)
2121 for (
int i = last_saved_id+1; i <
m ; i++)
2127 for (
int i = 0; i < last_saved_id+1 ; i++)
2147 mfem::out <<
"LBFGS: No convergence!\n";
2153 int m_max,
int m_min,
int m_step,
real_t cf,
2161 Vector s(m+1), cs(m+1), sn(m+1);
2168 real_t normb = w.Norml2();
2180 resid =
beta / normb;
2182 if (resid * resid <= tol)
2184 tol = resid * resid;
2192 <<
" Iteration : " << setw(3) << 0
2193 <<
" (r, r) = " <<
beta*
beta <<
'\n';
2196 tol *= (normb*normb);
2197 tol = (atol > tol) ? atol : tol;
2201 for (i= 0; i<=m; i++)
2208 while (j <= max_iter)
2216 for (i = 0; i < m && j <= max_iter; i++)
2221 for (k = 0; k <= i; k++)
2223 H(k,i) = w * (*v[k]);
2224 w.
Add(-H(k,i), (*v[k]));
2227 H(i+1,i) = w.Norml2();
2229 v[i+1] ->
Add (1.0/H(i+1,i), w);
2231 for (k = 0; k < i; k++)
2240 resid = fabs(
s(i+1));
2244 <<
" Iteration : " << setw(3) << i+1
2245 <<
" (r, r) = " << resid*resid <<
'\n';
2248 if ( resid*resid < tol)
2251 tol = resid * resid;
2253 for (i= 0; i<=m; i++)
2272 if ( resid*resid < tol)
2274 tol = resid * resid;
2276 for (i= 0; i<=m; i++)
2285 if (m - m_step >= m_min)
2298 tol = resid * resid;
2299 for (i= 0; i<=m; i++)
2309 : C(C_), D(D_), c_e(NULL), d_lo(NULL), d_hi(NULL), x_lo(NULL), x_hi(NULL),
2318 MFEM_ASSERT(
C,
"The C operator is unspecified -- can't set constraints.");
2319 MFEM_ASSERT(c.
Size() ==
C->
Height(),
"Wrong size of the constraint.");
2327 MFEM_ASSERT(
D,
"The D operator is unspecified -- can't set constraints.");
2329 "Wrong size of the constraint.");
2337 "Wrong size of the constraint.");
2354 MFEM_WARNING(
"Objective functional is ignored as SLBQP always minimizes"
2355 "the l2 norm of (x - x_target).");
2357 MFEM_ASSERT(
prob.GetC(),
"Linear constraint is not set.");
2358 MFEM_ASSERT(
prob.GetC()->Height() == 1,
"Solver expects scalar constraint.");
2379 mfem::out <<
"SLBQP iteration " << it <<
": residual = " << r
2380 <<
", lambda = " << l <<
'\n';
2410 mfem::out <<
"SLBQP bracketing phase" <<
'\n';
2428 llow = l; rlow = r; l = l + dl;
2431 r =
solve(l,xt,x,nclip);
2434 while ((r < 0) && (nclip <
max_iter))
2438 if (
s < smin) {
s = smin; }
2443 r =
solve(l,xt,x,nclip);
2451 lupp = l; rupp = r; l = l - dl;
2454 r =
solve(l,xt,x,nclip);
2457 while ((r > 0) && (nclip <
max_iter))
2461 if (
s < smin) {
s = smin; }
2466 r =
solve(l,xt,x,nclip);
2479 mfem::out <<
"SLBQP secant phase" <<
'\n';
2482 s = 1.0 - rlow/rupp; dl = dl/
s; l = lupp - dl;
2485 r =
solve(l,xt,x,nclip);
2488 while ( (fabs(r) > tol) && (nclip <
max_iter) )
2494 lupp = l; rupp = r;
s = 1.0 - rlow/rupp;
2495 dl = (lupp - llow)/
s; l = lupp - dl;
2500 if (
s < smin) {
s = smin; }
2502 lnew = 0.75*llow + 0.25*l;
2503 if (lnew < l-dl) { lnew = l-dl; }
2504 lupp = l; rupp = r; l = lnew;
2505 s = (lupp - llow)/(lupp - l);
2513 llow = l; rlow = r;
s = 1.0 - rlow/rupp;
2514 dl = (lupp - llow)/
s; l = lupp - dl;
2519 if (
s < smin) {
s = smin; }
2521 lnew = 0.75*lupp + 0.25*l;
2522 if (lnew < l+dl) { lnew = l+dl; }
2523 llow = l; rlow = r; l = lnew;
2524 s = (lupp - llow)/(lupp - l);
2529 r =
solve(l,xt,x,nclip);
2545 <<
" lambda = " << l <<
'\n'
2550 mfem::out <<
"SLBQP: No convergence!" <<
'\n';
2556 const std::vector<real_t> &w;
2557 std::vector<size_t> c;
2558 std::vector<int> loc;
2560 WeightMinHeap(
const std::vector<real_t> &w_) : w(w_)
2562 c.reserve(w.size());
2563 loc.resize(w.size());
2564 for (
size_t i=0; i<w.size(); ++i) { push(i); }
2567 size_t percolate_up(
size_t pos,
real_t val)
2569 for (; pos > 0 && w[c[(pos-1)/2]] > val; pos = (pos-1)/2)
2571 c[pos] = c[(pos-1)/2];
2572 loc[c[(pos-1)/2]] = pos;
2577 size_t percolate_down(
size_t pos,
real_t val)
2579 while (2*pos+1 < c.size())
2581 size_t left = 2*pos+1;
2582 size_t right = left+1;
2584 if (right < c.size() && w[c[right]] < w[c[left]]) { tgt = right; }
2585 else { tgt = left; }
2586 if (w[c[tgt]] < val)
2604 size_t pos = c.size()-1;
2605 pos = percolate_up(pos, val);
2613 size_t j = c.back();
2617 if (c.empty()) {
return i; }
2620 pos = percolate_down(pos, val);
2626 void update(
size_t i)
2628 size_t pos = loc[i];
2630 pos = percolate_up(pos, val);
2631 pos = percolate_down(pos, val);
2636 bool picked(
size_t i)
2651 for (
int i=0; i<n; ++i)
2653 for (
int j=I[i]; j<I[i+1]; ++j)
2655 V[j] = abs(V[j]/D[i]);
2659 std::vector<real_t> w(n, 0.0);
2660 for (
int k=0; k<n; ++k)
2663 for (
int ii=I[k]; ii<I[k+1]; ++ii)
2668 for (
int kk=I[i]; kk<I[i+1]; ++kk)
2676 for (
int jj=I[k]; jj<I[k+1]; ++jj)
2679 if (j == k) {
continue; }
2681 bool ij_exists =
false;
2682 for (
int jj2=I[i]; jj2<I[i+1]; ++jj2)
2690 if (!ij_exists) { w[k] += pow(C_ik*C_kj,2); }
2696 WeightMinHeap w_heap(w);
2700 for (
int ii=0; ii<n; ++ii)
2702 int pi = w_heap.pop();
2705 for (
int kk=I[pi]; kk<I[pi+1]; ++kk)
2708 if (w_heap.picked(k)) {
continue; }
2712 for (
int ii2=I[k]; ii2<I[k+1]; ++ii2)
2715 if (w_heap.picked(i)) {
continue; }
2718 for (
int kk2=I[i]; kk2<I[i+1]; ++kk2)
2726 for (
int jj=I[k]; jj<I[k+1]; ++jj)
2729 if (j == k || w_heap.picked(j)) {
continue; }
2731 bool ij_exists =
false;
2732 for (
int jj2=I[i]; jj2<I[i+1]; ++jj2)
2740 if (!ij_exists) { w[k] += pow(C_ik*C_kj,2); }
2753 block_size(block_size_),
2755 reordering(reordering_)
2762 :
BlockILU(block_size_, reordering_, k_fill_)
2784 MFEM_ABORT(
"BlockILU must be created with a SparseMatrix or HypreParMatrix");
2789 MFEM_ASSERT(A->
Finalized(),
"Matrix must be finalized.");
2790 CreateBlockPattern(*A);
2794void BlockILU::CreateBlockPattern(
const SparseMatrix &A)
2796 MFEM_VERIFY(k_fill == 0,
"Only block ILU(0) is currently supported.");
2797 if (A.
Height() % block_size != 0)
2799 MFEM_ABORT(
"BlockILU: block size must evenly divide the matrix size");
2803 const int *I = A.
GetI();
2804 const int *J = A.
GetJ();
2807 int nblockrows = nrows / block_size;
2809 std::vector<std::set<int>> unique_block_cols(nblockrows);
2811 for (
int iblock = 0; iblock < nblockrows; ++iblock)
2813 for (
int bi = 0; bi < block_size; ++bi)
2815 int i = iblock * block_size + bi;
2816 for (
int k = I[i]; k < I[i + 1]; ++k)
2818 unique_block_cols[iblock].insert(J[k] / block_size);
2821 nnz += unique_block_cols[iblock].size();
2826 SparseMatrix C(nblockrows, nblockrows);
2827 for (
int iblock = 0; iblock < nblockrows; ++iblock)
2829 for (
int jblock : unique_block_cols[iblock])
2831 for (
int bi = 0; bi < block_size; ++bi)
2833 int i = iblock * block_size + bi;
2834 for (
int k = I[i]; k < I[i + 1]; ++k)
2837 if (j >= jblock * block_size && j < (jblock + 1) * block_size)
2839 C.Add(iblock, jblock, V[k]*V[k]);
2846 real_t *CV = C.GetData();
2847 for (
int i=0; i<C.NumNonZeroElems(); ++i)
2849 CV[i] = sqrt(CV[i]);
2858 MFEM_ABORT(
"BlockILU: unknown reordering")
2865 for (
int i=0; i<nblockrows; ++i)
2873 for (
int i=0; i<nblockrows; ++i)
2879 std::vector<std::vector<int>> unique_block_cols_perminv(nblockrows);
2880 for (
int i=0; i<nblockrows; ++i)
2882 std::vector<int> &cols = unique_block_cols_perminv[i];
2883 for (
int j : unique_block_cols[P[i]])
2885 cols.push_back(Pinv[j]);
2887 std::sort(cols.begin(), cols.end());
2894 AB.
SetSize(block_size, block_size, nnz);
2895 DB.
SetSize(block_size, block_size, nblockrows);
2898 ipiv.
SetSize(block_size*nblockrows);
2901 for (
int iblock = 0; iblock < nblockrows; ++iblock)
2903 int iblock_perm = P[iblock];
2904 for (
int jblock : unique_block_cols_perminv[iblock])
2906 int jblock_perm = P[jblock];
2907 if (iblock == jblock)
2909 ID[iblock] = counter;
2911 JB[counter] = jblock;
2912 for (
int bi = 0; bi < block_size; ++bi)
2914 int i = iblock_perm*block_size + bi;
2915 for (
int k = I[i]; k < I[i + 1]; ++k)
2918 if (j >= jblock_perm*block_size && j < (jblock_perm + 1)*block_size)
2920 int bj = j - jblock_perm*block_size;
2922 AB(bi, bj, counter) = val;
2924 if (iblock == jblock)
2926 DB(bi, bj, iblock) = val;
2933 IB[iblock + 1] = counter;
2937void BlockILU::Factorize()
2939 int nblockrows =
Height()/block_size;
2942 for (
int i=0; i<nblockrows; ++i)
2944 LUFactors factorization(DB.
GetData(i), &ipiv[i*block_size]);
2945 factorization.Factor(block_size);
2951 DenseMatrix A_ik, A_ij, A_kj;
2953 for (
int i=1; i<nblockrows; ++i)
2956 for (
int kk=IB[i]; kk<IB[i+1]; ++kk)
2960 if (k == i) {
break; }
2963 MFEM_ABORT(
"Matrix must be sorted with nonzero diagonal");
2965 LUFactors A_kk_inv(DB.
GetData(k), &ipiv[k*block_size]);
2966 A_ik.UseExternalData(&AB(0,0,kk), block_size, block_size);
2968 A_kk_inv.RightSolve(block_size, block_size, A_ik.GetData());
2970 for (
int jj=kk+1; jj<IB[i+1]; ++jj)
2973 if (j <= k) {
continue; }
2974 A_ij.UseExternalData(&AB(0,0,jj), block_size, block_size);
2975 for (
int ll=IB[k]; ll<IB[k+1]; ++ll)
2980 A_kj.UseExternalData(&AB(0,0,ll), block_size, block_size);
2987 LUFactors factorization(DB.
GetData(i), &ipiv[i*block_size]);
2988 factorization.Factor(block_size);
3000 MFEM_ASSERT(
height > 0,
"BlockILU(0) preconditioner is not constructed");
3001 int nblockrows =
Height()/block_size;
3010 for (
int i=0; i<nblockrows; ++i)
3013 for (
int ib=0; ib<block_size; ++ib)
3015 yi[ib] =
b[ib + P[i]*block_size];
3017 for (
int k=IB[i]; k<ID[i]; ++k)
3027 for (
int i=nblockrows-1; i >= 0; --i)
3030 for (
int ib=0; ib<block_size; ++ib)
3032 xi[ib] = y[ib + i*block_size];
3034 for (
int k=ID[i]+1; k<IB[i+1]; ++k)
3042 LUFactors A_ii_inv(&DB(0,0,i), &ipiv[i*block_size]);
3054 real_t bc_norm_squared = 0.0;
3060 bc_norm_squared += r_entry*r_entry;
3065 if (comm != MPI_COMM_NULL)
3067 double glob_bc_norm_squared = 0.0;
3068 MPI_Reduce(&bc_norm_squared, &glob_bc_norm_squared, 1,
3071 bc_norm_squared = glob_bc_norm_squared;
3073 MPI_Comm_rank(comm, &rank);
3074 print = (rank == 0);
3077 if ((it == 0 ||
final || bc_norm_squared > 0.0) && print)
3079 mfem::out <<
" ResidualBCMonitor : b.c. residual norm = "
3080 << sqrt(bc_norm_squared) << endl;
3085#ifdef MFEM_USE_SUITESPARSE
3110 umfpack_di_free_numeric(&
Numeric);
3114 umfpack_dl_free_numeric(&
Numeric);
3119 MFEM_VERIFY(
mat,
"not a SparseMatrix");
3128 MFEM_VERIFY(
width ==
height,
"not a square matrix");
3141 umfpack_di_report_status(
Control, status);
3143 " umfpack_di_symbolic() failed!");
3151 umfpack_di_report_status(
Control, status);
3153 " umfpack_di_numeric() failed!");
3155 umfpack_di_free_symbolic(&
Symbolic);
3159 SuiteSparse_long status;
3163 AI =
new SuiteSparse_long[
width + 1];
3164 AJ =
new SuiteSparse_long[Ap[
width]];
3165 for (
int i = 0; i <=
width; i++)
3167 AI[i] = (SuiteSparse_long)(Ap[i]);
3169 for (
int i = 0; i < Ap[
width]; i++)
3171 AJ[i] = (SuiteSparse_long)(Ai[i]);
3179 umfpack_dl_report_status(
Control, status);
3181 " umfpack_dl_symbolic() failed!");
3189 umfpack_dl_report_status(
Control, status);
3191 " umfpack_dl_numeric() failed!");
3193 umfpack_dl_free_symbolic(&
Symbolic);
3200 mfem_error(
"UMFPackSolver::Mult : matrix is not set!"
3201 " Call SetOperator first!");
3213 umfpack_di_report_status(
Control, status);
3214 mfem_error(
"UMFPackSolver::Mult : umfpack_di_solve() failed!");
3219 SuiteSparse_long status =
3226 umfpack_dl_report_status(
Control, status);
3227 mfem_error(
"UMFPackSolver::Mult : umfpack_dl_solve() failed!");
3235 mfem_error(
"UMFPackSolver::MultTranspose : matrix is not set!"
3236 " Call SetOperator first!");
3248 umfpack_di_report_status(
Control, status);
3250 " umfpack_di_solve() failed!");
3255 SuiteSparse_long status =
3262 umfpack_dl_report_status(
Control, status);
3264 " umfpack_dl_solve() failed!");
3277 umfpack_di_free_numeric(&
Numeric);
3281 umfpack_dl_free_numeric(&
Numeric);
3296 "Had Numeric pointer in KLU, but not Symbolic");
3304 MFEM_VERIFY(
mat != NULL,
"not a SparseMatrix");
3312 MFEM_VERIFY(
width ==
height,
"not a square matrix");
3324 MFEM_VERIFY(
mat != NULL,
3325 "KLUSolver::Mult : matrix is not set! Call SetOperator first!");
3338 MFEM_VERIFY(
mat != NULL,
3339 "KLUSolver::Mult : matrix is not set! Call SetOperator first!");
3366 for (
int i = 0; i < block_dof.
NumRows(); ++i)
3371 block_solvers[i].SetOperator(sub_A);
3380 for (
int i = 0; i < block_dof.
NumRows(); ++i)
3385 block_solvers[i].Mult(sub_rhs, sub_sol);
3399 add(-1.0, z, 1.0, x, z);
3416 add(-1.0, z, 1.0, x, z);
3425 :
Solver(0, false), global_size(-1)
3433 :
Solver(0, false), mycomm(mycomm_), global_size(-1), parallel(true) { }
3441 MFEM_VERIFY(
height ==
width,
"Solver must be a square Operator!");
3447 MFEM_VERIFY(solver,
"Solver hasn't been set, call SetSolver() first.");
3451 MFEM_VERIFY(
height ==
width,
"Solver must be a square Operator!");
3457 MFEM_VERIFY(solver,
"Solver hasn't been set, call SetSolver() first.");
3459 "solver was modified externally! call SetSolver() again!");
3460 MFEM_VERIFY(
height ==
b.Size(),
"incompatible input Vector size!");
3461 MFEM_VERIFY(
height == x.
Size(),
"incompatible output Vector size!");
3464 Orthogonalize(
b, b_ortho);
3470 solver->
Mult(b_ortho, x);
3473 Orthogonalize(x, x);
3476void OrthoSolver::Orthogonalize(
const Vector &v,
Vector &v_ortho)
const
3478 if (global_size == -1)
3484 MPI_Allreduce(MPI_IN_PLACE, &global_size, 1, HYPRE_MPI_BIG_INT,
3497 MPI_Allreduce(MPI_IN_PLACE, &global_sum, 1, MPITypeMap<real_t>::mpi_type,
3502 real_t ratio = global_sum /
static_cast<real_t>(global_size);
3506 for (
int i = 0; i < v_ortho.
Size(); ++i)
3508 v_ortho(i) = v(i) - ratio;
3515 bool op_is_symmetric,
3517 :
Solver(op.NumRows()), aux_map_(aux_map, own_aux_map)
3519 aux_system_.
Reset(
RAP(&op, aux_map));
3522 aux_smoother_.
As<
HypreSmoother>()->SetOperatorSymmetry(op_is_symmetric);
3525void AuxSpaceSmoother::Mult(
const Vector &x,
Vector &y,
bool transpose)
const
3530 Vector aux_sol(aux_rhs.Size());
3537 aux_smoother_->
Mult(aux_rhs, aux_sol);
3541 aux_map_->
Mult(aux_sol, y);
3545#ifdef MFEM_USE_LAPACK
3547#ifdef MFEM_USE_SINGLE
3549sormqr_(
char *,
char *,
int *,
int *,
int *,
float *,
int*,
float *,
3550 float *,
int *,
float *,
int*,
int*);
3553sgeqrf_(
int *,
int *,
float *,
int *,
float *,
float *,
int *,
int *);
3556sgemv_(
char *,
int *,
int *,
float *,
float *,
int *,
float *,
int *,
3557 float *,
float *,
int *);
3560strsm_(
char *side,
char *uplo,
char *transa,
char *diag,
int *m,
int *n,
3561 float *
alpha,
float *
a,
int *lda,
float *
b,
int *ldb);
3562#elif defined MFEM_USE_DOUBLE
3564dormqr_(
char *,
char *,
int *,
int *,
int *,
double *,
int*,
double *,
3565 double *,
int *,
double *,
int*,
int*);
3568dgeqrf_(
int *,
int *,
double *,
int *,
double *,
double *,
int *,
int *);
3571dgemv_(
char *,
int *,
int *,
double *,
double *,
int *,
double *,
int *,
3572 double *,
double *,
int *);
3575dtrsm_(
char *side,
char *uplo,
char *transa,
char *diag,
int *m,
int *n,
3576 double *
alpha,
double *
a,
int *lda,
double *
b,
int *ldb);
3580 :
Solver(0), mat(nullptr), const_tol_(1.0e-14), min_nnz_(0),
3581 max_nnz_(0), verbosity_(0), res_change_termination_tol_(1.0e-4),
3582 zero_tol_(1.0e-14), rhs_delta_(1.0e-11), n_outer_(100000),
3583 n_inner_(100000), nStallCheck_(100), normalize_(true),
3590 MFEM_VERIFY(mat,
"NNLSSolver operator must be of type DenseMatrix");
3602 qr_residual_mode_ = qr_residual_mode;
3605 NNLS_qrres_on_ =
true;
3614 MFEM_VERIFY(rhs_lb.
Size() == m && rhs_ub.
Size() == m,
"");
3620 Vector rhs_halfgap = rhs_ub;
3621 rhs_halfgap -= rhs_lb;
3624 Vector rhs_avg_glob = rhs_avg;
3625 Vector rhs_halfgap_glob = rhs_halfgap;
3626 Vector halfgap_target(m);
3627 halfgap_target = 1.0e3 * const_tol_;
3631 for (
int i=0; i<m; ++i)
3633 const real_t s = halfgap_target(i) / rhs_halfgap_glob(i);
3634 row_scaling_[i] =
s;
3636 rhs_lb(i) = (rhs_avg(i) *
s) - halfgap_target(i);
3637 rhs_ub(i) = (rhs_avg(i) *
s) + halfgap_target(i);
3643 MFEM_VERIFY(mat,
"NNLSSolver operator must be of type DenseMatrix");
3645 mat->
Mult(w, rhs_ub);
3646 rhs_ub *= row_scaling_;
3651 for (
int i=0; i<rhs_ub.
Size(); ++i)
3653 rhs_lb(i) -= rhs_delta_;
3654 rhs_ub(i) += rhs_delta_;
3658 Solve(rhs_lb, rhs_ub, sol);
3663 for (
int i=0; i<sol.
Size(); ++i)
3671 mfem::out <<
"Number of nonzeros in NNLSSolver solution: " << nnz
3672 <<
", out of " << sol.
Size() << endl;
3676 mat->
Mult(sol, res);
3677 res *= row_scaling_;
3683 const real_t relNorm = res.
Norml2() / std::max(normGsol, normRHS);
3684 mfem::out <<
"Relative residual norm for NNLSSolver solution of Gs = Gw: "
3695 MFEM_VERIFY(rhs_lb.
Size() == m && rhs_lb.
Size() == m && soln.
Size() == n,
"");
3696 MFEM_VERIFY(n >= m,
"NNLSSolver system cannot be over-determined.");
3708 Vector rhs_halfgap(rhs_ub);
3709 rhs_halfgap -= rhs_lb;
3712 Vector rhs_avg_glob(rhs_avg);
3713 Vector rhs_halfgap_glob(rhs_halfgap);
3722 std::vector<unsigned int> nz_ind(m);
3729 int min_nnz_cap = std::min(
static_cast<int>(min_nnz_), std::min(m,n));
3731 std::vector<real_t> l2_res_hist;
3732 std::vector<unsigned int> stalled_indices;
3733 int stalledFlag = 0;
3734 int num_stalled = 0;
3735 int nz_ind_zero = 0;
3738 Vector soln_nz_glob_up(m);
3741 Vector mat_0_data(m * n);
3742 Vector mat_qr_data(m * n);
3743 Vector submat_data(m * n);
3751 std::vector<real_t> work;
3752 int n_outer_iter = 0;
3753 int n_total_inner_iter = 0;
3760 res_glob = rhs_avg_glob;
3761 Vector qt_rhs_glob = rhs_avg_glob;
3762 Vector qqt_rhs_glob = qt_rhs_glob;
3763 Vector sub_qt = rhs_avg_glob;
3769 Vector rhs_scaled(rhs_halfgap_glob);
3771 rhs_scaled *= row_scaling_;
3774 mu_tol = 1.0e-15 * tmp.
Max();
3780 for (
int oiter = 0; oiter < n_outer_; ++oiter)
3784 rmax = fabs(res_glob(0)) - rhs_halfgap_glob(0);
3785 for (
int i=1; i<m; ++i)
3787 rmax = std::max(rmax, fabs(res_glob(i)) - rhs_halfgap_glob(i));
3790 l2_res_hist.push_back(res_glob.
Norml2());
3794 mfem::out <<
"NNLS " << oiter <<
" " << n_total_inner_iter <<
" " << m
3795 <<
" " << n <<
" " << n_glob <<
" " << rmax <<
" "
3796 << l2_res_hist[oiter] << endl;
3798 if (rmax <= const_tol_ && n_glob >= min_nnz_cap)
3802 mfem::out <<
"NNLS target tolerance met" << endl;
3808 if (n_glob >= max_nnz_)
3812 mfem::out <<
"NNLS target nnz met" << endl;
3822 mfem::out <<
"NNLS system is square... exiting" << endl;
3829 if (oiter > nStallCheck_)
3833 for (
int i=0; i<nStallCheck_/2; ++i)
3835 mean0 += l2_res_hist[oiter - i];
3836 mean1 += l2_res_hist[oiter - (nStallCheck_) - i];
3839 real_t mean_res_change = (mean1 / mean0) - 1.0;
3840 if (std::abs(mean_res_change) < res_change_termination_tol_)
3844 mfem::out <<
"NNLSSolver stall detected... exiting" << endl;
3852 res_glob *= row_scaling_;
3855 for (
int i = 0; i < n_nz_ind; ++i)
3857 mu(nz_ind[i]) = 0.0;
3859 for (
unsigned int i = 0; i < stalled_indices.size(); ++i)
3861 mu(stalled_indices[i]) = 0.0;
3868 num_stalled = stalled_indices.size();
3869 if (num_stalled > 0)
3873 mfem::out <<
"NNLS Lagrange multiplier is below the minimum "
3874 <<
"threshold: mumax = " << mumax <<
", mutol = "
3875 << mu_tol <<
"\n" <<
" Resetting stalled indices "
3876 <<
"vector of size " << num_stalled <<
"\n";
3878 stalled_indices.resize(0);
3882 for (
int i = 0; i < n_nz_ind; ++i)
3884 mu(nz_ind[i]) = 0.0;
3894 for (
int i=1; i<n; ++i)
3905 nz_ind[n_nz_ind] = imax;
3910 mfem::out <<
"Found next index: " << imax <<
" " << mumax << endl;
3913 for (
int i=0; i<m; ++i)
3915 mat_0_data(i + (n_glob*m)) = (*mat)(i,imax) * row_scaling_[i];
3916 mat_qr_data(i + (n_glob*m)) = mat_0_data(i + (n_glob*m));
3919 i_qr_start = n_glob;
3924 mfem::out <<
"Updated matrix with new index" << endl;
3927 for (
int iiter = 0; iiter < n_inner_; ++iiter)
3929 ++n_total_inner_iter;
3932 const bool incremental_update =
true;
3933 n_update = n_glob - i_qr_start;
3934 m_update = m - i_qr_start;
3935 if (incremental_update)
3941#ifdef MFEM_USE_SINGLE
3943#elif defined MFEM_USE_DOUBLE
3947 mat_qr_data.
GetData() + (i_qr_start * m), &m,
3948 work.data(), &lwork, &info);
3949 MFEM_VERIFY(info == 0,
"");
3950 lwork =
static_cast<int>(work[0]);
3952#ifdef MFEM_USE_SINGLE
3954#elif defined MFEM_USE_DOUBLE
3958 mat_qr_data.
GetData() + (i_qr_start * m), &m,
3959 work.data(), &lwork, &info);
3960 MFEM_VERIFY(info == 0,
"");
3967 for (
int i=0; i<m_update; ++i)
3968 for (
int j=0; j<n_update; ++j)
3970 submat_data[i + (j * m_update)] =
3971 mat_qr_data[i + i_qr_start + ((j + i_qr_start) * m)];
3975 for (
int j=0; j<n_update; ++j)
3977 sub_tau[j] = tau[i_qr_start + j];
3980#ifdef MFEM_USE_SINGLE
3982#elif defined MFEM_USE_DOUBLE
3986 work.data(), &lwork, &info);
3987 MFEM_VERIFY(info == 0,
"");
3988 lwork =
static_cast<int>(work[0]);
3989 if (lwork == 0) { lwork = 1; }
3991#ifdef MFEM_USE_SINGLE
3993#elif defined MFEM_USE_DOUBLE
3997 work.data(), &lwork, &info);
3998 MFEM_VERIFY(info == 0,
"");
4001 for (
int i=0; i<m_update; ++i)
4002 for (
int j=0; j<n_update; ++j)
4004 mat_qr_data[i + i_qr_start + ((j + i_qr_start)* m)] =
4005 submat_data[i + (j * m_update)];
4008 for (
int j=0; j<n_update; ++j)
4010 tau[i_qr_start + j] = sub_tau[j];
4016 for (
int i=0; i<m; ++i)
4017 for (
int j=0; j<n_glob; ++j)
4019 mat_qr_data(i + (j*m)) = mat_0_data(i + (j*m));
4026#ifdef MFEM_USE_SINGLE
4028#elif defined MFEM_USE_DOUBLE
4032 work.data(), &lwork, &info);
4033 MFEM_VERIFY(info == 0,
"");
4034 lwork =
static_cast<int>(work[0]);
4036#ifdef MFEM_USE_SINGLE
4038#elif defined MFEM_USE_DOUBLE
4042 work.data(), &lwork, &info);
4043 MFEM_VERIFY(info == 0,
"");
4048 mfem::out <<
"Updated QR " << iiter << endl;
4052 if (incremental_update && iiter == 0)
4062 for (
int i=0; i<m_update; ++i)
4064 submat_data[i] = mat_qr_data[i + i_qr_start + (i_qr_start * m)];
4065 sub_qt[i] = qt_rhs_glob[i + i_qr_start];
4068 sub_tau[0] = tau[i_qr_start];
4070#ifdef MFEM_USE_SINGLE
4072#elif defined MFEM_USE_DOUBLE
4077 work.data(), &lwork, &info);
4078 MFEM_VERIFY(info == 0,
"");
4079 lwork =
static_cast<int>(work[0]);
4081#ifdef MFEM_USE_SINGLE
4083#elif defined MFEM_USE_DOUBLE
4088 work.data(), &lwork, &info);
4089 MFEM_VERIFY(info == 0,
"");
4091 for (
int i=0; i<m_update; ++i)
4093 qt_rhs_glob[i + i_qr_start] = sub_qt[i];
4099 qt_rhs_glob = rhs_avg_glob;
4102#ifdef MFEM_USE_SINGLE
4104#elif defined MFEM_USE_DOUBLE
4109 work.data(), &lwork, &info);
4110 MFEM_VERIFY(info == 0,
"");
4111 lwork =
static_cast<int>(work[0]);
4113#ifdef MFEM_USE_SINGLE
4115#elif defined MFEM_USE_DOUBLE
4120 work.data(), &lwork, &info);
4121 MFEM_VERIFY(info == 0,
"");
4126 mfem::out <<
"Updated rhs " << iiter << endl;
4133#ifdef MFEM_USE_SINGLE
4134 strsm_(&lside, &upper, ¬rans, &nounit,
4135#elif defined MFEM_USE_DOUBLE
4136 dtrsm_(&lside, &upper, ¬rans, &nounit,
4138 &n_glob, &ione, &fone,
4144 mfem::out <<
"Solved triangular system " << iiter << endl;
4149 real_t smin = n_glob > 0 ? vec1(0) : 0.0;
4150 for (
int i=0; i<n_glob; ++i)
4152 soln_nz_glob_up(i) = vec1(i);
4153 smin = std::min(smin, soln_nz_glob_up(i));
4156 if (smin > zero_tol_)
4159 for (
int i=0; i<n_glob; ++i)
4161 soln_nz_glob(i) = soln_nz_glob_up(i);
4172 mfem::out <<
"Start pruning " << iiter << endl;
4173 for (
int i = 0; i < n_glob; ++i)
4175 if (soln_nz_glob_up(i) <= zero_tol_)
4177 mfem::out << i <<
" " << n_glob <<
" " << soln_nz_glob_up(i) << endl;
4182 if (soln_nz_glob_up(n_glob - 1) <= zero_tol_)
4189 mfem::out <<
"Detected stall due to adding and removing same "
4190 <<
"column. Switching to QR residual calculation "
4191 <<
"method." << endl;
4195 mfem::out <<
"Detected stall due to adding and removing same"
4196 <<
" column. Exiting now." << endl;
4203 NNLS_qrres_on_ =
true;
4210 for (
int i = 0; i < n_glob; ++i)
4212 if (soln_nz_glob_up(i) <= zero_tol_)
4214 alpha = std::min(
alpha, soln_nz_glob(i)/(soln_nz_glob(i) - soln_nz_glob_up(i)));
4219 for (
int i = 0; i < n_glob; ++i)
4221 soln_nz_glob(i) +=
alpha*(soln_nz_glob_up(i) - soln_nz_glob(i));
4222 if (i == 0 || soln_nz_glob(i) < smin)
4224 smin = soln_nz_glob(i);
4228 while (smin > zero_tol_)
4236 smin = soln_nz_glob(0);
4237 for (
int i = 1; i < n_glob; ++i)
4239 if (soln_nz_glob(i) < smin)
4241 smin = soln_nz_glob(i);
4246 alpha = soln_nz_glob(index_min)/(soln_nz_glob(index_min)
4247 - soln_nz_glob_up(index_min));
4250 for (
int i = 0; i < n_glob; ++i)
4252 soln_nz_glob(i) +=
alpha*(soln_nz_glob_up(i) - soln_nz_glob(i));
4257 i_qr_start = n_glob+1;
4263 smin = n_glob > 0 ? soln_nz_glob(0) : 0.0;
4264 for (
int i=1; i<n_glob; ++i)
4266 smin = std::min(smin, soln_nz_glob(i));
4269 if (smin < zero_tol_)
4278 if (zero_ibool == 0)
4287 for (
int i = 0; i < n_glob; ++i)
4289 if (soln_nz_glob(i) < zero_tol_)
4295 MFEM_VERIFY(ind_zero != -1,
"");
4298 for (
int i = 0; i < ind_zero; ++i)
4305 for (
int i=0; i<m; ++i)
4306 for (
int j=ind_zero; j<n_glob-1; ++j)
4308 mat_qr_data(i + (j*m)) = mat_0_data(i + ((j+1)*m));
4313 for (
int i=0; i<m; ++i)
4314 for (
int j=ind_zero; j<n_glob-1; ++j)
4316 mat_0_data(i + (j*m)) = mat_qr_data(i + (j*m));
4321 for (
int i = nz_ind_zero; i < n_nz_ind-1; ++i)
4323 nz_ind[i] = nz_ind[i+1];
4328 for (
int i = ind_zero; i < n_glob-1; ++i)
4330 soln_nz_glob(i) = soln_nz_glob(i+1);
4333 i_qr_start = std::min(i_qr_start, ind_zero);
4339 mfem::out <<
"Finished pruning " << iiter << endl;
4344 if (stalledFlag == 1)
4348 num_stalled = stalled_indices.size();
4349 stalled_indices.resize(num_stalled + 1);
4350 stalled_indices[num_stalled] = imax;
4353 mfem::out <<
"Adding index " << imax <<
" to stalled index list "
4354 <<
"of size " << num_stalled << endl;
4359 if (!NNLS_qrres_on_)
4361 res_glob = rhs_avg_glob;
4363#ifdef MFEM_USE_SINGLE
4364 sgemv_(¬rans, &m, &n_glob, &fmone,
4365#elif defined MFEM_USE_DOUBLE
4366 dgemv_(¬rans, &m, &n_glob, &fmone,
4369 soln_nz_glob.
GetData(), &ione, &fone,
4379 for (
int i=0; i<n_glob; ++i)
4381 qqt_rhs_glob(i) = qt_rhs_glob(i);
4384#ifdef MFEM_USE_SINGLE
4385 sormqr_(&lside, ¬rans, &m, &ione, &n_glob, mat_qr_data.
GetData(), &m,
4386#elif defined MFEM_USE_DOUBLE
4387 dormqr_(&lside, ¬rans, &m, &ione, &n_glob, mat_qr_data.
GetData(), &m,
4390 work.data(), &lwork, &info);
4392 MFEM_VERIFY(info == 0,
"");
4393 lwork =
static_cast<int>(work[0]);
4395#ifdef MFEM_USE_SINGLE
4396 sormqr_(&lside, ¬rans, &m, &ione, &n_glob, mat_qr_data.
GetData(), &m,
4397#elif defined MFEM_USE_DOUBLE
4398 dormqr_(&lside, ¬rans, &m, &ione, &n_glob, mat_qr_data.
GetData(), &m,
4401 work.data(), &lwork, &info);
4402 MFEM_VERIFY(info == 0,
"");
4403 res_glob = rhs_avg_glob;
4404 res_glob -= qqt_rhs_glob;
4409 mfem::out <<
"Computed residual" << endl;
4416 MFEM_VERIFY(n_glob == n_nz_ind,
"");
4418 for (
int i = 0; i < n_glob; ++i)
4420 soln(nz_ind[i]) = soln_nz_glob(i);
4425 mfem::out <<
"NNLS solver: m = " << m <<
", n = " << n
4426 <<
", outer_iter = " << n_outer_iter <<
", inner_iter = "
4427 << n_total_inner_iter;
4435 mfem::out << endl <<
"Warning, NNLS convergence stalled: "
4436 << (exit_flag == 2) << endl;
4437 mfem::out <<
"resErr = " << rmax <<
" vs tol = " << const_tol_
4438 <<
"; 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.
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)
virtual void Mult(const Vector &b, Vector &x) const
Iterative solution of the linear system using the BiCGSTAB method.
virtual void SetOperator(const Operator &op)
Also calls SetOperator for the preconditioner if there is one.
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.
virtual void SetOperator(const Operator &op)
Also calls SetOperator for the preconditioner if there is one.
virtual void Mult(const Vector &b, Vector &x) const
Iterative solution of the linear system using the Conjugate Gradient method.
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)
DirectSubBlockSolver(const SparseMatrix &A, const SparseMatrix &block_dof)
virtual void Mult(const Vector &x, Vector &y) const
Direct solution of the block diagonal linear system.
virtual void Mult(const Vector &b, Vector &x) const
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.
virtual void Mult(const Vector &b, Vector &x) const
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.
const class IterativeSolver * iter_solver
The last IterativeSolver to which this monitor was attached.
virtual void MonitorSolution(int it, real_t norm, const Vector &x, bool final)
Monitor the solution vector x.
virtual void MonitorResidual(int it, real_t norm, const Vector &r, bool final)
Monitor the residual vector r.
Abstract base class for iterative solver.
real_t abs_tol
Absolute tolerance.
void 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.
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().
virtual 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.
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)
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.
IterativeSolverMonitor * monitor
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()
virtual void MultTranspose(const Vector &b, Vector &x) const
Direct solution of the transposed linear system using KLU.
virtual void Mult(const Vector &b, Vector &x) const
Direct solution of the linear system using KLU.
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Array< Vector * > skArray
Array< Vector * > ykArray
virtual void Mult(const Vector &b, Vector &x) const
Solve the nonlinear system with right-hand side b.
virtual void Solve(int m, int n, real_t *X) const
virtual void Mult(const Vector &b, Vector &x) const
Iterative solution of the linear system using the MINRES method.
virtual void SetOperator(const Operator &op)
Also calls SetOperator for the preconditioner if there is one.
virtual void SetPreconditioner(Solver &pr)
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 void SetOperator(const Operator &op)
Also calls SetOperator for the preconditioner if there is one.
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 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...
virtual void Mult(const Vector &b, Vector &x) const
Solve the nonlinear system with right-hand side b.
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 Mult(const Vector &b, Vector &x) const
Perform the action of the OrthoSolver: P * solver * P where P is the projection to the subspace of ve...
void SetSolver(Solver &s)
Set the solver used by the OrthoSolver.
virtual void SetOperator(const Operator &op)
Set the Operator that is the OrthoSolver is to invert (approximately).
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)).
virtual void MultTranspose(const Vector &x, Vector &y) const
Solution of the transposed linear system using a product of subsolvers.
virtual void Mult(const Vector &x, Vector &y) const
Solution of the linear system using a product of subsolvers.
void MonitorResidual(int it, real_t norm, const Vector &r, bool final) override
Monitor the residual vector r.
const Array< int > * ess_dofs_list
Not owned.
virtual void Mult(const Vector &xt, Vector &x) const
virtual void SetOptimizationProblem(const OptimizationProblem &prob)
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
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)
virtual void Mult(const Vector &b, Vector &x) const
Iterative solution of the linear system using Stationary Linear Iteration.
virtual void SetOperator(const Operator &op)
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.
virtual void MultTranspose(const Vector &x, Vector &y) const
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.
virtual void Mult(const Vector &x, Vector &y) const
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
virtual void SetOperator(const Operator &op)
Factorize the given Operator op which must be a SparseMatrix.
real_t Control[UMFPACK_CONTROL]
virtual void Mult(const Vector &b, Vector &x) const
Direct solution of the linear system using UMFPACK.
virtual void MultTranspose(const Vector &b, Vector &x) const
Direct solution of the transposed linear system using UMFPACK.
real_t Info[UMFPACK_INFO]
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 trans(const Vector &u, Vector &x)
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 Swap(Array< T > &, Array< T > &)
void dtrsm_(char *side, char *uplo, char *transa, char *diag, int *m, int *n, double *alpha, double *a, int *lda, double *b, int *ldb)
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 sgemv_(char *, int *, int *, float *, float *, int *, float *, int *, float *, float *, int *)
void ApplyPlaneRotation(real_t &dx, real_t &dy, real_t &cs, real_t &sn)
void RAP(const DenseMatrix &A, const DenseMatrix &P, DenseMatrix &RAP)
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 strsm_(char *side, char *uplo, char *transa, char *diag, int *m, int *n, float *alpha, float *a, int *lda, float *b, int *ldb)
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 dgemv_(char *, int *, int *, double *, double *, int *, double *, int *, double *, double *, int *)
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 sgeqrf_(int *, int *, float *, int *, float *, float *, int *, int *)
void dormqr_(char *, char *, int *, int *, int *, double *, int *, double *, double *, int *, double *, int *, int *)
void subtract(const Vector &x, const Vector &y, Vector &z)
MemoryType
Memory types supported by MFEM.
void MinimumDiscardedFillOrdering(SparseMatrix &C, Array< int > &p)
void dgeqrf_(int *, int *, double *, int *, double *, double *, int *, int *)
void sormqr_(char *, char *, int *, int *, int *, float *, int *, float *, float *, int *, float *, int *, int *)
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)
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.