<jupyter_start><jupyter_text>Logging to a GSD file Overview Questions* What is a Logger?* How can I write thermodynamic and other quantities to a file?* How can I access that data? Objectives* Describe and give examples of **loggable quantities**.* Show how to add quantities to a **Logger**.* Demonstrate **GSD** as a log writer.* Explain how to read logged quantities from **GSD** files.* Describe how **namespaces** appear in the names of the logged quantities. Boilerplate code<jupyter_code>import gsd.hoomd
import hoomd
import matplotlib

%matplotlib inline
matplotlib.style.use('ggplot')
import os

fn = os.path.join(os.getcwd(), 'log.gsd')
![ -e "$fn" ] && rm "$fn"<jupyter_output><empty_output><jupyter_text>IntroductionHOOMD separates logging into three parts: **Loggable quantities**, the **Logger** class, and **Writers**.* **Loggable quantities** are values computed during a simulation.* The **Logger** class provides a way to collect and name quantities of interest.* **Writers** write these values out in a format you can use.In this section, you will use the **GSD Writer** to capture the values of quantities during a simulation run for later analysis.  Define the SimulationThis tutorial executes the Lennard-Jones particle simulation from a previous tutorial. See [*Introducing Molecular Dyamics*](../01-Introducing-Molecular-Dynamics/00-index.ipynb) for a complete description of this code.<jupyter_code>cpu = hoomd.device.CPU()
sim = hoomd.Simulation(device=cpu)
sim.create_state_from_gsd(
    filename='../01-Introducing-Molecular-Dynamics/random.gsd')

integrator = hoomd.md.Integrator(dt=0.005)
cell = hoomd.md.nlist.Cell()
lj = hoomd.md.pair.LJ(nlist=cell)
lj.params[('A', 'A')] = dict(epsilon=1, sigma=1)
lj.r_cut[('A', 'A')] = 2.5
integrator.forces.append(lj)
nvt = hoomd.md.methods.NVT(kT=1.5, filter=hoomd.filter.All(), tau=1.0)
integrator.methods.append(nvt)
sim.operations.integrator = integrator
sim.run(0)<jupyter_output><empty_output><jupyter_text>Loggable quantitiesMany classes in HOOMD-blue provide special *properties* called **loggable quantities**.For example, the **Simulation** class provides `timestep`, `tps`, and others.The reference documentation labels each of these as _Loggable_.You can also examine the ``loggables`` property to determine the **loggable quantities**:<jupyter_code>sim.loggables<jupyter_output><empty_output><jupyter_text>The **ThermodynamicQuantities** class computes a variety of **thermodynamic properties** in MD simulations.These are all loggable.<jupyter_code>thermodynamic_properties = hoomd.md.compute.ThermodynamicQuantities(
    filter=hoomd.filter.All())
sim.operations.computes.append(thermodynamic_properties)
thermodynamic_properties.loggables<jupyter_output><empty_output><jupyter_text>**Loggable quantities** are class properties or methods.You can directly access them in your code.<jupyter_code>sim.timestep
thermodynamic_properties.kinetic_temperature<jupyter_output><empty_output><jupyter_text>Each **loggable quantity** has a **category**, which is listed both in the reference documentation and in ``loggables``.The **category** is a string that identifies the quantity's type or category.Example categories include:* `scalar` - numbers* `sequence` - arrays of numbers* `string` - strings of characters* `particle` - arrays of per-particle values  Add quantities to a Logger Add each of the quantities you would like to store to a **Logger**.The **Logger** will maintain these quantities in a list and provide them to the **Writer** when needed.<jupyter_code>logger = hoomd.logging.Logger()<jupyter_output><empty_output><jupyter_text>You can add **loggable quantities** from any number of objects to a **Logger**.**Logger** uses the namespace of the class to assign a unique name for each quantity.Call `add` to add all quantities provided by `thermodynamic_properties`:<jupyter_code>logger.add(thermodynamic_properties)<jupyter_output><empty_output><jupyter_text>You can also select specific quantities to add with the `quantities` argument.Add only the `timestep` and `walltime` quantities from **Simulation**:<jupyter_code>logger.add(sim, quantities=['timestep', 'walltime'])<jupyter_output><empty_output><jupyter_text>Writing log quantities to a GSD file**GSD** files always store trajectories of particle properties.Set the `log` attribute and **GSD** will also store the selected quantities.You can store _only_ the logged quantities by using the **Null** filter to select no particles for the trajectory.This way, you can log thermodynamic properties at a high rate and keep the file size small.<jupyter_code>gsd_writer = hoomd.write.GSD(filename='log.gsd',
                             trigger=hoomd.trigger.Periodic(1000),
                             mode='xb',
                             filter=hoomd.filter.Null())
sim.operations.writers.append(gsd_writer)<jupyter_output><empty_output><jupyter_text>Assign the logger to include the logged quanties in the GSD file:<jupyter_code>gsd_writer.log = logger<jupyter_output><empty_output><jupyter_text>The writer triggers and writes to the log file when the simulation runs:<jupyter_code>sim.run(100000)<jupyter_output><empty_output><jupyter_text>Reading logged data from a GSD file You need to close the **GSD** file that `gsd_writer` has open before you can read it.The following code block deletes the simulation and operations manually so that it is safe to open the file for reading later in this notebook.In typical workflows, you will run separate simulation and analysis scripts and the **GSD** file will be closed when your simulation script exits.<jupyter_code>del sim, gsd_writer, thermodynamic_properties, logger
del integrator, nvt, lj, cell, cpu<jupyter_output><empty_output><jupyter_text>Use the `gsd` package to open the file:<jupyter_code>traj = gsd.hoomd.open('log.gsd', 'rb')<jupyter_output><empty_output><jupyter_text>Each frame in the trajectory has a `log` dictionary that maps quantity names to values.Inspect this dictionary in the first frame:<jupyter_code>traj[0].log<jupyter_output><empty_output><jupyter_text>The dictionary keys are verbose names that include the **namespace** of the class which computed the quantity, where `.` has been replaced with `/`.For example, access the potential energy computed by **ThermodynamicQuantities** with the key `md/compute/ThermodynamicQuantities/potential_energy`.<jupyter_code>traj[0].log['md/compute/ThermodynamicQuantities/potential_energy']<jupyter_output><empty_output><jupyter_text>**GSD** stores all quantities in arrays.It stores scalar quantities such as the system potential energy in length 1 arrays (above) while it stores vector and other array quantities as appropriately sized arrays:<jupyter_code>traj[0].log['md/compute/ThermodynamicQuantities/pressure_tensor']<jupyter_output><empty_output><jupyter_text>**GSD** provides logged quantities individually at each frame in the file.You can convert this to time-series data with a loop and then plot or analyze it:<jupyter_code>timestep = []
walltime = []
potential_energy = []

for frame in traj:
    timestep.append(frame.configuration.step)
    walltime.append(frame.log['Simulation/walltime'][0])
    potential_energy.append(
        frame.log['md/compute/ThermodynamicQuantities/potential_energy'][0])
fig = matplotlib.figure.Figure(figsize=(10, 6.18))
ax = fig.add_subplot()
ax.plot(timestep, potential_energy)
ax.set_xlabel('timestep')
ax.set_ylabel('potential energy')
fig<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10136217948717949, 'fraction_numerical': 0.005341880341880342, 'mean_word_length': 6.270873786407767, 'pattern_counts': {'":': 0, '<': 69, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '17', 'dir': 'jupyter-structured-clean-dedup', 'id': '625208', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 2272, 'n_tokens_neox': 2196, 'n_words': 714, 'path': '02-Logging/01-Logging-to-a-GSD-file.ipynb', 'repo_name': 'glotzerlab/hoomd-examples', 'size': '7488'}