.. _quantities: Physical Quantities =================== A simulation output stores many different types of physical information about its matter components, e.g. gas, stars, dark matter, and supermassive black holes. The original snapshots contain basic information, such as positions and masses, and we refer to these as **default snapshot quantities**. After a galaxy/halo finder has been run, the resulting group catalogs aggregate these same fields, computing e.g. the total stellar mass of a galaxy by summing up the masses of its associated stars. We refer to these fields as **default catalog quantities**. From these physical quantities, many others can be derived. These are value-added properties which are not output directly by the simulation, but must be calculated. For example, simple unit conversions (e.g. from code mass, to solar masses), fundamental derived quantities (e.g. pressure, given density and internal energy), non-trivial theoretical quantities (e.g. enclosed mass, gravitational free-fall time, or the ratio of gas cooling time to free-fall time), and post-processed quantities and observables (e.g. gas x-ray emission, stellar light and spectra, or ion abundances from photoionization modeling). These we refer to as **custom snapshot quantities**, and when the derived properties are for galaxies or halos instead of individual particles/cells, **custom catalog quantities**. Default Snapshot Quantities --------------------------- These are the fields which are directly available from the on-disk snapshot files themselves. For example, ``PartType0/StarFormationRate`` (for gas) or ``PartType4/Masses`` (for stars). For complete documentation of available fields, their definitions, and units, see * the IllustrisTNG Public Data Release `Snapshot Documentation `_. The :py:mod:`temet.load.snap_fields` module defines metadata associated with these fields, including a description (label for plotting), units, and default bounds. Default Catalog Quantities -------------------------- These are the fields which are directly available from the on-disk group catalog files themselves. Specifically, by the combination of the friends-of-friends (FoF) algorithm plus the Subfind algorithm, which identifies gravitationally bound structures: halos and subhalos. For example, ``SubhaloMass`` or ``Group_M_Crit200`` are two common fields. For complete documentation of available fields, their definitions, and units, see * the IllustrisTNG Public Data Release `Group Catalog Documentation `_. Custom Snapshot Quantities -------------------------- The following particle/cell-level custom quantities are currently defined, in the :py:mod:`temet.load.snap_fields_custom` module, along with associated metadata including a description, units, reasonable bounds, and so on. .. include:: quants_custom.rst .. # note: changing intro line from '..' to '.. exec::' makes this an executing code block # this snippet is left here, in case we need a similar source parsing functionality # code executes in temet/ directory, load the source of a file import re with open('temet/plot/quantities.py','r') as f: lines = f.readlines() # start output (is then run through the rest/html build parser) print('.. csv-table::') print(' :header: "Quantity Name", "Aliases", "Units", "Description"') print(' :widths: 10, 30, 20, 40') print('') start = False for line in lines: # skip to our function of interest if "def simParticleQuantity(" in line: start = True if not start: continue # find conditionals if "if prop in [" in line: m = re.findall("'(.+?)'", line) #m = re.search("'(.+?)'", line) if m: name = m[0] aliases = ', '.join(m[1:]) print(' "%s", "%s", "", ""' % (name,aliases)) #print(" " + str(m.group(1))) # TODO: handle lines of type "if 'something' in ptProperty" #print('\n') .. _custom_group_quantities: Adding New Custom Snapshot Quantities ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Each custom field is generated by a function, and the name of the function is the name of the custom field. All such defined fields are recorded in a 'registry'. To create a new custom field is simple: just define a function, and decorate it with the ``@snap_field`` decorator, as shown below. It must accept four ordered arguments: ``(sim, partType, field, args)``, and must return a numpy array of the requested values. You can find all built-in custom quantities defined in the :py:mod:`temet.load.snap_fields_custom` module. If you are editing this package directly, or want to share your custom fields in the future, you can add to that file. But, you can also define your custom field in any file you want. For example, to define a new custom field for the 'spherical equivalent radius' of a gas cell:: from temet.load.snapshot import snap_field @snap_field def cell_radius(sim, partType, field, args): # load and manipulate data, return vol = sim.snapshotSubset(partType, 'vol', **args) return (vol * 3.0 / (4*np.pi))**(1.0/3.0) Important metadata should also be specified, just below (and outside) the function itself:: cell_radius.units = 'code_length' cell_radius.label = 'Cell Radius' cell_radius.limits = [-2.0, 2.0] cell_radius.log = True Note: ``units`` and ``label`` should correspond to the returned values. ``limits`` is a default suggestion for a ``[min,max]`` range for plotting, while ``log`` indicates if the value should in general be logged for plotting/display (usually True, and by default True if omitted, as our convention is to always return linear values). You can also register the same derived field under one or more additional names ('aliases'):: @snap_field(aliases=['cellrad','rcell']) def cell_radius(sim, partType, field, args): # load and manipulate data, return # ... Finally, you can define 'wildcard' fields which capture, and then handle, many different field names at once. For example, imagine you could compute the optical stellar spectrum for any star particle, and you wanted to define a new field of the form ``specmean_{wavemin}_{wavemax}`` which would return the mean flux between the two specified wavelengths, which are arbitrary inputs. If we had such a custom field, we could compute e.g. ``D4000 = specmean_4050_4250 / specmean_3750_3950}`` (indeed, we could then define yet another custom field called ``D4000`` which did exactly this, automatically). To handle these two field names, or any others of the same form, we could define:: @snap_field(multi=True) def specmean_(sim, partType, field, args): # get wavelengths out of field string _, wavemin, wavemax = field.split('_') # compute spectrum, measure mean in this wavelength window, and return # ... In this case, any snapshot load request (e.g. ``sim.stars('specmean_5000,6000', haloID=10)``) which contains the string ``specmean_`` will get routed to this generator function. Note: in the case that ``multi`` is not a simple bool, but instead a string, then the value itself is used as the matching pattern (see ``cloudy_`` for an example, which matches on spaces). Custom Catalog Quantities ------------------------- The following halo/subhalo custom quantities are currently defined, in the :py:mod:`temet.load.groupcat_fields_custom` module, along with associated metadata including a description, units, reasonable bounds, and so on. .. include:: quants_cat_custom.rst Adding New Custom Catalog Quantiites ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TODO.