I would like to write a FITS file out of an off-axis projection along some given direction of a field ("i_nu") which I create as a derived field. However, the parameters I set in the main Python program (pl_inu.py) using set_field_parameter() are not passed down to the derived field i_nu. Here is the main macro I am using:
""" pl_inu.py """
import numpy as np
import yt
from yt.utilities.cosmology import Cosmology
from yt import derived_field
import matplotlib.pyplot as plt
from yt.fields.api import ValidateParameter
from bckfl_fns import b_p,_e_dens, e_dens, _chi_nu,_kappa, f_kappa, _i_nu, f_chi_nu, los_unit_vector, proj_dist
from yt import YTArray, YTQuantity
float_formatter = "{:.3f}".format
cosmo = Cosmology()
LFLY = YTArray(1.0/cosmo.hubble_constant.value,"Mpc").in_cgs()
TFLY = (2./3./cosmo.hubble_constant).in_cgs()
MFLY = YTArray(5.23e12/cosmo.hubble_constant.value,"Msun").in_cgs()
uo = {"length_unit":LFLY, "time_unit":TFLY, "mass_unit":MFLY}
fname = 'virgoS12_str_hdf5_plt_cnt_0015'
ds=yt.load(fname,units_override=uo)
dd=ds.all_data()
ds.add_field(("gas", "n_e"), function=_e_dens, units="cm**(-3)", sampling_type='cell', display_name="Electron density", force_override=True)
ds.add_field(("gas", "kappa"), function=_kappa, units="kpc**(-1)", sampling_type='cell', display_name="N(E) norm coeff", force_override=True)
ds.add_field(("gas", "chi_nu"), function=_chi_nu, units="kpc**(-1)", sampling_type='cell', display_name="synchr. abs. coeff.", force_override=True)
ds.add_field(("gas", "i_nu"), function=_i_nu, units="W/(m**2)/Hz", sampling_type='cell', display_name="Synchr. emission", force_override=True, validators=[ValidateParameter(["lmin","l.o.s.","lmin origin","Background I_nu","Magnetic field","Electron p-law index","b(p)","nu (Ghz)"])])
# Output time (in Myr)
#
co = Cosmology()
time = ds.parameters.get('time')*co.t_from_z(0.).in_units("Myr")
p = 5./2.
E_min = 1.5
E_max = 2.e1
bm4 = 0.01
nu = 1.5
dd.set_field_parameter("Magnetic field", bm4)
dd.set_field_parameter("Electron p-law index",p)
dd.set_field_parameter("1-p", (1-p))
dd.set_field_parameter("b(p)",b_p(p))
dd.set_field_parameter('E_min', E_min)
dd.set_field_parameter('E_max', E_max)
dd.set_field_parameter("nu (Ghz)", nu)
eul_angles_deg=np.array([4.,22.])
n_dir = los_unit_vector(eul_angles_deg)
pos_0 = YTArray([0.,0,-130],'kpc')
grid_pos=YTArray([dd['gas','x'],dd['gas','y'],dd['gas','z']]).in_units('kpc')
lmin = np.amin(proj_dist(n_dir,grid_pos,pos_0))
i_nu_lmin = YTQuantity(1.e-27,'W/(m**2)/Hz')
dd.set_field_parameter('Background I_nu', i_nu_lmin)
dd.set_field_parameter("lmin", lmin)
dd.set_field_parameter("l.o.s.", n_dir)
dd.set_field_parameter('lmin origin', pos_0)
dd.set_field_parameter('grid pos', grid_pos)
synchr_fits=yt.FITSOffAxisSlice(ds,n_dir,("gas", "i_nu"), width=((50,'kpc')))
fits_name = 'i_nu_r0000_15.fits'
synchr_fits.writeto(fits_name, overwrite='True')
====
and this is the collection of functions I use to create the field "i_nu":
""" bckfl_fns.py """
import sys
import yt
import numpy as np
import global_vars
from yt import derived_field
from yt import YTArray, YTQuantity
from yt.fields.api import ValidateParameter
""" Derived fields in yt-FLASH """
def _kappa(field, data):
import math
from yt import YTQuantity
if data.has_field_parameter("E_min"):
E_min = data.get_field_parameter("E_min")
else:
E_min = 0.
if data.has_field_parameter("E_max"):
E_max = data.get_field_parameter("E_max")
else:
E_max = 0.
ne_tot = data["gas", "n_e"].v
if data.has_field_parameter("Electron p-law index"):
p = data.get_field_parameter("Electron p-law index")
else:
p = 0.
if data.has_field_parameter("E_min") and data.has_field_parameter("E_max") \
and data.has_field_parameter("Electron p-law index"):
k=YTQuantity(1.0,"kpc**(-1)")*(1-p)*ne_tot/(pow(E_max,(1-p)) - pow(E_min,(1-p)))
print("Inside kappa: p-law index is",p, E_min, E_max)
else:
k=YTQuantity(1.0,"kpc**(-1)")
if np.any(k < 0):
print("k negative!", k)
return k
def _chi_nu(field, data):
if data.has_field_parameter("Electron p-law index") and \
data.has_field_parameter("b(p)") and \
data.has_field_parameter("Magnetic field") and \
data.has_field_parameter("nu (Ghz)"):
p = data.get_field_parameter("Electron p-law index")
bp = data.get_field_parameter("b(p)")
bm4 = data.get_field_parameter("Magnetic field")
nu = data.get_field_parameter("nu (Ghz)")
ne_tot = data[("gas","n_e")].v
kappa = data[("gas","kappa")]
a = 6.445e-6
chi_nu=a*np.power(10,(p/2))*np.power(5.67,p)*kappa*bp*pow(bm4,(0.5*p+1))/np.power(nu,(0.5*p+2))
else:
chi_nu=YTQuantity(0.0,"kpc**(-1)")
return chi_nu
def _i_nu(field, data):
from unyt import kpc
from yt import YTArray, YTQuantity
from yt.units import mass_hydrogen
#
if data.has_field_parameter("lmin"):
lmin = data.get_field_parameter("lmin")
print("Inside _i_nu, lmin=",lmin)
else:
lmin = YTQuantity(0.0,"kpc")
if data.has_field_parameter("l.o.s."):
los = data.get_field_parameter("l.o.s.")
print("Inside _i_nu, l.o.s.=",los)
else:
los = [0, 0, 0]
if data.has_field_parameter("lmin origin"):
pos_0 = data.get_field_parameter("lmin origin")
print("Inside _i_nu, pos_0=",pos_0)
else:
pos_0 = data.ds.arr(np.zeros(3), 'kpc')
if data.has_field_parameter("Background I_nu"):
i_nulmin = data.get_field_parameter("Background I_nu")
print("Inside _i_nu, i_nulmin=",i_nulmin)
else:
i_nu_lmin = 0.
if data.has_field_parameter("Magnetic field"):
bm4 = data.get_field_parameter("Magnetic field")
print("Inside _i_nu, bm4=",bm4)
else:
bm4 = 1.e-20
## i_nu_lmin=YTQuantity(i_nulmin,"W/(m**2)/Hz")
# i_nu_lmin=YTQuantity(i_nulmin,"W/(m**2)/Hz").in_units("Jansky")
if data.has_field_parameter("Electron p-law index"):
p = data.get_field_parameter("Electron p-law index")
print("Inside _i_nu, p=",p)
fact_joc = np.power(10,-p)
else:
p=0.
fact_joc = 0.
if data.has_field_parameter("b(p)"):
bp = data.get_field_parameter("b(p)")
print("Inside _i_nu, b(p)=",bp)
else:
bp = 0.
if data.has_field_parameter("nu (Ghz)"):
nu = data.get_field_parameter("nu (Ghz)")
print("Inside _i_nu, nu=",nu)
else:
nu = 0
ne_tot = data["gas","density"].v/mass_hydrogen.v
kappa = data["kappa"]
a = YTQuantity(4.97766e-17,'W/(m**2)/Hz')
chi_nu = f_chi_nu(nu,bm4,p,bp,kappa)
j_over_chi = a*fact_joc*(nu**2.5)/np.power(bm4,0.5)
grid_pos=YTArray([data['gas','x'],data['gas','y'],data['gas','z']]).in_units('kpc')
r = proj_dist(los,grid_pos,pos_0)
ad = r-lmin
print("Inside _i_nu", i_nulmin, j_over_chi, a)
b = np.exp(-chi_nu*(r-lmin))
i_nu = i_nulmin*b + j_over_chi*(1-b)
return i_nu
""" General purpose functions """
def _e_dens(field, data):
""" Computes electron density from gas density."""
from yt.units import mass_hydrogen
return data[("gas","density")]/mass_hydrogen
def e_dens(dens):
""" Computes electron density from gas density."""
from yt.units import mass_hydrogen
return dens.v/mass_hydrogen.v
def f_kappa(ntot,emin,emax,p):
import sys, math
fk = (1-p)*ntot/(np.power(emax,(1-p))-np.power(emin,(1-p)))
return fk
def a_p(p):
from scipy import interpolate as int_erp
p=[1,1.5,2,2.5,3,3.5,4,4.5,5]
bp=[2.056,0.909,0.529,0.359,0.269,0.217,0.186,0.167,0.157]
f_interp=int_erp.interp1d(p,bp)
return f_interp(p_inp)
def b_p(p_inp):
from scipy import interpolate as int_erp
p=[1,1.5,2,2.5,3,3.5,4,4.5,5]
bp=[0.397,0.314,0.269,0.244,0.233,0.230,0.236,0.248,0.268]
f_interp=int_erp.interp1d(p,bp)
return f_interp(p_inp)
def f_chi_nu(nu,B,p,bp,kappa):
import sys, math
a1 = 5.67**p
a2 = pow(10,p/2)
c1 = 0.5*p + 1
c2 = 0.5*p + 2
abs_coeff = YTArray([6.445e-6],'kpc**(-1)')
return abs_coeff
def los_unit_vector(inp_angles):
from numpy import radians
from math import sin, cos
eul_angles_rad=radians(inp_angles)
v_dir = np.array([sin(eul_angles_rad[0])*cos(eul_angles_rad[1]),sin(eul_angles_rad[0])*sin(eul_angles_rad[1]),cos(eul_angles_rad[0])])
return v_dir
def proj_dist(los,xyz,origin):
import numpy as np
d = ((xyz.T - origin)*los)
dist = np.sqrt(np.sum(d*d, axis=1))
return dist
=======
Fr some reasons I do not quite understand, the field parameters I define in the main program are not passed down to the "i_nu" field through the _i_nu function. Here the error message:
> python3 pl_synchr_test.py
yt : [WARNING ] 2021-10-16 17:45:34,946 Overriding code units: Use this option only if you know that the dataset doesn't define the units correctly or at all.
yt : [INFO ] 2021-10-16 17:45:34,946 Overriding length_unit: 4.346024761918768e+24 cm.
yt : [INFO ] 2021-10-16 17:45:34,947 Overriding time_unit: 2.897349841279178e+17 s.
yt : [INFO ] 2021-10-16 17:45:34,947 Overriding mass_unit: 1.4647063306760563e+46 g.
yt : [INFO ] 2021-10-16 17:45:35,024 Parameters: current_time = 0.0016112618581139734
yt : [INFO ] 2021-10-16 17:45:35,024 Parameters: domain_dimensions = [8 8 8]
yt : [INFO ] 2021-10-16 17:45:35,024 Parameters: domain_left_edge = [-0.7 -0.7 -0.7]
yt : [INFO ] 2021-10-16 17:45:35,024 Parameters: domain_right_edge = [0.7 0.7 0.7]
yt : [INFO ] 2021-10-16 17:45:35,024 Parameters: cosmological_simulation = 0
Inside _i_nu, lmin= 0.0
Inside _i_nu, l.o.s.= 0.0
Inside _i_nu, pos_0= 0.0
Inside _i_nu, i_nulmin= 0.0
Inside _i_nu, bm4= 0.0
Inside _i_nu, p= 0.0
Inside _i_nu, b(p)= 0.0
Inside _i_nu, nu= 0.0
/g100/home/userexternal/vantonuc/.local/lib/python3.8/site-packages/unyt/array.py:1778: RuntimeWarning: invalid value encountered in true_divide
out_arr = func(
Inside _i_nu 0.0 nan W/(Hz*m**2) 4.97766e-17 W/(Hz*m**2)
yt : [INFO ] 2021-10-16 17:45:41,439 Making a fixed resolution buffer of (('gas', 'i_nu')) 512 by 512
Traceback (most recent call last):
File "pl_synchr_test.py", line 64, in <module>
synchr_fits=yt.FITSOffAxisSlice(ds,n_dir,("gas", "i_nu"), width=((50,'kpc')))
File "/g100/home/userexternal/vantonuc/.local/lib/python3.8/site-packages/yt/visualization/fits_image.py", line 1275, in __init__
super().__init__(frb, fields=fields, length_unit=lunit, wcs=w)
File "/g100/home/userexternal/vantonuc/.local/lib/python3.8/site-packages/yt/visualization/fits_image.py", line 244, in __init__
this_img = img_data[field]
File "/g100/home/userexternal/vantonuc/.local/lib/python3.8/site-packages/yt/visualization/fixed_resolution.py", line 139, in __getitem__
buff = self.ds.coordinates.pixelize(
File "/g100/home/userexternal/vantonuc/.local/lib/python3.8/site-packages/yt/geometry/coordinates/cartesian_coordinates.py", line 221, in pixelize
return self._oblique_pixelize(data_source, field, bounds, size, antialias)
File "/g100/home/userexternal/vantonuc/.local/lib/python3.8/site-packages/yt/geometry/coordinates/cartesian_coordinates.py", line 570, in _oblique_pixelize
data_source[field],
File "/g100/home/userexternal/vantonuc/.local/lib/python3.8/site-packages/yt/data_objects/data_containers.py", line 258, in __getitem__
self.get_data(f)
File "/g100/home/userexternal/vantonuc/.local/lib/python3.8/site-packages/yt/data_objects/selection_objects/data_selection_objects.py", line 169, in get_data
finfo.check_available(self)
File "/g100/home/userexternal/vantonuc/.local/lib/python3.8/site-packages/yt/fields/derived_field.py", line 244, in check_available
validator(data)
File "/g100/home/userexternal/vantonuc/.local/lib/python3.8/site-packages/yt/fields/derived_field.py", line 503, in __call__
raise NeedsParameter(doesnt_have)
yt.fields.field_exceptions.NeedsParameter: (['lmin', 'l.o.s.', 'lmin origin', 'Background I_nu', 'Magnetic field', 'Electron p-law index', 'b(p)', 'nu (Ghz)'])
========
Many thanks in advance for any help/suggestions.