Skip to content

Commit b15adfc

Browse files
authored
Merge pull request #144 from AFD-Illinois/fix/excised-timestep
Fix the timestep when `excise_polar_flux=true`
2 parents b89afd6 + 4a4d636 commit b15adfc

File tree

6 files changed

+66
-45
lines changed

6 files changed

+66
-45
lines changed

kharma/b_cleanup/b_cleanup.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
1-
/*
1+
/*
22
* File: b_cleanup.cpp
3-
*
3+
*
44
* BSD 3-Clause License
5-
*
5+
*
66
* Copyright (c) 2020, AFD Group at UIUC
77
* All rights reserved.
8-
*
8+
*
99
* Redistribution and use in source and binary forms, with or without
1010
* modification, are permitted provided that the following conditions are met:
11-
*
11+
*
1212
* 1. Redistributions of source code must retain the above copyright notice, this
1313
* list of conditions and the following disclaimer.
14-
*
14+
*
1515
* 2. Redistributions in binary form must reproduce the above copyright notice,
1616
* this list of conditions and the following disclaimer in the documentation
1717
* and/or other materials provided with the distribution.
18-
*
18+
*
1919
* 3. Neither the name of the copyright holder nor the names of its
2020
* contributors may be used to endorse or promote products derived from
2121
* this software without specific prior written permission.
22-
*
22+
*
2323
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2424
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2525
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -202,7 +202,7 @@ TaskStatus B_Cleanup::CleanupDivergence(std::shared_ptr<MeshData<Real>>& md)
202202
}
203203

204204
// Calculate/print inital max divB exactly as we would during run
205-
double divb_start;
205+
double divb_start;
206206
if (use_b_ct) {
207207
divb_start = B_CT::GlobalMaxDivB(md.get());
208208
} else {
@@ -274,7 +274,7 @@ TaskStatus B_Cleanup::CleanupDivergence(std::shared_ptr<MeshData<Real>>& md)
274274
// Synchronize to update cons.B's ghost zones
275275
KHARMADriver::SyncAllBounds(md);
276276
// Make sure prims.B reflects solution
277-
B_CT::MeshUtoP(md.get(), IndexDomain::entire, false);
277+
B_CT::MeshUtoP(md.get(), IndexDomain::entire);
278278
// Recalculate divB max for one last check
279279
divb_end = B_CT::GlobalMaxDivB(md.get());
280280
} else {
@@ -283,7 +283,7 @@ TaskStatus B_Cleanup::CleanupDivergence(std::shared_ptr<MeshData<Real>>& md)
283283
// Synchronize to update cons.B's ghost zones
284284
KHARMADriver::SyncAllBounds(md);
285285
// Make sure prims.B reflects solution
286-
B_FluxCT::MeshUtoP(md.get(), IndexDomain::entire, false);
286+
B_FluxCT::MeshUtoP(md.get(), IndexDomain::entire);
287287
// Recalculate divB max for one last check
288288
divb_end = B_FluxCT::GlobalMaxDivB(md.get());
289289
}

kharma/b_ct/b_ct.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ TaskStatus B_CT::CalculateEMF(MeshData<Real> *md)
376376
);
377377
} else if (scheme == "gs05_c" || scheme == "sg07") {
378378
auto& rho = md->PackVariablesAndFluxes(std::vector<std::string>{"cons.rho"});
379-
pmb0->par_for("B_CT_emf_GS05_c", block.s, block.e, b1.ks, b1.ke, b1.js, b1.je, b1.is, b1.ie,
379+
pmb0->par_for("B_CT_emf_SG07", block.s, block.e, b1.ks, b1.ke, b1.js, b1.je, b1.is, b1.ie,
380380
KOKKOS_LAMBDA (const int &bl, const int &k, const int &j, const int &i) {
381381
// Following adapted closely from AthenaK, including clever use of the mass flux for the
382382
// sign of the contact mode.
@@ -519,6 +519,11 @@ TaskStatus B_CT::DerefinePoles(MeshData<Real> *md)
519519
const int offset = (binner) ? 1 : -1; // offset to read the physical face values
520520
const int point_out = offset; // if F2 B field at j_f + offset face is positive when pointing out of the cell, +1.
521521

522+
// Should we allow flux through the pole?
523+
auto &bpars = pmesh->packages.Get("Boundaries")->AllParams();
524+
const bool allow_flux = binner ? bpars.Get<bool>("excise_flux_inner_x2"):
525+
bpars.Get<bool>("excise_flux_outer_x2");
526+
522527
// F1 average
523528
pmb->par_for("B_CT_derefine_poles_avg_F1", bCC.ks, bCC.ke, j_p.s, j_p.e, bF1.is, bF1.ie,
524529
KOKKOS_LAMBDA (const int &k, const int &j, const int &i) {
@@ -545,7 +550,7 @@ TaskStatus B_CT::DerefinePoles(MeshData<Real> *md)
545550
// starting k-index of the coarse cell
546551
const int k_start = k - k_fine;
547552

548-
if (j == j_f) {
553+
if (!allow_flux && j == j_f) {
549554
// The fine cells have 0 fluxes through the physical-ghost boundaries.
550555
B_avg(F2, 0, k, j, i) = 0.;
551556
} else { // average the fine cells

kharma/b_ct/b_ct_boundaries.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ void B_CT::ReconnectBoundaryB3(MeshBlockData<Real> *rc, IndexDomain domain, cons
341341
Inverter::u_to_p<Inverter::Type::kastaun>(G, U, m_u, gam, k, jf, i, P, m_p, Loci::center,
342342
floors, 25, 1e-12);
343343
// Floor them
344+
// TODO THIS IS IN FLUID FRAME
344345
int fflag = Floors::apply_geo_floors(G, P, m_p, gam, k, jf, i, floors, floors, Loci::center);
345346
// Recalculate U on anything we floored
346347
if (fflag)

kharma/boundaries/boundaries.cpp

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,7 @@ std::shared_ptr<KHARMAPackage> KBoundaries::Initialize(ParameterInput *pin, std:
173173
// Ensure fluxes through the zero-size face at the pole are zero
174174
bool zero_flux = pin->GetOrAddBoolean("boundaries", "zero_flux_" + bname, zero_polar_flux && bdir == X2DIR);
175175
params.Add("zero_flux_" + bname, zero_flux);
176-
177-
// Ensure fluxes through the zero-size face at the pole are zero
176+
// OR allow them via faux-excision
178177
bool excise_flux = pin->GetOrAddBoolean("boundaries", "excise_flux_" + bname, excise_polar_flux && bdir == X2DIR);
179178
params.Add("excise_flux_" + bname, excise_flux);
180179

@@ -196,8 +195,8 @@ std::shared_ptr<KHARMAPackage> KBoundaries::Initialize(ParameterInput *pin, std:
196195
bool reconnect_B3 = pin->GetOrAddBoolean("boundaries", "reconnect_B3_" + bname, false);
197196
params.Add("reconnect_B3_"+bname, reconnect_B3);
198197

199-
// Special EMF averaging. Allows B slippage, e.g. around pole for transmitting conditions
200-
// Useful for certain dirichlet conditions e.g. multizone
198+
// Special EMF averaging. Allows B3 to "slip" around the pole
199+
// Also useful to allow coherent motion even with Dirichlet boundaries, for e.g. multizone
201200
bool average_EMF = pin->GetOrAddBoolean("boundaries", "average_EMF_" + bname, (btype == "transmitting"));
202201
params.Add("average_EMF_"+bname, average_EMF);
203202
// Otherwise, always zero EMFs to prevent B field escaping the domain in polar/dirichlet bounds
@@ -704,6 +703,10 @@ TaskStatus KBoundaries::FixFlux(MeshData<Real> *md)
704703
if (pmb->boundary_flag[bface] == BoundaryFlag::user) {
705704
if (bdir != 2) throw std::runtime_error("Excised polar fluxes only fully implemented in X2!");
706705

706+
// Pack w/B to match indices with the `Flux.X` below
707+
// We won't *update* B field though
708+
auto &F = rc->PackVariablesAndFluxes({Metadata::WithFluxes}, cons_map);
709+
707710
// Going to need the primitive vars
708711
PackIndexMap prims_map;
709712
std::vector<MetadataFlag> prims_flags = {Metadata::GetUserFlag("Primitive"), Metadata::Cell};
@@ -770,7 +773,8 @@ TaskStatus KBoundaries::FixFlux(MeshData<Real> *md)
770773

771774
// Use LLF flux
772775
PLOOP {
773-
F.flux(dir, ip, k, j, i) = Flux::llf(Fl_all(ip, k, j, i), Fr_all(ip, k, j, i),
776+
if (ip != m_u.B1 && ip != m_u.B2 && ip != m_u.B3)
777+
F.flux(dir, ip, k, j, i) = Flux::llf(Fl_all(ip, k, j, i), Fr_all(ip, k, j, i),
774778
cmax(dir-1, k, j, i), cmin(dir-1, k, j, i),
775779
Ul_all(ip, k, j, i), Ur_all(ip, k, j, i)) * 0.5;
776780
}
@@ -817,21 +821,19 @@ TaskStatus KBoundaries::FixFlux(MeshData<Real> *md)
817821

818822
// Use LLF flux
819823
PLOOP {
820-
F.flux(bdir, ip, k, j, i) = Flux::llf(Fl_all(ip, k, j, i), Fr_all(ip, k, j, i),
821-
cmax(bdir-1, k, j, i), cmin(bdir-1, k, j, i),
822-
Ul_all(ip, k, j, i), Ur_all(ip, k, j, i));
823-
// Reduce the X1 flux in a semi-consistent way
824-
const int jc = (binner) ? j_cell + 1 : j_cell;
825-
F.flux(X1DIR, ip, k, j_cell, i) *= 0.5
826-
* (G.gdet(Loci::face1, j_cell, i) + G.gdet(Loci::corner, jc, i)) / 2 / G.gdet(Loci::face1, j_cell, i);
827-
// This is also a decent guess, but less accurate than recalculating as above
828-
// F.flux(X3DIR, ip, k, j_cell, i) *= 0.5
829-
// * G.gdet(loc, j_cell, i) / G.gdet(Loci::center, j_cell, i);
824+
if (ip != m_u.B1 && ip != m_u.B2 && ip != m_u.B3) {
825+
F.flux(bdir, ip, k, j, i) = Flux::llf(Fl_all(ip, k, j, i), Fr_all(ip, k, j, i),
826+
cmax(bdir-1, k, j, i), cmin(bdir-1, k, j, i),
827+
Ul_all(ip, k, j, i), Ur_all(ip, k, j, i));
828+
// Reduce the X1 flux in a semi-consistent way
829+
const int jc = (binner) ? j_cell + 1 : j_cell;
830+
F.flux(X1DIR, ip, k, j_cell, i) *= 0.5
831+
* (G.gdet(Loci::face1, j_cell, i) + G.gdet(Loci::corner, jc, i)) / 2 / G.gdet(Loci::face1, j_cell, i);
832+
// This is also a decent guess, but less accurate than recalculating as above
833+
// F.flux(X3DIR, ip, k, j_cell, i) *= 0.5
834+
// * G.gdet(loc, j_cell, i) / G.gdet(Loci::center, j_cell, i);
835+
}
830836
}
831-
832-
// Account for the half-size in the timestep later
833-
cmax(bdir-1, k, j, i) *= 2;
834-
cmin(bdir-1, k, j, i) *= 2;
835837
}
836838
);
837839
// Then average to make absolutely sure fluxes match
@@ -903,7 +905,9 @@ void KBoundaries::AddSource(MeshData<Real> *md, MeshData<Real> *mdudt, IndexDoma
903905
b.ks = b.ke = (binner) ? bi.ks : bi.ke;
904906
}
905907

906-
auto &dUdt = rc->PackVariables({Metadata::WithFluxes});
908+
// The magnetic field is probably defined at faces; even if it's defined in cells,
909+
// we shouldn't be monkeying with it. We just do not adjust it here.
910+
auto &dUdt = rc->PackVariables({Metadata::GetUserFlag("HD"), Metadata::WithFluxes});
907911
const auto& G = pmb->coords;
908912
const Loci loc = (binner) ? Loci::outer_half : Loci::inner_half;
909913

kharma/grmhd/grmhd.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
// TODO eliminate when Parthenon gets reduction types
4040
#include "Kokkos_Core.hpp"
4141

42+
#include "b_ct.hpp"
4243
#include "boundaries.hpp"
4344
#include "current.hpp"
4445
#include "floors.hpp"
@@ -257,6 +258,7 @@ Real EstimateTimestep(MeshData<Real> *md)
257258
const auto& grmhd_pars = pmesh->packages.Get("GRMHD")->AllParams();
258259

259260
// If we have to recompute ctop anywhere, we do it now
261+
// TODO only call if one of the reconnect_ or excised polar is enabled
260262
UpdateAveragedCtop(md);
261263

262264
// Other things we might have to return (light-crossing, pre-set timestep, etc.)
@@ -312,12 +314,17 @@ Real EstimateTimestep(MeshData<Real> *md)
312314
const auto& cmax = rc->PackVariables(std::vector<std::string>{"Flux.cmax"});
313315
const auto& cmin = rc->PackVariables(std::vector<std::string>{"Flux.cmin"});
314316

317+
auto& boundaries = pmesh->packages.Get<KHARMAPackage>("Boundaries")->AllParams();
318+
const bool excise_inner_x2 = boundaries.Get<bool>("excise_flux_inner_x2");
319+
const bool excise_outer_x2 = boundaries.Get<bool>("excise_flux_outer_x2");
320+
315321
double block_min_ndt = 0.;
316322
pmb->par_reduce("ndt_min", b.ks, b.ke, b.js, b.je, b.is, b.ie,
317323
KOKKOS_LAMBDA (const int k, const int j, const int i,
318324
double &local_result) {
319325
const auto& G = cmax.GetCoords();
320326
int ismr_factor = 1;
327+
double excise_factor = 1.0;
321328
double courant_limit = 1.0;
322329
if (ismr_poles && polar_inner_x2 && j < (b.js + ismr_nlevels)) {
323330
ismr_factor = m::pow(2, ismr_nlevels - (j - b.js));
@@ -328,8 +335,14 @@ Real EstimateTimestep(MeshData<Real> *md)
328335
courant_limit = 0.5;
329336
}
330337

338+
if (excise_inner_x2 && polar_inner_x2 && j == b.js) {
339+
excise_factor = 0.5;
340+
} else if (excise_outer_x2 && polar_outer_x2 && j == b.je) {
341+
excise_factor = 0.5;
342+
}
343+
331344
double ndt_zone = courant_limit / (1 / (G.Dxc<1>(i) / m::max(cmax(V1, k, j, i), cmin(V1, k, j, i))) +
332-
1 / (G.Dxc<2>(j) / m::max(cmax(V2, k, j, i), cmin(V2, k, j, i))) +
345+
1 / (G.Dxc<2>(j) * excise_factor / m::max(cmax(V2, k, j, i), cmin(V2, k, j, i))) +
333346
1 / (G.Dxc<3>(k) * ismr_factor / m::max(cmax(V3, k, j, i), cmin(V3, k, j, i))));
334347

335348
if (!m::isnan(ndt_zone) && (ndt_zone < local_result)) {
@@ -642,6 +655,8 @@ void CancelBoundaryT3(MeshBlockData<Real> *rc, IndexDomain domain, bool coarse)
642655
void UpdateAveragedCtop(MeshData<Real> *md)
643656
{
644657
auto pmesh = md->GetMeshPointer();
658+
if (pmesh->packages.AllPackages().count("B_CT"))
659+
B_CT::MeshUtoP(md, IndexDomain::interior);
645660
auto& params = pmesh->packages.Get<KHARMAPackage>("Boundaries")->AllParams();
646661
for (auto &pmb : pmesh->block_list) {
647662
auto &rc = pmb->meshblock_data.Get(md->StageName());
@@ -661,7 +676,8 @@ void UpdateAveragedCtop(MeshData<Real> *md)
661676
// If we've modified values on the pole...
662677
if (params.Get<bool>("cancel_T3_" + bname) ||
663678
params.Get<bool>("cancel_U3_" + bname) ||
664-
b3_is_reconnected) {
679+
b3_is_reconnected ||
680+
params.Get<bool>("excise_flux_" + bname)) {
665681
// ...and if this face of the block corresponds to a global boundary...
666682
if (pmb->boundary_flag[bface] == BoundaryFlag::user) {
667683
PackIndexMap prims_map, cons_map;
@@ -699,10 +715,6 @@ void UpdateAveragedCtop(MeshData<Real> *md)
699715
Flux::vchar_global(G, P, m_p, Dtmp, gam, emhd_params, k, jf, i, Loci::center, X3DIR,
700716
cmax(V3, k, jf, i), cmin_minus);
701717
cmin(V3, k, jf, i) = -cmin_minus;
702-
if (half_cells) {
703-
cmin(bdir-1, k, jf, i) *= 0.5;
704-
cmax(bdir-1, k, jf, i) *= 0.5;
705-
}
706718
}
707719
);
708720
}

kharma/prob/problem.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,11 @@ void KHARMA::ProblemGenerator(MeshBlock *pmb, ParameterInput *pin)
154154
// If needed, they are applied within the problem-specific call.
155155
// See InitializeFMTorus in fm_torus.cpp for the details for torus problems.
156156

157-
// Note we no longer call PtoU here either, as GRMHD variables' PtoU requires
158-
// the magnetic field, which is added in PostInitialize, after all blocks
159-
// are filled with other variables (it can be related to density averages which
160-
// require correct ghost zones)
161-
// If the B field will depend on the conserved variables (for some reason?)
162-
// they must be computed by the particular problem.
157+
// This is a temporary PtoU call. It will underestimate T^0_0 for magnetized
158+
// problems, since the magnetic field is not yet initialized.
159+
// However, the polar mitigations expect P,U in a consistent state,
160+
// so we have to give them something.
161+
Flux::BlockPtoU(rc.get(), IndexDomain::interior);
163162

164163
EndFlag();
165164
}

0 commit comments

Comments
 (0)