diff --git a/cmake/Fluid.cmake b/cmake/Fluid.cmake index 0ac34af5..11a618ae 100644 --- a/cmake/Fluid.cmake +++ b/cmake/Fluid.cmake @@ -18,14 +18,6 @@ else() set(USE_VALENCIA 0 CACHE BOOL "Covariant formulation of GRMHD") endif() -option(PHOEBUS_C2P_ROBUST_FLOORS "Use full floors for c2p robust" ON) - -if(PHOEBUS_C2P_ROBUST_FLOORS) - set(USE_C2P_ROBUST_FLOORS 1 CACHE BOOL "Use regular floors for c2p robust") -else() - set(USE_C2P_ROBUST_FLOORS 0 CACHE BOOL "Use only sanity floors for c2p robust") -endif() - option(PHOEBUS_FLUX_AND_SRC_DIAGS "Stash flux divergence and sources for possible output" OFF) if(PHOEBUS_FLUX_AND_SRC_DIAGS) set(SET_FLUX_SRC_DIAGS 1 CACHE BOOL "Allocate and set these diagnostics") diff --git a/inputs/linear_modes.pin b/inputs/linear_modes.pin index 1925b65c..d7e942ef 100644 --- a/inputs/linear_modes.pin +++ b/inputs/linear_modes.pin @@ -112,7 +112,6 @@ riemann = hll c2p_max_iter = 100 recon = linear c2p_tol = 1.e-12 -#c2p_method = classic c2p_method = robust diff --git a/inputs/radiation_advection.pin b/inputs/radiation_advection.pin index a42194d0..fd064d8a 100644 --- a/inputs/radiation_advection.pin +++ b/inputs/radiation_advection.pin @@ -105,6 +105,7 @@ absorption = true do_nu_electron = true do_nu_electron_anti = false do_nu_heavy = false +src_solver = oned scattering_fraction = 1.0 diff --git a/inputs/torus.pin b/inputs/torus.pin index 61a2c40a..f1e65ba6 100644 --- a/inputs/torus.pin +++ b/inputs/torus.pin @@ -125,6 +125,7 @@ sie_exp_floor = -1.0 ceiling_type = ConstantGamSie sie0_ceiling = 1.0 gam0_ceiling = 10.0 +enable_ox1_fmks_inflow_check = true target_beta = 100. diff --git a/inputs/torus_rad.pin b/inputs/torus_rad.pin new file mode 100644 index 00000000..a6022b33 --- /dev/null +++ b/inputs/torus_rad.pin @@ -0,0 +1,191 @@ + + +problem = torus +ix1_bc = outflow +ox1_bc = outflow +ix2_bc = reflect +ox2_bc = reflect + + +bc_vars = primitive + + +problem_id = torus # problem ID: basename of output filenames + + +file_type = rst +dt = 200.0 + + +variables = p.density, & +# c.density, & + p.velocity, & +# c.momentum, & + p.energy, & +# c.energy, & +# pressure, & + r.p.J, & + r.p.H, & +# r.c.E, & +# r.c.F, & + g.c.coord, & + g.n.coord, & + g.c.detgam, & +# g.c.bcon, & + g.c.alpha, & + g.c.gcov, & +# src_terms, & +# flux_divergence, & + r.i.kappaH, & + p.bfield + +file_type = hdf5 # Tabular data dump +dt = 5.0 # time increment between outputs + + +nlim = -1 # cycle limit +tlim = 2000. # time limit +integrator = rk2 # time integration algorithm +ncycle_out = 1 # interval for stdout summary info +dt_init_fact = 1.e-6 + + +nghost = 4 +#refinement = adaptive +#numlevel = 3 + +nx1 = 256 # Number of zones in X1-direction +#nx1 = 128 +x1min = 0.59 # minimum value of X1; overwritten for the torus problem +x1max = 3.69 # maximum value of X1; set by /r_outer for the torus problem +ix1_bc = user # Inner-X1 boundary condition flag +ox1_bc = user # Outer-X1 boundary condition flag + +nx2 = 256 # Number of zones in X2-direction +#nx2 = 128 +x2min = 0 # minimum value of X2 +x2max = 1 # maximum value of X2. X2 = 1 -> theta = pi +ix2_bc = user # Inner-X2 boundary condition flag +ox2_bc = user # Outer-X2 boundary condition flag + +nx3 = 1 # Number of zones in X3-direction +#nx3 = 64 +x3min = 0 # minimum value of X3 +x3max = 6.28318530718 # maximum value of X3. 2*pi +ix3_bc = periodic # Inner-X3 boundary condition flag +ox3_bc = periodic # Outer-X3 boundary condition flfgag + +num_threads = 1 # maximum number of OMP threads + +# Commenting out meshblock sizes makes the simulation 1 meshblock +# +# nx1 = 128 +# nx2 = 128 +# nx3 = 1 + + +field = c.c.bulk.rho +method = derivative_order_1 +max_level = 3 + + +type = IdealGas +Gamma = 1.66666666666666666666666667 +Cv = 1.0 + + +hydro = true +rad = true + + +xorder = 2 +cfl = 0.8 +riemann = llf +recon = weno5 +c2p_max_iter = 100 +c2p_tol = 1.e-8 +c2p_floor_scale_fac = 1.e-10 +c2p_fail_on_floors = false +c2p_fail_on_ceilings = false +c2p_method = robust +Ye = false +mhd = true + + +a = 0.9375 + + +derefine_poles = false +r_outer = 250 + + +cfl = 0.5 +recon = weno5 +method = moment_eddington +absorption = true +do_nu_electron = true +do_nu_electron_anti = false +do_nu_heavy = false +src_solver = oned # fourd +src_use_oned_backup = false # true +src_rootfind_eps = 1.e-6 +src_rootfind_tol = 1.e-8 +src_rootfind_maxiter = 100 +oned_fixup_strategy = ignore_dJ +recon_fixup_strategy = bounds +closure_c2p_strategy = robust + +#scattering_fraction = 1.0 +scattering_fraction = 0.5 + + +type = gray +gray_kappa = 1.e-10 # midplane tau/zone >1e3 + + +scale_free = false +geom_mass_msun = 1. +fluid_mass_g = 1.e26 + + +enable_floors = true +enable_mhd_floors = true +enable_rad_floors = true +enable_ceilings = true +enable_rad_ceilings = true +enable_flux_fixup = false # true +enable_c2p_fixup = true +enable_source_fixup = true +report_c2p_fails = false +report_source_fails = false +c2p_failure_force_fixup_both = false +enable_ox1_fmks_inflow_check = true + +fluid_c2p_failure_strategy = interpolate +rad_c2p_failure_strategy = interpolate +src_failure_strategy = floors + +floor_type = ExpX1RhoSie +rho0_floor = 1.0e-5 +sie0_floor = 1.0e-2 +rho_exp_floor = -2.0 +sie_exp_floor = -1.0 +ceiling_type = ConstantGamSie +sie0_ceiling = 1.0 +gam0_ceiling = 10.0 +rad_floor_type = ExpX1J +J0_floor = 1.e-6 +J_exp_floor = -3.0 +rad_ceiling_type = ConstantXi0 +xi0_ceiling = 0.95 + + +target_beta = 100. +harm_beta_normalization = true +u_jitter = 0.05 +kappa = 0.01 +rin = 6.0 +rmax = 12.0 +n_inside_horizon = 5 +magnetized = true +initial_radiation = thermal diff --git a/scripts/python/phoebus_eos.py b/scripts/python/phoebus_eos.py index a95eb89c..cfdab419 100644 --- a/scripts/python/phoebus_eos.py +++ b/scripts/python/phoebus_eos.py @@ -26,6 +26,9 @@ def T_from_rho_u_Ye(self, rho, u, Ye): def u_from_rho_T_Ye(self, rho, T, Ye): raise NotImplementedError() + def P_from_rho_u_Ye(self, rho, u, Ye): + raise NotImplementedError() + # -- Ideal gas EOS class IdealEOS(BaseEOS): def __init__(self, params): @@ -40,6 +43,9 @@ def T_from_rho_u_Ye(self, rho, u, Ye): def u_from_rho_T_Ye(self, rho, T, Ye): return rho * self.Cv * T + def P_from_rho_u_Ye(self, rho, u, Ye): + return self.gm1 * u + # ---------------------------------------------------------------------------- # # -- Dictionary of EOS types eos_type_dict = {'IdealGas' : IdealEOS} diff --git a/scripts/python/phoedf.py b/scripts/python/phoedf.py index 532ed769..1bc63898 100644 --- a/scripts/python/phoedf.py +++ b/scripts/python/phoedf.py @@ -21,10 +21,13 @@ # Phoebus-specific derived class from Parthenon's phdf datafile reader class phoedf(phdf.phdf): - def __init__(self, filename): + def __init__(self, filename, geomfile=None): super().__init__(filename) - self.eos_type = self.Params['eos/type'] + try: + self.eos_type = self.Params['eos/type'].decode() + except (UnicodeDecodeError, AttributeError): + self.eos_type = self.Params['eos/type'] if 'opacity/type' in self.Params: self.opacity_model = self.Params['opacity/type'] @@ -38,8 +41,191 @@ def __init__(self, filename): self.EnergyDensityCodeToCGS = self.EnergyCodeToCGS * self.NumberDensityCodeToCGS self.MassDensityCodeToCGS = self.MassCodeToCGS * self.NumberDensityCodeToCGS + self.Nx1 = self.MeshBlockSize[0] + self.Nx2 = self.MeshBlockSize[1] + self.Nx3 = self.MeshBlockSize[2] + + self.ScalarField = [self.NumBlocks, self.Nx3, self.Nx2, self.Nx1] + +# TODO(BRR) store output data only once with get/load functions + + if geomfile is None: + self.flatgcov = self.Get("g.c.gcov", flatten=False) + def flatten_indices(mu, nu): + ind = [[0,1,3,6],[1,2,4,7],[3,4,5,8],[6,7,8,9]] + return ind[mu][nu] + self.gcov = np.zeros([self.NumBlocks, self.Nx3, self.Nx2, self.Nx1, 4, 4]) + print(self.flatgcov.shape) + for mu in range(4): + for nu in range(4): + self.gcov[:,:,:,:,mu,nu] = self.flatgcov[:,:,:,:,flatten_indices(mu,nu)] + del(self.flatgcov) + self.gcon = np.zeros([self.NumBlocks, self.Nx3, self.Nx2, self.Nx1, 4, 4]) + for b in range(self.NumBlocks): + for k in range(self.Nx3): + for j in range(self.Nx2): + for i in range(self.Nx1): + self.gcon[b,k,j,i,:,:] = np.linalg.inv(self.gcov[b,k,j,i,:,:]) + self.alpha = np.zeros([self.NumBlocks, self.Nx3, self.Nx2, self.Nx1]) + self.alpha[:,:,:,:] = np.sqrt(-1./self.gcon[:,:,:,:,0,0]) + self.betacon = np.zeros([self.NumBlocks, self.Nx3, self.Nx2, self.Nx1, 3]) + self.betacon[:,:,:,:,:] = self.gcon[:,:,:,:,1:,0]*(self.alpha[:,:,:,:,np.newaxis]**2) + self.gammacon = np.zeros([self.NumBlocks, self.Nx3, self.Nx2, self.Nx1, 3, 3]) + for ii in range(3): + for jj in range(3): + self.gammacon[:,:,:,:,ii,jj] = self.gcon[:,:,:,:,ii+1,jj+1] + self.betacon[:,:,:,:,ii]*self.betacon[:,:,:,:,jj]/(self.alpha[:,:,:,:]**2) + + # Output quantities loaded upon request + self.rho = None + + # Derived quantities evaluated upon request + self.Gamma = None + self.xi = None + self.Pg = None + self.Pm = None + self.Pr = None + self.tau = None + self.Tg = None + + def GetRho(self): + if self.rho is not None: + return self.rho + + self.rho = self.Get("p.density", flatten=False) + + return self.rho + def GetEOS(self): return eos_type_dict[self.eos_type](self.Params) def GetOpacity(self, constants='cgs'): return opacity_type_dict[self.opacity_model](self.Params, constants) + + # Optical depth per zone + def GetTau(self): + if self.tau is not None: + return self.tau + + self.tau = np.zeros(self.ScalarField) + + kappaH = self.Get("r.i.kappaH", flatten=False) + + for b in range(self.NumBlocks): + dX1 = (self.BlockBounds[b][1] - self.BlockBounds[b][0])/self.Nx1 + dX2 = (self.BlockBounds[b][3] - self.BlockBounds[b][2])/self.Nx1 + self.tau[b,:,:,:] = kappaH[b,:,:,:,]*np.sqrt((dX1*self.gcov[b,:,:,:,1,1])**2 + (dX2*self.gcov[b,:,:,:,2,2])**2) + + self.tau = np.clip(self.tau, 1.e-20, 1.e20) + + return self.tau + + def GetPg(self): + if self.Pg is not None: + return self.Pg + + self.Pg = np.zeros(self.ScalarField) + + eos = self.GetEOS() + rho = self.GetRho() + u = self.Get("p.energy", flatten=False) + Ye = np.zeros(self.ScalarField) + self.Pg[:,:,:,:] = eos.P_from_rho_u_Ye(rho[:,:,:,:], u[:,:,:,:], Ye[:,:,:,:]) + + self.Pg = np.clip(self.Pg, 1.e-20, 1.e20) + + return self.Pg + + def GetTg(self): + if self.Tg is not None: + return self.Tg + + self.Tg = np.zeros(self.ScalarField) + + eos = self.GetEOS() + rho = self.GetRho() + u = self.Get("p.energy", flatten=False) + Ye = np.zeros(self.ScalarField) + self.Tg[:,:,:,:] = eos.T_from_rho_u_Ye(rho[:,:,:,:], u[:,:,:,:], Ye[:,:,:,:]) + self.Tg *= self.TemperatureCodeToCGS + + self.Tg = np.clip(self.Tg, 1., 1.e20) + + return self.Tg + + + def GetPm(self): + if self.Pm is not None: + return self.Pm + + self.Pm = np.zeros(self.ScalarField) + + Gamma = self.GetGamma() + + bcon0 = np.zeros(self.ScalarField) + Bsq = np.zeros(self.ScalarField) + bsq = np.zeros(self.ScalarField) + Bcon = self.Get("p.bfield", flatten=False) + vpcon = self.Get("p.velocity", flatten=False) + for ii in range(3): + for jj in range(3): + bcon0[:,:,:,:] += self.gcov[:,:,:,:,ii+1,jj+1]*Bcon[:,:,:,:,ii]*vpcon[:,:,:,:,jj] + Bsq[:,:,:,:] += self.gcov[:,:,:,:,ii+1,jj+1]*Bcon[:,:,:,:,ii]*Bcon[:,:,:,:,jj] + bsq[:,:,:,:] = (Bsq[:,:,:,:] + (self.alpha[:,:,:,:]*bcon0[:,:,:,:])**2)/(Gamma[:,:,:,:]**2) + + self.Pm = bsq / 2. + self.Pm = np.clip(self.Pm, 1.e-20, 1.e20) + + return self.Pm + + def GetPr(self): + if self.Pr is not None: + return self.Pr + + self.Pr = np.zeros(self.ScalarField) + + J = self.Get("r.p.J", flatten=False) + self.Pr[:,:,:,:] = 1./3.*J[:,:,:,:] + + self.Pr = np.clip(self.Pr, 1.e-20, 1.e20) + + return self.Pr + + def GetGamma(self): + if self.Gamma is not None: + return self.Gamma + + self.Gamma = np.zeros([self.NumBlocks, self.Nx3, self.Nx2, self.Nx1]) + + vpcon = self.Get("p.velocity", flatten=False) + for ii in range(3): + for jj in range(3): + self.Gamma[:,:,:,:] += self.gcov[:,:,:,:,ii+1,jj+1] * vpcon[:,:,:,:,ii] * vpcon[:,:,:,:,jj] + self.Gamma = np.sqrt(1. + self.Gamma) + + return self.Gamma + + def GetXi(self): + if self.xi is not None: + return self.xi + + self.xi = np.zeros([self.NumBlocks, self.Nx3, self.Nx2, self.Nx1]) + Hcov = self.Get("r.p.H", flatten=False) + vcon = self.Get("p.velocity", flatten=False) + Gamma = self.GetGamma() + vcon[:,:,:,:,:] /= Gamma[:,:,:,:,np.newaxis] + vdH = np.zeros([self.NumBlocks, self.Nx3, self.Nx2, self.Nx1]) + for ii in range(3): + vdH += vcon[:,:,:,:,ii]*Hcov[:,:,:,:,ii] + for jj in range(3): + self.xi[:,:,:,:] += self.gammacon[:,:,:,:,ii,jj]*Hcov[:,:,:,:,ii]*Hcov[:,:,:,:,jj] + self.xi[:,:,:,:] -= vdH*vdH + self.xi = np.sqrt(self.xi) + + print(f"xi max: {self.xi.max()}") + + self.xi = np.clip(self.xi, 1.e-10, 1.) + + return self.xi + + + diff --git a/scripts/python/plot_radiation_advection.py b/scripts/python/plot_radiation_advection.py index bf18bd5e..1e58d9c0 100644 --- a/scripts/python/plot_radiation_advection.py +++ b/scripts/python/plot_radiation_advection.py @@ -121,7 +121,10 @@ def BoostedDiffusion(kappa, x0p, v, t0p, J0, x, t): color = cmap((t - minTime)/(maxTime - minTime)) for block in range(dfile.NumBlocks): - plt_ax.plot(x[block, :], J[block, iz, iy, :, ispec], color=color) + if J.ndim == 5: + plt_ax.plot(x[block, :], J[block, iz, iy, :, ispec], color=color) + else: + plt_ax.plot(x[block, :], J[block, iz, iy, :], color=color) xmin = np.amin(x) xmax = np.amax(x) @@ -143,7 +146,10 @@ def BoostedDiffusion(kappa, x0p, v, t0p, J0, x, t): plt_ax.set_xlim([xl, xh]) plt_ax.set_ylim([yl, yh]) -etot = sum(J[0, iz, iy, :, ispec]) +if J.ndim == 5: + etot = sum(J[0, iz, iy, :, ispec]) +else: + etot = sum(J[0, iz, iy, :]) print("etot: ", etot) plt_ax.text(0.05*(xh-xl)+xl, 0.95*(yh-yl)+yl, '$\kappa={}$'.format(kappa)) diff --git a/scripts/python/plot_snap2d.py b/scripts/python/plot_snap2d.py index 18ae34a9..5e7e537e 100755 --- a/scripts/python/plot_snap2d.py +++ b/scripts/python/plot_snap2d.py @@ -45,6 +45,7 @@ def plot_dump(filename, varname, log=True): data = phdf(filename) print(data) + time = data.Time q = data.Get(varname, False) NB = q.shape[0] @@ -86,7 +87,12 @@ def plot_dump(filename, varname, fig = plt.figure() p = fig.add_subplot(111, aspect=1) for i in range(NB): - mesh = p.pcolormesh(x[i,0,:,:], y[i,0,:,:], q[i,0,:,:], shading='gouraud', + val = q[i,0,:,:] + if len(val.shape) > 2: + print("WARNING plotting the 0th index of multidimensional variable!") + val = val[:,:,0] + + mesh = p.pcolormesh(x[i,0,:,:], y[i,0,:,:], val[:,:], shading='gouraud', vmin=qmin, vmax=qmax, cmap=colormap) plt.xlim(x1bounds[0], x1bounds[1]) @@ -96,6 +102,8 @@ def plot_dump(filename, varname, plt.ylabel(r'$y$') plt.colorbar(mesh, label=cbar_label) + plt.title("t = %g" % time) + plt.savefig(savename, dpi=300, bbox_inches='tight') plt.clf() plt.cla() diff --git a/scripts/python/plot_torus.py b/scripts/python/plot_torus.py new file mode 100644 index 00000000..285c565c --- /dev/null +++ b/scripts/python/plot_torus.py @@ -0,0 +1,229 @@ +#!/usr/bin/env python + +# © 2022. Triad National Security, LLC. All rights reserved. This +# program was produced under U.S. Government contract +# 89233218CNA000001 for Los Alamos National Laboratory (LANL), which +# is operated by Triad National Security, LLC for the U.S. Department +# of Energy/National Nuclear Security Administration. All rights in +# the program are reserved by Triad National Security, LLC, and the +# U.S. Department of Energy/National Nuclear Security +# Administration. The Government is granted for itself and others +# acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +# license in this material to reproduce, prepare derivative works, +# distribute copies to the public, perform publicly and display +# publicly, and to permit others to do so. + +import argparse +import numpy as np +import matplotlib +import matplotlib.pyplot as plt +import matplotlib.patches as patches +from mpl_toolkits.axes_grid1 import make_axes_locatable +import sys +import shutil +import os +from subprocess import call, DEVNULL +import glob +from parthenon_tools import phdf +import time +from enum import Enum +from phoebus_constants import cgs, scalefree +import phoebus_utils +from phoedf import phoedf + +def plot_frame(ifname, fname, savefig, geomfile=None, rlim=40, coords='cartesian'): + print(fname) + + xlim = 0 + + cmap_uniform = 'viridis' + cmap_diverging = 'RdYlBu' + + dfile = phoedf(fname) + + rad_active = dfile.Params['radiation/active'] + + a = dfile.Params['geometry/a'] + hslope = dfile.Params['geometry/h'] + + if rad_active: + fig, axes = plt.subplots(2, 4, figsize=(8,6)) + else: + fig, axes = plt.subplots(2, 2, figsize=(4,6)) + + if geomfile is None: + geomfile = dfile + + nblocks = geomfile.NumBlocks + nx = geomfile.MeshBlockSize[0] + ny = geomfile.MeshBlockSize[1] + nz = geomfile.MeshBlockSize[2] + + time = dfile.Time + + # Get pcolormesh grid for each block + x1block = np.zeros([nblocks, nx+1, ny+1]) + x2block = np.zeros([nblocks, nx+1, ny+1]) + for b in range(nblocks): + for i in range(nx+1): + for j in range(ny+1): + dx1 = (geomfile.BlockBounds[b][1] - geomfile.BlockBounds[b][0])/nx + dx2 = (geomfile.BlockBounds[b][3] - geomfile.BlockBounds[b][2])/ny + x1block[b,i,j] = geomfile.BlockBounds[b][0] + i*dx1 + x2block[b,i,j] = geomfile.BlockBounds[b][2] + j*dx2 + rblock = np.exp(x1block) + thblock = np.pi*x2block + ((1. - hslope)/2.)*np.sin(2.*np.pi*x2block) + xblock = rblock*np.sin(thblock) + yblock = rblock*np.cos(thblock) + + if coords == "cartesian": + xplot = xblock + yplot = yblock + elif coords == "mks": + xplot = x1block + yplot = x2block + + ax = axes[0,0] + ldensity = np.log10(np.clip(dfile.Get("p.density", flatten=False), 1.e-20, None)) + for b in range(nblocks): + im = ax.pcolormesh(xplot[b,:,:], yplot[b,:,:], ldensity[b,0,:,:].transpose(), vmin=-5, vmax=0, + cmap=cmap_uniform) + div = make_axes_locatable(ax) + cax = div.append_axes('right', size="5%", pad = 0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + ax.set_title(r'$\log_{10}~\rho$') + + ax = axes[0,1] + Gamma = dfile.GetGamma() + for b in range(nblocks): + im = ax.pcolormesh(xplot[b,:,:], yplot[b,:,:], Gamma[b,0,:,:].transpose(), vmin=1, vmax=5, + cmap=cmap_uniform) + div = make_axes_locatable(ax) + cax = div.append_axes('right', size="5%", pad = 0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + ax.set_title(r'$\Gamma$') + + if rad_active: + + ax = axes[0,2] + Pg = dfile.GetPg() + Pm = np.clip(dfile.GetPm(), 1.e-20, 1.e20) + lbeta = np.log10(Pg/Pm) + for b in range(nblocks): + im = ax.pcolormesh(xplot[b,:,:], yplot[b,:,:], lbeta[b,0,:,:].transpose(), vmin=-2, vmax=2, + cmap=cmap_diverging) + div = make_axes_locatable(ax) + cax = div.append_axes('right', size="5%", pad = 0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + ax.set_title(r'$\log_{10}~\beta_{\rm M}$') + + ax = axes[0,3] + lTg = np.log10(dfile.GetTg()) + for b in range(nblocks): + im = ax.pcolormesh(xplot[b,:,:], yplot[b,:,:], lTg[b,0,:,:].transpose(), vmin=5, vmax=10, + cmap=cmap_diverging) + div = make_axes_locatable(ax) + cax = div.append_axes('right', size="5%", pad = 0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + ax.set_title(r'$\log_{10}~T_{\rm g}~({\rm K})$') + + ax = axes[1,0] + lJ = np.log10(np.clip(dfile.Get("r.p.J", flatten=False), 1.e-20, None)) + for b in range(nblocks): + im = ax.pcolormesh(xplot[b,:,:], yplot[b,:,:], lJ[b,0,:,:].transpose(), vmin=-5, vmax=0, + cmap=cmap_uniform) + div = make_axes_locatable(ax) + cax = div.append_axes('right', size="5%", pad = 0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + ax.set_title(r'$\log_{10}~J$') + + ax = axes[1,1] + lxi = np.log10(dfile.GetXi()) + for b in range(nblocks): + im = ax.pcolormesh(xplot[b,:,:], yplot[b,:,:], lxi[b,0,:,:].transpose(), vmin=-3, vmax=0, + cmap=cmap_uniform) + div = make_axes_locatable(ax) + cax = div.append_axes('right', size="5%", pad = 0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + ax.set_title(r'$\log_{10}~\xi$') + + ax = axes[1,2] + Pg = dfile.GetPg() + Pr = dfile.GetPr() + lbetar = np.log10(Pg/Pr) + for b in range(nblocks): + im = ax.pcolormesh(xplot[b,:,:], yplot[b,:,:], lbetar[b,0,:,:].transpose(), vmin=-2, vmax=2, + cmap=cmap_diverging) + div = make_axes_locatable(ax) + cax = div.append_axes('right', size="5%", pad = 0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + ax.set_title(r'$\log_{10}~\beta_{\rm R}$') + + ax = axes[1,3] + ltau = np.log10(dfile.GetTau()) + for b in range(nblocks): + im = ax.pcolormesh(xplot[b,:,:], yplot[b,:,:], ltau[b,0,:,:].transpose(), vmin=-3, vmax=3, + cmap=cmap_diverging) + div = make_axes_locatable(ax) + cax = div.append_axes('right', size="5%", pad = 0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + ax.set_title(r'$\log_{10}~\tau_{\rm zone}$') + + else: + ax = axes[1,0] + lenergy = np.log10(np.clip(dfile.Get("p.energy", flatten=False), 1.e-20, None)) + for b in range(nblocks): + im = ax.pcolormesh(xplot[b,:,:], yplot[b,:,:], lenergy[b,0,:,:].transpose(), vmin=-5, vmax=0, + cmap=cmap_uniform) + div = make_axes_locatable(ax) + cax = div.append_axes('right', size="5%", pad = 0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + ax.set_title(r'$\log_{10}~u$') + + ax = axes[1,1] + Pg = dfile.GetPg() + Pm = np.clip(dfile.GetPm(), 1.e-20, 1.e20) + lbeta = np.log10(Pg/Pm) + for b in range(nblocks): + im = ax.pcolormesh(xplot[b,:,:], yplot[b,:,:], lbeta[b,0,:,:].transpose(), vmin=-2, vmax=2, + cmap=cmap_diverging) + div = make_axes_locatable(ax) + cax = div.append_axes('right', size="5%", pad = 0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + ax.set_title(r'$\log_{10}~\beta_{\rm M}$') + + for nrow, tmp_ax in enumerate(axes): + for ncol, ax in enumerate(tmp_ax): + if coords == "cartesian": + ax.set_xlim([xlim, rlim]) + ax.set_ylim([-rlim, rlim]) + ax.set_aspect('equal') + if ncol > 0: + ax.yaxis.set_ticklabels([]) + + + plt.suptitle("Time = %g M" % dfile.Time) + + fig.tight_layout() + + savename = str(ifname).rjust(5,"0") + '.png' + plt.savefig(savename, dpi=300, bbox_inches='tight') + plt.close(fig) + +if __name__ == "__main__": + + parser = argparse.ArgumentParser(description='Plot neutrino thermalization') + parser.add_argument('-gf', '--geometry_file', dest='geometry_file', default=None, help='Optional dump file containing the time-independent (no AMR) geometry data') + parser.add_argument('--savefig', type=bool, default=False, help='Whether to save figure') + parser.add_argument('--numin', type=float, default=1.e-4, help='Minimum frequency (Hz)') + parser.add_argument('--numax', type=float, default=1.e2, help='Maximum frequency (Hz)') + parser.add_argument('--nnu', type=int, default=100, help='Number of frequency support points') + parser.add_argument('--coords', type=str, default="cartesian", help='Coordinates to plot in') + parser.add_argument('files', type=str, nargs='+', + help='Files to take a snapshot of') + args = parser.parse_args() + + matplotlib.use('Agg') + + for i, fname in enumerate(args.files): + plot_frame(i, fname, args.savefig, coords=args.coords) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bc6fdc59..dd913e42 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -15,8 +15,11 @@ add_executable(phoebus main.cpp # first # alphabetical - fixup/fixup.cpp fixup/fixup.hpp + fixup/fixup.cpp + fixup/fixup_c2p.cpp + fixup/fixup_radc2p.cpp + fixup/fixup_src.cpp fluid/con2prim.hpp fluid/con2prim_robust.hpp @@ -122,6 +125,7 @@ add_executable(phoebus radiation/cooling_function.cpp radiation/mocmc.cpp radiation/moments.cpp + radiation/moments_source.cpp radiation/monte_carlo.cpp radiation/geodesics.hpp diff --git a/src/fixup/fixup.cpp b/src/fixup/fixup.cpp index 0d6a1123..6be71430 100644 --- a/src/fixup/fixup.cpp +++ b/src/fixup/fixup.cpp @@ -1,5 +1,5 @@ -// © 2021. Triad National Security, LLC. All rights reserved. This -// program was produced under U.S. Government contract +// © 2021-2022. Triad National Security, LLC. All rights reserved. +// This program was produced under U.S. Government contract // 89233218CNA000001 for Los Alamos National Laboratory (LANL), which // is operated by Triad National Security, LLC for the U.S. // Department of Energy/National Nuclear Security Administration. All @@ -20,15 +20,26 @@ #include #include "fluid/con2prim_robust.hpp" +#include "fluid/fluid.hpp" #include "fluid/prim2con.hpp" #include "geometry/geometry.hpp" +#include "phoebus_utils/programming_utils.hpp" #include "phoebus_utils/relativity_utils.hpp" #include "phoebus_utils/robust.hpp" #include "phoebus_utils/variables.hpp" - +#include "radiation/closure.hpp" +#include "radiation/closure_m1.hpp" +#include "radiation/closure_mocmc.hpp" +#include "radiation/radiation.hpp" + +using radiation::ClosureEquation; +using radiation::ClosureSettings; +using radiation::ClosureVerbosity; +using radiation::Tens2; +using radiation::Vec; using robust::ratio; - -#define FIXUP_PRINT_TOTAL_NFAIL 0 +using singularity::RadiationType; +using singularity::neutrinos::Opacity; namespace fixup { @@ -36,20 +47,49 @@ std::shared_ptr Initialize(ParameterInput *pin) { auto fix = std::make_shared("fixup"); Params ¶ms = fix->AllParams(); + const bool enable_mhd = pin->GetOrAddBoolean("fluid", "mhd", false); + const bool enable_rad = pin->GetOrAddBoolean("physics", "rad", false); + bool enable_flux_fixup = pin->GetOrAddBoolean("fixup", "enable_flux_fixup", false); params.Add("enable_flux_fixup", enable_flux_fixup); + bool enable_ox1_fmks_inflow_check = + pin->GetOrAddBoolean("fixup", "enable_ox1_fmks_inflow_check", false); + params.Add("enable_ox1_fmks_inflow_check", enable_ox1_fmks_inflow_check); bool enable_fixup = pin->GetOrAddBoolean("fixup", "enable_fixup", false); params.Add("enable_fixup", enable_fixup); bool enable_floors = pin->GetOrAddBoolean("fixup", "enable_floors", false); bool enable_c2p_fixup = pin->GetOrAddBoolean("fixup", "enable_c2p_fixup", false); params.Add("enable_c2p_fixup", enable_c2p_fixup); + bool enable_source_fixup = pin->GetOrAddBoolean("fixup", "enable_source_fixup", false); + params.Add("enable_source_fixup", enable_source_fixup); bool enable_ceilings = pin->GetOrAddBoolean("fixup", "enable_ceilings", false); params.Add("enable_ceilings", enable_ceilings); bool report_c2p_fails = pin->GetOrAddBoolean("fixup", "report_c2p_fails", false); params.Add("report_c2p_fails", report_c2p_fails); + bool report_source_fails = pin->GetOrAddBoolean("fixup", "report_source_fails", false); + params.Add("report_source_fails", report_source_fails); bool enable_mhd_floors = pin->GetOrAddBoolean("fixup", "enable_mhd_floors", false); + bool enable_rad_floors = pin->GetOrAddBoolean("fixup", "enable_rad_floors", false); + bool enable_rad_ceilings = pin->GetOrAddBoolean("fixup", "enable_rad_ceilings", false); + + if (enable_mhd_floors && !enable_mhd) { + enable_mhd_floors = false; + PARTHENON_WARN("WARNING Disabling MHD floors because MHD is disabled!"); + } params.Add("enable_mhd_floors", enable_mhd_floors); + if (enable_rad_floors && !enable_rad) { + enable_rad_floors = false; + PARTHENON_WARN("WARNING Disabling radiation floors because radiation is disabled!"); + } + params.Add("enable_rad_floors", enable_rad_floors); + + if (enable_rad_ceilings && !enable_rad) { + enable_rad_ceilings = false; + PARTHENON_WARN("WARNING Disabling radiation ceilings because radiation is disabled!"); + } + params.Add("enable_rad_ceilings", enable_rad_ceilings); + if (enable_c2p_fixup && !enable_floors) { enable_floors = true; PARTHENON_WARN( @@ -60,6 +100,11 @@ std::shared_ptr Initialize(ParameterInput *pin) { PARTHENON_WARN( "WARNING Forcing enable_floors to \"true\" because enable_mhd_floors = true"); } + if (enable_rad_floors && !enable_floors) { + enable_floors = true; + PARTHENON_WARN( + "WARNING Forcing enable_floors to \"true\" because enable_rad_floors = true"); + } params.Add("enable_floors", enable_floors); if (enable_floors) { @@ -113,38 +158,131 @@ std::shared_ptr Initialize(ParameterInput *pin) { params.Add("ceiling", Ceilings()); } + if (enable_rad_floors) { + const std::string floor_type = pin->GetString("fixup", "rad_floor_type"); + if (floor_type == "ConstantJ") { + Real J0 = pin->GetOrAddReal("fixup", "J0_floor", 0.0); + params.Add("rad_floor", RadiationFloors(constant_j_floor_tag, J0)); + } else if (floor_type == "ExpX1J") { + Real J0 = pin->GetOrAddReal("fixup", "J0_floor", 0.0); + Real Jp = pin->GetOrAddReal("fixup", "J_exp_floor", -2.0); + params.Add("rad_floor", RadiationFloors(exp_x1_j_floor_tag, J0, Jp)); + } else { + PARTHENON_FAIL("invalid /rad_floor_type input"); + } + } else { + params.Add("rad_floor", RadiationFloors()); + } + + if (enable_rad_ceilings) { + const std::string radiation_ceiling_type = + pin->GetOrAddString("fixup", "radiation_ceiling_type", "ConstantXi0"); + if (radiation_ceiling_type == "ConstantXi0") { + Real xi0 = pin->GetOrAddReal("fixup", "xi0_ceiling", 0.99); + params.Add("rad_ceiling", + RadiationCeilings(constant_xi0_radiation_ceiling_tag, xi0)); + } + } else { + params.Add("rad_ceiling", RadiationCeilings()); + } + if (enable_mhd_floors) { - Real bsqorho_max = pin->GetOrAddReal("fixup", "bsqorho_max", 50.); - Real bsqou_max = pin->GetOrAddReal("fixup", "bsqou_max", 2500.); - Real uorho_max = pin->GetOrAddReal("fixup", "uorho_max", 50.); - params.Add("bsqorho_max", bsqorho_max); - params.Add("bsqou_max", bsqou_max); - params.Add("uorho_max", uorho_max); + const std::string mhd_ceiling_type = + pin->GetOrAddString("fixup", "mhd_ceiling_type", "ConstantBsqRat"); + if (mhd_ceiling_type == "ConstantBsqRat") { + Real bsqorho0 = pin->GetOrAddReal("fixup", "bsqorho0_ceiling", 50.); + Real bsqou0 = pin->GetOrAddReal("fixup", "bsqou0_ceiling", 2500.); + params.Add("mhd_ceiling", + MHDCeilings(constant_bsq_rat_ceiling_tag, bsqorho0, bsqou0)); + } else { + PARTHENON_FAIL("invalid /mhd_ceiling_type input"); + } + } else { + params.Add("mhd_ceiling", MHDCeilings()); } + FAILURE_STRATEGY fluid_c2p_failure_strategy; + std::string fluid_c2p_failure_strategy_str = + pin->GetOrAddString("fixup", "fluid_c2p_failure_strategy", "interpolate"); + if (fluid_c2p_failure_strategy_str == "interpolate") { + fluid_c2p_failure_strategy = FAILURE_STRATEGY::interpolate; + } else if (fluid_c2p_failure_strategy_str == "floors") { + fluid_c2p_failure_strategy = FAILURE_STRATEGY::floors; + } else { + PARTHENON_FAIL("fixup/fluid_c2p_failure_strategy not supported!"); + } + params.Add("fluid_c2p_failure_strategy", fluid_c2p_failure_strategy); + + FAILURE_STRATEGY rad_c2p_failure_strategy; + std::string rad_c2p_failure_strategy_str = + pin->GetOrAddString("fixup", "rad_c2p_failure_strategy", "interpolate"); + if (rad_c2p_failure_strategy_str == "interpolate") { + rad_c2p_failure_strategy = FAILURE_STRATEGY::interpolate; + } else if (rad_c2p_failure_strategy_str == "floors") { + rad_c2p_failure_strategy = FAILURE_STRATEGY::floors; + } else { + PARTHENON_FAIL("fixup/rad_c2p_failure_strategy not supported!"); + } + params.Add("rad_c2p_failure_strategy", rad_c2p_failure_strategy); + + FAILURE_STRATEGY src_failure_strategy; + std::string src_failure_strategy_str = + pin->GetOrAddString("fixup", "src_failure_strategy", "interpolate"); + if (src_failure_strategy_str == "interpolate") { + src_failure_strategy = FAILURE_STRATEGY::interpolate; + } else if (src_failure_strategy_str == "floors") { + src_failure_strategy = FAILURE_STRATEGY::floors; + } else { + PARTHENON_FAIL("fixup/src_c2p_failure_strategy not supported!"); + } + params.Add("src_failure_strategy", src_failure_strategy); + + const bool c2p_failure_force_fixup_both = + pin->GetOrAddBoolean("fixup", "c2p_failure_force_fixup_both", true); + params.Add("c2p_failure_force_fixup_both", c2p_failure_force_fixup_both); + params.Add("bounds", - Bounds(params.Get("floor"), params.Get("ceiling"))); + Bounds(params.Get("floor"), params.Get("ceiling"), + params.Get("mhd_ceiling"), + params.Get("rad_floor"), + params.Get("rad_ceiling"))); return fix; } -template -TaskStatus ApplyFloors(T *rc) { +/// Given a valid state (including consistency between prim and cons variables), +/// this function returns another valid state that is within the bounds of specified +/// floors and ceilings. +template +TaskStatus ApplyFloorsImpl(T *rc, IndexDomain domain = IndexDomain::entire) { namespace p = fluid_prim; namespace c = fluid_cons; + namespace pr = radmoment_prim; + namespace cr = radmoment_cons; + namespace ir = radmoment_internal; namespace impl = internal_variables; auto *pmb = rc->GetParentPointer().get(); - IndexRange ib = pmb->cellbounds.GetBoundsI(IndexDomain::entire); - IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::entire); - IndexRange kb = pmb->cellbounds.GetBoundsK(IndexDomain::entire); + IndexRange ib = pmb->cellbounds.GetBoundsI(domain); + IndexRange jb = pmb->cellbounds.GetBoundsJ(domain); + IndexRange kb = pmb->cellbounds.GetBoundsK(domain); StateDescriptor *fix_pkg = pmb->packages.Get("fixup").get(); StateDescriptor *eos_pkg = pmb->packages.Get("eos").get(); + StateDescriptor *fluid_pkg = pmb->packages.Get("fluid").get(); + StateDescriptor *rad_pkg = pmb->packages.Get("radiation").get(); + + bool rad_active = rad_pkg->Param("active"); + + bool enable_floors = fix_pkg->Param("enable_floors"); + bool enable_mhd_floors = fix_pkg->Param("enable_mhd_floors"); + bool enable_rad_floors = fix_pkg->Param("enable_rad_floors"); - const std::vector vars({p::density, c::density, p::velocity, c::momentum, - p::energy, c::energy, p::bfield, p::ye, c::ye, - p::pressure, p::temperature, p::gamma1, - impl::cell_signal_speed, impl::fail}); + if (!enable_floors) return TaskStatus::complete; + + const std::vector vars( + {p::density, c::density, p::velocity, c::momentum, p::energy, c::energy, p::bfield, + p::ye, c::ye, p::pressure, p::temperature, p::gamma1, pr::J, pr::H, cr::E, cr::F, + impl::cell_signal_speed, impl::fail, ir::tilPi}); PackIndexMap imap; auto v = rc->PackVariables(vars, imap); @@ -166,22 +304,28 @@ TaskStatus ApplyFloors(T *rc) { const int pb_hi = imap[p::bfield].second; int pye = imap[p::ye].second; // negative if not present int cye = imap[c::ye].second; + auto idx_J = imap.GetFlatIdx(pr::J, false); + auto idx_H = imap.GetFlatIdx(pr::H, false); + auto idx_E = imap.GetFlatIdx(cr::E, false); + auto idx_F = imap.GetFlatIdx(cr::F, false); + auto iTilPi = imap.GetFlatIdx(ir::tilPi, false); - bool enable_floors = fix_pkg->Param("enable_floors"); - if (!enable_floors) return TaskStatus::complete; - bool enable_mhd_floors = fix_pkg->Param("enable_mhd_floors"); + const int num_species = enable_rad_floors ? rad_pkg->Param("num_species") : 0; auto eos = eos_pkg->Param("d.EOS"); auto geom = Geometry::GetCoordinateSystem(rc); auto bounds = fix_pkg->Param("bounds"); + const Real c2p_tol = fluid_pkg->Param("c2p_tol"); + const int c2p_max_iter = fluid_pkg->Param("c2p_max_iter"); + const Real c2p_floor_scale_fac = fluid_pkg->Param("c2p_floor_scale_fac"); + const bool c2p_fail_on_floors = fluid_pkg->Param("c2p_fail_on_floors"); + const bool c2p_fail_on_ceilings = fluid_pkg->Param("c2p_fail_on_ceilings"); + auto invert = con2prim_robust::ConToPrimSetup(rc, bounds, c2p_tol, c2p_max_iter, + c2p_floor_scale_fac, c2p_fail_on_floors, + c2p_fail_on_ceilings); + Coordinates_t coords = rc->GetParentPointer().get()->coords; - Real bsqorho_max, bsqou_max, uorho_max; - if (enable_mhd_floors) { - bsqorho_max = fix_pkg->Param("bsqorho_max"); - bsqou_max = fix_pkg->Param("bsqou_max"); - uorho_max = fix_pkg->Param("uorho_max"); - } parthenon::par_for( DEFAULT_LOOP_PATTERN, "ApplyFloors", DevExecSpace(), 0, v.GetDim(5) - 1, kb.s, kb.e, @@ -195,20 +339,33 @@ TaskStatus ApplyFloors(T *rc) { double rho_floor, sie_floor; bounds.GetFloors(coords.x1v(k, j, i), coords.x2v(k, j, i), coords.x3v(k, j, i), rho_floor, sie_floor); + double gamma_max, e_max; + bounds.GetCeilings(coords.x1v(k, j, i), coords.x2v(k, j, i), coords.x3v(k, j, i), + gamma_max, e_max); + Real bsqorho_max, bsqou_max; + bounds.GetMHDCeilings(coords.x1v(k, j, i), coords.x2v(k, j, i), + coords.x3v(k, j, i), bsqorho_max, bsqou_max); + Real J_floor; + bounds.GetRadiationFloors(coords.x1v(k, j, i), coords.x2v(k, j, i), + coords.x3v(k, j, i), J_floor); + Real xi_max; + bounds.GetRadiationCeilings(coords.x1v(k, j, i), coords.x2v(k, j, i), + coords.x3v(k, j, i), xi_max); + + Real rho_floor_max = rho_floor; + Real u_floor_max = rho_floor * sie_floor; bool floor_applied = false; - if (v(b, prho, k, j, i) < rho_floor) { - floor_applied = true; - v(b, prho, k, j, i) = rho_floor; - } - if (v(b, peng, k, j, i) / v(b, prho, k, j, i) < sie_floor) { - floor_applied = true; - v(b, peng, k, j, i) = sie_floor * v(b, prho, k, j, i); - } + bool ceiling_applied = false; Real gcov[4][4]; geom.SpacetimeMetric(CellLocation::Cent, k, j, i, gcov); + Real gammacon[3][3]; + geom.MetricInverse(CellLocation::Cent, k, j, i, gammacon); const Real alpha = geom.Lapse(CellLocation::Cent, k, j, i); + Real betacon[3]; + geom.ContravariantShift(CellLocation::Cent, k, j, i, betacon); + const Real sdetgam = geom.DetGamma(CellLocation::Cent, b, k, j, i); if (enable_mhd_floors) { Real Bsq = 0.0; @@ -226,239 +383,259 @@ TaskStatus ApplyFloors(T *rc) { Real bcon0 = W * Bdotv / alpha; const Real bsq = (Bsq + alpha * alpha * bcon0 * bcon0) * iW * iW; - if (bsq / v(b, prho, k, j, i) > bsqorho_max) { - floor_applied = true; - v(b, prho, k, j, i) = bsq / bsqorho_max; - } - if (bsq / v(b, peng, k, j, i) > bsqou_max) { - floor_applied = true; - v(b, peng, k, j, i) = bsq / bsqou_max; - } - if (v(b, peng, k, j, i) / v(b, prho, k, j, i) > uorho_max) { - floor_applied = true; - v(b, peng, k, j, i) = uorho_max * v(b, prho, k, j, i); - } - } + rho_floor_max = std::max(rho_floor_max, bsq / bsqorho_max); + u_floor_max = std::max(u_floor_max, bsq / bsqou_max); - if (floor_applied) { - // Update dependent primitives - if (pye > 0) eos_lambda[0] = v(b, pye, k, j, i); - v(b, tmp, k, j, i) = eos.TemperatureFromDensityInternalEnergy( - v(b, prho, k, j, i), v(b, peng, k, j, i) / v(b, prho, k, j, i), eos_lambda); - v(b, prs, k, j, i) = eos.PressureFromDensityTemperature( - v(b, prho, k, j, i), v(b, tmp, k, j, i), eos_lambda); - v(b, gm1, k, j, i) = eos.BulkModulusFromDensityTemperature( - v(b, prho, k, j, i), v(b, tmp, k, j, i), eos_lambda) / - v(b, prs, k, j, i); - - // Update conserved variables - const Real gdet = geom.DetGamma(CellLocation::Cent, k, j, i); - Real gcon[3][3]; - geom.MetricInverse(CellLocation::Cent, k, j, i, gcon); - Real beta[3]; - geom.ContravariantShift(CellLocation::Cent, k, j, i, beta); - Real S[3]; - const Real vel[] = {v(b, pvel_lo, k, j, i), v(b, pvel_lo + 1, k, j, i), - v(b, pvel_hi, k, j, i)}; - Real bcons[3]; - Real bp[3] = {0.0, 0.0, 0.0}; - if (pb_hi > 0) { - bp[0] = v(b, pb_lo, k, j, i); - bp[1] = v(b, pb_lo + 1, k, j, i); - bp[2] = v(b, pb_hi, k, j, i); - } - Real ye_cons; - Real ye_prim = 0.0; - if (pye > 0) { - ye_prim = v(b, pye, k, j, i); - } - Real sig[3]; - prim2con::p2c(v(b, prho, k, j, i), vel, bp, v(b, peng, k, j, i), ye_prim, - v(b, prs, k, j, i), v(b, gm1, k, j, i), gcov, gcon, beta, alpha, - gdet, v(b, crho, k, j, i), S, bcons, v(b, ceng, k, j, i), ye_cons, - sig); - v(b, cmom_lo, k, j, i) = S[0]; - v(b, cmom_lo + 1, k, j, i) = S[1]; - v(b, cmom_hi, k, j, i) = S[2]; - if (pye > 0) v(b, cye, k, j, i) = ye_cons; - for (int m = slo; m <= shi; m++) { - v(b, m, k, j, i) = sig[m - slo]; - } + rho_floor_max = std::max( + rho_floor_max, std::max(v(b, peng, k, j, i), u_floor_max) / e_max); } - }); - - return TaskStatus::complete; -} - -template -TaskStatus ConservedToPrimitiveFixup(T *rc) { - namespace p = fluid_prim; - namespace c = fluid_cons; - namespace impl = internal_variables; - auto *pmb = rc->GetParentPointer().get(); - IndexRange ib = pmb->cellbounds.GetBoundsI(IndexDomain::interior); - IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::interior); - IndexRange kb = pmb->cellbounds.GetBoundsK(IndexDomain::interior); - - StateDescriptor *fix_pkg = pmb->packages.Get("fixup").get(); - StateDescriptor *eos_pkg = pmb->packages.Get("eos").get(); - const std::vector vars({p::density, c::density, p::velocity, c::momentum, - p::energy, c::energy, p::bfield, p::ye, c::ye, - p::pressure, p::temperature, p::gamma1, - impl::cell_signal_speed, impl::fail}); + Real drho = rho_floor_max - v(b, prho, k, j, i); + Real du = u_floor_max - v(b, peng, k, j, i); + if (drho > 0. || du > 0.) { + floor_applied = true; + drho = std::max(drho, du / sie_floor); + du = std::max(du, sie_floor * drho); + } - PackIndexMap imap; - auto v = rc->PackVariables(vars, imap); + Real dcrho, dS[3], dBcons[3], dtau, dyecons; + Real bp[3] = {0}; + if (pb_hi > 0) { + SPACELOOP(ii) { bp[ii] = v(b, pb_lo + ii, k, j, i); } + } - const int prho = imap[p::density].first; - const int crho = imap[c::density].first; - const int pvel_lo = imap[p::velocity].first; - const int pvel_hi = imap[p::velocity].second; - const int cmom_lo = imap[c::momentum].first; - const int cmom_hi = imap[c::momentum].second; - const int peng = imap[p::energy].first; - const int ceng = imap[c::energy].first; - const int prs = imap[p::pressure].first; - const int tmp = imap[p::temperature].first; - const int gm1 = imap[p::gamma1].first; - const int slo = imap[impl::cell_signal_speed].first; - const int shi = imap[impl::cell_signal_speed].second; - const int pb_lo = imap[p::bfield].first; - const int pb_hi = imap[p::bfield].second; - int pye = imap[p::ye].second; // negative if not present - int cye = imap[c::ye].second; - int ifail = imap[impl::fail].first; - - bool report_c2p_fails = fix_pkg->Param("report_c2p_fails"); - if (report_c2p_fails) { - int nfail_total; - parthenon::par_reduce( - parthenon::loop_pattern_mdrange_tag, "ConToPrim::Solve fixup failures", - DevExecSpace(), 0, v.GetDim(5) - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, - KOKKOS_LAMBDA(const int b, const int k, const int j, const int i, int &nf) { - if (v(b, ifail, k, j, i) == con2prim_robust::FailFlags::fail) { - nf++; + if (floor_applied) { + Real vp_normalobs[3] = {0}; // Inject floors at rest in normal observer frame + Real ye_prim_default = 0.5; + eos_lambda[0] = ye_prim_default; + Real dprs = + eos.PressureFromDensityInternalEnergy(drho, ratio(du, drho), eos_lambda); + Real dgm1 = ratio( + eos.BulkModulusFromDensityInternalEnergy(drho, ratio(du, drho), eos_lambda), + dprs); + prim2con::p2c(drho, vp_normalobs, bp, du, ye_prim_default, dprs, dgm1, gcov, + gammacon, betacon, alpha, sdetgam, dcrho, dS, dBcons, dtau, + dyecons); + + // Update cons vars (not B field) + v(b, crho, k, j, i) += dcrho; + SPACELOOP(ii) { v(b, cmom_lo + ii, k, j, i) += dS[ii]; } + v(b, ceng, k, j, i) += dtau; + if (pye > 0) { + v(b, cye, k, j, i) += dyecons; } - }, - Kokkos::Sum(nfail_total)); - printf("total nfail: %i\n", nfail_total); - } - - bool enable_c2p_fixup = fix_pkg->Param("enable_c2p_fixup"); - if (!enable_c2p_fixup) return TaskStatus::complete; - - const int ndim = pmb->pmy_mesh->ndim; - - auto eos = eos_pkg->Param("d.EOS"); - auto geom = Geometry::GetCoordinateSystem(rc); - auto bounds = fix_pkg->Param("bounds"); - - Coordinates_t coords = rc->GetParentPointer().get()->coords; - parthenon::par_for( - DEFAULT_LOOP_PATTERN, "ConToPrim::Solve fixup", DevExecSpace(), 0, v.GetDim(5) - 1, - kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, - KOKKOS_LAMBDA(const int b, const int k, const int j, const int i) { - Real eos_lambda[2]; // use last temp as initial guess - eos_lambda[0] = 0.5; - eos_lambda[1] = std::log10(v(b, tmp, k, j, i)); - - auto fixup = [&](const int iv, const Real inv_mask_sum) { - v(b, iv, k, j, i) = v(b, ifail, k, j, i - 1) * v(b, iv, k, j, i - 1) + - v(b, ifail, k, j, i + 1) * v(b, iv, k, j, i + 1); - if (ndim > 1) { - v(b, iv, k, j, i) += v(b, ifail, k, j - 1, i) * v(b, iv, k, j - 1, i) + - v(b, ifail, k, j + 1, i) * v(b, iv, k, j + 1, i); - if (ndim == 3) { - v(b, iv, k, j, i) += v(b, ifail, k - 1, j, i) * v(b, iv, k - 1, j, i) + - v(b, ifail, k + 1, j, i) * v(b, iv, k + 1, j, i); - } - } - return inv_mask_sum * v(b, iv, k, j, i); - }; - if (v(b, ifail, k, j, i) == con2prim_robust::FailFlags::fail) { - Real num_valid = v(b, ifail, k, j, i - 1) + v(b, ifail, k, j, i + 1); - if (ndim > 1) num_valid += v(b, ifail, k, j - 1, i) + v(b, ifail, k, j + 1, i); - if (ndim == 3) num_valid += v(b, ifail, k - 1, j, i) + v(b, ifail, k + 1, j, i); - if (num_valid > 0.5) { - const Real norm = 1.0 / num_valid; - v(b, prho, k, j, i) = fixup(prho, norm); - for (int pv = pvel_lo; pv <= pvel_hi; pv++) { - v(b, pv, k, j, i) = fixup(pv, norm); + // fluid c2p + auto status = invert(geom, eos, coords, k, j, i); + if (status == con2prim_robust::ConToPrimStatus::failure) { + // If fluid c2p fails, set to floors + v(b, prho, k, j, i) = drho; + SPACELOOP(ii) { v(b, pvel_lo + ii, k, j, i) = vp_normalobs[ii]; } + v(b, peng, k, j, i) = du; + if (pye > 0) { + v(b, pye, k, j, i) = ye_prim_default; } - v(b, peng, k, j, i) = fixup(peng, norm); - if (pye > 0) v(b, pye, k, j, i) = fixup(pye, norm); - if (pye > 0) eos_lambda[0] = v(b, pye, k, j, i); + // Update auxiliary primitives + if (pye > 0) { + eos_lambda[0] = v(b, pye, k, j, i); + } v(b, tmp, k, j, i) = eos.TemperatureFromDensityInternalEnergy( - v(b, prho, k, j, i), ratio(v(b, peng, k, j, i), v(b, prho, k, j, i)), - eos_lambda); - v(b, prs, k, j, i) = eos.PressureFromDensityTemperature( - v(b, prho, k, j, i), v(b, tmp, k, j, i), eos_lambda); - v(b, gm1, k, j, i) = eos.BulkModulusFromDensityTemperature( - v(b, prho, k, j, i), ratio(v(b, tmp, k, j, i), v(b, prs, k, j, i)), + v(b, prho, k, j, i), v(b, peng, k, j, i) / v(b, prho, k, j, i), eos_lambda); - } else { - // No valid neighbors; set fluid mass/energy to near-zero and set primitive - // velocities to zero - v(b, prho, k, j, i) = 1.e-20; - v(b, peng, k, j, i) = 1.e-20; - - // Safe value for ye + // Update cons vars (not B field) + prim2con::p2c(drho, vp_normalobs, bp, du, ye_prim_default, dprs, dgm1, gcov, + gammacon, betacon, alpha, sdetgam, v(b, crho, k, j, i), dS, + dBcons, v(b, ceng, k, j, i), dyecons); + SPACELOOP(ii) { v(b, cmom_lo + ii, k, j, i) = dS[ii]; } if (pye > 0) { - v(b, pye, k, j, i) = 0.5; + v(b, cye, k, j, i) = dyecons; } + } + } - if (pye > 0) eos_lambda[0] = v(b, pye, k, j, i); - v(b, tmp, k, j, i) = eos.TemperatureFromDensityInternalEnergy( - v(b, prho, k, j, i), ratio(v(b, peng, k, j, i), v(b, prho, k, j, i)), - eos_lambda); - v(b, prs, k, j, i) = eos.PressureFromDensityTemperature( - v(b, prho, k, j, i), v(b, tmp, k, j, i), eos_lambda); - v(b, gm1, k, j, i) = eos.BulkModulusFromDensityTemperature( - v(b, prho, k, j, i), ratio(v(b, tmp, k, j, i), v(b, prs, k, j, i)), - eos_lambda); + // Fluid ceilings? + Real vpcon[3] = {v(b, pvel_lo, k, j, i), v(b, pvel_lo + 1, k, j, i), + v(b, pvel_lo + 2, k, j, i)}; + const Real W = phoebus::GetLorentzFactor(vpcon, gcov); + if (W > gamma_max || v(b, peng, k, j, i) / v(b, prho, k, j, i) > e_max) { + ceiling_applied = true; + } - // Zero primitive velocities - SPACELOOP(ii) { v(b, pvel_lo + ii, k, j, i) = 0.; } - } - // Update conserved variables - const Real gdet = geom.DetGamma(CellLocation::Cent, k, j, i); - const Real alpha = geom.Lapse(CellLocation::Cent, k, j, i); - Real beta[3]; - geom.ContravariantShift(CellLocation::Cent, k, j, i, beta); - Real gcov[4][4]; - geom.SpacetimeMetric(CellLocation::Cent, k, j, i, gcov); - Real gcon[3][3]; - geom.MetricInverse(CellLocation::Cent, k, j, i, gcon); - Real S[3]; - const Real vel[] = {v(b, pvel_lo, k, j, i), v(b, pvel_lo + 1, k, j, i), - v(b, pvel_hi, k, j, i)}; - Real bcons[3]; - Real bp[3] = {0.0, 0.0, 0.0}; - if (pb_hi > 0) { - bp[0] = v(b, pb_lo, k, j, i); - bp[1] = v(b, pb_lo + 1, k, j, i); - bp[2] = v(b, pb_hi, k, j, i); + if (ceiling_applied) { + const Real rescale = std::sqrt(gamma_max * gamma_max - 1.) / (W * W - 1.); + SPACELOOP(ii) { vpcon[ii] *= rescale; } + SPACELOOP(ii) { v(b, pvel_lo + ii, k, j, i) = vpcon[ii]; } + + Real ye = 0.; + if (pye > 0) { + ye = v(b, pye, k, j, i); } - Real ye_cons; - Real ye_prim = 0.0; + prim2con::p2c(v(b, prho, k, j, i), vpcon, bp, v(b, peng, k, j, i), ye, + v(b, prs, k, j, i), v(b, gm1, k, j, i), gcov, gammacon, betacon, + alpha, sdetgam, v(b, crho, k, j, i), dS, dBcons, + v(b, ceng, k, j, i), dyecons); + SPACELOOP(ii) { v(b, cmom_lo + ii, k, j, i) = dS[ii]; } if (pye > 0) { - ye_prim = v(b, pye, k, j, i); + v(b, cye, k, j, i) = dyecons; } - Real sig[3]; - prim2con::p2c(v(b, prho, k, j, i), vel, bp, v(b, peng, k, j, i), ye_prim, - v(b, prs, k, j, i), v(b, gm1, k, j, i), gcov, gcon, beta, alpha, - gdet, v(b, crho, k, j, i), S, bcons, v(b, ceng, k, j, i), ye_cons, - sig); - v(b, cmom_lo, k, j, i) = S[0]; - v(b, cmom_lo + 1, k, j, i) = S[1]; - v(b, cmom_hi, k, j, i) = S[2]; - if (pye > 0) v(b, cye, k, j, i) = ye_cons; - for (int m = slo; m <= shi; m++) { - v(b, m, k, j, i) = sig[m - slo]; + } + + if (floor_applied || ceiling_applied) { + // Update derived prims + if (pye > 0) eos_lambda[0] = v(b, pye, k, j, i); + v(b, tmp, k, j, i) = eos.TemperatureFromDensityInternalEnergy( + v(b, prho, k, j, i), ratio(v(b, peng, k, j, i), v(b, prho, k, j, i)), + eos_lambda); + v(b, prs, k, j, i) = eos.PressureFromDensityTemperature( + v(b, prho, k, j, i), v(b, tmp, k, j, i), eos_lambda); + v(b, gm1, k, j, i) = + ratio(eos.BulkModulusFromDensityTemperature(v(b, prho, k, j, i), + v(b, tmp, k, j, i), eos_lambda), + v(b, prs, k, j, i)); + } + + if (rad_active) { + Vec con_vp{v(b, pvel_lo, k, j, i), v(b, pvel_lo + 1, k, j, i), + v(b, pvel_lo + 2, k, j, i)}; + const Real W = phoebus::GetLorentzFactor(con_vp.data, gcov); + Vec con_v{v(b, pvel_lo, k, j, i) / W, v(b, pvel_lo + 1, k, j, i) / W, + v(b, pvel_lo + 2, k, j, i) / W}; + typename CLOSURE::LocalGeometryType g(geom, CellLocation::Cent, b, k, j, i); + Real E; + Real J; + Vec cov_H; + Vec cov_F; + Tens2 con_TilPi; + CLOSURE c(con_v, &g); + + // If we applied fluid floors or ceilings we modified v^i, so we need to call + // rad c2p here before we can use radiation primitive variables + if (floor_applied || ceiling_applied) { + // rad c2p + + for (int ispec = 0; ispec < num_species; ++ispec) { + E = v(b, idx_E(ispec), k, j, i) / sdetgam; + SPACELOOP(ii) { cov_F(ii) = v(b, idx_F(ispec, ii), k, j, i) / sdetgam; } + + // We need the real conTilPi + if (iTilPi.IsValid()) { + SPACELOOP2(ii, jj) { + con_TilPi(ii, jj) = v(b, iTilPi(ispec, ii, jj), k, j, i); + } + } else { + // TODO(BRR) don't be lazy and actually retrieve these + Real xi = 0.; + Real phi = acos(-1.0) * 1.000001; + c.GetConTilPiFromCon(E, cov_F, xi, phi, &con_TilPi); + } + + c.Con2Prim(E, cov_F, con_TilPi, &J, &cov_H); + v(b, idx_J(ispec), k, j, i) = J; + SPACELOOP(ii) { v(b, idx_H(ispec, ii), k, j, i) = cov_H(ii) / J; } + } + } + + // TODO(BRR) use Bounds class + Vec con_v_normalobs{0}; + CLOSURE c_iso(con_v_normalobs, &g); + Tens2 con_tilPi_iso{0}; + for (int ispec = 0; ispec < num_species; ++ispec) { + Real dJ = J_floor - v(b, idx_J(ispec), k, j, i); + if (dJ > 0.) { + + constexpr bool update_cons_vars = true; // false; + // Update cons vars, c2p + if (update_cons_vars) { + J = dJ; + SPACELOOP(ii) { + cov_H(ii) = 0.; // No flux H^i = 0 (note H^0 = 0 so H_i = 0) + } + PARTHENON_DEBUG_REQUIRE(!std::isnan(J), "bad"); + PARTHENON_DEBUG_REQUIRE(!std::isnan(cov_H(0)), "bad"); + PARTHENON_DEBUG_REQUIRE(!std::isnan(cov_H(1)), "bad"); + PARTHENON_DEBUG_REQUIRE(!std::isnan(cov_H(2)), "bad"); + c_iso.Prim2Con(J, cov_H, con_tilPi_iso, &E, &cov_F); + + E += v(b, idx_E(ispec), k, j, i) / sdetgam; + SPACELOOP(ii) { cov_F(ii) += v(b, idx_F(ispec, ii), k, j, i) / sdetgam; } + + v(b, idx_E(ispec), k, j, i) = E * sdetgam; + SPACELOOP(ii) { v(b, idx_F(ispec, ii), k, j, i) = cov_F(ii) * sdetgam; } + + // We need the real conTilPi + if (iTilPi.IsValid()) { + SPACELOOP2(ii, jj) { + con_TilPi(ii, jj) = v(b, iTilPi(ispec, ii, jj), k, j, i); + } + } else { + // TODO(BRR) don't be lazy and actually retrieve these + Real xi = 0.; + Real phi = acos(-1.0) * 1.000001; + c.GetConTilPiFromCon(E, cov_F, xi, phi, &con_TilPi); + } + + c.Con2Prim(E, cov_F, con_TilPi, &J, &cov_H); + + v(b, idx_J(ispec), k, j, i) = J; + SPACELOOP(ii) { v(b, idx_H(ispec, ii), k, j, i) = cov_H(ii) / J; } + } else { + v(b, idx_J(ispec), k, j, i) += dJ; + + J = v(b, idx_J(ispec), k, j, i); + SPACELOOP(ii) { cov_H(ii) = v(b, idx_H(ispec, ii), k, j, i) * J; } + + // We need the real conTilPi + if (iTilPi.IsValid()) { + SPACELOOP2(ii, jj) { + con_TilPi(ii, jj) = v(b, iTilPi(ispec, ii, jj), k, j, i); + } + } else { + c.GetConTilPiFromPrim(J, cov_H, &con_TilPi); + } + + PARTHENON_DEBUG_REQUIRE(!std::isnan(J), "bad"); + PARTHENON_DEBUG_REQUIRE(!std::isnan(cov_H(0)), "bad"); + PARTHENON_DEBUG_REQUIRE(!std::isnan(cov_H(1)), "bad"); + PARTHENON_DEBUG_REQUIRE(!std::isnan(cov_H(2)), "bad"); + + c.Prim2Con(J, cov_H, con_TilPi, &E, &cov_F); + v(b, idx_E(ispec), k, j, i) = E * sdetgam; + SPACELOOP(ii) { v(b, idx_F(ispec, ii), k, j, i) = cov_F(ii) * sdetgam; } + } + } + + Vec cov_H{v(b, idx_H(ispec, 0), k, j, i), v(b, idx_H(ispec, 1), k, j, i), + v(b, idx_H(ispec, 2), k, j, i)}; + const Real xi = + std::sqrt(g.contractCov3Vectors(cov_H, cov_H) - + std::pow(g.contractConCov3Vectors(con_v, cov_H), 2)); + + if (xi > xi_max) { + + J = v(b, idx_J(ispec), k, j, i); + SPACELOOP(ii) { + cov_H(ii) = (xi_max / xi) * v(b, idx_H(ispec, ii), k, j, i) * J; + v(b, idx_H(ispec, ii), k, j, i) = cov_H(ii) / J; + } + + // We need the real conTilPi + if (iTilPi.IsValid()) { + SPACELOOP2(ii, jj) { + con_TilPi(ii, jj) = v(b, iTilPi(ispec, ii, jj), k, j, i); + } + } else { + c.GetConTilPiFromPrim(J, cov_H, &con_TilPi); + } + PARTHENON_DEBUG_REQUIRE(!std::isnan(J), "bad"); + PARTHENON_DEBUG_REQUIRE(!std::isnan(cov_H(0)), "bad"); + PARTHENON_DEBUG_REQUIRE(!std::isnan(cov_H(1)), "bad"); + PARTHENON_DEBUG_REQUIRE(!std::isnan(cov_H(2)), "bad"); + c.Prim2Con(J, cov_H, con_TilPi, &E, &cov_F); + v(b, idx_E(ispec), k, j, i) = E * sdetgam; + SPACELOOP(ii) { v(b, idx_F(ispec, ii), k, j, i) = cov_F(ii) * sdetgam; } + } } } }); @@ -466,12 +643,44 @@ TaskStatus ConservedToPrimitiveFixup(T *rc) { return TaskStatus::complete; } +template +TaskStatus ApplyFloors(T *rc) { + auto *pm = rc->GetParentPointer().get(); + StateDescriptor *rad_pkg = pm->packages.Get("radiation").get(); + StateDescriptor *fix_pkg = pm->packages.Get("fixup").get(); + const bool enable_rad_floors = fix_pkg->Param("enable_rad_floors"); + std::string method; + if (enable_rad_floors) { + method = rad_pkg->Param("method"); + } + + // TODO(BRR) share these settings somewhere else. Set at configure time? + using settings = + ClosureSettings; + if (method == "moment_m1") { + return ApplyFloorsImpl>(rc); + } else if (method == "moment_eddington") { + return ApplyFloorsImpl>(rc); + } else if (method == "mocmc") { + return ApplyFloorsImpl>(rc); + } else { + // TODO(BRR) default to Eddington closure, check that rad floors are unused for + // Monte Carlo/cooling function + PARTHENON_REQUIRE(!enable_rad_floors, + "Rad floors not supported with cooling function/Monte Carlo!"); + return ApplyFloorsImpl>(rc); + } + return TaskStatus::fail; +} + +template TaskStatus ApplyFloors>(MeshBlockData *rc); + TaskStatus FixFluxes(MeshBlockData *rc) { using parthenon::BoundaryFace; using parthenon::BoundaryFlag; auto *pmb = rc->GetParentPointer().get(); - if (!pmb->packages.Get("fixup")->Param("enable_flux_fixup")) - return TaskStatus::complete; + auto &fixup_pkg = pmb->packages.Get("fixup"); + if (!fixup_pkg->Param("enable_flux_fixup")) return TaskStatus::complete; auto fluid = pmb->packages.Get("fluid"); const std::string ix1_bc = fluid->Param("ix1_bc"); @@ -479,6 +688,12 @@ TaskStatus FixFluxes(MeshBlockData *rc) { const std::string ix2_bc = fluid->Param("ix2_bc"); const std::string ox2_bc = fluid->Param("ox2_bc"); + auto rad = pmb->packages.Get("radiation"); + int num_species = 0; + if (rad->Param("active")) { + num_species = rad->Param("num_species"); + } + IndexRange ib = pmb->cellbounds.GetBoundsI(IndexDomain::interior); IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::interior); IndexRange kb = pmb->cellbounds.GetBoundsK(IndexDomain::interior); @@ -487,49 +702,70 @@ TaskStatus FixFluxes(MeshBlockData *rc) { namespace p = fluid_prim; namespace c = fluid_cons; + namespace cr = radmoment_cons; // x1-direction if (pmb->boundary_flag[BoundaryFace::inner_x1] == BoundaryFlag::user) { if (ix1_bc == "outflow") { - auto flux = - rc->PackVariablesAndFluxes(std::vector({fluid_cons::density}), - std::vector({fluid_cons::density})); + PackIndexMap imap; + auto v = rc->PackVariablesAndFluxes(std::vector({c::density}), + std::vector({c::density}), imap); + const auto crho = imap[c::density].first; parthenon::par_for( DEFAULT_LOOP_PATTERN, "FixFluxes::x1", DevExecSpace(), kb.s, kb.e, jb.s, jb.e, ib.s, ib.s, KOKKOS_LAMBDA(const int k, const int j, const int i) { - flux.flux(X1DIR, 0, k, j, i) = std::min(flux.flux(X1DIR, 0, k, j, i), 0.0); + v.flux(X1DIR, crho, k, j, i) = std::min(v.flux(X1DIR, crho, k, j, i), 0.0); }); } else if (ix1_bc == "reflect") { - auto flux = rc->PackVariablesAndFluxes( - std::vector({fluid_cons::density, fluid_cons::energy}), - std::vector({fluid_cons::density, fluid_cons::energy})); + PackIndexMap imap; + auto v = rc->PackVariablesAndFluxes( + std::vector({c::density, c::energy, cr::E}), + std::vector({c::density, c::energy, cr::E}), imap); + const auto crho = imap[c::density].first; + const auto cener = imap[c::energy].first; + auto idx_E = imap.GetFlatIdx(cr::E, false); parthenon::par_for( DEFAULT_LOOP_PATTERN, "FixFluxes::x1", DevExecSpace(), kb.s, kb.e, jb.s, jb.e, ib.s, ib.s, KOKKOS_LAMBDA(const int k, const int j, const int i) { - flux.flux(X1DIR, 0, k, j, i) = 0.0; - flux.flux(X1DIR, 1, k, j, i) = 0.0; + v.flux(X1DIR, crho, k, j, i) = 0.0; + v.flux(X1DIR, cener, k, j, i) = 0.0; + if (idx_E.IsValid()) { + for (int ispec = 0; ispec < num_species; ispec++) { + v.flux(X1DIR, idx_E(ispec), k, j, i) = 0.0; + } + } }); } } if (pmb->boundary_flag[BoundaryFace::outer_x1] == BoundaryFlag::user) { if (ox1_bc == "outflow") { - auto flux = - rc->PackVariablesAndFluxes(std::vector({fluid_cons::density}), - std::vector({fluid_cons::density})); + PackIndexMap imap; + auto v = rc->PackVariablesAndFluxes(std::vector({c::density}), + std::vector({c::density}), imap); + const auto crho = imap[c::density].first; parthenon::par_for( DEFAULT_LOOP_PATTERN, "FixFluxes::x1", DevExecSpace(), kb.s, kb.e, jb.s, jb.e, ib.e + 1, ib.e + 1, KOKKOS_LAMBDA(const int k, const int j, const int i) { - flux.flux(X1DIR, 0, k, j, i) = std::max(flux.flux(X1DIR, 0, k, j, i), 0.0); + v.flux(X1DIR, crho, k, j, i) = std::max(v.flux(X1DIR, crho, k, j, i), 0.0); }); } else if (ox1_bc == "reflect") { - auto flux = rc->PackVariablesAndFluxes( - std::vector({fluid_cons::density, fluid_cons::energy}), - std::vector({fluid_cons::density, fluid_cons::energy})); + PackIndexMap imap; + auto v = rc->PackVariablesAndFluxes( + std::vector({c::density, c::energy, cr::E}), + std::vector({c::density, c::energy, cr::E}), imap); + const auto crho = imap[c::density].first; + const auto cener = imap[c::energy].first; + auto idx_E = imap.GetFlatIdx(cr::E, false); parthenon::par_for( DEFAULT_LOOP_PATTERN, "FixFluxes::x1", DevExecSpace(), kb.s, kb.e, jb.s, jb.e, ib.e + 1, ib.e + 1, KOKKOS_LAMBDA(const int k, const int j, const int i) { - flux.flux(X1DIR, 0, k, j, i) = 0.0; - flux.flux(X1DIR, 1, k, j, i) = 0.0; + v.flux(X1DIR, crho, k, j, i) = 0.0; + v.flux(X1DIR, cener, k, j, i) = 0.0; + if (idx_E.IsValid()) { + for (int ispec = 0; ispec < num_species; ispec++) { + v.flux(X1DIR, idx_E(ispec), k, j, i) = 0.0; + } + } }); } } @@ -538,61 +774,78 @@ TaskStatus FixFluxes(MeshBlockData *rc) { // x2-direction if (pmb->boundary_flag[BoundaryFace::inner_x2] == BoundaryFlag::user) { if (ix2_bc == "outflow") { - auto flux = - rc->PackVariablesAndFluxes(std::vector({fluid_cons::density}), - std::vector({fluid_cons::density})); + PackIndexMap imap; + auto v = rc->PackVariablesAndFluxes(std::vector({c::density}), + std::vector({c::density}), imap); + const auto crho = imap[c::density].first; parthenon::par_for( DEFAULT_LOOP_PATTERN, "FixFluxes::x2", DevExecSpace(), kb.s, kb.e, jb.s, jb.s, ib.s, ib.e, KOKKOS_LAMBDA(const int k, const int j, const int i) { - flux.flux(X2DIR, 0, k, j, i) = std::min(flux.flux(X2DIR, 0, k, j, i), 0.0); + v.flux(X2DIR, crho, k, j, i) = std::min(v.flux(X2DIR, crho, k, j, i), 0.0); }); } else if (ix2_bc == "reflect") { PackIndexMap imap; - auto flux = rc->PackVariablesAndFluxes( - std::vector( - {fluid_cons::density, fluid_cons::energy, fluid_cons::momentum}), - std::vector( - {fluid_cons::density, fluid_cons::energy, fluid_cons::momentum}), + auto v = rc->PackVariablesAndFluxes( + std::vector({c::density, c::energy, c::momentum, cr::E, cr::F}), + std::vector({c::density, c::energy, c::momentum, cr::E, cr::F}), imap); - const int cmom_lo = imap[c::momentum].first; - const int cmom_hi = imap[c::momentum].second; + const auto crho = imap[c::density].first; + const auto cener = imap[c::energy].first; + auto idx_cmom = imap.GetFlatIdx(c::momentum); + auto idx_E = imap.GetFlatIdx(cr::E, false); + auto idx_F = imap.GetFlatIdx(cr::F, false); parthenon::par_for( DEFAULT_LOOP_PATTERN, "FixFluxes::x2", DevExecSpace(), kb.s, kb.e, jb.s, jb.s, ib.s, ib.e, KOKKOS_LAMBDA(const int k, const int j, const int i) { - flux.flux(X2DIR, 0, k, j, i) = 0.0; - flux.flux(X2DIR, 1, k, j, i) = 0.0; - flux.flux(X2DIR, cmom_lo, k, j, i) = 0.0; - flux.flux(X2DIR, cmom_lo + 2, k, j, i) = 0.0; + v.flux(X2DIR, crho, k, j, i) = 0.0; + v.flux(X2DIR, cener, k, j, i) = 0.0; + v.flux(X2DIR, idx_cmom(0), k, j, i) = 0.0; + v.flux(X2DIR, idx_cmom(2), k, j, i) = 0.0; + for (int ispec = 0; ispec < num_species; ispec++) { + v.flux(X2DIR, idx_E(ispec), k, j, i) = 0.0; + v.flux(X2DIR, idx_F(ispec, 0), k, j, i) = 0.0; + v.flux(X2DIR, idx_F(ispec, 2), k, j, i) = 0.0; + } }); } } if (pmb->boundary_flag[BoundaryFace::outer_x2] == BoundaryFlag::user) { if (ox2_bc == "outflow") { - auto flux = - rc->PackVariablesAndFluxes(std::vector({fluid_cons::density}), - std::vector({fluid_cons::density})); + PackIndexMap imap; + auto v = rc->PackVariablesAndFluxes(std::vector({c::density}), + std::vector({c::density}), imap); + const auto crho = imap[c::density].first; + parthenon::par_for( DEFAULT_LOOP_PATTERN, "FixFluxes::x2", DevExecSpace(), kb.s, kb.e, jb.e + 1, jb.e + 1, ib.s, ib.e, KOKKOS_LAMBDA(const int k, const int j, const int i) { - flux.flux(X2DIR, 0, k, j, i) = std::max(flux.flux(X2DIR, 0, k, j, i), 0.0); + v.flux(X2DIR, crho, k, j, i) = std::max(v.flux(X2DIR, crho, k, j, i), 0.0); }); } else if (ox2_bc == "reflect") { PackIndexMap imap; - auto flux = rc->PackVariablesAndFluxes( - std::vector( - {fluid_cons::density, fluid_cons::energy, fluid_cons::momentum}), - std::vector( - {fluid_cons::density, fluid_cons::energy, fluid_cons::momentum}), + auto v = rc->PackVariablesAndFluxes( + std::vector({c::density, c::energy, c::momentum, cr::E, cr::F}), + std::vector({c::density, c::energy, c::momentum, cr::E, cr::F}), imap); - const int cmom_lo = imap[c::momentum].first; - const int cmom_hi = imap[c::momentum].second; + const auto crho = imap[c::density].first; + const auto cener = imap[c::energy].first; + auto idx_cmom = imap.GetFlatIdx(c::momentum); + auto idx_E = imap.GetFlatIdx(cr::E, false); + auto idx_F = imap.GetFlatIdx(cr::F, false); parthenon::par_for( DEFAULT_LOOP_PATTERN, "FixFluxes::x2", DevExecSpace(), kb.s, kb.e, jb.e + 1, jb.e + 1, ib.s, ib.e, KOKKOS_LAMBDA(const int k, const int j, const int i) { - flux.flux(X2DIR, 0, k, j, i) = 0.0; - flux.flux(X2DIR, 1, k, j, i) = 0.0; - flux.flux(X2DIR, cmom_lo, k, j, i) = 0.0; - flux.flux(X2DIR, cmom_lo + 2, k, j, i) = 0.0; + v.flux(X2DIR, crho, k, j, i) = 0.0; + v.flux(X2DIR, cener, k, j, i) = 0.0; + v.flux(X2DIR, idx_cmom(0), k, j, i) = 0.0; + v.flux(X2DIR, idx_cmom(2), k, j, i) = 0.0; + if (idx_E.IsValid()) { + for (int ispec = 0; ispec < num_species; ispec++) { + v.flux(X2DIR, idx_E(ispec), k, j, i) = 0.0; + v.flux(X2DIR, idx_F(ispec, 0), k, j, i) = 0.0; + v.flux(X2DIR, idx_F(ispec, 2), k, j, i) = 0.0; + } + } }); } } @@ -601,52 +854,67 @@ TaskStatus FixFluxes(MeshBlockData *rc) { // x3-direction if (pmb->boundary_flag[BoundaryFace::inner_x3] == BoundaryFlag::outflow) { - auto flux = - rc->PackVariablesAndFluxes(std::vector({fluid_cons::density}), - std::vector({fluid_cons::density})); + PackIndexMap imap; + auto v = rc->PackVariablesAndFluxes(std::vector({c::density}), + std::vector({c::density}), imap); + const auto crho = imap[c::density].first; parthenon::par_for( DEFAULT_LOOP_PATTERN, "FixFluxes::x3", DevExecSpace(), kb.s, kb.s, jb.s, jb.e, ib.s, ib.e, KOKKOS_LAMBDA(const int k, const int j, const int i) { - flux.flux(X3DIR, 0, k, j, i) = std::min(flux.flux(X3DIR, 0, k, j, i), 0.0); + v.flux(X3DIR, crho, k, j, i) = std::min(v.flux(X3DIR, crho, k, j, i), 0.0); }); } else if (pmb->boundary_flag[BoundaryFace::inner_x3] == BoundaryFlag::reflect) { - auto flux = rc->PackVariablesAndFluxes( - std::vector({fluid_cons::density, fluid_cons::energy}), - std::vector({fluid_cons::density, fluid_cons::energy})); + PackIndexMap imap; + auto v = rc->PackVariablesAndFluxes( + std::vector({c::density, c::energy, cr::E}), + std::vector({c::density, c::energy, cr::E}), imap); + const auto crho = imap[c::density].first; + const auto cener = imap[c::energy].first; + auto idx_E = imap.GetFlatIdx(cr::E, false); parthenon::par_for( DEFAULT_LOOP_PATTERN, "FixFluxes::x3", DevExecSpace(), kb.s, kb.s, jb.s, jb.e, ib.s, ib.e, KOKKOS_LAMBDA(const int k, const int j, const int i) { - flux.flux(X3DIR, 0, k, j, i) = 0.0; - flux.flux(X3DIR, 1, k, j, i) = 0.0; + v.flux(X3DIR, crho, k, j, i) = 0.0; + v.flux(X3DIR, cener, k, j, i) = 0.0; + if (idx_E.IsValid()) { + for (int ispec = 0; ispec < num_species; ispec++) { + v.flux(X3DIR, idx_E(ispec), k, j, i) = 0.; + } + } }); } if (pmb->boundary_flag[BoundaryFace::outer_x3] == BoundaryFlag::outflow) { - auto flux = - rc->PackVariablesAndFluxes(std::vector({fluid_cons::density}), - std::vector({fluid_cons::density})); + PackIndexMap imap; + auto v = rc->PackVariablesAndFluxes(std::vector({c::density}), + std::vector({c::density}), imap); + const auto crho = imap[c::density].first; parthenon::par_for( DEFAULT_LOOP_PATTERN, "FixFluxes::x3", DevExecSpace(), kb.e + 1, kb.e + 1, jb.s, jb.e, ib.s, ib.e, KOKKOS_LAMBDA(const int k, const int j, const int i) { - flux.flux(X3DIR, 0, k, j, i) = std::max(flux.flux(X3DIR, 0, k, j, i), 0.0); + v.flux(X3DIR, crho, k, j, i) = std::max(v.flux(X3DIR, crho, k, j, i), 0.0); }); } else if (pmb->boundary_flag[BoundaryFace::outer_x3] == BoundaryFlag::reflect) { - auto flux = rc->PackVariablesAndFluxes( - std::vector({fluid_cons::density, fluid_cons::energy}), - std::vector({fluid_cons::density, fluid_cons::energy})); + PackIndexMap imap; + auto v = rc->PackVariablesAndFluxes( + std::vector({c::density, c::energy, cr::E}), + std::vector({c::density, c::energy, cr::E}), imap); + const auto crho = imap[c::density].first; + const auto cener = imap[c::energy].first; + auto idx_E = imap.GetFlatIdx(cr::E, false); parthenon::par_for( DEFAULT_LOOP_PATTERN, "FixFluxes::x3", DevExecSpace(), kb.e + 1, kb.e + 1, jb.s, jb.e, ib.s, ib.e, KOKKOS_LAMBDA(const int k, const int j, const int i) { - flux.flux(X3DIR, 0, k, j, i) = 0.0; - flux.flux(X3DIR, 1, k, j, i) = 0.0; + v.flux(X3DIR, crho, k, j, i) = 0.0; + v.flux(X3DIR, cener, k, j, i) = 0.0; + if (idx_E.IsValid()) { + for (int ispec = 0; ispec < num_species; ispec++) { + v.flux(X3DIR, idx_E(ispec), k, j, i) = 0.; + } + } }); } return TaskStatus::complete; } -template TaskStatus ApplyFloors>(MeshBlockData *rc); - -template TaskStatus -ConservedToPrimitiveFixup>(MeshBlockData *rc); - } // namespace fixup diff --git a/src/fixup/fixup.hpp b/src/fixup/fixup.hpp index c4099e9c..6cc4cb87 100644 --- a/src/fixup/fixup.hpp +++ b/src/fixup/fixup.hpp @@ -1,5 +1,5 @@ -// © 2021. Triad National Security, LLC. All rights reserved. This -// program was produced under U.S. Government contract +// © 2021-2022. Triad National Security, LLC. All rights reserved. +// This program was produced under U.S. Government contract // 89233218CNA000001 for Los Alamos National Laboratory (LANL), which // is operated by Triad National Security, LLC for the U.S. // Department of Energy/National Nuclear Security Administration. All @@ -23,12 +23,21 @@ using namespace parthenon::package::prelude; namespace fixup { +enum class FAILURE_STRATEGY { + interpolate, // Average involved primitive variables over good neighbors + floors // Set involved primitive variables to floors +}; + std::shared_ptr Initialize(ParameterInput *pin); TaskStatus FixFluxes(MeshBlockData *rc); template TaskStatus ApplyFloors(T *rc); template +TaskStatus RadConservedToPrimitiveFixup(T *rc); +template TaskStatus ConservedToPrimitiveFixup(T *rc); +template +TaskStatus SourceFixup(T *rc); static struct ConstantRhoSieFloor { } constant_rho_sie_floor_tag; @@ -98,6 +107,41 @@ class Floors { const FloorFlag floor_flag_; }; +static struct ConstantJFloor { +} constant_j_floor_tag; +static struct ExpX1JFloor { +} exp_x1_j_floor_tag; + +enum class RadiationFloorFlag { ConstantJ, ExpX1J }; + +class RadiationFloors { + public: + RadiationFloors() + : RadiationFloors(constant_j_floor_tag, -std::numeric_limits::max()) {} + RadiationFloors(ConstantJFloor, const Real J0) + : J0_(J0), floor_flag_(RadiationFloorFlag::ConstantJ) {} + RadiationFloors(ExpX1JFloor, const Real J0, const Real Jp) + : J0_(J0), Jalpha_(Jp), floor_flag_(RadiationFloorFlag::ExpX1J) {} + + KOKKOS_INLINE_FUNCTION + void GetRadiationFloors(const Real x1, const Real x2, const Real x3, Real &Jflr) const { + switch (floor_flag_) { + case RadiationFloorFlag::ConstantJ: + Jflr = J0_; + break; + case RadiationFloorFlag::ExpX1J: + Jflr = J0_ * std::exp(Jalpha_ * x1); + break; + default: + PARTHENON_FAIL("No valid radiation floor set."); + } + } + + private: + Real J0_, Jalpha_; + const RadiationFloorFlag floor_flag_; +}; + static struct ConstantGamSieCeiling { } constant_gam_sie_ceiling_tag; @@ -127,12 +171,78 @@ class Ceilings { const int ceiling_flag_; }; +static struct ConstantBsqRatCeiling { +} constant_bsq_rat_ceiling_tag; + +class MHDCeilings { + public: + MHDCeilings() + : MHDCeilings(constant_bsq_rat_ceiling_tag, std::numeric_limits::max(), + std::numeric_limits::max()) {} + MHDCeilings(ConstantBsqRatCeiling, const Real bsqorho0, const Real bsqou0) + : bsqorho0_(bsqorho0), bsqou0_(bsqou0), mhd_ceiling_flag_(1) {} + + KOKKOS_INLINE_FUNCTION + void GetMHDCeilings(const Real x1, const Real x2, const Real x3, Real &bsqorho, + Real &bsqou) const { + switch (mhd_ceiling_flag_) { + case 1: + bsqorho = bsqorho0_; + bsqou = bsqou0_; + break; + default: + PARTHENON_FAIL("No valid MHD ceiling set."); + } + } + + private: + Real bsqorho0_, bsqou0_; + const int mhd_ceiling_flag_; +}; + +static struct ConstantXi0RadiationCeiling { +} constant_xi0_radiation_ceiling_tag; + +class RadiationCeilings { + public: + RadiationCeilings() + : RadiationCeilings(constant_xi0_radiation_ceiling_tag, + std::numeric_limits::max()) {} + RadiationCeilings(ConstantXi0RadiationCeiling, const Real xi0) + : xi0_(xi0), radiation_ceiling_flag_(1) {} + + KOKKOS_INLINE_FUNCTION + void GetRadiationCeilings(const Real x1, const Real x2, const Real x3, + Real &ximax) const { + switch (radiation_ceiling_flag_) { + case 1: + ximax = xi0_; + break; + default: + PARTHENON_FAIL("No valid radiation ceiling set."); + } + } + + private: + Real xi0_; + const int radiation_ceiling_flag_; +}; + class Bounds { public: - Bounds() : floors_(Floors()), ceilings_(Ceilings()) {} - Bounds(const Floors &fl, const Ceilings &cl) : floors_(fl), ceilings_(cl) {} - explicit Bounds(const Floors &fl) : floors_(fl), ceilings_(Ceilings()) {} - explicit Bounds(const Ceilings &cl) : floors_(Floors()), ceilings_(cl) {} + Bounds() + : floors_(Floors()), ceilings_(Ceilings()), mhd_ceilings_(MHDCeilings()), + radiation_floors_(RadiationFloors()), radiation_ceilings_(RadiationCeilings()) {} + Bounds(const Floors &fl, const Ceilings &cl, const MHDCeilings &mcl, + const RadiationFloors &rfl, const RadiationCeilings &rcl) + : floors_(fl), ceilings_(cl), mhd_ceilings_(mcl), radiation_floors_(rfl), + radiation_ceilings_(rcl) {} + explicit Bounds(const Floors &fl) + : floors_(fl), ceilings_(Ceilings()), mhd_ceilings_(MHDCeilings()), + radiation_floors_(RadiationFloors()), radiation_ceilings_(RadiationCeilings()) {} + explicit Bounds(const Ceilings &cl) + : floors_(Floors()), ceilings_(cl), mhd_ceilings_(MHDCeilings()), + radiation_floors_(RadiationFloors()), radiation_ceilings_(RadiationCeilings()) {} template KOKKOS_INLINE_FUNCTION void GetFloors(Args &&...args) const { @@ -144,9 +254,27 @@ class Bounds { ceilings_.GetCeilings(std::forward(args)...); } + template + KOKKOS_INLINE_FUNCTION void GetMHDCeilings(Args &&...args) const { + mhd_ceilings_.GetMHDCeilings(std::forward(args)...); + } + + template + KOKKOS_INLINE_FUNCTION void GetRadiationFloors(Args &&...args) const { + radiation_floors_.GetRadiationFloors(std::forward(args)...); + } + + template + KOKKOS_INLINE_FUNCTION void GetRadiationCeilings(Args &&...args) const { + radiation_ceilings_.GetRadiationCeilings(std::forward(args)...); + } + private: const Floors floors_; const Ceilings ceilings_; + const MHDCeilings mhd_ceilings_; + const RadiationFloors radiation_floors_; + const RadiationCeilings radiation_ceilings_; }; } // namespace fixup diff --git a/src/fixup/fixup_c2p.cpp b/src/fixup/fixup_c2p.cpp new file mode 100644 index 00000000..2e94e4ec --- /dev/null +++ b/src/fixup/fixup_c2p.cpp @@ -0,0 +1,388 @@ +// © 2022. Triad National Security, LLC. All rights reserved. +// This program was produced under U.S. Government contract +// 89233218CNA000001 for Los Alamos National Laboratory (LANL), which +// is operated by Triad National Security, LLC for the U.S. +// Department of Energy/National Nuclear Security Administration. All +// rights in the program are reserved by Triad National Security, LLC, +// and the U.S. Department of Energy/National Nuclear Security +// Administration. The Government is granted for itself and others +// acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +// license in this material to reproduce, prepare derivative works, +// distribute copies to the public, perform publicly and display +// publicly, and to permit others to do so. + +#include + +#include "fixup.hpp" + +#include +#include +#include + +#include "fluid/con2prim_robust.hpp" +#include "fluid/prim2con.hpp" +#include "geometry/geometry.hpp" +#include "geometry/tetrads.hpp" +#include "phoebus_utils/programming_utils.hpp" +#include "phoebus_utils/relativity_utils.hpp" +#include "phoebus_utils/robust.hpp" +#include "phoebus_utils/variables.hpp" +#include "radiation/closure.hpp" +#include "radiation/closure_m1.hpp" +#include "radiation/closure_mocmc.hpp" +#include "radiation/radiation.hpp" + +using radiation::ClosureEquation; +using radiation::ClosureSettings; +using radiation::ClosureVerbosity; +using radiation::Tens2; +using radiation::Vec; +using robust::ratio; +using singularity::RadiationType; +using singularity::neutrinos::Opacity; + +namespace fixup { + +template +TaskStatus ConservedToPrimitiveFixupImpl(T *rc) { + namespace p = fluid_prim; + namespace c = fluid_cons; + namespace impl = internal_variables; + namespace ir = radmoment_internal; + namespace pr = radmoment_prim; + namespace cr = radmoment_cons; + auto *pmb = rc->GetParentPointer().get(); + IndexRange ib = pmb->cellbounds.GetBoundsI(IndexDomain::interior); + IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::interior); + IndexRange kb = pmb->cellbounds.GetBoundsK(IndexDomain::interior); + + StateDescriptor *fix_pkg = pmb->packages.Get("fixup").get(); + StateDescriptor *fluid_pkg = pmb->packages.Get("fluid").get(); + StateDescriptor *rad_pkg = pmb->packages.Get("radiation").get(); + StateDescriptor *eos_pkg = pmb->packages.Get("eos").get(); + + const std::vector vars({p::density, + c::density, + p::velocity, + c::momentum, + p::energy, + c::energy, + p::bfield, + p::ye, + c::ye, + p::pressure, + p::temperature, + p::gamma1, + impl::cell_signal_speed, + impl::fail, + ir::c2pfail, + ir::tilPi, + pr::J, + pr::H, + cr::E, + cr::F, + ir::xi, + ir::phi}); + + PackIndexMap imap; + auto v = rc->PackVariables(vars, imap); + + const int prho = imap[p::density].first; + const int crho = imap[c::density].first; + const int pvel_lo = imap[p::velocity].first; + const int pvel_hi = imap[p::velocity].second; + const int cmom_lo = imap[c::momentum].first; + const int cmom_hi = imap[c::momentum].second; + const int peng = imap[p::energy].first; + const int ceng = imap[c::energy].first; + const int prs = imap[p::pressure].first; + const int tmp = imap[p::temperature].first; + const int gm1 = imap[p::gamma1].first; + const int slo = imap[impl::cell_signal_speed].first; + const int shi = imap[impl::cell_signal_speed].second; + const int pb_lo = imap[p::bfield].first; + const int pb_hi = imap[p::bfield].second; + int pye = imap[p::ye].second; // negative if not present + int cye = imap[c::ye].second; + + int ifail = imap[impl::fail].first; + int irfail = imap[ir::c2pfail].first; + + auto idx_E = imap.GetFlatIdx(cr::E, false); + auto idx_F = imap.GetFlatIdx(cr::F, false); + auto idx_J = imap.GetFlatIdx(pr::J, false); + auto idx_H = imap.GetFlatIdx(pr::H, false); + auto iTilPi = imap.GetFlatIdx(ir::tilPi, false); + auto iXi = imap.GetFlatIdx(ir::xi, false); + auto iPhi = imap.GetFlatIdx(ir::phi, false); + + const bool rad_active = rad_pkg->Param("active"); + const int num_species = rad_active ? rad_pkg->Param("num_species") : 0; + + bool enable_c2p_fixup = fix_pkg->Param("enable_c2p_fixup"); + bool update_fluid = fluid_pkg->Param("active"); + if (!enable_c2p_fixup || !update_fluid) return TaskStatus::complete; + + bool report_c2p_fails = fix_pkg->Param("report_c2p_fails"); + if (report_c2p_fails) { + int nfail_total; + parthenon::par_reduce( + parthenon::loop_pattern_mdrange_tag, "ConToPrim::Solve fixup failures", + DevExecSpace(), 0, v.GetDim(5) - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + KOKKOS_LAMBDA(const int b, const int k, const int j, const int i, int &nf) { + if (v(b, ifail, k, j, i) == con2prim_robust::FailFlags::fail) { + nf++; + } + }, + Kokkos::Sum(nfail_total)); + printf("total nfail: %i\n", nfail_total); + IndexRange ibi = pmb->cellbounds.GetBoundsI(IndexDomain::interior); + IndexRange jbi = pmb->cellbounds.GetBoundsJ(IndexDomain::interior); + IndexRange kbi = pmb->cellbounds.GetBoundsK(IndexDomain::interior); + nfail_total = 0; + parthenon::par_reduce( + parthenon::loop_pattern_mdrange_tag, "Rad ConToPrim::Solve fixup failures", + DevExecSpace(), 0, v.GetDim(5) - 1, kbi.s, kbi.e, jbi.s, jbi.e, ibi.s, ibi.e, + KOKKOS_LAMBDA(const int b, const int k, const int j, const int i, int &nf) { + if (v(b, ifail, k, j, i) == con2prim_robust::FailFlags::fail) { + nf++; + } + }, + Kokkos::Sum(nfail_total)); + printf("total interior nfail: %i\n", nfail_total); + } + + const int ndim = pmb->pmy_mesh->ndim; + + auto eos = eos_pkg->Param("d.EOS"); + auto geom = Geometry::GetCoordinateSystem(rc); + auto bounds = fix_pkg->Param("bounds"); + + Coordinates_t coords = rc->GetParentPointer().get()->coords; + + auto fluid_c2p_failure_strategy = + fix_pkg->Param("fluid_c2p_failure_strategy"); + const auto c2p_failure_force_fixup_both = + fix_pkg->Param("c2p_failure_force_fixup_both"); + + PARTHENON_REQUIRE(!c2p_failure_force_fixup_both, + "As currently implemented this is a race condition!"); + + parthenon::par_for( + DEFAULT_LOOP_PATTERN, "ConToPrim::Solve fixup", DevExecSpace(), 0, v.GetDim(5) - 1, + kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + KOKKOS_LAMBDA(const int b, const int k, const int j, const int i) { + Real eos_lambda[2]; // use last temp as initial guess + eos_lambda[0] = 0.5; + eos_lambda[1] = std::log10(v(b, tmp, k, j, i)); + + Real gamma_max, e_max; + bounds.GetCeilings(coords.x1v(k, j, i), coords.x2v(k, j, i), coords.x3v(k, j, i), + gamma_max, e_max); + + if (c2p_failure_force_fixup_both && rad_active) { + if (v(b, ifail, k, j, i) == con2prim_robust::FailFlags::fail || + v(b, irfail, k, j, i) == radiation::FailFlags::fail) { + v(b, ifail, k, j, i) = con2prim_robust::FailFlags::fail; + v(b, irfail, k, j, i) = radiation::FailFlags::fail; + } + } + + // Need to account for not stenciling outside of ghost zones + // bool is_outer_ghost_layer = + // (i == ib.s || i == ib.e || j == jb.s || j == jb.e || k == kb.s || k == + // kb.e); + + auto fail = [&](const int k, const int j, const int i) { + if (c2p_failure_force_fixup_both) { + return v(b, ifail, k, j, i) * v(b, irfail, k, j, i); + } else { + return v(b, ifail, k, j, i); + } + }; + auto fixup = [&](const int iv, const Real inv_mask_sum) { + v(b, iv, k, j, i) = fail(k, j, i - 1) * v(b, iv, k, j, i - 1) + + fail(k, j, i + 1) * v(b, iv, k, j, i + 1); + if (ndim > 1) { + v(b, iv, k, j, i) += fail(k, j - 1, i) * v(b, iv, k, j - 1, i) + + fail(k, j + 1, i) * v(b, iv, k, j + 1, i); + if (ndim == 3) { + v(b, iv, k, j, i) += fail(k - 1, j, i) * v(b, iv, k - 1, j, i) + + fail(k + 1, j, i) * v(b, iv, k + 1, j, i); + } + } + return inv_mask_sum * v(b, iv, k, j, i); + }; + // When using IndexDomain::entire, can't stencil from e.g. i = 0 because 0 - 1 = + // -1 is a segfault + if (v(b, ifail, k, j, i) == con2prim_robust::FailFlags::fail) { + Real num_valid = 0; + num_valid = v(b, ifail, k, j, i - 1) + v(b, ifail, k, j, i + 1); + if (ndim > 1) num_valid += v(b, ifail, k, j - 1, i) + v(b, ifail, k, j + 1, i); + if (ndim == 3) num_valid += v(b, ifail, k - 1, j, i) + v(b, ifail, k + 1, j, i); + + // if (num_valid > 0.5 && + // fluid_c2p_failure_strategy == FAILURE_STRATEGY::interpolate && i > ib.s && + // i < ib.e - 1 && j > jb.s && j < jb.e - 1 && k > kb.s && k < kb.e - 1) { + if (num_valid > 0.5 && + fluid_c2p_failure_strategy == FAILURE_STRATEGY::interpolate) { + const Real norm = 1.0 / num_valid; + v(b, prho, k, j, i) = fixup(prho, norm); + for (int pv = pvel_lo; pv <= pvel_hi; pv++) { + v(b, pv, k, j, i) = fixup(pv, norm); + } + v(b, peng, k, j, i) = fixup(peng, norm); + + if (pye > 0) v(b, pye, k, j, i) = fixup(pye, norm); + + v(b, prho, k, j, i) = + std::max(v(b, prho, k, j, i), 100. * robust::SMALL()); + v(b, peng, k, j, i) = + std::max(v(b, peng, k, j, i), 100. * robust::SMALL()); + } else { + // No valid neighbors; set fluid mass/energy to near-zero and set primitive + // velocities to zero + + v(b, prho, k, j, i) = 100. * robust::SMALL(); + v(b, peng, k, j, i) = 100. * robust::SMALL(); + + // Safe value for ye + if (pye > 0) { + v(b, pye, k, j, i) = 0.5; + } + + // Zero primitive velocities + SPACELOOP(ii) { v(b, pvel_lo + ii, k, j, i) = 0.; } + } + + const Real sdetgam = geom.DetGamma(CellLocation::Cent, k, j, i); + const Real alpha = geom.Lapse(CellLocation::Cent, k, j, i); + Real beta[3]; + geom.ContravariantShift(CellLocation::Cent, k, j, i, beta); + Real gcov[4][4]; + geom.SpacetimeMetric(CellLocation::Cent, k, j, i, gcov); + Real gcon[3][3]; + geom.MetricInverse(CellLocation::Cent, k, j, i, gcon); + + // Clamp velocity now (for rad inversion) + Real vpcon[3] = {v(b, pvel_lo, k, j, i), v(b, pvel_lo + 1, k, j, i), + v(b, pvel_lo + 2, k, j, i)}; + Real W = phoebus::GetLorentzFactor(vpcon, gcov); + if (W > gamma_max) { + const Real rescale = std::sqrt(gamma_max * gamma_max - 1.) / (W * W - 1.); + SPACELOOP(ii) { vpcon[ii] *= rescale; } + SPACELOOP(ii) { v(b, pvel_lo + ii, k, j, i) = vpcon[ii]; } + W = gamma_max; + } + + // Update dependent primitives + if (pye > 0) eos_lambda[0] = v(b, pye, k, j, i); + v(b, tmp, k, j, i) = eos.TemperatureFromDensityInternalEnergy( + v(b, prho, k, j, i), ratio(v(b, peng, k, j, i), v(b, prho, k, j, i)), + eos_lambda); + v(b, prs, k, j, i) = eos.PressureFromDensityTemperature( + v(b, prho, k, j, i), v(b, tmp, k, j, i), eos_lambda); + v(b, gm1, k, j, i) = + ratio(eos.BulkModulusFromDensityTemperature(v(b, prho, k, j, i), + v(b, tmp, k, j, i), eos_lambda), + v(b, prs, k, j, i)); + + // Update conserved variables + + Real S[3]; + Real bcons[3]; + Real bp[3] = {0.0, 0.0, 0.0}; + if (pb_hi > 0) { + bp[0] = v(b, pb_lo, k, j, i); + bp[1] = v(b, pb_lo + 1, k, j, i); + bp[2] = v(b, pb_hi, k, j, i); + } + Real ye_cons; + Real ye_prim = 0.5; + if (pye > 0) { + ye_prim = v(b, pye, k, j, i); + } + Real sig[3]; + prim2con::p2c(v(b, prho, k, j, i), vpcon, bp, v(b, peng, k, j, i), ye_prim, + v(b, prs, k, j, i), v(b, gm1, k, j, i), gcov, gcon, beta, alpha, + sdetgam, v(b, crho, k, j, i), S, bcons, v(b, ceng, k, j, i), + ye_cons, sig); + v(b, cmom_lo, k, j, i) = S[0]; + v(b, cmom_lo + 1, k, j, i) = S[1]; + v(b, cmom_hi, k, j, i) = S[2]; + if (pye > 0) v(b, cye, k, j, i) = ye_cons; + for (int m = slo; m <= shi; m++) { + v(b, m, k, j, i) = sig[m - slo]; + } + + if (irfail >= 0) { + // If rad c2p failed, we'll fix that up subsequently + if (v(b, irfail, k, j, i) == radiation::FailFlags::success) { + for (int ispec = 0; ispec < num_species; ispec++) { + typename CLOSURE::LocalGeometryType g(geom, CellLocation::Cent, b, k, j, + i); + Vec con_v{vpcon[0] / W, vpcon[1] / W, vpcon[2] / W}; + CLOSURE c(con_v, &g); + + Real E = v(b, idx_E(ispec), k, j, i) / sdetgam; + Vec cov_F; + SPACELOOP(ii) { cov_F(ii) = v(b, idx_F(ispec, ii), k, j, i) / sdetgam; } + Tens2 con_tilPi; + Real J; + Vec cov_H; + if (iTilPi.IsValid()) { + SPACELOOP2(ii, jj) { + con_tilPi(ii, jj) = v(b, iTilPi(ispec, ii, jj), k, j, i); + } + } else { + Real xi = 0.; + Real phi = M_PI; + // TODO(BRR) STORE_GUESS + c.GetConTilPiFromCon(E, cov_F, xi, phi, &con_tilPi); + } + + c.Con2Prim(E, cov_F, con_tilPi, &J, &cov_H); + + v(b, idx_J(ispec), k, j, i) = J; + SPACELOOP(ii) { v(b, idx_H(ispec, ii), k, j, i) = cov_H(ii) / J; } + + // Floors and ceilings will be applied subsequently by ApplyFloors task + } + } + } + } + }); + + return TaskStatus::complete; +} + +template +TaskStatus ConservedToPrimitiveFixup(T *rc) { + auto *pm = rc->GetParentPointer().get(); + StateDescriptor *rad_pkg = pm->packages.Get("radiation").get(); + StateDescriptor *fix_pkg = pm->packages.Get("fixup").get(); + const bool enable_rad_floors = fix_pkg->Param("enable_rad_floors"); + std::string method; + if (enable_rad_floors) { + method = rad_pkg->Param("method"); + } + + // TODO(BRR) share these settings somewhere else. Set at configure time? + using settings = + ClosureSettings; + if (method == "moment_m1") { + return ConservedToPrimitiveFixupImpl>(rc); + } else if (method == "moment_eddington") { + return ConservedToPrimitiveFixupImpl>(rc); + } else if (method == "mocmc") { + return ConservedToPrimitiveFixupImpl>(rc); + } else { + return ConservedToPrimitiveFixupImpl>(rc); + } + return TaskStatus::fail; +} + +template TaskStatus +ConservedToPrimitiveFixup>(MeshBlockData *rc); + +} // namespace fixup diff --git a/src/fixup/fixup_radc2p.cpp b/src/fixup/fixup_radc2p.cpp new file mode 100644 index 00000000..9807fbd4 --- /dev/null +++ b/src/fixup/fixup_radc2p.cpp @@ -0,0 +1,254 @@ +// © 2021-2022. Triad National Security, LLC. All rights reserved. +// This program was produced under U.S. Government contract +// 89233218CNA000001 for Los Alamos National Laboratory (LANL), which +// is operated by Triad National Security, LLC for the U.S. +// Department of Energy/National Nuclear Security Administration. All +// rights in the program are reserved by Triad National Security, LLC, +// and the U.S. Department of Energy/National Nuclear Security +// Administration. The Government is granted for itself and others +// acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +// license in this material to reproduce, prepare derivative works, +// distribute copies to the public, perform publicly and display +// publicly, and to permit others to do so. + +#include + +#include "fixup.hpp" + +#include +#include +#include + +#include "fluid/con2prim_robust.hpp" +#include "fluid/prim2con.hpp" +#include "geometry/geometry.hpp" +#include "geometry/tetrads.hpp" +#include "phoebus_utils/programming_utils.hpp" +#include "phoebus_utils/relativity_utils.hpp" +#include "phoebus_utils/robust.hpp" +#include "phoebus_utils/variables.hpp" +#include "radiation/closure.hpp" +#include "radiation/closure_m1.hpp" +#include "radiation/closure_mocmc.hpp" +#include "radiation/radiation.hpp" + +using radiation::ClosureEquation; +using radiation::ClosureSettings; +using radiation::ClosureVerbosity; +using radiation::Tens2; +using radiation::Vec; +using robust::ratio; +using singularity::RadiationType; +using singularity::neutrinos::Opacity; + +namespace fixup { + +template +TaskStatus RadConservedToPrimitiveFixupImpl(T *rc) { + namespace p = fluid_prim; + namespace c = fluid_cons; + namespace impl = internal_variables; + namespace ir = radmoment_internal; + namespace pr = radmoment_prim; + namespace cr = radmoment_cons; + + auto *pmb = rc->GetParentPointer().get(); + IndexRange ib = pmb->cellbounds.GetBoundsI(IndexDomain::interior); + IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::interior); + IndexRange kb = pmb->cellbounds.GetBoundsK(IndexDomain::interior); + + StateDescriptor *fix_pkg = pmb->packages.Get("fixup").get(); + StateDescriptor *eos_pkg = pmb->packages.Get("eos").get(); + StateDescriptor *rad_pkg = pmb->packages.Get("radiation").get(); + + bool enable_c2p_fixup = fix_pkg->Param("enable_c2p_fixup"); + bool update_rad = rad_pkg->Param("active"); + if (!enable_c2p_fixup || !update_rad) return TaskStatus::complete; + + const std::vector vars({p::velocity, p::ye, c::ye, pr::J, pr::H, cr::E, + cr::F, ir::tilPi, ir::c2pfail, impl::fail}); + + PackIndexMap imap; + auto v = rc->PackVariables(vars, imap); + + auto idx_pvel = imap.GetFlatIdx(p::velocity); + int pye = imap[p::ye].second; // negative if not present + int cye = imap[c::ye].second; + auto idx_J = imap.GetFlatIdx(pr::J, false); + auto idx_H = imap.GetFlatIdx(pr::H, false); + auto idx_E = imap.GetFlatIdx(cr::E, false); + auto idx_F = imap.GetFlatIdx(cr::F, false); + int ifluidfail = imap[impl::fail].first; + int iradfail = imap[ir::c2pfail].first; + auto iTilPi = imap.GetFlatIdx(ir::tilPi, false); + + bool report_c2p_fails = fix_pkg->Param("report_c2p_fails"); + if (report_c2p_fails) { + int nfail_total; + parthenon::par_reduce( + parthenon::loop_pattern_mdrange_tag, "Rad ConToPrim::Solve fixup failures", + DevExecSpace(), 0, v.GetDim(5) - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + KOKKOS_LAMBDA(const int b, const int k, const int j, const int i, int &nf) { + if (v(b, iradfail, k, j, i) == radiation::FailFlags::fail) { + nf++; + } + }, + Kokkos::Sum(nfail_total)); + printf("total rad nfail: %i\n", nfail_total); + IndexRange ibi = pmb->cellbounds.GetBoundsI(IndexDomain::interior); + IndexRange jbi = pmb->cellbounds.GetBoundsJ(IndexDomain::interior); + IndexRange kbi = pmb->cellbounds.GetBoundsK(IndexDomain::interior); + nfail_total = 0; + parthenon::par_reduce( + parthenon::loop_pattern_mdrange_tag, "Rad ConToPrim::Solve fixup failures", + DevExecSpace(), 0, v.GetDim(5) - 1, kbi.s, kbi.e, jbi.s, jbi.e, ibi.s, ibi.e, + KOKKOS_LAMBDA(const int b, const int k, const int j, const int i, int &nf) { + if (v(b, iradfail, k, j, i) == radiation::FailFlags::fail) { + nf++; + } + }, + Kokkos::Sum(nfail_total)); + printf("total rad interior nfail: %i\n", nfail_total); + } + + auto geom = Geometry::GetCoordinateSystem(rc); + auto bounds = fix_pkg->Param("bounds"); + + Coordinates_t coords = rc->GetParentPointer().get()->coords; + + const int nspec = idx_E.DimSize(1); + const int ndim = pmb->pmy_mesh->ndim; + + auto rad_c2p_failure_strategy = + fix_pkg->Param("rad_c2p_failure_strategy"); + + parthenon::par_for( + DEFAULT_LOOP_PATTERN, "RadConToPrim::Solve fixup", DevExecSpace(), 0, + v.GetDim(5) - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + KOKKOS_LAMBDA(const int b, const int k, const int j, const int i) { + Real xi_max; + bounds.GetRadiationCeilings(coords.x1v(k, j, i), coords.x2v(k, j, i), + coords.x3v(k, j, i), xi_max); + + // It is assumed that the fluid is already fixed up + auto fail = [&](const int k, const int j, const int i) { + return v(b, iradfail, k, j, i); + }; + auto fixup = [&](const int iv, const Real inv_mask_sum) { + v(b, iv, k, j, i) = fail(k, j, i - 1) * v(b, iv, k, j, i - 1) + + fail(k, j, i + 1) * v(b, iv, k, j, i + 1); + if (ndim > 1) { + v(b, iv, k, j, i) += fail(k, j - 1, i) * v(b, iv, k, j - 1, i) + + fail(k, j + 1, i) * v(b, iv, k, j + 1, i); + if (ndim == 3) { + v(b, iv, k, j, i) += fail(k - 1, j, i) * v(b, iv, k - 1, j, i) + + fail(k + 1, j, i) * v(b, iv, k + 1, j, i); + } + } + return inv_mask_sum * v(b, iv, k, j, i); + }; + + if (v(b, iradfail, k, j, i) == radiation::FailFlags::fail) { + const Real sdetgam = geom.DetGamma(CellLocation::Cent, k, j, i); + Real gcov[4][4]; + geom.SpacetimeMetric(CellLocation::Cent, k, j, i, gcov); + const Real vel[] = {v(b, idx_pvel(0), k, j, i), v(b, idx_pvel(1), k, j, i), + v(b, idx_pvel(2), k, j, i)}; + const Real W = phoebus::GetLorentzFactor(vel, gcov); + Vec con_v({vel[0] / W, vel[1] / W, vel[2] / W}); + + typename CLOSURE::LocalGeometryType g(geom, CellLocation::Cent, b, k, j, i); + + Real num_valid = v(b, iradfail, k, j, i - 1) + v(b, iradfail, k, j, i + 1); + if (ndim > 1) + num_valid += v(b, iradfail, k, j - 1, i) + v(b, iradfail, k, j + 1, i); + if (ndim == 3) + num_valid += v(b, iradfail, k - 1, j, i) + v(b, iradfail, k + 1, j, i); + // Can't stencil outside of memory of this meshblock + // if (num_valid > 0.5 && + // rad_c2p_failure_strategy == FAILURE_STRATEGY::interpolate && i > ib.s && + // i < ib.e - 1 && j > jb.s && j < jb.e - 1 && k > kb.s && k < kb.e - 1) { + if (num_valid > 0.5 && + rad_c2p_failure_strategy == FAILURE_STRATEGY::interpolate) { + const Real norm = 1.0 / num_valid; + for (int ispec = 0; ispec < nspec; ispec++) { + v(b, idx_J(ispec), k, j, i) = fixup(idx_J(ispec), norm); + SPACELOOP(ii) { + v(b, idx_H(ispec, ii), k, j, i) = fixup(idx_H(ispec, ii), norm); + } + } + } else { + for (int ispec = 0; ispec < nspec; ispec++) { + v(b, idx_J(ispec), k, j, i) = 10. * robust::SMALL(); + SPACELOOP(ii) { v(b, idx_H(ispec, ii), k, j, i) = 0.; } + } + } + + for (int ispec = 0; ispec < nspec; ispec++) { + Vec cov_H = {v(b, idx_H(ispec, 0), k, j, i), v(b, idx_H(ispec, 1), k, j, i), + v(b, idx_H(ispec, 2), k, j, i)}; + const Real xi = + std::sqrt(g.contractCov3Vectors(cov_H, cov_H) - + std::pow(g.contractConCov3Vectors(con_v, cov_H), 2)); + if (xi > xi_max) { + SPACELOOP(ii) { v(b, idx_H(ispec, ii), k, j, i) *= xi_max / xi; } + } + } + + CLOSURE c(con_v, &g); + for (int ispec = 0; ispec < nspec; ispec++) { + Real E; + Vec cov_F; + Tens2 con_tilPi; + Real J = v(b, idx_J(ispec), k, j, i); + Vec cov_H = {v(b, idx_H(ispec, 0), k, j, i) * J, + v(b, idx_H(ispec, 1), k, j, i) * J, + v(b, idx_H(ispec, 2), k, j, i) * J}; + if (iTilPi.IsValid()) { + SPACELOOP2(ii, jj) { + con_tilPi(ii, jj) = v(b, iTilPi(ispec, ii, jj), k, j, i); + } + } else { + c.GetConTilPiFromPrim(J, cov_H, &con_tilPi); + } + c.Prim2Con(J, cov_H, con_tilPi, &E, &cov_F); + + v(b, idx_E(ispec), k, j, i) = sdetgam * E; + SPACELOOP(ii) { v(b, idx_F(ispec, ii), k, j, i) = sdetgam * cov_F(ii); } + } + } + }); + + return TaskStatus::complete; +} + +template +TaskStatus RadConservedToPrimitiveFixup(T *rc) { + auto *pm = rc->GetParentPointer().get(); + StateDescriptor *rad_pkg = pm->packages.Get("radiation").get(); + StateDescriptor *fix_pkg = pm->packages.Get("fixup").get(); + const bool enable_rad_floors = fix_pkg->Param("enable_rad_floors"); + std::string method; + if (enable_rad_floors) { + method = rad_pkg->Param("method"); + } else { + return TaskStatus::complete; + } + + // TODO(BRR) share these settings somewhere else. Set at configure time? + using settings = + ClosureSettings; + if (method == "moment_m1") { + return RadConservedToPrimitiveFixupImpl>(rc); + } else if (method == "moment_eddington") { + return RadConservedToPrimitiveFixupImpl>(rc); + } else if (method == "mocmc") { + return RadConservedToPrimitiveFixupImpl>(rc); + } + return TaskStatus::fail; +} + +template TaskStatus +RadConservedToPrimitiveFixup>(MeshBlockData *rc); + +} // namespace fixup diff --git a/src/fixup/fixup_src.cpp b/src/fixup/fixup_src.cpp new file mode 100644 index 00000000..7b520a1f --- /dev/null +++ b/src/fixup/fixup_src.cpp @@ -0,0 +1,353 @@ +// © 2022. Triad National Security, LLC. All rights reserved. +// This program was produced under U.S. Government contract +// 89233218CNA000001 for Los Alamos National Laboratory (LANL), which +// is operated by Triad National Security, LLC for the U.S. +// Department of Energy/National Nuclear Security Administration. All +// rights in the program are reserved by Triad National Security, LLC, +// and the U.S. Department of Energy/National Nuclear Security +// Administration. The Government is granted for itself and others +// acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +// license in this material to reproduce, prepare derivative works, +// distribute copies to the public, perform publicly and display +// publicly, and to permit others to do so. + +#include + +#include "fixup.hpp" + +#include +#include +#include + +#include "fluid/con2prim_robust.hpp" +#include "fluid/fluid.hpp" +#include "fluid/prim2con.hpp" +#include "geometry/geometry.hpp" +#include "phoebus_utils/programming_utils.hpp" +#include "phoebus_utils/relativity_utils.hpp" +#include "phoebus_utils/robust.hpp" +#include "phoebus_utils/variables.hpp" +#include "radiation/closure.hpp" +#include "radiation/closure_m1.hpp" +#include "radiation/closure_mocmc.hpp" +#include "radiation/radiation.hpp" + +using radiation::ClosureEquation; +using radiation::ClosureSettings; +using radiation::ClosureVerbosity; +using radiation::Tens2; +using radiation::Vec; +using robust::ratio; +using singularity::RadiationType; +using singularity::neutrinos::Opacity; + +namespace fixup { + +// If radiation source terms fail (probably due to a rootfind failing to converge) average +// the fluid and radiation primitive variables over good neighbors. Or if there are no +// good neighbors, set everything to the floors. Then call p2c on both fluid and +// radiation. +template +TaskStatus SourceFixupImpl(T *rc) { + namespace p = fluid_prim; + namespace c = fluid_cons; + namespace impl = internal_variables; + namespace pr = radmoment_prim; + namespace cr = radmoment_cons; + namespace ir = radmoment_internal; + auto *pmb = rc->GetParentPointer().get(); + IndexRange ib = pmb->cellbounds.GetBoundsI(IndexDomain::interior); + IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::interior); + IndexRange kb = pmb->cellbounds.GetBoundsK(IndexDomain::interior); + + StateDescriptor *fix_pkg = pmb->packages.Get("fixup").get(); + StateDescriptor *eos_pkg = pmb->packages.Get("eos").get(); + StateDescriptor *rad_pkg = pmb->packages.Get("radiation").get(); + if (!rad_pkg->Param("active")) { + return TaskStatus::complete; + } + bool enable_source_fixup = fix_pkg->Param("enable_source_fixup"); + if (!enable_source_fixup) { + return TaskStatus::complete; + } + + auto eos = eos_pkg->Param("d.EOS"); + StateDescriptor *opac = pmb->packages.Get("opacity").get(); + const auto &d_opacity = opac->Param("d.opacity"); + auto bounds = fix_pkg->Param("bounds"); + + const std::vector vars( + {p::density, c::density, p::velocity, c::momentum, p::energy, c::energy, p::bfield, + p::ye, c::ye, p::pressure, p::temperature, p::gamma1, pr::J, pr::H, cr::E, cr::F, + impl::cell_signal_speed, ir::srcfail, ir::tilPi}); + + PackIndexMap imap; + auto v = rc->PackVariables(vars, imap); + + const int prho = imap[p::density].first; + const int crho = imap[c::density].first; + auto idx_pvel = imap.GetFlatIdx(p::velocity); + auto idx_cmom = imap.GetFlatIdx(c::momentum); + const int peng = imap[p::energy].first; + const int ceng = imap[c::energy].first; + const int prs = imap[p::pressure].first; + const int tmp = imap[p::temperature].first; + const int gm1 = imap[p::gamma1].first; + const int slo = imap[impl::cell_signal_speed].first; + const int shi = imap[impl::cell_signal_speed].second; + int pye = imap[p::ye].second; + int cye = imap[c::ye].second; + const int pb_lo = imap[p::bfield].first; + const int pb_hi = imap[p::bfield].second; + auto idx_J = imap.GetFlatIdx(pr::J); + auto idx_H = imap.GetFlatIdx(pr::H); + auto idx_E = imap.GetFlatIdx(cr::E); + auto idx_F = imap.GetFlatIdx(cr::F); + int ifail = imap[ir::srcfail].first; + auto iTilPi = imap.GetFlatIdx(ir::tilPi, false); + + bool report_source_fails = fix_pkg->Param("report_source_fails"); + if (report_source_fails) { + int nfail_total; + parthenon::par_reduce( + parthenon::loop_pattern_mdrange_tag, "Source fixup failures", DevExecSpace(), 0, + v.GetDim(5) - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + KOKKOS_LAMBDA(const int b, const int k, const int j, const int i, int &nf) { + if (v(b, ifail, k, j, i) == radiation::FailFlags::fail) { + nf++; + } + }, + Kokkos::Sum(nfail_total)); + printf("total source nfail: %i\n", nfail_total); + } + + const int ndim = pmb->pmy_mesh->ndim; + + auto geom = Geometry::GetCoordinateSystem(rc); + Coordinates_t coords = rc->GetParentPointer().get()->coords; + + auto num_species = rad_pkg->Param("num_species"); + + // TODO(BRR) make this less ugly + IndexRange ibe = pmb->cellbounds.GetBoundsI(IndexDomain::entire); + IndexRange jbe = pmb->cellbounds.GetBoundsJ(IndexDomain::entire); + IndexRange kbe = pmb->cellbounds.GetBoundsK(IndexDomain::entire); + parthenon::par_for( + DEFAULT_LOOP_PATTERN, "Source fail initialization", DevExecSpace(), 0, + v.GetDim(5) - 1, kbe.s, kbe.e, jbe.s, jbe.e, ibe.s, ibe.e, + KOKKOS_LAMBDA(const int b, const int k, const int j, const int i) { + if (i < ib.s || i > ib.e || j < jb.s || j > jb.e || k < kb.s || k > kb.e) { + // Do not use ghost zones as data for averaging + // TODO(BRR) need to allow ghost zones from neighboring blocks + v(b, ifail, k, j, i) = radiation::FailFlags::fail; + } + }); + + auto src_failure_strategy = fix_pkg->Param("src_failure_strategy"); + + parthenon::par_for( + DEFAULT_LOOP_PATTERN, "Source fixup", DevExecSpace(), 0, v.GetDim(5) - 1, kb.s, + kb.e, jb.s, jb.e, ib.s, ib.e, + KOKKOS_LAMBDA(const int b, const int k, const int j, const int i) { + double gamma_max, e_max; + bounds.GetCeilings(coords.x1v(k, j, i), coords.x2v(k, j, i), coords.x3v(k, j, i), + gamma_max, e_max); + Real xi_max; + bounds.GetRadiationCeilings(coords.x1v(k, j, i), coords.x2v(k, j, i), + coords.x3v(k, j, i), xi_max); + + double eos_lambda[2]; // used for stellarcollapse eos and other EOS's that require + // root finding. + eos_lambda[1] = std::log10(v(b, tmp, k, j, i)); // use last temp as initial guess + + auto fixup = [&](const int iv, const Real inv_mask_sum) { + v(b, iv, k, j, i) = v(b, ifail, k, j, i - 1) * v(b, iv, k, j, i - 1) + + v(b, ifail, k, j, i + 1) * v(b, iv, k, j, i + 1); + if (ndim > 1) { + v(b, iv, k, j, i) += v(b, ifail, k, j - 1, i) * v(b, iv, k, j - 1, i) + + v(b, ifail, k, j + 1, i) * v(b, iv, k, j + 1, i); + if (ndim == 3) { + v(b, iv, k, j, i) += v(b, ifail, k - 1, j, i) * v(b, iv, k - 1, j, i) + + v(b, ifail, k + 1, j, i) * v(b, iv, k + 1, j, i); + } + } + return inv_mask_sum * v(b, iv, k, j, i); + }; + + if (v(b, ifail, k, j, i) == radiation::FailFlags::fail) { + Real num_valid = v(b, ifail, k, j, i - 1) + v(b, ifail, k, j, i + 1); + if (ndim > 1) num_valid += v(b, ifail, k, j - 1, i) + v(b, ifail, k, j + 1, i); + if (ndim == 3) num_valid += v(b, ifail, k - 1, j, i) + v(b, ifail, k + 1, j, i); + + if (num_valid > 0.5 && src_failure_strategy == FAILURE_STRATEGY::interpolate) { + const Real norm = 1.0 / num_valid; + + v(b, prho, k, j, i) = fixup(prho, norm); + v(b, peng, k, j, i) = fixup(peng, norm); + SPACELOOP(ii) { v(b, idx_pvel(ii), k, j, i) = fixup(idx_pvel(ii), norm); } + if (pye > 0) { + v(b, pye, k, j, i) = fixup(pye, norm); + } + if (pye > 0) eos_lambda[0] = v(b, pye, k, j, i); + v(b, tmp, k, j, i) = eos.TemperatureFromDensityInternalEnergy( + v(b, prho, k, j, i), ratio(v(b, peng, k, j, i), v(b, prho, k, j, i)), + eos_lambda); + v(b, prs, k, j, i) = eos.PressureFromDensityTemperature( + v(b, prho, k, j, i), v(b, tmp, k, j, i), eos_lambda); + v(b, gm1, k, j, i) = + ratio(eos.BulkModulusFromDensityTemperature( + v(b, prho, k, j, i), v(b, tmp, k, j, i), eos_lambda), + v(b, prs, k, j, i)); + + for (int ispec = 0; ispec < num_species; ispec++) { + v(b, idx_J(ispec), k, j, i) = fixup(idx_J(ispec), norm); + SPACELOOP(ii) { + v(b, idx_H(ispec, ii), k, j, i) = fixup(idx_H(ispec, ii), norm); + } + } + } else { + // No valid neighbors; set to floors with zero spatial velocity + + v(b, prho, k, j, i) = 10. * robust::SMALL(); + v(b, peng, k, j, i) = 10. * robust::SMALL(); + + // Zero primitive velocities + SPACELOOP(ii) { v(b, idx_pvel(ii), k, j, i) = 0.; } + + // Auxiliary primitives + // Safe value for ye + if (pye > 0) { + v(b, pye, k, j, i) = 0.5; + } + if (pye > 0) eos_lambda[0] = v(b, pye, k, j, i); + v(b, tmp, k, j, i) = eos.TemperatureFromDensityInternalEnergy( + v(b, prho, k, j, i), ratio(v(b, peng, k, j, i), v(b, prho, k, j, i)), + eos_lambda); + v(b, prs, k, j, i) = eos.PressureFromDensityTemperature( + v(b, prho, k, j, i), v(b, tmp, k, j, i), eos_lambda); + v(b, gm1, k, j, i) = + ratio(eos.BulkModulusFromDensityTemperature( + v(b, prho, k, j, i), v(b, tmp, k, j, i), eos_lambda), + v(b, prs, k, j, i)); + + for (int ispec = 0; ispec < num_species; ispec++) { + v(b, idx_J(ispec), k, j, i) = 10. * robust::SMALL(); + + SPACELOOP(ii) { v(b, idx_H(ispec, ii), k, j, i) = 0.; } + } + } + + const Real sdetgam = geom.DetGamma(CellLocation::Cent, k, j, i); + const Real alpha = geom.Lapse(CellLocation::Cent, k, j, i); + Real beta[3]; + geom.ContravariantShift(CellLocation::Cent, k, j, i, beta); + Real gcon[3][3]; + geom.MetricInverse(CellLocation::Cent, k, j, i, gcon); + Real gcov[4][4]; + geom.SpacetimeMetric(CellLocation::Cent, k, j, i, gcov); + + // Clamp velocity now (for rad inversion) + Real vpcon[3] = {v(b, idx_pvel(0), k, j, i), v(b, idx_pvel(1), k, j, i), + v(b, idx_pvel(2), k, j, i)}; + Real W = phoebus::GetLorentzFactor(vpcon, gcov); + if (W > gamma_max) { + const Real rescale = std::sqrt(gamma_max * gamma_max - 1.) / (W * W - 1.); + SPACELOOP(ii) { vpcon[ii] *= rescale; } + SPACELOOP(ii) { v(b, idx_pvel(ii), k, j, i) = vpcon[ii]; } + W = gamma_max; + } + Vec con_v({vpcon[0] / W, vpcon[1] / W, vpcon[2] / W}); + + typename CLOSURE::LocalGeometryType g(geom, CellLocation::Cent, b, k, j, i); + + for (int ispec = 0; ispec < num_species; ispec++) { + Vec cov_H = {v(b, idx_H(ispec, 0), k, j, i), v(b, idx_H(ispec, 1), k, j, i), + v(b, idx_H(ispec, 2), k, j, i)}; + const Real xi = + std::sqrt(g.contractCov3Vectors(cov_H, cov_H) - + std::pow(g.contractConCov3Vectors(con_v, cov_H), 2)); + } + + // Update MHD conserved variables + Real S[3]; + Real bcons[3]; + Real bp[3] = {0.0, 0.0, 0.0}; + if (pb_hi > 0) { + bp[0] = v(b, pb_lo, k, j, i); + bp[1] = v(b, pb_lo + 1, k, j, i); + bp[2] = v(b, pb_hi, k, j, i); + } + Real ye_cons; + Real ye_prim = 0.0; + if (pye > 0) { + ye_prim = v(b, pye, k, j, i); + } + Real sig[3]; + prim2con::p2c(v(b, prho, k, j, i), vpcon, bp, v(b, peng, k, j, i), ye_prim, + v(b, prs, k, j, i), v(b, gm1, k, j, i), gcov, gcon, beta, alpha, + sdetgam, v(b, crho, k, j, i), S, bcons, v(b, ceng, k, j, i), + ye_cons, sig); + v(b, idx_cmom(0), k, j, i) = S[0]; + v(b, idx_cmom(1), k, j, i) = S[1]; + v(b, idx_cmom(2), k, j, i) = S[2]; + if (pye > 0) v(b, cye, k, j, i) = ye_cons; + for (int m = slo; m <= shi; m++) { + v(b, m, k, j, i) = sig[m - slo]; + } + + // Update radiation conserved variables + CLOSURE c(con_v, &g); + for (int ispec = 0; ispec < num_species; ispec++) { + Real E; + Vec cov_F; + Tens2 con_TilPi = {0}; + Real J = v(b, idx_J(ispec), k, j, i); + Vec cov_H = {J * v(b, idx_H(ispec, 0), k, j, i), + J * v(b, idx_H(ispec, 1), k, j, i), + J * v(b, idx_H(ispec, 2), k, j, i)}; + if (iTilPi.IsValid()) { + SPACELOOP2(ii, jj) { + con_TilPi(ii, jj) = v(b, iTilPi(ispec, ii, jj), k, j, i); + } + } else { + c.GetConTilPiFromPrim(J, cov_H, &con_TilPi); + } + c.Prim2Con(J, cov_H, con_TilPi, &E, &cov_F); + v(b, idx_E(ispec), k, j, i) = sdetgam * E; + SPACELOOP(ii) { v(b, idx_F(ispec, ii), k, j, i) = sdetgam * cov_F(ii); } + } + } + }); + + return TaskStatus::complete; +} + +template +TaskStatus SourceFixup(T *rc) { + auto *pm = rc->GetParentPointer().get(); + StateDescriptor *rad_pkg = pm->packages.Get("radiation").get(); + StateDescriptor *fix_pkg = pm->packages.Get("fixup").get(); + const bool enable_rad_floors = fix_pkg->Param("enable_rad_floors"); + std::string method; + if (enable_rad_floors) { + method = rad_pkg->Param("method"); + } else { + return TaskStatus::complete; + } + + // TODO(BRR) share these settings somewhere else. Set at configure time? + using settings = + ClosureSettings; + if (method == "moment_m1") { + return SourceFixupImpl>(rc); + } else if (method == "moment_eddington") { + return SourceFixupImpl>(rc); + } else if (method == "mocmc") { + return SourceFixupImpl>(rc); + } + return TaskStatus::fail; +} + +template TaskStatus SourceFixup>(MeshBlockData *rc); + +} // namespace fixup diff --git a/src/fluid/con2prim.hpp b/src/fluid/con2prim.hpp index bb93f4c3..2ef5bfaf 100644 --- a/src/fluid/con2prim.hpp +++ b/src/fluid/con2prim.hpp @@ -1,17 +1,15 @@ -//======================================================================================== -// (C) (or copyright) 2021. Triad National Security, LLC. All rights reserved. -// -// This program was produced under U.S. Government contract 89233218CNA000001 -// for Los Alamos National Laboratory (LANL), which is operated by Triad -// National Security, LLC for the U.S. Department of Energy/National Nuclear -// Security Administration. All rights in the program are reserved by Triad -// National Security, LLC, and the U.S. Department of Energy/National Nuclear -// Security Administration. The Government is granted for itself and others -// acting on its behalf a nonexclusive, paid-up, irrevocable worldwide license -// in this material to reproduce, prepare derivative works, distribute copies to -// the public, perform publicly and display publicly, and to permit others to do -// so. -//======================================================================================== +// © 2021-2022. Triad National Security, LLC. All rights reserved. +// This program was produced under U.S. Government contract +// 89233218CNA000001 for Los Alamos National Laboratory (LANL), which +// is operated by Triad National Security, LLC for the U.S. +// Department of Energy/National Nuclear Security Administration. All +// rights in the program are reserved by Triad National Security, LLC, +// and the U.S. Department of Energy/National Nuclear Security +// Administration. The Government is granted for itself and others +// acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +// license in this material to reproduce, prepare derivative works, +// distribute copies to the public, perform publicly and display +// publicly, and to permit others to do so. #ifndef CON2PRIM_HPP_ #define CON2PRIM_HPP_ diff --git a/src/fluid/con2prim_robust.hpp b/src/fluid/con2prim_robust.hpp index 0c3eee2d..8686541f 100644 --- a/src/fluid/con2prim_robust.hpp +++ b/src/fluid/con2prim_robust.hpp @@ -1,15 +1,15 @@ -//======================================================================================== -// (C) (or copyright) 2020. Triad National Security, LLC. All rights reserved. -// -// This program was produced under U.S. Government contract 89233218CNA000001 for Los -// Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC -// for the U.S. Department of Energy/National Nuclear Security Administration. All rights -// in the program are reserved by Triad National Security, LLC, and the U.S. Department -// of Energy/National Nuclear Security Administration. The Government is granted for -// itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide -// license in this material to reproduce, prepare derivative works, distribute copies to -// the public, perform publicly and display publicly, and to permit others to do so. -//======================================================================================== +// © 2021-2022. Triad National Security, LLC. All rights reserved. +// This program was produced under U.S. Government contract +// 89233218CNA000001 for Los Alamos National Laboratory (LANL), which +// is operated by Triad National Security, LLC for the U.S. +// Department of Energy/National Nuclear Security Administration. All +// rights in the program are reserved by Triad National Security, LLC, +// and the U.S. Department of Energy/National Nuclear Security +// Administration. The Government is granted for itself and others +// acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +// license in this material to reproduce, prepare derivative works, +// distribute copies to the public, perform publicly and display +// publicly, and to permit others to do so. #ifndef CON2PRIM_ROBUST_HPP_ #define CON2PRIM_ROBUST_HPP_ @@ -35,8 +35,6 @@ using namespace parthenon::package::prelude; #include "phoebus_utils/variables.hpp" #include "prim2con.hpp" -#define CON2PRIM_ROBUST_PRINT_FAILURES 0 - namespace con2prim_robust { using namespace robust; @@ -53,17 +51,16 @@ class Residual { Residual(const Real D, const Real q, const Real bsq, const Real bsq_rpsq, const Real rsq, const Real rbsq, const Real v0sq, const Real Ye, const singularity::EOS &eos, const fixup::Bounds &bnds, const Real x1, - const Real x2, const Real x3) + const Real x2, const Real x3, const Real floor_scale_fac) : D_(D), q_(q), bsq_(bsq), bsq_rpsq_(bsq_rpsq), rsq_(rsq), rbsq_(rbsq), v0sq_(v0sq), - eos_(eos), bounds_(bnds), x1_(x1), x2_(x2), x3_(x3) { + eos_(eos), bounds_(bnds), x1_(x1), x2_(x2), x3_(x3), + floor_scale_fac_(floor_scale_fac) { lambda_[0] = Ye; Real garbage = 0.0; bounds_.GetFloors(x1_, x2_, x3_, rho_floor_, garbage); bounds_.GetCeilings(x1_, x2_, x3_, gam_max_, e_max_); -#if !USE_C2P_ROBUST_FLOORS - rho_floor_ = 1.e-20; -#endif + rho_floor_ *= floor_scale_fac_; } KOKKOS_FORCEINLINE_FUNCTION @@ -106,6 +103,7 @@ class Residual { const Real What) { Real rho = rhohat_mu(1.0 / What); bounds_.GetFloors(x1_, x2_, x3_, rho, e_floor_); + e_floor_ *= floor_scale_fac_; const Real ehat_trial = What * (qbar - mu * rbarsq) + vhatsq * What * What / (1.0 + What); used_energy_floor_ = false; @@ -170,6 +168,7 @@ class Residual { const singularity::EOS &eos_; const fixup::Bounds &bounds_; const Real x1_, x2_, x3_; + const Real floor_scale_fac_; Real lambda_[2]; Real rho_floor_, e_floor_, gam_max_, e_max_; bool used_density_floor_, used_energy_floor_, used_energy_max_, used_gamma_max_; @@ -205,7 +204,6 @@ struct CellGeom { : gdet(geom.DetGamma(CellLocation::Cent, k, j, i)), lapse(geom.Lapse(CellLocation::Cent, k, j, i)) { geom.SpacetimeMetric(CellLocation::Cent, k, j, i, gcov4); - SPACELOOP2(m, n) { gcov[m][n] = gcov4[m + 1][n + 1]; } geom.MetricInverse(CellLocation::Cent, k, j, i, gcon); geom.ContravariantShift(CellLocation::Cent, k, j, i, beta); } @@ -215,11 +213,9 @@ struct CellGeom { : gdet(geom.DetGamma(CellLocation::Cent, b, k, j, i)), lapse(geom.Lapse(CellLocation::Cent, b, k, j, i)) { geom.SpacetimeMetric(CellLocation::Cent, b, k, j, i, gcov4); - SPACELOOP2(m, n) { gcov[m][n] = gcov4[m + 1][n + 1]; } geom.MetricInverse(CellLocation::Cent, b, k, j, i, gcon); geom.ContravariantShift(CellLocation::Cent, b, k, j, i, beta); } - Real gcov[3][3]; Real gcov4[4][4]; Real gcon[3][3]; Real beta[3]; @@ -230,7 +226,9 @@ struct CellGeom { template class ConToPrim { public: - ConToPrim(Data_t *rc, fixup::Bounds bnds, const Real tol, const int max_iterations) + ConToPrim(Data_t *rc, fixup::Bounds bnds, const Real tol, const int max_iterations, + const Real floor_scale_fac, const bool fail_on_floors, + const bool fail_on_ceilings) : bounds(bnds), var(rc->PackVariables(Vars(), imap)), prho(imap[fluid_prim::density].first), crho(imap[fluid_cons::density].first), pvel_lo(imap[fluid_prim::velocity].first), @@ -246,7 +244,8 @@ class ConToPrim { sig_hi(imap[internal_variables::cell_signal_speed].second), gm1(imap[fluid_prim::gamma1].first), c2p_mu(imap[internal_variables::c2p_mu].first), rel_tolerance(tol), - max_iter(max_iterations), h0sq_(1.0) {} + max_iter(max_iterations), h0sq_(1.0), floor_scale_fac_(floor_scale_fac), + fail_on_floors_(fail_on_floors), fail_on_ceilings_(fail_on_ceilings) {} std::vector Vars() { return std::vector( @@ -287,6 +286,9 @@ class ConToPrim { const Real rel_tolerance; const int max_iter; const Real h0sq_; + const Real floor_scale_fac_; + const bool fail_on_floors_; + const bool fail_on_ceilings_; KOKKOS_INLINE_FUNCTION ConToPrimStatus solve(const VarAccessor &v, const CellGeom &g, @@ -299,6 +301,8 @@ class ConToPrim { Real rhoflr = 0.0; Real epsflr; bounds.GetFloors(x1, x2, x3, rhoflr, epsflr); + rhoflr *= floor_scale_fac_; + epsflr *= floor_scale_fac_; Real gam_max, eps_max; bounds.GetCeilings(x1, x2, x3, gam_max, eps_max); @@ -344,7 +348,7 @@ class ConToPrim { bu[i] = v(pb_lo + i) * sD; bdotr += bu[i] * rcov[i]; } - SPACELOOP2(i, j) bsq += g.gcov[i][j] * bu[i] * bu[j]; + SPACELOOP2(i, j) bsq += g.gcov4[i + 1][j + 1] * bu[i] * bu[j]; bsq = std::max(0.0, bsq); rbsq = bdotr * bdotr; @@ -353,7 +357,8 @@ class ConToPrim { const Real zsq = rsq / h0sq_; Real v0sq = std::min(zsq / (1.0 + zsq), 1.0 - 1.0 / (gam_max * gam_max)); - Residual res(D, q, bsq, bsq_rpsq, rsq, rbsq, v0sq, ye_local, eos, bounds, x1, x2, x3); + Residual res(D, q, bsq, bsq_rpsq, rsq, rbsq, v0sq, ye_local, eos, bounds, x1, x2, x3, + floor_scale_fac_); // find the upper bound // TODO(JCD): revisit this. is it worth it to find the upper bound? @@ -429,7 +434,13 @@ class ConToPrim { num_nans = std::isnan(v(crho)) + std::isnan(v(cmom_lo)) + std::isnan(v(ceng)); - if (num_nans > 0 || res.used_gamma_max()) { + if (num_nans > 0) { + return ConToPrimStatus::failure; + } + if (fail_on_floors_ && (res.used_density_floor() || res.used_energy_floor())) { + return ConToPrimStatus::failure; + } + if (fail_on_ceilings_ == true && res.used_gamma_max()) { return ConToPrimStatus::failure; } return ConToPrimStatus::success; @@ -440,8 +451,12 @@ using C2P_Block_t = ConToPrim, VariablePack>; using C2P_Mesh_t = ConToPrim, MeshBlockPack>; inline C2P_Block_t ConToPrimSetup(MeshBlockData *rc, fixup::Bounds bounds, - const Real tol, const int max_iter) { - return C2P_Block_t(rc, bounds, tol, max_iter); + const Real tol, const int max_iter, + const Real c2p_floor_scale_fac, + const bool fail_on_floors, + const bool fail_on_ceilings) { + return C2P_Block_t(rc, bounds, tol, max_iter, c2p_floor_scale_fac, fail_on_floors, + fail_on_ceilings); } /*inline C2P_Mesh_t ConToPrimSetup(MeshData *rc) { return C2P_Mesh_t(rc); diff --git a/src/fluid/fluid.cpp b/src/fluid/fluid.cpp index c0a911de..55472e57 100644 --- a/src/fluid/fluid.cpp +++ b/src/fluid/fluid.cpp @@ -1,5 +1,5 @@ -// © 2021. Triad National Security, LLC. All rights reserved. This -// program was produced under U.S. Government contract +// © 2021-2022. Triad National Security, LLC. All rights reserved. +// This program was produced under U.S. Government contract // 89233218CNA000001 for Los Alamos National Laboratory (LANL), which // is operated by Triad National Security, LLC for the U.S. // Department of Energy/National Nuclear Security Administration. All @@ -15,6 +15,7 @@ #include "con2prim.hpp" #include "con2prim_robust.hpp" +#include "fixup/fixup.hpp" #include "geometry/geometry.hpp" #include "geometry/geometry_utils.hpp" #include "phoebus_utils/cell_locations.hpp" @@ -75,6 +76,20 @@ std::shared_ptr Initialize(ParameterInput *pin) { int c2p_max_iter = pin->GetOrAddInteger("fluid", "c2p_max_iter", 20); params.Add("c2p_max_iter", c2p_max_iter); + // The factor by which the floors in c2p are reduced from the floors used in + // ApplyFloors + Real c2p_floor_scale_fac = pin->GetOrAddReal("fluid", "c2p_floor_scale_fac", 1.); + PARTHENON_REQUIRE(c2p_floor_scale_fac <= 1. && c2p_floor_scale_fac > 0., + "fluid/c2p_floor_scale_fac must be between 0 and 1!"); + params.Add("c2p_floor_scale_fac", c2p_floor_scale_fac); + + bool c2p_fail_on_floors = pin->GetOrAddBoolean("fluid", "c2p_fail_on_floors", false); + params.Add("c2p_fail_on_floors", c2p_fail_on_floors); + + bool c2p_fail_on_ceilings = + pin->GetOrAddBoolean("fluid", "c2p_fail_on_ceilings", false); + params.Add("c2p_fail_on_ceilings", c2p_fail_on_ceilings); + std::string recon = pin->GetOrAddString("fluid", "recon", "linear"); PhoebusReconstruction::ReconType rt = PhoebusReconstruction::ReconType::linear; if (recon == "weno5" || recon == "weno5z") { @@ -93,7 +108,8 @@ std::shared_ptr Initialize(ParameterInput *pin) { } else if (recon == "constant") { rt = PhoebusReconstruction::ReconType::constant; } else { - PARTHENON_THROW("Invalid Reconstruction option. Choose from [linear,weno5]"); + PARTHENON_THROW("Invalid Reconstruction option. Choose from " + "[constant,linear,mp5,weno5,weno5z]"); } params.Add("Recon", rt); @@ -190,7 +206,10 @@ std::shared_ptr Initialize(ParameterInput *pin) { // Just want constant primitive fields around to serve as // background if we are not evolving the fluid, don't need // to do the rest. - if (!active) return physics; + // TODO(BRR) logic gets very complicated accounting for this in situations where + // radiation is active but fluid isn't -- for example we want fluid prims from c2p to + // calculate opacities. + // if (!active) return physics; // this fail flag should really be an enum or something // but parthenon doesn't yet support that kind of thing @@ -207,6 +226,9 @@ std::shared_ptr Initialize(ParameterInput *pin) { physics->AddField(c::ye, mcons_scalar); } + // If fluid is not active, still don't add reconstruction variables + if (!active) return physics; + #if SET_FLUX_SRC_DIAGS // DIAGNOSTIC STUFF FOR DEBUGGING std::vector five_vec(1, 5); @@ -400,15 +422,22 @@ TaskStatus PrimitiveToConservedRegion(MeshBlockData *rc, const IndexRange return TaskStatus::complete; } +template +TaskStatus ConservedToPrimitiveRegion(T *rc, const IndexRange &ib, const IndexRange &jb, + const IndexRange &kb) { + auto *pmb = rc->GetParentPointer().get(); + StateDescriptor *pkg = pmb->packages.Get("fluid").get(); + auto c2p = pkg->Param>("c2p_func"); + return c2p(rc, ib, jb, kb); +} + template TaskStatus ConservedToPrimitive(T *rc) { auto *pmb = rc->GetParentPointer().get(); IndexRange ib = pmb->cellbounds.GetBoundsI(IndexDomain::entire); IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::entire); IndexRange kb = pmb->cellbounds.GetBoundsK(IndexDomain::entire); - StateDescriptor *pkg = pmb->packages.Get("fluid").get(); - auto c2p = pkg->Param>("c2p_func"); - return c2p(rc, ib, jb, kb); + return ConservedToPrimitiveRegion(rc, ib, jb, kb); } template @@ -422,7 +451,12 @@ TaskStatus ConservedToPrimitiveRobust(T *rc, const IndexRange &ib, const IndexRa StateDescriptor *pkg = pmb->packages.Get("fluid").get(); const Real c2p_tol = pkg->Param("c2p_tol"); const int c2p_max_iter = pkg->Param("c2p_max_iter"); - auto invert = con2prim_robust::ConToPrimSetup(rc, bounds, c2p_tol, c2p_max_iter); + const Real c2p_floor_scale_fac = pkg->Param("c2p_floor_scale_fac"); + const bool c2p_fail_on_floors = pkg->Param("c2p_fail_on_floors"); + const bool c2p_fail_on_ceilings = pkg->Param("c2p_fail_on_ceilings"); + auto invert = con2prim_robust::ConToPrimSetup(rc, bounds, c2p_tol, c2p_max_iter, + c2p_floor_scale_fac, c2p_fail_on_floors, + c2p_fail_on_ceilings); StateDescriptor *eos_pkg = pmb->packages.Get("eos").get(); auto eos = eos_pkg->Param("d.EOS"); @@ -458,7 +492,6 @@ TaskStatus ConservedToPrimitiveClassic(T *rc, const IndexRange &ib, const IndexR const Real c2p_tol = pkg->Param("c2p_tol"); const int c2p_max_iter = pkg->Param("c2p_max_iter"); auto invert = con2prim::ConToPrimSetup(rc, c2p_tol, c2p_max_iter); - auto invert_robust = con2prim_robust::ConToPrimSetup(rc, bounds, c2p_tol, c2p_max_iter); StateDescriptor *eos_pkg = pmb->packages.Get("eos").get(); auto eos = eos_pkg->Param("d.EOS"); diff --git a/src/fluid/fluid.hpp b/src/fluid/fluid.hpp index ed50f3f1..a6e3ff9f 100644 --- a/src/fluid/fluid.hpp +++ b/src/fluid/fluid.hpp @@ -30,6 +30,9 @@ TaskStatus PrimitiveToConserved(MeshBlockData *rc); TaskStatus PrimitiveToConservedRegion(MeshBlockData *rc, const IndexRange &ib, const IndexRange &jb, const IndexRange &kb); template +TaskStatus ConservedToPrimitiveRegion(T *rc, const IndexRange &ib, const IndexRange &jb, + const IndexRange &kb); +template TaskStatus ConservedToPrimitive(T *rc); template TaskStatus ConservedToPrimitiveRobust(T *rc, const IndexRange &ib, const IndexRange &jb, @@ -66,14 +69,27 @@ TaskStatus CopyFluxDivergence(T *rc) { std::vector vars( {fluid_cons::density, fluid_cons::momentum, fluid_cons::energy}); + vars.push_back(radmoment_cons::E); + vars.push_back(radmoment_cons::F); PackIndexMap imap; auto divf = rc->PackVariables(vars, imap); const int crho = imap[fluid_cons::density].first; const int cmom_lo = imap[fluid_cons::momentum].first; const int cmom_hi = imap[fluid_cons::momentum].second; const int ceng = imap[fluid_cons::energy].first; - std::vector diag_vars({diagnostic_variables::divf}); - auto diag = rc->PackVariables(diag_vars); + auto idx_E = imap.GetFlatIdx(radmoment_cons::E, false); + auto idx_F = imap.GetFlatIdx(radmoment_cons::F, false); + std::vector diag_vars( + {diagnostic_variables::divf, diagnostic_variables::r_divf}); + PackIndexMap imap_diag; + auto diag = rc->PackVariables(diag_vars, imap_diag); + auto idx_r_divf = imap_diag.GetFlatIdx(diagnostic_variables::r_divf, false); + + StateDescriptor *rad = pmb->packages.Get("radiation").get(); + int num_species = 0; + if (idx_E.IsValid()) { + num_species = rad->Param("num_species"); + } // TODO(JMM): If we expose a way to get cellbounds from the mesh or // meshdata object, that would be better. @@ -86,6 +102,14 @@ TaskStatus CopyFluxDivergence(T *rc) { diag(b, 2, k, j, i) = divf(b, cmom_lo + 1, k, j, i); diag(b, 3, k, j, i) = divf(b, cmom_lo + 2, k, j, i); diag(b, 4, k, j, i) = divf(b, ceng, k, j, i); + for (int ispec = 0; ispec < num_species; ispec++) { + if (idx_E.IsValid()) { + diag(b, idx_r_divf(ispec, 0), k, j, i) = divf(b, idx_E(ispec), k, j, i); + diag(b, idx_r_divf(ispec, 1), k, j, i) = divf(b, idx_F(ispec, 0), k, j, i); + diag(b, idx_r_divf(ispec, 2), k, j, i) = divf(b, idx_F(ispec, 1), k, j, i); + diag(b, idx_r_divf(ispec, 3), k, j, i) = divf(b, idx_F(ispec, 2), k, j, i); + } + } }); return TaskStatus::complete; } diff --git a/src/fluid/prim2con.hpp b/src/fluid/prim2con.hpp index 664ed746..244d8fcc 100644 --- a/src/fluid/prim2con.hpp +++ b/src/fluid/prim2con.hpp @@ -1,20 +1,23 @@ -//======================================================================================== -// (C) (or copyright) 2021. Triad National Security, LLC. All rights reserved. -// -// This program was produced under U.S. Government contract 89233218CNA000001 for Los -// Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC -// for the U.S. Department of Energy/National Nuclear Security Administration. All rights -// in the program are reserved by Triad National Security, LLC, and the U.S. Department -// of Energy/National Nuclear Security Administration. The Government is granted for -// itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide -// license in this material to reproduce, prepare derivative works, distribute copies to -// the public, perform publicly and display publicly, and to permit others to do so. -//======================================================================================== +// © 2021-2022. Triad National Security, LLC. All rights reserved. +// This program was produced under U.S. Government contract +// 89233218CNA000001 for Los Alamos National Laboratory (LANL), which +// is operated by Triad National Security, LLC for the U.S. +// Department of Energy/National Nuclear Security Administration. All +// rights in the program are reserved by Triad National Security, LLC, +// and the U.S. Department of Energy/National Nuclear Security +// Administration. The Government is granted for itself and others +// acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +// license in this material to reproduce, prepare derivative works, +// distribute copies to the public, perform publicly and display +// publicly, and to permit others to do so. #ifndef FLUID_PRIM2CON_HPP_ #define FLUID_PRIM2CON_HPP_ +#include + #include "phoebus_utils/relativity_utils.hpp" +#include "phoebus_utils/robust.hpp" namespace prim2con { @@ -25,6 +28,10 @@ void signal_speeds(const Real &rho, const Real &u, const Real &p, const Real &bs const Real rho_rel = rho + u + p; const Real vasq = bsq / (rho_rel + bsq); Real cssq = gam1 * p / rho_rel; + PARTHENON_DEBUG_REQUIRE(rho > robust::SMALL(), "rho is unacceptably small!"); + PARTHENON_DEBUG_REQUIRE(u > robust::SMALL(), "u is unacceptably small!"); + PARTHENON_DEBUG_REQUIRE(p > robust::SMALL(), "p is unacceptably small!"); + PARTHENON_DEBUG_REQUIRE(gam1 > robust::SMALL(), "gam1 is unacceptably small!"); cssq += vasq - cssq * vasq; const Real vcoff = alpha / (1.0 - vsq * cssq); SPACELOOP(m) { diff --git a/src/fluid/riemann.hpp b/src/fluid/riemann.hpp index 0dc1a98a..41b0d35f 100644 --- a/src/fluid/riemann.hpp +++ b/src/fluid/riemann.hpp @@ -1,5 +1,5 @@ -// © 2021. Triad National Security, LLC. All rights reserved. This -// program was produced under U.S. Government contract +// © 2021-2022. Triad National Security, LLC. All rights reserved. +// This program was produced under U.S. Government contract // 89233218CNA000001 for Los Alamos National Laboratory (LANL), which // is operated by Triad National Security, LLC for the U.S. // Department of Energy/National Nuclear Security Administration. All @@ -88,6 +88,10 @@ class FluxState { Real vpcon[] = {q(dir, pvel_lo, k, j, i), q(dir, pvel_lo + 1, k, j, i), q(dir, pvel_lo + 2, k, j, i)}; Real W = phoebus::GetLorentzFactor(vpcon, g.gcov); + if (W > gam_max) { + const Real rescale = std::sqrt((gam_max * gam_max - 1.) / (W * W - 1.)); + SPACELOOP(ii) { vpcon[ii] *= rescale; } + } Real vcon[] = {vpcon[0] / W, vpcon[1] / W, vpcon[2] / W}; const Real &vel = vcon[dir]; Real Bcon[] = {0.0, 0.0, 0.0}; diff --git a/src/pgen/advection.cpp b/src/pgen/advection.cpp index 50739553..fa3ae8d0 100644 --- a/src/pgen/advection.cpp +++ b/src/pgen/advection.cpp @@ -26,10 +26,10 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { auto &rc = pmb->meshblock_data.Get(); PackIndexMap imap; - auto v = rc->PackVariables({fluid_prim::density, fluid_prim::velocity, - fluid_prim::energy, fluid_prim::bfield, fluid_prim::ye, - fluid_prim::pressure, fluid_prim::temperature}, - imap); + auto v = rc->PackVariables( + {fluid_prim::density, fluid_prim::velocity, fluid_prim::energy, fluid_prim::bfield, + fluid_prim::ye, fluid_prim::pressure, fluid_prim::temperature, fluid_prim::gamma1}, + imap); const int irho = imap[fluid_prim::density].first; const int ivlo = imap[fluid_prim::velocity].first; @@ -40,6 +40,7 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { const int iye = imap[fluid_prim::ye].second; const int iprs = imap[fluid_prim::pressure].first; const int itmp = imap[fluid_prim::temperature].first; + const int igm1 = imap[fluid_prim::gamma1].first; const Real rho = pin->GetOrAddReal("advection", "rho", 1.0); const Real u = pin->GetOrAddReal("advection", "u", 1.0); @@ -81,6 +82,9 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { v(iprs, k, j, i) = P; v(ieng, k, j, i) = u; v(itmp, k, j, i) = T; + v(igm1, k, j, i) = eos.BulkModulusFromDensityTemperature( + v(irho, k, j, i), v(itmp, k, j, i), eos_lambda) / + v(iprs, k, j, i); Real vsq = 0.; const Real vcon[3] = {vx, vy, vz}; SPACELOOP2(ii, jj) { vsq += vcon[ii] * vcon[jj]; } diff --git a/src/pgen/blandford_mckee.cpp b/src/pgen/blandford_mckee.cpp index d377e407..bf8de059 100644 --- a/src/pgen/blandford_mckee.cpp +++ b/src/pgen/blandford_mckee.cpp @@ -31,10 +31,10 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { auto &rc = pmb->meshblock_data.Get(); PackIndexMap imap; - auto v = rc->PackVariables({fluid_prim::density, fluid_prim::velocity, - fluid_prim::energy, fluid_prim::bfield, fluid_prim::ye, - fluid_prim::pressure, fluid_prim::temperature}, - imap); + auto v = rc->PackVariables( + {fluid_prim::density, fluid_prim::velocity, fluid_prim::energy, fluid_prim::bfield, + fluid_prim::ye, fluid_prim::pressure, fluid_prim::temperature, fluid_prim::gamma1}, + imap); const int irho = imap[fluid_prim::density].first; const int ivlo = imap[fluid_prim::velocity].first; @@ -45,6 +45,7 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { const int iye = imap[fluid_prim::ye].second; const int iprs = imap[fluid_prim::pressure].first; const int itmp = imap[fluid_prim::temperature].first; + const int igm1 = imap[fluid_prim::gamma1].first; const Real wshock = pin->GetOrAddReal("blandford_mckee", "lorentz_shock", 7); Real rescale = std::sqrt(1 - (1 / (wshock * wshock))); @@ -88,6 +89,9 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { v(iprs, k, j, i) = P; v(ieng, k, j, i) = u; v(itmp, k, j, i) = T; + v(igm1, k, j, i) = eos.BulkModulusFromDensityTemperature( + v(irho, k, j, i), v(itmp, k, j, i), eos_lambda) / + v(iprs, k, j, i); for (int d = 0; d < 3; d++) v(ivlo + d, k, j, i) = 0.0; v(ivlo, k, j, i) = W * vel; diff --git a/src/pgen/bondi.cpp b/src/pgen/bondi.cpp index c24e571f..9a69ee02 100644 --- a/src/pgen/bondi.cpp +++ b/src/pgen/bondi.cpp @@ -91,10 +91,10 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { auto rc = pmb->meshblock_data.Get().get(); PackIndexMap imap; - auto v = rc->PackVariables({fluid_prim::density, fluid_prim::velocity, - fluid_prim::energy, fluid_prim::bfield, fluid_prim::ye, - fluid_prim::pressure, fluid_prim::temperature}, - imap); + auto v = rc->PackVariables( + {fluid_prim::density, fluid_prim::velocity, fluid_prim::energy, fluid_prim::bfield, + fluid_prim::ye, fluid_prim::pressure, fluid_prim::temperature, fluid_prim::gamma1}, + imap); const int irho = imap[fluid_prim::density].first; const int ivlo = imap[fluid_prim::velocity].first; @@ -105,6 +105,7 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { const int iye = imap[fluid_prim::ye].second; const int iprs = imap[fluid_prim::pressure].first; const int itmp = imap[fluid_prim::temperature].first; + const int igm1 = imap[fluid_prim::gamma1].first; // this only works with ideal gases const std::string eos_type = pin->GetString("eos", "type"); @@ -174,6 +175,9 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { v(ieng, k, j, i) = v(irho, k, j, i) * v(itmp, k, j, i) / (gam - 1.0); v(iprs, k, j, i) = eos.PressureFromDensityInternalEnergy( v(irho, k, j, i), v(ieng, k, j, i) / v(irho, k, j, i), eos_lambda); + v(igm1, k, j, i) = eos.BulkModulusFromDensityTemperature( + v(irho, k, j, i), v(itmp, k, j, i), eos_lambda) / + v(iprs, k, j, i); Real ucon_bl[] = {0.0, 0.0, 0.0, 0.0}; ucon_bl[1] = -C1 / (std::pow(v(itmp, k, j, i), n) * std::pow(r, 2)); diff --git a/src/pgen/friedmann.cpp b/src/pgen/friedmann.cpp index 4d945ed2..361ff4e6 100644 --- a/src/pgen/friedmann.cpp +++ b/src/pgen/friedmann.cpp @@ -36,16 +36,17 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { auto &rc = pmb->meshblock_data.Get(); PackIndexMap imap; - auto v = rc->PackVariables({fluid_prim::density, fluid_prim::velocity, - fluid_prim::energy, fluid_prim::bfield, fluid_prim::ye, - fluid_prim::pressure, fluid_prim::temperature}, - imap); + auto v = rc->PackVariables( + {fluid_prim::density, fluid_prim::velocity, fluid_prim::energy, fluid_prim::bfield, + fluid_prim::ye, fluid_prim::pressure, fluid_prim::temperature, fluid_prim::gamma1}, + imap); const int irho = imap[fluid_prim::density].first; const int ivlo = imap[fluid_prim::velocity].first; const int ieng = imap[fluid_prim::energy].first; const int iye = imap[fluid_prim::ye].second; const int iprs = imap[fluid_prim::pressure].first; const int itmp = imap[fluid_prim::temperature].first; + const int igm1 = imap[fluid_prim::gamma1].first; const Real rho = pin->GetOrAddReal("friedmann", "rho", 1.0); const Real eps = pin->GetOrAddReal("friedmann", "sie", 1.0); @@ -74,6 +75,9 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { v(iprs, k, j, i) = P; v(ieng, k, j, i) = u; v(itmp, k, j, i) = T; + v(igm1, k, j, i) = eos.BulkModulusFromDensityTemperature( + v(irho, k, j, i), v(itmp, k, j, i), eos_lambda) / + v(iprs, k, j, i); SPACELOOP(i) { v(ivlo + i, k, j, i) = 0; } }); diff --git a/src/pgen/homogeneous_sphere.cpp b/src/pgen/homogeneous_sphere.cpp index 2fd24813..8e69511e 100644 --- a/src/pgen/homogeneous_sphere.cpp +++ b/src/pgen/homogeneous_sphere.cpp @@ -81,9 +81,9 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { v(idJ(ispec), k, j, i) = J; printf("i = %i r = %e J = %e rho = %e\n", i, r, v(idJ(ispec), k, j, i), v(prho, k, j, i)); - v(idH(0, ispec), k, j, i) = Hx; - v(idH(1, ispec), k, j, i) = Hy; - v(idH(2, ispec), k, j, i) = Hz; + v(idH(ispec, 0), k, j, i) = Hx; + v(idH(ispec, 1), k, j, i) = Hy; + v(idH(ispec, 2), k, j, i) = Hz; } }); diff --git a/src/pgen/kh.cpp b/src/pgen/kh.cpp index 718c7f30..3a95f04d 100644 --- a/src/pgen/kh.cpp +++ b/src/pgen/kh.cpp @@ -26,10 +26,10 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { auto &rc = pmb->meshblock_data.Get(); PackIndexMap imap; - auto v = rc->PackVariables({fluid_prim::density, fluid_prim::velocity, - fluid_prim::energy, fluid_prim::bfield, fluid_prim::ye, - fluid_prim::pressure, fluid_prim::temperature}, - imap); + auto v = rc->PackVariables( + {fluid_prim::density, fluid_prim::velocity, fluid_prim::energy, fluid_prim::bfield, + fluid_prim::ye, fluid_prim::pressure, fluid_prim::temperature, fluid_prim::gamma1}, + imap); const int irho = imap[fluid_prim::density].first; const int ivlo = imap[fluid_prim::velocity].first; @@ -40,6 +40,7 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { const int iye = imap[fluid_prim::ye].second; const int iprs = imap[fluid_prim::pressure].first; const int itmp = imap[fluid_prim::temperature].first; + const int igm1 = imap[fluid_prim::gamma1].first; const Real rho0 = pin->GetOrAddReal("kelvin_helmholtz", "rho0", 1.0); const Real rho1 = pin->GetOrAddReal("kelvin_helmholtz", "rho1", 1.0); @@ -90,6 +91,9 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { v(itmp, k, j, i) = eos.TemperatureFromDensityInternalEnergy( rho, v(ieng, k, j, i) / rho, eos_lambda); // this doesn't have to be exact, just a reasonable guess + v(igm1, k, j, i) = eos.BulkModulusFromDensityTemperature( + v(irho, k, j, i), v(itmp, k, j, i), eos_lambda) / + v(iprs, k, j, i); for (int d = 0; d < 3; d++) v(ivlo + d, k, j, i) = v_pert * 2.0 * (rng_gen.drand() - 0.5); v(ivlo, k, j, i) += vel; diff --git a/src/pgen/leptoneq.cpp b/src/pgen/leptoneq.cpp index 820a37a9..087b4189 100644 --- a/src/pgen/leptoneq.cpp +++ b/src/pgen/leptoneq.cpp @@ -32,7 +32,8 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { PackIndexMap imap; auto v = rc->PackVariables( - {p::density, p::velocity, p::energy, p::ye, p::pressure, p::temperature}, imap); + {p::density, p::velocity, p::energy, p::ye, p::pressure, p::temperature, p::gamma1}, + imap); const int irho = imap[p::density].first; const int ivlo = imap[p::velocity].first; @@ -41,6 +42,7 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { const int iye = imap[p::ye].first; const int iprs = imap[p::pressure].first; const int itmp = imap[p::temperature].first; + const int igm1 = imap[p::gamma1].first; IndexRange ib = pmb->cellbounds.GetBoundsI(IndexDomain::entire); IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::entire); @@ -75,6 +77,9 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { v(ieng, k, j, i) = rho0 * eos.InternalEnergyFromDensityTemperature(rho0, T0, lambda); v(iprs, k, j, i) = eos.PressureFromDensityTemperature(rho0, T0, lambda); + v(igm1, k, j, i) = eos.BulkModulusFromDensityTemperature( + v(irho, k, j, i), v(itmp, k, j, i), lambda) / + v(iprs, k, j, i); for (int d = 0; d < 3; d++) v(ivlo + d, k, j, i) = 0.0; diff --git a/src/pgen/linear_modes.cpp b/src/pgen/linear_modes.cpp index 43c9af4e..d30a4d43 100644 --- a/src/pgen/linear_modes.cpp +++ b/src/pgen/linear_modes.cpp @@ -43,9 +43,10 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { const int ndim = pmb->pmy_mesh->ndim; PackIndexMap imap; - std::vector vars( - {fluid_prim::density, fluid_prim::velocity, fluid_prim::energy, fluid_prim::bfield, - fluid_prim::pressure, fluid_prim::temperature, fluid_prim::ye}); + std::vector vars({fluid_prim::density, fluid_prim::velocity, + fluid_prim::energy, fluid_prim::bfield, + fluid_prim::pressure, fluid_prim::temperature, + fluid_prim::gamma1, fluid_prim::ye}); auto v = rc->PackVariables(vars, imap); const int irho = imap[fluid_prim::density].first; @@ -56,6 +57,7 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { const int ib_hi = imap[fluid_prim::bfield].second; const int iprs = imap[fluid_prim::pressure].first; const int itmp = imap[fluid_prim::temperature].first; + const int igm1 = imap[fluid_prim::gamma1].first; const int iye = imap[fluid_prim::ye].second; const int nv = ivhi - ivlo + 1; @@ -222,6 +224,9 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { // k, j, i)/rho); v(itmp, k, j, i) = eos.TemperatureFromDensityInternalEnergy( rho, v(ieng, k, j, i) / rho, eos_lambda); + v(igm1, k, j, i) = eos.BulkModulusFromDensityTemperature( + v(irho, k, j, i), v(itmp, k, j, i), eos_lambda) / + v(iprs, k, j, i); if (ivhi > 0) { v(ivlo, k, j, i) = u10 + (du1 * mode).real(); } diff --git a/src/pgen/p2c2p.cpp b/src/pgen/p2c2p.cpp index eaea4509..31fdd31e 100644 --- a/src/pgen/p2c2p.cpp +++ b/src/pgen/p2c2p.cpp @@ -73,10 +73,10 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { auto &rc = pmb->meshblock_data.Get(); PackIndexMap imap; - auto v = rc->PackVariables({fluid_prim::density, fluid_prim::velocity, - fluid_prim::energy, fluid_prim::bfield, fluid_prim::ye, - fluid_prim::pressure, fluid_prim::temperature}, - imap); + auto v = rc->PackVariables( + {fluid_prim::density, fluid_prim::velocity, fluid_prim::energy, fluid_prim::bfield, + fluid_prim::ye, fluid_prim::pressure, fluid_prim::temperature, fluid_prim::gamma1}, + imap); const int irho = imap[fluid_prim::density].first; const int ivlo = imap[fluid_prim::velocity].first; @@ -86,6 +86,7 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { const int ib_hi = imap[fluid_prim::bfield].second; const int iprs = imap[fluid_prim::pressure].first; const int itmp = imap[fluid_prim::temperature].first; + const int igm1 = imap[fluid_prim::gamma1].first; IndexRange ib = pmb->cellbounds.GetBoundsI(IndexDomain::entire); IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::entire); @@ -113,6 +114,9 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { v(irho, k, j, i), v(ieng, k, j, i) / v(irho, k, j, i)); v(itmp, k, j, i) = eos.TemperatureFromDensityInternalEnergy( v(irho, k, j, i), v(ieng, k, j, i) / v(irho, k, j, i)); + v(igm1, k, j, i) = + eos.BulkModulusFromDensityTemperature(v(irho, k, j, i), v(itmp, k, j, i)) / + v(iprs, k, j, i); }); for (int i = 0; i < 100; i++) { diff --git a/src/pgen/radiation_advection.cpp b/src/pgen/radiation_advection.cpp index d7eb11e7..fc91fc2b 100644 --- a/src/pgen/radiation_advection.cpp +++ b/src/pgen/radiation_advection.cpp @@ -111,7 +111,7 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { v(prho, k, j, i) * eos.InternalEnergyFromDensityTemperature( v(prho, k, j, i), v(pT, k, j, i), lambda); - v(idv(0), k, j, i) = vx; + v(idv(0), k, j, i) = W * vx; v(idv(1), k, j, i) = 0.0; v(idv(2), k, j, i) = 0.0; @@ -132,10 +132,9 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { J0 * std::max(exp(-std::pow((x - 0.5) / width, 2) / 2.0), 1.e-10); } - printf("ispec: %i\n", ispec); - v(idH(0, ispec), k, j, i) = Hx; - v(idH(1, ispec), k, j, i) = Hy; - v(idH(2, ispec), k, j, i) = Hz; + v(idH(ispec, 0), k, j, i) = Hx; + v(idH(ispec, 1), k, j, i) = Hy; + v(idH(ispec, 2), k, j, i) = Hz; } }); diff --git a/src/pgen/radiation_equilibration.cpp b/src/pgen/radiation_equilibration.cpp index 595afc55..edc059bf 100644 --- a/src/pgen/radiation_equilibration.cpp +++ b/src/pgen/radiation_equilibration.cpp @@ -31,11 +31,12 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { auto &rc = pmb->meshblock_data.Get(); PackIndexMap imap; - auto v = rc->PackVariables( - {radmoment_prim::J, radmoment_prim::H, radmoment_internal::xi, - radmoment_internal::phi, fluid_prim::density, fluid_prim::temperature, - fluid_prim::pressure, fluid_prim::energy, fluid_prim::ye, fluid_prim::velocity}, - imap); + auto v = rc->PackVariables({radmoment_prim::J, radmoment_prim::H, + radmoment_internal::xi, radmoment_internal::phi, + fluid_prim::density, fluid_prim::temperature, + fluid_prim::pressure, fluid_prim::gamma1, + fluid_prim::energy, fluid_prim::ye, fluid_prim::velocity}, + imap); auto idJ = imap.GetFlatIdx(radmoment_prim::J); auto idH = imap.GetFlatIdx(radmoment_prim::H); @@ -45,6 +46,7 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { const int iRho = imap[fluid_prim::density].first; const int iT = imap[fluid_prim::temperature].first; const int iP = imap[fluid_prim::pressure].first; + const int igm1 = imap[fluid_prim::gamma1].first; const int ieng = imap[fluid_prim::energy].first; const int pye = imap[fluid_prim::ye].first; auto idv = imap.GetFlatIdx(fluid_prim::velocity); @@ -86,11 +88,14 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { v(iT, k, j, i) = Tg0; v(iP, k, j, i) = P; v(ieng, k, j, i) = v(iRho, k, j, i) * eps; + v(igm1, k, j, i) = + eos.BulkModulusFromDensityTemperature(v(iRho, k, j, i), v(iT, k, j, i)) / + v(iP, k, j, i); v(pye, k, j, i) = Ye0; SPACELOOP(ii) v(idv(ii), k, j, i) = 0.0; for (int ispec = specB.s; ispec <= specB.e; ++ispec) { - SPACELOOP(ii) v(idH(ii, ispec), k, j, i) = 0.0; + SPACELOOP(ii) v(idH(ispec, ii), k, j, i) = 0.0; v(idJ(ispec), k, j, i) = opac_d.EnergyDensityFromTemperature(Tr0, dev_species[ispec]); } @@ -104,8 +109,8 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { } } - radiation::MomentPrim2Con(rc.get(), IndexDomain::entire); fluid::PrimitiveToConserved(rc.get()); + radiation::MomentPrim2Con(rc.get(), IndexDomain::entire); } } // namespace radiation_equilibration diff --git a/src/pgen/rhs_tester.cpp b/src/pgen/rhs_tester.cpp index b4cf6dfc..2d03a32e 100644 --- a/src/pgen/rhs_tester.cpp +++ b/src/pgen/rhs_tester.cpp @@ -20,10 +20,10 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { auto &rc = pmb->meshblock_data.Get(); PackIndexMap imap; - auto v = rc->PackVariables({fluid_prim::density, fluid_prim::velocity, - fluid_prim::energy, fluid_prim::bfield, fluid_prim::ye, - fluid_prim::pressure, fluid_prim::temperature}, - imap); + auto v = rc->PackVariables( + {fluid_prim::density, fluid_prim::velocity, fluid_prim::energy, fluid_prim::bfield, + fluid_prim::ye, fluid_prim::pressure, fluid_prim::temperature, fluid_prim::gamma1}, + imap); const int irho = imap[fluid_prim::density].first; const int ivlo = imap[fluid_prim::velocity].first; @@ -34,6 +34,7 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { const int iye = imap[fluid_prim::ye].second; const int iprs = imap[fluid_prim::pressure].first; const int itmp = imap[fluid_prim::temperature].first; + const int igm1 = imap[fluid_prim::gamma1].first; IndexRange ib = pmb->cellbounds.GetBoundsI(IndexDomain::entire); IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::entire); @@ -65,6 +66,9 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { v(itmp, k, j, i) = eos.TemperatureFromDensityInternalEnergy( rho, v(ieng, k, j, i) / rho, eos_lambda); + v(igm1, k, j, i) = eos.BulkModulusFromDensityTemperature( + v(irho, k, j, i), v(itmp, k, j, i), eos_lambda) / + v(iprs, k, j, i); for (int d = 0; d < 3; ++d) v(ivlo + d, k, j, i) = 0.0; v(ivlo, k, j, i) = vel; diff --git a/src/pgen/rotor.cpp b/src/pgen/rotor.cpp index 0368e220..ddb8c2f9 100644 --- a/src/pgen/rotor.cpp +++ b/src/pgen/rotor.cpp @@ -32,10 +32,10 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { auto &rc = pmb->meshblock_data.Get(); PackIndexMap imap; - auto v = rc->PackVariables({fluid_prim::density, fluid_prim::velocity, - fluid_prim::energy, fluid_prim::bfield, fluid_prim::ye, - fluid_prim::pressure, fluid_prim::temperature}, - imap); + auto v = rc->PackVariables( + {fluid_prim::density, fluid_prim::velocity, fluid_prim::energy, fluid_prim::bfield, + fluid_prim::ye, fluid_prim::pressure, fluid_prim::temperature, fluid_prim::gamma1}, + imap); const int irho = imap[fluid_prim::density].first; const int ivlo = imap[fluid_prim::velocity].first; @@ -46,6 +46,7 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { const int iye = imap[fluid_prim::ye].second; const int iprs = imap[fluid_prim::pressure].first; const int itmp = imap[fluid_prim::temperature].first; + const int igm1 = imap[fluid_prim::gamma1].first; const Real rho0 = pin->GetOrAddReal("rotor", "rho0", 10.0); const Real rho1 = pin->GetOrAddReal("rotor", "rho1", 1.0); @@ -110,6 +111,9 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { v(itmp, k, j, i) = eos.TemperatureFromDensityInternalEnergy( rho, v(ieng, k, j, i) / rho, eos_lambda); // this doesn't have to be exact, just a reasonable guess + v(igm1, k, j, i) = eos.BulkModulusFromDensityTemperature( + v(irho, k, j, i), v(itmp, k, j, i), eos_lambda) / + v(iprs, k, j, i); Real u_mink[] = {Gamma, Gamma * vx, Gamma * vy, 0.0}; Real B_mink[3] = {B0, 0.0, 0.0}; diff --git a/src/pgen/sedov.cpp b/src/pgen/sedov.cpp index 547efe6f..4b4a2ca7 100644 --- a/src/pgen/sedov.cpp +++ b/src/pgen/sedov.cpp @@ -31,10 +31,10 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { auto &rc = pmb->meshblock_data.Get(); PackIndexMap imap; - auto v = rc->PackVariables({fluid_prim::density, fluid_prim::velocity, - fluid_prim::energy, fluid_prim::bfield, fluid_prim::ye, - fluid_prim::pressure, fluid_prim::temperature}, - imap); + auto v = rc->PackVariables( + {fluid_prim::density, fluid_prim::velocity, fluid_prim::energy, fluid_prim::bfield, + fluid_prim::ye, fluid_prim::pressure, fluid_prim::temperature, fluid_prim::gamma1}, + imap); const int irho = imap[fluid_prim::density].first; const int ivlo = imap[fluid_prim::velocity].first; @@ -45,6 +45,7 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { const int iye = imap[fluid_prim::ye].second; const int iprs = imap[fluid_prim::pressure].first; const int itmp = imap[fluid_prim::temperature].first; + const int igm1 = imap[fluid_prim::gamma1].first; const Real rhoa = pin->GetOrAddReal("sedov", "rho_ambient", 1.0); const Real rinner = pin->GetOrAddReal("sedov", "rinner", 0.01); @@ -99,6 +100,9 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { v(iprs, k, j, i) = P; v(ieng, k, j, i) = u; v(itmp, k, j, i) = T; + v(igm1, k, j, i) = eos.BulkModulusFromDensityTemperature( + v(irho, k, j, i), v(itmp, k, j, i), lambda) / + v(iprs, k, j, i); for (int d = ivlo; d <= ivhi; d++) v(d, k, j, i) = 0.0; }); diff --git a/src/pgen/shock_tube.cpp b/src/pgen/shock_tube.cpp index 440d3367..1a762a11 100644 --- a/src/pgen/shock_tube.cpp +++ b/src/pgen/shock_tube.cpp @@ -35,10 +35,10 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { auto &rc = pmb->meshblock_data.Get(); PackIndexMap imap; - auto v = rc->PackVariables({fluid_prim::density, fluid_prim::velocity, - fluid_prim::energy, fluid_prim::bfield, fluid_prim::ye, - fluid_prim::pressure, fluid_prim::temperature}, - imap); + auto v = rc->PackVariables( + {fluid_prim::density, fluid_prim::velocity, fluid_prim::energy, fluid_prim::bfield, + fluid_prim::ye, fluid_prim::pressure, fluid_prim::temperature, fluid_prim::gamma1}, + imap); const int irho = imap[fluid_prim::density].first; const int ivlo = imap[fluid_prim::velocity].first; @@ -49,6 +49,7 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { const int iye = imap[fluid_prim::ye].second; const int iprs = imap[fluid_prim::pressure].first; const int itmp = imap[fluid_prim::temperature].first; + const int igm1 = imap[fluid_prim::gamma1].first; const Real rhol = pin->GetOrAddReal("shocktube", "rhol", 1.0); const Real Pl = pin->GetOrAddReal("shocktube", "Pl", 1.0); @@ -93,6 +94,9 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { v(itmp, k, j, i) = eos.TemperatureFromDensityInternalEnergy( rho, v(ieng, k, j, i) / rho, lambda); // this doesn't have to be exact, just a reasonable guess + v(igm1, k, j, i) = eos.BulkModulusFromDensityTemperature( + v(irho, k, j, i), v(itmp, k, j, i), lambda) / + v(iprs, k, j, i); for (int d = 0; d < 3; d++) v(ivlo + d, k, j, i) = 0.0; v(ivlo, k, j, i) = vel; diff --git a/src/pgen/thin_cooling.cpp b/src/pgen/thin_cooling.cpp index 19011f59..180b847c 100644 --- a/src/pgen/thin_cooling.cpp +++ b/src/pgen/thin_cooling.cpp @@ -32,7 +32,8 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { PackIndexMap imap; auto v = rc->PackVariables( - {p::density, p::velocity, p::energy, p::ye, p::pressure, p::temperature}, imap); + {p::density, p::velocity, p::energy, p::ye, p::pressure, p::temperature, p::gamma1}, + imap); const int irho = imap[p::density].first; const int ivlo = imap[p::velocity].first; @@ -41,6 +42,7 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { const int iye = imap[p::ye].second; const int iprs = imap[p::pressure].first; const int itmp = imap[p::temperature].first; + const int igm1 = imap[p::gamma1].first; IndexRange ib = pmb->cellbounds.GetBoundsI(IndexDomain::entire); IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::entire); @@ -77,6 +79,9 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { v(itmp, k, j, i) = eos.TemperatureFromDensityInternalEnergy(rho0, u0 / rho0, lambda); v(iprs, k, j, i) = eos.PressureFromDensityInternalEnergy(rho0, u0 / rho0, lambda); + v(igm1, k, j, i) = eos.BulkModulusFromDensityTemperature( + v(irho, k, j, i), v(itmp, k, j, i), lambda) / + v(iprs, k, j, i); v(iye, k, j, i) = 0.5; // TODO(BRR) change depending on species for (int d = 0; d < 3; d++) diff --git a/src/pgen/torus.cpp b/src/pgen/torus.cpp index ce452b68..9218affd 100644 --- a/src/pgen/torus.cpp +++ b/src/pgen/torus.cpp @@ -29,11 +29,44 @@ #include "phoebus_utils/reduction.hpp" #include "phoebus_utils/relativity_utils.hpp" #include "phoebus_utils/robust.hpp" +#include "phoebus_utils/root_find.hpp" +#include "radiation/radiation.hpp" typedef Kokkos::Random_XorShift64_Pool<> RNGPool; namespace torus { +using pc = parthenon::constants::PhysicalConstants; + +using namespace radiation; +using singularity::EOS; +using namespace singularity::neutrinos; + +class GasRadTemperatureResidual { + public: + KOKKOS_FUNCTION + GasRadTemperatureResidual(const Real Ptot, const Real rho, const Opacity &opac, + const EOS &eos, RadiationType type, const Real Ye) + : Ptot_(Ptot), rho_(rho), opac_(opac), eos_(eos), type_(type), Ye_(Ye) {} + + KOKKOS_INLINE_FUNCTION + Real operator()(const Real T) { + Real lambda[2] = {Ye_, 0.0}; + return Ptot_ - (4. / 3. - 1.) * opac_.EnergyDensityFromTemperature(T, type_) - + eos_.PressureFromDensityTemperature(rho_, T, lambda); + } + + private: + const Real Ptot_; + const Real rho_; + const Opacity &opac_; + const EOS &eos_; + const RadiationType type_; + const Real Ye_; +}; + +enum class InitialRadiation { none, thermal }; + // Prototypes // ---------------------------------------------------------------------- KOKKOS_FUNCTION @@ -54,10 +87,14 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { auto rc = pmb->meshblock_data.Get().get(); + auto rad_pkg = pmb->packages.Get("radiation"); + bool do_rad = rad_pkg->Param("active"); + PackIndexMap imap; auto v = rc->PackVariables({fluid_prim::density, fluid_prim::velocity, fluid_prim::energy, fluid_prim::bfield, fluid_prim::ye, - fluid_prim::pressure, fluid_prim::temperature}, + fluid_prim::pressure, fluid_prim::temperature, + fluid_prim::gamma1, radmoment_prim::J, radmoment_prim::H}, imap); const int irho = imap[fluid_prim::density].first; @@ -69,6 +106,11 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { const int iye = imap[fluid_prim::ye].second; const int iprs = imap[fluid_prim::pressure].first; const int itmp = imap[fluid_prim::temperature].first; + const int igm1 = imap[fluid_prim::gamma1].first; + + auto iJ = imap.GetFlatIdx(radmoment_prim::J, false); + auto iH = imap.GetFlatIdx(radmoment_prim::H, false); + const auto specB = iJ.IsValid() ? iJ.GetBounds(1) : parthenon::IndexRange(); // this only works with ideal gases // The Fishbone solver needs to know about Ye @@ -103,6 +145,33 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { auto geom = Geometry::GetCoordinateSystem(rc); + // TODO(BRR) Make this an input parameter + InitialRadiation init_rad = InitialRadiation::thermal; + + StateDescriptor *opac = pmb->packages.Get("opacity").get(); + Opacity d_opacity; + std::vector species; + int num_species = 0; + RadiationType species_d[MaxNumRadiationSpecies] = {}; + if (do_rad) { + d_opacity = opac->Param("d.opacity"); + const std::string init_rad_str = + pin->GetOrAddString("torus", "initial_radiation", "None"); + if (init_rad_str == "None") { + init_rad = InitialRadiation::none; + } else if (init_rad_str == "thermal") { + init_rad = InitialRadiation::thermal; + } else { + PARTHENON_FAIL("\"torus/initial_radiation\" not recognized!"); + } + + species = rad_pkg->Param>("species"); + num_species = rad_pkg->Param("num_species"); + for (int s = 0; s < num_species; s++) { + species_d[s] = species[s]; + } + } + // set up transformation stuff auto gpkg = pmb->packages.Get("geometry"); bool derefine_poles = gpkg->Param("derefine_poles"); @@ -197,6 +266,72 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { v(irho, k, j, i), v(ieng, k, j, i) / v(irho, k, j, i), lambda); v(iprs, k, j, i) = eos.PressureFromDensityTemperature(v(irho, k, j, i), v(itmp, k, j, i), lambda); + v(igm1, k, j, i) = eos.BulkModulusFromDensityTemperature( + v(irho, k, j, i), v(itmp, k, j, i), lambda) / + v(iprs, k, j, i); + + Real ucon[4] = {0}; + Real vpcon[3] = {v(ivlo, k, j, i), v(ivlo + 1, k, j, i), v(ivlo + 2, k, j, i)}; + Real gcov[4][4] = {0}; + geom.SpacetimeMetric(CellLocation::Cent, k, j, i, gcov); + GetFourVelocity(vpcon, geom, CellLocation::Cent, k, j, i, ucon); + + // Radiation + if (do_rad) { + + Real r = tr.bl_radius(x1v); + Real th = tr.bl_theta(x1v, x2v); + Real lnh = -1.0; + Real uphi; + if (r > rin) lnh = log_enthalpy(r, th, a, rin, angular_mom, uphi); + + // Set radiation inside the disk according to the Fishbone gas solution + if (lnh > 0.0) { + + // TODO(BRR) only first species right now + for (int ispec = specB.s; ispec < 1; ispec++) { + // Given total pressure, calculate temperature such that fluid and radiation + // pressures sum to total pressure + // TODO(BRR) Generalize to all neutrino species + const Real Ptot = v(iprs, k, j, i); + const Real T = v(itmp, k, j, i); + const Real Ye = iye > 0 ? v(iye, k, j, i) : 0.5; + + if (init_rad == InitialRadiation::thermal) { + root_find::RootFind root_find; + GasRadTemperatureResidual res(v(iprs, k, j, i), v(irho, k, j, i), + d_opacity, eos, species_d[ispec], Ye); + v(itmp, k, j, i) = root_find.secant(res, 0, T, 1.e-6 * T, T); + } + + // Set fluid u/P/T and radiation J using equilibrium temperature + Real lambda[2] = {Ye, 0.0}; + v(ieng, k, j, i) = + v(irho, k, j, i) * eos.InternalEnergyFromDensityTemperature( + v(irho, k, j, i), v(itmp, k, j, i), lambda); + v(iprs, k, j, i) = eos.PressureFromDensityTemperature( + v(irho, k, j, i), v(itmp, k, j, i), lambda); + + if (init_rad == InitialRadiation::thermal) { + v(iJ(ispec), k, j, i) = d_opacity.EnergyDensityFromTemperature( + v(itmp, k, j, i), species_d[ispec]); + } else { + v(iJ(ispec), k, j, i) = 1.e-5 * v(ieng, k, j, i); + } + + // Zero comoving frame fluxes + SPACELOOP(ii) { v(iH(ispec, 0), k, j, i) = 0.; } + } + } else { + // In the atmosphere set some small radiation energy + for (int ispec = specB.s; ispec < 1; ispec++) { + v(iJ(ispec), k, j, i) = 1.e-5 * v(ieng, k, j, i); + + // Zero comoving frame fluxes + SPACELOOP(ii) { v(iH(ispec, 0), k, j, i) = 0.; } + } + } + } rng_pool.free_state(rng_gen); }); @@ -238,6 +373,11 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { } fluid::PrimitiveToConserved(rc); + if (do_rad) { + radiation::MomentPrim2Con(rc); + } + + fixup::ApplyFloors(rc); } void ProblemModifier(ParameterInput *pin) { @@ -268,10 +408,23 @@ void ProblemModifier(ParameterInput *pin) { "\tThis translates to x1min, x1max = %g %g\n", std::exp(x1min), x1min, x1max); } + + // Set Cv properly for radiation + const bool do_rad = pin->GetOrAddBoolean("physics", "rad", false); + if (do_rad) { + const std::string eos_type = pin->GetString("eos", "type"); + if (eos_type == "IdealGas") { + const Real Gamma = pin->GetReal("eos", "Gamma"); + const Real cv = (Gamma - 1.) * pc::kb / pc::mp; + pin->SetReal("eos", "Cv", cv); + } else { + PARTHENON_FAIL( + "eos_type not supported for initializing radiation torus currently!"); + } + } } void PostInitializationModifier(ParameterInput *pin, Mesh *pmesh) { - const bool magnetized = pin->GetOrAddBoolean("torus", "magnetized", true); const Real beta_target = pin->GetOrAddReal("torus", "target_beta", 100.); const bool harm_style_beta = @@ -404,9 +557,10 @@ void ComputeBetas(Mesh *pmesh, Real rho_min_bnorm, Real &beta_min_global, auto kb = pmb->cellbounds.GetBoundsK(IndexDomain::interior); PackIndexMap imap; - auto v = rc->PackVariables({fluid_prim::density, fluid_prim::velocity, - fluid_prim::bfield, fluid_prim::pressure}, - imap); + auto v = + rc->PackVariables({fluid_prim::density, fluid_prim::velocity, fluid_prim::bfield, + fluid_prim::pressure, radmoment_prim::J}, + imap); const int irho = imap[fluid_prim::density].first; const int ivlo = imap[fluid_prim::velocity].first; @@ -415,6 +569,8 @@ void ComputeBetas(Mesh *pmesh, Real rho_min_bnorm, Real &beta_min_global, const int ibhi = imap[fluid_prim::bfield].second; const int iprs = imap[fluid_prim::pressure].first; + auto idx_J = imap.GetFlatIdx(radmoment_prim::J, false); + if (ibhi < 0) return; Real beta_min_local; @@ -424,6 +580,12 @@ void ComputeBetas(Mesh *pmesh, Real rho_min_bnorm, Real &beta_min_global, KOKKOS_LAMBDA(const int k, const int j, const int i, Real &beta_min) { const Real bsq = GetMagneticFieldSquared(CellLocation::Cent, k, j, i, geom, v, ivlo, iblo); + Real Ptot = v(iprs, k, j, i); + // TODO(BRR) multiple species + if (idx_J.IsValid()) { + int ispec = 0; + Ptot += 1. / 3. * v(idx_J(ispec), k, j, i); + } const Real beta = robust::ratio(v(iprs, k, j, i), 0.5 * bsq); if (v(irho, k, j, i) > rho_min_bnorm && beta < beta_min) beta_min = beta; }, diff --git a/src/pgen/tov.cpp b/src/pgen/tov.cpp index e76dc1cc..36ca4c38 100644 --- a/src/pgen/tov.cpp +++ b/src/pgen/tov.cpp @@ -71,10 +71,10 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { auto geom = Geometry::GetCoordinateSystem(rc.get()); PackIndexMap imap; - auto v = rc->PackVariables({fluid_prim::density, fluid_prim::velocity, - fluid_prim::energy, fluid_prim::bfield, fluid_prim::ye, - fluid_prim::pressure, fluid_prim::temperature}, - imap); + auto v = rc->PackVariables( + {fluid_prim::density, fluid_prim::velocity, fluid_prim::energy, fluid_prim::bfield, + fluid_prim::ye, fluid_prim::pressure, fluid_prim::temperature, fluid_prim::gamma1}, + imap); const int irho = imap[fluid_prim::density].first; const int ivlo = imap[fluid_prim::velocity].first; @@ -85,6 +85,7 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { const int iye = imap[fluid_prim::ye].second; const int iprs = imap[fluid_prim::pressure].first; const int itmp = imap[fluid_prim::temperature].first; + const int igm1 = imap[fluid_prim::gamma1].first; pmb->par_for( "Phoebus::ProblemGenerator::TOV", kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, @@ -109,6 +110,9 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { v(iprs, k, j, i) = P; v(ieng, k, j, i) = eps * rho; v(itmp, k, j, i) = eos.TemperatureFromDensityInternalEnergy(rho, eps); + v(igm1, k, j, i) = + eos.BulkModulusFromDensityTemperature(v(irho, k, j, i), v(itmp, k, j, i)) / + v(iprs, k, j, i); for (int d = 0; d < 3; ++d) { v(ivlo + d, k, j, i) = 0.0; } diff --git a/src/phoebus_boundaries/phoebus_boundaries.cpp b/src/phoebus_boundaries/phoebus_boundaries.cpp index 9a187955..e2e10844 100644 --- a/src/phoebus_boundaries/phoebus_boundaries.cpp +++ b/src/phoebus_boundaries/phoebus_boundaries.cpp @@ -97,6 +97,7 @@ void GenericBC(std::shared_ptr> &rc, bool coarse) { const Real detg_ref = geom.DetGamma(CellLocation::Cent, kref, jref, iref); const Real detg = geom.DetGamma(CellLocation::Cent, k, j, i); const Real gratio = robust::ratio(detg, detg_ref); + q(l, k, j, i) = sgn * gratio * q(l, kref, jref, iref); }); } @@ -111,12 +112,11 @@ void OutflowInnerX1(std::shared_ptr> &rc, bool coarse) { auto q = rc->PackVariables(std::vector{Metadata::FillGhost}, imap, coarse); auto nb = IndexRange{0, q.GetDim(4) - 1}; + // auto nb1 = IndexRange{0, 0}; auto domain = IndexDomain::inner_x1; - const int pv_lo = imap[fluid_prim::velocity].first; - - auto &pkg = rc->GetParentPointer()->packages.Get("fluid"); - std::string bc_vars = pkg->Param("bc_vars"); + auto &fluid = rc->GetParentPointer()->packages.Get("fluid"); + std::string bc_vars = fluid->Param("bc_vars"); if (bc_vars == "conserved") { pmb->par_for_bndry( @@ -132,28 +132,6 @@ void OutflowInnerX1(std::shared_ptr> &rc, bool coarse) { "OutflowInnerX1Prim", nb, domain, coarse, KOKKOS_LAMBDA(const int &l, const int &k, const int &j, const int &i) { q(l, k, j, i) = q(l, k, j, ref); - - // Enforce u^1 <= 0 - Real vcon[3] = {q(pv_lo, k, j, i), q(pv_lo + 1, k, j, i), - q(pv_lo + 2, k, j, i)}; - Real gammacov[3][3]; - geom.Metric(CellLocation::Cent, k, j, i, gammacov); - Real W = phoebus::GetLorentzFactor(vcon, gammacov); - const Real alpha = geom.Lapse(CellLocation::Cent, k, j, i); - Real beta[3]; - geom.ContravariantShift(CellLocation::Cent, k, j, i, beta); - - Real ucon1 = vcon[0] - W * beta[0] / alpha; - - if (ucon1 > 0) { - SPACELOOP(ii) { vcon[ii] /= W; } - vcon[0] = beta[0] / alpha; - Real vsq = 0.; - SPACELOOP2(ii, jj) { vsq += gammacov[ii][jj] * vcon[ii] * vcon[jj]; } - W = 1. / sqrt(1. - vsq); - - SPACELOOP(ii) { q(pv_lo + ii, k, j, i) = W * vcon[ii]; } - } }); } } @@ -168,12 +146,17 @@ void OutflowOuterX1(std::shared_ptr> &rc, bool coarse) { auto q = rc->PackVariables(std::vector{Metadata::FillGhost}, imap, coarse); auto nb = IndexRange{0, q.GetDim(4) - 1}; + auto nb1 = IndexRange{0, 0}; + auto domain = IndexDomain::outer_x1; const int pv_lo = imap[fluid_prim::velocity].first; + auto idx_H = imap.GetFlatIdx(radmoment_prim::H, false); - auto &pkg = rc->GetParentPointer()->packages.Get("fluid"); - std::string bc_vars = pkg->Param("bc_vars"); + auto &fluid = rc->GetParentPointer()->packages.Get("fluid"); + auto &rad = rc->GetParentPointer()->packages.Get("radiation"); + std::string bc_vars = fluid->Param("bc_vars"); + const int num_species = rad->Param("active") ? rad->Param("num_species") : 0; if (bc_vars == "conserved") { pmb->par_for_bndry( @@ -189,28 +172,6 @@ void OutflowOuterX1(std::shared_ptr> &rc, bool coarse) { "OutflowOuterX1Prim", nb, domain, coarse, KOKKOS_LAMBDA(const int &l, const int &k, const int &j, const int &i) { q(l, k, j, i) = q(l, k, j, ref); - - // Enforce u^1 >= 0 - Real vcon[3] = {q(pv_lo, k, j, i), q(pv_lo + 1, k, j, i), - q(pv_lo + 2, k, j, i)}; - Real gammacov[3][3]; - geom.Metric(CellLocation::Cent, k, j, i, gammacov); - Real W = phoebus::GetLorentzFactor(vcon, gammacov); - const Real alpha = geom.Lapse(CellLocation::Cent, k, j, i); - Real beta[3]; - geom.ContravariantShift(CellLocation::Cent, k, j, i, beta); - - Real ucon1 = vcon[0] - W * beta[0] / alpha; - - if (ucon1 < 0) { - SPACELOOP(ii) { vcon[ii] /= W; } - vcon[0] = beta[0] / alpha; - Real vsq = 0.; - SPACELOOP2(ii, jj) { vsq += gammacov[ii][jj] * vcon[ii] * vcon[jj]; } - W = 1. / sqrt(1. - vsq); - - SPACELOOP(ii) { q(pv_lo + ii, k, j, i) = W * vcon[ii]; } - } }); } } @@ -256,7 +217,6 @@ void ReflectOuterX3(std::shared_ptr> &rc, bool coarse) { } TaskStatus ConvertBoundaryConditions(std::shared_ptr> &rc) { - auto pmb = rc->GetBlockPointer(); const int ndim = pmb->pmy_mesh->ndim; @@ -271,25 +231,127 @@ TaskStatus ConvertBoundaryConditions(std::shared_ptr> &rc) { } auto &pkg = rc->GetParentPointer()->packages.Get("fluid"); + auto &pkg_rad = rc->GetParentPointer()->packages.Get("radiation"); + auto &pkg_fix = rc->GetParentPointer()->packages.Get("fixup"); + std::string bc_vars = pkg->Param("bc_vars"); + + // Apply inflow check to ox1 for BH problem at simulation BC only + const bool enable_ox1_fmks_inflow_check = + pkg_fix->Param("enable_ox1_fmks_inflow_check"); + if (typeid(PHOEBUS_GEOMETRY) == typeid(Geometry::FMKS) && + enable_ox1_fmks_inflow_check && + pmb->boundary_flag[1] != parthenon::BoundaryFlag::block) { + + const IndexDomain domain = IndexDomain::outer_x1; + IndexRange ib = rc->GetBoundsI(domain); + IndexRange jb = rc->GetBoundsJ(domain); + IndexRange kb = rc->GetBoundsK(domain); + + if (bc_vars == "conserved") { + // Just call C2P everywhere instead of 6 different kernels + fluid::ConservedToPrimitiveRegion(rc.get(), ib, jb, kb); + } + + // Inflow check and then p2c + std::shared_ptr pmb = rc->GetBlockPointer(); + auto geom = Geometry::GetCoordinateSystem(rc.get()); + + // TODO(BRR) Is this always true? + const bool coarse = false; + + PackIndexMap imap; + std::vector vars{fluid_prim::velocity, radmoment_prim::H}; + auto q = rc->PackVariables(vars, imap, coarse); + auto nb1 = IndexRange{0, 0}; + + const int pv_lo = imap[fluid_prim::velocity].first; + auto idx_H = imap.GetFlatIdx(radmoment_prim::H, false); + + const int num_species = + pkg_rad->Param("active") ? pkg_rad->Param("num_species") : 0; + pmb->par_for_bndry( + "OutflowOuterX1PrimFixup", nb1, domain, coarse, + KOKKOS_LAMBDA(const int &dummy, const int &k, const int &j, const int &i) { + // Enforce u^1 >= 0 + Real vcon[3] = {q(pv_lo, k, j, i), q(pv_lo + 1, k, j, i), + q(pv_lo + 2, k, j, i)}; + Real gammacov[3][3]; + geom.Metric(CellLocation::Cent, k, j, i, gammacov); + Real W = phoebus::GetLorentzFactor(vcon, gammacov); + const Real alpha = geom.Lapse(CellLocation::Cent, k, j, i); + Real beta[3]; + geom.ContravariantShift(CellLocation::Cent, k, j, i, beta); + + Real ucon1 = vcon[0] - W * beta[0] / alpha; + + if (ucon1 < 0) { + SPACELOOP(ii) { vcon[ii] /= W; } + vcon[0] = beta[0] / alpha; + Real vsq = 0.; + SPACELOOP2(ii, jj) { vsq += gammacov[ii][jj] * vcon[ii] * vcon[jj]; } + W = 1. / sqrt(1. - vsq); + + SPACELOOP(ii) { q(pv_lo + ii, k, j, i) = W * vcon[ii]; } + } + + // No flux of radiation into the simulation + if (idx_H.IsValid()) { + Real gammacon[3][3]; + geom.MetricInverse(CellLocation::Cent, k, j, i, gammacon); + for (int ispec = 0; ispec < num_species; ispec++) { + Real Hcon[3] = {0}; + SPACELOOP2(ii, jj) { + Hcon[ii] += gammacon[ii][jj] * q(idx_H(ispec, jj), k, j, i); + } + if (Hcon[0] < 0.) { + Hcon[0] = 0.; + + // Check xi + Real xi = 0.; + SPACELOOP2(ii, jj) { xi += gammacov[ii][jj] * Hcon[ii] * Hcon[jj]; } + xi = std::sqrt(xi); + if (xi > 0.99) { + SPACELOOP(ii) { Hcon[ii] *= 0.99 / xi; } + } + + SPACELOOP(ii) { + q(idx_H(ispec, ii), k, j, i) = 0.; + SPACELOOP(jj) { + q(idx_H(ispec, ii), k, j, i) += gammacov[ii][jj] * Hcon[jj]; + } + } + } + } + } + }); + + fluid::PrimitiveToConservedRegion(rc.get(), ib, jb, kb); + } + if (pkg->Param("active")) { - std::string bc_vars = pkg->Param("bc_vars"); if (bc_vars == "primitive") { // auto c2p = pkg->Param("c2p_func"); - for (auto &domain : domains) { - IndexRange ib = rc->GetBoundsI(domain); - IndexRange jb = rc->GetBoundsJ(domain); - IndexRange kb = rc->GetBoundsK(domain); - fluid::PrimitiveToConservedRegion(rc.get(), ib, jb, kb); + for (int n = 0; n < domains.size(); n++) { + if (pmb->boundary_flag[n] != parthenon::BoundaryFlag::block) { + const auto &domain = domains[n]; + IndexRange ib = rc->GetBoundsI(domain); + IndexRange jb = rc->GetBoundsJ(domain); + IndexRange kb = rc->GetBoundsK(domain); + fluid::PrimitiveToConservedRegion(rc.get(), ib, jb, kb); + } } } } - auto &pkg_rad = rc->GetParentPointer()->packages.Get("radiation"); if (pkg_rad->Param("active")) { - std::string bc_vars = pkg_rad->Param("bc_vars"); + // Fluid and rad always have same value + // std::string bc_vars = pkg_rad->Param("bc_vars"); if (bc_vars == "primitive") { - for (auto &domain : domains) { - radiation::MomentPrim2Con(rc.get(), domain); + for (int n = 0; n < domains.size(); n++) { + if (pmb->boundary_flag[n] != parthenon::BoundaryFlag::block) { + const auto &domain = domains[n]; + radiation::MomentPrim2Con(rc.get(), domain); + } } } } diff --git a/src/phoebus_driver.cpp b/src/phoebus_driver.cpp index 7eac33b7..80f68818 100644 --- a/src/phoebus_driver.cpp +++ b/src/phoebus_driver.cpp @@ -105,18 +105,22 @@ void PhoebusDriver::PostInitializationCommunication() { auto fluid = pmesh->packages.Get("fluid"); const bool rad_active = rad->Param("active"); const bool fluid_active = fluid->Param("active"); - bool rad_moments_active = false; - bool rad_mocmc_active = false; - if (rad_active) { - rad_moments_active = rad->Param("moments_active"); - rad_mocmc_active = (rad->Param("method") == "mocmc"); - } const int num_partitions = pmesh->DefaultNumPartitions(); - TaskRegion &sync_region = tc.AddRegion(num_partitions); + + TaskRegion &async_region_1 = tc.AddRegion(blocks.size()); + for (int ib = 0; ib < blocks.size(); ib++) { + auto pmb = blocks[ib].get(); + auto &tl = async_region_1[ib]; + auto &sc = pmb->meshblock_data.Get(); + auto apply_floors = + tl.AddTask(none, fixup::ApplyFloors>, sc.get()); + } + + TaskRegion &sync_region_1 = tc.AddRegion(num_partitions); for (int ib = 0; ib < num_partitions; ib++) { auto &md = pmesh->mesh_data.GetOrAdd("base", ib); - auto &tl = sync_region[ib]; + auto &tl = sync_region_1[ib]; const auto any = parthenon::BoundaryType::any; const auto local = parthenon::BoundaryType::local; @@ -145,10 +149,10 @@ void PhoebusDriver::PostInitializationCommunication() { } } - TaskRegion &async_region = tc.AddRegion(blocks.size()); - for (int ib = 0; ib < blocks.size(); ib++) { - auto pmb = blocks[ib].get(); - auto &tl = async_region[ib]; + TaskRegion &async_region_2 = tc.AddRegion(blocks.size()); + for (int i = 0; i < blocks.size(); i++) { + auto &pmb = blocks[i]; + auto &tl = async_region_2[i]; auto &sc = pmb->meshblock_data.Get(); auto prolongBound = tl.AddTask(none, parthenon::ProlongateBoundaries, sc); @@ -157,10 +161,8 @@ void PhoebusDriver::PostInitializationCommunication() { auto convert_bc = tl.AddTask(set_bc, Boundaries::ConvertBoundaryConditions, sc); - // Radiation should actually be included in ConvertBoundaryConditions - // using MDT = std::remove_pointer::type; - // auto momentp2c = tl.AddTask(convert_bc, radiation::MomentPrim2Con, sc.get(), - // IndexDomain::entire); + auto fill_derived = tl.AddTask( + convert_bc, parthenon::Update::FillDerived>, sc.get()); } tc.Execute(); @@ -242,36 +244,40 @@ TaskCollection PhoebusDriver::RungeKuttaStage(const int stage) { } bool time_dependent_geom = geom_params.Get("time_dependent", false); - // First we need to make all the meshblock-level containers + const int num_partitions = pmesh->DefaultNumPartitions(); + + const auto any = parthenon::BoundaryType::any; + const auto local = parthenon::BoundaryType::local; + const auto nonlocal = parthenon::BoundaryType::nonlocal; + if (stage == 1) { - for (int i = 0; i < blocks.size(); ++i) { + for (int i = 0; i < blocks.size(); i++) { auto &pmb = blocks[i]; auto &base = pmb->meshblock_data.Get(); pmb->meshblock_data.Add("dUdt", base); - for (int i = 1; i < integrator->nstages; i++) { - pmb->meshblock_data.Add(stage_name[i], base); - pmb->meshblock_data.Add("geometric source terms", base, src_w_diag); + pmb->meshblock_data.Add("geometric source terms", base, src_w_diag); + for (int s = 1; s < integrator->nstages; s++) { + pmb->meshblock_data.Add(stage_name[s], base); } } } + const auto num_independent_task_lists = blocks.size(); + // be ready for flux corrections and boundary comms - const int num_partitions = pmesh->DefaultNumPartitions(); - TaskRegion &sync_region_0 = tc.AddRegion(num_partitions); + TaskRegion &sync_region_1 = tc.AddRegion(num_partitions); for (int ib = 0; ib < num_partitions; ++ib) { auto &base = pmesh->mesh_data.GetOrAdd("base", ib); auto &sc0 = pmesh->mesh_data.GetOrAdd(stage_name[stage - 1], ib); auto &sc1 = pmesh->mesh_data.GetOrAdd(stage_name[stage], ib); - auto &tl = sync_region_0[ib]; + auto &tl = sync_region_1[ib]; - const auto any = parthenon::BoundaryType::any; tl.AddTask(none, parthenon::cell_centered_bvars::StartReceiveBoundBufs, sc1); if (pmesh->multilevel) { tl.AddTask(none, parthenon::cell_centered_bvars::StartReceiveFluxCorrections, sc0); } } - auto num_independent_task_lists = blocks.size(); TaskRegion &async_region_1 = tc.AddRegion(num_independent_task_lists); for (int ib = 0; ib < num_independent_task_lists; ib++) { auto pmb = blocks[ib].get(); @@ -293,7 +299,6 @@ TaskCollection PhoebusDriver::RungeKuttaStage(const int stage) { if (fluid_active) { auto hydro_flux = tl.AddTask(none, fluid::CalculateFluxes, sc0.get()); - auto fix_flux = tl.AddTask(hydro_flux, fixup::FixFluxes, sc0.get()); auto hydro_flux_ct = tl.AddTask(hydro_flux, fluid::FluxCT, sc0.get()); auto hydro_geom_src = tl.AddTask(none, fluid::CalculateFluidSourceTerms, sc0.get(), gsrc.get()); @@ -316,6 +321,11 @@ TaskCollection PhoebusDriver::RungeKuttaStage(const int stage) { geom_src = geom_src | moment_geom_src; } + if (rad_moments_active || fluid_active) { + auto fix_flux = tl.AddTask(sndrcv_flux_depend, fixup::FixFluxes, sc0.get()); + sndrcv_flux_depend = sndrcv_flux_depend | fix_flux; + } + if (rad_mocmc_active) { using MDT = std::remove_pointer::type; // TODO(BRR) stage_name[stage - 1]? @@ -337,55 +347,14 @@ TaskCollection PhoebusDriver::RungeKuttaStage(const int stage) { } } - if (rad_mocmc_active && stage == integrator->nstages) { - TaskRegion &tuning_region = tc.AddRegion(num_independent_task_lists); - { - particle_resolution.val.resize(1); // total - for (int i = 0; i < particle_resolution.val.size(); i++) { - particle_resolution.val[i] = 0.; - } - int reg_dep_id = 0; - auto &tl = tuning_region[0]; - - auto update_count = tl.AddTask(none, radiation::MOCMCUpdateParticleCount, pmesh, - &particle_resolution.val); - - tuning_region.AddRegionalDependencies(reg_dep_id, 0, update_count); - reg_dep_id++; - - auto start_count_reduce = - tl.AddTask(update_count, &AllReduce>::StartReduce, - &particle_resolution, MPI_SUM); - - auto finish_count_reduce = - tl.AddTask(start_count_reduce, &AllReduce>::CheckReduce, - &particle_resolution); - tuning_region.AddRegionalDependencies(reg_dep_id, 0, finish_count_reduce); - reg_dep_id++; - - // Report particle count - auto report_count = - (Globals::my_rank == 0 ? tl.AddTask( - finish_count_reduce, - [](std::vector *res) { - std::cout << "MOCMC total particles = " - << static_cast((*res)[0]) - << std::endl; - return TaskStatus::complete; - }, - &particle_resolution.val) - : none); - } - } - - TaskRegion &sync_region = tc.AddRegion(num_partitions); + TaskRegion &sync_region_2 = tc.AddRegion(num_partitions); for (int ib = 0; ib < num_partitions; ib++) { auto &base = pmesh->mesh_data.GetOrAdd("base", ib); auto &sc0 = pmesh->mesh_data.GetOrAdd(stage_name[stage - 1], ib); auto &sc1 = pmesh->mesh_data.GetOrAdd(stage_name[stage], ib); auto &dudt = pmesh->mesh_data.GetOrAdd("dUdt", ib); + auto &tl = sync_region_2[ib]; auto &gsrc = pmesh->mesh_data.GetOrAdd("geometric source terms", ib); - auto &tl = sync_region[ib]; int reg_dep_id = 0; using MDT = std::remove_pointer::type; @@ -398,56 +367,15 @@ TaskCollection PhoebusDriver::RungeKuttaStage(const int stage) { if (monopole_gr_active) { auto interp_to_monopole = tl.AddTask(none, MonopoleGR::InterpolateMatterTo1D, sc0.get()); - sync_region.AddRegionalDependencies(reg_dep_id++, ib, interp_to_monopole); - } - - // fluxes now sent/received in mesh-data. - auto send_flux = - tl.AddTask(none, parthenon::cell_centered_bvars::LoadAndSendFluxCorrections, sc0); - auto recv_flux = - tl.AddTask(none, parthenon::cell_centered_bvars::ReceiveFluxCorrections, sc0); - auto set_flux = - tl.AddTask(recv_flux, parthenon::cell_centered_bvars::SetFluxCorrections, sc0); - - // compute the divergence of fluxes of conserved variables - auto flux_div = - tl.AddTask(set_flux, parthenon::Update::FluxDivergence>, sc0.get(), - dudt.get()); + sync_region_2.AddRegionalDependencies(reg_dep_id++, ib, interp_to_monopole); -#if SET_FLUX_SRC_DIAGS - auto copy_flux_div = - tl.AddTask(flux_div, fluid::CopyFluxDivergence>, dudt.get()); -#endif - - auto add_rhs = tl.AddTask(flux_div, SumData>, src_names, - dudt.get(), gsrc.get(), dudt.get()); - - // update step - auto avg_data = tl.AddTask(add_rhs, AverageIndependentData>, sc0.get(), - base.get(), beta); - auto update = tl.AddTask(avg_data, UpdateIndependentData>, sc0.get(), - dudt.get(), beta * dt, sc1.get()); - - if (rad_mocmc_active) { - auto impl_update = tl.AddTask(update, radiation::MOCMCFluidSource>, - sc1.get(), beta * dt, fluid_active); - auto impl_edd = - tl.AddTask(impl_update, radiation::MOCMCEddington>, sc1.get()); - update = impl_update | update; - } else if (rad_moments_active) { - auto impl_update = tl.AddTask(update, radiation::MomentFluidSource>, - sc1.get(), beta * dt, fluid_active); - update = impl_update | update; - } - - // TODO(JMM): Is this the right place for this? - // TODO(JMM): Should this stuff be in the synchronous region? - if (monopole_gr_active) { + // TODO(JMM): Is this the right place for this? + // TODO(JMM): Should this stuff be in the synchronous region? auto matter_to_host = (ib == 0 ? tl.AddTask(interp_to_monopole, MonopoleGR::MatterToHost, monopole.get(), true) : none); - sync_region.AddRegionalDependencies(reg_dep_id++, ib, matter_to_host); + sync_region_2.AddRegionalDependencies(reg_dep_id++, ib, matter_to_host); auto start_reduce_matter = (ib == 0 ? tl.AddTask(matter_to_host, &MonoMatRed_t::StartReduce, pmono_mat_red, MPI_SUM) @@ -458,10 +386,10 @@ TaskCollection PhoebusDriver::RungeKuttaStage(const int stage) { : none); auto finish_reduce_matter = tl.AddTask(start_reduce_matter, &MonoMatRed_t::CheckReduce, pmono_mat_red); - sync_region.AddRegionalDependencies(reg_dep_id++, ib, finish_reduce_matter); + sync_region_2.AddRegionalDependencies(reg_dep_id++, ib, finish_reduce_matter); auto finish_reduce_vols = tl.AddTask(start_reduce_vols, &MonoVolRed_t::CheckReduce, pmono_vol_red); - sync_region.AddRegionalDependencies(reg_dep_id++, ib, finish_reduce_vols); + sync_region_2.AddRegionalDependencies(reg_dep_id++, ib, finish_reduce_vols); auto finish_mono_reds = finish_reduce_matter | finish_reduce_vols; auto divide_vols = (ib == 0 ? tl.AddTask(finish_mono_reds, MonopoleGR::DivideVols, monopole.get()) @@ -483,74 +411,213 @@ TaskCollection PhoebusDriver::RungeKuttaStage(const int stage) { monopole.get(), tm.dt / 2) : none); } + } - // update ghost cells - const auto local = parthenon::BoundaryType::local; - const auto nonlocal = parthenon::BoundaryType::nonlocal; - auto send = - tl.AddTask(update, parthenon::cell_centered_bvars::SendBoundBufs, sc1); + // Communicate flux corrections and update independent data with fluxes and geometric + // sources + TaskRegion &sync_region_3 = tc.AddRegion(num_partitions); + for (int i = 0; i < num_partitions; i++) { + auto &tl = sync_region_3[i]; + auto &mbase = pmesh->mesh_data.GetOrAdd("base", i); + auto &mc0 = pmesh->mesh_data.GetOrAdd(stage_name[stage - 1], i); + auto &mc1 = pmesh->mesh_data.GetOrAdd(stage_name[stage], i); + auto &mdudt = pmesh->mesh_data.GetOrAdd("dUdt", i); + auto &mgsrc = pmesh->mesh_data.GetOrAdd("geometric source terms", i); - auto send_local = - tl.AddTask(update, parthenon::cell_centered_bvars::SendBoundBufs, sc1); - auto recv_local = - tl.AddTask(update, parthenon::cell_centered_bvars::ReceiveBoundBufs, sc1); - auto set_local = - tl.AddTask(recv_local, parthenon::cell_centered_bvars::SetBounds, sc1); + auto send_flux = + tl.AddTask(none, parthenon::cell_centered_bvars::LoadAndSendFluxCorrections, mc0); + auto recv_flux = + tl.AddTask(none, parthenon::cell_centered_bvars::ReceiveFluxCorrections, mc0); + auto set_flux = + tl.AddTask(recv_flux, parthenon::cell_centered_bvars::SetFluxCorrections, mc0); - auto recv = tl.AddTask( - update, parthenon::cell_centered_bvars::ReceiveBoundBufs, sc1); - auto set = tl.AddTask(recv, parthenon::cell_centered_bvars::SetBounds, sc1); + auto flux_div = + tl.AddTask(set_flux, parthenon::Update::FluxDivergence>, mc0.get(), + mdudt.get()); - if (pmesh->multilevel) { - tl.AddTask(set | set_local, - parthenon::cell_centered_refinement::RestrictPhysicalBounds, sc1.get()); - } +#if SET_FLUX_SRC_DIAGS + auto copy_flux_div = tl.AddTask( + flux_div /*| geom_src*/, fluid::CopyFluxDivergence>, mdudt.get()); +#endif + + auto add_rhs = tl.AddTask(flux_div, SumData>, src_names, + mdudt.get(), mgsrc.get(), mdudt.get()); + + auto avg_data = tl.AddTask(flux_div, AverageIndependentData>, + mc0.get(), mbase.get(), beta); + + auto update = tl.AddTask(avg_data, UpdateIndependentData>, mc0.get(), + mdudt.get(), beta * dt, mc1.get()); } + // Fix up flux failures TaskRegion &async_region_2 = tc.AddRegion(num_independent_task_lists); for (int ib = 0; ib < num_independent_task_lists; ib++) { auto pmb = blocks[ib].get(); auto &tl = async_region_2[ib]; + + // first make other useful containers + auto &base = pmb->meshblock_data.Get(); + + // pull out the container we'll use to get fluxes and/or compute RHSs auto &sc1 = pmb->meshblock_data.Get(stage_name[stage]); + using MDT = std::remove_pointer::type; - auto prolongBound = tl.AddTask(none, parthenon::ProlongateBoundaries, sc1); + // fill in derived fields + auto fill_derived = + tl.AddTask(none, parthenon::Update::FillDerived>, sc1.get()); - // set physical boundaries - auto set_bc = tl.AddTask(prolongBound, parthenon::ApplyBoundaryConditions, sc1); + auto fixup = tl.AddTask( + fill_derived, fixup::ConservedToPrimitiveFixup>, sc1.get()); - auto convert_bc = tl.AddTask(set_bc, Boundaries::ConvertBoundaryConditions, sc1); + auto radfixup = tl.AddTask( + fixup, fixup::RadConservedToPrimitiveFixup>, sc1.get()); + + auto floors = + tl.AddTask(radfixup, fixup::ApplyFloors>, sc1.get()); + + TaskID gas_rad_int(0); + if (rad_mocmc_active) { + auto impl_update = + tl.AddTask(floors, radiation::MOCMCFluidSource>, sc1.get(), + beta * dt, fluid_active); + auto impl_edd = tl.AddTask( + impl_update, radiation::MOCMCEddington>, sc1.get()); + gas_rad_int = gas_rad_int | impl_edd; + } else if (rad_moments_active) { + auto impl_update = + tl.AddTask(floors, radiation::MomentFluidSource>, sc1.get(), + beta * dt, fluid_active); + gas_rad_int = gas_rad_int | impl_update; + } + + if (rad_moments_active) { + // Fixup for interaction failures + auto src_fixup = + tl.AddTask(gas_rad_int, fixup::SourceFixup>, sc1.get()); + + // fill in derived fields after source update + auto fill_derived = tl.AddTask( + src_fixup, parthenon::Update::FillDerived>, sc1.get()); + + auto fixup = tl.AddTask( + fill_derived, fixup::ConservedToPrimitiveFixup>, sc1.get()); + + auto radfixup = tl.AddTask( + fixup, fixup::RadConservedToPrimitiveFixup>, sc1.get()); + + auto floors = + tl.AddTask(src_fixup, fixup::ApplyFloors>, sc1.get()); + } + } + + // Communicate (after applying stencil-based fixup) + TaskRegion &sync_region_4 = tc.AddRegion(num_partitions); + for (int ip = 0; ip < num_partitions; ip++) { + auto &tl = sync_region_4[ip]; + auto &mc1 = pmesh->mesh_data.GetOrAdd(stage_name[stage], ip); + + auto send_local = + tl.AddTask(none, parthenon::cell_centered_bvars::SendBoundBufs, mc1); + auto send_nonlocal = + tl.AddTask(none, parthenon::cell_centered_bvars::SendBoundBufs, mc1); + + auto recv_local = + tl.AddTask(none, parthenon::cell_centered_bvars::ReceiveBoundBufs, mc1); + auto recv_nonlocal = + tl.AddTask(none, parthenon::cell_centered_bvars::ReceiveBoundBufs, mc1); + + auto set_local = + tl.AddTask(recv_local, parthenon::cell_centered_bvars::SetBounds, mc1); + auto set_nonlocal = tl.AddTask( + recv_nonlocal, parthenon::cell_centered_bvars::SetBounds, mc1); + + if (pmesh->multilevel) { + tl.AddTask(set_nonlocal | set_local, + parthenon::cell_centered_refinement::RestrictPhysicalBounds, mc1.get()); + } + } + // TODO(BRR) loop this in thoughtfully! + TaskRegion &async_region_3 = tc.AddRegion(num_independent_task_lists); + for (int i = 0; i < blocks.size(); i++) { + auto &pmb = blocks[i]; + auto &tl = async_region_3[i]; + auto &sc = pmb->meshblock_data.Get(stage_name[stage]); + + auto prolongBound = tl.AddTask(none, parthenon::ProlongateBoundaries, sc); + + auto set_bc = tl.AddTask(prolongBound, parthenon::ApplyBoundaryConditions, sc); + + auto convert_bc = tl.AddTask(set_bc, Boundaries::ConvertBoundaryConditions, sc); - // fill in derived fields auto fill_derived = tl.AddTask( - convert_bc, parthenon::Update::FillDerived>, sc1.get()); + convert_bc, parthenon::Update::FillDerived>, sc.get()); auto fixup = tl.AddTask( - fill_derived, fixup::ConservedToPrimitiveFixup>, sc1.get()); + fill_derived, fixup::ConservedToPrimitiveFixup>, sc.get()); + + auto radfixup = tl.AddTask( + fixup, fixup::RadConservedToPrimitiveFixup>, sc.get()); + + auto floors = tl.AddTask(radfixup, fixup::ApplyFloors>, sc.get()); + + if (rad_mocmc_active && stage == integrator->nstages) { + particle_resolution.val.resize(1); // total + // for (int i = 0; i < particle_resolution.val.size(); i++) { + particle_resolution.val[i] = 0.; + //} + int reg_dep_id = 0; + // auto &tl = async_region_3[0]; + + auto update_count = tl.AddTask(none, radiation::MOCMCUpdateParticleCount, pmesh, + &particle_resolution.val); + + async_region_3.AddRegionalDependencies(reg_dep_id, 0, update_count); + reg_dep_id++; + + auto start_count_reduce = + tl.AddTask(update_count, &AllReduce>::StartReduce, + &particle_resolution, MPI_SUM); - auto floors = tl.AddTask(fixup, fixup::ApplyFloors>, sc1.get()); + auto finish_count_reduce = + tl.AddTask(start_count_reduce, &AllReduce>::CheckReduce, + &particle_resolution); + async_region_3.AddRegionalDependencies(reg_dep_id, 0, finish_count_reduce); + reg_dep_id++; + + // Report particle count + auto report_count = + (Globals::my_rank == 0 ? tl.AddTask( + finish_count_reduce, + [](std::vector *res) { + std::cout << "MOCMC total particles = " + << static_cast((*res)[0]) + << std::endl; + return TaskStatus::complete; + }, + &particle_resolution.val) + : none); + } - // TODO(JMM): Should this be at the beginning of a cycle? The end? - // After the monopole solver is done? - // Update cached metric if needed if (time_dependent_geom) { auto update_geom = - tl.AddTask(none, Geometry::UpdateGeometry>, sc1.get()); + tl.AddTask(floors, Geometry::UpdateGeometry>, sc.get()); } // estimate next time step if (stage == integrator->nstages) { auto new_dt = tl.AddTask( - floors, parthenon::Update::EstimateTimestep>, sc1.get()); + floors, parthenon::Update::EstimateTimestep>, sc.get()); if (fluid_active) { - auto divb = tl.AddTask(set_bc, fluid::CalculateDivB, sc1.get()); + auto divb = tl.AddTask(floors, fluid::CalculateDivB, sc.get()); } // Update refinement if (pmesh->adaptive) { // using tag_type = TaskStatus(std::shared_ptr> &); - auto tag_refine = tl.AddTask( - floors, parthenon::Refinement::Tag>, sc1.get()); + auto tag_refine = + tl.AddTask(floors, parthenon::Refinement::Tag>, sc.get()); } } } diff --git a/src/phoebus_utils/linear_algebra.hpp b/src/phoebus_utils/linear_algebra.hpp index 5c636e5e..374a8d97 100644 --- a/src/phoebus_utils/linear_algebra.hpp +++ b/src/phoebus_utils/linear_algebra.hpp @@ -1,5 +1,5 @@ -// © 2021. Triad National Security, LLC. All rights reserved. This -// program was produced under U.S. Government contract +// © 2021-2022. Triad National Security, LLC. All rights reserved. +// This program was produced under U.S. Government contract // 89233218CNA000001 for Los Alamos National Laboratory (LANL), which // is operated by Triad National Security, LLC for the U.S. // Department of Energy/National Nuclear Security Administration. All @@ -95,6 +95,57 @@ KOKKOS_INLINE_FUNCTION void SolveAxb2x2(T A[2][2], T b[2], T x[2]) { x[1] = invDet * DifferenceOfProducts(A[0][0], b[1], A[1][0], b[0]); } +KOKKOS_INLINE_FUNCTION +Real MINOR(Real m[16], int r0, int r1, int r2, int c0, int c1, int c2) { + return m[4 * r0 + c0] * + (m[4 * r1 + c1] * m[4 * r2 + c2] - m[4 * r2 + c1] * m[4 * r1 + c2]) - + m[4 * r0 + c1] * + (m[4 * r1 + c0] * m[4 * r2 + c2] - m[4 * r2 + c0] * m[4 * r1 + c2]) + + m[4 * r0 + c2] * + (m[4 * r1 + c0] * m[4 * r2 + c1] - m[4 * r2 + c0] * m[4 * r1 + c1]); +} + +KOKKOS_INLINE_FUNCTION +void adjoint(Real m[16], Real adjOut[16]) { + adjOut[0] = MINOR(m, 1, 2, 3, 1, 2, 3); + adjOut[1] = -MINOR(m, 0, 2, 3, 1, 2, 3); + adjOut[2] = MINOR(m, 0, 1, 3, 1, 2, 3); + adjOut[3] = -MINOR(m, 0, 1, 2, 1, 2, 3); + + adjOut[4] = -MINOR(m, 1, 2, 3, 0, 2, 3); + adjOut[5] = MINOR(m, 0, 2, 3, 0, 2, 3); + adjOut[6] = -MINOR(m, 0, 1, 3, 0, 2, 3); + adjOut[7] = MINOR(m, 0, 1, 2, 0, 2, 3); + + adjOut[8] = MINOR(m, 1, 2, 3, 0, 1, 3); + adjOut[9] = -MINOR(m, 0, 2, 3, 0, 1, 3); + adjOut[10] = MINOR(m, 0, 1, 3, 0, 1, 3); + adjOut[11] = -MINOR(m, 0, 1, 2, 0, 1, 3); + + adjOut[12] = -MINOR(m, 1, 2, 3, 0, 1, 2); + adjOut[13] = MINOR(m, 0, 2, 3, 0, 1, 2); + adjOut[14] = -MINOR(m, 0, 1, 3, 0, 1, 2); + adjOut[15] = MINOR(m, 0, 1, 2, 0, 1, 2); +} + +KOKKOS_INLINE_FUNCTION +Real determinant(Real m[16]) { + return m[0] * MINOR(m, 1, 2, 3, 1, 2, 3) - m[1] * MINOR(m, 1, 2, 3, 0, 2, 3) + + m[2] * MINOR(m, 1, 2, 3, 0, 1, 3) - m[3] * MINOR(m, 1, 2, 3, 0, 1, 2); +} + +KOKKOS_INLINE_FUNCTION +void matrixInverse4x4(Real mat[4][4], Real matinv[4][4]) { + adjoint(&(mat[0][0]), &(matinv[0][0])); + + Real det = determinant(&(mat[0][0])); + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + matinv[i][j] /= det; + } + } +} + } // namespace LinearAlgebra #endif // PHOEBUS_UTILS_LINEAR_ALGEBRA_HPP_ diff --git a/src/phoebus_utils/robust.hpp b/src/phoebus_utils/robust.hpp index 0ffe6f6b..52a55eb5 100644 --- a/src/phoebus_utils/robust.hpp +++ b/src/phoebus_utils/robust.hpp @@ -6,6 +6,10 @@ namespace robust { +template +KOKKOS_FORCEINLINE_FUNCTION constexpr auto LARGE() { + return 0.1 * std::numeric_limits::max(); +} template KOKKOS_FORCEINLINE_FUNCTION constexpr auto SMALL() { return 10 * std::numeric_limits::min(); diff --git a/src/phoebus_utils/root_find.hpp b/src/phoebus_utils/root_find.hpp index bec818fa..a029bbd4 100644 --- a/src/phoebus_utils/root_find.hpp +++ b/src/phoebus_utils/root_find.hpp @@ -58,7 +58,7 @@ struct RootFind { template KOKKOS_INLINE_FUNCTION Real secant(F &func, Real a, Real b, const Real tol, - const Real guess) { + const Real guess, RootFindStatus *status = nullptr) { Real ya, yb; refine_bracket(func, guess, a, b, ya, yb); Real x1, x2, y1, y2; @@ -82,9 +82,11 @@ struct RootFind { // guard against roundoff because ya or yb is sufficiently close to zero if (x0 == x1) { x2 = x1; + iteration_count++; continue; } else if (x0 == x2) { x1 = x2; + iteration_count++; continue; } Real y0 = sign * func(x0); @@ -92,7 +94,14 @@ struct RootFind { y2 = y1; x1 = x0; y1 = y0; + iteration_count++; } + + if (status != nullptr) { + *status = + iteration_count == max_iter ? RootFindStatus::failure : RootFindStatus::success; + } + return 0.5 * (x1 + x2); } @@ -115,9 +124,11 @@ struct RootFind { // guard against roundoff because ya or yb is sufficiently close to zero if (c == a) { b = a; + iteration_count++; continue; } else if (c == b) { a = b; + iteration_count++; continue; } Real yc = sign * func(c); diff --git a/src/phoebus_utils/variables.hpp b/src/phoebus_utils/variables.hpp index 5467f092..5b5f1ef7 100644 --- a/src/phoebus_utils/variables.hpp +++ b/src/phoebus_utils/variables.hpp @@ -56,6 +56,8 @@ constexpr char kappaH[] = "r.i.kappaH"; constexpr char JBB[] = "r.i.JBB"; constexpr char tilPi[] = "r.i.tilPi"; constexpr char kappaH_mean[] = "r.i.kappaH_mean"; +constexpr char c2pfail[] = "r.i.c2p_fail"; +constexpr char srcfail[] = "r.i.src_fail"; } // namespace radmoment_internal namespace mocmc_internal { @@ -87,6 +89,8 @@ namespace diagnostic_variables { constexpr char divb[] = "divb"; constexpr char divf[] = "flux_divergence"; constexpr char src_terms[] = "src_terms"; +constexpr char r_divf[] = "r.flux_divergence"; +constexpr char r_src_terms[] = "r.src_terms"; } // namespace diagnostic_variables #endif // PHOEBUS_UTILS_VARIABLES_HPP_ diff --git a/src/radiation/closure.hpp b/src/radiation/closure.hpp index 6e623312..aee022c5 100644 --- a/src/radiation/closure.hpp +++ b/src/radiation/closure.hpp @@ -33,7 +33,11 @@ using namespace LinearAlgebra; using namespace robust; /// Status of closure calculation -enum class ClosureStatus { success = 0, failure = 1 }; +enum class ClosureStatus { + success = 0, // C2P inversion completed successfully + failure = 1, // C2P inversion failed; must be fixed up + modified = 2 // C2P inversion recovered but cons vars must be updated +}; enum class ClosureType { Eddington, M1, MOCMC }; @@ -48,9 +52,17 @@ struct ClosureSettings { static const ClosureVerbosity verbosity = VB; }; +enum class ClosureCon2PrimStrategy { + frail, // Mark cell as failed if inversion produces unphysical state + robust // Attempt to repair unphysical states +}; +struct ClosureRuntimeSettings { + ClosureCon2PrimStrategy con2prim_strategy; +}; + /// Holds methods for closing the radiation moment equations as well as calculating /// radiation moment source terms. -template > +template > class ClosureEdd { public: using LocalGeometryType = LocalThreeGeometry; @@ -59,7 +71,8 @@ class ClosureEdd { /// Constructor just calculates the inverse 3-metric, covariant three-velocity, and the /// Lorentz factor for the given background state. KOKKOS_FUNCTION - ClosureEdd(const Vec con_v_in, LocalGeometryType *g); + ClosureEdd(const Vec con_v_in, LocalGeometryType *g, + ClosureRuntimeSettings rset = {ClosureCon2PrimStrategy::robust}); //------------------------------------------------------------------------------------- /// Calculate the update values dE and cov_dF for a linear, implicit source term update @@ -106,13 +119,13 @@ class ClosureEdd { Vec *cov_H); KOKKOS_FUNCTION - ClosureStatus GetCovTilPiFromPrim(const Real J, const Vec cov_tilH, Tens2 *con_tilPi) { + ClosureStatus GetConTilPiFromPrim(const Real J, const Vec cov_tilH, Tens2 *con_tilPi) { SPACELOOP2(i, j) (*con_tilPi)(i, j) = 0.0; return ClosureStatus::success; } KOKKOS_FUNCTION - ClosureStatus GetCovTilPiFromCon(const Real E, const Vec cov_F, Real &xi, Real &phi, + ClosureStatus GetConTilPiFromCon(const Real E, const Vec cov_F, Real &xi, Real &phi, Tens2 *con_tilPi) { SPACELOOP2(i, j) (*con_tilPi)(i, j) = 0.0; xi = 0.0; @@ -124,6 +137,7 @@ class ClosureEdd { Vec cov_v; Vec con_v; LocalGeometryType *gamma; + ClosureRuntimeSettings rset_; protected: KOKKOS_FORCEINLINE_FUNCTION @@ -139,21 +153,25 @@ class ClosureEdd { } }; -template -KOKKOS_FUNCTION ClosureEdd::ClosureEdd(const Vec con_v_in, - LocalGeometryType *g) - : gamma(g) { +template +KOKKOS_FUNCTION ClosureEdd::ClosureEdd(const Vec con_v_in, LocalGeometryType *g, + ClosureRuntimeSettings rset) + : gamma(g), rset_(rset) { SPACELOOP(i) con_v(i) = con_v_in(i); gamma->lower3Vector(con_v, &cov_v); v2 = 0.0; SPACELOOP(i) v2 += con_v(i) * cov_v(i); + // TODO(BRR) use gamma max ceiling (may mess with rootfind) + v2 = std::min(v2, 0.9999); W = 1 / std::sqrt(1 - v2); W2 = W * W; + + PARTHENON_DEBUG_REQUIRE(!std::isinf(W), "Infinite Lorentz factor!"); } -template -KOKKOS_FUNCTION ClosureStatus ClosureEdd::LinearSourceUpdate( +template +KOKKOS_FUNCTION ClosureStatus ClosureEdd::LinearSourceUpdate( const Real Estar, const Vec cov_Fstar, const Tens2 con_tilPi, const Real JBB, const Real tauJ, const Real tauH, Real *dE, Vec *cov_dF) { @@ -202,10 +220,12 @@ KOKKOS_FUNCTION ClosureStatus ClosureEdd::LinearSourceUpdate( return ClosureStatus::success; } -template -KOKKOS_FUNCTION ClosureStatus ClosureEdd::getFluxesFromPrim( - const Real J, const Vec cov_tilH, const Tens2 con_tilPi, Vec *con_F, - Tens2 *concov_P) { +template +KOKKOS_FUNCTION ClosureStatus ClosureEdd::getFluxesFromPrim(const Real J, + const Vec cov_tilH, + const Tens2 con_tilPi, + Vec *con_F, + Tens2 *concov_P) { getConCovPFromPrim(J, cov_tilH, con_tilPi, concov_P); if (SET::eqn_type == ClosureEquation::energy_conserve) { Real E; @@ -220,8 +240,8 @@ KOKKOS_FUNCTION ClosureStatus ClosureEdd::getFluxesFromPrim( return ClosureStatus::success; } -template -KOKKOS_FORCEINLINE_FUNCTION ClosureStatus ClosureEdd::getConPFromPrim( +template +KOKKOS_FORCEINLINE_FUNCTION ClosureStatus ClosureEdd::getConPFromPrim( const Real J, const Vec cov_tilH, const Tens2 con_tilPi, Tens2 *con_P) { Vec con_tilH; gamma->raise3Vector(cov_tilH, &con_tilH); @@ -233,8 +253,8 @@ KOKKOS_FORCEINLINE_FUNCTION ClosureStatus ClosureEdd::getConPFr return ClosureStatus::success; } -template -KOKKOS_FORCEINLINE_FUNCTION ClosureStatus ClosureEdd::getConCovPFromPrim( +template +KOKKOS_FORCEINLINE_FUNCTION ClosureStatus ClosureEdd::getConCovPFromPrim( const Real J, const Vec cov_tilH, const Tens2 con_tilPi, Tens2 *concov_P) { Vec con_tilH; Tens2 concov_tilPi; @@ -254,11 +274,10 @@ KOKKOS_FORCEINLINE_FUNCTION ClosureStatus ClosureEdd::getConCov return ClosureStatus::success; } -template -KOKKOS_FUNCTION ClosureStatus ClosureEdd::Prim2Con(const Real J, - const Vec cov_H, - const Tens2 con_tilPi, - Real *E, Vec *cov_F) { +template +KOKKOS_FUNCTION ClosureStatus ClosureEdd::Prim2Con(const Real J, const Vec cov_H, + const Tens2 con_tilPi, Real *E, + Vec *cov_F) { Real vvPi; Vec cov_vPi; GetTilPiContractions(con_tilPi, &cov_vPi, &vvPi); @@ -270,15 +289,17 @@ KOKKOS_FUNCTION ClosureStatus ClosureEdd::Prim2Con(const Real J } else if (SET::eqn_type == ClosureEquation::number_conserve) { *E = W * J + vH; } + PARTHENON_DEBUG_REQUIRE(!std::isnan(*E), "NAN in radiation P2C!"); SPACELOOP(i) (*cov_F)(i) = 4 * W2 / 3 * cov_v(i) * J + W * cov_v(i) * vH + W * cov_H(i) + J * cov_vPi(i); return ClosureStatus::success; } -template -KOKKOS_FUNCTION ClosureStatus ClosureEdd::Con2Prim( - Real E, const Vec cov_F, const Tens2 con_tilPi, Real *J, Vec *cov_tilH) { +template +KOKKOS_FUNCTION ClosureStatus ClosureEdd::Con2Prim(Real E, const Vec cov_F, + const Tens2 con_tilPi, Real *J, + Vec *cov_tilH) { Real vvTilPi; Vec cov_vTilPi; GetTilPiContractions(con_tilPi, &cov_vTilPi, &vvTilPi); @@ -302,6 +323,30 @@ KOKKOS_FUNCTION ClosureStatus ClosureEdd::Con2Prim( // Calculate fluid rest frame (i.e. primitive) quantities *J = ratio((2 * W2 - 1) * E - 2 * W2 * vF, lam); SPACELOOP(i) (*cov_tilH)(i) = (cov_F(i) - (*J) * cov_vTilPi(i) - cov_v(i) * a) / W; + + const Real xi = + std::sqrt(gamma->contractCov3Vectors(*cov_tilH, *cov_tilH) - + std::pow(gamma->contractConCov3Vectors(con_v, *cov_tilH), 2)) / + (*J); + + if (std::isnan(xi) || std::isnan(*J)) { + return ClosureStatus::failure; + } + + if (*J < 0. || xi >= 1.0) { + if (rset_.con2prim_strategy == ClosureCon2PrimStrategy::robust) { + if (*J < 0.) { + *J = std::min(*J, 10. * robust::SMALL()); + } + if (xi >= 1.0) { + SPACELOOP(ii) { (*cov_tilH)(ii) *= 0.999 / xi; } + } + return ClosureStatus::modified; + } else { + return ClosureStatus::failure; + } + } + return ClosureStatus::success; } diff --git a/src/radiation/closure_m1.hpp b/src/radiation/closure_m1.hpp index a435380a..7dea807c 100644 --- a/src/radiation/closure_m1.hpp +++ b/src/radiation/closure_m1.hpp @@ -44,8 +44,8 @@ struct M1Result { /// Holds methods for closing the radiation moment equations as well as calculating /// radiation moment source terms. -template > -class ClosureM1 : public ClosureEdd { +template > +class ClosureM1 : public ClosureEdd { protected: KOKKOS_FORCEINLINE_FUNCTION Real closure(Real xi) { @@ -55,24 +55,25 @@ class ClosureM1 : public ClosureEdd { } public: - using typename ClosureEdd::LocalGeometryType; + using typename ClosureEdd::LocalGeometryType; //------------------------------------------------------------------------------------- /// Constructor just calculates the inverse 3-metric, covariant three-velocity, and the /// Lorentz factor for the given background state. KOKKOS_FUNCTION - ClosureM1(const Vec con_v_in, LocalGeometryType *g) - : ClosureEdd(con_v_in, g) {} + ClosureM1(const Vec con_v_in, LocalGeometryType *g, + ClosureRuntimeSettings r = {ClosureCon2PrimStrategy::robust}) + : ClosureEdd(con_v_in, g, r) {} KOKKOS_FUNCTION - ClosureStatus GetCovTilPiFromPrim(const Real J, const Vec cov_H, Tens2 *con_tilPi) { + ClosureStatus GetConTilPiFromPrim(const Real J, const Vec cov_H, Tens2 *con_tilPi) { Vec con_tilf; M1FluidPressureTensor(J, cov_H, con_tilPi, &con_tilf); return ClosureStatus::success; } KOKKOS_FUNCTION - ClosureStatus GetCovTilPiFromCon(Real E, const Vec cov_F, Real &xi, Real &phi, + ClosureStatus GetConTilPiFromCon(Real E, const Vec cov_F, Real &xi, Real &phi, Tens2 *con_tilPi) { if (SET::eqn_type == ClosureEquation::number_conserve) { @@ -91,14 +92,14 @@ class ClosureM1 : public ClosureEdd { void GetM1GuessesFromEddington(const Real E, const Vec cov_F, Real *xi, Real *phi); // Make base template class variables dependent names (pretty ugly, I know) - using ClosureEdd::Con2Prim; - using ClosureEdd::Prim2Con; - using ClosureEdd::v2; - using ClosureEdd::W; - using ClosureEdd::W2; - using ClosureEdd::cov_v; - using ClosureEdd::con_v; - using ClosureEdd::gamma; + using ClosureEdd::Con2Prim; + using ClosureEdd::Prim2Con; + using ClosureEdd::v2; + using ClosureEdd::W; + using ClosureEdd::W2; + using ClosureEdd::cov_v; + using ClosureEdd::con_v; + using ClosureEdd::gamma; protected: // All internal methods are written in terms of E = n^\mu n^\nu M_{\mu \nu} @@ -151,10 +152,10 @@ class ClosureM1 : public ClosureEdd { //---- Method templates instantiated below -template -KOKKOS_FUNCTION void -ClosureM1::GetM1GuessesFromEddington(const Real E, const Vec cov_F, - Real *xi, Real *phi) { +template +KOKKOS_FUNCTION void ClosureM1::GetM1GuessesFromEddington(const Real E, + const Vec cov_F, Real *xi, + Real *phi) { // Get the basis vectors for the search Vec con_tilg, con_tild; GetBasisVectors(cov_F, &con_tilg, &con_tild); @@ -170,6 +171,7 @@ ClosureM1::GetM1GuessesFromEddington(const Real E, const Vec co Real vHEdd = gamma->contractConCov3Vectors(con_v, cov_HEdd); Real HEdd = sqrt(gamma->contractCov3Vectors(cov_HEdd, cov_HEdd) - vHEdd * vHEdd); + // TODO(BRR) Use radiation ceilings value here? *xi = std::min(ratio(HEdd, JEdd), 0.99); *phi = 1.000001 * acos(-1); } @@ -177,12 +179,10 @@ ClosureM1::GetM1GuessesFromEddington(const Real E, const Vec co //---------------- // Protected functions below //---------------- -template -KOKKOS_FUNCTION M1Result ClosureM1::SolveClosure(Real E, Vec cov_F, - Real *xi_out, - Real *phi_out, - const Real xi_guess, - const Real phi_guess) { +template +KOKKOS_FUNCTION M1Result ClosureM1::SolveClosure(Real E, Vec cov_F, Real *xi_out, + Real *phi_out, const Real xi_guess, + const Real phi_guess) { const int max_iter = 30; const Real tol = 1.e6 * std::numeric_limits::epsilon(); const Real eps = std::sqrt(10 * std::numeric_limits::epsilon()); @@ -266,10 +266,12 @@ KOKKOS_FUNCTION M1Result ClosureM1::SolveClosure(Real E, Vec co return result; } -template -KOKKOS_FUNCTION ClosureStatus ClosureM1::M1Residuals( - const Real E, const Vec cov_F, const Real xi, const Real phi, const Vec con_tilg, - const Vec con_tild, Real *fXi, Real *fPhi) { +template +KOKKOS_FUNCTION ClosureStatus ClosureM1::M1Residuals(const Real E, const Vec cov_F, + const Real xi, const Real phi, + const Vec con_tilg, + const Vec con_tild, Real *fXi, + Real *fPhi) { // Calculate rest frame fluid variables Tens2 con_tilPi; Vec con_tilf; @@ -292,9 +294,11 @@ KOKKOS_FUNCTION ClosureStatus ClosureM1::M1Residuals( return ClosureStatus::success; } -template -KOKKOS_FUNCTION ClosureStatus ClosureM1::M1FluidPressureTensor( - const Real J, const Vec cov_tilH, Tens2 *con_tilPi, Vec *con_tilf) { +template +KOKKOS_FUNCTION ClosureStatus ClosureM1::M1FluidPressureTensor(const Real J, + const Vec cov_tilH, + Tens2 *con_tilPi, + Vec *con_tilf) { Vec con_tilH; gamma->raise3Vector(cov_tilH, &con_tilH); Real H(0.0), vH(0.0); @@ -314,8 +318,8 @@ KOKKOS_FUNCTION ClosureStatus ClosureM1::M1FluidPressureTensor( return ClosureStatus::success; } -template -KOKKOS_FUNCTION ClosureStatus ClosureM1::M1FluidPressureTensor( +template +KOKKOS_FUNCTION ClosureStatus ClosureM1::M1FluidPressureTensor( const Vec /*cov_F*/, const Real xi, const Real phi, const Vec con_tilg, const Vec con_tild, Tens2 *con_tilPi, Vec *con_tilf) { @@ -337,10 +341,10 @@ KOKKOS_FUNCTION ClosureStatus ClosureM1::M1FluidPressureTensor( return ClosureStatus::success; } -template -KOKKOS_FUNCTION ClosureStatus ClosureM1::GetBasisVectors(const Vec cov_F, - Vec *con_tilg, - Vec *con_tild) { +template +KOKKOS_FUNCTION ClosureStatus ClosureM1::GetBasisVectors(const Vec cov_F, + Vec *con_tilg, + Vec *con_tild) { // Build projected basis vectors for flux direction // These vectors are actually fixed, so there is no need to recalculate // them every step in the root find diff --git a/src/radiation/closure_mocmc.hpp b/src/radiation/closure_mocmc.hpp index c7b541ff..038427cf 100644 --- a/src/radiation/closure_mocmc.hpp +++ b/src/radiation/closure_mocmc.hpp @@ -35,21 +35,22 @@ using namespace robust; /// Holds methods for closing the radiation moment equations as well as calculating /// radiation moment source terms. -template > -class ClosureMOCMC : public ClosureEdd { +template > +class ClosureMOCMC : public ClosureEdd { public: - using typename ClosureEdd::LocalGeometryType; + using typename ClosureEdd::LocalGeometryType; //------------------------------------------------------------------------------------- /// Constructor just calculates the inverse 3-metric, covariant three-velocity, and the /// Lorentz factor for the given background state. KOKKOS_FUNCTION - ClosureMOCMC(const Vec con_v_in, LocalGeometryType *g) - : ClosureEdd(con_v_in, g) {} + ClosureMOCMC(const Vec con_v_in, LocalGeometryType *g, + ClosureRuntimeSettings r = {ClosureCon2PrimStrategy::robust}) + : ClosureEdd(con_v_in, g, r) {} KOKKOS_FUNCTION - ClosureStatus GetCovTilPiFromPrim(const Real J, const Vec cov_H, Tens2 *con_tilPi) { + ClosureStatus GetConTilPiFromPrim(const Real J, const Vec cov_H, Tens2 *con_tilPi) { PARTHENON_FAIL("MOCMC has already stored TilPi elsewhere!"); // Do nothing @@ -57,7 +58,7 @@ class ClosureMOCMC : public ClosureEdd { } KOKKOS_FUNCTION - ClosureStatus GetCovTilPiFromCon(Real E, const Vec cov_F, Real &xi, Real &phi, + ClosureStatus GetConTilPiFromCon(Real E, const Vec cov_F, Real &xi, Real &phi, Tens2 *con_tilPi) { PARTHENON_FAIL("MOCMC has already stored TilPi elsewhere!"); diff --git a/src/radiation/cooling_function.cpp b/src/radiation/cooling_function.cpp index 5b6c7864..7c6f3c42 100644 --- a/src/radiation/cooling_function.cpp +++ b/src/radiation/cooling_function.cpp @@ -99,7 +99,7 @@ TaskStatus CoolingFunctionCalculateFourForce(MeshBlockData *rc, const doub Real detG = geom.DetG(CellLocation::Cent, k, j, i); for (int mu = Gcov_lo; mu <= Gcov_lo + 3; mu++) { - Kokkos::atomic_add(&(v(mu, k, j, i)), detG * Gcov_coord[mu - Gcov_lo]); + Kokkos::atomic_add(&(v(mu, k, j, i)), -detG * Gcov_coord[mu - Gcov_lo]); } Kokkos::atomic_add(&(v(Gye, k, j, i)), -detG * Jye); }); diff --git a/src/radiation/mocmc.cpp b/src/radiation/mocmc.cpp index 80652540..fe66bc39 100644 --- a/src/radiation/mocmc.cpp +++ b/src/radiation/mocmc.cpp @@ -102,6 +102,15 @@ void MOCMCInitSamples(T *rc) { const int nsamp_per_zone = rad->Param("nsamp_per_zone"); int nsamp_tot = 0; + auto nusamp = rad->Param>("nusamp"); + const int nu_bins = rad->Param("nu_bins"); + auto species = rad->Param>("species"); + const auto num_species = rad->Param("num_species"); + RadiationType species_d[3] = {}; + for (int s = 0; s < num_species; s++) { + species_d[s] = species[s]; + } + // Fill nsamp per zone per species and sum over zones // TODO(BRR) make this a separate function and use it to update dnsamp which is then // used to decide whether to refine/derefine @@ -110,7 +119,7 @@ void MOCMCInitSamples(T *rc) { nblock - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, KOKKOS_LAMBDA(const int b, const int k, const int j, const int i, int &nsamp) { Real Jtot = 0.; - for (int s = 0; s < 3; s++) { + for (int s = 0; s < num_species; s++) { Jtot += v(b, pJ(s), k, j, i); } v(b, dn, k, j, i) = @@ -161,15 +170,6 @@ void MOCMCInitSamples(T *rc) { auto swarm_d = swarm->GetDeviceContext(); - auto nusamp = rad->Param>("nusamp"); - const int nu_bins = rad->Param("nu_bins"); - auto species = rad->Param>("species"); - auto num_species = rad->Param("num_species"); - RadiationType species_d[3] = {}; - for (int s = 0; s < num_species; s++) { - species_d[s] = species[s]; - } - parthenon::par_for( DEFAULT_LOOP_PATTERN, "MOCMC::Init::Sample", DevExecSpace(), 0, nblock - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, @@ -193,10 +193,7 @@ void MOCMCInitSamples(T *rc) { y(n) = minx_j + (j - jb.s + rng_gen.drand()) * dx_j; z(n) = minx_k + (k - kb.s + rng_gen.drand()) * dx_k; - const Real rho = v(b, pdens, k, j, i); const Real Temp = v(b, pT, k, j, i); - const Real Ye = v(b, pye, k, j, i); - Real lambda[2] = {Ye, 0.}; // Sample uniformly in solid angle const Real theta = acos(2. * rng_gen.drand() - 1.); @@ -277,22 +274,21 @@ TaskStatus MOCMCSampleBoundaries(T *rc) { species_d[s] = species[s]; } - /// TODO: (LFR) Fix this junk - RadiationType dev_species[3] = {species[0], species[1], species[2]}; - auto swarm_d = swarm->GetDeviceContext(); + // TODO(BRR) provide *all* MOCMC boundaries + auto ix1_bc = rad->Param("ix1_bc"); - auto ox1_bc = rad->Param("ox1_bc"); + // auto ox1_bc = rad->Param("ox1_bc"); Real ix1_temp = 0.; - Real ox1_temp = 0.; + // Real ox1_temp = 0.; if (ix1_bc == MOCMCBoundaries::fixed_temp) { ix1_temp = rad->Param("ix1_temp"); } - if (ox1_bc == MOCMCBoundaries::fixed_temp) { - ox1_temp = rad->Param("ox1_temp"); - } + // if (ox1_bc == MOCMCBoundaries::fixed_temp) { + // ox1_temp = rad->Param("ox1_temp"); + //} pmb->par_for( "Temporary MOCMC boundaries", 0, swarm->GetMaxActiveIndex(), @@ -313,8 +309,8 @@ TaskStatus MOCMCSampleBoundaries(T *rc) { Real temp = 0.; if (ix1_bc == MOCMCBoundaries::outflow) { // Temperature from J in ghost zone - temp = opac_d.TemperatureFromEnergyDensity(v(iJ(s), k, j, i), - dev_species[s]); + temp = + opac_d.TemperatureFromEnergyDensity(v(iJ(s), k, j, i), species_d[s]); } else { // Fixed temperature temp = ix1_temp; @@ -325,7 +321,7 @@ TaskStatus MOCMCSampleBoundaries(T *rc) { const Real nu = nusamp(nubin); Inuinv(nubin, s, n) = std::max(robust::SMALL(), opac_d.ThermalDistributionOfTNu( - temp, dev_species[s], nu)) / + temp, species_d[s], nu)) / std::pow(nu, 3); } } @@ -382,12 +378,6 @@ TaskStatus MOCMCReconstruction(T *rc) { auto nusamp = rad->Param>("nusamp"); const int nu_bins = rad->Param("nu_bins"); - auto species = rad->Param>("species"); - auto num_species = rad->Param("num_species"); - RadiationType species_d[MAX_SPECIES] = {}; - for (int s = 0; s < num_species; s++) { - species_d[s] = species[s]; - } swarm->SortParticlesByCell(); auto swarm_d = swarm->GetDeviceContext(); @@ -590,9 +580,6 @@ TaskStatus MOCMCFluidSource(T *rc, const Real dt, const bool update_fluid) { const int iblock = 0; // No meshblockpacks right now int nspec = idx_E.DimSize(1); - /// TODO: (LFR) Fix this junk - RadiationType dev_species[3] = {species[0], species[1], species[2]}; - if (true) { // update = lagged parthenon::par_for( DEFAULT_LOOP_PATTERN, "MOCMC::FluidSource", DevExecSpace(), kb.s, kb.e, jb.s, @@ -610,7 +597,6 @@ TaskStatus MOCMCFluidSource(T *rc, const Real dt, const bool update_fluid) { for (int ispec = 0; ispec < num_species; ++ispec) { const int nsamp = swarm_d.GetParticleCountPerCell(k, j, i); - const Real dtau = dt; // TODO(BRR): dtau = dt / u^0 // Set up the background state Vec con_v{{v(iblock, pv(0), k, j, i), v(iblock, pv(1), k, j, i), @@ -629,9 +615,9 @@ TaskStatus MOCMCFluidSource(T *rc, const Real dt, const bool update_fluid) { con_tilPi(ii, jj) = v(iblock, iTilPi(ispec, ii, jj), k, j, i); } Real JBB = opac_d.EnergyDensityFromTemperature(v(iblock, pT, k, j, i), - dev_species[ispec]); + species_d[ispec]); - ClosureMOCMC c(con_v, &g); + ClosureMOCMC<> c(con_v, &g); Real dE = 0; Vec cov_dF; @@ -658,7 +644,7 @@ TaskStatus MOCMCFluidSource(T *rc, const Real dt, const bool update_fluid) { for (int bin = 0; bin < nu_bins; bin++) { kappaJ += opac_d.AngleAveragedAbsorptionCoefficient( v(iblock, pdens, k, j, i), v(iblock, pT, k, j, i), - v(iblock, pye, k, j, i), dev_species[ispec], nusamp(bin)) * + v(iblock, pye, k, j, i), species_d[ispec], nusamp(bin)) * v(iblock, Inu0(ispec, bin), k, j, i) * nusamp(bin); Itot += v(iblock, Inu0(ispec, bin), k, j, i) * nusamp(bin); } @@ -667,13 +653,13 @@ TaskStatus MOCMCFluidSource(T *rc, const Real dt, const bool update_fluid) { kappaJ -= 0.5 * opac_d.AngleAveragedAbsorptionCoefficient( v(iblock, pdens, k, j, i), v(iblock, pT, k, j, i), - v(iblock, pye, k, j, i), dev_species[ispec], nusamp(0)) * + v(iblock, pye, k, j, i), species_d[ispec], nusamp(0)) * v(iblock, Inu0(ispec, 0), k, j, i) * nusamp(0); kappaJ -= 0.5 * opac_d.AngleAveragedAbsorptionCoefficient( v(iblock, pdens, k, j, i), v(iblock, pT, k, j, i), - v(iblock, pye, k, j, i), dev_species[ispec], nusamp(nu_bins - 1)) * + v(iblock, pye, k, j, i), species_d[ispec], nusamp(nu_bins - 1)) * v(iblock, Inu0(ispec, nu_bins - 1), k, j, i) * nusamp(nu_bins - 1); Itot -= 0.5 * (v(iblock, Inu0(ispec, 0), k, j, i) * nusamp(0) + @@ -729,7 +715,7 @@ TaskStatus MOCMCFluidSource(T *rc, const Real dt, const bool update_fluid) { nu_fluid * scattering_fraction * opac_d.AngleAveragedAbsorptionCoefficient( v(iblock, pdens, k, j, i), v(iblock, pT, k, j, i), - v(iblock, pye, k, j, i), dev_species[ispec], nu_fluid); + v(iblock, pye, k, j, i), species_d[ispec], nu_fluid); v(iblock, ijinvs(ispec, bin), k, j, i) = v(iblock, Inu0(ispec, bin), k, j, i) / (nu_fluid * nu_fluid * nu_fluid) * alphainv_s; @@ -743,15 +729,15 @@ TaskStatus MOCMCFluidSource(T *rc, const Real dt, const bool update_fluid) { nu_fluid * (1. - scattering_fraction) * opac_d.AngleAveragedAbsorptionCoefficient( v(iblock, pdens, k, j, i), v(iblock, pT, k, j, i), - v(iblock, pye, k, j, i), dev_species[ispec], nu_fluid); + v(iblock, pye, k, j, i), species_d[ispec], nu_fluid); const Real alphainv_s = nu_fluid * scattering_fraction * opac_d.AngleAveragedAbsorptionCoefficient( v(iblock, pdens, k, j, i), v(iblock, pT, k, j, i), - v(iblock, pye, k, j, i), dev_species[ispec], nu_fluid); + v(iblock, pye, k, j, i), species_d[ispec], nu_fluid); const Real jinv_a = opac_d.ThermalDistributionOfTNu(v(iblock, pT, k, j, i), - dev_species[ispec], nu_fluid) / + species_d[ispec], nu_fluid) / (nu_fluid * nu_fluid * nu_fluid) * alphainv_a; // Interpolate invariant scattering emissivity to lab frame @@ -821,13 +807,7 @@ TaskStatus MOCMCEddington(T *rc) { const int nu_bins = rad->Param("nu_bins"); const Real dlnu = rad->Param("dlnu"); auto nusamp = rad->Param>("nusamp"); - auto species = rad->Param>("species"); auto num_species = rad->Param("num_species"); - RadiationType species_d[3] = {}; - for (int s = 0; s < num_species; s++) { - species_d[s] = species[s]; - } - constexpr int MAX_SPECIES = 3; // TODO(BRR) block packing eventually const int iblock = 0; diff --git a/src/radiation/moments.cpp b/src/radiation/moments.cpp index efe26d39..09065342 100644 --- a/src/radiation/moments.cpp +++ b/src/radiation/moments.cpp @@ -15,7 +15,11 @@ #include #include +#include + +#include "phoebus_utils/linear_algebra.hpp" #include "phoebus_utils/programming_utils.hpp" +#include "phoebus_utils/root_find.hpp" #include "radiation/closure.hpp" #include "radiation/closure_m1.hpp" #include "radiation/closure_mocmc.hpp" @@ -23,8 +27,15 @@ #include "radiation/radiation.hpp" #include "reconstruction.hpp" +#include "fluid/con2prim_robust.hpp" +#include "fluid/prim2con.hpp" + namespace radiation { +using namespace singularity::neutrinos; +using fixup::Bounds; +using singularity::EOS; + template class ReconstructionIndexer { public: @@ -55,16 +66,15 @@ TaskStatus MomentCon2PrimImpl(T *rc) { namespace ir = radmoment_internal; auto *pm = rc->GetParentPointer().get(); + StateDescriptor *rad = pm->packages.Get("radiation").get(); IndexRange ib = pm->cellbounds.GetBoundsI(IndexDomain::entire); IndexRange jb = pm->cellbounds.GetBoundsJ(IndexDomain::entire); IndexRange kb = pm->cellbounds.GetBoundsK(IndexDomain::entire); - std::vector variables{cr::E, cr::F, pr::J, pr::H, fluid_prim::velocity, - ir::xi, ir::phi}; - if (programming::is_specialization_of::value) { - variables.push_back(ir::tilPi); - } + std::vector variables{ + cr::E, cr::F, pr::J, pr::H, fluid_prim::velocity, + ir::xi, ir::phi, ir::c2pfail, ir::tilPi}; PackIndexMap imap; auto v = rc->PackVariables(variables, imap); @@ -73,20 +83,21 @@ TaskStatus MomentCon2PrimImpl(T *rc) { auto cF = imap.GetFlatIdx(cr::F); auto pH = imap.GetFlatIdx(pr::H); auto pv = imap.GetFlatIdx(fluid_prim::velocity); - // TODO(BRR) Should be able to just get an invalid iTilPi back from imap when MOCMC off - vpack_types::FlatIdx iTilPi({-1}, -1); - if (programming::is_specialization_of::value) { - iTilPi = imap.GetFlatIdx(ir::tilPi); - } + auto iTilPi = imap.GetFlatIdx(ir::tilPi, false); auto specB = cE.GetBounds(1); - auto dirB = pH.GetBounds(1); + auto dirB = pH.GetBounds(2); auto iXi = imap.GetFlatIdx(ir::xi); auto iPhi = imap.GetFlatIdx(ir::phi); + auto ifail = imap[ir::c2pfail].first; + auto geom = Geometry::GetCoordinateSystem(rc); const Real pi = acos(-1); + auto closure_runtime_params = + rad->Param("closure_runtime_params"); + parthenon::par_for( DEFAULT_LOOP_PATTERN, "RadMoments::Con2Prim", DevExecSpace(), 0, v.GetDim(5) - 1, // Loop over meshblocks @@ -95,13 +106,18 @@ TaskStatus MomentCon2PrimImpl(T *rc) { jb.s, jb.e, // y-loop ib.s, ib.e, // x-loop KOKKOS_LAMBDA(const int b, const int ispec, const int k, const int j, const int i) { - Vec con_v{{v(b, pv(0), k, j, i), v(b, pv(1), k, j, i), v(b, pv(2), k, j, i)}}; Tens2 cov_gamma; geom.Metric(CellLocation::Cent, b, k, j, i, cov_gamma.data); const Real isdetgam = 1.0 / geom.DetGamma(CellLocation::Cent, b, k, j, i); + const Real vp[3] = {v(b, pv(0), k, j, i), v(b, pv(1), k, j, i), + v(b, pv(2), k, j, i)}; + const Real W = phoebus::GetLorentzFactor(vp, cov_gamma.data); + Vec con_v{{v(b, pv(0), k, j, i) / W, v(b, pv(1), k, j, i) / W, + v(b, pv(2), k, j, i) / W}}; + typename CLOSURE::LocalGeometryType g(geom, CellLocation::Cent, b, k, j, i); - CLOSURE c(con_v, &g); + CLOSURE c(con_v, &g, closure_runtime_params); Real J; Vec covH; @@ -111,39 +127,48 @@ TaskStatus MomentCon2PrimImpl(T *rc) { v(b, cF(ispec, 1), k, j, i) * isdetgam, v(b, cF(ispec, 2), k, j, i) * isdetgam}}; - if (programming::is_specialization_of::value) { + if (iTilPi.IsValid()) { SPACELOOP2(ii, jj) { conTilPi(ii, jj) = v(b, iTilPi(ispec, ii, jj), k, j, i); } } else { Real xi = 0.0; Real phi = pi; + // TODO(BRR) Remove STORE_GUESS parameter and instead check if closure type is + // M1? if (STORE_GUESS) { xi = v(b, iXi(ispec), k, j, i); phi = 1.0001 * v(b, iPhi(ispec), k, j, i); } - c.GetCovTilPiFromCon(E, covF, xi, phi, &conTilPi); + c.GetConTilPiFromCon(E, covF, xi, phi, &conTilPi); if (STORE_GUESS) { v(b, iXi(ispec), k, j, i) = xi; v(b, iPhi(ispec), k, j, i) = phi; } } - c.Con2Prim(E, covF, conTilPi, &J, &covH); - if (std::isnan(J) || std::isnan(covH(0)) || std::isnan(covH(1)) || - std::isnan(covH(2))) { - PARTHENON_FAIL("Radiation Con2Prim NaN."); + auto status = c.Con2Prim(E, covF, conTilPi, &J, &covH); + + if (status == ClosureStatus::modified) { + c.Prim2Con(J, covH, conTilPi, &E, &covF); + v(b, cE(ispec), k, j, i) = E / isdetgam; + SPACELOOP(ii) { v(b, cF(ispec, ii), k, j, i) = covF(ii) / isdetgam; } + status = ClosureStatus::success; } v(b, pJ(ispec), k, j, i) = J; for (int idir = dirB.s; idir <= dirB.e; ++idir) { // Loop over directions - v(b, pH(ispec, idir), k, j, i) = - covH(idir) / - J; // Used the scaled value of the rest frame flux for reconstruction + // Use the scaled value of the rest frame flux for reconstruction + v(b, pH(ispec, idir), k, j, i) = robust::ratio(covH(idir), J); } + + v(b, ifail, k, j, i) = + (status == ClosureStatus::success ? FailFlags::success : FailFlags::fail); }); return TaskStatus::complete; } template +// TODO(BRR) add domain so we can do this only over interior if we are using prims as +// boundary data? TaskStatus MomentCon2Prim(T *rc) { auto *pm = rc->GetParentPointer().get(); StateDescriptor *rad = pm->packages.Get("radiation").get(); @@ -152,11 +177,11 @@ TaskStatus MomentCon2Prim(T *rc) { using settings = ClosureSettings; if (method == "moment_m1") { - return MomentCon2PrimImpl, true>(rc); + return MomentCon2PrimImpl, true>(rc); } else if (method == "moment_eddington") { - return MomentCon2PrimImpl, false>(rc); + return MomentCon2PrimImpl, false>(rc); } else if (method == "mocmc") { - return MomentCon2PrimImpl, false>(rc); + return MomentCon2PrimImpl, false>(rc); } else { PARTHENON_FAIL("Radiation method unknown"); } @@ -189,13 +214,10 @@ TaskStatus MomentPrim2ConImpl(T *rc, IndexDomain domain) { auto cF = imap.GetFlatIdx(cr::F); auto pH = imap.GetFlatIdx(pr::H); auto pv = imap.GetFlatIdx(fluid_prim::velocity); - vpack_types::FlatIdx iTilPi({-1}, -1); - if (programming::is_specialization_of::value) { - iTilPi = imap.GetFlatIdx(ir::tilPi); - } + auto iTilPi = imap.GetFlatIdx(ir::tilPi, false); auto specB = cE.GetBounds(1); - auto dirB = pH.GetBounds(1); + auto dirB = pH.GetBounds(2); auto geom = Geometry::GetCoordinateSystem(rc); @@ -208,12 +230,16 @@ TaskStatus MomentPrim2ConImpl(T *rc, IndexDomain domain) { ib.s, ib.e, // x-loop KOKKOS_LAMBDA(const int b, const int ispec, const int k, const int j, const int i) { // Set up the background - Vec con_v{{v(b, pv(0), k, j, i), v(b, pv(1), k, j, i), v(b, pv(2), k, j, i)}}; + const Real sdetgam = geom.DetGamma(CellLocation::Cent, b, k, j, i); Tens2 cov_gamma; geom.Metric(CellLocation::Cent, b, k, j, i, cov_gamma.data); - const Real sdetgam = geom.DetGamma(CellLocation::Cent, b, k, j, i); + typename CLOSURE::LocalGeometryType g(geom, CellLocation::Cent, b, k, j, i); + + const Real con_vp[3] = {v(b, pv(0), k, j, i), v(b, pv(1), k, j, i), + v(b, pv(2), k, j, i)}; + const Real W = phoebus::GetLorentzFactor(con_vp, cov_gamma.data); + Vec con_v{{con_vp[0] / W, con_vp[1] / W, con_vp[2] / W}}; - typename CLOSURE::LocalGeometryType g(geom, CellLocation::Cent, 0, b, j, i); CLOSURE c(con_v, &g); Real E; @@ -223,12 +249,14 @@ TaskStatus MomentPrim2ConImpl(T *rc, IndexDomain domain) { Vec covH = {{v(b, pH(ispec, 0), k, j, i) * J, v(b, pH(ispec, 1), k, j, i) * J, v(b, pH(ispec, 2), k, j, i) * J}}; - if (programming::is_specialization_of::value) { + if (iTilPi.IsValid()) { SPACELOOP2(ii, jj) { conTilPi(ii, jj) = v(b, iTilPi(ispec, ii, jj), k, j, i); } } else { - c.GetCovTilPiFromPrim(J, covH, &conTilPi); + c.GetConTilPiFromPrim(J, covH, &conTilPi); } + PARTHENON_DEBUG_REQUIRE(!std::isnan(J), "NAN J in rad P2C!"); + c.Prim2Con(J, covH, conTilPi, &E, &covF); v(b, cE(ispec), k, j, i) = sdetgam * E; @@ -248,11 +276,11 @@ TaskStatus MomentPrim2Con(T *rc, IndexDomain domain) { using settings = ClosureSettings; if (method == "moment_m1") { - return MomentPrim2ConImpl>(rc, domain); + return MomentPrim2ConImpl>(rc, domain); } else if (method == "moment_eddington") { - return MomentPrim2ConImpl>(rc, domain); + return MomentPrim2ConImpl>(rc, domain); } else if (method == "mocmc") { - return MomentPrim2ConImpl>(rc, domain); + return MomentPrim2ConImpl>(rc, domain); } else { PARTHENON_FAIL("Radiation method unknown!"); } @@ -267,15 +295,10 @@ TaskStatus ReconstructEdgeStates(T *rc) { using namespace PhoebusReconstruction; auto *pmb = rc->GetParentPointer().get(); - StateDescriptor *rad = pmb->packages.Get("radiation").get(); - auto method = rad->Param("method"); - bool eddington_known = false; - if (method == "mocmc") { - eddington_known = true; - } + StateDescriptor *rad_pkg = pmb->packages.Get("radiation").get(); + auto rt = rad_pkg->Param("Recon"); IndexRange ib = pmb->cellbounds.GetBoundsI(IndexDomain::interior); - const int di = (pmb->pmy_mesh->ndim > 0 ? 1 : 0); IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::interior); const int dj = (pmb->pmy_mesh->ndim > 1 ? 1 : 0); @@ -292,18 +315,12 @@ TaskStatus ReconstructEdgeStates(T *rc) { rc->PackVariables(std::vector{ir::ql}, imap_ql); VariablePack qr_base = rc->PackVariables(std::vector{ir::qr}, imap_qr); - std::vector variables = {pr::J, pr::H}; - if (eddington_known) { - variables.push_back(ir::tilPi); - } + std::vector variables = {pr::J, pr::H, ir::tilPi}; variables.push_back(ir::dJ); VariablePack v = rc->PackVariables(variables, imap); auto idx_J = imap.GetFlatIdx(pr::J); auto idx_dJ = imap.GetFlatIdx(ir::dJ); - vpack_types::FlatIdx iTilPi({-1}, -1); - if (eddington_known) { - iTilPi = imap.GetFlatIdx(ir::tilPi); - } + auto iTilPi = imap.GetFlatIdx(ir::tilPi, false); ParArrayND ql_v = rc->Get(ir::ql_v).data; ParArrayND qr_v = rc->Get(ir::qr_v).data; @@ -313,7 +330,7 @@ TaskStatus ReconstructEdgeStates(T *rc) { const int nspec = qIdx.DimSize(1); int nrecon = 4 * nspec; - if (eddington_known) { + if (iTilPi.IsValid()) { nrecon = (4 + 9) * nspec; // TODO(BRR) 6 instead of 9 for conTilPi by symmetry } @@ -335,12 +352,18 @@ TaskStatus ReconstructEdgeStates(T *rc) { const VariablePack &var = (n < nrecon ? v : v_vel); const int var_id = n % nrecon; Real *pv = &var(b, var_id, k, j, 0); + Real *pvim2 = pv - 2; Real *pvim1 = pv - 1; Real *pvip1 = pv + 1; + Real *pvip2 = pv + 2; + Real *pvjm2 = &var(b, var_id, k, j - 2 * dj, 0); Real *pvjm1 = &var(b, var_id, k, j - dj, 0); Real *pvjp1 = &var(b, var_id, k, j + dj, 0); + Real *pvjp2 = &var(b, var_id, k, j + 2 * dj, 0); + Real *pvkm2 = &var(b, var_id, k - 2 * dk, j, 0); Real *pvkm1 = &var(b, var_id, k - dk, j, 0); Real *pvkp1 = &var(b, var_id, k + dk, j, 0); + Real *pvkp2 = &var(b, var_id, k + 2 * dk, j, 0); Real *vi_l, *vi_r, *vj_l, *vj_r, *vk_l, *vk_r; if (n < nrecon) { vi_l = &ql(0, n, k, j, 1); @@ -349,6 +372,8 @@ TaskStatus ReconstructEdgeStates(T *rc) { vj_r = &qr(1 % ndim, n, k, j, 0); vk_l = &ql(2 % ndim, n, k + dk, j, 0); vk_r = &qr(2 % ndim, n, k, j, 0); + if (n == 0) { + } } else { vi_l = &ql_v(0, var_id, k, j, 1); vi_r = &qr_v(0, var_id, k, j, 0); @@ -358,16 +383,43 @@ TaskStatus ReconstructEdgeStates(T *rc) { vk_r = &qr_v(2 % ndim, var_id, k, j, 0); } - // TODO(JCD): do we want to enable other recon methods like weno5? - // x-direction - ReconLoop(member, ib.s - 1, ib.e + 1, pvim1, pv, pvip1, vi_l, - vi_r); - // y-direction - if (ndim > 1) - ReconLoop(member, ib.s, ib.e, pvjm1, pv, pvjp1, vj_l, vj_r); - // z-direction - if (ndim > 2) - ReconLoop(member, ib.s, ib.e, pvkm1, pv, pvkp1, vk_l, vk_r); + switch (rt) { + case ReconType::weno5z: + ReconLoop(member, ib.s - 1, ib.e + 1, pvim2, pvim1, pv, pvip1, pvip2, + vi_l, vi_r); + if (ndim > 1) + ReconLoop(member, ib.s, ib.e, pvjm2, pvjm1, pv, pvjp1, pvjp2, vj_l, + vj_r); + if (ndim > 2) + ReconLoop(member, ib.s, ib.e, pvkm2, pvkm1, pv, pvkp1, pvkp2, vk_l, + vk_r); + break; + case ReconType::mp5: + ReconLoop(member, ib.s - 1, ib.e + 1, pvim2, pvim1, pv, pvip1, pvip2, vi_l, + vi_r); + if (ndim > 1) + ReconLoop(member, ib.s - 1, ib.e + 1, pvjm2, pvjm1, pv, pvjp1, pvjp2, + vj_l, vj_r); + if (ndim > 2) + ReconLoop(member, ib.s - 1, ib.e + 1, pvkm2, pvkm1, pv, pvkp1, pvkp2, + vk_l, vk_r); + break; + case ReconType::linear: + ReconLoop(member, ib.s - 1, ib.e + 1, pvim1, pv, pvip1, vi_l, + vi_r); + if (ndim > 1) + ReconLoop(member, ib.s, ib.e, pvjm1, pv, pvjp1, vj_l, vj_r); + if (ndim > 2) + ReconLoop(member, ib.s, ib.e, pvkm1, pv, pvkp1, vk_l, vk_r); + break; + case ReconType::constant: + ReconLoop(member, ib.s - 1, ib.e + 1, pv, vi_l, vi_r); + if (ndim > 1) ReconLoop(member, ib.s, ib.e, pv, vj_l, vj_r); + if (ndim > 2) ReconLoop(member, ib.s, ib.e, pv, vk_l, vk_r); + break; + default: + PARTHENON_FAIL("Invalid recon option."); + } // Calculate spatial derivatives of J at zone faces for diffusion limit // x--> @@ -442,7 +494,8 @@ template TaskStatus ReconstructEdgeStates>(MeshBlockData TaskStatus CalculateFluxesImpl(T *rc) { auto *pmb = rc->GetParentPointer().get(); - StateDescriptor *rad = pmb->packages.Get("radiation").get(); + StateDescriptor *rad_pkg = pmb->packages.Get("radiation").get(); + StateDescriptor *fix_pkg = pmb->packages.Get("fixup").get(); IndexRange ib = pmb->cellbounds.GetBoundsI(IndexDomain::interior); const int di = (pmb->pmy_mesh->ndim > 0 ? 1 : 0); @@ -473,21 +526,21 @@ TaskStatus CalculateFluxesImpl(T *rc) { auto idx_Ff = imap.GetFlatIdx(cr::F); auto idx_Ef = imap.GetFlatIdx(cr::E); - auto species = rad->Param>("species"); - auto num_species = rad->Param("num_species"); - RadiationType species_d[3] = {}; - for (int s = 0; s < num_species; s++) { - species_d[s] = species[s]; - } + auto num_species = rad_pkg->Param("num_species"); // const int nblock = 1; //v.GetDim(5); auto geom = Geometry::GetCoordinateSystem(rc); + auto bounds = fix_pkg->Param("bounds"); + + // TODO(BRR) add to radiation floors const Real kappaH_min = 1.e-20; auto &coords = pmb->coords; + auto recon_fixup_strategy = rad_pkg->Param("recon_fixup_strategy"); + parthenon::par_for( DEFAULT_LOOP_PATTERN, "RadMoments::Fluxes", DevExecSpace(), X1DIR, pmb->pmy_mesh->ndim, // Loop over directions @@ -514,31 +567,92 @@ TaskStatus CalculateFluxesImpl(T *rc) { face = CellLocation::Face3; break; } + Real X[4]; + X[1] = (face == CellLocation::Face1 ? coords.x1f(k, j, i) : coords.x1v(k, j, i)); + X[2] = (face == CellLocation::Face2 ? coords.x2f(k, j, i) : coords.x2v(k, j, i)); + X[3] = (face == CellLocation::Face3 ? coords.x3f(k, j, i) : coords.x3v(k, j, i)); + + Real W_ceiling, garbage; + bounds.GetCeilings(X[1], X[2], X[3], W_ceiling, garbage); + + Real J_floor; + bounds.GetRadiationFloors(X[1], X[2], X[3], J_floor); + + Real xi_ceiling; + bounds.GetRadiationCeilings(X[1], X[2], X[3], xi_ceiling); Vec con_beta; Tens2 cov_gamma; geom.Metric(face, k, j, i, cov_gamma.data); geom.ContravariantShift(face, k, j, i, con_beta.data); const Real sdetgam = geom.DetGamma(face, k, j, i); + Tens2 con_gamma; + geom.MetricInverse(face, k, j, i, con_gamma.data); + const Real alpha = geom.Lapse(face, k, j, i); typename CLOSURE::LocalGeometryType g(geom, face, 0, k, j, i); const Real dx = coords.Dx(idir_in, k, j, i) * sqrt(cov_gamma(idir, idir)); - for (int ispec = 0; ispec < num_species; ++ispec) { + Real con_vpl[3] = {v(idx_qlv(0, idir), k, j, i), v(idx_qlv(1, idir), k, j, i), + v(idx_qlv(2, idir), k, j, i)}; + Real con_vpr[3] = {v(idx_qrv(0, idir), k, j, i), v(idx_qrv(1, idir), k, j, i), + v(idx_qrv(2, idir), k, j, i)}; + Real Wl = phoebus::GetLorentzFactor(con_vpl, cov_gamma.data); + Real Wr = phoebus::GetLorentzFactor(con_vpr, cov_gamma.data); + + if (recon_fixup_strategy == ReconFixupStrategy::bounds) { + if (Wl > W_ceiling) { + const Real rescale = std::sqrt(W_ceiling * W_ceiling - 1.) / (Wl * Wl - 1.); + SPACELOOP(ii) { con_vpl[ii] *= rescale; } + Wl = W_ceiling; + } + if (Wr > W_ceiling) { + const Real rescale = std::sqrt(W_ceiling * W_ceiling - 1.) / (Wr * Wr - 1.); + SPACELOOP(ii) { con_vpr[ii] *= rescale; } + Wr = W_ceiling; + } + } + + Vec con_vl{{con_vpl[0] / Wl, con_vpl[1] / Wl, con_vpl[2] / Wl}}; + Vec con_vr{{con_vpr[0] / Wr, con_vpr[1] / Wr, con_vpr[2] / Wr}}; - const Real &Jl = v(idx_ql(ispec, 0, idir), k, j, i); - const Real &Jr = v(idx_qr(ispec, 0, idir), k, j, i); - const Vec Hl = {Jl * v(idx_ql(ispec, 1, idir), k, j, i), - Jl * v(idx_ql(ispec, 2, idir), k, j, i), - Jl * v(idx_ql(ispec, 3, idir), k, j, i)}; - const Vec Hr = {Jr * v(idx_qr(ispec, 1, idir), k, j, i), - Jr * v(idx_qr(ispec, 2, idir), k, j, i), - Jr * v(idx_qr(ispec, 3, idir), k, j, i)}; + // Signal speeds (assume (i.e. somewhat overestimate, esp. for large opt. depth) + // cs_rad = 1) + const Real sigp = alpha * std::sqrt(con_gamma(idir, idir)) - con_beta(idir); + const Real sigm = -alpha * std::sqrt(con_gamma(idir, idir)) - con_beta(idir); + const Real asym_sigl = alpha * con_vl(idir) - con_beta(idir); + const Real asym_sigr = alpha * con_vr(idir) - con_beta(idir); - Vec con_vl{{v(idx_qlv(0, idir), k, j, i), v(idx_qlv(1, idir), k, j, i), - v(idx_qlv(2, idir), k, j, i)}}; - Vec con_vr{{v(idx_qrv(0, idir), k, j, i), v(idx_qrv(1, idir), k, j, i), - v(idx_qrv(2, idir), k, j, i)}}; + for (int ispec = 0; ispec < num_species; ++ispec) { + // TODO(BRR) Use floors + Real Jl = v(idx_ql(ispec, 0, idir), k, j, i); + Real Jr = v(idx_qr(ispec, 0, idir), k, j, i); + if (recon_fixup_strategy == ReconFixupStrategy::bounds) { + Jl = std::max(Jl, J_floor); + Jr = std::max(Jr, J_floor); + } + Vec Hl = {Jl * v(idx_ql(ispec, 1, idir), k, j, i), + Jl * v(idx_ql(ispec, 2, idir), k, j, i), + Jl * v(idx_ql(ispec, 3, idir), k, j, i)}; + Vec Hr = {Jr * v(idx_qr(ispec, 1, idir), k, j, i), + Jr * v(idx_qr(ispec, 2, idir), k, j, i), + Jr * v(idx_qr(ispec, 3, idir), k, j, i)}; + if (recon_fixup_strategy == ReconFixupStrategy::bounds) { + const Real xil = + std::sqrt(g.contractCov3Vectors(Hl, Hl) - + std::pow(g.contractConCov3Vectors(con_vl, Hl), 2)) / + Jl; + const Real xir = + std::sqrt(g.contractCov3Vectors(Hr, Hr) - + std::pow(g.contractConCov3Vectors(con_vr, Hr), 2)) / + Jr; + if (xil > xi_ceiling) { + SPACELOOP(ii) { Hl(ii) *= xi_ceiling / xil; } + } + if (xir > xi_ceiling) { + SPACELOOP(ii) { Hr(ii) *= xi_ceiling / xir; } + } + } Vec cov_dJ{{v(idx_dJ(ispec, 0, idir), k, j, i), v(idx_dJ(ispec, 1, idir), k, j, i), @@ -572,8 +686,8 @@ TaskStatus CalculateFluxesImpl(T *rc) { con_tilPir(ii, jj) = v(idx_qr(ispec, 4 + ii + 3 * jj, idir), k, j, i); } } else { - cl.GetCovTilPiFromPrim(Jl, HasymL, &con_tilPil); - cr.GetCovTilPiFromPrim(Jr, HasymR, &con_tilPir); + cl.GetConTilPiFromPrim(Jl, HasymL, &con_tilPil); + cr.GetConTilPiFromPrim(Jr, HasymR, &con_tilPir); } cl.getFluxesFromPrim(Jl, HasymL, con_tilPil, &conFl_asym, &Pl_asym); cr.getFluxesFromPrim(Jr, HasymR, con_tilPir, &conFr_asym, &Pr_asym); @@ -581,8 +695,8 @@ TaskStatus CalculateFluxesImpl(T *rc) { // Regular fluxes if (!programming::is_specialization_of::value) { // Recalculate Eddington if using J, H - cl.GetCovTilPiFromPrim(Jl, Hl, &con_tilPil); - cr.GetCovTilPiFromPrim(Jr, Hr, &con_tilPir); + cl.GetConTilPiFromPrim(Jl, Hl, &con_tilPil); + cr.GetConTilPiFromPrim(Jr, Hr, &con_tilPir); } cl.getFluxesFromPrim(Jl, Hl, con_tilPil, &conFl, &Pl); cr.getFluxesFromPrim(Jr, Hr, con_tilPir, &conFr, &Pr); @@ -591,12 +705,16 @@ TaskStatus CalculateFluxesImpl(T *rc) { // Mix the fluxes by the Peclet number // TODO: (LFR) Make better choices - const Real speed = a * 1.0 + (1 - a) * std::max(sqrt(cl.v2), sqrt(cr.v2)); conFl = a * conFl + (1 - a) * conFl_asym; conFr = a * conFr + (1 - a) * conFr_asym; Pl = a * Pl + (1 - a) * Pl_asym; Pr = a * Pr + (1 - a) * Pr_asym; + const Real rad_sigspeed = std::max(std::fabs(sigm), std::fabs(sigp)); + const Real asym_sigspeed = + std::max(std::fabs(asym_sigl), std::fabs(asym_sigr)); + const Real sigspeed = a * rad_sigspeed + (1. - a) * asym_sigspeed; + // Correct the fluxes with the shift terms conFl(idir) -= con_beta(idir) * El; conFr(idir) -= con_beta(idir) * Er; @@ -608,14 +726,15 @@ TaskStatus CalculateFluxesImpl(T *rc) { // Calculate the numerical flux using LLF v.flux(idir_in, idx_Ef(ispec), k, j, i) = - 0.5 * sdetgam * (conFl(idir) + conFr(idir) + speed * (El - Er)); + 0.5 * sdetgam * (conFl(idir) + conFr(idir) + sigspeed * (El - Er)); SPACELOOP(ii) { v.flux(idir_in, idx_Ff(ispec, ii), k, j, i) = 0.5 * sdetgam * - (Pl(idir, ii) + Pr(idir, ii) + speed * (covFl(ii) - covFr(ii))); + (Pl(idir, ii) + Pr(idir, ii) + sigspeed * (covFl(ii) - covFr(ii))); } - if (sdetgam < std::numeric_limits::min() * 10) { + + if (sdetgam < robust::SMALL()) { v.flux(idir_in, idx_Ef(ispec), k, j, i) = 0.0; SPACELOOP(ii) v.flux(idir_in, idx_Ff(ispec, ii), k, j, i) = 0.0; } @@ -633,11 +752,11 @@ TaskStatus CalculateFluxes(T *rc) { using settings = ClosureSettings; if (method == "moment_m1") { - return CalculateFluxesImpl>(rc); + return CalculateFluxesImpl>(rc); } else if (method == "moment_eddington") { - return CalculateFluxesImpl>(rc); + return CalculateFluxesImpl>(rc); } else if (method == "mocmc") { - return CalculateFluxesImpl>(rc); + return CalculateFluxesImpl>(rc); } else { PARTHENON_FAIL("Radiation method unknown!"); } @@ -648,7 +767,6 @@ template TaskStatus CalculateFluxes>(MeshBlockData *); template TaskStatus CalculateGeometricSourceImpl(T *rc, T *rc_src) { constexpr int ND = Geometry::NDFULL; - // constexpr int NS = Geometry::NDSPACE; auto *pmb = rc->GetParentPointer().get(); namespace cr = radmoment_cons; @@ -656,20 +774,19 @@ TaskStatus CalculateGeometricSourceImpl(T *rc, T *rc_src) { namespace ir = radmoment_internal; namespace p = fluid_prim; PackIndexMap imap; - std::vector vars{cr::E, cr::F, pr::J, pr::H, p::velocity}; - if (programming::is_specialization_of::value) { - vars.push_back(ir::tilPi); - } + std::vector vars{cr::E, cr::F, pr::J, pr::H, p::velocity, ir::tilPi}; + vars.push_back(diagnostic_variables::r_src_terms); +#if SET_FLUX_SRC_DIAGS + vars.push_back(diagnostic_variables::r_src_terms); +#endif auto v = rc->PackVariables(vars, imap); auto idx_E = imap.GetFlatIdx(cr::E); auto idx_F = imap.GetFlatIdx(cr::F); auto idx_J = imap.GetFlatIdx(pr::J); auto idx_H = imap.GetFlatIdx(pr::H); auto pv = imap.GetFlatIdx(p::velocity); - vpack_types::FlatIdx iTilPi({-1}, -1); - if (programming::is_specialization_of::value) { - iTilPi = imap.GetFlatIdx(ir::tilPi); - } + auto iTilPi = imap.GetFlatIdx(ir::tilPi, false); + auto idx_diag = imap.GetFlatIdx(diagnostic_variables::r_src_terms, false); PackIndexMap imap_src; std::vector vars_src{cr::E, cr::F}; @@ -695,10 +812,12 @@ TaskStatus CalculateGeometricSourceImpl(T *rc, T *rc_src) { ib.s, ib.e, // x-loop KOKKOS_LAMBDA(const int iblock, const int k, const int j, const int i) { // Set up the background state - Vec con_v{{v(iblock, pv(0), k, j, i), v(iblock, pv(1), k, j, i), - v(iblock, pv(2), k, j, i)}}; Tens2 cov_gamma; geom.Metric(CellLocation::Cent, iblock, k, j, i, cov_gamma.data); + const Real con_vp[3] = {v(iblock, pv(0), k, j, i), v(iblock, pv(1), k, j, i), + v(iblock, pv(2), k, j, i)}; + const Real W = phoebus::GetLorentzFactor(con_vp, cov_gamma.data); + Vec con_v{{con_vp[0] / W, con_vp[1] / W, con_vp[2] / W}}; typename CLOSURE::LocalGeometryType g(geom, CellLocation::Cent, iblock, k, j, i); CLOSURE c(con_v, &g); @@ -707,25 +826,16 @@ TaskStatus CalculateGeometricSourceImpl(T *rc, T *rc_src) { Real sdetgam = geom.DetGamma(CellLocation::Cent, iblock, k, j, i); Vec con_beta; geom.ContravariantShift(CellLocation::Cent, k, j, i, con_beta.data); - Real beta2 = 0.0; - SPACELOOP2(ii, jj) beta2 += con_beta(ii) * con_beta(jj) * cov_gamma(ii, jj); - + Real con_g[4][4] = {0}; + geom.SpacetimeMetricInverse(CellLocation::Cent, iblock, k, j, i, con_g); Real dlnalp[ND]; Real Gamma[ND][ND][ND]; geom.GradLnAlpha(CellLocation::Cent, iblock, k, j, i, dlnalp); geom.ConnectionCoefficient(CellLocation::Cent, iblock, k, j, i, Gamma); - // Get the gradient of the shift from the Christoffel symbols of the first kind - // Get the extrinsic curvature from the Christoffel symbols of the first kind - // All indices are covariant - Tens2 dbeta, K; - const Real iFac = 1.0 / (alp + beta2 / alp); - SPACELOOP2(ii, jj) { - dbeta(ii, jj) = Gamma[ii + 1][jj + 1][0] + Gamma[ii + 1][0][jj + 1]; - K(ii, jj) = Gamma[ii + 1][0][jj + 1]; - SPACELOOP(kk) K(ii, jj) -= Gamma[ii + 1][kk + 1][jj + 1] * con_beta(kk); - K(ii, jj) *= iFac; - } + Real con_u[4]; + con_u[0] = W / alp; + SPACELOOP(ii) { con_u[ii + 1] = W * con_v(ii) - con_beta(ii) / alp; } for (int ispec = 0; ispec < nspec; ++ispec) { Real E = v(iblock, idx_E(ispec), k, j, i) / sdetgam; @@ -736,37 +846,71 @@ TaskStatus CalculateGeometricSourceImpl(T *rc, T *rc_src) { Vec covH{{J * v(iblock, idx_H(ispec, 0), k, j, i), J * v(iblock, idx_H(ispec, 1), k, j, i), J * v(iblock, idx_H(ispec, 2), k, j, i)}}; + Vec conF; g.raise3Vector(covF, &conF); - Tens2 conP, con_tilPi; - if (programming::is_specialization_of::value) { + Real con_H4[4] = {0}; + SPACELOOP2(ii, jj) { con_H4[ii + 1] += g.con_gamma(ii, jj) * covH(jj); } + + Real conTilPi[4][4] = {0}; + if (iTilPi.IsValid()) { SPACELOOP2(ii, jj) { - con_tilPi(ii, jj) = v(iblock, iTilPi(ispec, ii, jj), k, j, i); + conTilPi[ii + 1][jj + 1] = v(iblock, iTilPi(ispec, ii, jj), k, j, i); } } else { - c.GetCovTilPiFromPrim(J, covH, &con_tilPi); + Tens2 con_tilPi{0}; + c.GetConTilPiFromPrim(J, covH, &con_tilPi); + SPACELOOP2(ii, jj) { conTilPi[ii + 1][jj + 1] = con_tilPi(ii, jj); } + } + + Real con_T[4][4]; + SPACETIMELOOP2(mu, nu) { + Real conh_munu = con_g[mu][nu] + con_u[mu] * con_u[nu]; + con_T[mu][nu] = (con_u[mu] * con_u[nu] + conh_munu / 3.) * J; + con_T[mu][nu] += con_u[mu] * con_H4[nu] + con_u[nu] * con_H4[mu]; + con_T[mu][nu] += J * conTilPi[mu][nu]; } - c.getConPFromPrim(J, covH, con_tilPi, &conP); + + // TODO(BRR) add Pij contribution Real srcE = 0.0; - SPACELOOP2(ii, jj) srcE += K(ii, jj) * conP(ii, jj); - SPACELOOP(ii) srcE -= dlnalp[ii + 1] * conF(ii); - srcE *= alp; + SPACETIMELOOP(mu) { + srcE += con_T[mu][0] * dlnalp[mu]; + SPACETIMELOOP(nu) { + Real Gamma_udd = 0.; + SPACETIMELOOP(lam) { Gamma_udd += con_g[0][lam] * Gamma[lam][nu][mu]; } + srcE -= con_T[mu][nu] * Gamma_udd; + } + } + srcE *= alp * alp; Vec srcF{0, 0, 0}; SPACELOOP(ii) { - SPACELOOP(jj) srcF(ii) += covF(jj) * dbeta(ii, jj); - srcF(ii) -= alp * E * dlnalp[ii + 1]; - SPACELOOP2(jj, kk) - srcF(ii) += alp * conP(jj, kk) * Gamma[jj + 1][kk + 1][ii + 1]; + SPACETIMELOOP2(mu, nu) { srcF(ii) += con_T[mu][nu] * Gamma[mu][nu][ii + 1]; } + srcF(ii) *= alp; } + v_src(iblock, idx_E_src(ispec), k, j, i) = sdetgam * srcE; - SPACELOOP(ii) v_src(iblock, idx_F_src(ispec, ii), k, j, i) = sdetgam * srcF(ii); + SPACELOOP(ii) { + v_src(iblock, idx_F_src(ispec, ii), k, j, i) = sdetgam * srcF(ii); + } + +#if SET_FLUX_SRC_DIAGS + v(iblock, idx_diag(ispec, 0), k, j, i) = + v_src(iblock, idx_E_src(ispec), k, j, i); + v(iblock, idx_diag(ispec, 1), k, j, i) = + v_src(iblock, idx_F_src(ispec, 0), k, j, i); + v(iblock, idx_diag(ispec, 2), k, j, i) = + v_src(iblock, idx_F_src(ispec, 1), k, j, i); + v(iblock, idx_diag(ispec, 3), k, j, i) = + v_src(iblock, idx_F_src(ispec, 2), k, j, i); +#endif } }); return TaskStatus::complete; } + template TaskStatus CalculateGeometricSource(T *rc, T *rc_src) { auto *pm = rc->GetParentPointer().get(); @@ -775,12 +919,11 @@ TaskStatus CalculateGeometricSource(T *rc, T *rc_src) { using settings = ClosureSettings; if (method == "moment_m1") { - return CalculateGeometricSourceImpl>(rc, rc_src); + return CalculateGeometricSourceImpl>(rc, rc_src); } else if (method == "moment_eddington") { - return CalculateGeometricSourceImpl>(rc, rc_src); + return CalculateGeometricSourceImpl>(rc, rc_src); } else if (method == "mocmc") { - return CalculateGeometricSourceImpl>(rc, - rc_src); + return CalculateGeometricSourceImpl>(rc, rc_src); } else { PARTHENON_FAIL("Radiation method unknown!"); } @@ -789,144 +932,6 @@ TaskStatus CalculateGeometricSource(T *rc, T *rc_src) { template TaskStatus CalculateGeometricSource>(MeshBlockData *, MeshBlockData *); -// TODO(BRR) Unsure how else to get radiation parameters from MeshData -template <> -TaskStatus MomentFluidSource(MeshData *rc, Real dt, bool update_fluid) { - for (int n = 0; n < rc->NumBlocks(); n++) { - MomentFluidSource(rc->GetBlockData(n).get(), dt, update_fluid); - } - return TaskStatus::complete; -} - -template -TaskStatus MomentFluidSource(T *rc, Real dt, bool update_fluid) { - auto *pmb = rc->GetParentPointer().get(); - StateDescriptor *rad = pmb->packages.Get("radiation").get(); - namespace cr = radmoment_cons; - namespace pr = radmoment_prim; - namespace ir = radmoment_internal; - namespace c = fluid_cons; - namespace p = fluid_prim; - std::vector vars{cr::E, cr::F, p::density, p::temperature, - p::ye, p::velocity, pr::J, pr::H, - ir::kappaJ, ir::kappaH, ir::JBB}; - if (update_fluid) { - vars.push_back(c::energy); - vars.push_back(c::momentum); - vars.push_back(c::ye); - } - - PackIndexMap imap; - auto v = rc->PackVariables(vars, imap); - auto idx_E = imap.GetFlatIdx(cr::E); - auto idx_F = imap.GetFlatIdx(cr::F); - auto idx_J = imap.GetFlatIdx(pr::J); - auto idx_H = imap.GetFlatIdx(pr::H); - - auto idx_kappaJ = imap.GetFlatIdx(ir::kappaJ); - auto idx_kappaH = imap.GetFlatIdx(ir::kappaH); - auto idx_JBB = imap.GetFlatIdx(ir::JBB); - auto pv = imap.GetFlatIdx(p::velocity); - - int prho = imap[p::density].first; - int pT = imap[p::temperature].first; - int pYe = imap[p::ye].first; - - int ceng(-1), cmom_lo(-1), cye(-1); - if (update_fluid) { - ceng = imap[c::energy].first; - cmom_lo = imap[c::momentum].first; - cye = imap[c::ye].first; - } - - IndexRange ib = rc->GetBoundsI(IndexDomain::interior); - IndexRange jb = rc->GetBoundsJ(IndexDomain::interior); - IndexRange kb = rc->GetBoundsK(IndexDomain::interior); - - // Get the background geometry - auto geom = Geometry::GetCoordinateSystem(rc); - - int nblock = v.GetDim(5); - // TODO(BRR) This updates all neutrino species (including contributions to fluid) - // regardless of whether they are active - // int nspec = idx_E.DimSize(1); - - auto species = rad->Param>("species"); - auto num_species = rad->Param("num_species"); - RadiationType species_d[3] = {}; - for (int s = 0; s < num_species; s++) { - species_d[s] = species[s]; - } - - parthenon::par_for( - DEFAULT_LOOP_PATTERN, "RadMoments::FluidSource", DevExecSpace(), 0, - nblock - 1, // Loop over blocks - kb.s, kb.e, // z-loop - jb.s, jb.e, // y-loop - ib.s, ib.e, // x-loop - KOKKOS_LAMBDA(const int iblock, const int k, const int j, const int i) { - for (int ispec = 0; ispec < num_species; ++ispec) { - - // Set up the background state - Vec con_v{{v(iblock, pv(0), k, j, i), v(iblock, pv(1), k, j, i), - v(iblock, pv(2), k, j, i)}}; - Tens2 cov_gamma; - geom.Metric(CellLocation::Cent, iblock, k, j, i, cov_gamma.data); - Real alpha = geom.Lapse(CellLocation::Cent, iblock, k, j, i); - Real sdetgam = geom.DetGamma(CellLocation::Cent, iblock, k, j, i); - LocalThreeGeometry g(geom, CellLocation::Cent, iblock, k, j, i); - - /// TODO: (LFR) Move beyond Eddington for this update - ClosureEdd c(con_v, &g); - - Real Estar = v(iblock, idx_E(ispec), k, j, i) / sdetgam; - Vec cov_Fstar{v(iblock, idx_F(ispec, 0), k, j, i) / sdetgam, - v(iblock, idx_F(ispec, 1), k, j, i) / sdetgam, - v(iblock, idx_F(ispec, 2), k, j, i) / sdetgam}; - - Real dE; - Vec cov_dF; - - // Treat the Eddington tensor explicitly for now - Real &J = v(iblock, idx_J(ispec), k, j, i); - Vec cov_H{{ - J * v(iblock, idx_H(ispec, 0), k, j, i), - J * v(iblock, idx_H(ispec, 1), k, j, i), - J * v(iblock, idx_H(ispec, 2), k, j, i), - }}; - Tens2 con_tilPi; - - c.GetCovTilPiFromPrim(J, cov_H, &con_tilPi); - - Real B = v(iblock, idx_JBB(ispec), k, j, i); - Real tauJ = alpha * dt * v(iblock, idx_kappaJ(ispec), k, j, i); - Real tauH = alpha * dt * v(iblock, idx_kappaH(ispec), k, j, i); - Real kappaH = v(iblock, idx_kappaH(ispec), k, j, i); - c.LinearSourceUpdate(Estar, cov_Fstar, con_tilPi, B, tauJ, tauH, &dE, &cov_dF); - - // Add source corrections to conserved iration variables - v(iblock, idx_E(ispec), k, j, i) += sdetgam * dE; - for (int idir = 0; idir < 3; ++idir) { - v(iblock, idx_F(ispec, idir), k, j, i) += sdetgam * cov_dF(idir); - } - - // Add source corrections to conserved fluid variables - if (update_fluid) { - v(iblock, cye, k, j, i) -= sdetgam * 0.0; - v(iblock, ceng, k, j, i) -= sdetgam * dE; - v(iblock, cmom_lo + 0, k, j, i) -= sdetgam * cov_dF(0); - v(iblock, cmom_lo + 1, k, j, i) -= sdetgam * cov_dF(1); - v(iblock, cmom_lo + 2, k, j, i) -= sdetgam * cov_dF(2); - } - } - }); - - return TaskStatus::complete; -} -// template TaskStatus MomentFluidSource>(MeshData *, Real, bool); -template TaskStatus MomentFluidSource>(MeshBlockData *, Real, - bool); - template TaskStatus MomentCalculateOpacities(T *rc) { auto *pmb = rc->GetParentPointer().get(); @@ -964,12 +969,11 @@ TaskStatus MomentCalculateOpacities(T *rc) { IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::entire); IndexRange kb = pmb->cellbounds.GetBoundsK(IndexDomain::entire); - // Mainly for testing purposes, probably should be able to do this with the opacity code - // itself + // Mainly for testing purposes, probably should be able to do this with the opacity + // code itself const auto scattering_fraction = rad->Param("scattering_fraction"); // Get the device opacity object - using namespace singularity::neutrinos; const auto &d_opacity = opac->Param("d.opacity"); const auto &d_mean_opacity = opac->Param("d.mean_opacity"); @@ -983,7 +987,7 @@ TaskStatus MomentCalculateOpacities(T *rc) { RadiationType dev_species[3] = {species[0], species[1], species[2]}; parthenon::par_for( - DEFAULT_LOOP_PATTERN, "RadMoments::FluidSource", DevExecSpace(), 0, + DEFAULT_LOOP_PATTERN, "RadMoments::CalculateOpacities", DevExecSpace(), 0, nblock - 1, // Loop over blocks kb.s, kb.e, // z-loop jb.s, jb.e, // y-loop @@ -992,7 +996,7 @@ TaskStatus MomentCalculateOpacities(T *rc) { for (int ispec = 0; ispec < nspec; ++ispec) { const Real rho = v(iblock, prho, k, j, i); const Real Temp = v(iblock, pT, k, j, i); - const Real Ye = v(iblock, pYe, k, j, i); + const Real Ye = pYe > 0 ? v(iblock, pYe, k, j, i) : 0.5; Real kappa = d_mean_opacity.RosselandMeanAbsorptionCoefficient( rho, Temp, Ye, dev_species[ispec]); diff --git a/src/radiation/moments_source.cpp b/src/radiation/moments_source.cpp new file mode 100644 index 00000000..d7d9ed24 --- /dev/null +++ b/src/radiation/moments_source.cpp @@ -0,0 +1,796 @@ +// © 2022. Triad National Security, LLC. All rights reserved. +// This program was produced under U.S. Government contract +// 89233218CNA000001 for Los Alamos National Laboratory (LANL), which +// is operated by Triad National Security, LLC for the U.S. +// Department of Energy/National Nuclear Security Administration. All +// rights in the program are reserved by Triad National Security, LLC, +// and the U.S. Department of Energy/National Nuclear Security +// Administration. The Government is granted for itself and others +// acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +// license in this material to reproduce, prepare derivative works, +// distribute copies to the public, perform publicly and display +// publicly, and to permit others to do so. + +#include +#include +#include + +#include + +#include "phoebus_utils/linear_algebra.hpp" +#include "phoebus_utils/programming_utils.hpp" +#include "phoebus_utils/root_find.hpp" +#include "radiation/closure.hpp" +#include "radiation/closure_m1.hpp" +#include "radiation/closure_mocmc.hpp" +#include "radiation/local_three_geometry.hpp" +#include "radiation/radiation.hpp" +#include "reconstruction.hpp" + +//#include "fluid/con2prim_robust.hpp" +#include "fixup/fixup.hpp" +#include "fluid/prim2con.hpp" + +namespace radiation { + +using namespace singularity::neutrinos; +using fixup::Bounds; +using singularity::EOS; + +template +class SourceResidual4 { + public: + KOKKOS_FUNCTION + SourceResidual4(const EOS &eos, const Opacity &opac, const MeanOpacity &mopac, + const Real rho, const Real Ye, const Real bprim[3], + const RadiationType species, /*const*/ Tens2 &conTilPi, + const Real (&gcov)[4][4], const Real (&gammacon)[3][3], + const Real alpha, const Real beta[3], const Real sdetgam, + const Real scattering_fraction, typename CLOSURE::LocalGeometryType &g, + Real (&U_mhd_0)[4], Real (&U_rad_0)[4], const int &k, const int &j, + const int &i) + : eos_(eos), opac_(opac), mopac_(mopac), rho_(rho), bprim_(&(bprim[0])), + species_(species), conTilPi_(conTilPi), gcov_(&gcov), gammacon_(&gammacon), + alpha_(alpha), beta_(&(beta[0])), sdetgam_(sdetgam), + scattering_fraction_(scattering_fraction), g_(g), U_mhd_0_(&U_mhd_0), + U_rad_0_(&U_rad_0), k_(k), j_(j), i_(i) { + lambda_[0] = Ye; + lambda_[1] = 0.; + } + + KOKKOS_INLINE_FUNCTION + void CalculateMHDConserved(Real P_mhd[4], Real U_mhd[4]) { + Real Pg = eos_.PressureFromDensityInternalEnergy(rho_, P_mhd[0] / rho_, lambda_); + Real gam1 = + eos_.BulkModulusFromDensityInternalEnergy(rho_, P_mhd[0] / rho_, lambda_) / Pg; + Real D; + Real bcons[3]; + Real ye_cons; + prim2con::p2c(rho_, &(P_mhd[1]), bprim_, P_mhd[0], lambda_[0], Pg, gam1, *gcov_, + *gammacon_, beta_, alpha_, sdetgam_, D, &(U_mhd[1]), bcons, U_mhd[0], + ye_cons); + } + + KOKKOS_INLINE_FUNCTION + void CalculateRadConserved(Real U_mhd[4], Real U_rad[4]) { + for (int n = 0; n < 4; n++) { + U_rad[n] = (*U_rad_0_)[n] - (U_mhd[n] - (*U_mhd_0_)[n]); + } + } + + KOKKOS_INLINE_FUNCTION + void CalculateRadConservedFromRadPrim(Real P_rad[4], Real U_rad[4]) { + PARTHENON_FAIL("Not implemented!"); + } + + KOKKOS_INLINE_FUNCTION + ClosureStatus CalculateRadPrimitive(Real P_mhd[4], Real U_rad[4], Real P_rad[4]) { + const Real E = U_rad[0] / sdetgam_; + Vec cov_F{U_rad[1] / sdetgam_, U_rad[2] / sdetgam_, U_rad[3] / sdetgam_}; + Vec cov_H; + Real W = 0.; + SPACELOOP2(ii, jj) { W += (*gcov_)[ii + 1][jj + 1] * P_mhd[ii + 1] * P_mhd[jj + 1]; } + W = std::sqrt(1. + W); + Vec con_v{P_mhd[1] / W, P_mhd[2] / W, P_mhd[3] / W}; + CLOSURE c(con_v, &g_); + // TODO(BRR) Accept separately calculated con_tilPi as an option + // TODO(BRR) Store xi, phi guesses + Real xi; + Real phi; + c.GetConTilPiFromCon(E, cov_F, xi, phi, &conTilPi_); + auto status = c.Con2Prim(E, cov_F, conTilPi_, &(P_rad[0]), &cov_H); + SPACELOOP(ii) { P_rad[ii + 1] = cov_H(ii); } + return status; + } + + KOKKOS_INLINE_FUNCTION + void CalculateSource(Real P_mhd[4], Real P_rad[4], Real S[4]) { + Real Tg = eos_.TemperatureFromDensityInternalEnergy(rho_, P_mhd[0] / rho_, lambda_); + Real JBB = opac_.EnergyDensityFromTemperature(Tg, species_); + Real kappaH = + mopac_.RosselandMeanAbsorptionCoefficient(rho_, Tg, lambda_[0], species_); + // TODO(BRR) this is arguably cheating, arguably not. Should include dt though + // kappaH * dt < 1 / eps + kappaH = std::min(kappaH, 1.e5); + Real kappaJ = (1. - scattering_fraction_) * kappaH; + Real W = 0.; + SPACELOOP2(ii, jj) { W += (*gcov_)[ii + 1][jj + 1] * P_mhd[ii + 1] * P_mhd[jj + 1]; } + W = std::sqrt(1. + W); + Real cov_v[3] = {0}; + SPACELOOP2(ii, jj) { cov_v[ii] += (*gcov_)[ii + 1][jj + 1] * P_mhd[ii + 1] / W; } + Real vdH = 0.; + SPACELOOP(ii) { vdH += P_mhd[ii + 1] / W * P_rad[ii + 1]; } + + S[0] = alpha_ * sdetgam_ * (kappaJ * W * (JBB - P_rad[0]) - kappaH * vdH); + SPACELOOP(ii) { + S[ii + 1] = alpha_ * sdetgam_ * + (kappaJ * W * cov_v[ii] * (JBB - P_rad[0]) - kappaH * P_rad[1 + ii]); + } + } + + private: + const EOS &eos_; + const Opacity &opac_; + const MeanOpacity &mopac_; + const Real rho_; + const Real *bprim_; + const RadiationType species_; + Real lambda_[2]; + Tens2 &conTilPi_; + + const Real (*gcov_)[4][4]; + const Real (*gammacon_)[3][3]; + const Real alpha_; + const Real *beta_; + const Real sdetgam_; + const Real scattering_fraction_; + + typename CLOSURE::LocalGeometryType &g_; + + const Real (*U_mhd_0_)[4]; + const Real (*U_rad_0_)[4]; + + const int &k_, &j_, &i_; +}; + +class InteractionTResidual { + public: + KOKKOS_FUNCTION + InteractionTResidual(const EOS &eos, const Opacity &opacity, + const MeanOpacity &mean_opacity, const Real &rho, const Real &ug0, + const Real &Ye, const Real J0[3], const int &nspec, + const RadiationType species[3], const Real &scattering_fraction, + const Real &dtau) + : eos_(eos), opacity_(opacity), mean_opacity_(mean_opacity), rho_(rho), ug0_(ug0), + Ye_(Ye), nspec_(nspec), scattering_fraction_(scattering_fraction), dtau_(dtau) { + for (int ispec = 0; ispec < nspec; ++ispec) { + J0_[ispec] = J0[ispec]; + species_[ispec] = species[ispec]; + } + } + + KOKKOS_INLINE_FUNCTION + Real operator()(const Real T) { + Real lambda[2] = {Ye_, 0.0}; + + Real J0_tot = 0.; + Real dJ_tot = 0.; + + for (int ispec = 0; ispec < nspec_; ++ispec) { + J0_tot += J0_[ispec]; + const Real kappa = + (1. - scattering_fraction_) * + mean_opacity_.RosselandMeanAbsorptionCoefficient(rho_, T, Ye_, species_[ispec]); + + const Real JBB = opacity_.EnergyDensityFromTemperature(T, species_[ispec]); + + dJ_tot += (J0_[ispec] + dtau_ * kappa * JBB) / (1. + dtau_ * kappa) - J0_[ispec]; + } + + const Real ug1 = rho_ * eos_.InternalEnergyFromDensityTemperature(rho_, T, lambda); + + return ((ug1 - ug0_) + (dJ_tot)) / (ug0_ + J0_tot); + } + + private: + const EOS &eos_; + const Opacity &opacity_; + const MeanOpacity &mean_opacity_; + const Real &rho_; + const Real &ug0_; + const Real &Ye_; + Real J0_[MaxNumRadiationSpecies]; + const int &nspec_; + const Real &scattering_fraction_; + const Real &dtau_; // Proper time + RadiationType species_[MaxNumRadiationSpecies]; +}; + +template +TaskStatus MomentFluidSourceImpl(T *rc, Real dt, bool update_fluid) { + PARTHENON_REQUIRE(USE_VALENCIA, "Covariant MHD formulation not supported!"); + + auto *pmb = rc->GetParentPointer().get(); + StateDescriptor *fluid_pkg = pmb->packages.Get("fluid").get(); + StateDescriptor *rad = pmb->packages.Get("radiation").get(); + StateDescriptor *eos_pkg = pmb->packages.Get("eos").get(); + StateDescriptor *opac = pmb->packages.Get("opacity").get(); + StateDescriptor *fix_pkg = pmb->packages.Get("fixup").get(); + auto eos = eos_pkg->Param("d.EOS"); + namespace cr = radmoment_cons; + namespace pr = radmoment_prim; + namespace ir = radmoment_internal; + namespace c = fluid_cons; + namespace p = fluid_prim; + std::vector vars{c::energy, c::momentum, c::ye, cr::E, + cr::F, c::bfield, p::density, p::temperature, + p::energy, p::ye, p::velocity, p::bfield, + pr::J, pr::H, ir::kappaJ, ir::kappaH, + ir::JBB, ir::tilPi, ir::srcfail}; + + PackIndexMap imap; + auto v = rc->PackVariables(vars, imap); + auto idx_E = imap.GetFlatIdx(cr::E); + auto idx_F = imap.GetFlatIdx(cr::F); + auto idx_J = imap.GetFlatIdx(pr::J); + auto idx_H = imap.GetFlatIdx(pr::H); + + auto idx_kappaJ = imap.GetFlatIdx(ir::kappaJ); + auto idx_kappaH = imap.GetFlatIdx(ir::kappaH); + auto idx_JBB = imap.GetFlatIdx(ir::JBB); + auto idx_tilPi = imap.GetFlatIdx(ir::tilPi, false); + auto ifail = imap[ir::srcfail].first; + auto pv = imap.GetFlatIdx(p::velocity); + + int prho = imap[p::density].first; + int peng = imap[p::energy].first; + int pT = imap[p::temperature].first; + int pYe = imap[p::ye].first; + int pb_lo = imap[p::bfield].first; + int cb_lo = imap[c::bfield].first; + + int ceng = imap[c::energy].first; + int cmom_lo = imap[c::momentum].first; + int cmom_hi = imap[c::momentum].second; + int cye = imap[c::ye].first; + + IndexRange ib = rc->GetBoundsI(IndexDomain::interior); + IndexRange jb = rc->GetBoundsJ(IndexDomain::interior); + IndexRange kb = rc->GetBoundsK(IndexDomain::interior); + + // Get the background geometry + auto geom = Geometry::GetCoordinateSystem(rc); + + int nblock = v.GetDim(5); + + auto species = rad->Param>("species"); + auto num_species = rad->Param("num_species"); + RadiationType species_d[3] = {}; + for (int s = 0; s < num_species; s++) { + species_d[s] = species[s]; + } + + auto bounds = fix_pkg->Param("bounds"); + + auto coords = pmb->coords; + + const auto &d_opacity = opac->Param("d.opacity"); + const auto &d_mean_opacity = opac->Param("d.mean_opacity"); + // Mainly for testing purposes, probably should be able to do this with the opacity code + // itself + const auto scattering_fraction = rad->Param("scattering_fraction"); + + const auto src_solver = rad->Param("src_solver"); + const auto src_use_oned_backup = rad->Param("src_use_oned_backup"); + const auto src_rootfind_eps = rad->Param("src_rootfind_eps"); + const auto src_rootfind_tol = rad->Param("src_rootfind_tol"); + const auto src_rootfind_maxiter = rad->Param("src_rootfind_maxiter"); + const auto oned_fixup_strategy = rad->Param("oned_fixup_strategy"); + + parthenon::par_for( + DEFAULT_LOOP_PATTERN, "RadMoments::FluidSource", DevExecSpace(), 0, + nblock - 1, // Loop over blocks + kb.s, kb.e, // z-loop + jb.s, jb.e, // y-loop + ib.s, ib.e, // x-loop + KOKKOS_LAMBDA(const int iblock, const int k, const int j, const int i) { + // Geometry + Tens2 cov_gamma; + geom.Metric(CellLocation::Cent, iblock, k, j, i, cov_gamma.data); + Tens2 con_gamma; + geom.MetricInverse(CellLocation::Cent, iblock, k, j, i, con_gamma.data); + Real cov_g[4][4]; + geom.SpacetimeMetric(CellLocation::Cent, iblock, k, j, i, cov_g); + Real beta[3]; + geom.ContravariantShift(CellLocation::Cent, iblock, k, j, i, beta); + Real alpha = geom.Lapse(CellLocation::Cent, iblock, k, j, i); + Real sdetgam = geom.DetGamma(CellLocation::Cent, iblock, k, j, i); + typename CLOSURE::LocalGeometryType g(geom, CellLocation::Cent, iblock, k, j, i); + + // Bounds + Real xi_max; + bounds.GetRadiationCeilings(coords.x1v(k, j, i), coords.x2v(k, j, i), + coords.x3v(k, j, i), xi_max); + + Real rho = v(iblock, prho, k, j, i); + Real ug = v(iblock, peng, k, j, i); + Real Tg = v(iblock, pT, k, j, i); + Real Ye = pYe > 0 ? v(iblock, pYe, k, j, i) : 0.5; + Real bprim[3] = {0}; + if (pb_lo > -1) { + Real bprim[3] = {v(iblock, pb_lo, k, j, i), v(iblock, pb_lo + 1, k, j, i), + v(iblock, pb_lo + 2, k, j, i)}; + } + Real lambda[2] = {Ye, 0.}; + Real con_vp[3] = {v(iblock, pv(0), k, j, i), v(iblock, pv(1), k, j, i), + v(iblock, pv(2), k, j, i)}; + + Real dE[MaxNumRadiationSpecies]; + Vec cov_dF[MaxNumRadiationSpecies]; + + bool success = false; + if (src_solver == SourceSolver::zerod) { + PARTHENON_FAIL("zerod solver temporarily disabled!"); + success = true; + } else if (src_solver == SourceSolver::oned) { + oned_solver_begin: + for (int ispec = 0; ispec < num_species; ispec++) { + + const Real W = phoebus::GetLorentzFactor(con_vp, cov_gamma.data); + Vec con_v{{con_vp[0] / W, con_vp[1] / W, con_vp[2] / W}}; + + Real J0[3] = {v(iblock, idx_J(0), k, j, i), 0, 0}; + PARTHENON_REQUIRE(num_species == 1, "Multiple species not implemented"); + + const Real dtau = alpha * dt / W; // Elapsed time in fluid frame + + // Rootfind over fluid temperature in fluid rest frame + root_find::RootFind root_find(src_rootfind_maxiter); + InteractionTResidual res(eos, d_opacity, d_mean_opacity, rho, ug, Ye, J0, + num_species, species_d, scattering_fraction, dtau); + root_find::RootFindStatus status; + const Real T1 = root_find.secant(res, 0, 1.e3 * v(iblock, pT, k, j, i), + 1.e-8 * v(iblock, pT, k, j, i), + v(iblock, pT, k, j, i), &status); + if (status == root_find::RootFindStatus::failure) { + success = false; + // break; + } + + CLOSURE c(con_v, &g); + + Real Estar = v(iblock, idx_E(ispec), k, j, i) / sdetgam; + Vec cov_Fstar{v(iblock, idx_F(ispec, 0), k, j, i) / sdetgam, + v(iblock, idx_F(ispec, 1), k, j, i) / sdetgam, + v(iblock, idx_F(ispec, 2), k, j, i) / sdetgam}; + + // Treat the Eddington tensor explicitly for now + Real J = v(iblock, idx_J(ispec), k, j, i); + Vec cov_H{{ + J * v(iblock, idx_H(ispec, 0), k, j, i), + J * v(iblock, idx_H(ispec, 1), k, j, i), + J * v(iblock, idx_H(ispec, 2), k, j, i), + }}; + Tens2 con_tilPi; + + if (idx_tilPi.IsValid()) { + SPACELOOP2(ii, jj) { + con_tilPi(ii, jj) = v(iblock, idx_tilPi(ispec, ii, jj), k, j, i); + } + } else { + c.GetConTilPiFromPrim(J, cov_H, &con_tilPi); + } + + Real JBB = d_opacity.EnergyDensityFromTemperature(T1, species_d[ispec]); + Real kappa = d_mean_opacity.RosselandMeanAbsorptionCoefficient( + rho, T1, Ye, species_d[ispec]); + Real tauJ = alpha * dt * (1. - scattering_fraction) * kappa; + Real tauH = alpha * dt * kappa; + + if (status == root_find::RootFindStatus::success) { + c.LinearSourceUpdate(Estar, cov_Fstar, con_tilPi, JBB, tauJ, tauH, + &(dE[ispec]), &(cov_dF[ispec])); + + Estar += dE[ispec]; + SPACELOOP(ii) cov_Fstar(ii) += cov_dF[ispec](ii); + + // Check result for sanity (note that this doesn't check fluid energy + // density) + auto c2p_status = c.Con2Prim(Estar, cov_Fstar, con_tilPi, &J, &cov_H); + if (c2p_status == ClosureStatus::success) { + success = true; + } else { + success = false; + } + } else { + success = false; + } + + if (!success && oned_fixup_strategy == OneDFixupStrategy::ignore_dJ) { + // Retry the solver update but without updating internal energy + Estar = v(iblock, idx_E(ispec), k, j, i) / sdetgam; + SPACELOOP(ii) { + cov_Fstar(ii) = v(iblock, idx_F(ispec, ii), k, j, i) / sdetgam; + } + + JBB = v(iblock, idx_J(ispec), k, j, i); + kappa = d_mean_opacity.RosselandMeanAbsorptionCoefficient( + rho, v(iblock, pT, k, j, i), Ye, species_d[ispec]); + tauJ = alpha * dt * (1. - scattering_fraction) * kappa; + tauH = alpha * dt * kappa; + c.LinearSourceUpdate(Estar, cov_Fstar, con_tilPi, JBB, tauJ, tauH, + &(dE[ispec]), &(cov_dF[ispec])); + + // Check xi + Estar = v(iblock, idx_E(ispec), k, j, i) / sdetgam + dE[ispec]; + SPACELOOP(ii) { + cov_Fstar(ii) = + v(iblock, idx_F(ispec, ii), k, j, i) / sdetgam + cov_dF[ispec](ii); + } + auto c2p_status = c.Con2Prim(Estar, cov_Fstar, con_tilPi, &J, &cov_H); + + const Real xi = + std::sqrt(g.contractCov3Vectors(cov_H, cov_H) - + std::pow(g.contractConCov3Vectors(con_v, cov_H), 2)) / + J; + if (c2p_status == ClosureStatus::success) { + success = true; + } else { + success = false; + break; + } + } else if (!success && oned_fixup_strategy == OneDFixupStrategy::ignore_all) { + dE[ispec] = 0.; + SPACELOOP(ii) { cov_Fstar(ii) = 0.; } + success = true; + } else { + break; // Don't bother with other species if this failed + } + } // ispec + } else if (src_solver == SourceSolver::fourd) { + // TODO(BRR) generalize to multiple species + int ispec = 0; + + // Rootfind via Newton's method over 4-momentum with some fixups inside the + // rootfind. + Real P_mhd_guess[4] = {ug, v(iblock, pv(0), k, j, i), v(iblock, pv(1), k, j, i), + v(iblock, pv(2), k, j, i)}; + Real U_mhd_0[4]; + const Real Pg0 = eos.PressureFromDensityInternalEnergy(rho, ug / rho, lambda); + const Real gam1 = + eos.BulkModulusFromDensityInternalEnergy(rho, ug / rho, lambda) / Pg0; + Real D; + Real bcons[3]; + Real ye_cons; + prim2con::p2c(rho, &(P_mhd_guess[1]), bprim, P_mhd_guess[0], lambda[0], Pg0, + gam1, cov_g, con_gamma.data, beta, alpha, sdetgam, D, + &(U_mhd_0[1]), bcons, U_mhd_0[0], ye_cons); + Real U_rad_0[4] = { + v(iblock, idx_E(ispec), k, j, i), v(iblock, idx_F(ispec, 0), k, j, i), + v(iblock, idx_F(ispec, 1), k, j, i), v(iblock, idx_F(ispec, 2), k, j, i)}; + + // TODO(BRR) instead update con_TilPi each substep? + // TODO(BRR) update v in closure each substep? + Vec con_v{{P_mhd_guess[1], P_mhd_guess[2], P_mhd_guess[3]}}; + const Real W = phoebus::GetLorentzFactor(con_v.data, cov_gamma.data); + SPACELOOP(ii) { con_v(ii) /= W; } + CLOSURE c(con_v, &g); + Tens2 con_tilPi = {0}; + if (idx_tilPi.IsValid()) { + SPACELOOP2(ii, jj) { + con_tilPi(ii, jj) = v(iblock, idx_tilPi(ispec, ii, jj), k, j, i); + } + } else { + Real J = v(iblock, idx_J(ispec), k, j, i); + Vec covH{{v(iblock, idx_F(ispec, 0), k, j, i), + v(iblock, idx_F(ispec, 1), k, j, i), + v(iblock, idx_F(ispec, 2), k, j, i)}}; + c.GetConTilPiFromPrim(J, covH, &con_tilPi); + } + SourceResidual4 srm(eos, d_opacity, d_mean_opacity, rho, Ye, bprim, + species_d[ispec], con_tilPi, cov_g, con_gamma.data, + alpha, beta, sdetgam, scattering_fraction, g, + U_mhd_0, U_rad_0, k, j, i); + + // Memory for evaluating Jacobian via finite differences + Real P_rad_m[4]; + Real P_rad_p[4]; + Real U_mhd_m[4]; + Real U_mhd_p[4]; + Real U_rad_m[4]; + Real U_rad_p[4]; + Real dS_m[4]; + Real dS_p[4]; + + Real U_mhd_guess[4]; + Real U_rad_guess[4]; + Real P_rad_guess[4]; + Real dS_guess[4]; + + // Initialize residuals + Real resid[4]; + srm.CalculateMHDConserved(P_mhd_guess, U_mhd_guess); + srm.CalculateRadConserved(U_mhd_guess, U_rad_guess); + auto status = srm.CalculateRadPrimitive(P_mhd_guess, U_rad_guess, P_rad_guess); + srm.CalculateSource(P_mhd_guess, P_rad_guess, dS_guess); + for (int n = 0; n < 4; n++) { + resid[n] = U_mhd_guess[n] - U_mhd_0[n] + dt * dS_guess[n]; + } + + Real err = 1.e100; + int niter = 0; + bool bad_guess = false; + do { + // Numerically calculate Jacobian + Real jac[4][4] = {0}; + + // Minimum non-zero magnitude from P_mhd_guess + Real P_mhd_mag_min = robust::LARGE(); + for (int m = 0; m < 4; m++) { + if (std::fabs(P_mhd_guess[m]) > 0.) { + P_mhd_mag_min = std::min(P_mhd_mag_min, std::fabs(P_mhd_guess[m])); + } + } + + bool bad_guess_m = false; + bool bad_guess_p = false; + for (int m = 0; m < 4; m++) { + Real P_mhd_m[4] = {P_mhd_guess[0], P_mhd_guess[1], P_mhd_guess[2], + P_mhd_guess[3]}; + Real P_mhd_p[4] = {P_mhd_guess[0], P_mhd_guess[1], P_mhd_guess[2], + P_mhd_guess[3]}; + const Real fd_step = std::max(src_rootfind_eps * P_mhd_mag_min, + src_rootfind_eps * std::fabs(P_mhd_guess[m])); + P_mhd_m[m] -= fd_step; + P_mhd_p[m] += fd_step; + + srm.CalculateMHDConserved(P_mhd_m, U_mhd_m); + srm.CalculateRadConserved(U_mhd_m, U_rad_m); + auto status_m = srm.CalculateRadPrimitive(P_mhd_m, U_rad_m, P_rad_m); + srm.CalculateSource(P_mhd_m, P_rad_m, dS_m); + if (status_m == ClosureStatus::failure) { + bad_guess_m = true; + } + + srm.CalculateMHDConserved(P_mhd_p, U_mhd_p); + srm.CalculateRadConserved(U_mhd_p, U_rad_p); + auto status_p = srm.CalculateRadPrimitive(P_mhd_p, U_rad_p, P_rad_p); + srm.CalculateSource(P_mhd_p, P_rad_p, dS_p); + if (status_p == ClosureStatus::failure) { + bad_guess_p = true; + } + + for (int n = 0; n < 4; n++) { + Real fp = U_mhd_p[n] - U_mhd_0[n] + dt * dS_p[n]; + Real fm = U_mhd_m[n] - U_mhd_0[n] + dt * dS_m[n]; + jac[n][m] = (fp - fm) / (P_mhd_p[m] - P_mhd_m[m]); + } + } + + // Fail or repair if jacobian evaluation was pathological + if (bad_guess_m == true && bad_guess_p == true) { + // If both + and - finite difference support points are bad, this + // interaction fails + bad_guess = true; + break; + } else if (bad_guess_m == true) { + // If only - finite difference support point is bad, do one-sided + // difference with + support point + for (int m = 0; m < 4; m++) { + Real P_mhd_p[4] = {P_mhd_guess[0], P_mhd_guess[1], P_mhd_guess[2], + P_mhd_guess[3]}; + P_mhd_p[m] += std::max(src_rootfind_eps * P_mhd_mag_min, + src_rootfind_eps * std::fabs(P_mhd_p[m])); + srm.CalculateMHDConserved(P_mhd_p, U_mhd_p); + srm.CalculateRadConserved(U_mhd_p, U_rad_p); + auto status_p = srm.CalculateRadPrimitive(P_mhd_p, U_rad_p, P_rad_p); + srm.CalculateSource(P_mhd_p, P_rad_p, dS_p); + PARTHENON_DEBUG_REQUIRE(status_p == ClosureStatus::success, + "This inversion should have already worked!"); + for (int n = 0; n < 4; n++) { + Real fp = U_mhd_p[n] - U_mhd_0[n] + dt * dS_p[n]; + Real fguess = U_mhd_guess[n] - U_mhd_0[n] + dt * dS_guess[n]; + jac[n][m] = (fp - fguess) / (P_mhd_p[m] - P_mhd_guess[m]); + } + } + } else if (bad_guess_p == true) { + // If only + finite difference support point is bad, do one-sided + // difference with - support point + for (int m = 0; m < 4; m++) { + Real P_mhd_m[4] = {P_mhd_guess[0], P_mhd_guess[1], P_mhd_guess[2], + P_mhd_guess[3]}; + P_mhd_m[m] -= std::max(src_rootfind_eps * P_mhd_mag_min, + src_rootfind_eps * std::fabs(P_mhd_m[m])); + srm.CalculateMHDConserved(P_mhd_m, U_mhd_m); + srm.CalculateRadConserved(U_mhd_m, U_rad_m); + auto status_m = srm.CalculateRadPrimitive(P_mhd_m, U_rad_m, P_rad_m); + srm.CalculateSource(P_mhd_m, P_rad_m, dS_m); + PARTHENON_DEBUG_REQUIRE(status_m == ClosureStatus::success, + "This inversion should have already worked!"); + for (int n = 0; n < 4; n++) { + Real fguess = U_mhd_guess[n] - U_mhd_0[n] + dt * dS_guess[n]; + Real fm = U_mhd_m[n] - U_mhd_0[n] + dt * dS_m[n]; + jac[n][m] = (fguess - fm) / (P_mhd_guess[m] - P_mhd_m[m]); + } + } + } + + Real jacinv[4][4]; + LinearAlgebra::matrixInverse4x4(jac, jacinv); + + if (bad_guess == false) { + + // Save energies before update in case we need to rescale step + double ug0 = P_mhd_guess[0]; + double ur0 = P_rad_guess[0]; + + // Update guess + for (int m = 0; m < 4; m++) { + for (int n = 0; n < 4; n++) { + P_mhd_guess[m] -= jacinv[m][n] * resid[n]; + } + } + + srm.CalculateMHDConserved(P_mhd_guess, U_mhd_guess); + srm.CalculateRadConserved(U_mhd_guess, U_rad_guess); + status = srm.CalculateRadPrimitive(P_mhd_guess, U_rad_guess, P_rad_guess); + srm.CalculateSource(P_mhd_guess, P_rad_guess, dS_guess); + if (status == ClosureStatus::failure) { + bad_guess = true; + } + + if (bad_guess) { + // Try reducing the step size so xi < ximax, ug > 0, J > 0 + Vec cov_H{P_rad_guess[1] / P_rad_guess[0], + P_rad_guess[2] / P_rad_guess[0], + P_rad_guess[3] / P_rad_guess[0]}; + Vec con_v{P_mhd_guess[1], P_mhd_guess[2], P_mhd_guess[3]}; + Real J = P_rad_guess[0]; + const Real xi = + std::sqrt(g.contractCov3Vectors(cov_H, cov_H) - + std::pow(g.contractConCov3Vectors(con_v, cov_H), 2)) / + J; + + constexpr Real umin = 100. * robust::SMALL(); + constexpr Real Jmin = 100. * robust::SMALL(); + + Real scaling_factor = 0.; + if (xi > xi_max) { + scaling_factor = std::max(scaling_factor, xi_max / xi); + } + if (P_mhd_guess[0] < umin) { + scaling_factor = std::max(scaling_factor, + (ug0 - umin) / (ug0 - P_mhd_guess[0])); + } + if (P_rad_guess[0] < Jmin) { + scaling_factor = std::max(scaling_factor, + (ur0 - Jmin) / (ur0 - P_rad_guess[0])); + } + if (!(scaling_factor > robust::SMALL() && scaling_factor >= 1.)) { + // Nonsensical scaling factor, maybe negative P_rad_guess[0] + printf("bad scaling factor! breaking [%i %i %i]\n", k, j, i); + bad_guess = true; + break; + } + // Nudge it a bit + scaling_factor *= 0.5; + for (int m = 0; m < 4; m++) { + for (int n = 0; n < 4; n++) { + P_mhd_guess[m] += (1. - scaling_factor) * jacinv[m][n] * resid[n]; + } + } + srm.CalculateMHDConserved(P_mhd_guess, U_mhd_guess); + srm.CalculateRadConserved(U_mhd_guess, U_rad_guess); + status = srm.CalculateRadPrimitive(P_mhd_guess, U_rad_guess, P_rad_guess); + srm.CalculateSource(P_mhd_guess, P_rad_guess, dS_guess); + if (status == ClosureStatus::success) { + bad_guess = false; + } + } + } + + // If guess was invalid, break and mark this zone as a failure + if (bad_guess) { + break; + } + + // Update residuals + for (int n = 0; n < 4; n++) { + resid[n] = U_mhd_guess[n] - U_mhd_0[n] + dt * dS_guess[n]; + if (std::isnan(resid[n])) { + bad_guess = true; + break; + } + } + if (bad_guess == true) { + break; + } + + // Calculate error + err = robust::SMALL(); + Real max_divisor = robust::SMALL(); + for (int n = 0; n < 4; n++) { + max_divisor = std::max(max_divisor, std::fabs(U_mhd_guess[n]) + + std::fabs(U_mhd_0[n]) + + std::fabs(dt * dS_guess[n])); + } + for (int n = 0; n < 4; n++) { + Real suberr = std::fabs(resid[n]) / max_divisor; + if (suberr > err) { + err = suberr; + } + } + + niter++; + if (niter == src_rootfind_maxiter) { + break; + } + } while (err > src_rootfind_tol); + + if (niter == src_rootfind_maxiter || err > src_rootfind_tol || + std::isnan(U_rad_guess[0]) || std::isnan(U_rad_guess[1]) || + std::isnan(U_rad_guess[2]) || std::isnan(U_rad_guess[3]) || bad_guess) { + success = false; + } else { + success = true; + dE[ispec] = (U_rad_guess[0] - v(iblock, idx_E(ispec), k, j, i)) / sdetgam; + SPACELOOP(ii) { + cov_dF[ispec](ii) = + (U_rad_guess[ii + 1] - v(iblock, idx_F(ispec, ii), k, j, i)) / sdetgam; + } + } + + if (success == false) { + // Optionally fall back to oned solver if fourd encounters an issue + if (src_use_oned_backup) { + goto oned_solver_begin; + } + } + } // SourceSolver + + if (success == true) { + for (int ispec = 0; ispec < num_species; ispec++) { + v(iblock, ifail, k, j, i) = FailFlags::success; + + v(iblock, idx_E(ispec), k, j, i) += sdetgam * dE[ispec]; + SPACELOOP(ii) { + v(iblock, idx_F(ispec, ii), k, j, i) += sdetgam * cov_dF[ispec](ii); + } + if (update_fluid) { + if (cye > 0) { + v(iblock, cye, k, j, i) -= sdetgam * 0.0; + } + v(iblock, ceng, k, j, i) -= sdetgam * dE[ispec]; + SPACELOOP(ii) { + v(iblock, cmom_lo + ii, k, j, i) -= sdetgam * cov_dF[ispec](ii); + } + } + } + } else { + v(iblock, ifail, k, j, i) = FailFlags::fail; + } + }); + return TaskStatus::complete; +} +template +TaskStatus MomentFluidSource(T *rc, Real dt, bool update_fluid) { + auto *pm = rc->GetParentPointer().get(); + StateDescriptor *rad = pm->packages.Get("radiation").get(); + auto method = rad->Param("method"); + using settings = + ClosureSettings; + if (method == "moment_m1") { + return MomentFluidSourceImpl>(rc, dt, update_fluid); + } else if (method == "moment_eddington") { + return MomentFluidSourceImpl>(rc, dt, update_fluid); + } else if (method == "mocmc") { + return MomentFluidSourceImpl>(rc, dt, update_fluid); + } else { + PARTHENON_FAIL("Radiation method unknown!"); + } + return TaskStatus::fail; +} +template TaskStatus MomentFluidSource>(MeshBlockData *, Real, + bool); + +} // namespace radiation diff --git a/src/radiation/monte_carlo.cpp b/src/radiation/monte_carlo.cpp index 3821cf57..a7f393fa 100644 --- a/src/radiation/monte_carlo.cpp +++ b/src/radiation/monte_carlo.cpp @@ -1,5 +1,5 @@ -// © 2021. Triad National Security, LLC. All rights reserved. This -// program was produced under U.S. Government contract +// © 2021-2022. Triad National Security, LLC. All rights reserved. +// This program was produced under U.S. Government contract // 89233218CNA000001 for Los Alamos National Laboratory (LANL), which // is operated by Triad National Security, LLC for the U.S. // Department of Energy/National Nuclear Security Administration. All @@ -48,9 +48,12 @@ TaskStatus MonteCarloSourceParticles(MeshBlock *pmb, MeshBlockData *rc, const auto d_opacity = opac->Param("d.opacity"); - bool do_species[3] = {rad->Param("do_nu_electron"), - rad->Param("do_nu_electron_anti"), - rad->Param("do_nu_heavy")}; + auto species = rad->Param>("species"); + auto num_species = rad->Param("num_species"); + RadiationType species_d[MaxNumRadiationSpecies] = {}; + for (int s = 0; s < num_species; s++) { + species_d[s] = species[s]; + } // Meshblock geometry const IndexRange &ib = pmb->cellbounds.GetBoundsI(IndexDomain::interior); @@ -104,73 +107,70 @@ TaskStatus MonteCarloSourceParticles(MeshBlock *pmb, MeshBlockData *rc, v(Gye, k, j, i) = 0.; }); - for (int sidx = 0; sidx < 3; sidx++) { - if (do_species[sidx]) { - auto s = species[sidx]; - pmb->par_for( - "MonteCarlodNdlnu", kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, - KOKKOS_LAMBDA(const int k, const int j, const int i) { - auto rng_gen = rng_pool.get_state(); - Real detG = geom.DetG(CellLocation::Cent, k, j, i); - const Real &dens = v(pdens, k, j, i); - const Real &temp = v(ptemp, k, j, i); - const Real &ye = v(pye, k, j, i); - - Real dN = 0.; - Real dNdlnu_max = 0.; - for (int n = 0; n <= nu_bins; n++) { - Real nu = nusamp(n); - Real ener = h_code * nu; - Real wgt = GetWeight(wgtC, nu); - Real Jnu = d_opacity.EmissivityPerNu(dens, temp, ye, s, nu); - - dN += Jnu / (ener * wgt) * (nu * dlnu); - - // Note that factors of nu in numerator and denominator cancel - Real dNdlnu = Jnu * d3x * detG / (h_code * wgt); - v(idNdlnu + sidx + n * NumRadiationTypes, k, j, i) = dNdlnu; - if (dNdlnu > dNdlnu_max) { - dNdlnu_max = dNdlnu; - } + for (int sidx = 0; sidx < num_species; sidx++) { + auto s = species_d[sidx]; + pmb->par_for( + "MonteCarlodNdlnu", kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + KOKKOS_LAMBDA(const int k, const int j, const int i) { + auto rng_gen = rng_pool.get_state(); + Real detG = geom.DetG(CellLocation::Cent, k, j, i); + const Real &dens = v(pdens, k, j, i); + const Real &temp = v(ptemp, k, j, i); + const Real &ye = v(pye, k, j, i); + + Real dN = 0.; + Real dNdlnu_max = 0.; + for (int n = 0; n <= nu_bins; n++) { + Real nu = nusamp(n); + Real ener = h_code * nu; + Real wgt = GetWeight(wgtC, nu); + Real Jnu = d_opacity.EmissivityPerNu(dens, temp, ye, s, nu); + + dN += Jnu / (ener * wgt) * (nu * dlnu); + + // Note that factors of nu in numerator and denominator cancel + Real dNdlnu = Jnu * d3x * detG / (h_code * wgt); + // TODO(BRR) use FlatIdx + v(idNdlnu + sidx + n * num_species, k, j, i) = dNdlnu; + if (dNdlnu > dNdlnu_max) { + dNdlnu_max = dNdlnu; } + } - for (int n = 0; n <= nu_bins; n++) { - v(idNdlnu + sidx + n * NumRadiationTypes, k, j, i) /= dNdlnu_max; - } + for (int n = 0; n <= nu_bins; n++) { + v(idNdlnu + sidx + n * num_species, k, j, i) /= dNdlnu_max; + } - // Trapezoidal rule - Real nu0 = nusamp[0]; - Real nu1 = nusamp[nu_bins]; - dN -= 0.5 * d_opacity.EmissivityPerNu(dens, temp, ye, s, nu0) / - (h_code * GetWeight(wgtC, nu0)) * dlnu; - dN -= 0.5 * d_opacity.EmissivityPerNu(dens, temp, ye, s, nu1) / - (h_code * GetWeight(wgtC, nu1)) * dlnu; - dN *= d3x * detG * dt; + // Trapezoidal rule + Real nu0 = nusamp[0]; + Real nu1 = nusamp[nu_bins]; + dN -= 0.5 * d_opacity.EmissivityPerNu(dens, temp, ye, s, nu0) / + (h_code * GetWeight(wgtC, nu0)) * dlnu; + dN -= 0.5 * d_opacity.EmissivityPerNu(dens, temp, ye, s, nu1) / + (h_code * GetWeight(wgtC, nu1)) * dlnu; + dN *= d3x * detG * dt; - v(idNdlnu_max + sidx, k, j, i) = dNdlnu_max; + v(idNdlnu_max + sidx, k, j, i) = dNdlnu_max; - int Ns = static_cast(dN); - if (dN - Ns > rng_gen.drand()) { - Ns++; - } + int Ns = static_cast(dN); + if (dN - Ns > rng_gen.drand()) { + Ns++; + } - // TODO(BRR) Use a ParArrayND instead of these weird static_casts - v(idN + sidx, k, j, i) = dN; - v(iNs + sidx, k, j, i) = static_cast(Ns); - rng_pool.free_state(rng_gen); - }); - } + // TODO(BRR) Use a ParArrayND instead of these weird static_casts + v(idN + sidx, k, j, i) = dN; + v(iNs + sidx, k, j, i) = static_cast(Ns); + rng_pool.free_state(rng_gen); + }); } // Reduce dN over zones for calibrating weights (requires w ~ wgtC) Real dNtot = 0; parthenon::par_reduce( parthenon::loop_pattern_mdrange_tag, "MonteCarloReduceParticleCreation", - DevExecSpace(), 0, 2, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + DevExecSpace(), 0, num_species - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, KOKKOS_LAMBDA(const int sidx, const int k, const int j, const int i, Real &dNtot) { - if (do_species[sidx]) { - dNtot += v(idN + sidx, k, j, i); - } + dNtot += v(idN + sidx, k, j, i); }, Kokkos::Sum(dNtot)); @@ -182,30 +182,26 @@ TaskStatus MonteCarloSourceParticles(MeshBlock *pmb, MeshBlockData *rc, "tune_emission*dNtot is very large, you wouldn't want to overflow an integer"); pmb->par_for( - "MonteCarlodiNsEval", 0, 2, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + "MonteCarlodiNsEval", 0, num_species - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, KOKKOS_LAMBDA(const int sidx, const int k, const int j, const int i) { - if (do_species[sidx]) { - auto rng_gen = rng_pool.get_state(); + auto rng_gen = rng_pool.get_state(); - Real dN_upd = wgtCfac * v(idN + sidx, k, j, i); - int Ns = static_cast(dN_upd); - if (dN_upd - Ns > rng_gen.drand()) { - Ns++; - } - - // TODO(BRR) Use a ParArrayND instead of these weird static_casts - v(iNs + sidx, k, j, i) = static_cast(Ns); - rng_pool.free_state(rng_gen); + Real dN_upd = wgtCfac * v(idN + sidx, k, j, i); + int Ns = static_cast(dN_upd); + if (dN_upd - Ns > rng_gen.drand()) { + Ns++; } + + // TODO(BRR) Use a ParArrayND instead of these weird static_casts + v(iNs + sidx, k, j, i) = static_cast(Ns); + rng_pool.free_state(rng_gen); }); int Nstot = 0; parthenon::par_reduce( parthenon::loop_pattern_mdrange_tag, "MonteCarloReduceParticleCreationNs", - DevExecSpace(), 0, 2, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + DevExecSpace(), 0, num_species - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, KOKKOS_LAMBDA(const int sidx, const int k, const int j, const int i, int &Nstot) { - if (do_species[sidx]) { - Nstot += static_cast(v(iNs + sidx, k, j, i)); - } + Nstot += static_cast(v(iNs + sidx, k, j, i)); }, Kokkos::Sum(Nstot)); @@ -233,7 +229,7 @@ TaskStatus MonteCarloSourceParticles(MeshBlock *pmb, MeshBlockData *rc, auto dN = rc->Get("Ns").data; auto dN_h = dN.GetHostMirrorAndCopy(); int index = 0; - for (int sidx = 0; sidx < 3; sidx++) { + for (int sidx = 0; sidx < num_species; sidx++) { for (int k = 0; k < nx_k; k++) { for (int j = 0; j < nx_j; j++) { for (int i = 0; i < nx_i; i++) { @@ -249,92 +245,88 @@ TaskStatus MonteCarloSourceParticles(MeshBlock *pmb, MeshBlockData *rc, // auto dNdlnu_max = rc->Get("dNdlnu_max").data; // Loop over zones and generate appropriate number of particles in each zone - for (int sidx = 0; sidx < 3; sidx++) { - if (do_species[sidx]) { - auto s = species[sidx]; - - pmb->par_for( - "MonteCarloSourceParticles", kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, - KOKKOS_LAMBDA(const int k, const int j, const int i) { - // Create tetrad transformation once per zone - Real Gcov[4][4]; - geom.SpacetimeMetric(CellLocation::Cent, k, j, i, Gcov); - Real Ucon[4]; - Real vel[3] = {v(pvlo, k, j, i), v(pvlo + 1, k, j, i), v(pvlo + 2, k, j, i)}; - GetFourVelocity(vel, geom, CellLocation::Cent, k, j, i, Ucon); - Geometry::Tetrads Tetrads(Ucon, Gcov); - Real detG = geom.DetG(CellLocation::Cent, k, j, i); - int dNs = v(iNs + sidx, k, j, i); - - // Loop over particles to create in this zone - for (int n = 0; n < static_cast(dNs); n++) { - const int m = - new_indices(starting_index(sidx, k - kb.s, j - jb.s, i - ib.s) + n); - auto rng_gen = rng_pool.get_state(); - - // Set particle species - swarm_species(m) = static_cast(s); - - // Create particles at initial time - t(m) = t0; - - // Create particles at zone centers - x(m) = minx_i + (i - ib.s + 0.5) * dx_i; - y(m) = minx_j + (j - jb.s + 0.5) * dx_j; - z(m) = minx_k + (k - kb.s + 0.5) * dx_k; - - // Sample energy and set weight - Real nu; - int counter = 0; - do { - nu = exp(rng_gen.drand() * (lnu_max - lnu_min) + lnu_min); - counter++; - PARTHENON_REQUIRE(counter < 100000, - "Inefficient or impossible frequency sampling!"); - } while (rng_gen.drand() > - LogLinearInterp(nu, sidx, k, j, i, dNdlnu, lnu_min, dlnu)); - - weight(m) = GetWeight(wgtC / wgtCfac, nu); - - // Encode frequency and randomly sample direction - Real E = nu * h_code; - Real theta = acos(2. * rng_gen.drand() - 1.); - Real phi = 2. * M_PI * rng_gen.drand(); - Real K_tetrad[4] = {-E, E * cos(theta), E * cos(phi) * sin(theta), - E * sin(phi) * sin(theta)}; - Real K_coord[4]; - Tetrads.TetradToCoordCov(K_tetrad, K_coord); - - k0(m) = K_coord[0]; - k1(m) = K_coord[1]; - k2(m) = K_coord[2]; - k3(m) = K_coord[3]; - - for (int mu = Gcov_lo; mu <= Gcov_lo + 3; mu++) { - // detG is in both numerator and denominator - v(mu, k, j, i) += 1. / (d3x * dt) * weight(m) * K_coord[mu - Gcov_lo]; - } - // TODO(BRR) lepton sign - v(Gye, k, j, i) -= 1. / (d3x * dt) * Ucon[0] * weight(m) * mp_code; - - rng_pool.free_state(rng_gen); - } // for n - }); - } // if do_species[sidx] - } // for sidx + for (int sidx = 0; sidx < num_species; sidx++) { + auto s = species_d[sidx]; - if (remove_emitted_particles) { pmb->par_for( - "MonteCarloRemoveEmittedParticles", 0, 2, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, - KOKKOS_LAMBDA(const int sidx, const int k, const int j, const int i) { - if (do_species[sidx]) { - int dNs = v(iNs + sidx, k, j, i); - // Loop over particles to create in this zone - for (int n = 0; n < static_cast(dNs); n++) { - const int m = - new_indices(starting_index(sidx, k - kb.s, j - jb.s, i - ib.s) + n); - swarm_d.MarkParticleForRemoval(m); + "MonteCarloSourceParticles", kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + KOKKOS_LAMBDA(const int k, const int j, const int i) { + // Create tetrad transformation once per zone + Real Gcov[4][4]; + geom.SpacetimeMetric(CellLocation::Cent, k, j, i, Gcov); + Real Ucon[4]; + Real vel[3] = {v(pvlo, k, j, i), v(pvlo + 1, k, j, i), v(pvlo + 2, k, j, i)}; + GetFourVelocity(vel, geom, CellLocation::Cent, k, j, i, Ucon); + Geometry::Tetrads Tetrads(Ucon, Gcov); + Real detG = geom.DetG(CellLocation::Cent, k, j, i); + int dNs = v(iNs + sidx, k, j, i); + + // Loop over particles to create in this zone + for (int n = 0; n < static_cast(dNs); n++) { + const int m = + new_indices(starting_index(sidx, k - kb.s, j - jb.s, i - ib.s) + n); + auto rng_gen = rng_pool.get_state(); + + // Set particle species + swarm_species(m) = static_cast(s); + + // Create particles at initial time + t(m) = t0; + + // Create particles at zone centers + x(m) = minx_i + (i - ib.s + 0.5) * dx_i; + y(m) = minx_j + (j - jb.s + 0.5) * dx_j; + z(m) = minx_k + (k - kb.s + 0.5) * dx_k; + + // Sample energy and set weight + Real nu; + int counter = 0; + do { + nu = exp(rng_gen.drand() * (lnu_max - lnu_min) + lnu_min); + counter++; + PARTHENON_REQUIRE(counter < 100000, + "Inefficient or impossible frequency sampling!"); + } while (rng_gen.drand() > + LogLinearInterp(nu, sidx, k, j, i, dNdlnu, lnu_min, dlnu)); + + weight(m) = GetWeight(wgtC / wgtCfac, nu); + + // Encode frequency and randomly sample direction + Real E = nu * h_code; + Real theta = acos(2. * rng_gen.drand() - 1.); + Real phi = 2. * M_PI * rng_gen.drand(); + Real K_tetrad[4] = {-E, E * cos(theta), E * cos(phi) * sin(theta), + E * sin(phi) * sin(theta)}; + Real K_coord[4]; + Tetrads.TetradToCoordCov(K_tetrad, K_coord); + + k0(m) = K_coord[0]; + k1(m) = K_coord[1]; + k2(m) = K_coord[2]; + k3(m) = K_coord[3]; + + for (int mu = Gcov_lo; mu <= Gcov_lo + 3; mu++) { + // detG is in both numerator and denominator + v(mu, k, j, i) -= 1. / (d3x * dt) * weight(m) * K_coord[mu - Gcov_lo]; } + // TODO(BRR) lepton sign + v(Gye, k, j, i) -= 1. / (d3x * dt) * Ucon[0] * weight(m) * mp_code; + + rng_pool.free_state(rng_gen); + } // for n + }); + } // for sidx + + if (remove_emitted_particles) { + pmb->par_for( + "MonteCarloRemoveEmittedParticles", 0, num_species - 1, kb.s, kb.e, jb.s, jb.e, + ib.s, ib.e, KOKKOS_LAMBDA(const int sidx, const int k, const int j, const int i) { + int dNs = v(iNs + sidx, k, j, i); + // Loop over particles to create in this zone + for (int n = 0; n < static_cast(dNs); n++) { + const int m = + new_indices(starting_index(sidx, k - kb.s, j - jb.s, i - ib.s) + n); + swarm_d.MarkParticleForRemoval(m); } }); swarm->RemoveMarkedParticles(); @@ -413,7 +405,7 @@ TaskStatus MonteCarloTransport(MeshBlock *pmb, MeshBlockData *rc, // TODO(BRR) Get K^0 via metric Real Kcon0 = -k0(n); - Real dlam = dt / Kcon0; + // Real dlam = dt / Kcon0; int k, j, i; swarm_d.Xtoijk(x(n), y(n), z(n), i, j, k); @@ -432,13 +424,13 @@ TaskStatus MonteCarloTransport(MeshBlock *pmb, MeshBlockData *rc, Real xabs = -log(rng_gen.drand()); if (xabs <= dtau_abs) { // Deposit energy-momentum and lepton number in fluid - Kokkos::atomic_add(&(v(iGcov_lo, k, j, i)), -1. / d4x * weight(n) * k0(n)); + Kokkos::atomic_add(&(v(iGcov_lo, k, j, i)), 1. / d4x * weight(n) * k0(n)); Kokkos::atomic_add(&(v(iGcov_lo + 1, k, j, i)), - -1. / d4x * weight(n) * k1(n)); + 1. / d4x * weight(n) * k1(n)); Kokkos::atomic_add(&(v(iGcov_lo + 2, k, j, i)), - -1. / d4x * weight(n) * k2(n)); + 1. / d4x * weight(n) * k2(n)); Kokkos::atomic_add(&(v(iGcov_lo + 3, k, j, i)), - -1. / d4x * weight(n) * k3(n)); + 1. / d4x * weight(n) * k3(n)); // TODO(BRR) Add Ucon[0] in the below Kokkos::atomic_add(&(v(iGye, k, j, i)), 1. / d4x * weight(n) * mp_code); @@ -512,8 +504,9 @@ TaskStatus MonteCarloUpdateTuning(Mesh *pmesh, std::vector *resolution, // TODO(BRR): Tune based on ParticleResolution::total } else if (tuning == "dynamic_difference") { - // TODO(BRR) This should be Rout_rad (add it) or max cartesian size - const Real L = 1.; + // TODO(BRR) This should be Rout_rad (add it) or max cartesian size, and also actually + // used. + // const Real L = 1.; printf("t_tune_emission: %e t0 + dt: %e\n", t_tune_emission, t0 + dt); const auto num_emitted = (*resolution)[static_cast(ParticleResolution::emitted)]; diff --git a/src/radiation/radiation.cpp b/src/radiation/radiation.cpp index c246a988..ff880339 100644 --- a/src/radiation/radiation.cpp +++ b/src/radiation/radiation.cpp @@ -1,5 +1,5 @@ -// © 2021. Triad National Security, LLC. All rights reserved. This -// program was produced under U.S. Government contract +// © 2021-2022. Triad National Security, LLC. All rights reserved +// This program was produced under U.S. Government contract // 89233218CNA000001 for Los Alamos National Laboratory (LANL), which // is operated by Triad National Security, LLC for the U.S. // Department of Energy/National Nuclear Security Administration. All @@ -12,9 +12,14 @@ // publicly, and to permit others to do so. #include "radiation.hpp" +#include "fixup/fixup.hpp" #include "geometry/geometry.hpp" #include "phoebus_utils/programming_utils.hpp" #include "phoebus_utils/variables.hpp" +#include "radiation/local_three_geometry.hpp" +#include "reconstruction.hpp" + +#include "closure.hpp" #include @@ -97,8 +102,6 @@ std::shared_ptr Initialize(ParameterInput *pin) { params.Add("dlnu", dlnu); } - int num_species = pin->GetOrAddInteger("radiation", "num_species", 1); - params.Add("num_species", num_species); std::vector species; if (do_nu_electron) { species.push_back(RadiationType::NU_ELECTRON); @@ -109,9 +112,9 @@ std::shared_ptr Initialize(ParameterInput *pin) { if (do_nu_heavy) { species.push_back(RadiationType::NU_HEAVY); } + const int num_species = species.size(); + params.Add("num_species", num_species); params.Add("species", species); - PARTHENON_REQUIRE(num_species == species.size(), - "Number of species does not match requested species!"); bool absorption = pin->GetOrAddBoolean("radiation", "absorption", true); params.Add("absorption", absorption); @@ -129,7 +132,7 @@ std::shared_ptr Initialize(ParameterInput *pin) { Metadata fourv_swarmvalue_metadata({Metadata::Real}, std::vector{4}); physics->AddSwarmValue("ncov", swarm_name, fourv_swarmvalue_metadata); Metadata Inu_swarmvalue_metadata({Metadata::Real}, - std::vector{NumRadiationTypes, nu_bins}); + std::vector{num_species, nu_bins}); physics->AddSwarmValue("Inuinv", swarm_name, Inu_swarmvalue_metadata); // Boundary temperatures for outflow sample boundary conditions @@ -185,7 +188,7 @@ std::shared_ptr Initialize(ParameterInput *pin) { } params.Add("mocmc_recon", mocmc_recon); - std::vector Inu_size{NumRadiationTypes, nu_bins}; + std::vector Inu_size{num_species, nu_bins}; Metadata mInu = Metadata({Metadata::Cell, Metadata::OneCopy}, Inu_size); physics->AddField(mocmc_internal::Inu0, mInu); physics->AddField(mocmc_internal::Inu1, mInu); @@ -210,13 +213,13 @@ std::shared_ptr Initialize(ParameterInput *pin) { Metadata int_swarmvalue_metadata({Metadata::Integer}); physics->AddSwarmValue("species", swarm_name, int_swarmvalue_metadata); - Metadata mspecies_scalar = Metadata({Metadata::Cell, Metadata::OneCopy}, - std::vector(1, NumRadiationTypes)); + Metadata mspecies_scalar = + Metadata({Metadata::Cell, Metadata::OneCopy}, std::vector{num_species}); physics->AddField("dNdlnu_max", mspecies_scalar); physics->AddField("dN", mspecies_scalar); physics->AddField("Ns", mspecies_scalar); - std::vector dNdlnu_size{NumRadiationTypes, nu_bins + 1}; + std::vector dNdlnu_size{num_species, params.Get("nu_bins") + 1}; Metadata mdNdlnu = Metadata({Metadata::Cell, Metadata::OneCopy}, dNdlnu_size); physics->AddField("dNdlnu", mdNdlnu); @@ -304,27 +307,117 @@ std::shared_ptr Initialize(ParameterInput *pin) { namespace c = radmoment_cons; namespace i = radmoment_internal; - int ndim = 3; - // if (pin->GetInteger("parthenon/mesh", "nx3") > 1) ndim = 3; - // else if (pin->GetInteger("parthenon/mesh", "nx2") > 1) ndim = 2; + std::string closure_strategy_str = + pin->GetOrAddString("radiation", "closure_c2p_strategy", "robust"); + ClosureCon2PrimStrategy closure_strategy; + if (closure_strategy_str == "robust") { + closure_strategy = ClosureCon2PrimStrategy::robust; + } else if (closure_strategy_str == "frail") { + closure_strategy = ClosureCon2PrimStrategy::frail; + } else { + PARTHENON_THROW("Invalid closure_c2p_strategy option. Choose from [robust,frail]"); + } + + ClosureRuntimeSettings closure_runtime_params{closure_strategy}; + params.Add("closure_runtime_params", closure_runtime_params); + + std::string recon = pin->GetOrAddString("radiation", "recon", "linear"); + PhoebusReconstruction::ReconType rt = PhoebusReconstruction::ReconType::linear; + if (recon == "weno5" || recon == "weno5z") { + PARTHENON_REQUIRE_THROWS(parthenon::Globals::nghost >= 4, + "weno5 requires 4+ ghost cells"); + rt = PhoebusReconstruction::ReconType::weno5z; + } else if (recon == "mp5") { + PARTHENON_REQUIRE_THROWS(parthenon::Globals::nghost >= 4, + "mp5 requires 4+ ghost cells"); + if (cfl > 0.4) { + PARTHENON_WARN("mp5 often requires smaller cfl numbers for stability"); + } + rt = PhoebusReconstruction::ReconType::mp5; + } else if (recon == "linear") { + rt = PhoebusReconstruction::ReconType::linear; + } else if (recon == "constant") { + rt = PhoebusReconstruction::ReconType::constant; + } else { + PARTHENON_THROW("Invalid Reconstruction option. Choose from " + "[constant,linear,mp5,weno5,weno5z]"); + } + params.Add("Recon", rt); + + const std::string recon_fixup_strategy_str = + pin->GetOrAddString("radiation", "recon_fixup_strategy", "bounds"); + ReconFixupStrategy recon_fixup_strategy; + if (recon_fixup_strategy_str == "none") { + recon_fixup_strategy = ReconFixupStrategy::none; + } else if (recon_fixup_strategy_str == "bounds") { + recon_fixup_strategy = ReconFixupStrategy::bounds; + } else { + PARTHENON_FAIL("\"radiation/recon_fixup_strategy\" option unrecognized!"); + } + params.Add("recon_fixup_strategy", recon_fixup_strategy); + + const std::string src_solver_name = + pin->GetOrAddString("radiation", "src_solver", "oned"); + SourceSolver src_solver; + if (src_solver_name == "zerod") { + src_solver = SourceSolver::zerod; + } else if (src_solver_name == "oned") { + src_solver = SourceSolver::oned; + } else if (src_solver_name == "fourd") { + src_solver = SourceSolver::fourd; + } else { + PARTHENON_FAIL("\"radiation/src_solver\" option unrecognized!"); + } + params.Add("src_solver", src_solver); + + const bool src_use_oned_backup = + pin->GetOrAddBoolean("radiation", "src_use_oned_backup", false); + params.Add("src_use_oned_backup", src_use_oned_backup); + + Real src_rootfind_eps = pin->GetOrAddReal("radiation", "src_rootfind_eps", 1.e-8); + params.Add("src_rootfind_eps", src_rootfind_eps); + + Real src_rootfind_tol = pin->GetOrAddReal("radiation", "src_rootfind_tol", 1.e-12); + params.Add("src_rootfind_tol", src_rootfind_tol); + + int src_rootfind_maxiter = + pin->GetOrAddInteger("radiation", "src_rootfind_maxiter", 100); + params.Add("src_rootfind_maxiter", src_rootfind_maxiter); + + std::string oned_fixup_strategy_str = + pin->GetOrAddString("radiation", "oned_fixup_strategy", "none"); + OneDFixupStrategy oned_fixup_strategy; + if (oned_fixup_strategy_str == "none") { + oned_fixup_strategy = OneDFixupStrategy::none; + } else if (oned_fixup_strategy_str == "ignore_dJ") { + oned_fixup_strategy = OneDFixupStrategy::ignore_dJ; + } else if (oned_fixup_strategy_str == "ignore_all") { + oned_fixup_strategy = OneDFixupStrategy::ignore_all; + } else { + PARTHENON_FAIL("radiation/oned_fixup_strategy has an invalid entry!"); + } + params.Add("oned_fixup_strategy", oned_fixup_strategy); + + // Required to be 3D in dJ calculation in radiation::ReconstructEdgeStates + const int ndim = 3; Metadata mspecies_three_vector = Metadata({Metadata::Cell, Metadata::OneCopy, Metadata::Derived, Metadata::Intensive, Metadata::FillGhost, Metadata::Vector}, - std::vector{NumRadiationTypes, 3}); + std::vector{num_species, 3}); Metadata mspecies_scalar = Metadata({Metadata::Cell, Metadata::OneCopy, Metadata::Derived, Metadata::Intensive, Metadata::FillGhost}, - std::vector{NumRadiationTypes}); + std::vector{num_species}); Metadata mspecies_three_vector_cons = Metadata( {Metadata::Cell, Metadata::Independent, Metadata::Conserved, Metadata::Intensive, Metadata::WithFluxes, Metadata::FillGhost, Metadata::Vector}, - std::vector{NumRadiationTypes, 3}); + std::vector{num_species, 3}); Metadata mspecies_scalar_cons = Metadata({Metadata::Cell, Metadata::Independent, Metadata::Conserved, Metadata::Intensive, Metadata::WithFluxes, Metadata::FillGhost}, - std::vector{NumRadiationTypes}); + std::vector{num_species}); physics->AddField(c::E, mspecies_scalar_cons); physics->AddField(c::F, mspecies_three_vector_cons); @@ -344,7 +437,7 @@ std::shared_ptr Initialize(ParameterInput *pin) { nrecon += 9; // Reconstruct conTilPi // TODO(BRR) Use 6 elements by symmetry } Metadata mrecon = Metadata({Metadata::Cell, Metadata::Derived, Metadata::OneCopy}, - std::vector{NumRadiationTypes, nrecon, ndim}); + std::vector{num_species, nrecon, ndim}); Metadata mrecon_v = Metadata({Metadata::Cell, Metadata::Derived, Metadata::OneCopy}, std::vector{3, ndim}); physics->AddField(i::ql, mrecon); @@ -354,39 +447,63 @@ std::shared_ptr Initialize(ParameterInput *pin) { // Add variable for calculating gradients of rest frame energy density Metadata mdJ = Metadata({Metadata::Cell, Metadata::Derived, Metadata::OneCopy}, - std::vector{NumRadiationTypes, ndim, ndim}); + std::vector{num_species, ndim, ndim}); physics->AddField(i::dJ, mdJ); // Add variables for source functions Metadata mSourceVar = Metadata({Metadata::Cell, Metadata::Derived, Metadata::OneCopy}, - std::vector{NumRadiationTypes}); + std::vector{num_species}); physics->AddField(i::kappaJ, mSourceVar); physics->AddField(i::kappaH, mSourceVar); physics->AddField(i::JBB, mSourceVar); + // this fail flag should really be an enum or something + // but parthenon doesn't yet support that kind of thing + Metadata m_scalar = Metadata({Metadata::Cell, Metadata::OneCopy, Metadata::Derived, + Metadata::Intensive, Metadata::FillGhost}); + physics->AddField(i::c2pfail, m_scalar); + physics->AddField(i::srcfail, m_scalar); + // Make Eddington tensor an independent quantity for MOCMC to supply if (method == "mocmc") { Metadata mspecies_three_tensor = Metadata( {Metadata::Cell, Metadata::Derived, Metadata::OneCopy, Metadata::FillGhost}, - std::vector{NumRadiationTypes, 3, 3}); + std::vector{num_species, 3, 3}); physics->AddField(i::tilPi, mspecies_three_tensor); physics->AddField(mocmc_internal::dnsamp, mscalar); } - physics->FillDerivedBlock = MomentCon2Prim>; +#if SET_FLUX_SRC_DIAGS + // DIAGNOSTIC STUFF FOR DEBUGGING + std::vector spec_four_vec{num_species, 4}; + Metadata mdiv = Metadata({Metadata::Cell, Metadata::Intensive, Metadata::Vector, + Metadata::Derived, Metadata::OneCopy}, + std::vector{num_species, 4}); + physics->AddField(diagnostic_variables::r_divf, mdiv); + Metadata mdiag = Metadata({Metadata::Cell, Metadata::Intensive, Metadata::Vector, + Metadata::Derived, Metadata::OneCopy}, + std::vector{num_species, 4}); + physics->AddField(diagnostic_variables::r_src_terms, mdiag); + printf("name: %s\n", diagnostic_variables::r_src_terms); + printf("Added fields!\n"); +#endif + + // Use PostFillDerivedBlock to guarantee that fluid, if active, was already inverted + // (we need updated fluid primitive velocities to calculate radiation primitives) + physics->PostFillDerivedBlock = MomentCon2Prim>; } params.Add("moments_active", moments_active); physics->EstimateTimestepBlock = EstimateTimestepBlock; - printf("Done initializing\n"); - return physics; } TaskStatus ApplyRadiationFourForce(MeshBlockData *rc, const double dt) { + PARTHENON_REQUIRE(USE_VALENCIA, "Covariant GRMHD formulation not supported!"); + namespace c = fluid_cons; namespace iv = internal_variables; auto *pmb = rc->GetParentPointer().get(); @@ -409,7 +526,7 @@ TaskStatus ApplyRadiationFourForce(MeshBlockData *rc, const double dt) { parthenon::par_for( DEFAULT_LOOP_PATTERN, "ApplyRadiationFourForce", DevExecSpace(), kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, KOKKOS_LAMBDA(const int k, const int j, const int i) { - v(ceng, k, j, i) += v(Gcov_lo, k, j, i) * dt; + v(ceng, k, j, i) -= v(Gcov_lo, k, j, i) * dt; v(cmom_lo, k, j, i) += v(Gcov_lo + 1, k, j, i) * dt; v(cmom_lo + 1, k, j, i) += v(Gcov_lo + 2, k, j, i) * dt; v(cmom_lo + 2, k, j, i) += v(Gcov_lo + 3, k, j, i) * dt; @@ -420,6 +537,9 @@ TaskStatus ApplyRadiationFourForce(MeshBlockData *rc, const double dt) { } Real EstimateTimestepBlock(MeshBlockData *rc) { + namespace ir = radmoment_internal; + namespace p = fluid_prim; + // Note that this is still used for the cooling function even though that option // contains no transport. This is useful for consistency between methods. auto pmb = rc->GetBlockPointer(); @@ -427,19 +547,53 @@ Real EstimateTimestepBlock(MeshBlockData *rc) { IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::interior); IndexRange kb = pmb->cellbounds.GetBoundsK(IndexDomain::interior); + StateDescriptor *rad = pmb->packages.Get("radiation").get(); + auto &coords = pmb->coords; const int ndim = pmb->pmy_mesh->ndim; - // TODO(BRR) Can't just use dx^i/dx^0 = 1 for speed of light - // TODO(BRR) add a cfl-like fudge factor to radiation + auto geom = Geometry::GetCoordinateSystem(rc); + + PackIndexMap imap; + std::vector vars{ir::kappaH, p::velocity}; + auto v = rc->PackVariables(vars, imap); + auto idx_v = imap.GetFlatIdx(p::velocity); + auto idx_kappaH = imap.GetFlatIdx(ir::kappaH, false); + + auto num_species = rad->Param("num_species"); + auto &pars = pmb->packages.Get("radiation")->AllParams(); Real min_dt; pmb->par_reduce( "Radiation::EstimateTimestep::1", kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, KOKKOS_LAMBDA(const int k, const int j, const int i, Real &lmin_dt) { - Real csig = 1.0; - for (int d = 0; d < ndim; d++) { - lmin_dt = std::min(lmin_dt, 1.0 / (csig / coords.Dx(X1DIR + d, k, j, i))); + Vec con_beta; + geom.ContravariantShift(CellLocation::Cent, k, j, i, con_beta.data); + Tens2 cov_gamma; + geom.Metric(CellLocation::Cent, k, j, i, cov_gamma.data); + Tens2 con_gamma; + geom.MetricInverse(CellLocation::Cent, k, j, i, con_gamma.data); + const Real alpha = geom.Lapse(CellLocation::Cent, k, j, i); + + for (int ispec = 0; ispec < num_species; ispec++) { + + const Real kappaH = idx_kappaH.IsValid() ? v(idx_kappaH(ispec), k, j, i) : 0.; + + for (int d = 0; d < ndim; d++) { + // Signal speeds (assume (i.e. somewhat overestimate, esp. for large opt. + // depth) cs_rad = 1) + const Real sigp = alpha * std::sqrt(con_gamma(d, d)) - con_beta(d); + const Real sigm = -alpha * std::sqrt(con_gamma(d, d)) - con_beta(d); + const Real asym_sigl = alpha * v(idx_v(d), k, j, i) - con_beta(d); + const Real rad_speed = std::max(std::fabs(sigm), std::fabs(sigp)); + const Real asym_speed = std::fabs(asym_sigl); + + const Real dx = coords.Dx(X1DIR + d, k, j, i) * sqrt(cov_gamma(d, d)); + const Real a = tanh(ratio(1.0, std::pow(std::abs(kappaH * dx), 1))); + const Real csig = a * rad_speed + (1. - a) * asym_speed; + + lmin_dt = std::min(lmin_dt, 1.0 / (csig / coords.Dx(X1DIR + d, k, j, i))); + } } }, Kokkos::Min(min_dt)); diff --git a/src/radiation/radiation.hpp b/src/radiation/radiation.hpp index 02b7bb65..3e57d1d6 100644 --- a/src/radiation/radiation.hpp +++ b/src/radiation/radiation.hpp @@ -1,5 +1,5 @@ -// © 2021. Triad National Security, LLC. All rights reserved. This -// program was produced under U.S. Government contract +// © 2021-2022. Triad National Security, LLC. All rights reserved. +// This program was produced under U.S. Government contract // 89233218CNA000001 for Los Alamos National Laboratory (LANL), which // is operated by Triad National Security, LLC for the U.S. // Department of Energy/National Nuclear Security Administration. All @@ -43,12 +43,25 @@ enum class MOCMCRecon { kdgrid }; enum class MOCMCBoundaries { outflow, fixed_temp, periodic }; +enum class SourceSolver { zerod, oned, fourd }; + +enum class OneDFixupStrategy { + none, // Do not attempt to repair failed 1D rootfind + ignore_dJ, // If 1D rootfind fails, ignore update to radiation temperature + ignore_all // If 1D rootfind fails, do not apply radiation source +}; + +enum class ReconFixupStrategy { + none, // Do not apply fixups to reconstructed quantities + bounds // Apply floors and ceilings to reconstructed quantities +}; + using pc = parthenon::constants::PhysicalConstants; using singularity::RadiationType; -constexpr RadiationType species[3] = { +constexpr int MaxNumRadiationSpecies = 3; +constexpr RadiationType species[MaxNumRadiationSpecies] = { RadiationType::NU_ELECTRON, RadiationType::NU_ELECTRON_ANTI, RadiationType::NU_HEAVY}; -constexpr int NumRadiationTypes = 3; KOKKOS_INLINE_FUNCTION Real LogLinearInterp(Real x, int sidx, int k, int j, int i, ParArrayND table, @@ -60,6 +73,12 @@ Real LogLinearInterp(Real x, int sidx, int k, int j, int i, ParArrayND tab return (1. - dn) * table(n, sidx, k, j, i) + dn * table(n + 1, sidx, k, j, i); } +enum class SourceStatus { success, failure }; +struct FailFlags { + static constexpr Real success = 1.0; + static constexpr Real fail = 0.0; +}; + // Choice of RNG typedef Kokkos::Random_XorShift64_Pool<> RNGPool; diff --git a/tst/regression/bondi.py b/tst/regression/bondi.py index 5ebdd6e4..682eb3fe 100755 --- a/tst/regression/bondi.py +++ b/tst/regression/bondi.py @@ -21,6 +21,7 @@ parser = argparse.ArgumentParser(description='Run the Bondi accretion problem as a test') parser.add_argument('--upgold', dest='upgold', action='store_true') parser.add_argument('--use_gpu', dest='use_gpu', action='store_true') +parser.add_argument('--use_mpiexec', dest='use_mpiexec', action='store_true') parser.add_argument('--input', type=str, default=os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../inputs/bondi.pin')) parser.add_argument('--executable', type=str, default=None) parser.add_argument('--build_type', type=str, default='Release', choices=['Debug', 'Release']) @@ -36,6 +37,7 @@ executable=args.executable, geometry='FMKS', use_gpu=args.use_gpu, + use_mpiexec=args.use_mpiexec, build_type=args.build_type, upgold=args.upgold, compression_factor=1) diff --git a/tst/regression/friedmann.py b/tst/regression/friedmann.py index 84653e28..6e28a467 100755 --- a/tst/regression/friedmann.py +++ b/tst/regression/friedmann.py @@ -21,6 +21,7 @@ parser = argparse.ArgumentParser(description='Run FLRW test') parser.add_argument('--upgold', dest='upgold', action='store_true') parser.add_argument('--use_gpu', dest='use_gpu', action='store_true') +parser.add_argument('--use_mpiexec', dest='use_mpiexec', action='store_true') parser.add_argument('--input', type=str, default=os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', 'inputs/friedmann.pin')) parser.add_argument('--executable', type=str, default=None) parser.add_argument('--build_type', type=str, default='Release', choices=['Debug', 'Release']) @@ -31,6 +32,7 @@ executable=args.executable, geometry='FLRW', use_gpu=args.use_gpu, + use_mpiexec=args.use_mpiexec, build_type=args.build_type, upgold=args.upgold) diff --git a/tst/regression/homogeneous_sphere.py b/tst/regression/homogeneous_sphere.py index 3ecfb0f1..70088c98 100755 --- a/tst/regression/homogeneous_sphere.py +++ b/tst/regression/homogeneous_sphere.py @@ -21,6 +21,7 @@ parser = argparse.ArgumentParser(description='Run a homogeneous sphere') parser.add_argument('--upgold', dest='upgold', action='store_true') parser.add_argument('--use_gpu', dest='use_gpu', action='store_true') +parser.add_argument('--use_mpiexec', dest='use_mpiexec', action='store_true') parser.add_argument('--input', type=str, default=os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../inputs/homogeneous_sphere.pin')) parser.add_argument('--executable', type=str, default=None) parser.add_argument('--build_type', type=str, default='Release', choices=['Debug, Release']) @@ -44,6 +45,7 @@ executable=args.executable, geometry='SphericalMinkowski', use_gpu=args.use_gpu, + use_mpiexec=args.use_mpiexec, build_type=args.build_type, upgold=args.upgold, compression_factor=10) diff --git a/tst/regression/linear_modes.gold b/tst/regression/linear_modes.gold index 29941ee7..571fe701 100644 --- a/tst/regression/linear_modes.gold +++ b/tst/regression/linear_modes.gold @@ -1,1232 +1,1232 @@ -1.000005628528739532e+00 -1.000002760802300550e+00 -9.999972997553338017e-01 -9.999943563572948335e-01 -9.999962801846589144e-01 -1.000001649258276837e+00 -1.000005620820334062e+00 -1.000004150766180988e+00 -9.999989030075261409e-01 -9.999945031723588285e-01 -9.999951247111897867e-01 -9.999999666911228990e-01 -1.000004883382004550e+00 -1.000005153047535122e+00 -1.000000599705294313e+00 -9.999955004486030807e-01 -9.999944881934780261e-01 -9.999982906361591928e-01 -1.000003652479025895e+00 -1.000005628541846825e+00 -1.000002244380341576e+00 -9.999968100808547256e-01 -9.999943599485604517e-01 -9.999967457293845730e-01 -1.000002185340829408e+00 -1.000005642541941020e+00 -1.000003720006343633e+00 -9.999983506438546721e-01 -9.999943794813748177e-01 -9.999954614264627839e-01 -1.000000534103744565e+00 -1.000005228487242270e+00 -1.000004875453037512e+00 -1.000000033313619863e+00 -9.999951164331567499e-01 -9.999946341582036657e-01 -9.999988401547134087e-01 -1.000004088571126992e+00 -1.000005593284785776e+00 -1.000001709470952349e+00 -9.999963473356909827e-01 -9.999943704194970140e-01 -9.999972393583208552e-01 -1.000002700092997632e+00 -1.000005643849237513e+00 -1.000003254450103407e+00 -9.999978145320155276e-01 -9.999943574942783409e-01 -9.999958494267148223e-01 -1.000001096926375732e+00 -1.000005496774726943e+00 -1.000004875452669584e+00 -9.999994658651549795e-01 -9.999947713165886487e-01 -9.999948470910047238e-01 -9.999994003354394367e-01 -1.000004499364685495e+00 -1.000005512001406638e+00 -1.000001159920171689e+00 -9.999959112267413630e-01 -9.999944067110044799e-01 -9.999977557557993002e-01 -1.000003189758528865e+00 -1.000005640313947675e+00 -1.000002760802300550e+00 -9.999972997557676768e-01 -9.999943560688479005e-01 -9.999962801842345872e-01 -1.000001649257038938e+00 -1.000005621004812717e+00 -1.000004538757190087e+00 -9.999989030075642216e-01 -9.999945030243991839e-01 -9.999951247130476339e-01 -9.999999666910829310e-01 -1.000004883539776568e+00 -1.000005365915851652e+00 -1.000000599705294313e+00 -9.999955004500691302e-01 -9.999944880729773056e-01 -9.999982906363659163e-01 -1.000003652484243277e+00 -1.000005627067319880e+00 -1.000002760802310542e+00 -9.999968100813726446e-01 -9.999943587434514392e-01 -9.999967457292208151e-01 -1.000002185339766481e+00 -1.000005642856323318e+00 -1.000004150766037547e+00 -9.999983506438546721e-01 -9.999943793195951169e-01 -9.999954614275690101e-01 -1.000000534102996053e+00 -1.000005228451245953e+00 -1.000005153042230033e+00 -1.000000033313618086e+00 -9.999951164340383780e-01 -9.999946341918117820e-01 -9.999988401550783390e-01 -1.000004088573421823e+00 -1.000005592102742868e+00 -1.000002244380358674e+00 -9.999963473356909827e-01 -9.999943708998354497e-01 -9.999972393583131947e-01 -1.000002700091364494e+00 -1.000005643622340346e+00 -1.000003720006071184e+00 -9.999978145317437450e-01 -9.999943574706082750e-01 -9.999958494265849263e-01 -1.000001096927432220e+00 -1.000005496575158581e+00 -1.000004875448803565e+00 -1.000000033313679593e+00 -9.999947713165886487e-01 -9.999948470919628463e-01 -9.999994003355955341e-01 -1.000004499438863936e+00 -1.000005512169376720e+00 -1.000001709470946354e+00 -9.999959112259187988e-01 -9.999944066527843844e-01 -9.999977557556760654e-01 -1.000003189752930677e+00 -1.000005639422707926e+00 -1.000003254449838064e+00 -9.999972997553338017e-01 -9.999943560688479005e-01 -9.999962801842277038e-01 -1.000001649258156711e+00 -1.000005621386515831e+00 -1.000004538758224371e+00 -9.999994658652552326e-01 -9.999945030200390050e-01 -9.999951247131133591e-01 -9.999999666910801555e-01 -1.000004883363642572e+00 -1.000005366041464505e+00 -1.000001159920191895e+00 -9.999955004486030807e-01 -9.999944880729773056e-01 -9.999982906361969404e-01 -1.000003652475752958e+00 -1.000005625834710976e+00 -1.000002760802211066e+00 -9.999972997562609489e-01 -9.999943586451935928e-01 -9.999967457292189277e-01 -1.000002185340485239e+00 -1.000005642549671059e+00 -1.000004150767109579e+00 -9.999989030078371144e-01 -9.999943794813748177e-01 -9.999954614275690101e-01 -1.000000534103019145e+00 -1.000005228568834337e+00 -1.000005153061212182e+00 -1.000000599705332727e+00 -9.999951164793701164e-01 -9.999946341923420245e-01 -9.999988401550476969e-01 -1.000004088577316930e+00 -1.000005593928879444e+00 -1.000002244380455263e+00 -9.999968100858261932e-01 -9.999943704194970140e-01 -9.999972393583131947e-01 -1.000002700086370488e+00 -1.000005644432087282e+00 -1.000003720006215957e+00 -9.999983506445834225e-01 -9.999943575934433504e-01 -9.999958494266537601e-01 -1.000001096925456467e+00 -1.000005496899583068e+00 -1.000004875454455266e+00 -1.000000033313196868e+00 -9.999951164930553915e-01 -9.999948470910047238e-01 -9.999994003355955341e-01 -1.000004499321753393e+00 -1.000005511920205148e+00 -1.000001709470967448e+00 -9.999963473372371903e-01 -9.999944062123556909e-01 -9.999977557557915286e-01 -1.000003189739357756e+00 -1.000005642795034788e+00 -1.000003254449985057e+00 -9.999978145329047052e-01 -9.999943563572948335e-01 -9.999962801842345872e-01 -1.000001649258156711e+00 -1.000005619599322992e+00 -1.000004538759156958e+00 -9.999994658639600464e-01 -9.999947714438510715e-01 -9.999951247112304209e-01 -9.999999666913291785e-01 -1.000004883399038924e+00 -1.000005365872079333e+00 -1.000001159920033578e+00 -9.999959112445278020e-01 -9.999944881934780261e-01 -9.999982906363659163e-01 -1.000003652475752958e+00 -1.000005632338691219e+00 -1.000002760802288337e+00 -9.999972997472790226e-01 -9.999943567464447680e-01 -9.999967457292198159e-01 -1.000002185344750050e+00 -1.000005642550357843e+00 -1.000004150766443001e+00 -9.999989030047454763e-01 -9.999945035217056022e-01 -9.999954614264627839e-01 -1.000000534102996053e+00 -1.000005228568834337e+00 -1.000005153038430850e+00 -1.000000599705102911e+00 -9.999955003701609391e-01 -9.999946341798189309e-01 -9.999988401550761186e-01 -1.000004088588974716e+00 -1.000005592525647469e+00 -1.000002244380356675e+00 -9.999968100447359509e-01 -9.999943610515239500e-01 -9.999972393583208552e-01 -1.000002700091364494e+00 -1.000005644432087282e+00 -1.000003720005975927e+00 -9.999983506418793633e-01 -9.999943790659656662e-01 -9.999958494266214526e-01 -1.000001096925393851e+00 -1.000005496709364339e+00 -1.000004875462937370e+00 -1.000000033313657388e+00 -9.999951161300691949e-01 -9.999946340991267002e-01 -9.999994003354394367e-01 -1.000004499438863936e+00 -1.000005511920205148e+00 -1.000001709471006528e+00 -9.999963473216946230e-01 -9.999943736582742604e-01 -9.999977557556830599e-01 -1.000003189743372323e+00 -1.000005639596431850e+00 -1.000003254450003931e+00 -9.999978145331541723e-01 -9.999943571553258082e-01 -9.999962801846589144e-01 -1.000001649257038938e+00 -1.000005621386515831e+00 -1.000004538759156958e+00 -9.999994658655363411e-01 -9.999947711702450448e-01 -9.999948470910431375e-01 -9.999999666915803109e-01 -1.000004883258530208e+00 -1.000005365874394370e+00 -1.000001159920109517e+00 -9.999959112661601646e-01 -9.999944082371383658e-01 -9.999982906361591928e-01 -1.000003652484243277e+00 -1.000005625834710976e+00 -1.000002760802288337e+00 -9.999972997569891442e-01 -9.999943557159270968e-01 -9.999962801846287164e-01 -1.000002185340025163e+00 -1.000005642176008847e+00 -1.000004150765567479e+00 -9.999989030076809060e-01 -9.999945034702872881e-01 -9.999951247204843519e-01 -1.000000534103744565e+00 -1.000005228451245953e+00 -1.000005153061212182e+00 -1.000000599705102911e+00 -9.999955004476279719e-01 -9.999944881888750414e-01 -9.999988401548404182e-01 -1.000004088606992303e+00 -1.000005594940963638e+00 -1.000002244380288952e+00 -9.999968100845629815e-01 -9.999943613398070141e-01 -9.999967457294722806e-01 -1.000002700092997632e+00 -1.000005643622340346e+00 -1.000003720006215957e+00 -9.999983506418793633e-01 -9.999943795461668783e-01 -9.999954614258708130e-01 -1.000001096926525168e+00 -1.000005496958468632e+00 -1.000004875463852416e+00 -1.000000033312921977e+00 -9.999951165621137061e-01 -9.999946341059653410e-01 -9.999988401548982608e-01 -1.000004499364685495e+00 -1.000005512169376720e+00 -1.000001709470967448e+00 -9.999963473216946230e-01 -9.999943696170027208e-01 -9.999972393583844710e-01 -1.000003189746767607e+00 -1.000005643480392559e+00 -1.000003254449885803e+00 -9.999978145247830907e-01 -9.999943579815728789e-01 -9.999958494264630238e-01 -1.000001649258276837e+00 -1.000005621004812717e+00 -1.000004538758224371e+00 -9.999994658639600464e-01 -9.999947711702450448e-01 -9.999948470843763593e-01 -9.999994003352858929e-01 -1.000004883338294182e+00 -1.000005365845172189e+00 -1.000001159920220983e+00 -9.999959111446200533e-01 -9.999944054997563780e-01 -9.999977557557988561e-01 -1.000003652479025895e+00 -1.000005627067319880e+00 -1.000002760802211066e+00 -9.999972997472790226e-01 -9.999943557159270968e-01 -9.999962801843798044e-01 -1.000001649258226211e+00 -1.000005642635592551e+00 -1.000004150767031641e+00 -9.999989030075279173e-01 -9.999945026359662315e-01 -9.999951247017295763e-01 -9.999999666912579022e-01 -1.000005228487242270e+00 -1.000005153042230033e+00 -1.000000599705332727e+00 -9.999955003701609391e-01 -9.999944881888750414e-01 -9.999982906362907542e-01 -1.000004088582988171e+00 -1.000005593699111905e+00 -1.000002244380362448e+00 -9.999968100784266678e-01 -9.999943560692980959e-01 -9.999967457293303941e-01 -1.000002185341857697e+00 -1.000005643849237513e+00 -1.000003720006071184e+00 -9.999983506445834225e-01 -9.999943790659656662e-01 -9.999954614258708130e-01 -1.000000534103909544e+00 -1.000005496884300182e+00 -1.000004875456988129e+00 -1.000000033313726000e+00 -9.999951165602208869e-01 -9.999946344156538380e-01 -9.999988401548888239e-01 -1.000004088580648709e+00 -1.000005512001406638e+00 -1.000001709470946354e+00 -9.999963473372371903e-01 -9.999943736582742604e-01 -9.999972393583844710e-01 -1.000002700094186014e+00 -1.000005641490590458e+00 -1.000003254450039458e+00 -9.999978145329936341e-01 -9.999943578841843372e-01 -9.999958494268899045e-01 -1.000001096926845356e+00 -1.000005620820334062e+00 -1.000004538757190087e+00 -9.999994658652552326e-01 -9.999947714438510715e-01 -9.999948470910431375e-01 -9.999994003352858929e-01 -1.000004499353685850e+00 -1.000005365897656429e+00 -1.000001159920152149e+00 -9.999959112420302443e-01 -9.999944051090710051e-01 -9.999977557558098473e-01 -1.000003189750150678e+00 -1.000005628541846825e+00 -1.000002760802310542e+00 -9.999972997562609489e-01 -9.999943567464447680e-01 -9.999962801846287164e-01 -1.000001649258226211e+00 -1.000005620814725660e+00 -1.000004150766166111e+00 -9.999989030075592256e-01 -9.999945030900928566e-01 -9.999951247068651350e-01 -9.999999666912370300e-01 -1.000004883374563613e+00 -1.590264765490082914e-06 -1.850729140869637458e-07 --1.388588244203136346e-06 --1.701031557416438364e-06 --5.275213099630358417e-07 -1.127180602577723188e-06 -1.726204084242227366e-06 -6.926305762819332230e-07 --9.844306660256146090e-07 --1.740803289592741682e-06 --1.004289949222725119e-06 -6.744112212491573858e-07 -1.741335549237821071e-06 -1.148018656192231561e-06 --5.090023917688826266e-07 --1.734498598948816102e-06 --1.400634720834447876e-06 -1.648279703523221325e-07 -1.613568967277801687e-06 -1.504597324170937172e-06 -1.028067228938113768e-08 --1.507104483490528637e-06 --1.655936937116649721e-06 --3.579361456535955894e-07 -1.261764197295514305e-06 -1.726212177919020907e-06 -5.275539698013462470e-07 --1.127236664219711872e-06 --1.737220343331189526e-06 --8.519527408269153213e-07 -8.332674221312309354e-07 -1.741805190543981896e-06 -1.004344870327094468e-06 --6.744500693762746864e-07 --1.741403751630510061e-06 --1.280895003494581976e-06 -3.385191388017711458e-07 -1.696356387088678474e-06 -1.400690768157706481e-06 --1.648377153886270362e-07 --1.613615946761236905e-06 --1.590224364818632895e-06 --1.850607130217392161e-07 -1.388532104941291530e-06 -1.701031341485648219e-06 -3.579589418115815814e-07 --1.261822845087495224e-06 --1.726119637576285491e-06 --6.925890190663733147e-07 -9.843772412154688514e-07 -1.740927294808470333e-06 -8.520018471357216599e-07 --8.333136191524715298e-07 --1.741691672644508485e-06 --1.147960314753250192e-06 -5.089729776927090865e-07 -1.734534116829732256e-06 -1.400690801915521886e-06 --3.385393394898985487e-07 --1.696405267145462151e-06 --1.504546415202605068e-06 --1.027946375866068890e-08 -1.507023368261896227e-06 -1.655957371204284394e-06 -1.850729093002186981e-07 --1.388594751825199030e-06 --1.701013619523377908e-06 --5.275213653444438600e-07 -1.127183222209527258e-06 -1.737421589172538437e-06 -6.926305765555142771e-07 --9.844309318740227226e-07 --1.740786773625750572e-06 --1.004290020861649846e-06 -6.744120618436009555e-07 -1.741390778335149306e-06 -1.280953965234318406e-06 --5.090024021606439771e-07 --1.734632918663487114e-06 --1.400634057052309753e-06 -1.648278595439363850e-07 -1.613607653265826696e-06 -1.590264905666604030e-06 -1.028067065780491688e-08 --1.507107115435284108e-06 --1.655926036113621952e-06 --3.579363188955392669e-07 -1.261781259633358326e-06 -1.726655678971084598e-06 -6.926305783295573401e-07 --1.127236716565594789e-06 --1.737006477177174457e-06 --8.519527617554620274e-07 -8.332646747978481785e-07 -1.742258799404387898e-06 -1.148018555346056507e-06 --6.744500485209134269e-07 --1.741347098123176928e-06 --1.280894987313796288e-06 -3.385181697038487692e-07 -1.696401660585019038e-06 -1.504598040628004677e-06 --1.648377187923204881e-07 --1.613613792776174776e-06 --1.590222706573371879e-06 --1.850608810711246522e-07 -1.388522568641007264e-06 -1.701136590258371164e-06 -5.275539753600890077e-07 --1.261822820560824661e-06 --1.726131226545413262e-06 --6.925890031772266819e-07 -9.843718222060919152e-07 -1.742000704344227011e-06 -1.004344794715776859e-06 --8.333134573449257216e-07 --1.741714163750060391e-06 --1.147960327360615846e-06 -5.089712561595381667e-07 -1.734574036784703316e-06 -1.400691744043100323e-06 --1.648377415733707867e-07 --1.696400115162551198e-06 --1.504545903645650570e-06 --1.027953056309141547e-08 -1.506989973039731223e-06 -1.655920479308038736e-06 -3.579589522959742434e-07 --1.388593351470622148e-06 --1.701011952376674966e-06 --5.275212863162724223e-07 -1.127177964477139891e-06 -1.738250354748017606e-06 -8.520018101900386781e-07 --9.844303504170458106e-07 --1.740859182696326817e-06 --1.004290027059698876e-06 -6.744107908519097616e-07 -1.741116874674736869e-06 -1.280954091395851010e-06 --3.385393066482944901e-07 --1.734642112838170612e-06 --1.400633959351386143e-06 -1.648282474766000761e-07 -1.613508647759532765e-06 -1.590249907748959577e-06 -1.850729168912970547e-07 --1.507102555053953027e-06 --1.655924432546027512e-06 --3.579362132718278165e-07 -1.261761708176442196e-06 -1.726532829553030439e-06 -6.926305492548642814e-07 --9.844306970560387685e-07 --1.736893099432485814e-06 --8.519527397257628548e-07 -8.332692941469899978e-07 -1.741728089231568348e-06 -1.148018495461474057e-06 --5.090023511046549143e-07 --1.741303242388386698e-06 --1.280894957643578081e-06 -3.385193196125991168e-07 -1.696379544777888894e-06 -1.504602180952277671e-06 -1.028068958602692250e-08 --1.613561232713966268e-06 --1.590222696773235619e-06 --1.850608111244003354e-07 -1.388538546951377015e-06 -1.701034391126270827e-06 -5.275539233213765546e-07 --1.127234671664729506e-06 --1.726011152294675224e-06 --6.925890098825439449e-07 -9.843883284494780983e-07 -1.740038832783223951e-06 -1.004344836786030559e-06 --6.744498740321052226e-07 --1.741504245649460200e-06 --1.147960309000444030e-06 -5.089722069015032994e-07 -1.734508523287152402e-06 -1.400692320193904770e-06 --1.648377033204455520e-07 --1.613557636144620663e-06 --1.504546181484033033e-06 --1.027957913124318570e-08 -1.507101195155202836e-06 -1.655965490179735808e-06 -3.579588997065866131e-07 --1.261816372878705018e-06 --1.701023201711399771e-06 --5.275213654853882366e-07 -1.127182558734247784e-06 -1.736287626053159374e-06 -8.520018575416590598e-07 --8.333115896018436259e-07 --1.741233791562141908e-06 --1.004290013300689863e-06 -6.744104854365436031e-07 -1.741474501100723134e-06 -1.280954225901281985e-06 --3.385392123944796676e-07 --1.696339783109555203e-06 --1.400633853529916587e-06 -1.648276988163869395e-07 -1.613616280226383397e-06 -1.590272583922566486e-06 -1.850728452661747030e-07 --1.388571029411387782e-06 --1.655924530264996947e-06 --3.579363204340156911e-07 -1.261765294842253382e-06 -1.725704550970076383e-06 -6.926305822189542276e-07 --9.844239440449483160e-07 --1.741860529457180813e-06 --8.519527518524718275e-07 -8.332648269389474782e-07 -1.741686763624658990e-06 -1.148018541475697390e-06 --5.090025861066646113e-07 --1.734476959485240437e-06 --1.280894948269444336e-06 -3.385183143243838288e-07 -1.696254254232860618e-06 -1.504595116280361796e-06 -1.028056233335913099e-08 --1.507077654368541262e-06 --1.590216314667034771e-06 --1.850608713169052016e-07 -1.388520441361015031e-06 -1.700980338400680608e-06 -5.275539633215826346e-07 --1.127236063755064691e-06 --1.738352324809754403e-06 --6.925889977216639691e-07 -9.843722963441212532e-07 -1.741591220560113558e-06 -1.004344803979023826e-06 --6.744506833673830678e-07 --1.741389301872752054e-06 --1.147960219981160685e-06 -5.089721876573454540e-07 -1.734476542971107082e-06 -1.400690338484537455e-06 --1.648377427507179431e-07 --1.613657006753198217e-06 --1.590211924678924318e-06 --1.027959209146975030e-08 -1.506988131456349131e-06 -1.655938485993354342e-06 -3.579589168854693923e-07 --1.261829484093831079e-06 --1.726715825596879808e-06 --5.275212437362224136e-07 -1.127178057903389972e-06 -1.737521352184773082e-06 -8.520018229417028529e-07 --8.333125651304750253e-07 --1.742161269370573554e-06 --1.004289947210272245e-06 -6.744127985546446917e-07 -1.741051388884109057e-06 -1.280953755630713605e-06 --3.385392033861634126e-07 --1.696253277177149094e-06 --1.504548069805109415e-06 -1.648278354643091128e-07 -1.613475959251400039e-06 -1.590262408484331375e-06 -1.850728479543541457e-07 --1.388583254850119703e-06 --1.700955423263663647e-06 --3.579361129172779379e-07 -1.261779325749936502e-06 -1.726525155565902702e-06 -6.926305780720819822e-07 --9.844266832580904818e-07 --1.741654060643989825e-06 --1.004289939756303958e-06 -8.332680579400941169e-07 -1.742243013133727748e-06 -1.148018595987038247e-06 --5.090027725329849093e-07 --1.734378166739236002e-06 --1.400636100968319663e-06 -3.385190319124972339e-07 -1.696506281846732884e-06 -1.504604861744389618e-06 -1.028059905200941356e-08 --1.507069193346817950e-06 --1.655914345597965604e-06 --1.850606863265083224e-07 -1.388552092878703080e-06 -1.701122628313673062e-06 -5.275539809636132356e-07 --1.127232993435450235e-06 --1.737436630235110488e-06 --8.519527397658789705e-07 -9.843782249210293688e-07 -1.740739431917946449e-06 -1.004344838814747736e-06 --6.744508427269661772e-07 --1.741353822898104329e-06 --1.280895085241792278e-06 -5.089722879147188954e-07 -1.734705775677896747e-06 -1.400691819755092668e-06 --1.648375501755424355e-07 --1.613494986889711667e-06 --1.590222334497007968e-06 --1.850607192132729485e-07 -1.507043730069361151e-06 -1.655922976586692305e-06 -3.579589254593023206e-07 --1.261827036489203838e-06 --1.725958591374725790e-06 --6.925890294860836820e-07 -1.127180733253413700e-06 -1.736649648758746197e-06 -8.520018083487564456e-07 --8.333123625034528594e-07 --1.741452707647580027e-06 --1.147960193312130135e-06 -6.744112495709264575e-07 -1.741096945602424631e-06 -1.280954164947170303e-06 --3.385392326444060757e-07 --1.696434418638351865e-06 --1.504549858019050800e-06 --1.027942930088404444e-08 -1.613534489317199388e-06 -1.590260040480478103e-06 -1.850729169299731349e-07 --1.388605987413341007e-06 --1.701035332109263384e-06 --5.275213130458057946e-07 -1.261763984985514936e-06 -1.726241266265620074e-06 -6.926305555714041155e-07 --9.844252420403123427e-07 --1.740161427431340968e-06 --1.004289978381531725e-06 -6.744112099647509990e-07 -1.741731817663470630e-06 -1.148018570729173269e-06 --5.090026755620329171e-07 --1.734742759434928427e-06 --1.400634515905571959e-06 -1.648279538339424900e-07 -1.696376704814610811e-06 -1.504598494872169923e-06 -1.028066870892576501e-08 --1.507091911883608387e-06 --1.655893623464248965e-06 --3.579361675225453786e-07 -1.388533938734241403e-06 -1.701038926954952633e-06 -5.275539739055161733e-07 --1.127234130548387463e-06 --1.736386854650884862e-06 --8.519527442219273472e-07 -8.332673401775128358e-07 -1.740817689762474523e-06 -1.004344825011346362e-06 --6.744500422891672025e-07 --1.741096689210724751e-06 --1.280894868778158905e-06 -3.385189366979776427e-07 -1.734652198908528086e-06 -1.400690791354813143e-06 --1.648377541514747078e-07 --1.613519101369212377e-06 --1.590222433229536816e-06 --1.850607103140266643e-07 -1.388533408879053315e-06 -1.655954223837759175e-06 -3.579589533039035342e-07 --1.261819035994373110e-06 --1.726388645621787296e-06 --6.925890301642044953e-07 -9.843785017159068400e-07 -1.737000350907603905e-06 -8.520018475476419348e-07 --8.333136848140522488e-07 --1.742061194791934156e-06 --1.147960231265457910e-06 -5.089721727050693534e-07 -1.741297441231007580e-06 -1.280954014745376018e-06 --3.385392960721465077e-07 --1.696451581426947372e-06 --1.504550365415478776e-06 --1.027943118621443695e-08 -1.507040538203202165e-06 -1.590264633512082422e-06 -1.850729074580114792e-07 --1.388589550375052561e-06 --1.701090859141943968e-06 --5.275213157429978796e-07 -1.127180362195730999e-06 -1.726192361805550371e-06 -6.926305758712251581e-07 --9.844312394114428420e-07 --1.740848301116477094e-06 --1.004289947260643176e-06 -6.744111886836564748e-07 -1.741318183988452249e-06 -1.148018657348503531e-06 --5.090024160993471123e-07 --1.734644591159978853e-06 --1.400635158561785535e-06 -1.648279631807470339e-07 -1.613526411383233149e-06 -1.504597547354309073e-06 -1.028065787466899798e-08 --1.507094808177593535e-06 --1.655919501024793512e-06 --3.579361336895907404e-07 -1.261761598316162847e-06 -1.701043142061134715e-06 -5.275539686005711651e-07 --1.127236636967320203e-06 --1.736909142709718707e-06 --8.519527328932085376e-07 -8.332673448540016429e-07 -1.741725489135484205e-06 -1.004344870763382504e-06 --6.744501337659342148e-07 --1.741340970541436932e-06 --1.280894975300672104e-06 -3.385190317652273211e-07 -1.696338176289258743e-06 -1.400690744447755463e-06 --1.648377118329533743e-07 --1.613597865805794811e-06 --1.590226031244483694e-06 --1.850606733397233657e-07 -1.388531945827222191e-06 -1.701047207817729136e-06 -3.579589414388314452e-07 --1.261823264317818449e-06 --1.726313466700230310e-06 --6.925889919202242462e-07 -9.843787614439498560e-07 -1.740917213504126696e-06 -8.520018467356391998e-07 --8.333135005031860428e-07 --1.741557060862754581e-06 --1.147960268085925917e-06 -5.089725240092820862e-07 -1.734630835993027996e-06 -1.280954040857855735e-06 --3.385392950009363383e-07 --1.696389995147857853e-06 --1.504546890036757210e-06 --1.027961188272786209e-08 -1.507036240073446114e-06 -1.655959555826614411e-06 -1.850729076436188443e-07 --1.388593212752186936e-06 --1.701006838237213828e-06 --5.275212852257531840e-07 -1.127178683840543033e-06 -1.737020925846196760e-06 -6.926305748046115189e-07 --9.844299088774786119e-07 --1.740925542203291759e-06 --1.004290007003716702e-06 -6.744107042022599548e-07 -1.741435709825935481e-06 -1.280954053944180827e-06 --5.090023840791434605e-07 --1.734595364073576457e-06 --1.400634092044772874e-06 -1.648279295576969274e-07 -1.613463305719000815e-06 -1.590265258593738983e-06 -1.028065892532635130e-08 --1.507095744533528857e-06 --1.655925203232106663e-06 --3.579362009799558894e-07 -1.261748430319599773e-06 -1.726121581406505635e-06 -5.275539683611384561e-07 --1.127236383812855309e-06 --1.737105258668889080e-06 --8.519527344823373202e-07 -8.332655063772550808e-07 -1.741999493867693744e-06 -1.148018639623488477e-06 --6.744501555272217753e-07 --1.741300265041495049e-06 --1.280894964161216665e-06 -3.385198128477862204e-07 -1.696089828885080503e-06 -1.504598314128847461e-06 --1.648377264320529201e-07 --1.613602985855504784e-06 --1.590222425754394400e-06 --1.850606615669670153e-07 -1.388531452354886985e-06 -1.701102540831980756e-06 -5.275539716868027299e-07 --1.261823966723208634e-06 --1.726190644147426965e-06 --6.925889942170049046e-07 -9.843857574402787822e-07 -1.741095491941425659e-06 -1.004344842583398701e-06 --8.333135707087331351e-07 --1.741663383577325622e-06 --1.147960329353777756e-06 -5.089728844887976374e-07 -1.734684800346359833e-06 -1.400691590590690259e-06 --3.385393480201725429e-07 --1.696399485446525602e-06 --1.504546510586320973e-06 --1.027938485238273844e-08 -1.507080305796631483e-06 -1.656015133408582491e-06 -3.579589492293104631e-07 --1.388594604913892693e-06 --1.701010685315829370e-06 --5.275212901818534962e-07 -1.127185078357103859e-06 -1.736616342016953167e-06 -8.520018344173663146e-07 --9.844304725327911878e-07 --1.740965161270790161e-06 --1.004290031213002537e-06 -6.744108472012478456e-07 -1.741581278298808486e-06 -1.280954403015497926e-06 --3.385393118433523258e-07 --1.734619107468389150e-06 --1.400633980049512253e-06 -1.648278906750231311e-07 -1.613570582697605439e-06 -1.590260759974151735e-06 -1.850729094683444679e-07 --1.507102500025513167e-06 --1.655921556354297312e-06 --3.579362475542472533e-07 -1.261756780791450496e-06 -1.725748945055332470e-06 -6.926305705391843071e-07 --1.127237630278965120e-06 --1.737040415864784659e-06 --8.519527374473198244e-07 -8.332656578725061578e-07 -1.742253152560022106e-06 -1.148018563730156966e-06 --5.090024215591247669e-07 --1.741243658726735979e-06 --1.280894950455009569e-06 -3.385185393912210502e-07 -1.696334705621889013e-06 -1.504592795340949584e-06 -1.028061790487706699e-08 --1.613657169410413575e-06 --1.590222084155557492e-06 --1.850608462758699380e-07 -1.388518131384592072e-06 -1.701072734164493894e-06 -5.275539304736860212e-07 --1.127238008125842839e-06 --1.726185478023244631e-06 --6.925889787473879732e-07 -9.843733839301473761e-07 -1.740160141609993975e-06 -1.004344780140668966e-06 --6.744507542533378564e-07 --1.741669229525617891e-06 --1.147960308469618858e-06 -5.089713572115521794e-07 -1.734339372165476306e-06 -1.400691425918160963e-06 --1.648376386491944467e-07 --1.696477797889114190e-06 --1.504546315678766606e-06 --1.027938717743279726e-08 -1.506990789283571675e-06 -1.655976698270561457e-06 -3.579589494230031813e-07 --1.261830028874151778e-06 --1.700983082463960959e-06 --5.275212621773382855e-07 -1.127173160533150306e-06 -1.737568977892021735e-06 -8.520018339862569317e-07 --8.333142415685074648e-07 --1.740939344644816669e-06 --1.004290007531021605e-06 -6.744115422746657827e-07 -1.740955319811052847e-06 -1.280954237749410292e-06 --3.385392772277136745e-07 --1.696408577544060122e-06 --1.400633975581495195e-06 -1.648283710793455411e-07 -1.613541157771279822e-06 -1.590271223727216485e-06 -1.850729391147819072e-07 --1.388612279700782862e-06 --1.655908914243125178e-06 --3.579361619669748092e-07 -1.261772547886908059e-06 -1.726494664666686955e-06 -6.926306019008986165e-07 --9.844319084557291042e-07 --1.737026184834235509e-06 --8.519527400719455380e-07 -8.332689029542550202e-07 -1.741371226171650574e-06 -1.148018655309984913e-06 --5.090027485612200303e-07 --1.734723042830691599e-06 --1.280894883536558799e-06 -3.385195705406192733e-07 -1.696366486535114283e-06 -1.504602990292107365e-06 -1.028077317576515492e-08 --1.507133447163947495e-06 --1.590222092814339725e-06 --1.850607621872985744e-07 -1.388542698225709939e-06 -1.700956209036821758e-06 -5.275540081326880979e-07 --1.127234033009331002e-06 --1.736801148419747147e-06 --6.925890247408395166e-07 -9.843863585442160342e-07 -1.741897476277560789e-06 -1.004344838463326896e-06 --6.744498164834365655e-07 --1.741618202388645123e-06 --1.147960252130848252e-06 -5.089719849636938765e-07 -1.734786802983807041e-06 -1.400690929348552800e-06 --1.648375407929886808e-07 --1.613487824697420219e-06 --1.504546947025254604e-06 --1.027949592541522509e-08 -1.507082540295700812e-06 -1.655914888576624143e-06 -3.579589548223013070e-07 --1.261825295115731484e-06 --1.725877888125440188e-06 --5.275212640265594401e-07 -1.127177136628583626e-06 -1.736480201726351806e-06 -8.520018414740653490e-07 --8.333128431089876549e-07 --1.741956109823979605e-06 --1.004289970032103924e-06 -6.744083160638388031e-07 -1.741423660789217258e-06 -1.280953714161992211e-06 --3.385396475408251925e-07 --1.696242829560748933e-06 --1.504544921077952609e-06 -1.648277199650172369e-07 -1.613573796495554423e-06 -1.590262895351839295e-06 -1.850729264289812674e-07 --1.388617896793517876e-06 --1.701104335420668386e-06 --3.579361365442565734e-07 -1.261725574991984579e-06 -1.725927095259592511e-06 -6.926305975980303250e-07 --9.844332591812374142e-07 --1.741566735081765478e-06 --8.519527372834580185e-07 -8.332631232779616813e-07 -1.742211802605906232e-06 -1.148018435661381874e-06 --5.090026485225517664e-07 --1.734720142535303327e-06 --1.400634780055624592e-06 -3.385191237651266991e-07 -1.696085009963342313e-06 -1.504596475680821139e-06 -1.028076077472234919e-08 --1.507123908665125899e-06 --1.655938862777205078e-06 --1.850607029207132426e-07 -1.388509248107039563e-06 -1.701066517026948025e-06 -5.275540059934432856e-07 --1.127239805770184038e-06 --1.736092143553970527e-06 --8.519527361450001035e-07 -9.843754225922577657e-07 -1.739643212083854234e-06 -1.004344843433495366e-06 --6.744496218819077910e-07 --1.741333365699922349e-06 --1.280895317327004634e-06 -5.089723609021159452e-07 -1.734482161150154862e-06 -1.400692954643723281e-06 --1.648375766769760290e-07 --1.613699532047422093e-06 --1.590226314757858155e-06 --1.027944017076012186e-08 -1.507039298405862370e-06 -1.656006947935212472e-06 -3.579589261123017248e-07 --1.261825516591687405e-06 --1.726366632561289537e-06 --6.925890308139091532e-07 -1.127179188628730195e-06 -1.738538725988569965e-06 -8.520018361738839483e-07 --8.333130985189662907e-07 --1.741587194395977850e-06 --1.147960233455665095e-06 -6.744110676648418459e-07 -1.741333821610902535e-06 -1.280954485934699437e-06 --3.385393181167661655e-07 --1.696443634018159185e-06 --1.504546304205754675e-06 --1.027943251450810224e-08 -1.613533829205230461e-06 -1.590252344359356449e-06 -1.850729367243258634e-07 --1.388583961626842159e-06 --1.700953865505401834e-06 --5.275213143991535331e-07 -1.261760805805104762e-06 -1.725819267574720927e-06 -6.926305500241761324e-07 --9.844303732986032653e-07 --1.740293455998816554e-06 --1.004289964934459536e-06 -8.332671041652599658e-07 -1.742274051589850055e-06 -1.148018616373521665e-06 --5.090030226700787340e-07 --1.734395104781504249e-06 --1.400634788150126604e-06 -1.648279423971163625e-07 -1.696371138759718979e-06 -1.504596158615509619e-06 -1.028067767113458230e-08 --1.507099273513728817e-06 --1.655912739855413748e-06 --3.579361695146866141e-07 -1.388528122621444856e-06 -1.701050240375294913e-06 -5.275539633029978847e-07 --1.127239214595986499e-06 --1.738200214381804411e-06 --8.519527517336309874e-07 -8.332671037666123795e-07 -1.740751701307312179e-06 -1.004344783992067638e-06 --6.744508687318256995e-07 --1.741251296447213591e-06 --1.280895004223554836e-06 -3.385188939962563274e-07 -1.734572544061627382e-06 -1.400691395214223112e-06 --1.648377751771490938e-07 --1.613654069756421429e-06 --1.590215504365368672e-06 --1.850607111848939276e-07 -1.507037537425401796e-06 -1.655958339317997208e-06 -3.579589518641616114e-07 --1.261822172097506300e-06 --1.725797783200190056e-06 --6.925890294727918293e-07 -9.843778963328664999e-07 -1.737178431780542629e-06 -8.520018413846791268e-07 --8.333139473196456831e-07 --1.742245021774007872e-06 --1.147960148770921662e-06 -5.089721369342301751e-07 -1.741310603667982871e-06 -1.280953932279122835e-06 --3.385393170266433916e-07 --1.696296137648279874e-06 --1.504548338331404144e-06 --1.027942829324316174e-08 -1.507035621867332381e-06 -1.590264345849646242e-06 -1.850729035477137626e-07 --1.388595280322372227e-06 --1.701050399214992493e-06 --5.275213135840591278e-07 -1.127179510866506852e-06 -1.726137462826043499e-06 -6.926305803623038528e-07 --9.844296559440050383e-07 --1.739797690169686256e-06 --1.004289941200076911e-06 -6.744111433083192837e-07 -1.741811333519652724e-06 -1.148018651135363127e-06 --5.090023546146911557e-07 --1.734527413667989552e-06 --1.400635785566348553e-06 -1.648279431176801968e-07 -1.613534133241710520e-06 -1.504597441069569458e-06 -1.028065202879326984e-08 --1.507090455995950591e-06 --1.655940491521968514e-06 --3.579361683397125794e-07 -1.261762431799203453e-06 +1.000005632655319499e+00 +1.000002760808383684e+00 +9.999972996949745285e-01 +9.999943565266583567e-01 +9.999962802371848980e-01 +1.000001649208487331e+00 +1.000005620483547686e+00 +1.000004150727892061e+00 +9.999989029694753562e-01 +9.999945052546052038e-01 +9.999951245617294537e-01 +9.999999666961703060e-01 +1.000004883968774960e+00 +1.000005153020244952e+00 +1.000000599734518048e+00 +9.999955005058174251e-01 +9.999944869738877085e-01 +9.999982906507698388e-01 +1.000003652558603573e+00 +1.000005628965033422e+00 +1.000002244374423199e+00 +9.999968100084866141e-01 +9.999943649241527233e-01 +9.999967457378612368e-01 +1.000002185287540257e+00 +1.000005642989404420e+00 +1.000003719999225105e+00 +9.999983506855543158e-01 +9.999943790434682178e-01 +9.999954615166134486e-01 +1.000000534120877971e+00 +1.000005228450156824e+00 +1.000004875483002431e+00 +1.000000033345461725e+00 +9.999951164123052072e-01 +9.999946323421767813e-01 +9.999988401746482403e-01 +1.000004088373919187e+00 +1.000005589093612368e+00 +1.000001709466136646e+00 +9.999963473093869126e-01 +9.999943761293018651e-01 +9.999972393619038780e-01 +1.000002700093578278e+00 +1.000005644115180781e+00 +1.000003254457284108e+00 +9.999978146264839607e-01 +9.999943568631461943e-01 +9.999958495106286982e-01 +1.000001096971994130e+00 +1.000005495535843947e+00 +1.000004875450465347e+00 +9.999994658331410324e-01 +9.999947709284359165e-01 +9.999948465842898315e-01 +9.999994003330860970e-01 +1.000004499339977482e+00 +1.000005513960985581e+00 +1.000001159938610495e+00 +9.999959108496043747e-01 +9.999944056627527722e-01 +9.999977557711768883e-01 +1.000003189886431443e+00 +1.000005636202187853e+00 +1.000002760808383684e+00 +9.999972998744335317e-01 +9.999943559924534542e-01 +9.999962802054666033e-01 +1.000001649278303040e+00 +1.000005620628910519e+00 +1.000004538623388450e+00 +9.999989029677013308e-01 +9.999945028654575463e-01 +9.999951245676423905e-01 +9.999999667078377508e-01 +1.000004883749974649e+00 +1.000005367520260258e+00 +1.000000599734518048e+00 +9.999955009783095816e-01 +9.999944860242014899e-01 +9.999982906563524843e-01 +1.000003652592456493e+00 +1.000005626612752385e+00 +1.000002760794253653e+00 +9.999968099938674193e-01 +9.999943548367293822e-01 +9.999967457329563825e-01 +1.000002185325947535e+00 +1.000005642809836504e+00 +1.000004150697972882e+00 +9.999983506855543158e-01 +9.999943783760981697e-01 +9.999954615040358430e-01 +1.000000534158342669e+00 +1.000005228311358962e+00 +1.000005153536246860e+00 +1.000000033271464250e+00 +9.999951155518908008e-01 +9.999946330534588146e-01 +9.999988401823904915e-01 +1.000004088583912543e+00 +1.000005588376624566e+00 +1.000002244346593239e+00 +9.999963473093869126e-01 +9.999943743511141570e-01 +9.999972393620715216e-01 +1.000002700174408510e+00 +1.000005643771175512e+00 +1.000003719963573623e+00 +9.999978144589464213e-01 +9.999943569558090717e-01 +9.999958495208238762e-01 +1.000001096972067183e+00 +1.000005495200696481e+00 +1.000004875516921521e+00 +1.000000033248674702e+00 +9.999947709284359165e-01 +9.999948467812824759e-01 +9.999994003578855928e-01 +1.000004499543848624e+00 +1.000005513648303479e+00 +1.000001709420340612e+00 +9.999959110738979584e-01 +9.999944112094069082e-01 +9.999977557586826604e-01 +1.000003189792319835e+00 +1.000005635582378538e+00 +1.000003254426833799e+00 +9.999972996949745285e-01 +9.999943559924534542e-01 +9.999962802051375332e-01 +1.000001649284675054e+00 +1.000005621498109232e+00 +1.000004538640674401e+00 +9.999994658109249146e-01 +9.999945035818743611e-01 +9.999951246263967253e-01 +9.999999666998068415e-01 +1.000004883316716331e+00 +1.000005367234137355e+00 +1.000001159884960744e+00 +9.999955005058174251e-01 +9.999944860242014899e-01 +9.999982906307588459e-01 +1.000003652605387927e+00 +1.000005624334296517e+00 +1.000002760792013445e+00 +9.999972997383014262e-01 +9.999943614488633337e-01 +9.999967457341174537e-01 +1.000002185393187970e+00 +1.000005642143994233e+00 +1.000004150708544870e+00 +9.999989029061402412e-01 +9.999943790434682178e-01 +9.999954615040358430e-01 +1.000000534081493475e+00 +1.000005228295131277e+00 +1.000005153196704244e+00 +1.000000599682605351e+00 +9.999951170624205021e-01 +9.999946333588105585e-01 +9.999988401642738722e-01 +1.000004088706652361e+00 +1.000005595181765905e+00 +1.000002244379371907e+00 +9.999968101646514729e-01 +9.999943761293018651e-01 +9.999972393620715216e-01 +1.000002700108178377e+00 +1.000005642882210610e+00 +1.000003720001498175e+00 +9.999983506322962512e-01 +9.999943596158442638e-01 +9.999958494945223597e-01 +1.000001096905887232e+00 +1.000005495644664899e+00 +1.000004875475132726e+00 +1.000000033312556269e+00 +9.999951170408881707e-01 +9.999948465842898315e-01 +9.999994003578855928e-01 +1.000004499522637147e+00 +1.000005512885039138e+00 +1.000001709484434675e+00 +9.999963472312672907e-01 +9.999944020628815933e-01 +9.999977557613660695e-01 +1.000003189716275331e+00 +1.000005639801760493e+00 +1.000003254451671930e+00 +9.999978145217349734e-01 +9.999943565266583567e-01 +9.999962802054666033e-01 +1.000001649284675054e+00 +1.000005620784933713e+00 +1.000004538678776589e+00 +9.999994658770350320e-01 +9.999947714133969878e-01 +9.999951245978127012e-01 +9.999999667342928111e-01 +1.000004883138554179e+00 +1.000005367418171476e+00 +1.000001159934313488e+00 +9.999959109807341484e-01 +9.999944869738877085e-01 +9.999982906563524843e-01 +1.000003652605387927e+00 +1.000005619484136021e+00 +1.000002760804144186e+00 +9.999972997261444840e-01 +9.999943567613929218e-01 +9.999967457339060672e-01 +1.000002185403360278e+00 +1.000005642411317064e+00 +1.000004150689643767e+00 +9.999989030539646606e-01 +9.999945040795561457e-01 +9.999954615166134486e-01 +1.000000534158342669e+00 +1.000005228295131277e+00 +1.000005153882767006e+00 +1.000000599705133553e+00 +9.999955003056808511e-01 +9.999946334501745859e-01 +9.999988401734757337e-01 +1.000004088639646405e+00 +1.000005593670743709e+00 +1.000002244387094841e+00 +9.999968100584690767e-01 +9.999943599343450451e-01 +9.999972393619038780e-01 +1.000002700174408510e+00 +1.000005642882210610e+00 +1.000003719982992090e+00 +9.999983506613785433e-01 +9.999943787217002722e-01 +9.999958495178359330e-01 +1.000001096954051372e+00 +1.000005496312835085e+00 +1.000004875478968547e+00 +1.000000033287579804e+00 +9.999951168764663612e-01 +9.999946331056811522e-01 +9.999994003330860970e-01 +1.000004499543848624e+00 +1.000005512885039138e+00 +1.000001709477368106e+00 +9.999963473939638137e-01 +9.999943780502227320e-01 +9.999977557667091288e-01 +1.000003189830621864e+00 +1.000005637416242932e+00 +1.000003254456625301e+00 +9.999978144411570957e-01 +9.999943589123083676e-01 +9.999962802371848980e-01 +1.000001649278303040e+00 +1.000005621498109232e+00 +1.000004538678776589e+00 +9.999994658622803900e-01 +9.999947722049712384e-01 +9.999948463156687062e-01 +9.999999666883998550e-01 +1.000004883059735450e+00 +1.000005366258192918e+00 +1.000001159913265214e+00 +9.999959109662573953e-01 +9.999944021225303237e-01 +9.999982906507698388e-01 +1.000003652592456493e+00 +1.000005624334296517e+00 +1.000002760804144186e+00 +9.999972997290592636e-01 +9.999943563340063513e-01 +9.999962802322818201e-01 +1.000002185330710391e+00 +1.000005640836852283e+00 +1.000004150751921728e+00 +9.999989029865307133e-01 +9.999945034238885144e-01 +9.999951246482331468e-01 +1.000000534120877971e+00 +1.000005228311358962e+00 +1.000005153196704244e+00 +1.000000599705133553e+00 +9.999955002942768623e-01 +9.999944865621374079e-01 +9.999988401662210924e-01 +1.000004088660306545e+00 +1.000005597738118590e+00 +1.000002244387627748e+00 +9.999968100301691587e-01 +9.999943593569411426e-01 +9.999967457255370951e-01 +1.000002700093578278e+00 +1.000005643771175512e+00 +1.000003720001498175e+00 +9.999983506613785433e-01 +9.999943800857316045e-01 +9.999954615287282023e-01 +1.000001096930779321e+00 +1.000005496538477034e+00 +1.000004875481131261e+00 +1.000000033332056004e+00 +9.999951162199782750e-01 +9.999946336329671448e-01 +9.999988401593464804e-01 +1.000004499339977482e+00 +1.000005513648303479e+00 +1.000001709484434675e+00 +9.999963473939638137e-01 +9.999943649475041552e-01 +9.999972393553445693e-01 +1.000003189733285724e+00 +1.000005644760634915e+00 +1.000003254444560064e+00 +9.999978145439466504e-01 +9.999943571569811507e-01 +9.999958494474100457e-01 +1.000001649208487331e+00 +1.000005620628910519e+00 +1.000004538640674401e+00 +9.999994658770350320e-01 +9.999947722049712384e-01 +9.999948468252387590e-01 +9.999994003217230754e-01 +1.000004883005678025e+00 +1.000005366956320030e+00 +1.000001159915184790e+00 +9.999959114697550833e-01 +9.999944071037120130e-01 +9.999977557691764884e-01 +1.000003652558603573e+00 +1.000005626612752385e+00 +1.000002760792013445e+00 +9.999972997261444840e-01 +9.999943563340063513e-01 +9.999962801845050375e-01 +1.000001649218661415e+00 +1.000005641543503909e+00 +1.000004150665656066e+00 +9.999989029996332324e-01 +9.999945047613947313e-01 +9.999951247846718960e-01 +9.999999667155246019e-01 +1.000005228450156824e+00 +1.000005153536246860e+00 +1.000000599682605351e+00 +9.999955003056808511e-01 +9.999944865621374079e-01 +9.999982906611800670e-01 +1.000004088755765075e+00 +1.000005598271136220e+00 +1.000002244348032532e+00 +9.999968100916505342e-01 +9.999943640835056158e-01 +9.999967457235865442e-01 +1.000002185347521610e+00 +1.000005644115180781e+00 +1.000003719963573623e+00 +9.999983506322962512e-01 +9.999943787217002722e-01 +9.999954615287282023e-01 +1.000000534153414167e+00 +1.000005496702192076e+00 +1.000004875448733621e+00 +1.000000033272859801e+00 +9.999951163138114385e-01 +9.999946326145957576e-01 +9.999988401736024102e-01 +1.000004088469371721e+00 +1.000005513960985581e+00 +1.000001709420340612e+00 +9.999963472312672907e-01 +9.999943780502227320e-01 +9.999972393553445693e-01 +1.000002700212754503e+00 +1.000005645330762860e+00 +1.000003254434076005e+00 +9.999978145630771253e-01 +9.999943576993874927e-01 +9.999958495086429533e-01 +1.000001096954989510e+00 +1.000005620483547686e+00 +1.000004538623388450e+00 +9.999994658109249146e-01 +9.999947714133969878e-01 +9.999948463156687062e-01 +9.999994003217230754e-01 +1.000004499638560196e+00 +1.000005366980012411e+00 +1.000001159875671508e+00 +9.999959114989783737e-01 +9.999944078390725632e-01 +9.999977557599983857e-01 +1.000003189869540288e+00 +1.000005628965033422e+00 +1.000002760794253653e+00 +9.999972997383014262e-01 +9.999943567613929218e-01 +9.999962802322818201e-01 +1.000001649218661415e+00 +1.000005620196233735e+00 +1.000004150703476480e+00 +9.999989029721221279e-01 +9.999945044132163563e-01 +9.999951245066918126e-01 +9.999999666814920474e-01 +1.000004883573349268e+00 +1.590367539041457537e-06 +1.850912408548692162e-07 +-1.388671263919384155e-06 +-1.701402812589428375e-06 +-5.275245537920439392e-07 +1.127207486787609383e-06 +1.725513118501249725e-06 +6.926330706003840947e-07 +-9.843926778009791954e-07 +-1.741847553483955041e-06 +-1.004286466214067983e-06 +6.744469082427657453e-07 +1.741808948583900944e-06 +1.148018083313236715e-06 +-5.089801355624572556e-07 +-1.734300937657732912e-06 +-1.400619844916229366e-06 +1.648243680517588008e-07 +1.613372567611652862e-06 +1.504581194016223573e-06 +1.027057519218336824e-08 +-1.506965207472381200e-06 +-1.656413222052862091e-06 +-3.579387071900327507e-07 +1.261832909686356920e-06 +1.726530510927856447e-06 +5.275505036001899248e-07 +-1.127283476069760551e-06 +-1.738991200931393030e-06 +-8.519558241342447753e-07 +8.332683681776776070e-07 +1.741543189546330788e-06 +1.004348184969015373e-06 +-6.744859534995672576e-07 +-1.741128142201565000e-06 +-1.280871119453824414e-06 +3.385081253452617528e-07 +1.695890104207147870e-06 +1.400661979984600656e-06 +-1.648645316816077902e-07 +-1.613580376379654210e-06 +-1.590413693388966491e-06 +-1.850598198757230344e-07 +1.388569531686582505e-06 +1.701594467880254092e-06 +3.579597281925138896e-07 +-1.262011462870778688e-06 +-1.727044134608643941e-06 +-6.925960486877090200e-07 +9.843413329179845028e-07 +1.741951384656060736e-06 +8.520003192028401959e-07 +-8.334344866947607621e-07 +-1.741882352976100373e-06 +-1.147954552841384033e-06 +5.089651065550712443e-07 +1.734499890489319603e-06 +1.400657029138366716e-06 +-3.385102729909338517e-07 +-1.696068296688998337e-06 +-1.504578035365303085e-06 +-1.027792459486570175e-08 +1.506889434950186658e-06 +1.656390619447936956e-06 +1.850579395021460447e-07 +-1.388808107645545854e-06 +-1.701449497581291826e-06 +-5.275302993430160891e-07 +1.127129333673650356e-06 +1.739139556716176440e-06 +6.926275968399265429e-07 +-9.843286574677046199e-07 +-1.738833342797969636e-06 +-1.004290676010142285e-06 +6.744290190047559574e-07 +1.741608192516847482e-06 +1.280938630120717270e-06 +-5.089962051112259242e-07 +-1.734595962635921047e-06 +-1.400613937252086356e-06 +1.648187793660271902e-07 +1.613277429219103755e-06 +1.590372361279220448e-06 +1.026314296979694244e-08 +-1.507199462265586231e-06 +-1.656498548720226997e-06 +-3.579462891905561392e-07 +1.261786933656091673e-06 +1.727036888705413617e-06 +6.926335290490646140e-07 +-1.127305826552776190e-06 +-1.734666481337623469e-06 +-8.519554876257128211e-07 +8.332817916134800692e-07 +1.741570517560293097e-06 +1.148022411434485064e-06 +-6.745069916869999551e-07 +-1.740893134080086125e-06 +-1.280863526478345686e-06 +3.385007361086511826e-07 +1.695925012644290348e-06 +1.504607413513912528e-06 +-1.648357971565737352e-07 +-1.613293906584121117e-06 +-1.590371049557741721e-06 +-1.850698468576710981e-07 +1.388584273480631005e-06 +1.701619351222137502e-06 +5.275664409881972963e-07 +-1.261890835872668019e-06 +-1.726952582184757882e-06 +-6.925939866257344096e-07 +9.843387710206114620e-07 +1.741827775922222212e-06 +1.004355416021173411e-06 +-8.332887313101556406e-07 +-1.741493618313671237e-06 +-1.147954127011784552e-06 +5.089536504049958006e-07 +1.734405951374010952e-06 +1.400665060755398470e-06 +-1.648147270693007677e-07 +-1.696026167294465809e-06 +-1.504516816255540277e-06 +-1.028570061164219897e-08 +1.506966518059593660e-06 +1.656403618202785754e-06 +3.579714705349063427e-07 +-1.388536818637949710e-06 +-1.701761632405453606e-06 +-5.275227261590045916e-07 +1.127176760524699177e-06 +1.738899137111849145e-06 +8.520110766617004472e-07 +-9.843379307777278582e-07 +-1.741806689421038490e-06 +-1.004295364866518706e-06 +6.743993238623917024e-07 +1.741251734869187301e-06 +1.280939977094745456e-06 +-3.385363576962681561e-07 +-1.734477658715999417e-06 +-1.400598327554048858e-06 +1.648342583341889763e-07 +1.613392098859980280e-06 +1.590351309578219981e-06 +1.850793076461093879e-07 +-1.506990158082079201e-06 +-1.656348914111078322e-06 +-3.579349890952416767e-07 +1.261748446896396022e-06 +1.726954622768805722e-06 +6.926407633502231383e-07 +-9.843909964545581157e-07 +-1.737771171945459064e-06 +-8.519585978329506073e-07 +8.332596957649066877e-07 +1.741883632174271865e-06 +1.148021789733716254e-06 +-5.089646463921921279e-07 +-1.741108470592745993e-06 +-1.280864836161371862e-06 +3.385379663369058124e-07 +1.696309625747959570e-06 +1.504609226014816693e-06 +1.029970426659359921e-08 +-1.613350527324997949e-06 +-1.590302724258083714e-06 +-1.850619383300565058e-07 +1.388450251314567264e-06 +1.701199448021600421e-06 +5.275580778973880034e-07 +-1.127288025163849908e-06 +-1.726563348516592840e-06 +-6.925950592092194851e-07 +9.843972034917504489e-07 +1.741986631626964369e-06 +1.004347296229844827e-06 +-6.744476113853419399e-07 +-1.741626188449242454e-06 +-1.147951644189643252e-06 +5.089802152540511556e-07 +1.734464186140258252e-06 +1.400680181652775881e-06 +-1.648386383732958587e-07 +-1.613458033031303169e-06 +-1.504577710435353542e-06 +-1.028608283527124951e-08 +1.506928969757272522e-06 +1.656256499901239233e-06 +3.579525644479939614e-07 +-1.261872342220463811e-06 +-1.701610355631484363e-06 +-5.275271344634275999e-07 +1.127198902199723192e-06 +1.738062302039671397e-06 +8.520017892937290931e-07 +-8.333539228821495243e-07 +-1.739065206108945372e-06 +-1.004291260290182602e-06 +6.744101958019806226e-07 +1.740803442299043410e-06 +1.280937036840117323e-06 +-3.385636630176459017e-07 +-1.696207774224466475e-06 +-1.400602580196387577e-06 +1.648167040171728496e-07 +1.613295641558825584e-06 +1.590472857050408798e-06 +1.850645034035481419e-07 +-1.388546378061128693e-06 +-1.656265722646537589e-06 +-3.579423946587949524e-07 +1.261757825222560384e-06 +1.727582033192779542e-06 +6.926310400115253552e-07 +-9.844404762875896280e-07 +-1.740739744440883911e-06 +-8.519585516470582605e-07 +8.332593986167771238e-07 +1.742379863835736858e-06 +1.148012931887122658e-06 +-5.090402292842649397e-07 +-1.734407858537690999e-06 +-1.280868972595230153e-06 +3.384999746174194464e-07 +1.696185029077676697e-06 +1.504623543518964511e-06 +1.028223359323060603e-08 +-1.507075600978145329e-06 +-1.590475652061203466e-06 +-1.850639222710864662e-07 +1.388557421002558836e-06 +1.701684251364760647e-06 +5.275512265607479172e-07 +-1.127286411336689808e-06 +-1.737395596505640334e-06 +-6.925970737149970458e-07 +9.843206542173732238e-07 +1.741832499020683313e-06 +1.004348077440545941e-06 +-6.744556533661682400e-07 +-1.740774003594915025e-06 +-1.147947685019042703e-06 +5.089704719231065102e-07 +1.734460067992656717e-06 +1.400663872155841370e-06 +-1.648378112527584822e-07 +-1.613128151027974754e-06 +-1.590478454220823225e-06 +-1.027735954261626783e-08 +1.506985638456615903e-06 +1.656094988251150500e-06 +3.579615998315412844e-07 +-1.261784008739208135e-06 +-1.726486447474969463e-06 +-5.275304255328125951e-07 +1.127163313841367346e-06 +1.738319230226277259e-06 +8.520030490968967593e-07 +-8.333047458639765553e-07 +-1.741716031385066482e-06 +-1.004287515401397678e-06 +6.744269820492903251e-07 +1.741063303667368066e-06 +1.280944197266247243e-06 +-3.385375740156370755e-07 +-1.696114681665394089e-06 +-1.504607320341262842e-06 +1.648247549435342491e-07 +1.613279411811395556e-06 +1.590272262240389021e-06 +1.850763445089354181e-07 +-1.388543432206800262e-06 +-1.701579535502788515e-06 +-3.579417799535259882e-07 +1.261825112859412937e-06 +1.726522186015714916e-06 +6.926298797425628815e-07 +-9.844451534597710166e-07 +-1.739154462062785886e-06 +-1.004287950956870439e-06 +8.332800073558788083e-07 +1.741705419103144528e-06 +1.148018190478056903e-06 +-5.089998106922283231e-07 +-1.734196579128229177e-06 +-1.400607469785205336e-06 +3.385147902400103756e-07 +1.696188697615942383e-06 +1.504598469109849392e-06 +1.028602692912153095e-08 +-1.507149469115720502e-06 +-1.656302740691107855e-06 +-1.850615676620913606e-07 +1.388597063993844476e-06 +1.701598914005255437e-06 +5.275488683394952047e-07 +-1.127246230087635691e-06 +-1.735630160281970369e-06 +-8.519545802429056960e-07 +9.843770273985061775e-07 +1.738994245936507767e-06 +1.004344838744613408e-06 +-6.744224451044774395e-07 +-1.741648171681971972e-06 +-1.280885326922608207e-06 +5.089825455281064240e-07 +1.734625715760534243e-06 +1.400662582495071480e-06 +-1.648427259867010545e-07 +-1.613604219551383351e-06 +-1.590309690913316708e-06 +-1.850585260142685255e-07 +1.507093017892425353e-06 +1.656433997566742238e-06 +3.579501898796839463e-07 +-1.261749084508135586e-06 +-1.724793762976749918e-06 +-6.925917484604561872e-07 +1.127192347382897711e-06 +1.734482175110829926e-06 +8.520028454191943851e-07 +-8.332712925714974420e-07 +-1.741297315315238620e-06 +-1.147961367548260921e-06 +6.744510731501280489e-07 +1.741062871064385555e-06 +1.280935962263143594e-06 +-3.385459381808079238e-07 +-1.695877980024644523e-06 +-1.504538951390613589e-06 +-1.027454453753881087e-08 +1.613311494828473454e-06 +1.590490523396869758e-06 +1.850695136122860865e-07 +-1.388564292089949174e-06 +-1.701054595687863222e-06 +-5.275258794933226751e-07 +1.261802895159962122e-06 +1.725896452052280683e-06 +6.926385417940661657e-07 +-9.843876064109259510e-07 +-1.742343816791561549e-06 +-1.004292673205916525e-06 +6.744367176308645790e-07 +1.741774388432576809e-06 +1.148021657984709214e-06 +-5.090048672716291640e-07 +-1.734424760616408426e-06 +-1.400604165194647486e-06 +1.648261974188203075e-07 +1.696104137809677338e-06 +1.504611812673658253e-06 +1.028752509823473208e-08 +-1.506835049173077311e-06 +-1.656367124297569766e-06 +-3.579465736156574359e-07 +1.388594163091088900e-06 +1.701600197062117496e-06 +5.275662193295627331e-07 +-1.127189509723428754e-06 +-1.739140251596924240e-06 +-8.519555146344949567e-07 +8.332803391730492215e-07 +1.739083119561703616e-06 +1.004355888144604765e-06 +-6.744274295560516419e-07 +-1.741157556063786170e-06 +-1.280874370092632454e-06 +3.384979849638089985e-07 +1.734512488043795267e-06 +1.400653876346155224e-06 +-1.648191437038570666e-07 +-1.613357878702286843e-06 +-1.590415680388212322e-06 +-1.850664008729975969e-07 +1.388616654257874299e-06 +1.656410100155959239e-06 +3.579718078982790880e-07 +-1.261742194831940182e-06 +-1.727519293799483035e-06 +-6.925931453648272117e-07 +9.842945020186080504e-07 +1.734544076054722863e-06 +8.520144031590257785e-07 +-8.332964747435799942e-07 +-1.742269274102159542e-06 +-1.147947761448823896e-06 +5.089688992861910061e-07 +1.741034279003410450e-06 +1.280937689492520769e-06 +-3.385423636830984105e-07 +-1.696046231791591712e-06 +-1.504618301607008335e-06 +-1.027719594533354700e-08 +1.506805351404585447e-06 +1.590436401080494455e-06 +1.851002823797434524e-07 +-1.388659116484511387e-06 +-1.701540621950765053e-06 +-5.275256108826528761e-07 +1.127166171203310547e-06 +1.725110778275020941e-06 +6.926393770930866481e-07 +-9.844323146218771484e-07 +-1.741784308782007532e-06 +-1.004286311019523964e-06 +6.744500208297343382e-07 +1.741938329515638949e-06 +1.148014876225550924e-06 +-5.089785309167015760e-07 +-1.734497322243950889e-06 +-1.400614927829939636e-06 +1.648214631468875859e-07 +1.613184576308203552e-06 +1.504606788480569668e-06 +1.027859207800901093e-08 +-1.507276578279591926e-06 +-1.656275217839760236e-06 +-3.579405943675265619e-07 +1.261816236083089866e-06 +1.700849706196831590e-06 +5.275493876965313214e-07 +-1.127198411639394720e-06 +-1.734249179605773024e-06 +-8.519561298198576426e-07 +8.332521341154560291e-07 +1.741764638932950718e-06 +1.004347431623458245e-06 +-6.744596310186115941e-07 +-1.741748314809797923e-06 +-1.280869111820689546e-06 +3.385171037921494635e-07 +1.695901592563524869e-06 +1.400678617835233387e-06 +-1.648565488028164046e-07 +-1.613561807138776761e-06 +-1.590478919667941100e-06 +-1.850638870732223280e-07 +1.388590675464703539e-06 +1.701433691138633940e-06 +3.579618944853186432e-07 +-1.261779512233267517e-06 +-1.726504418213852149e-06 +-6.925968883290548120e-07 +9.843697821249760282e-07 +1.741881945693986421e-06 +8.520030971635724024e-07 +-8.333062008962849171e-07 +-1.742331654135019675e-06 +-1.147952122313779147e-06 +5.089734434596512497e-07 +1.734662045847583257e-06 +1.280942301929910373e-06 +-3.384895853315081937e-07 +-1.696161302241622052e-06 +-1.504564104073877981e-06 +-1.027659593009093002e-08 +1.507009727967658865e-06 +1.656445198085565982e-06 +1.850641972503618116e-07 +-1.388693950052137218e-06 +-1.701040840053128679e-06 +-5.275290161123662693e-07 +1.127187285536431175e-06 +1.734723813921674311e-06 +6.926307761678843503e-07 +-9.843077859588004430e-07 +-1.739164557000898997e-06 +-1.004292273601492378e-06 +6.744365888437088794e-07 +1.742010130835613369e-06 +1.280938872272856700e-06 +-5.090256218436111423e-07 +-1.734564342862144349e-06 +-1.400616732860756689e-06 +1.648170136371230491e-07 +1.613363813253878648e-06 +1.590438272052297480e-06 +1.025305568602594536e-08 +-1.506926596493520195e-06 +-1.656431298117337317e-06 +-3.579410847930974386e-07 +1.261875034073571594e-06 +1.726397781239574585e-06 +5.275604617026915171e-07 +-1.127137339160950026e-06 +-1.739180713235708337e-06 +-8.519550466243470749e-07 +8.332820516221241366e-07 +1.741974380368915069e-06 +1.148021876526727446e-06 +-6.744862491138618203e-07 +-1.741113204422817864e-06 +-1.280873208255707068e-06 +3.385022989464865713e-07 +1.695972778829141366e-06 +1.504589322247046242e-06 +-1.648193240548547792e-07 +-1.613117730023353339e-06 +-1.590520135504460998e-06 +-1.850727975776422814e-07 +1.388654221902107873e-06 +1.701326020156905512e-06 +5.275682709626586915e-07 +-1.261947505715531078e-06 +-1.726078486393322259e-06 +-6.925948186026352393e-07 +9.843279579363112002e-07 +1.741660351150165014e-06 +1.004355483758935434e-06 +-8.333099001568666338e-07 +-1.742964785873333881e-06 +-1.147945751530698009e-06 +5.089534599001360521e-07 +1.734599858759064124e-06 +1.400664681976267818e-06 +-3.385016663087549197e-07 +-1.695870676087512766e-06 +-1.504554066993212823e-06 +-1.028948149217973521e-08 +1.507067109023507444e-06 +1.656464995976781995e-06 +3.579755870487922869e-07 +-1.388613154987747987e-06 +-1.701443479170704020e-06 +-5.275255413453798391e-07 +1.127166071302384452e-06 +1.734503200677021406e-06 +8.520142368580808288e-07 +-9.844001539690870857e-07 +-1.741656127705483338e-06 +-1.004294452983678689e-06 +6.744018012792296245e-07 +1.741914613915466185e-06 +1.280937446172547368e-06 +-3.385295895269946168e-07 +-1.734981101659022615e-06 +-1.400588052416376249e-06 +1.648316694002071529e-07 +1.613486565481482708e-06 +1.590483001996038449e-06 +1.850813389808183833e-07 +-1.507046180103455067e-06 +-1.656478180211654670e-06 +-3.579349198709450374e-07 +1.261721756539615536e-06 +1.726441261398884717e-06 +6.926417775169320062e-07 +-1.127277146577362529e-06 +-1.735176888438899801e-06 +-8.519584793928184132e-07 +8.332792681452140573e-07 +1.742157773790548184e-06 +1.148017886747695187e-06 +-5.090103794232628682e-07 +-1.741570079490782926e-06 +-1.280866889089690358e-06 +3.385394777859105416e-07 +1.696098376610258425e-06 +1.504587084259393158e-06 +1.028785662284046328e-08 +-1.613721909539123835e-06 +-1.590494503503302450e-06 +-1.850666926647154778e-07 +1.388542047507202778e-06 +1.701004739452484825e-06 +5.275550978710463273e-07 +-1.127242889265855080e-06 +-1.724557476696404319e-06 +-6.925939616939340237e-07 +9.844457602245243228e-07 +1.739765484603756400e-06 +1.004345694661083607e-06 +-6.744448456179310710e-07 +-1.741858256020505802e-06 +-1.147945817186612501e-06 +5.089811917854148751e-07 +1.734594781773205028e-06 +1.400685564424060619e-06 +-1.648459173018137831e-07 +-1.696301470419201054e-06 +-1.504565791851446476e-06 +-1.028660033549784524e-08 +1.507102629175416761e-06 +1.656165813660437616e-06 +3.579516650658177460e-07 +-1.261767226410950790e-06 +-1.701502509763890978e-06 +-5.275255364334288959e-07 +1.127258241735445696e-06 +1.738397037242816289e-06 +8.519992627385563252e-07 +-8.333155900301203234e-07 +-1.739221311409126995e-06 +-1.004289595998266989e-06 +6.743959648938684969e-07 +1.741615939271367849e-06 +1.280948672552883438e-06 +-3.385524990879865896e-07 +-1.696233800921703517e-06 +-1.400615320269782821e-06 +1.648185908126635101e-07 +1.613437983733279720e-06 +1.590376068386415433e-06 +1.850698379245635073e-07 +-1.388559203520277344e-06 +-1.656422452523023210e-06 +-3.579448456761001503e-07 +1.261793790873533917e-06 +1.724840191291488373e-06 +6.926291817612108503e-07 +-9.844155398481135369e-07 +-1.739034044670750390e-06 +-8.519585025669481418e-07 +8.332434238338562824e-07 +1.742439124717288334e-06 +1.148015029905874473e-06 +-5.090224365676433484e-07 +-1.734886862324567029e-06 +-1.280870799559112837e-06 +3.384997738350057584e-07 +1.695894495341171505e-06 +1.504610243716362610e-06 +1.028324945307817011e-08 +-1.507023215201327417e-06 +-1.590389675798358597e-06 +-1.850716221977319632e-07 +1.388596165212837243e-06 +1.701872268799283530e-06 +5.275521592616450156e-07 +-1.127213027036639802e-06 +-1.738868422425264749e-06 +-6.925967090994584708e-07 +9.843423265322836092e-07 +1.739658055559617132e-06 +1.004347820281614206e-06 +-6.744326650540783592e-07 +-1.741589486302994863e-06 +-1.147951091273796405e-06 +5.089665116460267154e-07 +1.734732998372292519e-06 +1.400646831852552351e-06 +-1.648303833899749357e-07 +-1.613310940965321688e-06 +-1.504616294783919238e-06 +-1.028165214295071204e-08 +1.506992341721636064e-06 +1.656530616962355248e-06 +3.579615973366801713e-07 +-1.261896119614707845e-06 +-1.725099656955503595e-06 +-5.275287952149862621e-07 +1.127169131548336438e-06 +1.736726332399427330e-06 +8.520031875083780306e-07 +-8.332788361584564856e-07 +-1.741739780205732736e-06 +-1.004287541940401894e-06 +6.744270469032312699e-07 +1.741887255151474092e-06 +1.280932833180469980e-06 +-3.385350963948087381e-07 +-1.695992647258216778e-06 +-1.504617839395090027e-06 +1.648217192121360978e-07 +1.613600533049282307e-06 +1.590344747451266808e-06 +1.850778758784153934e-07 +-1.388497459901435881e-06 +-1.701694326018869044e-06 +-3.579403082721944544e-07 +1.261788553692148542e-06 +1.725249752752758465e-06 +6.926305704182332962e-07 +-9.844267509989011877e-07 +-1.739205736135453973e-06 +-8.519543788221921723e-07 +8.332742280914557694e-07 +1.741817340405137131e-06 +1.148018306641354476e-06 +-5.089990489542986116e-07 +-1.734404740651791544e-06 +-1.400611542120221849e-06 +3.385030299852301277e-07 +1.696213744038989187e-06 +1.504595461529449285e-06 +1.028736312899410621e-08 +-1.507070054026904670e-06 +-1.656396408560201997e-06 +-1.850607566820000722e-07 +1.388605038353589448e-06 +1.701245856308883713e-06 +5.275505345612582854e-07 +-1.127252558694745794e-06 +-1.738070038224574988e-06 +-8.519549505936305591e-07 +9.843313317470496922e-07 +1.739225041207011783e-06 +1.004346551016468279e-06 +-6.744387716338965728e-07 +-1.740866185716938826e-06 +-1.280870248436358718e-06 +5.089666806394039543e-07 +1.734652445953194618e-06 +1.400686053030659741e-06 +-1.648523921474952950e-07 +-1.613681664011344824e-06 +-1.590316014061567975e-06 +-1.027950810415140155e-08 +1.506931218489344571e-06 +1.656346474519701670e-06 +3.579517781802106437e-07 +-1.261829655859476321e-06 +-1.727214126451728340e-06 +-6.925930708928146570e-07 +1.127135099675787796e-06 +1.739042613578682417e-06 +8.520049857849844323e-07 +-8.333550763716032250e-07 +-1.741223931084412381e-06 +-1.147960783092397317e-06 +6.744292292009189618e-07 +1.741077513878259454e-06 +1.280943363517365134e-06 +-3.385752748583262396e-07 +-1.696353572023426503e-06 +-1.504547365475786380e-06 +-1.027654991288985169e-08 +1.613222830497776154e-06 +1.590460028730889177e-06 +1.850729280492534397e-07 +-1.388806688619792916e-06 +-1.701267205312941893e-06 +-5.275260701054195476e-07 +1.261773888119183541e-06 +1.725800301839937553e-06 +6.926372703249363807e-07 +-9.844933858999205134e-07 +-1.742084440336276215e-06 +-1.004293243730852016e-06 +8.332837782442656153e-07 +1.741681429266680129e-06 +1.148018244108631514e-06 +-5.090140825880851954e-07 +-1.734648181794856410e-06 +-1.400615529873207839e-06 +1.648194043834948003e-07 +1.696085223384804340e-06 +1.504625704785217146e-06 +1.029153370613536142e-08 +-1.507118939351625321e-06 +-1.655993897924089542e-06 +-3.579469875844075512e-07 +1.388652301991538058e-06 +1.701558517642712207e-06 +5.275674631140396064e-07 +-1.127395666019526808e-06 +-1.734941680691810245e-06 +-8.519556369383823392e-07 +8.332644240114245081e-07 +1.739256246116809773e-06 +1.004353996353650715e-06 +-6.744530441635463773e-07 +-1.742187448380313789e-06 +-1.280886367995999871e-06 +3.384972043392220203e-07 +1.734506840627408643e-06 +1.400668240434210029e-06 +-1.648250127578891211e-07 +-1.613605146426856459e-06 +-1.590345985028447486e-06 +-1.850701461615776516e-07 +1.507153337590947545e-06 +1.656372251468303937e-06 +3.579702221657228762e-07 +-1.261874832669292944e-06 +-1.726027473690091609e-06 +-6.925920677498453038e-07 +9.843190773326566283e-07 +1.739058466695084452e-06 +8.520157362474218902e-07 +-8.333066511850163643e-07 +-1.742433685415770509e-06 +-1.147955603304021991e-06 +5.089720785437955275e-07 +1.741096844482296675e-06 +1.280939701917045734e-06 +-3.385226925826214097e-07 +-1.696133847163606545e-06 +-1.504574588735058261e-06 +-1.027584873402550068e-08 +1.506900793475349959e-06 +1.590413619220728538e-06 +1.850912530880386366e-07 +-1.388642336697858351e-06 +-1.701249147872202525e-06 +-5.275242307718781953e-07 +1.127191767414049902e-06 +1.726028621147986852e-06 +6.926392242527476744e-07 +-9.844647089534297558e-07 +-1.739939757177752584e-06 +-1.004288355418123485e-06 +6.744529207682478307e-07 +1.742380102408182492e-06 +1.148016912806621430e-06 +-5.089940474249223597e-07 +-1.734603309747968123e-06 +-1.400616570006886963e-06 +1.648218615872110605e-07 +1.613295571530132512e-06 +1.504603161806901259e-06 +1.029429429793979145e-08 +-1.506989540017813416e-06 +-1.656398114490014354e-06 +-3.579385752429690782e-07 +1.261835544753514274e-06 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 diff --git a/tst/regression/linear_modes.py b/tst/regression/linear_modes.py index 6a92f593..7ee968ec 100755 --- a/tst/regression/linear_modes.py +++ b/tst/regression/linear_modes.py @@ -21,6 +21,7 @@ parser = argparse.ArgumentParser(description='Run a linear mode as a test') parser.add_argument('--upgold', dest='upgold', action='store_true') parser.add_argument('--use_gpu', dest='use_gpu', action='store_true') +parser.add_argument('--use_mpiexec', dest='use_mpiexec', action='store_true') parser.add_argument('--input', type=str, default=os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../inputs/linear_modes.pin')) parser.add_argument('--executable', type=str, default=None) parser.add_argument('--build_type', type=str, default='Release', choices=['Debug, Release']) @@ -38,6 +39,7 @@ executable=args.executable, geometry='Minkowski', use_gpu=args.use_gpu, + use_mpiexec=args.use_mpiexec, build_type=args.build_type, upgold=args.upgold, compression_factor=10) diff --git a/tst/regression/mocmc_diffusion.gold b/tst/regression/mocmc_diffusion.gold index 2c3e570a..c781a305 100644 --- a/tst/regression/mocmc_diffusion.gold +++ b/tst/regression/mocmc_diffusion.gold @@ -1,76 +1,25 @@ -1.107667635301233942e-06 -8.678469590435074669e-11 -9.971481965236875367e-11 -9.639947382410148605e-09 -1.268340826133416413e-03 -6.562967553167058377e-01 -4.470716447853096201e-04 -9.999999999999995194e-11 -9.999999999999995194e-11 -2.334632208492531946e-02 -7.622557034077365179e-02 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -1.495235949844014333e-05 -9.927199198898888355e-01 -5.498364121645113345e-07 -9.999999999999995194e-11 -9.999999999999995194e-11 -5.716019338297739566e-04 --2.825591164626063668e-04 --2.420653647569474473e-02 --2.049083258733951779e-02 --7.560785253149245912e-03 -2.678448152425867007e-02 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.090170239953292955e-16 -1.717855834510626225e-16 -8.487991656731448068e-17 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.358067774462864810e-16 -6.886394415575321099e-17 -0.000000000000000000e+00 -1.232937520260024407e-16 -1.232937520260024407e-16 -4.909950132900829226e-19 --2.081219149297657992e-18 --3.534472263881267203e-18 -3.058232911759794560e-19 --6.143732111690850347e-19 --2.095180251051548739e-18 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -3.720535392342713946e-18 -4.275850048651767063e-18 --5.382624650889726464e-19 --7.417127987768036823e-20 -4.497843815824792516e-18 --1.111063243719671523e-18 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 +2.578814481287522261e-07 +8.539726882840010634e-11 +9.881445129638454866e-11 +2.880460357023297414e-08 +2.198153555894490595e-03 +6.512936231879706828e-01 +1.589897079949697579e-04 +2.487714603862677815e-02 +2.197674042014615206e-02 +1.033579527379025267e-02 +2.531893588544332965e-03 +1.082843017130332049e-02 +4.744884338522545320e-02 +4.023157107288660425e-18 +5.334164668525514679e-19 +-9.664413533137839830e-18 +-2.005083506756888166e-19 +3.571266278200496982e-20 +3.223146623850273342e-18 +3.207972302156737700e-18 +-1.679074899601851184e-18 +5.418718223120794605e-19 +-6.520174545248790648e-18 +-3.870719990762739149e-19 +7.706258448627096981e-20 diff --git a/tst/regression/mocmc_diffusion.py b/tst/regression/mocmc_diffusion.py index c17d28c8..b17fc63a 100755 --- a/tst/regression/mocmc_diffusion.py +++ b/tst/regression/mocmc_diffusion.py @@ -21,6 +21,7 @@ parser = argparse.ArgumentParser(description='Run a finite velocity radiation diffusion test') parser.add_argument('--upgold', dest='upgold', action='store_true') parser.add_argument('--use_gpu', dest='use_gpu', action='store_true') +parser.add_argument('--use_mpiexec', dest='use_mpiexec', action='store_true') parser.add_argument('--input', type=str, default=os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../inputs/radiation_advection.pin')) parser.add_argument('--executable', type=str, default=None) parser.add_argument('--build_type', type=str, default='Release', choices=['Debug, Release']) @@ -50,6 +51,7 @@ executable=args.executable, geometry='Minkowski', use_gpu=args.use_gpu, + use_mpiexec=args.use_mpiexec, build_type=args.build_type, upgold=args.upgold, compression_factor=10) diff --git a/tst/regression/mocmc_equilibration.gold b/tst/regression/mocmc_equilibration.gold index c9dff0d1..50c369f2 100644 --- a/tst/regression/mocmc_equilibration.gold +++ b/tst/regression/mocmc_equilibration.gold @@ -1,48 +1,16 @@ -7.698791973673840827e-01 -7.698791973673841937e-01 -7.698791973673841937e-01 -7.698791973673841937e-01 -4.284275586993940603e-06 -4.284275586993940603e-06 -4.284275586993940603e-06 -4.284275586993940603e-06 -4.284275586993940603e-06 -4.284275586993940603e-06 -4.284275586993940603e-06 -4.284275586993940603e-06 --5.762953094575590744e-17 -5.498122101827441854e-19 -2.777543941330130466e-17 -4.294387260632054687e-17 -1.067556358522548975e-17 --1.336966267211103380e-18 --1.199923993368624513e-17 --6.229729789468637579e-19 -1.067556358522548975e-17 --1.336966267211103380e-18 --1.199923993368624513e-17 --6.229729789468637579e-19 --5.517577778551251501e-18 --2.538214576051772947e-18 -3.049304360568872501e-18 --1.552656291095903384e-18 -9.387642492333292603e-22 -6.986267570443693290e-20 -1.312427541847825429e-19 -8.925212202882793537e-20 -9.387642492333292603e-22 -6.986267570443693290e-20 -1.312427541847825429e-19 -8.925212202882793537e-20 --3.192727491011909151e-18 -1.653363882546770656e-18 --4.038102919687933026e-19 -3.615790116856251509e-18 -1.517984834423053999e-19 -2.839068997223774963e-19 --1.527350036312204870e-19 --2.617359030719125647e-19 -1.517984834423053999e-19 -2.839068997223774963e-19 --1.527350036312204870e-19 --2.617359030719125647e-19 +7.782239480291789357e-01 +7.782239480291789357e-01 +7.782239480291788247e-01 +7.782239480291789357e-01 +-3.319442647366402016e-17 +-2.641239402025653325e-17 +1.803654437194548050e-17 +5.094346950324803810e-17 +-1.430155146108605356e-18 +-6.894023125021501989e-18 +-5.658156072167891793e-18 +4.106285280551914311e-18 +1.742030982911749756e-19 +1.424440983663824178e-18 +5.480844936769992495e-18 +1.804352161149941056e-18 diff --git a/tst/regression/mocmc_equilibration.py b/tst/regression/mocmc_equilibration.py index 027a6906..db2f5414 100755 --- a/tst/regression/mocmc_equilibration.py +++ b/tst/regression/mocmc_equilibration.py @@ -21,6 +21,7 @@ parser = argparse.ArgumentParser(description='Run a uniform radiation equilibration test') parser.add_argument('--upgold', dest='upgold', action='store_true') parser.add_argument('--use_gpu', dest='use_gpu', action='store_true') +parser.add_argument('--use_mpiexec', dest='use_mpiexec', action='store_true') parser.add_argument('--input', type=str, default=os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../inputs/radiation_equilibration.pin')) parser.add_argument('--executable', type=str, default=None) parser.add_argument('--build_type', type=str, default='Release', choices=['Debug, Release']) @@ -42,6 +43,7 @@ executable=args.executable, geometry='Minkowski', use_gpu=args.use_gpu, + use_mpiexec=args.use_mpiexec, build_type=args.build_type, upgold=args.upgold, compression_factor=1) diff --git a/tst/regression/radiation_diffusion.gold b/tst/regression/radiation_diffusion.gold index f15ca816..491e1857 100644 --- a/tst/regression/radiation_diffusion.gold +++ b/tst/regression/radiation_diffusion.gold @@ -1,614 +1,204 @@ -6.590802047219230527e-07 -2.895726903543413000e-08 -1.082059331377261301e-09 -1.132501352946665660e-10 -9.695487468326294212e-11 -9.696861685650317468e-11 -9.697024162538643100e-11 -9.697023158510526264e-11 -9.697017471767806751e-11 -9.697008114020457140e-11 -9.697172886792639668e-11 -9.698884721451962999e-11 -9.707255147494808234e-11 -9.733208120800911255e-11 -9.788416708374486100e-11 -9.868367189115946074e-11 -9.942945540692541627e-11 -9.984733968844056005e-11 -9.997784286517222481e-11 -9.999853714432487629e-11 -9.999996951220606026e-11 -9.999999995658193953e-11 -1.000000000101677207e-10 -1.000000035076977904e-10 -1.000005177660854903e-10 -1.000403315986682734e-10 -1.019354033664554237e-10 -1.642564908385391851e-10 -1.710988235070783498e-09 -3.159525526764937289e-08 -4.830255439560780466e-07 -5.830768036751755110e-06 -5.551628690768006997e-05 -4.171315357356847656e-04 -2.473941067088241980e-03 -1.158069051036157010e-02 -4.276938268100800855e-02 -1.245288648986814239e-01 -2.855558019910507395e-01 -5.149781892849423226e-01 -7.290614244568736080e-01 -8.069267078160836659e-01 -6.995883024470237466e-01 -4.718216504556480562e-01 -2.468297603442667909e-01 -9.972827668512493360e-02 -3.096029982750925572e-02 -7.340255310971256081e-03 -1.319485015356200702e-03 -1.783007313164483413e-04 -1.792503907970291230e-05 -1.283328363396617389e-06 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -2.834367163623160653e-10 -1.311837918196246202e-08 -4.258695418886732627e-07 -9.658469508983062916e-06 -1.524095442615976744e-04 -1.666472719181591022e-03 -1.257330059604601542e-02 -6.518092929800380075e-02 -2.311738993932118125e-01 -5.584728660685404078e-01 -9.149114013495547315e-01 -1.011831977976676455e+00 -7.519662568863217933e-01 -3.737885289234215147e-01 -1.236905710058610469e-01 -2.711709850761196555e-02 -3.919456421830514077e-03 -3.716471517466445073e-04 -2.300224141827204906e-05 -9.245297999283187748e-07 -2.400625424148625927e-08 -4.005765425711561238e-10 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -1.261940887654029262e-10 -6.267039777250052688e-09 -2.184753861023164977e-07 -5.325095401838725881e-06 -9.038141835017141394e-05 -1.063832493428873947e-03 -8.647648482836766196e-03 -4.834083919818173841e-02 -1.850351616039731806e-01 -4.828609632450478473e-01 -8.552483764030662794e-01 -1.023551028711331412e+00 -8.239259143820713005e-01 -4.440292650055747137e-01 -1.594525739303113698e-01 -3.797235161897568462e-02 -5.967688164117255882e-03 -6.158863091513743730e-04 -4.153074579718389457e-05 -1.820529609118573093e-06 -5.160991217103456228e-08 -9.412133726191222586e-10 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -9.999999999999995194e-11 -4.892826835578330952e-02 -5.371437413232456326e-02 -4.386246293637343502e-02 -1.772648356150767881e-03 --5.287096583227925291e-06 --1.615498228363867525e-07 -1.421858367528866852e-09 -8.144788051238867322e-09 -2.400804246495652077e-08 --1.508465410368909087e-07 --2.209989286913192900e-06 --1.220954465140679777e-05 --4.075085662460314163e-05 --9.165121638267280043e-05 --1.391153066049254344e-04 --1.345389071825166261e-04 --7.683500104356228257e-05 --2.383488415478195643e-05 --3.605673454589700634e-06 --2.217319372391007247e-07 --3.427148591266687960e-09 --2.230445621057478629e-12 --1.184214293932077303e-10 --2.440402206927628208e-08 --2.391696713424233643e-06 --1.341695781149990782e-04 --4.594714061615178848e-03 --3.912794327056327848e-02 --5.021486642309502813e-02 --4.700714502997708349e-02 --4.302405463103554234e-02 --3.900283430891650360e-02 --3.497178836767270843e-02 --3.093001428467637495e-02 --2.687547120789864422e-02 --2.280600549242635389e-02 --1.871941517757406623e-02 --1.461349001237759876e-02 --1.048564467726495648e-02 --6.331835962768793576e-03 --2.146103806865463665e-03 -2.065739968495666507e-03 -6.324992781800572832e-03 -1.062440424004904710e-02 -1.497148085889632094e-02 -1.937443644120311059e-02 -2.384302375758504122e-02 -2.838868513387808601e-02 -3.302581563786338020e-02 -3.777307488446960543e-02 -4.265565820368213273e-02 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -2.158506422854103140e-16 -1.719030325363644554e-16 -1.303292293441791604e-16 -1.593747140547621655e-16 -6.234837145105545280e-17 -1.586662998989982662e-16 -6.512853585570631863e-17 --5.846216254346590063e-17 -1.536804884603564561e-16 -1.485342304936081630e-16 -1.060404540227259763e-16 -2.246918037525050074e-16 -0.000000000000000000e+00 -1.574453339374590153e-16 -9.344094994858259823e-17 -6.290048079562879820e-17 -6.435052186281657839e-17 -1.005538873763623526e-16 -1.206052547103363822e-16 -1.674104628043279761e-16 -8.010273590271059107e-17 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.571268584378664751e-16 -1.165853955035590820e-16 -1.851407970437848187e-16 -1.871943719176715004e-16 -1.020935785211542690e-16 -2.412705772672882698e-16 -9.189026113987148258e-17 -1.529354115900700122e-16 -9.309314575065510278e-17 -1.665314350520613726e-16 -1.099235919757483238e-16 -1.075793956879619842e-16 -7.841132255838816570e-17 -1.710523961390401574e-16 -1.402656532828927073e-16 -8.688981261590935631e-17 -1.634437801218010695e-16 -0.000000000000000000e+00 -1.935847310469869844e-16 -1.641866980051309727e-16 -2.157785107307271072e-16 -2.208789095374280884e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -1.232937520260024407e-16 -5.198681906648446405e-23 -4.073863901085789319e-22 --2.663221399877816108e-22 -2.425088292989806806e-22 -1.844756802338523839e-22 -9.940728546961471774e-24 -9.790003893554628855e-23 -8.426128350091030883e-23 -2.779644958799751976e-22 -5.934868693567515469e-23 --1.901765502930479800e-23 -6.045857045948731889e-24 -2.525784463574456095e-22 -1.009672308266028149e-22 -1.730875855981527555e-22 -1.054842659734705212e-22 --4.232278809032752689e-23 -1.418105347821328126e-22 --1.366101847231823538e-23 -4.123964092325017352e-24 --3.365298343973154912e-22 -2.186197515234779752e-22 --1.409659959461806736e-22 --8.285369093972993350e-23 --9.540617698584953110e-24 --2.663465613733615777e-23 -4.286010137540330402e-22 --2.972965450436250952e-22 --3.640344994718869664e-23 -3.656402322960056716e-22 -6.502138106893311429e-23 -5.624668111728423775e-23 -1.721594482652187220e-23 -7.958760550504436329e-23 --3.485023778530299852e-22 --1.354019678333328615e-22 -3.484949732972849812e-23 --1.222906511020615734e-22 --5.144424531307829736e-23 --2.993924701204381969e-22 -2.299459842250667159e-22 -1.221162717285059325e-22 --5.633591648544763567e-22 -2.944601823537548699e-22 --1.787140162117773112e-22 --3.446024865095947392e-22 -4.032655989318169633e-24 -1.447391148380846452e-22 -5.721573344323661590e-23 --8.064556138814519883e-23 --3.152326102122695254e-22 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -9.973575939347133548e-23 --6.289222750991511454e-24 --1.625013294514567333e-22 --1.614075328269213537e-22 -8.825554158928354559e-23 -1.217576549779483440e-22 --7.158101720270305163e-23 -3.397447773619363125e-23 --1.237266003168271106e-22 -2.734560755065920225e-22 --3.086508804128979297e-22 -1.505468703594889385e-23 --5.354291946503867914e-24 -1.365502102257285093e-22 -9.864496779636868673e-23 --1.063264658829741765e-22 -4.420359756789446085e-23 --5.713578239633000657e-23 -1.374381778212612983e-22 --9.619429798459198153e-24 -2.812487716599325878e-23 --7.438899032036293516e-23 --4.669761817446118159e-25 --1.625786760816277499e-22 --3.031505046408947564e-22 --2.670724126389504376e-22 --1.957305302833232392e-22 --5.143717086967088413e-22 -5.936920905781148775e-23 --4.565483381518469957e-22 --2.606342430665272871e-23 --3.094096768850477535e-22 --3.928135970338702462e-23 --1.381324794439877811e-22 -2.193332328585047323e-22 --3.093800916139826000e-22 -1.329677683123175938e-23 -7.634095794705736673e-23 -4.095824846165767872e-22 --4.810478280618034505e-23 --2.109857318722960927e-22 -1.832673134707372580e-22 -2.070389066611084849e-22 -3.853705298230872663e-22 --1.220519313120750839e-22 -6.068291725073441928e-23 -4.339619733486351951e-23 -2.329063949748066536e-22 --5.439911146256075425e-23 -9.166663631202754951e-23 -2.007137947439320034e-22 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 +5.727756994965741107e-07 +2.390134319486193814e-08 +8.552041533534603929e-10 +1.078296430112438255e-10 +9.711876459274814704e-11 +9.713910069953824051e-11 +9.714019477587792320e-11 +9.714018556719315477e-11 +9.714013583064870344e-11 +9.714004143906464299e-11 +9.714136057593579443e-11 +9.715605647034080452e-11 +9.723061089041014331e-11 +9.746785021414432990e-11 +9.798169248803661456e-11 +9.873601435495406986e-11 +9.944825354323748637e-11 +9.985170078244693900e-11 +9.997856789721988854e-11 +9.999862401572627799e-11 +9.999997429126054452e-11 +9.999999997608928821e-11 +1.000000000145483658e-10 +1.000000045740659748e-10 +1.000006404787214849e-10 +1.000486007678750447e-10 +1.023092093125954396e-10 +1.757621936255252641e-10 +1.941590168349629347e-09 +3.504491520959139734e-08 +5.225935904712614139e-07 +6.176559144957394034e-06 +5.779425074201656898e-05 +4.282440483189258341e-04 +2.512772859434292752e-03 +1.167086067769809547e-02 +4.287634506986493649e-02 +1.244570709266686059e-01 +2.850180079099509656e-01 +5.140050326773016875e-01 +7.282509198683039253e-01 +8.067801476054498044e-01 +6.998498162483933749e-01 +4.717382893901957419e-01 +2.462135553878652960e-01 +9.900483254205033612e-02 +3.049183983645776391e-02 +7.143371984330685459e-03 +1.262702652840828584e-03 +1.668041847985371744e-04 +1.627808859937458411e-05 +1.123635279827189608e-06 +5.016698617450413011e-02 +5.311995564210914705e-02 +1.680911903892173126e-02 +2.685308764014417737e-05 +-2.355360567424356871e-06 +-2.278357952927824541e-09 +2.666990782156583800e-09 +1.268488380862240013e-08 +1.269934983023156121e-08 +-4.400954823020613186e-07 +-4.079477796912064746e-06 +-1.864875973507270276e-05 +-5.415651297234061804e-05 +-1.063016992923664149e-04 +-1.377446224131152167e-04 +-1.102671082456366903e-04 +-5.036791500535578632e-05 +-1.194434774016882478e-05 +-1.280766957280250141e-06 +-4.683094165951429397e-08 +-1.484523971368724864e-10 +-4.421683828727284305e-12 +-1.451083907244640042e-09 +-2.046534387257917219e-07 +-1.533153330580197809e-05 +-7.046323563659109140e-04 +-1.645589022743774305e-02 +-4.965832613189432448e-02 +-5.020480634544629422e-02 +-4.626722341124878124e-02 +-4.213012095570779075e-02 +-3.798606919926614950e-02 +-3.384163722145845654e-02 +-2.969559488533472791e-02 +-2.554636732861058357e-02 +-2.139230530721048310e-02 +-1.723174961639093936e-02 +-1.306297343227217148e-02 +-8.883500610029093983e-03 +-4.689001102128412431e-03 +-2.397992361796622116e-04 +3.754639271729428174e-03 +8.014743424946998984e-03 +1.230509638607602159e-02 +1.663267006808126849e-02 +2.100717937714598194e-02 +2.543980051006095033e-02 +2.994404537918130688e-02 +3.453717733249576233e-02 +3.924181203534789220e-02 +4.407161256738487826e-02 +-2.401333176974653320e-22 +3.098535732814056733e-23 +7.863337070088176244e-23 +5.283802366595079944e-23 +-6.944684327132200223e-23 +-2.218499460327680794e-22 +-1.996714926280015180e-22 +-1.075607772514589342e-22 +-2.373814146831378406e-22 +-1.339305197413000030e-22 +-4.261670326149361140e-23 +1.620593766970830532e-22 +-2.497738224454524445e-22 +-1.305236417127731090e-22 +-2.381880695098998261e-22 +-3.165778036229801105e-23 +2.724707692538124307e-22 +5.979002565080849839e-23 +-8.860804698436186775e-24 +-2.650716423850867457e-22 +1.199032518964721064e-22 +-6.382709326488530058e-23 +3.798506326691394817e-22 +8.481224383324701134e-23 +1.219331301977731060e-23 +-1.134705989638526051e-22 +-1.506540697866051409e-22 +-3.079155556072635552e-22 +1.236398494587647572e-22 +2.789631629251780663e-23 +-2.842561281782300470e-22 +-2.265480122597969408e-22 +-1.329643378655957358e-22 +-2.396580222080832166e-22 +-1.837849235199753693e-22 +2.255390206753711147e-22 +-8.226186850613797959e-23 +-2.846846672823250557e-23 +7.089985944641566405e-23 +-2.013050774325366637e-23 +8.943202787078291817e-23 +1.136969106268601348e-22 +-4.817731346778944567e-22 +-2.854081727522716353e-22 +-4.825227776047941744e-22 +8.399482467781627927e-23 +-1.919629861503503608e-23 +-1.479616696728036012e-22 +1.104531983232182453e-22 +-2.000684336265987235e-23 +-2.704462936173801199e-22 +-8.616841280284873567e-24 +3.061167519508874604e-22 +1.230647568630916241e-22 +9.637374046679052283e-23 +3.343319228661788036e-22 +-2.675319232018354831e-22 +-1.303341573371865335e-22 +-3.340263019659249304e-22 +-1.637915657594944520e-22 +-6.645766458852628434e-23 +-6.049180879669107083e-23 +-1.646484833776144565e-22 +-8.927076239295978461e-23 +-3.168643959137814685e-23 +-2.716954332797437559e-22 +-1.622732947265936234e-22 +3.099550491478542655e-23 +9.272987334760096538e-23 +-8.751925105159440267e-23 +1.827705100817865104e-22 +1.044786457838318912e-22 +3.081723926594299342e-23 +2.283374966500224249e-22 +-2.749710018637551029e-22 +1.090861488926846408e-22 +1.778860915443959508e-22 +-8.855784712273776874e-23 +1.237408500447430053e-22 +6.844515083603637562e-23 +7.870956770838802636e-22 +-8.478381197121709938e-23 +1.958042142012662267e-22 +4.338380747060757127e-22 +8.324137401675781494e-23 +1.433035169058252973e-22 +2.964266411938769243e-23 +2.009833323147422772e-23 +8.253686730879343963e-23 +-2.025902846018915908e-22 +-2.218469230811688183e-24 +2.146603178305245965e-22 +-1.653333771085185817e-22 +-7.915970538461456024e-23 +2.701083395015952865e-22 +-1.772110543039980272e-22 +4.570069463935689368e-23 +4.864434859605115226e-23 +1.932109968022707632e-22 +1.500202169723187240e-22 +-2.202213269512400579e-22 diff --git a/tst/regression/radiation_diffusion.py b/tst/regression/radiation_diffusion.py index 2df7e94d..75171778 100755 --- a/tst/regression/radiation_diffusion.py +++ b/tst/regression/radiation_diffusion.py @@ -21,6 +21,7 @@ parser = argparse.ArgumentParser(description='Run a finite velocity radiation diffusion test') parser.add_argument('--upgold', dest='upgold', action='store_true') parser.add_argument('--use_gpu', dest='use_gpu', action='store_true') +parser.add_argument('--use_mpiexec', dest='use_mpiexec', action='store_true') parser.add_argument('--input', type=str, default=os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../inputs/radiation_advection.pin')) parser.add_argument('--executable', type=str, default=None) parser.add_argument('--build_type', type=str, default='Release', choices=['Debug, Release']) @@ -45,6 +46,7 @@ executable=args.executable, geometry='Minkowski', use_gpu=args.use_gpu, + use_mpiexec=args.use_mpiexec, build_type=args.build_type, upgold=args.upgold, compression_factor=10) diff --git a/tst/regression/radiation_equilibration.gold b/tst/regression/radiation_equilibration.gold index 1660ae7a..c760e2a3 100644 --- a/tst/regression/radiation_equilibration.gold +++ b/tst/regression/radiation_equilibration.gold @@ -1,39 +1,7 @@ -7.698791973673840827e-01 -7.698791973673840827e-01 -7.698791973673840827e-01 -7.698791973673840827e-01 -4.284275586993940603e-06 -4.284275586993940603e-06 -4.284275586993940603e-06 -4.284275586993940603e-06 -4.284275586993940603e-06 -4.284275586993940603e-06 -4.284275586993940603e-06 -4.284275586993940603e-06 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 +7.590477907760553311e-01 +7.590477907760553311e-01 +7.590477907760553311e-01 +7.590477907760553311e-01 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 diff --git a/tst/regression/radiation_equilibration.py b/tst/regression/radiation_equilibration.py index e5c0c021..1fc15aeb 100755 --- a/tst/regression/radiation_equilibration.py +++ b/tst/regression/radiation_equilibration.py @@ -21,6 +21,7 @@ parser = argparse.ArgumentParser(description='Run a uniform radiation equilibration test') parser.add_argument('--upgold', dest='upgold', action='store_true') parser.add_argument('--use_gpu', dest='use_gpu', action='store_true') +parser.add_argument('--use_mpiexec', dest='use_mpiexec', action='store_true') parser.add_argument('--input', type=str, default=os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../inputs/radiation_equilibration.pin')) parser.add_argument('--executable', type=str, default=None) parser.add_argument('--build_type', type=str, default='Release', choices=['Debug, Release']) @@ -38,6 +39,7 @@ executable=args.executable, geometry='Minkowski', use_gpu=args.use_gpu, + use_mpiexec=args.use_mpiexec, build_type=args.build_type, upgold=args.upgold, compression_factor=1) diff --git a/tst/regression/regression_test.py b/tst/regression/regression_test.py index a28813ea..eca8fd50 100644 --- a/tst/regression/regression_test.py +++ b/tst/regression/regression_test.py @@ -189,8 +189,8 @@ def cleanup(): # -- Run test problem with previously built code, input file, and modified inputs, and compare # to gold output def gold_comparison(variables, input_file, modified_inputs={}, - executable=None, geometry='Minkowski', use_gpu=False, build_type='Release', - upgold=False, compression_factor=1, tolerance=1.e-5): + executable=None, geometry='Minkowski', use_gpu=False, use_mpiexec=False, + build_type='Release', upgold=False, compression_factor=1, tolerance=1.e-5): if executable is None: executable = os.path.join(BUILD_DIR, 'src', 'phoebus') @@ -208,10 +208,13 @@ def gold_comparison(variables, input_file, modified_inputs={}, modify_input(key, modified_inputs[key], TEMPORARY_INPUT_FILE) # Run test problem + preamble = [] + if use_mpiexec: + preamble = preamble + ['mpiexec', '-n', '1'] if os.path.isabs(executable): - call([executable, '-i', TEMPORARY_INPUT_FILE]) + call(preamble + [executable, '-i', TEMPORARY_INPUT_FILE]) else: - call([os.path.join('..', executable), '-i', TEMPORARY_INPUT_FILE]) + call(preamble + [os.path.join('..', executable), '-i', TEMPORARY_INPUT_FILE]) # Get last dump file dumpfiles = np.sort(glob.glob('*.phdf')) @@ -250,7 +253,7 @@ def gold_comparison(variables, input_file, modified_inputs={}, success = False else: for n in range(len(gold_variables)): - if not soft_equiv(variables_data[n], gold_variables[n]): + if not soft_equiv(variables_data[n], gold_variables[n], tol=tolerance): success = False cleanup() diff --git a/tst/regression/thincooling.py b/tst/regression/thincooling.py index 81b6718d..7da11bd8 100755 --- a/tst/regression/thincooling.py +++ b/tst/regression/thincooling.py @@ -21,6 +21,7 @@ parser = argparse.ArgumentParser(description='Run optically thin cooling as a test') parser.add_argument('--upgold', dest='upgold', action='store_true') parser.add_argument('--use_gpu', dest='use_gpu', action='store_true') +parser.add_argument('--use_mpiexec', dest='use_mpiexec', action='store_true') parser.add_argument('--input', type=str, default=os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', 'inputs/thincooling.pin')) parser.add_argument('--executable', type=str, default=None) parser.add_argument('--build_type', type=str, default='Release', choices=['Debug', 'Release']) @@ -35,7 +36,9 @@ executable=args.executable, geometry='Minkowski', use_gpu=args.use_gpu, + use_mpiexec=args.use_mpiexec, build_type=args.build_type, - upgold=args.upgold) + upgold=args.upgold, + tolerance=1.e-2) sys.exit(code) diff --git a/tst/regression/thincooling_coolingfunction.py b/tst/regression/thincooling_coolingfunction.py index b1e42ed9..083f86de 100755 --- a/tst/regression/thincooling_coolingfunction.py +++ b/tst/regression/thincooling_coolingfunction.py @@ -21,6 +21,7 @@ parser = argparse.ArgumentParser(description='Run optically thin cooling as a test') parser.add_argument('--upgold', dest='upgold', action='store_true') parser.add_argument('--use_gpu', dest='use_gpu', action='store_true') +parser.add_argument('--use_mpiexec', dest='use_mpiexec', action='store_true') parser.add_argument('--input', type=str, default=os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../inputs/thincooling.pin')) parser.add_argument('--executable', type=str, default=None) parser.add_argument('--build_type', type=str, default='Release', choices=['Debug', 'Release']) @@ -35,6 +36,7 @@ executable=args.executable, geometry='Minkowski', use_gpu=args.use_gpu, + use_mpiexec=args.use_mpiexec, build_type=args.build_type, upgold=args.upgold) diff --git a/tst/unit/radiation/test_closure.cpp b/tst/unit/radiation/test_closure.cpp index dce792b3..64754753 100644 --- a/tst/unit/radiation/test_closure.cpp +++ b/tst/unit/radiation/test_closure.cpp @@ -64,7 +64,7 @@ TEST_CASE("M1 Closure", "[radiation][closure]") { Vec con_v = {vmag * cos(phiv), vmag * sin(phiv), 0.0}; Tens2 cov_gamma = {{{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}}}; LocalThreeGeometry g(cov_gamma); - ClosureM1 cl(con_v, &g); + ClosureM1<> cl(con_v, &g); // Assume a fluid frame state Real J = 1.0; @@ -75,7 +75,7 @@ TEST_CASE("M1 Closure", "[radiation][closure]") { // Calculate comoving frame state Real E; Vec F; - cl.GetCovTilPiFromPrim(J, cov_tilH, &con_tilPi); + cl.GetConTilPiFromPrim(J, cov_tilH, &con_tilPi); cl.Prim2Con(J, cov_tilH, con_tilPi, &E, &F); // re-Calculate rest frame quantities using closure @@ -85,7 +85,7 @@ TEST_CASE("M1 Closure", "[radiation][closure]") { Real xig, phig; cl.GetM1GuessesFromEddington(E, F, &xig, &phig); - cl.GetCovTilPiFromCon(E, F, xig, phig, &con_tilPi); + cl.GetConTilPiFromCon(E, F, xig, phig, &con_tilPi); cl.Con2Prim(E, F, con_tilPi, &J_out, &H_out); // if (result.status == radiation::Status::failure) throw 2;