Skip to content

Commit d3a4aa3

Browse files
author
Wolfgang Kastaun
committed
Version 1.1 of the ReprimAnd library.
This is the exact version described in the final paper as published in Phys. Rev. D Changes: Recovery algorithm now takes into account rare corner case Improvements and Bugfixes in benchmark/accuracy plots Improvements of unit tests
1 parent eb39575 commit d3a4aa3

File tree

11 files changed

+209
-34
lines changed

11 files changed

+209
-34
lines changed

docsrc/sphinx/index.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ describing the recovery scheme:
2020

2121
Wolfgang Kastaun, Jay Vijay Kalinani, Riccardo Ciolfi,
2222
"Robust Recovery of Primitive Variables in Relativistic Ideal
23-
Magnetohydrodynamics" (2020).
23+
Magnetohydrodynamics",
24+
`arXiv:2005.01821 [gr-qc] <https://arxiv.org/abs/2005.01821>`_
25+
(2020).
2426

2527
Prospective users should be sure to check for updated versions
2628
that will likely be made available in a public repository.

library/Con2Prim_IMHD/con2prim_imhd.cc

Lines changed: 119 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#include <cmath>
88
#include "find_roots.h"
99

10-
1110
using namespace EOS_Toolkit;
1211
using namespace EOS_Toolkit::detail;
1312
using namespace std;
@@ -252,7 +251,7 @@ auto froot::initial_bracket(report& errs) const -> interval<real_t>
252251
f_upper g(h0, rsqr, rbsqr, bsqr);
253252

254253
ROOTSTAT status;
255-
mu_max = findroot_using_deriv(g, status, ndigits2);
254+
mu_max = findroot_using_deriv(g, status, ndigits2, ndigits2+4);
256255

257256
if (status != ROOTSTAT::SUCCESS) {
258257
if (status == ROOTSTAT::NOT_CONVERGED) {
@@ -343,35 +342,56 @@ void con2prim_mhd::operator()(prim_vars_mhd& pv, cons_vars_mhd& cv,
343342
set_to_nan(pv, cv);
344343
return;
345344
}
345+
346+
rarecase nc(bracket, eos.range_rho(), f);
347+
348+
if (nc.rho_too_big)
349+
{
350+
errs.set_range_rho(d, d);
351+
set_to_nan(pv, cv);
352+
return;
353+
}
346354

355+
if (nc.rho_too_small)
356+
{
357+
errs.set_atmo_set();
358+
atmo.set(pv, cv, g);
359+
return;
360+
}
361+
362+
347363
ROOTSTAT status;
348-
bracket = findroot_no_deriv(f, bracket, acc, max_iter, status);
349-
assert(bracket.contains(sol.lmu));
364+
bracket = findroot_no_deriv(f, nc.bracket, acc, max_iter, status);
350365

351366
errs.iters = sol.calls;
352367
if (status != ROOTSTAT::SUCCESS) {
353368
if (status == ROOTSTAT::NOT_CONVERGED) {
354369
errs.set_root_conv();
355370
}
356371
else if (status == ROOTSTAT::NOT_BRACKETED) {
372+
if (nc.rho_big) { //That's why
373+
errs.set_range_rho(d, d);
374+
set_to_nan(pv, cv);
375+
return;
376+
}
377+
if (nc.rho_small) {
378+
errs.set_atmo_set();
379+
atmo.set(pv, cv, g);
380+
return;
381+
}
357382
errs.set_root_bracket();
358383
}
359384
set_to_nan(pv, cv);
360385
return;
361386
}
387+
assert(bracket.contains(sol.lmu));
362388

363389

364390
if (sol.rho < atmo.rho_cut) {
365391
errs.set_atmo_set();
366392
atmo.set(pv, cv, g);
367393
return;
368394
}
369-
370-
if (sol.rho_raw > eos.range_rho()) {
371-
errs.set_range_rho(d, sol.rho);
372-
set_to_nan(pv, cv);
373-
return;
374-
}
375395

376396
auto rgeps = eos.range_eps(sol.rho, sol.ye);
377397
if (sol.eps_raw > rgeps) {
@@ -430,3 +450,92 @@ void con2prim_mhd::operator()(prim_vars_mhd& pv, cons_vars_mhd& cv,
430450
}
431451

432452

453+
454+
455+
456+
f_rare::f_rare(real_t wtarg_, const froot& f_)
457+
: v2targ(1.0 - 1.0/(wtarg_*wtarg_)), f(f_) {}
458+
459+
460+
/**
461+
This implements a root function for finding mu from W_hat
462+
**/
463+
auto f_rare::operator()(const real_t mu) const
464+
-> std::pair<real_t, real_t>
465+
{
466+
real_t x = f.x_from_mu(mu);
467+
real_t xsqr = x*x;
468+
real_t rfsqr = f.rfsqr_from_mu_x(mu,x);
469+
real_t vsqr = mu*mu * rfsqr;
470+
471+
real_t y = vsqr - v2targ;
472+
real_t dy = 2.0*mu*x*(xsqr * f.rsqr + mu * (xsqr+x+1.0) * f.rbsqr);
473+
474+
return {y, dy};
475+
}
476+
477+
478+
/**
479+
This checks for the corner case where the density might cross the
480+
allowed bounds while finding the root of the master function. In
481+
that case, a tighter initial root finding interval is constructed
482+
to guarantee uniqueness.
483+
**/
484+
rarecase::rarecase(const interval<real_t> ibracket,
485+
const interval<real_t> rgrho, const froot& f)
486+
{
487+
488+
real_t muc0 = ibracket.min();
489+
real_t muc1 = ibracket.max();
490+
const int ndigits = 30;
491+
492+
493+
if (f.d > rgrho.max()) {
494+
real_t wc = f.d / rgrho.max();
495+
if (wc > f.winf) {
496+
rho_too_big = true;
497+
}
498+
else {
499+
f_rare g(wc, f);
500+
501+
if (g(muc1).first <= 0) {
502+
rho_too_big = true;
503+
}
504+
else {
505+
if (g(muc0).first < 0) {
506+
ROOTSTAT status;
507+
real_t mucc = findroot_using_deriv(g, ibracket,
508+
status, ndigits, ndigits+2);
509+
assert(status == ROOTSTAT::SUCCESS);
510+
muc0 = max(muc0, mucc);
511+
rho_big = true;
512+
}
513+
}
514+
}
515+
}
516+
517+
if (f.d < f.winf * rgrho.min()) {
518+
real_t wc = f.d / rgrho.min();
519+
if (wc < 1) {
520+
rho_too_small = true;
521+
}
522+
else {
523+
f_rare g(wc, f);
524+
if (g(muc0).first >= 0) {
525+
rho_too_small = true;
526+
}
527+
else {
528+
if (g(muc1).first > 0) {
529+
ROOTSTAT status;
530+
real_t mucc = findroot_using_deriv(g, ibracket,
531+
status, ndigits, ndigits+2);
532+
assert(status == ROOTSTAT::SUCCESS);
533+
muc1 = min(muc1, mucc);
534+
rho_small = true;
535+
}
536+
}
537+
}
538+
}
539+
540+
bracket = interval<real_t>{muc0, muc1};
541+
}

library/Con2Prim_IMHD/include/con2prim_imhd_internals.h

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
namespace EOS_Toolkit {
1111
namespace detail {
1212

13+
class rarecase;
14+
class f_rare;
15+
1316
/// Function object representing the root function.
1417
/** This contains all the fixed parameters defining the function.
1518
It also remembers intermediate results from the last evaluation,
@@ -45,10 +48,14 @@ class froot {
4548
static real_t get_eps_raw(real_t mu, real_t qf,
4649
real_t rfsqr, real_t w);
4750

48-
51+
friend class rarecase;
52+
friend class f_rare;
53+
4954
public:
5055

5156
using value_t = real_t;
57+
58+
5259

5360
///Store intermediate results obtained when evaluating function.
5461
struct cache {
@@ -134,6 +141,43 @@ class f_upper {
134141
const real_t bsqr; ///< Fixed parameter \f$ b^2 = \frac{B^2}{D} \f$
135142
};
136143

144+
145+
146+
147+
///Root function used by rarecase class
148+
class f_rare {
149+
const real_t v2targ; ///< Target squared velocity
150+
const froot& f;
151+
152+
public:
153+
using value_t = real_t;
154+
155+
f_rare(
156+
real_t wtarg_, ///< Target Lorentz factor
157+
const froot& f_
158+
);
159+
160+
auto operator()(real_t mu) const -> std::pair<real_t,real_t>;
161+
};
162+
163+
///Class for handling rare corner case
164+
class rarecase {
165+
public:
166+
rarecase(
167+
const interval<real_t> bracket, ///< Initial master root bracket
168+
const interval<real_t> rgrho, ///< Allowed density range
169+
const froot& f ///< Master root function
170+
);
171+
172+
/// Root bracket on which solution is unique
173+
interval<real_t> bracket;
174+
175+
bool rho_too_big { false }; ///< Density definitely too large
176+
bool rho_big { false }; ///< Possibly too large
177+
bool rho_too_small { false }; ///< Density definitely too small
178+
bool rho_small { false }; ///< Possibly too small
179+
};
180+
137181
}
138182
}
139183

meson.build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
project('RePrimAnd', ['cpp','c'], default_options : ['cpp_std=c++11'],
3-
version : '1.0', license : 'CC BY-NC-SA 4.0')
3+
version : '1.1', license : 'CC BY-NC-SA 4.0')
44

55
project_headers_dest = 'reprimand'
66

meson_options.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11

22
option('build_documentation', type : 'boolean', value : true)
33
option('build_benchmarks', type : 'boolean', value : true)
4+
option('build_tests', type : 'boolean', value : true)

tests/benchmarks/scripts/plot_benchmark.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@
55
import sys
66
from stdplt import *
77

8-
8+
GAUSS_GU = 1.1973228161170991e-20
99

1010
def plot_perf_zeps(path, eosname, dat_bz, dat_bl):
1111
figname = "perf_eos%s_z_eps" % eosname
1212

1313
with Figure(os.path.join(path, figname)) as fig:
1414
grid = twopanel(fig)
1515

16-
maxit = max(int(dat_bz[-1].max()), int(dat_bl[-1].max()))
16+
maxit = max(int(dat_bz[-1][2].max()), int(dat_bl[-1][2].max()))
1717
bticks = np.arange(1,maxit, max(1,int(maxit/10)))
1818
clrmap = get_color_map("viridis", over='r')
1919

20-
for (x0,x1,it),ax in zip([dat_bz, dat_bl], grid):
20+
for (x0,x1,(z,eps,it,p,B)),ax in zip([dat_bz, dat_bl], grid):
2121
im = plot_color(it, x0, x1, vmin=0.999, vmax=maxit,
2222
cmap=clrmap, bar=False, axes=ax)
2323
ax.set_aspect('auto')
@@ -33,12 +33,23 @@ def plot_perf_zb(path, eosname, dat_c, dat_h):
3333
with Figure(os.path.join(path, figname)) as fig:
3434
grid = twopanel(fig)
3535

36-
maxit = max(int(dat_c[-1].max()), int(dat_h[-1].max()))
36+
maxit = max(int(dat_c[-1][2].max()), int(dat_h[-1][2].max()))
3737
bticks = np.arange(1,maxit, max(1,int(maxit/10)))
3838
clrmap = get_color_map("viridis", over='r')
39-
for (x0,x1,it),ax in zip([dat_c, dat_h], grid):
39+
for (x0,x1,(z,b,it,p,B)),ax in zip([dat_c, dat_h], grid):
4040
im = plot_color(it, x0, x1, vmin=0.999, vmax=maxit,
4141
cmap=clrmap, bar=False, axes=ax)
42+
43+
z1d = z[:,0]
44+
b1d = b[0,:]
45+
lgbeta = np.log10(B**2 / p)
46+
cs = ax.contour(np.log10(z1d), np.log10(b1d), lgbeta.T,
47+
levels=np.arange(-2,11,4), colors='y')
48+
49+
ax.clabel(cs, inline=True)
50+
ax.contour(np.log10(z1d), np.log10(b1d), B.T,
51+
levels=[1e16*GAUSS_GU], colors=['r'])
52+
4253
ax.set_aspect('auto')
4354
ax.set_ylabel(r'$\log_{10}(B / \sqrt{D})$')
4455
grid[1].set_xlabel(r'$\log_{10}(z[c])$')
@@ -49,8 +60,8 @@ def plot_perf_zb(path, eosname, dat_c, dat_h):
4960

5061
def load_data(path, eos):
5162
def read(t):
52-
c0,c1,d = load_grid(os.path.join(path, t % eos), 3)
53-
return c0,c1,d[2]
63+
c0,c1,d = load_grid(os.path.join(path, t % eos), 5)
64+
return c0,c1,d
5465
#
5566
files = ["perf_eos%s_z_b_cold.dat", "perf_eos%s_z_b_hot.dat",
5667
"perf_eos%s_z_eps_Bzero.dat",
@@ -63,8 +74,8 @@ def main():
6374
path = sys.argv[1]
6475
for eos in ['ig', 'hyb']:
6576
dat_c, dat_h, dat_bz, dat_bl = load_data(path, eos)
66-
plot_perf_zeps(path, eos, dat_c, dat_h)
67-
plot_perf_zb(path, eos, dat_bz, dat_bl)
77+
plot_perf_zeps(path, eos, dat_bz, dat_bl)
78+
plot_perf_zb(path, eos, dat_c, dat_h)
6879
#
6980
#
7081

tests/benchmarks/src/benchmark_con2prim_mhd.cc

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@ void map_z_eps(eos_thermal eos, con2prim_mhd& cv2pv, real_t b, real_t rho,
7575
}
7676
assert(!rep.failed());
7777
os << setw(20) << z << setw(20) << epsth
78-
<< setw(20) << rep.iters << endl;
78+
<< setw(20) << rep.iters
79+
<< setw(20) << pv.press
80+
<< setw(20) << b*sqrt(cv.dens)
81+
<< endl;
7982
}
8083
os << endl;
8184
}
@@ -85,7 +88,7 @@ void map_z_b(eos_thermal eos, con2prim_mhd& cv2pv, real_t epsth,
8588
real_t rho, real_t ye, sm_metric3& g, string fn)
8689
{
8790
auto iz = log_spacing(1e-2, 1e3, 200);
88-
auto ib = log_spacing(1e-4, 1e1, 200);
91+
auto ib = log_spacing(1e-4, 1e4, 200);
8992

9093
const real_t eps0 = eos.range_eps(rho, ye).min();
9194
const real_t eps = eps0 + epsth;
@@ -104,7 +107,10 @@ void map_z_b(eos_thermal eos, con2prim_mhd& cv2pv, real_t epsth,
104107
assert(false);
105108
}
106109
assert(!rep.failed());
107-
os << setw(20) << z << setw(20) << b <<setw(20) << rep.iters << endl;
110+
os << setw(20) << z << setw(20) << b <<setw(20) << rep.iters
111+
<< setw(20) << pv.press
112+
<< setw(20) << b*sqrt(cv.dens)
113+
<< endl;
108114
}
109115
os << endl;
110116
}
@@ -144,14 +150,14 @@ int main(int argc, char *argv[])
144150
eos_thermal eos_ig = get_eos_ig();
145151
atmosphere atmo_ig = get_atmo(eos_ig, 1e-6);
146152
const real_t acc = 1e-8;
147-
con2prim_mhd cv2pv_ig(eos_ig, atmo_ig.rho, false, 2e3, 1e2,
153+
con2prim_mhd cv2pv_ig(eos_ig, atmo_ig.rho, false, 2e3, 5e4,
148154
atmo_ig, acc, 100);
149155

150156

151157
auto eos_hyb = load_eos_thermal(PATH_EOS_HYB, units::geom_solar());
152158

153159
atmosphere atmo_hyb = get_atmo(eos_hyb, 0.0);
154-
con2prim_mhd cv2pv_hyb(eos_hyb, atmo_hyb.rho, false, 2e3, 1e2,
160+
con2prim_mhd cv2pv_hyb(eos_hyb, atmo_hyb.rho, false, 2e3, 5e4,
155161
atmo_hyb, acc, 100);
156162

157163

0 commit comments

Comments
 (0)