openpathsampling / openpathsampling

An open source Python framework for transition interface and path sampling calculations.
http://openpathsampling.org
MIT License
104 stars 47 forks source link

On "MultiMovers" (this is a long one….) #108

Closed dwhswenson closed 9 years ago

dwhswenson commented 9 years ago

(Note: I wrote all of this a couple weeks ago, and kept forgetting to post it. JHP, please take a look, and let me know what you think of the move_path attribute, whether it'll cause problems for storage: I think there's a problem there we need to solve, but I'm open to other solutions.)

Highlights

The main thing I need is advice from @jhprinz on whether this Sample.details.move_path will be a pain to add to storage.

If you see any holes in this implementation, let me know, but I think it will allow us to quickly add new move schemes in the future. It’s currently being implemented in the branch for PR #106.


As I’ve been putting together the framework for PathMovers in general, I’ve been thinking about the fact that many of our more interesting moves in path space can be described as some combination of more elementary moves. This is much the same as how our Ensembles are made of particular combinations of other the elementary ensembles.

So the questions I’ve been working on answering are:

For the first two, we’re fine if the answers are only partially complete. In fact, I’m not planning to implement some parts of this. But we do want to correctly anticipate best way to handle the last one.

The Move Tree

Before diving into the specifics, let me introduce the general idea of the move tree. The basic idea is that we typically have a decision tree to select which PathMover will generate Samples for this step in the Monte Carlo. For example, perhaps you first choose a replica exchange out of the list of shooting, replica exchange, minus move, or path reversal. Then you have to choose a specific replica exchange pair to use.

In order to make this sort of process as flexible as possible, we use the idea of the move tree. In general (at least with PathSampling approaches) we’ll have a root_mover which leads to the whole tree.

The point is that we need to, in some way, record the move tree path that led to generating a specific Sample. In fact, I’d argue that the Sample should be labelled as generated by the move tree path, not just by a given mover (in fact, JHP already added something to this effect by having MixedMover modify the sample.details -- what I propose here is to generalize and complete that).

Some moves also consist of several sequential submoves. That’s also handled in this discussion.

Elementary Moves

I don’t claim that this list is exhaustive, but here are a few of the moves I have identified as elementary. We may add others as we go along:

I think that a number of other moves (e.g., StateSwap) are just special cases of ReplicaExchange or EnsembleHop. A few sections below, I’ll show that OneWayShooting and MinusMove can be described using these elementary moves and the combination tools I describe in the next section.

It’s possible that 2-way shooting can be implemented as a combination move. I’d prefer that, although I haven’t thought out all the details of what would be needed to make that happen.

MultiMovers: Combining other moves

We need various ways to combine these moves to give the overall behavior we want. I’ve identified 5 such combinations; there may be others to be made. I describe each as a move consisting of submoves.

As discussed in #104, we could either make moves like these as pseudoclasses (i.e., offer convenience functions that construct them, but don’t actually have a class named, for example, OneWayShooting) or we can make actual classes which are mostly subclasses with different __init__ functions. I prefer the latter, because I think it will make analysis easier, and it may make fancier moves possible as well. Advanced users can always use either approach to create their own moves.

One-Way Shooting

Subclass of MixedMover, consisting of ForwardShootingMover and BackwardShootingMover, both using the same ShootingPointSelector. This is, indeed, how we’ve already implemented this.

Minus Move

Subclass of MixedMover, consisting of ForwardMinusMover and BackwardMinusMover. Each of those are, in turn, subclasses of ConditionalSequentialMover. The submoves of those ConditionalSequentialMovers are a replica exchange move followed by a shooting move (which selects the endpoint as the shooting point).

Managing MoveDetails

One part that gets tricky is that we now have to manage all the details of this information in the MoveDetails object. My suggestion is to replace the MoveDetails.mover object with a list, MoveDetails.mover_path, which consists of 2-tuples of (mover_ID, accepted) for each of the moves in the move tree path that led to this sample. MoveDetails.accepted is true if and only if all moves in the tree path were accepted.

This allows us to easily analyze acceptance ratios (which give us the first sign of problems) from many different angles: by starting with a move that includes all shooting moves, we can get the overall shooting accepted. Then we can drill down to see the acceptance for each individual replica. Then we can drill even further down to see how forward/backward shooting acceptance ratios differ for each replica.

To make this work, we need to think about the acceptance given in the mover_path 2-tuple for each multimover. For all movers except ConditionalSequentialMover, this is always True: acceptance of the sample depends only on acceptance of the submove. The previous paragraph is done by taking all Samples containing a given mover in their sample.details.mover_paths, and looking at sample.details.accepted.

But consider a MinusMove where the replica exchange part is accepted, but the extension is not. This will generate two samples: one from the replica exchange, and one from the extension. The mover_path entry from the replica exchange sample will say that the replica exchange was accepted, whereas the entry from the extension part will say it was accepted. The key is that in BOTH cases, the mover_path entry associated with the ConditionalSequentialEnsemble will be rejected. In this case, we can analyze the acceptance ratio of the replica exchange part by looking at its contributions to the mover_path list, which will give different information from the overall acceptance given by sample.details.accepted, which would be false for both of these.

Storage changes

The only downside of this approach is that it does require some modification to storage. Basically, we need to be able to store these move_path lists. @jhprinz, would that be hard to implement?

jhprinz commented 9 years ago

This is done, but leave this open for now to copy some stuff into the documentation!?!

dwhswenson commented 9 years ago

Applying (newly-created) label "docs" to this and closing; that way we can find it in closed issues while writing docs, without it filling up open issues. We should find similar things in already-closed issues/PRs (many good ones can probably be easily found by looking for the longest conversations!)