Writing Formatted Output#
Overview#
Questions#
How do I display status information during a simulation?
How can I log user-defined quantities?
How can I write formatted output to a text file?
Objectives#
Demonstrate user-defined log quantities.
Explain the use of Table to display status information during a simulation run.
Show that Table can write to a file.
Boilerplate code#
[1]:
import datetime
import hoomd
Define the Simulation#
This tutorial executes the Lennard-Jones particle simulation from a previous tutorial. See Introducing Molecular Dyamics for a complete description of this code.
[3]:
cpu = hoomd.device.CPU()
simulation = hoomd.Simulation(device=cpu, seed=1)
simulation.create_state_from_gsd(
filename='../01-Introducing-Molecular-Dynamics/random.gsd')
integrator = hoomd.md.Integrator(dt=0.005)
cell = hoomd.md.nlist.Cell(buffer=0.4)
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.ConstantVolume(
filter=hoomd.filter.All(),
thermostat=hoomd.md.methods.thermostats.Bussi(kT=1.5))
integrator.methods.append(nvt)
simulation.operations.integrator = integrator
Formatted output#
The Table writer formats log quantities in human-readable text and writes them to stdout
or a file. Table only supports scalar
and string
quantities due to the limitations of this format. This section shows you how to use Table to display status information during a simulation run.
Add quantities to a Logger#
The categories
argument to Logger defines the categories that it will accept.
[4]:
logger = hoomd.logging.Logger(categories=['scalar', 'string'])
Log the and simulation timestep
and tps
quantities:
[5]:
logger.add(simulation, quantities=['timestep', 'tps'])
You can also log user-defined quantities using functions, callable class instances, or class properties. For example, this class computes the estimated time remaining:
[6]:
class Status():
def __init__(self, simulation):
self.simulation = simulation
@property
def seconds_remaining(self):
try:
return (self.simulation.final_timestep
- self.simulation.timestep) / self.simulation.tps
except ZeroDivisionError:
return 0
@property
def etr(self):
return str(datetime.timedelta(seconds=self.seconds_remaining))
Assign the loggable quantity using the tuple (object, property_name, flag)
, where flag
is the string name of the flag for this quantity. (The tuple for callable objects would be (callable, flag)
).
[7]:
status = Status(simulation)
logger[('Status', 'etr')] = (status, 'etr', 'string')
Represent the namespace of your user-defined quantity with a tuple of strings - ('Status', 'etr'
) above. You can use any number of arbitrary strings in the tuple to name your quantity.
Display quantities with Table#
Table is a Writer that formats the quantities in a Logger into a human readable table. Create one that triggers periodically:
[8]:
table = hoomd.write.Table(trigger=hoomd.trigger.Periodic(period=5000),
logger=logger)
Add it to the simulation:
[9]:
simulation.operations.writers.append(table)
Run the simulation and see the output:
[10]:
simulation.run(100000)
Simulation.timestep Simulation.tps Status.etr
15000 7265.44980 0:00:13.075584
20000 7928.10708 0:00:11.352016
25000 8212.82940 0:00:10.349661
30000 8347.23914 0:00:09.584007
35000 8415.05520 0:00:08.912598
40000 8442.75984 0:00:08.291128
45000 8493.75873 0:00:07.652678
50000 8532.47563 0:00:07.031957
55000 8563.96280 0:00:06.422260
60000 8571.47951 0:00:05.833299
65000 8598.56480 0:00:05.233432
70000 8627.01996 0:00:04.636595
75000 8636.41757 0:00:04.052606
80000 8647.71201 0:00:03.469126
85000 8653.31308 0:00:02.889067
90000 8664.12848 0:00:02.308368
95000 8659.11603 0:00:01.732278
100000 8663.85839 0:00:01.154220
105000 8670.02276 0:00:00.576700
110000 8674.88580 0:00:00
Later in this notebook, you are going to create another Table Writer. Remove table
now to avoid confusing the two:
[11]:
simulation.operations.writers.remove(table)
Save Table output to a file#
Table writes to stdout
by default. It can write to a file (or any Python file-like object with write
and flush
methods) instead.
Open the file to write:
[12]:
file = open('log.txt', mode='x', newline='\n')
Create a Table Writer that outputs to this file and add it to the Simulation:
[13]:
table_file = hoomd.write.Table(output=file,
trigger=hoomd.trigger.Periodic(period=5000),
logger=logger)
simulation.operations.writers.append(table_file)
Run the simulation:
[14]:
simulation.run(100000)
You can read the file with standard tools:
[15]:
!tail log.txt
165000 8794.29467 0:00:05.116954
170000 8809.97435 0:00:04.540308
175000 8808.18898 0:00:03.973575
180000 8803.84588 0:00:03.407602
185000 8793.11174 0:00:02.843135
190000 8808.44379 0:00:02.270549
195000 8812.89983 0:00:01.702050
200000 8815.85406 0:00:01.134320
205000 8819.50353 0:00:00.566925
210000 8823.62751 0:00:00
In this section, you have displayed loggable quantities during a simulation run and saved them to a text file. This is the last section in the logging tutorial.