In [ ]:
import yt
Now that we've loaded yt, we can load up some data. Let's load the IsolatedGalaxy dataset.
In [ ]:
ds = yt.load("IsolatedGalaxy/galaxy0030/galaxy0030")
When you call the load function, yt tries to do very little -- this is designed to be a fast operation, just setting up some information about the simulation. Now, the first time you access the "index" it will read and load the mesh and then determine where data is placed in the physical domain and on disk. Once it knows that, yt can tell you some statistics about the simulation:
In [ ]:
ds.print_stats()
yt can also tell you the fields it found on disk:
In [ ]:
ds.field_list
And, all of the fields it thinks it knows how to generate:
In [ ]:
ds.derived_field_list
yt can also transparently generate fields. However, we encourage you to examine exactly what yt is doing when it generates those fields. To see, you can ask for the source of a given field.
In [ ]:
print(ds.field_info["gas", "vorticity_x"].get_source())
yt stores information about the domain of the simulation:
In [ ]:
ds.domain_width
yt can also convert this into various units:
In [ ]:
print (ds.domain_width.in_units("kpc"))
print (ds.domain_width.in_units("au"))
print (ds.domain_width.in_units("mile"))
Finally, we can get basic information about the particle types and number of particles in a simulation:
In [ ]:
print (ds.particle_types)
print (ds.particle_types_raw)
print (ds.particle_type_counts)
For this dataset, we see that there are two particle types defined, (io and all), but that only one of these particle types in in ds.particle_types_raw. The ds.particle_types list contains all particle types in the simulation, including ones that are dynamically defined like particle unions. The ds.particle_types_raw list includes only particle types that are in the output file we loaded the dataset from.
We can also see that there are a bit more than 1.1 million particles in this simulation. Only particle types in ds.particle_types_raw will appear in the ds.particle_type_counts dictionary.
In [ ]:
print (ds.index.grid_left_edge)
But, you may have to access information about individual grid objects! Each grid object mediates accessing data from the disk and has a number of attributes that tell you about it. The index (ds.index here) has an attribute grids which is all of the grid objects.
In [ ]:
ds.index.grids[1]
In [ ]:
g = ds.index.grids[1]
print(g)
Grids have dimensions, extents, level, and even a list of Child grids.
In [ ]:
g.ActiveDimensions
In [ ]:
g.LeftEdge, g.RightEdge
In [ ]:
g.Level
In [ ]:
g.Children
In [ ]:
gs = ds.index.select_grids(ds.index.max_level)
In [ ]:
g2 = gs[0]
print (g2)
print (g2.Parent)
print (g2.get_global_startindex())
In [ ]:
g2["density"][:,:,0]
In [ ]:
print ((g2.Parent.child_mask == 0).sum() * 8)
print (g2.ActiveDimensions.prod())
In [ ]:
for f in ds.field_list:
fv = g[f]
if fv.size == 0: continue
print (f, fv.min(), fv.max())
yt provides data object selectors. In subsequent notebooks we'll examine these in more detail, but we can select a sphere of data and perform a number of operations on it. yt makes it easy to operate on fluid fields in an object in bulk, but you can also examine individual field values.
This creates a sphere selector positioned at the most dense point in the simulation that has a radius of 10 kpc.
In [ ]:
sp = ds.sphere("max", (10, 'kpc'))
In [ ]:
sp
We can calculate a bunch of bulk quantities. Here's that list, but there's a list in the docs, too!
In [ ]:
list(sp.quantities.keys())
Let's look at the total mass. This is how you call a given quantity. yt calls these "Derived Quantities". We'll talk about a few in a later notebook.
In [ ]:
sp.quantities.total_mass()