"""
Fields specific to Enzo
"""
#-----------------------------------------------------------------------------
# Copyright (c) 2013, yt Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
import numpy as np
from yt.funcs import mylog
from yt.fields.field_info_container import \
FieldInfoContainer
from yt.units.yt_array import \
YTArray
from yt.utilities.physical_constants import \
mh, me, mp, \
mass_sun_cgs
b_units = "code_magnetic"
ra_units = "code_length / code_time**2"
rho_units = "code_mass / code_length**3"
vel_units = "code_velocity"
known_species_names = {
'HI' : 'H',
'HII' : 'H_p1',
'HeI' : 'He',
'HeII' : 'He_p1',
'HeIII' : 'He_p2',
'H2I' : 'H2',
'H2II' : 'H2_p1',
'HM' : 'H_m1',
'DI' : 'D',
'DII' : 'D_p1',
'HDI' : 'HD',
'Electron': 'El',
'OI' : 'O',
'OII' : 'O_p1',
'OIII' : 'O_p2',
'OIV' : 'O_p3',
'OV' : 'O_p4',
'OVI' : 'O_p5',
'OVII' : 'O_p6',
'OVIII' : 'O_p7',
'OIX' : 'O_p8',
}
[docs]class EnzoFieldInfo(FieldInfoContainer):
known_other_fields = (
("Cooling_Time", ("s", ["cooling_time"], None)),
("Dengo_Cooling_Rate", ("erg/g/s", [], None)),
("Grackle_Cooling_Rate", ("erg/s/cm**3", [], None)),
("HI_kph", ("1/code_time", [], None)),
("HeI_kph", ("1/code_time", [], None)),
("HeII_kph", ("1/code_time", [], None)),
("H2I_kdiss", ("1/code_time", [], None)),
("Bx", (b_units, ["magnetic_field_x"], None)),
("By", (b_units, ["magnetic_field_y"], None)),
("Bz", (b_units, ["magnetic_field_z"], None)),
("RadAccel1", (ra_units, ["radiation_acceleration_x"], None)),
("RadAccel2", (ra_units, ["radiation_acceleration_y"], None)),
("RadAccel3", (ra_units, ["radiation_acceleration_z"], None)),
("Dark_Matter_Density", (rho_units, ["dark_matter_density"], None)),
("Temperature", ("K", ["temperature"], None)),
("Dust_Temperature", ("K", ["dust_temperature"], None)),
("x-velocity", (vel_units, ["velocity_x"], None)),
("y-velocity", (vel_units, ["velocity_y"], None)),
("z-velocity", (vel_units, ["velocity_z"], None)),
("RaySegments", ("", ["ray_segments"], None)),
("PhotoGamma", (ra_units, ["photo_gamma"], None)),
("PotentialField", ("code_velocity**2", ["gravitational_potential"], None)),
("Density", (rho_units, ["density"], None)),
("Metal_Density", (rho_units, ["metal_density"], None)),
("SN_Colour", (rho_units, [], None)),
# Note: we do not alias Electron_Density to anything
("Electron_Density", (rho_units, [], None)),
)
known_particle_fields = (
("particle_position_x", ("code_length", [], None)),
("particle_position_y", ("code_length", [], None)),
("particle_position_z", ("code_length", [], None)),
("particle_velocity_x", (vel_units, [], None)),
("particle_velocity_y", (vel_units, [], None)),
("particle_velocity_z", (vel_units, [], None)),
("creation_time", ("code_time", [], None)),
("dynamical_time", ("code_time", [], None)),
("metallicity_fraction", ("code_metallicity", [], None)),
("metallicity", ("", [], None)),
("particle_type", ("", [], None)),
("particle_index", ("", [], None)),
("particle_mass", ("code_mass", [], None)),
("GridID", ("", [], None)),
("identifier", ("", ["particle_index"], None)),
("level", ("", [], None)),
)
[docs] def __init__(self, ds, field_list):
hydro_method = ds.parameters.get("HydroMethod", None)
if hydro_method is None:
hydro_method = ds.parameters["Physics"]["Hydro"]["HydroMethod"]
if hydro_method == 2:
sl_left = slice(None,-2,None)
sl_right = slice(1,-1,None)
div_fac = 1.0
else:
sl_left = slice(None,-2,None)
sl_right = slice(2,None,None)
div_fac = 2.0
slice_info = (sl_left, sl_right, div_fac)
super(EnzoFieldInfo, self).__init__(ds, field_list, slice_info)
[docs] def add_species_field(self, species):
# This is currently specific to Enzo. Hopefully in the future we will
# have deeper integration with other systems, such as Dengo, to provide
# better understanding of ionization and molecular states.
#
# We have several fields to add based on a given species field. First
# off, we add the species field itself. Then we'll add a few more
# items...
#
self.add_output_field(("enzo", "%s_Density" % species),
take_log=True,
units="code_mass/code_length**3")
yt_name = known_species_names[species]
# don't alias electron density since mass is wrong
if species != "Electron":
self.alias(("gas", "%s_density" % yt_name),
("enzo", "%s_Density" % species))
[docs] def setup_species_fields(self):
species_names = [fn.rsplit("_Density")[0] for ft, fn in
self.field_list if fn.endswith("_Density")]
species_names = [sp for sp in species_names
if sp in known_species_names]
def _electron_density(field, data):
return data["Electron_Density"] * (me/mp)
self.add_field(("gas", "El_density"),
function = _electron_density,
units = "g/cm**3")
for sp in species_names:
self.add_species_field(sp)
self.species_names.append(known_species_names[sp])
[docs] def setup_fluid_fields(self):
# Now we conditionally load a few other things.
params = self.ds.parameters
multi_species = params.get("MultiSpecies", None)
dengo = params.get("DengoChemistryModel", 0)
if multi_species is None:
multi_species = params["Physics"]["AtomicPhysics"]["MultiSpecies"]
if multi_species > 0 or dengo == 1:
self.setup_species_fields()
self.setup_energy_field()
[docs] def setup_energy_field(self):
# We check which type of field we need, and then we add it.
ge_name = None
te_name = None
params = self.ds.parameters
multi_species = params.get("MultiSpecies", None)
if multi_species is None:
multi_species = params["Physics"]["AtomicPhysics"]["MultiSpecies"]
hydro_method = params.get("HydroMethod", None)
if hydro_method is None:
hydro_method = params["Physics"]["Hydro"]["HydroMethod"]
dual_energy = params.get("DualEnergyFormalism", None)
if dual_energy is None:
dual_energy = params["Physics"]["Hydro"]["DualEnergyFormalism"]
if ("enzo", "Gas_Energy") in self.field_list:
ge_name = "Gas_Energy"
elif ("enzo", "GasEnergy") in self.field_list:
ge_name = "GasEnergy"
if ("enzo", "Total_Energy") in self.field_list:
te_name = "Total_Energy"
elif ("enzo", "TotalEnergy") in self.field_list:
te_name = "TotalEnergy"
if hydro_method == 2:
self.add_output_field(("enzo", te_name),
units="code_velocity**2")
self.alias(("gas", "thermal_energy"), ("enzo", te_name))
elif dual_energy == 1:
self.add_output_field(
("enzo", ge_name),
units="code_velocity**2")
self.alias(
("gas", "thermal_energy"),
("enzo", ge_name),
units = "erg/g")
elif hydro_method in (4, 6):
self.add_output_field(
("enzo", te_name),
units="code_velocity**2")
# Subtract off B-field energy
def _sub_b(field, data):
ret = data[te_name] - 0.5*data["velocity_x"]**2.0
if data.ds.dimensionality > 1:
ret -= 0.5*data["velocity_y"]**2.0
if data.ds.dimensionality > 2:
ret -= 0.5*data["velocity_z"]**2.0
ret -= data["magnetic_energy"]/data["density"]
return ret
self.add_field(
("gas", "thermal_energy"),
function=_sub_b, units = "erg/g")
else: # Otherwise, we assume TotalEnergy is kinetic+thermal
self.add_output_field(
("enzo", te_name),
units = "code_velocity**2")
self.alias(("gas", "total_energy"), ("enzo", te_name))
def _tot_minus_kin(field, data):
ret = data[te_name] - 0.5*data["velocity_x"]**2.0
if data.ds.dimensionality > 1:
ret -= 0.5*data["velocity_y"]**2.0
if data.ds.dimensionality > 2:
ret -= 0.5*data["velocity_z"]**2.0
return ret
self.add_field(
("gas", "thermal_energy"),
function = _tot_minus_kin,
units = "erg/g")
if multi_species == 0 and 'Mu' in params:
def _number_density(field, data):
return data['gas', 'density']/(mp*params['Mu'])
self.add_field(
("gas", "number_density"),
function = _number_density,
units="1/cm**3")
[docs] def setup_particle_fields(self, ptype):
def _age(field, data):
return data.ds.current_time - data["creation_time"]
self.add_field((ptype, "age"), function = _age,
particle_type = True,
units = "yr")
super(EnzoFieldInfo, self).setup_particle_fields(ptype)