@@ -171,6 +171,219 @@ MLNodeLaplacian::unimposeNeumannBC (int amrlev, MultiFab& rhs) const
171171 }
172172}
173173
174+ Real
175+ MLNodeLaplacian::getSolvabilityOffset (int amrlev, int mglev, MultiFab const & rhs) const
176+ {
177+ amrex::ignore_unused (amrlev);
178+ AMREX_ASSERT (amrlev==0 );
179+ AMREX_ASSERT (mglev+1 ==m_num_mg_levels[0 ] || mglev==0 );
180+
181+ if (m_coarsening_strategy == CoarseningStrategy::RAP) {
182+ #ifdef AMREX_USE_EB
183+ auto factory = dynamic_cast <EBFArrayBoxFactory const *>(m_factory[amrlev][0 ].get ());
184+ if (factory && !factory->isAllRegular ()) {
185+ if (mglev > 0 ) {
186+ return 0 ._rt ;
187+ } else {
188+ const MultiFab& vfrac = factory->getVolFrac ();
189+ const auto & vfrac_ma = vfrac.const_arrays ();
190+
191+ Box dom = Geom (amrlev,mglev).Domain ();
192+ for (int idim = 0 ; idim < AMREX_SPACEDIM; ++idim) {
193+ if (m_lobc[0 ][idim] != LinOpBCType::Neumann &&
194+ m_lobc[0 ][idim] != LinOpBCType::inflow)
195+ {
196+ dom.growLo (idim, 10 );
197+ }
198+ if (m_hibc[0 ][idim] != LinOpBCType::Neumann &&
199+ m_hibc[0 ][idim] != LinOpBCType::inflow)
200+ {
201+ dom.growHi (idim, 10 );
202+ }
203+ }
204+
205+ const auto & mask = (mglev+1 == m_num_mg_levels[0 ]) ? m_bottom_dot_mask : m_coarse_dot_mask;
206+ const auto & mask_ma = mask.const_arrays ();
207+ const auto & rhs_ma = rhs.const_arrays ();
208+ auto r = ParReduce (TypeList<ReduceOpSum,ReduceOpSum>{}, TypeList<Real,Real>{},
209+ rhs, IntVect (0 ),
210+ [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept
211+ -> GpuTuple<Real,Real>
212+ {
213+ Real scale = 0 .0_rt;
214+ #if (AMREX_SPACEDIM == 3)
215+ int const koff = 1 ;
216+ Real const fac = 0 .125_rt;
217+ #else
218+ int const koff = 0 ;
219+ Real const fac = 0 .25_rt;
220+ #endif
221+ for (int kc = k-koff; kc <= k; ++kc) {
222+ for (int jc = j-1 ; jc <= j; ++jc) {
223+ for (int ic = i-1 ; ic <= i; ++ic) {
224+ if (dom.contains (ic,jc,kc)) {
225+ scale += vfrac_ma[box_no](ic,jc,kc) * fac;
226+ }
227+ }}}
228+ return { mask_ma[box_no](i,j,k) * rhs_ma[box_no](i,j,k),
229+ mask_ma[box_no](i,j,k) * scale };
230+ });
231+
232+ Real s1 = amrex::get<0 >(r);
233+ Real s2 = amrex::get<1 >(r);
234+ ParallelAllReduce::Sum<Real>({s1,s2}, ParallelContext::CommunicatorSub ());
235+ return s1/s2;
236+ }
237+ } else
238+ #endif
239+ {
240+ Box nddom = amrex::surroundingNodes (Geom (amrlev,mglev).Domain ());
241+ for (int idim = 0 ; idim < AMREX_SPACEDIM; ++idim) {
242+ if (m_lobc[0 ][idim] != LinOpBCType::Neumann &&
243+ m_lobc[0 ][idim] != LinOpBCType::inflow)
244+ {
245+ nddom.growLo (idim, 10 ); // so that the test in ParReduce will faill
246+ }
247+ if (m_hibc[0 ][idim] != LinOpBCType::Neumann &&
248+ m_hibc[0 ][idim] != LinOpBCType::inflow)
249+ {
250+ nddom.growHi (idim, 10 );
251+ }
252+ }
253+
254+ const auto & mask = (mglev+1 == m_num_mg_levels[0 ]) ? m_bottom_dot_mask : m_coarse_dot_mask;
255+ const auto & mask_ma = mask.const_arrays ();
256+ const auto & rhs_ma = rhs.const_arrays ();
257+ auto r = ParReduce (TypeList<ReduceOpSum,ReduceOpSum>{}, TypeList<Real,Real>{},
258+ rhs, IntVect (0 ),
259+ [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept
260+ -> GpuTuple<Real,Real>
261+ {
262+ Real scale = 1 .0_rt;
263+ if (i == nddom.smallEnd (0 ) ||
264+ i == nddom.bigEnd (0 )) {
265+ scale *= 0 .5_rt;
266+ }
267+ #if (AMREX_SPACEDIM >= 2)
268+ if (j == nddom.smallEnd (1 ) ||
269+ j == nddom.bigEnd (1 )) {
270+ scale *= 0 .5_rt;
271+ }
272+ #endif
273+ #if (AMREX_SPACEDIM == 3)
274+ if (k == nddom.smallEnd (2 ) ||
275+ k == nddom.bigEnd (2 )) {
276+ scale *= 0 .5_rt;
277+ }
278+ #endif
279+ return { mask_ma[box_no](i,j,k) * rhs_ma[box_no](i,j,k),
280+ mask_ma[box_no](i,j,k) * scale };
281+ });
282+
283+ Real s1 = amrex::get<0 >(r);
284+ Real s2 = amrex::get<1 >(r);
285+ ParallelAllReduce::Sum<Real>({s1,s2}, ParallelContext::CommunicatorSub ());
286+ return s1/s2;
287+ }
288+ } else {
289+ return MLNodeLinOp::getSolvabilityOffset (amrlev, mglev, rhs);
290+ }
291+ }
292+
293+ void
294+ MLNodeLaplacian::fixSolvabilityByOffset (int amrlev, int mglev, MultiFab& rhs, Real offset) const
295+ {
296+ if (m_coarsening_strategy == CoarseningStrategy::RAP) {
297+ #ifdef AMREX_USE_EB
298+ auto factory = dynamic_cast <EBFArrayBoxFactory const *>(m_factory[amrlev][0 ].get ());
299+ if (factory && !factory->isAllRegular ()) {
300+ if (mglev == 0 ) {
301+ const MultiFab& vfrac = factory->getVolFrac ();
302+ const auto & vfrac_ma = vfrac.const_arrays ();
303+
304+ Box dom = Geom (amrlev,mglev).Domain ();
305+ for (int idim = 0 ; idim < AMREX_SPACEDIM; ++idim) {
306+ if (m_lobc[0 ][idim] != LinOpBCType::Neumann &&
307+ m_lobc[0 ][idim] != LinOpBCType::inflow)
308+ {
309+ dom.growLo (idim, 10 );
310+ }
311+ if (m_hibc[0 ][idim] != LinOpBCType::Neumann &&
312+ m_hibc[0 ][idim] != LinOpBCType::inflow)
313+ {
314+ dom.growHi (idim, 10 );
315+ }
316+ }
317+
318+ auto const & rhs_ma = rhs.arrays ();
319+ ParallelFor (rhs, IntVect (0 ),
320+ [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept
321+ {
322+ Real scale = 0 .0_rt;
323+ #if (AMREX_SPACEDIM == 3)
324+ int const koff = 1 ;
325+ Real const fac = 0 .125_rt;
326+ #else
327+ int const koff = 0 ;
328+ Real const fac = 0 .25_rt;
329+ #endif
330+ for (int kc = k-koff; kc <= k; ++kc) {
331+ for (int jc = j-1 ; jc <= j; ++jc) {
332+ for (int ic = i-1 ; ic <= i; ++ic) {
333+ if (dom.contains (ic,jc,kc)) {
334+ scale += vfrac_ma[box_no](ic,jc,kc) * fac;
335+ }
336+ }}}
337+ rhs_ma[box_no](i,j,k) -= offset * scale;
338+ });
339+ }
340+ } else
341+ #endif
342+ {
343+ Box nddom = amrex::surroundingNodes (Geom (amrlev,mglev).Domain ());
344+ for (int idim = 0 ; idim < AMREX_SPACEDIM; ++idim) {
345+ if (m_lobc[0 ][idim] != LinOpBCType::Neumann &&
346+ m_lobc[0 ][idim] != LinOpBCType::inflow)
347+ {
348+ nddom.growLo (idim, 10 ); // so that the test in ParReduce will faill
349+ }
350+ if (m_hibc[0 ][idim] != LinOpBCType::Neumann &&
351+ m_hibc[0 ][idim] != LinOpBCType::inflow)
352+ {
353+ nddom.growHi (idim, 10 );
354+ }
355+ }
356+
357+ auto const & rhs_ma = rhs.arrays ();
358+ ParallelFor (rhs, IntVect (0 ),
359+ [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept
360+ {
361+ Real scale = 1 .0_rt;
362+ if (i == nddom.smallEnd (0 ) ||
363+ i == nddom.bigEnd (0 )) {
364+ scale *= 0 .5_rt;
365+ }
366+ #if (AMREX_SPACEDIM >= 2)
367+ if (j == nddom.smallEnd (1 ) ||
368+ j == nddom.bigEnd (1 )) {
369+ scale *= 0 .5_rt;
370+ }
371+ #endif
372+ #if (AMREX_SPACEDIM == 3)
373+ if (k == nddom.smallEnd (2 ) ||
374+ k == nddom.bigEnd (2 )) {
375+ scale *= 0 .5_rt;
376+ }
377+ #endif
378+ rhs_ma[box_no](i,j,k) -= offset * scale;
379+ });
380+ }
381+ Gpu::streamSynchronize ();
382+ } else {
383+ rhs.plus (-offset, 0 , 1 );
384+ }
385+ }
386+
174387void
175388MLNodeLaplacian::setSigma (int amrlev, const MultiFab& a_sigma)
176389{
0 commit comments