gmx Python module reference

The Gromacs Python interface is implemented as a high-level scripting interface implemented in pure Python and a lower-level API implemented as a C++ extension. The pure Python implementation provides the basic gmx module and classes with a very stable syntax that can be maintained with maximal compatibility while mapping to lower level interfaces that may take a while to sort out. The separation also serves as a reminder that different execution contexts may be implemented quite diffently, though Python scripts using only the high-level interface should execute on all. Bindings to the libgromacs C++ API are provided in the submodule gmx.core.

The following documentation is extracted from the gmx Python module and is also available directly, using either pydoc from the command line or help() from within Python, such as during an interactive session.

Refer to the Python source code itself for additional clarification.

Procedural interface

gmx.run(work=None)[source]

Run the provided work on available resources.

Parameters:work (gmx.workflow.WorkSpec) – either a WorkSpec or an object with a workspec attribute containing a WorkSpec object.
Returns:run status.
Return type:gmx.status.Status
gmx.get_context(work=None)[source]

Get a concrete Context object.

Parameters:work (gmx.workflow.WorkSpec) – runnable work as a valid gmx.workflow.WorkSpec object
Returns:An object implementing the gmx.context.Context interface, if possible.
Raises:gmx.exceptions.ValueError if an appropriate context for work could not be loaded.

If work is provided, return a Context object capable of running the provided work or produce an error.

The semantics for finding Context implementations needs more consideration, and a more informative exception is likely possible.

A Context can run the provided work if

  • the Context supports can resolve all operations specified in the elements
  • the Context supports DAG topologies implied by the network of dependencies
  • the Context supports features required by the elements with the specified parameters, such as synchronous array jobs.
gmx.workflow.from_tpr(input=None, **kwargs)[source]

Create a WorkSpec from a (list of) tpr file(s).

Generates a work specification based on the provided simulation input and returns a handle to the MD simulation element of the workflow. Key word arguments can override simulation behavior from input.

If the MD operation discovers artifacts from a previous simulation that was launched from the same input, the simulation resumes from the last checkpointed step. If append_output is set False, existing artifacts are kept separate from new output with the standard file naming convention, and new output begins from the last checkpointed step, if any.

Setting end_time redefines the end point of the simulation trajectory from what was provided in input. It is equivalent to changing the number of steps requested in the MDP (or TPR) input, but it time is provided as picoseconds instead of a number of time steps.

Deprecated since version 0.0.7: If steps=N is provided and N is an integer greater than or equal to 1, the MD operation advances the trajectory by N steps, regardless of the number of simulation steps specified in input or end_time. For convenience, setting steps=None does not override input. Note that when it is not None, steps takes precedence over end_time and input, but can still be superceded by a signal, such as if an MD plugin or other code has a simulation completion condition that occurs before N additional steps have run.

Where key word arguments correspond to gmx mdrun command line options, the corresponding flags are noted below.

Keyword Arguments:
 
  • input (str) – Required string or list of strings giving the filename(s) of simulation input
  • append_output (bool) – Append output for continuous trajectories if True, truncate existing output data if False. (default True)
  • end_time (float) – Specify the final time in the simulation trajectory, overriding input read from TPR.
  • grid (tuple) – Domain decomposition grid divisions (nx, ny, nz). (-dd)
  • max_hours (float) – Terminate after 0.99 times this many hours if simulation is still running. (-maxh)
  • pme_ranks (int) – number of separate ranks to be used for PME electrostatics. (-npme)
  • pme_threads_per_rank (int) – Number of OpenMP threads per PME rank. (-ntomp_pme)
  • steps (int) – Override input files and run for this many steps. (-nsteps; deprecated)
  • threads (int) – Total number of threads to start. (-nt)
  • threads_per_rank (int) – number of OpenMP threads to start per MPI rank. (-ntomp)
  • tmpi (int) – number of thread-MPI ranks to start. (-ntmpi)
Returns:

simulation member of a gmx.workflow.WorkSpec object

Produces a WorkSpec with the following data:

version: gmxapi_workspec_0_1
elements:
    tpr_input:
        namespace: gromacs
        operation: load_tpr
        params: {'input': ['tpr_filename1', 'tpr_filename2', ...]}
    md_sim:
        namespace: gmxapi
        operation: md
        depends: ['tpr_input']
        params: {'kw1': arg1, 'kw2': arg2, ...}
Bugs: version 0.0.6
gmx.workflow.get_source_elements(workspec)[source]

Get an iterator of the starting nodes in the work spec.

Source elements have no dependencies and can be processed immediately. Elements with dependencies cannot be processed, instantiated, or added to a work spec until after their dependencies have been.

Parameters:workspec – an existing work specification to analyze, such as by a Context implementation preparing to schedule work.
Returns:iterator of gmx.workflow.WorkElement objects that may be processed without dependencies.

This function is provided in the API to allow flexibility in how source elements are determined.

gmx.version.api_is_at_least(major_version, minor_version=0, patch_version=0)[source]

Allow client to check whether installed module supports the requested API level.

Parameters:
  • major_version (int) – gmxapi major version number.
  • minor_version (int) – optional gmxapi minor version number (default: 0).
  • patch_version (int) – optional gmxapi patch level number (default: 0).
Returns:

True if installed gmx package is greater than or equal to the input level

Note that if gmx.version.release is False, the package is not guaranteed to correctly or fully support the reported API level.

Python API

Python context managers

Objects implementing the Context interfaces defined in gmx.context implement the Python context manager protocol. When used in a with block, a Context produces a Session object. See examples below.

Note

Session is not well specified in gmxapi 0.0.6.

gmx.fileio module

Provide the high-level interface to the file i/o behaviors the gmx package.

The submodule name may seem longer than necessary, but avoids a namespace collision with a standard Python module on the default path.

class gmx.fileio.TprFile(filename=None, mode=None)[source]

Handle to a Gromacs simulation run input file.

Open a TPR file.

File access mode is indicated by ‘r’ for read-only access.

Parameters:
  • filename (str) – Path to a run input file (e.g. ‘myfile.tpr’)
  • mode (str) – File access mode.

Note

Currently, TPR files are read-only from the Python interface.

Example

>>> import gmx
>>> filehandle = gmx.fileio.TprFile(filename, 'r')
gmx.fileio.read_tpr(tprfile=None)[source]

Get a simulation input object from a TPR run input file.

Parameters:tprfile – TPR input object or filename
Returns:simulation input object

The returned object may be inspected by the user. Simulation input parameters may be extracted through the parameters attribute.

Example

>>> sim_input = gmx.fileio.read_tpr(tprfile=tprfilename)
>>> params = sim_input.parameters.extract()
>>> print(params['init-step'])
0

Supports the read_tpr gmxapi work graph operation. (not yet implemented)

gmx.fileio.write_tpr_file(output, input=None)[source]

Create a new TPR file, combining user-provided input.

New in version 0.0.8: Initial version of this tool does not know how to generate a valid simulation run input file from scratch, so it requires input derived from an already valid TPR file.

The simulation input object should provide the gmx simulation_input interface, with output ports for parameters, structure, topology, and state, such as a TprFileHandle

Parameters:
  • output – TPR file name to write.
  • input – simulation input data from which to write a simulation run input file.

Use this function to write a new TPR file with data updated from an existing TPR file. Keyword arguments are objects that can provide gmxapi compatible access to the necessary simulation input data.

In the initial version, data must originate from an existing TPR file, and only simulation parameters may be rewritten. See gmx.fileio.read_tpr()

Example

>>> sim_input = gmx.fileio.read_tpr(tprfile=tprfilename)
>>> sim_input.parameters.set('init-step', 1)
>>> gmx.fileio.write_tpr_file(newfilename, input=sim_input)

Warning

The interface is in flux.

Todo

Be consistent about terminology for “simulation state”. We are currently using “simulation state” to refer both to the aggregate of data (superset) necessary to launch or continue a simulation _and_ to the extra data (subset) necessary to capture full program state, beyond the model/method input parameters and current phase space coordinates. Maybe we shouldn’t expose that as a separate user-accessible object and should instead make it an implementation detail of a wrapper object that has standard interfaces for the non-implementation-dependent encapsulated data.

Returns:possibly a completion condition of some sort and/or handle to the new File
Return type:TBD

gmx.context module

Execution Context

class gmx.context.Context(work=None, workdir_list=None, communicator=None)[source]

Manage an array of simulation work executing in parallel.

This is the first implementation of a new style of Context class that has some extra abstraction and uses the new WorkSpec idea.

Additional facilities are available to elements of the array members.

  • array element corresponding to work in the current sub-context
  • “global” resources managed by the ParallelArrayContext
work :obj:`gmx.workflow.WorkSpec`

specification of work to be performed when a session is launched.

rank

numerical index of the current worker in a running session (None if not running)

work_width

Minimum width needed for the parallelism required by the array of work being executed.

elements

dictionary of references to elements of the workflow.

rank, work_width, and elements are empty or None until the work is processed, as during session launch.

Example

Use mpiexec -n 2 python -m mpi4py myscript.py to run two jobs at the same time. In this example the jobs are identical. In myscript.py:

>>> import gmx
>>> import gmx.core
>>> from gmx.data import tpr_filename # Get a test tpr filename
>>> work = gmx.workflow.from_tpr([tpr_filename, tpr_filename])
>>> gmx.run(work)

Example

>>> import gmx
>>> import gmx.core
>>> from gmx.data import tpr_filename # Get a test tpr filename
>>> work = gmx.workflow.from_tpr([tpr_filename, tpr_filename])
>>> context = gmx.context.get_context(work)
>>> with context as session:
...    session.run()
...    # The session is one abstraction too low to know what rank it is. It lets the spawning context manage
...    # such things.
...    # rank = session.rank
...    # The local context object knows where it fits in the global array.
...    rank = context.rank
...    output_path = os.path.join(context.workdir_list[rank], 'traj.trr')
...    assert(os.path.exists(output_path))
...    print('Worker {} produced {}'.format(rank, output_path))

Implementation notes:

To produce a running session, the Context __enter__() method is called, according to the Python context manager protocol. At this time, the attached WorkSpec must be feasible on the available resources. To turn the specified work into an executable directed acyclic graph (DAG), handle objects for the elements in the work spec are sequenced in dependency-compatible order and the context creates a “builder” for each according to the element’s operation. Each builder is subscribed to the builders of its dependency elements. The DAG is then assembled by calling each builder in sequence. A builder can add zero, one, or more nodes and edges to the DAG.

The Session is then launched from the DAG. What happens next is implementation-dependent, and it may take a while for us to decide whether and how to standardize interfaces for the DAG nodes and edges and/or execution protocols. I expect each node will at least have a launch() method, but will also probably have typed input and output ports as well as some signalling. A sophisticated and abstract Session implementation could schedule work only to satisfy data dependencies of requested output upon request. Our immediate implementation will use the following protocol.

Each node has a launch() method. When the session is entered, the launch() method is called for each node in dependency order. The launch method returns either a callable (run() function) or None, raising an exception in case of an error. The sequence of non-None callables is stored by the Session. When Session.run() is called, the sequence of callables is called in order. If StopIteration is raised by the callable, it is removed from the sequence. The sequence is processed repeatedly until there are no more callables.

Note that this does not rigorously handle races or deadlocks, or flexibility in automatically chasing dependencies. A more thorough implementation could recursively call launch on dependencies (launch could be idempotent or involve some signalling to dependents when complete), run calls could be entirely event driven, and/or nodes could “publish” output (including just a completion message), blocking for acknowledgement before looking for the next set of subscribed inputs.

Create manager for computing resources.

Does not initialize resources because Python objects by themselves do not have a good way to deinitialize resources. Instead, resources are initialized using the Python context manager protocol when sessions are entered and exited.

Appropriate computing resources need to be knowable when the Context is created.

Keyword Arguments:
 
  • work – work specification with which to initialize this context
  • workdir_list – deprecated
  • communicator – non-owning reference to a multiprocessing communicator

If provided, communicator must implement the mpi4py.MPI.Comm interface. The Context will use this communicator as the parent for subcommunicators used when launching sessions. If provided, communicator is owned by the caller, and must be freed by the caller after any sessions are closed. By default, the Context will get a reference to MPI_COMM_WORLD, which will be freed when the Python process ends and cleans up its resources. The communicator stored by the Context instance will not be used directly, but will be duplicated when launching sessions using with.

add_operation(namespace, operation, get_builder)[source]

Add a builder factory to the operation map.

Extends the known operations of the Context by mapping an operation in a namespace to a function that returns a builder to process a work element referencing the operation. Must be called before the work specification is added, since the spec is inspected to confirm that the Context can run it.

It may be more appropriate to add this functionality to the Context constructor or as auxiliary information in the workspec, or to remove it entirely; it is straight-forward to just add snippets of code to additional files in the working directory and to make them available as modules for the Context to import.

Example

>>> # Import some custom extension code.
>>> import myplugin
>>> myelement = myplugin.new_element()
>>> workspec = gmx.workflow.WorkSpec()
>>> workspec.add_element(myelement)
>>> context = gmx.context.ParallelArrayContext()
>>> context.add_operation(myelement.namespace, myelement.operation, myplugin.element_translator)
>>> context.work = workspec
>>> with get_context() as session:
...    session.run()
ensemble_update(send, recv, tag=None)[source]

Implement the ensemble_update member function that gmxapi through 0.0.6 expects.

Depends on gmx.status, gmx.exceptions, gmx.workflow

gmx.exceptions module

Exceptions and Warnings raised by gmx module operations

Errors, warnings, and other exceptions used in the Gromacs gmx Python package are defined in the gmx.exceptions submodule.

The Gromacs gmx Python package defines a root exception, gmx.exceptions.Error, from which all Exceptions thrown from within the module should derive. If a published component of the gmx package throws an exception that cannot be caught as a gmx.exceptions.Error, please report the bug.

exception gmx.exceptions.Error[source]

Base exception for gmx.exceptions classes.

exception gmx.exceptions.ApiError[source]

An API operation was attempted with an incompatible object.

exception gmx.exceptions.CompatibilityError[source]

An operation or data is incompatible with the current gmxapi environment.

exception gmx.exceptions.FeatureNotAvailableError[source]

Feature is not installed, is missing dependencies, or is not compatible.

exception gmx.exceptions.FeatureNotAvailableWarning[source]

Feature is not installed, is missing dependencies, or is not compatible.

exception gmx.exceptions.FileError[source]

Problem with a file or filename.

exception gmx.exceptions.TypeError(got=None, expected=None)[source]

An object is of a type incompatible with the API operation.

exception gmx.exceptions.UsageError[source]

Unsupported syntax or call signatures.

Generic usage error for Gromacs gmx module.

exception gmx.exceptions.ValueError[source]

A user-provided value cannot be interpreted or doesn’t make sense.

gmx.status module

class gmx.status.Status(success=True)[source]

Status for API operation.

As of gmxapi 0.0.6, there is not a clear mapping between gmx.status.Status and gmx.core.Status.

Reference https://github.com/kassonlab/gmxapi/issues/121

gmx.system module

class gmx.system.System[source]

Gromacs simulation system objects. (Deprecated)

Deprecated since version 0.0.7: Instead, use gmx.workflow tools to set up a system for simulation.

Version 0.0.6 and earlier:

A System object connects all of the objects necessary to describe a molecular system to be simulated.

Once a system is created, objects can be attached or edited, accessed through the following properties.

workflow

element of work to be executed.

Example

>>> my_sim = gmx.System._from_file(tpr_filename)
>>> status = my_sim.run()

Example

>>> my_sim = gmx.System._from_file(tpr_filename)
>>> # Launch exectution of the runner and work on available resources.
>>> with gmx.context.DefaultContext(system) as session:
...     # Run the work specified in the TPR file
...     session.run()
...     # Extend the simulation and run an additional 1000 steps.
...     # (version 0.1.0)
...     #status = session.run(1000)
...     print(status)
...
gmx.Status(True)
Success
run(parameters=None)[source]

Launch execution.

If the System is attached to a Context, the Context is initialized, if necessary, and its instance run() method is called. If there is not yet a Context, one is created and then used.

Note: currently always initializes new context informed by the runner.

Parameters:parameters – optional parameters to pass to runner. Parameter type varies by runner type.
Returns:Gromacs status object.

gmx.version module

Provide version and release information.

gmx.version.major

gmxapi major version number.

Type:int
gmx.version.minor

gmxapi minor version number.

Type:int
gmx.version.patch

gmxapi patch level number.

Type:int
gmx.version.release

True if imported gmx module is an officially tagged release, else False.

Type:bool
gmx.version.api_is_at_least(major_version, minor_version=0, patch_version=0)[source]

Allow client to check whether installed module supports the requested API level.

Parameters:
  • major_version (int) – gmxapi major version number.
  • minor_version (int) – optional gmxapi minor version number (default: 0).
  • patch_version (int) – optional gmxapi patch level number (default: 0).
Returns:

True if installed gmx package is greater than or equal to the input level

Note that if gmx.version.release is False, the package is not guaranteed to correctly or fully support the reported API level.

gmx.workflow module

Provide workflow-level utilities and classes

Single-sim example:

>>> md = gmx.workflow.from_tpr(filename)
>>> gmx.run(md)
>>>
>>> # The above is shorthand for
>>> md = gmx.workflow.from_tpr(filename)
>>> with gmx.get_context(md.workspec) as session:
...    session.run()

Array sim example:

>>> md = gmx.workflow.from_tpr([filename1, filename2])
>>> gmx.run(md)

The representation of work and the way it is dispatched are areas of active development. See also https://github.com/kassonlab/gmxapi/milestone/3

class gmx.workflow.WorkSpec[source]

Container of workflow elements with data dependency information and requirements for execution.

An element cannot be added to a WorkSpec if it has dependencies that are not in the WorkSpec.

Work is added to the specification by passing a WorkElement object to WorkSpec.add_element(). Any dependencies in the WorkElement must already be specified in the target WorkSpec.

When iterated over, a WorkSpec object returns WorkElement objects. WorkElement objects are yielded in a valid order to keep dependencies satisfied, but not necessarily the same order in which add_element() calls were originally made. In other words, the WorkSpec is a directed acyclic dependency graph, and its iterator returns nodes in an arbitrary but topologically correct order.

The string representation of a WorkSpec object is a valid JSON serialized data object.

The schema for version 0.1 of the specification allows data structures like the following.

{
    'version': 'gmxapi_workspec_0_1',
    'elements':
    {
        'myinput':
        {
            'namespace': 'gromacs',
            'operation': 'load_tpr',
            'params': {'input': ['tpr_filename1', 'tpr_filename2']}
        },
        'mydata':
        {
            'namespace': 'gmxapi',
            'operation': 'open_global_data_with_barrier',
            'params': ['data_filename']
        },
        'mypotential':
        {
            'namespace': 'myplugin',
            'operation': 'create_mdmodule',
            'params': {...},
            'depends': ['mydata']
        },
        'mysim':
        {
            'namespace': 'gmxapi',
            'operation': 'md',
            'depends': ['myinput', 'mypotential']
        }
    }
}

The first mapping (version) is required as shown. The elements map contains uniquely named elements specifying an operation, the operation’s namespace, and parameters and dependencies of the operation for this element. depends is a sequence of string names of elements that are also in the work spec. params is a key-value map with string keys and values that are valid JSON data. namespace and operation are strings that the Context can map to directors it uses to construct the session. Namespace gmxapi is reserved for operations specified by the API. Namespace gromacs is reserved for operations implemented as GROMACS adapters (versioned separately from gmxapi). The period character (“.”) has special meaning and should not be used in naming elements, namespaces, or operations.

add_element(element)[source]

Add an element to a work specification if possible.

Adding an element to a WorkSpec must preserve the validity of the workspec, which involves several checks. We do not yet check for element uniqueness beyond a string name.

If an element is added that was previously in another WorkSpec, it must first be removed from the other WorkSpec.

serialize()[source]

Serialize the work specification in a form suitable to pass to any Context implementation.

Serialization is performed with the JSON data serialization module.

To simplify unique identification of work specifications, this function will also impose rules for reproducibility.

  1. All key-value maps are sorted alphanumerically by their string keys.
  2. Strings must consist of valid ASCII characters.
  3. Output is a byte sequence of the utf-8 encoded densely formatted JSON document.
Returns:unicode object in Python 2, bytes object in Python 3

Output of serialize() should be explicitly converted to a string before passing to a JSON deserializer.

>>> my_object = my_workspec.serialize()
>>> my_data_structure = json.loads(my_object.decode('utf-8'))
>>> # or...
>>> my_data_structure = json.loads(my_object, encoding='utf-8')
uid()[source]

Get a unique identifier for this work specification.

Returns:hash value

Generate a cryptographic hash of this work specification that is guaranteed to match that of another equivalent work specification. The returned string is a 64-character hexadecimal encoded SHA-256 hash digest of the serialized WorkSpec.

The definition of equivalence is likely to evolve, but currently means a work spec of the same version with the same named elements containing the same operations, dependencies, and parameters, as represented in the serialized version of the work specification. Note that this does not include checks on the actual contents of input files or anything that does not appear in the work specification directly. Also, the hash is lossy, so it is remotely conceivable that two specs could have the same hash. The work specs should be compared before making any expensive decisions based on work spec equivalence, such as with hash(workspec).

Element names probably shouldn’t be included in the unique identifying information (so that we can optimize out duplicated artifacts), but they are. A future API specification may add unique identification to the elements…

class gmx.workflow.WorkElement(namespace='gmxapi', operation=None, params=None, depends=())[source]

Encapsulate an element of a work specification.

add_dependency(element)[source]

Add another element as a dependency.

First move the provided element to the same WorkSpec, if not already here. Then, add to depends and update the WorkSpec.

classmethod deserialize(input, name=None, workspec=None)[source]

Create a new WorkElement object from a serialized representation.

Parameters:
  • input – a serialized WorkElement
  • name – new element name (optional) (deprecated)
  • workspec – an existing workspec to attach this element to (optional)

When subclasses become distinct, this factory function will need to do additional dispatching to create an object of the correct type. Alternatively, instead of subclassing, a slightly heavier single class may suffice, or more flexible duck typing might be better.

serialize()[source]

Create a byte sequence representation of the work element.

The WorkElement class exists just to provide convenient handles in Python. The WorkSpec is not actually a container of WorkElement objects.

Returns:Byte sequence of utf-8 encoded JSON document. May need to be decoded if needed as a (Unicode) string.

Depends on gmx.exceptions, gmx.util

Core API

Gromacs core module

gmx.core provides Python access to the Gromacs C++ API so that client code can be implemented in Python, C++, or a mixture. The classes provided are mirrored on the C++ side in the gmxapi namespace.

This documentation is generated from docstrings exported by C++ extension code.

Functions

gmx.core.from_tpr(arg0: str) → gmx.core.MDSystem

Return a system container initialized from the given input record.

Classes

class gmx.core.Context(self: gmx.core.Context) → None

Create a default execution context.

add_mdmodule(self: gmx.core.Context, arg0: object) → None

Add an MD plugin for the simulation.

setMDArgs(self: gmx.core.Context, arg0: gmx.core.MDArgs) → None

Set MD runtime parameters.

class gmx.core.MDArgs(self: gmx.core.MDArgs) → None

Create an empty MDArgs object.

set(self: gmx.core.MDArgs, arg0: dict) → None

Assign parameters in MDArgs from Python dict.

class gmx.core.MDSession
close(self: gmx.core.MDSession) → gmx.core.Status

Shut down the execution environment and close the session.

run(self: gmx.core.MDSession) → gmx.core.Status

Run the simulation workflow

class gmx.core.MDSystem
launch(self: gmx.core.MDSystem, arg0: gmx.core.Context) → gmx.core.MDSession

Launch the configured workflow in the provided context.

class gmx.core.Status

Holds status for API operations.

class gmx.core.TestModule(self: gmx.core.TestModule) → None

Test module…