Troubleshooting OPS

We've tried to make OPS as easy to use as possible, and we hope that usually it "just works." But a mistyped letter in your input could make the results nonsensical, or you might find yourself coming across a situation that we hadn't considered. In that case you need to do some troubleshooting.

Because OPS is a framework, you have access to all the functions used internally by the code itself. Many of these can help you identify any problems in your setup.

To make this notebook work, let's first load some toy data from a notebook:


In [1]:
import openpathsampling as paths
# storage = 

# trajectory = storage.trajectory[0] 
# ensemble = 
# stateA = 
# stateB = 
# interface =

Does OPS see your trajectory the way it should?

You're pretty sure you gave OPS a trajectory that should be A to B, but it says otherwise. How do you figure out what's going on?

Checking whether a trajectory is in a given ensemble is easy:


In [2]:
# ensemble(trajectory)

Some ensembles implement the helper function .trajectory_summary(trajectory) to tell you a little about how they see your trajectory. That function returns a dictionary for later analysis, whereas .trajectory_summary_str(trajectory) returns a string.


In [3]:
# ensemble.trajectory_summary(trajectory)

In [4]:
# ensemble.trajectory_summary_str(trajectory)

If you define a dictionary of volumes, you can get a summary of the trajectory in terms of those volumes. This will tell you how which volume the trajectory is in, and for how many frames:


In [5]:
# trajectory.summarize_by_volumes({"A" : stateA, "B" : stateB, "I" : interface & ~stateA, "X" : ~interface & ~stateB})

Note: for the above, the volumes need to be disjoint, otherwise OPS can't assign each frame to a unique volume. For example, interfaces are defined so that the state is a subset of the interface. If a frame is in the state, then it is also in the interface: since it can't be assigned to a unique volume, the trajectory summary will raise an error. This can be handled with an "and not" construction, i.e., interface & ~state.

If the frame does not match any volume in your list, it returns None as the volume label.


In [6]:
# trajectory.summarize_by_volumes({"A" : stateA, "B" : stateB, "X" : ~interface & ~stateB})

If you want to see what values OPS assigns to collective variables for your trajectory, it is also straightforward to get that:


In [7]:
# cv(trajectory)

You can, of course, also look at the data in the trajectory directly. This little example consists of 2 atoms in 3D (although they are fixed to the $x$-axis, so $y=z=0$.) You can either see the data with simtk.units unit values attached by using trajectory.coordinates, or without by using trajectory.xyz. Each individual frame also has the same properties.


In [8]:
# trajectory.coordinates

In [9]:
# trajectory.xyz

In [10]:
# trajectory[5].coordinates

How does OPS see this object?

Maybe the ensemble isn't actually the ensemble you thought it was. How do you check that? To make it as easy as possible, we've implemented several methods to make a string out of objects in OPS.

The first approach, which is usually the most readable, is str(object) (which is also what you get from print object. If an object has a name, this will give that to you:


In [11]:
#print ensemble

All objects also have repr(object) function, which will usually give you output that is more code-like:


In [12]:
#repr(ensemble)

Some objects, such as Ensembles, have an additional function object.description(). This provides you with a longer (but still mostly human-readable) description of the object. For ensembles, this gives us a set-theory based description:


In [13]:
#ensemble.description()

Some objects have different levels of verbosity within their description() functions.

Finding other functions

Many standard tools can help you more fully explore to functions and features built into the objects in OpenPathSampling. Summary versions of the API are provided at ???. A detailed hyperlinked version of the API can be found at ???.

If using IPython, we recommend exploring the options given by autocomplete (hit TAB after type a object. for some object) or by ?object and the more detailed ??object. There are also the standard Python docstrings (print object.__doc__) and help (help(object)).

Altogether, these tools provide many ways to explore capabilities of OpenPathSampling.

Checking your simulation for red flags

If doing a custom move scheme, it is possible to set up your simulation in such a way that certain moves are never called, or that certain moves have 0% acceptance.

We created a "red flag" checker that will look over your simulation and warn you if anything like that seems weird. Of course, it can only check these things after you've run your simulation. However, we recommend always using it as a part of your analysis process:


In [14]:
# redflags = paths.analysis.RedFlags(storage)

Note that, because the checks in RedFlags include a lot of the actual analysis of your objects, checking for red flags first can take a while but means that much of the remaining analysis is cached.

The RedFlags class contains several functions to check various objects within the code; if you create the object without a storage associated, you can use those functions directly:


In [15]:
# subflags = paths.analysis.RedFlags()
# subflags.check_zero_acceptance(storage.pathmovers, storage.steps)

In [ ]: