Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some updates and additions to astrophysics-related fields #2245

Merged
merged 85 commits into from Aug 19, 2019

Conversation

jzuhone
Copy link
Contributor

@jzuhone jzuhone commented Apr 17, 2019

PR Summary

This PR updates a number of the astronomy/astrophysics-specific fields in yt. In detail:

  • Wherever possible, change "cell_mass" to "mass" so that fields are not only defined for grid-based datasets. Similarly, if possible, do not use "cell_volume" for fields which are meant to be general.
  • Add a computation for the number density fields for free electrons, protons, and helium nuclei for when there are no species fields, assuming primordial abundances and full ionization.
  • Redefine "number_density" and "mean_molecular_weight" fields so that they can be calculated even if no species are defined, by assuming a constant mean molecular weight and primordial abundances.
  • Add an "optical_depth" field which depends on the "El_number_density" field. Redefine the two SZ fields in terms of this field (otherwise they just assume full ionization, which may not be true).
  • Add a "velocity_los" field for projections, which computes the velocity component along a line of sight, on-axis or off-axis. Use it in the "sz_kinetic" field.
  • Add a "magnetic_field_los" field for projections, which computes the magnetic field strength component along a line of sight, on-axis or off-axis. This is used for the Faraday rotation measure field, which is also added here.
  • Add an alias for the "particle_gpot" field in the FLASH frontend.
  • Move the "entropy" field to astro_fields, since its field definition is very astro-specific (and in fact it's very high-energy-astro-specific). Make it depend on the "El_number_density" field (otherwise it just assumes full ionization, which may not be true).
  • Remove chandra_emissivity field. It's not well-documented and it is not clear at all what it represents (i.e. what is the energy band? what is the instrument assumed?), so it's misleading.
  • Remove extra whitespace and parentheses in various places
  • Set up a function which computes a default mean molecular weight for frontends that may use one for defining things like temperature and number density but don't have one. This default mu is now used in the athena, athena_pp, and gadget frontends unless the user passes in a different value when loading the dataset. NOTE: This default mu assumes full ionization.
  • Made sure that the flash, enzo, and gamer frontends get to define fields like "number_density" the way they want.
  • Fixed a bug which prevented magnetic fields from being defined properly in SPH frontends.
  • The "cell_mass" and "courant_time_step" fields should have sampling_type="cell".
  • Add species fields to the Arepo frontend.
  • Fixed some bugs created in off-axis projections

PR Checklist

  • Code passes flake8 checker
  • New features are documented, with docstrings and narrative docs
  • Adds a test for any bugs fixed. Adds tests for new features.

@jzuhone
Copy link
Contributor Author

jzuhone commented Jul 5, 2019

After rebasing this PR I'd like to come back to it. The major unresolved issue is what I said above (see the full text above for context):

There is one subtle inconsistency in this setup at the moment. The field definitions I wrote for the "number_density' and "mean_molecular_weight" fields assume primordial abundances and zero ionization. This is what we do in a number of the SPH frontends when we need to compute the temperature but there are no species fields to compute the molecular weight. But defining an free electron number density field really only makes sense if at least the gas is partially ionized, so in that case I've assumed full ionization. But there's obviously an inconsistency there. It would be easy to just define the number density fields here and the temperature fields in the SPH frontends to assume full ionization instead if there are no species defined, but this is potentially a significant backwards-incompatible change for the latter.

The possible resolutions I can see are:

  1. Have the default for both species fields and the mean molecular weight be zero ionization
  2. Have the default for both species fields and the mean molecular weight be full ionization
  3. Have this set up in a frontend-dependent way, perhaps by using parameters

Copy link
Member

@brittonsmith brittonsmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jzuhone, these code improvements all look good to me. My only suggestion is to perhaps create an add_los_field function in vector_operations.py to generate line of sight fields from vector fields.

On the mean molecular weight issue, my inclination is toward assuming full ionization. As you mention, the neutral assumption leaves you with zero electron density, requiring the extra inconsistency to model that simply. This might be just me, but my impression is that simulations that focus on neutral gas are more likely to have the additional fields to compute mmw correctly, whereas simulations of higher temperature phenomena are more likely to follow just density.

In Grackle, we also include the effects of metals by assuming a mean molecular weight of 16 and using the metal density field. That number is about what you get for assuming fully ionized metals with a solar abundance pattern.

@jzuhone
Copy link
Contributor Author

jzuhone commented Jul 8, 2019

@brittonsmith I like that idea regarding vector operations.

Anyone who works with SPH data have any concerns about changing the zero ionization assumption? @qobilidop or @AshKelly? Note that this only affects data which doesn't have any abundances defined.

Relevant code is here, particularly the last 10 lines or so:

def setup_gas_particle_fields(self, ptype):
if (ptype, "ElectronAbundance") in self.ds.field_list:
def _temperature(field, data):
# Assume cosmic abundances
x_H = 0.76
gamma = 5.0/3.0
a_e = data[ptype, 'ElectronAbundance']
mu = 4.0 / (3.0 * x_H + 1.0 + 4.0 * x_H * a_e)
ret = data[ptype, "InternalEnergy"]*(gamma-1)*mu*mp/kb
return ret.in_units(self.ds.unit_system["temperature"])
else:
def _temperature(field, data):
# Assume cosmic abundances
x_H = 0.76
gamma = 5.0/3.0
if data.has_field_parameter("mean_molecular_weight"):
mu = data.get_field_parameter("mean_molecular_weight")
else:
# Assume zero ionization
mu = 4.0 / (3.0 * x_H + 1.0)
ret = data[ptype, "InternalEnergy"]*(gamma-1)*mu*mp/kb
return ret.in_units(self.ds.unit_system["temperature"])

@jzuhone
Copy link
Contributor Author

jzuhone commented Jul 8, 2019

Would also love any comment from @chummels

@brittonsmith
Copy link
Member

@jzuhone, I think Cameron is busily preparing to leave on a long trip at the end of the week. It's likely he's not going to have time to comment here.

@AshKelly
Copy link
Member

AshKelly commented Jul 9, 2019

yeah, I think zero ionization is appropriate if there are no other fields, e.g electron fraction. Hopefully, if people don't explicitly store electron fraction or temperature then they aren't too worried about it

@jzuhone
Copy link
Contributor Author

jzuhone commented Jul 9, 2019

@AshKelly the proposal here currently is to assume full ionization unless specified.

Unfortunately it’s not true that if people don’t store those things that they don’t care (although in theory it should be). For most applications in X-ray astrophysics, full ionization is assumed and so you need a mean molecular weight which reflects that to get electron number density and temperature, both of which are needed for emission and other calculations.

So we need to decide if we want to assume full ionization by default (a decidedly higher-temperature astrophysics bias) or zero ionization (a lower temperature general physics bias). Or if we want to have some kind of switch that does either.

@matthewturk
Copy link
Member

@jzuhone This is a really interesting question. I'm not sure I have the right answer, but I would propose that since we're talking about a default, we make room for different codes and frontends to set it, and we also identify how to set it -- probably in something less fragile than field_parameters.

I think that if we can't deduce it, then it's safe for this field to assume full ionization. Does that make sense?

@jzuhone
Copy link
Contributor Author

jzuhone commented Jul 12, 2019

Ok, I made a flurry of changes which I think settles the question regarding how to set mean molecular weights. Please have a look at the latest changes starting with 3e412fd and leave some feedback.

for ax in axis_order]

def _los_field(field, data):
axis = data.get_field_parameter("axis")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick question, does axis need to be checked to see if it's a unit vector?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be either a unit vector or a single integer for an axis-aligned l.o.s. Do you have a suggestion for a check?

else:
mu = 0.6
return (data["gas","pressure"]/data["gas","density"])*mu*mh/kboltz
return (data["gas","pressure"]/data["gas","density"])*data.ds.mu*mh/kboltz
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like above you're setting self.parameters["mu"]. Do you need to use that here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I didn't do this right. Thanks for the find again.

("gas", "mean_molecular_weight"),
sampling_type="cell",
function=_mean_molecular_weight,
units=unit_system["number_density"])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these the correct units?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, you are right, I'll fix that. Thanks for the catch.

function=_number_density,
units=unit_system["number_density"])

if "ye" in self.field_list:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not that familiar with the FLASH format. Can you get both this condition and the one above (if ("flash", "abar") in self)? If so, you could have one number_density field overwriting another. Should this be an elif?

(2.0 * _primordial_mass_fraction["H"])
mu += ChemicalFormula("He").weight / \
(3.0 * _primordial_mass_fraction["He"])

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This never returns mu.

@jzuhone jzuhone force-pushed the astro_fields branch 2 times, most recently from a13760c to e7c14a4 Compare July 22, 2019 19:00
Copy link
Member

@brittonsmith brittonsmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left one last minor comment, but this looks good to me. Cameron is away on a hike for the next 3+ months and I imagine Nathan is pretty busy with other things. @matthewturk, do you think you could take a quick look at this? I think two approves would be sufficient.

Also, John, we have a bot that prevents WIP PRs from being merged, so please go ahead and remove that from the title when you're ready to get this in.

Na_code = data.ds.quan(Na, '1/code_mass')
return data["flash", "dens"]*Na_code/data["gas", "mean_molecular_weight"]

self.add_field(("gas", "number_density"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, but you could indent this self.add_field call one to the left and remove the identical call inside the if statement above.

@jzuhone
Copy link
Contributor Author

jzuhone commented Aug 8, 2019

Since this touches a lot of stuff, we should probably enforce three approvals here.
@qobilidop, @AshKelly, @munkm, anyone?

@jzuhone
Copy link
Contributor Author

jzuhone commented Aug 14, 2019

Anyone want to take a peek at this?

Copy link
Member

@matthewturk matthewturk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Impressive and detailed! Good stuff.

doc/source/analyzing/fields.rst Show resolved Hide resolved
doc/source/analyzing/fields.rst Show resolved Hide resolved
yt/data_objects/construction_data_containers.py Outdated Show resolved Hide resolved
yt/fields/astro_fields.py Show resolved Hide resolved
@matthewturk
Copy link
Member

I see no reasons to hold off on merging this.

@jzuhone
Copy link
Contributor Author

jzuhone commented Aug 16, 2019

@matthewturk fine by me! Thanks!

Copy link
Member

@munkm munkm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks really great! I really like the line of sight field feature. I have a few minor things I've commented on, mostly docs clarifications.

doc/source/analyzing/fields.rst Outdated Show resolved Hide resolved
doc/source/analyzing/fields.rst Show resolved Hide resolved

At this time, this functionality is enabled for the velocity and magnetic vector
fields, ``("gas","velocity_los")`` and ``("gas","magnetic_field_los")``. The
following fields built into yt make use of these line-of-sight fields:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a user wants to have a line of sight field for a different vector field, is there a way to do that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not yet, but in fact, none of the vector field operations (like magnitude, etc) are available for any other fields than these two. We should probably expose this in a separate PR somehow.

doc/source/examining/loading_data.rst Outdated Show resolved Hide resolved
doc/source/examining/loading_data.rst Show resolved Hide resolved
yt/fields/xray_emission_fields.py Outdated Show resolved Hide resolved
@jzuhone
Copy link
Contributor Author

jzuhone commented Aug 19, 2019

@munkm I think I've addressed everything, but let me know if there is anything else. Thanks for the comments!

Copy link
Member

@munkm munkm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates @jzuhone! The clarifications you added were really helpful!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants