149 amrex::Box domain(
linop->
Geom(lev).growPeriodicDomain(1));
150 domain.convert(amrex::IntVect::TheNodeVector());
153 for (MFIter mfi(*a_model_mf[lev],
false); mfi.isValid(); ++mfi)
155 amrex::Box bx = mfi.grownnodaltilebox();
158 amrex::Array4<const T>
const& model = a_model_mf[lev]->array(mfi);
159 amrex::Array4<const Set::Scalar>
const& u = a_u_mf[lev]->array(mfi);
160 amrex::Array4<Set::Matrix>
const& dw = a_dw_mf[lev]->array(mfi);
161 amrex::Array4<Set::Matrix4<AMREX_SPACEDIM, T::sym>>
const& ddw = a_ddw_mf[lev]->array(mfi);
164 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) {
171 dw(i, j, k) = model(i, j, k).DW(gradu);
172 ddw(i, j, k) = model(i, j, k).DDW(gradu);
176 Set::Matrix eps = 0.5 * (gradu + gradu.transpose());
177 dw(i, j, k) = model(i, j, k).DW(eps);
178 ddw(i, j, k) = model(i, j, k).DDW(eps);
183 dw(i, j, k) = model(i, j, k).DW(F);
184 ddw(i, j, k) = model(i, j, k).DDW(F);
197 amrex::Box domain(
linop->
Geom(lev).growPeriodicDomain(1));
198 domain.convert(amrex::IntVect::TheNodeVector());
200 const amrex::Dim3 lo = amrex::lbound(domain), hi = amrex::ubound(domain);
201 for (MFIter mfi(*a_model_mf[lev],
false); mfi.isValid(); ++mfi)
203 amrex::Box bx = mfi.nodaltilebox();
205 amrex::Array4<const Set::Scalar>
const& u = a_u_mf[lev]->array(mfi);
206 amrex::Array4<const Set::Scalar>
const& b = a_b_mf[lev]->array(mfi);
207 amrex::Array4<const Set::Matrix>
const& dw = a_dw_mf[lev]->array(mfi);
208 amrex::Array4<Set::Scalar>
const& rhs = a_rhs_mf[lev]->array(mfi);
209 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
213 if (AMREX_D_TERM(i == lo.x || i == hi.x, || j == lo.y || j == hi.y, || k == lo.z || k == hi.z))
216 Set::Vector U(AMREX_D_DECL(u(i, j, k, 0), u(i, j, k, 1), u(i, j, k, 2)));
218 for (
int d = 0; d < AMREX_SPACEDIM; d++) rhs(i, j, k, d) = b(i, j, k, d) - ret(d);
223 for (
int p = 0; p < AMREX_SPACEDIM; p++) rhs(i, j, k, p) = b(i, j, k, p) - divdw(p);
242 amrex::Box domain(
linop->
Geom(lev).growPeriodicDomain(2));
243 domain.convert(amrex::IntVect::TheNodeVector());
244 amrex::Box row_domain(
linop->
Geom(lev).growPeriodicDomain(1));
245 row_domain.convert(amrex::IntVect::TheNodeVector());
248 const amrex::Dim3 hi = amrex::ubound(domain);
250 for (MFIter mfi(*a_model_mf[lev],
false); mfi.isValid(); ++mfi)
252 amrex::Box bx = mfi.grownnodaltilebox();
255 amrex::Array4<const T>
const& model = a_model_mf[lev]->array(mfi);
256 amrex::Array4<const Set::Vector>
const& u = a_u_mf[lev]->array(mfi);
257 amrex::Array4<Set::Matrix>
const& dw = a_dw_mf[lev]->array(mfi);
258 amrex::Array4<Set::Matrix4<AMREX_SPACEDIM, T::sym>>
const& ddw = a_ddw_mf[lev]->array(mfi);
260 if (conservative_solve)
262 amrex::Box cbx = mfi.grownnodaltilebox(-1, 1) & row_domain;
263 amrex::LoopConcurrentOnCpu(cbx, [=] (
int i,
int j,
int k)
271 kinvar = 0.5 * (gradu + gradu.transpose());
273 kinvar = gradu + Set::Matrix::Identity();
277 dw(i, j, k) = model(i, j, k).DW(kinvar);
278 ddw(i, j, k, 0) = model(i, j, k).DDW(kinvar);
279 for (
int face = 0; face < AMREX_SPACEDIM; ++face)
281 const int index[3] = {i, j, k};
282 const int upper[3] = {hi.x, hi.y, hi.z};
283 if (index[face] < upper[face])
285 model, u, i, j, k, face, dx);
287 ddw(i, j, k, face + 1) = ddw(i, j, k, 0);
294 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
303 kinvar = 0.5 * (gradu + gradu.transpose());
305 kinvar = gradu + Set::Matrix::Identity();
307 dw(i, j, k) = model(i, j, k).DW(kinvar);
308 ddw(i, j, k) = model(i, j, k).DDW(kinvar);
313 a_dw_mf[lev]->setMultiGhost(
true);
314 a_dw_mf[lev]->FillBoundaryAndSync(
m_elastic->
Geom(lev).periodicity());
315 a_ddw_mf[lev]->setMultiGhost(
true);
316 a_ddw_mf[lev]->FillBoundaryAndSync(
m_elastic->
Geom(lev).periodicity());
327 amrex::Box domain(
linop->
Geom(lev).growPeriodicDomain(2));
328 domain.convert(amrex::IntVect::TheNodeVector());
329 amrex::Box row_domain(
linop->
Geom(lev).growPeriodicDomain(1));
330 row_domain.convert(amrex::IntVect::TheNodeVector());
332 const amrex::Dim3 lo = amrex::lbound(domain), hi = amrex::ubound(domain);
333 for (MFIter mfi(*a_model_mf[lev],
false); mfi.isValid(); ++mfi)
335 amrex::Box bx = mfi.grownnodaltilebox() & domain;
336 amrex::Array4<const Set::Vector>
const& u = a_u_mf[lev]->array(mfi);
337 amrex::Array4<const Set::Vector>
const& b = a_b_mf[lev]->array(mfi);
338 amrex::Array4<const Set::Matrix>
const& dw = a_dw_mf[lev]->array(mfi);
339 amrex::Array4<Set::Scalar>
const& rhs = a_rhs_mf[lev]->array(mfi);
340 if (conservative_solve)
342 amrex::Box cbx = mfi.grownnodaltilebox(-1, 1) & row_domain;
343 amrex::Array4<const T>
const& model = a_model_mf[lev]->array(mfi);
344 amrex::LoopConcurrentOnCpu(cbx, [=] (
int i,
int j,
int k)
347 const int index[3] = {i, j, k};
348 const int lower[3] = {lo.x, lo.y, lo.z};
349 const int upper[3] = {hi.x, hi.y, hi.z};
350 bool on_boundary =
false;
351 for (
int dir = 0; dir < AMREX_SPACEDIM; ++dir)
352 on_boundary = on_boundary ||
353 index[dir] == lower[dir] ||
354 index[dir] == upper[dir];
359 u(i, j, k), gradu, dw(i, j, k), i, j, k, cbx);
360 for (
int d = 0; d < AMREX_SPACEDIM; d++) rhs(i, j, k, d) = b(i, j, k)(d) - ret(d);
365 model, u, i, j, k, dx);
366 for (
int d = 0; d < AMREX_SPACEDIM; d++) rhs(i, j, k, d) = b(i, j, k)(d) - divdw(d);
373 if (
m_psi ==
nullptr)
375 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
379 if (AMREX_D_TERM(i == lo.x || i == hi.x, || j == lo.y || j == hi.y, || k == lo.z || k == hi.z))
382 Set::Vector ret =
m_elastic->
GetBC()(u(i, j, k), gradu, dw(i, j, k), i, j, k, bx);
383 for (
int d = 0; d < AMREX_SPACEDIM; d++) rhs(i, j, k, d) = b(i, j, k)(d) - ret(d);
388 for (
int d = 0; d < AMREX_SPACEDIM; d++) rhs(i, j, k, d) = b(i, j, k)(d) - divdw(d);
397 const amrex::Dim3 boxlo = amrex::lbound(bx), boxhi = amrex::ubound(bx);
398 amrex::Array4<const Set::Scalar>
const& psi = (*m_psi)[lev]->array(mfi);
399 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
403 if (AMREX_D_TERM(i == lo.x || i == hi.x, || j == lo.y || j == hi.y, || k == lo.z || k == hi.z))
407 if (AMREX_D_TERM(i > boxlo.x && i<boxhi.x, && j>boxlo.y && j<boxhi.y, && k>boxlo.z && k < boxhi.z))
411 Set::Vector ret =
m_elastic->
GetBC()(u(i, j, k), gradu, dw(i, j, k) * psiavg, i, j, k, bx);
412 for (
int d = 0; d < AMREX_SPACEDIM; d++) rhs(i, j, k, d) = b(i, j, k)(d) - ret(d);
417 if (AMREX_D_TERM(i > boxlo.x && i<boxhi.x, && j>boxlo.y && j<boxhi.y, && k>boxlo.z && k < boxhi.z))
421 divdw += dw(i, j, k) * gradpsi;
423 for (
int d = 0; d < AMREX_SPACEDIM; d++) rhs(i, j, k, d) = b(i, j, k)(d) - divdw(d);
429 a_rhs_mf[lev]->setMultiGhost(
true);
430 a_rhs_mf[lev]->FillBoundaryAndSync(
m_elastic->
Geom(lev).periodicity());
431 a_ddw_mf[lev]->setMultiGhost(
true);
432 a_ddw_mf[lev]->FillBoundaryAndSync(
m_elastic->
Geom(lev).periodicity());
441 Real a_tol_rel, Real a_tol_abs,
const char* checkpoint_file =
nullptr)
460 dsol_mf.Define(lev, a_u_mf[lev]->boxArray(),
461 a_u_mf[lev]->DistributionMap(),
463 a_u_mf[lev]->nGrow());
464 dw_mf.
Define(lev, a_b_mf[lev]->boxArray(),
465 a_b_mf[lev]->DistributionMap(),
467 a_b_mf[lev]->nGrow());
468 ddw_mf.
Define(lev, a_b_mf[lev]->boxArray(),
469 a_b_mf[lev]->DistributionMap(),
471 a_b_mf[lev]->nGrow());
472 rhs_mf.Define(lev, a_b_mf[lev]->boxArray(),
473 a_b_mf[lev]->DistributionMap(),
475 a_b_mf[lev]->nGrow());
476 u0_mf.Define(lev, a_u_mf[lev]->boxArray(),
477 a_u_mf[lev]->DistributionMap(),
479 a_u_mf[lev]->nGrow());
480 utrial_mf.Define(lev, a_u_mf[lev]->boxArray(),
481 a_u_mf[lev]->DistributionMap(),
483 a_u_mf[lev]->nGrow());
485 dsol_mf[lev]->setVal(0.0);
486 dw_mf[lev]->setVal(Set::Matrix::Zero());
489 a_b_mf.
Copy(lev, *rhs_mf[lev], 0, 2);
493 for (
int nriter = 0; nriter <
m_nriters; nriter++)
507 for (
int lev = 0; lev < dsol_mf.size(); ++lev)
508 dsol_mf[lev]->setVal(0.0);
512 for (
int lev = 0; lev < dsol_mf.size(); ++lev)
514 for (
int comp = 0; comp < AMREX_SPACEDIM; comp++)
516 Set::Scalar tmpcornorm = dsol_mf[lev]->norm0(comp, 0);
517 if (tmpcornorm > cornorm) cornorm = tmpcornorm;
526 a_u_mf.
Copy(lev, *u0_mf[lev], 0, 2);
528 auto restore_baseline = [&]()
531 a_u_mf.
CopyFrom(lev, *u0_mf[lev], 0, 2);
533 constexpr int max_backtrack = 8;
534 bool accepted =
false;
535 for (
int bt = 0; bt <= max_backtrack; bt++)
539 amrex::MultiFab::Copy(*utrial_mf[lev], *u0_mf[lev],
540 0, 0, AMREX_SPACEDIM, 2);
541 amrex::MultiFab::Saxpy(*utrial_mf[lev], alpha,
542 *dsol_mf[lev], 0, 0, AMREX_SPACEDIM, 2);
543 a_u_mf.
CopyFrom(lev, *utrial_mf[lev], 0, 2);
563 if (std::isfinite(resnorm0) && std::isfinite(resnorm) &&
564 (resnorm0 == 0.0 ? resnorm == 0.0 :
565 resnorm / resnorm0 <= 1.0001))
579 max_backtrack,
" backtracks: initial residual=", resnorm0,
580 ", final trial residual=", resnorm);
585 for (
int lev = 0; lev < dsol_mf.size(); ++lev)
586 a_u_mf.
AddFrom(lev, *dsol_mf[lev], 0, 2);
591 const Set::Scalar accepted_update = alpha * full_update;
592 if (!std::isfinite(full_update) || !std::isfinite(accepted_update))
598 ", full max norm(ddisp) = ", full_update,
599 ", accepted max norm(ddisp) = ", accepted_update);
602 ", accepted = ", resnorm);
613 m_nriters,
" iterations: final full update=", full_update,
614 ", final accepted update=", accepted_update,
617 m_nriters,
" iterations: final full update=", full_update,
618 ", final accepted update=", accepted_update,
631 Real a_tol_rel, Real a_tol_abs,
const char* checkpoint_file =
nullptr)
643 dsol_mf.
Define(lev, a_u_mf[lev]->boxArray(),
644 a_u_mf[lev]->DistributionMap(),
645 a_u_mf[lev]->nComp(),
646 a_u_mf[lev]->nGrow());
647 dw_mf.
Define(lev, a_b_mf[lev]->boxArray(),
648 a_b_mf[lev]->DistributionMap(),
650 a_b_mf[lev]->nGrow());
651 ddw_mf.
Define(lev, a_b_mf[lev]->boxArray(),
652 a_b_mf[lev]->DistributionMap(),
654 a_b_mf[lev]->nGrow());
655 rhs_mf.
Define(lev, a_b_mf[lev]->boxArray(),
656 a_b_mf[lev]->DistributionMap(),
657 a_b_mf[lev]->nComp(),
658 a_b_mf[lev]->nGrow());
660 dsol_mf[lev]->setVal(0.0);
661 dw_mf[lev]->setVal(Set::Matrix::Zero());
664 amrex::MultiFab::Copy(*rhs_mf[lev], *a_b_mf[lev], 0, 0, AMREX_SPACEDIM, 2);
667 for (
int nriter = 0; nriter <
m_nriters; nriter++)
679 for (
int lev = 0; lev < dsol_mf.size(); ++lev)
681 for (
int comp = 0; comp < AMREX_SPACEDIM; comp++)
683 Set::Scalar tmpcornorm = dsol_mf[lev]->norm0(comp, 0);
684 if (tmpcornorm > cornorm) cornorm = tmpcornorm;
686 Set::Scalar tmpsolnorm = a_u_mf[lev]->norm0(comp, 0);
687 if (tmpsolnorm > solnorm) solnorm = tmpsolnorm;
692 if (solnorm == 0) relnorm = cornorm;
693 else relnorm = cornorm / solnorm;
696 for (
int lev = 0; lev < dsol_mf.size(); ++lev)
697 amrex::MultiFab::Add(*a_u_mf[lev], *dsol_mf[lev], 0, 0, AMREX_SPACEDIM, 2);
744 dw_mf.resize(a_u_mf.size());
745 ddw_mf.resize(a_u_mf.size());
746 res_mf.resize(a_u_mf.size());
748 for (
int lev = 0; lev < a_u_mf.size(); lev++)
750 dw_mf.
Define(lev, a_b_mf[lev]->boxArray(),
751 a_b_mf[lev]->DistributionMap(),
752 1, a_b_mf[lev]->nGrow());
753 ddw_mf.
Define(lev, a_b_mf[lev]->boxArray(),
754 a_b_mf[lev]->DistributionMap(),
755 ddw_ncomp, a_b_mf[lev]->nGrow());
756 res_mf.
Define(lev, a_b_mf[lev]->boxArray(),
757 a_b_mf[lev]->DistributionMap(),
758 AMREX_SPACEDIM, a_b_mf[lev]->nGrow());
759 dw_mf[lev]->setVal(Set::Matrix::Zero());
765 for (
int lev = a_u_mf.
finest_level - 1; lev >= 0; --lev)
767 *res_mf[lev + 1], *res_mf[lev + 1], *res_mf[lev + 1]);
769 for (
int lev = 0; lev < a_res_mf.size(); ++lev)
772 a_res_mf.
CopyFrom(lev, *res_mf[lev], 0, 2);
806 for (
int lev = 0; lev < a_u_mf.size(); lev++)
808 BL_PROFILE(
"Solver::Nonlocal::Newton::DW()");
810 const amrex::Real* DX =
linop->
Geom(lev).CellSize();
811 amrex::Box domain(
linop->
Geom(lev).Domain());
812 domain.convert(amrex::IntVect::TheNodeVector());
814 for (MFIter mfi(*a_u_mf[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
816 const Box& bx = mfi.tilebox();
817 amrex::Array4<T>
const& C = a_model_mf[lev]->array(mfi);
818 amrex::Array4<amrex::Real>
const& w = a_w_mf[lev]->array(mfi);
819 amrex::Array4<const amrex::Real>
const& u = a_u_mf[lev]->array(mfi);
820 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
827 for (
int p = 0; p < AMREX_SPACEDIM; p++)
829 AMREX_D_TERM(gradu(p, 0) = (
Numeric::Stencil<Set::Scalar, 1, 0, 0>::D(u, i, j, k, p, DX, sten));,
830 gradu(p, 1) = (
Numeric::Stencil<Set::Scalar, 0, 1, 0>::D(u, i, j, k, p, DX, sten));,
831 gradu(p, 2) = (
Numeric::Stencil<Set::Scalar, 0, 0, 1>::D(u, i, j, k, p, DX, sten)););
835 w(i, j, k) = C(i, j, k).W(gradu);
837 w(i, j, k) = C(i, j, k).W(0.5 * (gradu + gradu.transpose()));
839 w(i, j, k) = C(i, j, k).W(gradu + Set::Matrix::Identity());
849 for (
int lev = 0; lev < a_u_mf.size(); lev++)
851 BL_PROFILE(
"Solver::Nonlocal::Newton::DW()");
853 const amrex::Real* DX =
linop->
Geom(lev).CellSize();
854 amrex::Box domain(
linop->
Geom(lev).Domain());
855 domain.convert(amrex::IntVect::TheNodeVector());
857 for (MFIter mfi(*a_u_mf[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
859 const Box& bx = mfi.tilebox();
860 amrex::Array4<T>
const& C = a_model_mf[lev]->array(mfi);
861 amrex::Array4<amrex::Real>
const& dw = a_dw_mf[lev]->array(mfi);
862 amrex::Array4<const amrex::Real>
const& u = a_u_mf[lev]->array(mfi);
863 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
870 for (
int p = 0; p < AMREX_SPACEDIM; p++)
872 AMREX_D_TERM(gradu(p, 0) = (
Numeric::Stencil<Set::Scalar, 1, 0, 0>::D(u, i, j, k, p, DX, sten));,
873 gradu(p, 1) = (
Numeric::Stencil<Set::Scalar, 0, 1, 0>::D(u, i, j, k, p, DX, sten));,
874 gradu(p, 2) = (
Numeric::Stencil<Set::Scalar, 0, 0, 1>::D(u, i, j, k, p, DX, sten)););
880 sig = C(i, j, k).DW(gradu);
882 sig = C(i, j, k).DW(0.5 * (gradu + gradu.transpose()));
884 sig = C(i, j, k).DW(gradu + Set::Matrix::Identity());
888 AMREX_D_PICK(dw(i, j, k, 0) = sig(0, 0);
890 dw(i, j, k, 0) = sig(0, 0); dw(i, j, k, 1) = sig(0, 1);
891 dw(i, j, k, 2) = sig(1, 0); dw(i, j, k, 3) = sig(1, 1);
893 dw(i, j, k, 0) = sig(0, 0); dw(i, j, k, 1) = sig(0, 1); dw(i, j, k, 2) = sig(0, 2);
894 dw(i, j, k, 3) = sig(1, 0); dw(i, j, k, 4) = sig(1, 1); dw(i, j, k, 5) = sig(1, 2);
895 dw(i, j, k, 6) = sig(2, 0); dw(i, j, k, 7) = sig(2, 1); dw(i, j, k, 8) = sig(2, 2););