Executing Simulations¶
Overview¶
Questions¶
How can I execute a series of workflow steps on many simulations?
Objectives¶
Introduce workflows.
Demonstrate how to use signac-flow to define workflow steps and their associated pre-conditions and post-conditions.
Execute the workflow to randomize and compress all state points in the data space.
Boilerplate Code¶
[1]:
import math
import hoomd
Workflow Steps¶
The Introducing HOOMD-blue tutorial employs distinct workflow steps that must be performed in sequence to complete the self-assembly study at a given state point. These are initialization, randomization, compression, equilibration, and analysis. The previous section in this tutorial initialized every state point in the data space. This section will randomize and compress them and the next section will equilibrate them. Analysis can also be implemented as a workflow step, but this is left as an exercise for the reader.
Use signac-flow to define these workflow steps as Python functions and execute them in the proper sequence on all state points in the data space.
[2]:
import flow
Define a function that creates a Simulation object based on the signac job:
[3]:
def create_simulation(job):
cpu = hoomd.device.CPU()
# Set the simulation seed from the statepoint.
simulation = hoomd.Simulation(device=cpu, seed=job.statepoint.seed)
mc = hoomd.hpmc.integrate.ConvexPolyhedron()
mc.shape["octahedron"] = dict(
vertices=[
(-0.5, 0, 0),
(0.5, 0, 0),
(0, -0.5, 0),
(0, 0.5, 0),
(0, 0, -0.5),
(0, 0, 0.5),
]
)
simulation.operations.integrator = mc
return simulation
This is the code from Introducing HOOMD-blue, adapted to use the seed for the current signac job with job.statepoint.seed
.
Subclass FlowProject by convention.
[4]:
class Project(flow.FlowProject):
pass
Define a function that executes the randomization step:
[5]:
@Project.pre.true("initialized") # Pre-condition in job document.
@Project.post.true("randomized") # Post-condition in job document.
@Project.operation # Workflow step.
def randomize(job):
simulation = create_simulation(job)
# Read `lattice.gsd` from the signac job's directory.
simulation.create_state_from_gsd(filename=job.fn("lattice.gsd"))
simulation.run(10e3)
# Write `random.gsd` to the signac job's directory.
hoomd.write.GSD.write(
state=simulation.state, mode="xb", filename=job.fn("random.gsd")
)
# Set the 'randomized' to satisfy the post-condition.
job.document["randomized"] = True
In signac-flow’s terminology, a project operation is a complete workflow step that modifies the signac job’s state. Recall that the similarly named HOOMD-blue Operation is a class that acts on the state of the simulation at defined time steps. This tutorial uses the term workflow step wherever possible to avoid ambiguity.
@Project.operation
is a decorator that declares the randomize function is a workflow step. @Project.pre
and @Project.post
define pre-conditions and post-conditions for this step, which return a boolean to indicate whether a workflow step is ready to start (pre-condition) or complete (post-condition). In this block, both conditions are evaluated by pre.true
and post.true
which examine the job document and check whether the item with the given key
evaluates to True
. Use pre- and post-conditions to define the sequence in which the workflow steps will execute. Here, the pre-condition checking 'initialized'
is satisfied for those signac jobs that were initialized in the previous section which set job.document['initialize'] = True
.
The body of the function creates the Simulation object using the create_simulation
method from above, completes the randomization as in the Introducing HOOMD-blue tutorial, and sets the 'randomized'
item in the job document to True
. The function writes randomized.gsd
to the signac job’s assigned directory using the job.fn
method.
Similarly define a function that executes the compression step:
[6]:
@Project.pre.after(randomize) # Execute after randomize completes.
@Project.post.true("compressed_step")
@Project.operation
def compress(job):
simulation = create_simulation(job)
# Read `random.gsd` from the signac job directory.
simulation.create_state_from_gsd(filename=job.fn("random.gsd"))
a = math.sqrt(2) / 2
V_particle = 1 / 3 * math.sqrt(2) * a**3
initial_box = simulation.state.box
final_box = hoomd.Box.from_box(initial_box)
# Set the final box volume to the volume fraction for this signac job.
final_box.volume = (
simulation.state.N_particles * V_particle / job.statepoint.volume_fraction
)
compress = hoomd.hpmc.update.QuickCompress(
trigger=hoomd.trigger.Periodic(10), target_box=final_box
)
simulation.operations.updaters.append(compress)
periodic = hoomd.trigger.Periodic(10)
tune = hoomd.hpmc.tune.MoveSize.scale_solver(
moves=["a", "d"],
target=0.2,
trigger=periodic,
max_translation_move=0.2,
max_rotation_move=0.2,
)
simulation.operations.tuners.append(tune)
while not compress.complete and simulation.timestep < 1e6:
simulation.run(1000)
if not compress.complete:
message = "Compression failed to complete."
raise RuntimeError(message)
# Write `compressed.gsd` to the job document.
hoomd.write.GSD.write(
state=simulation.state, mode="xb", filename=job.fn("compressed.gsd")
)
# Set 'compressed step' in the signac job document.
job.document["compressed_step"] = simulation.timestep
This workflow step executes after the randomize step completes using the pre.after(randomize)
pre-condition. The body of the function contains the code from the Introducing HOOMD-blue tutorial, changed to use the volume fraction for the current signac job with job.statepoint.volume_fraction
and to read and write files from the signac job’s directory with job.fn
.
The compress operation sets the compressed_step
item in the job document and uses that to evaluate the post-condition. The next section of the tutorial will use the value of compressed_step
.
Run the Workflow¶
Now that you have defined the workflow steps, check the status of the workflow:
[7]:
project = Project()
project.print_status(
overview=False, detailed=True, hide_progress=True, parameters=["volume_fraction"]
)
Detailed View:
job id operation/group volume_fraction labels
-------------------------------- ----------------- ----------------- --------
59363805e6f46a715bc154b38dffc4e4 randomize [U] 0.6
972b10bd6b308f65f0bc3a06db58cf9d randomize [U] 0.4
c1a59a95a0e8b4526b28cf12aa0a689e randomize [U] 0.5
[U]:unknown [R]:registered [I]:inactive [S]:submitted [H]:held [Q]:queued [A]:active [E]:error [GR]:group_registered [GI]:group_inactive [GS]:group_submitted [GH]:group_held [GQ]:group_queued [GA]:group_active [GE]:group_error
Each signac job is ready to execute randomize, the first step in the workflow. Run it:
[8]:
project.run(names=["randomize"])
Every signac job directory in the data space now has a random.gsd
file produced by randomize:
[9]:
!ls workspace/*
workspace/59363805e6f46a715bc154b38dffc4e4:
lattice.gsd signac_job_document.json
random.gsd signac_statepoint.json
workspace/972b10bd6b308f65f0bc3a06db58cf9d:
lattice.gsd signac_job_document.json
random.gsd signac_statepoint.json
workspace/c1a59a95a0e8b4526b28cf12aa0a689e:
lattice.gsd signac_job_document.json
random.gsd signac_statepoint.json
Now, the status shows that the compress step is ready:
[10]:
project.print_status(
overview=False, detailed=True, hide_progress=True, parameters=["volume_fraction"]
)
Detailed View:
job id operation/group volume_fraction labels
-------------------------------- ----------------- ----------------- --------
59363805e6f46a715bc154b38dffc4e4 compress [U] 0.6
972b10bd6b308f65f0bc3a06db58cf9d compress [U] 0.4
c1a59a95a0e8b4526b28cf12aa0a689e compress [U] 0.5
[U]:unknown [R]:registered [I]:inactive [S]:submitted [H]:held [Q]:queued [A]:active [E]:error [GR]:group_registered [GI]:group_inactive [GS]:group_submitted [GH]:group_held [GQ]:group_queued [GA]:group_active [GE]:group_error
Execute it:
[11]:
project.run(names=["compress"])
Every signac job directory in the data space now has a compressed.gsd
file produced by compress:
[12]:
!ls workspace/*
workspace/59363805e6f46a715bc154b38dffc4e4:
compressed.gsd random.gsd signac_statepoint.json
lattice.gsd signac_job_document.json
workspace/972b10bd6b308f65f0bc3a06db58cf9d:
compressed.gsd random.gsd signac_statepoint.json
lattice.gsd signac_job_document.json
workspace/c1a59a95a0e8b4526b28cf12aa0a689e:
compressed.gsd random.gsd signac_statepoint.json
lattice.gsd signac_job_document.json
Summary¶
In this section of the tutorial, you defined the workflow steps to randomize and compress the initial configuration using signac-flow, along with the pre- and post-conditions needed to sequence the steps. Then you executed the workflow steps on all state points in the dataset. The directory for each simulation now contains compressed.gsd
and is ready for equilibration at the target volume fraction.
The next section in this tutorial teaches you how to write a workflow step that can continue itself and complete over several submissions.
This tutorial only teaches the basics of signac-flow. Read the signac-flow documentation to learn more.