Skip to content

External Engine#144

Merged
dwhswenson merged 74 commits into
openpathsampling:masterfrom
dwhswenson:external_engine
Dec 8, 2019
Merged

External Engine#144
dwhswenson merged 74 commits into
openpathsampling:masterfrom
dwhswenson:external_engine

Conversation

@dwhswenson

@dwhswenson dwhswenson commented Feb 4, 2015

Copy link
Copy Markdown
Member

(Eventually) An example of how to use an external process as the underlying dynamics engine. Primarily intended as a starting point for Gromacs support.

The "dynamics" in this just write "0.0" to a file, one per line (frame). So this can really only be used with LengthEnsembles.

The external program (engine.c) takes an argument of milliseconds between each write, so that we can test cases where the engine is faster than OPS can keep up with and cases where the engine is much slower than OPS.

Tasks:

  • external_engine.py can control a process, and read "frames" from its output file
  • Automatic optimization of sleep time between read attempts
  • Add support for an "input" initial frame in this external toy engine
  • Test in the context of a shooting move
  • Move testexternal_engine into the real nosetests suite

@jchodera

jchodera commented Feb 4, 2015 via email

Copy link
Copy Markdown
Contributor

@dwhswenson dwhswenson self-assigned this Mar 11, 2015
@dwhswenson dwhswenson added this to the Future milestone Mar 13, 2015
@dwhswenson

Copy link
Copy Markdown
Member Author

A little update, since I've been playing with this recently.

First, this is about "indirect control" engines, which use an external process to run dynamics, and check the output file as it is written. These differ from "direct control" (like OpenMM) where we have an easy-to-use API to get frames on demand.

Indirect control isn't as elegant as direct control, but the first thing I hear from prospective users is that they'd like to be able to use their own favorite MD engine, and we're not going to write a direct control API for every MD engine out there.

However, I think a single indirect control API can make it easy to add new external engines. Here's the API I've implemented in this PR.

First, there are 4 required functions:

  • read_frame_from_file(filename, frame_num): attempts to read frame number frame_num from filename, returns Snapshot if the frame exists, None if not, and (optionally) "partial" if it appears that the frame has been partially written.
  • write_frame_to_file(filename, snapshot, mode="a"): write the snapshot to a file; mainly used to create input conditions for a trajectory
  • set_filenames(number): sets the filename variables (input file, trajectory output file, anything else that changes with trajectory) for trajectory number : mainly differs because of different file extensions
  • engine_command(): writes the command which would run the dynamics engine (as if doing normal MD with it)

Next, there are 2 functions which may occasionally need to be overridden:

  • who_to_kill(): returns a psutil.Process object for the process to send the kill signal to (defaults to the process we launch, but in some circumstances you need to kill a child of that process, because the parent process fails to pass signals along to children)
  • cleanup(): any other cleanup that needs to be done after terminating the external program (defaults to none)

There's also a class variable killsig which determines which signal to send to terminate the process. It defaults to signal.SIGTERM, but can be overridden. And, of course, other subclass-specific details can be passed as part of the __init__ function.

I may add more features (handling of stdout and stderr from the subprocess, for example) and I'm planning to add a nice trick that automatically optimizes the time spent waiting for a new frame to be written. But this is the basic idea, and I think it should make it really easy to add support for more engines.

@dwhswenson

Copy link
Copy Markdown
Member Author

@kyleabeauchamp : What happens if MDTraj tries to read a file that is still being written? In particular, I'm hoping it is possible to get the cases listed for read_frame_from_file: (a) here's the frame you requested; (b) no frame of that number exists; or (c) it looks like we're in the middle of writing that frame.

If that's not possible, it's also fine if case (c) returns the same response as case (b). If we can use MDTraj for the read and write files, it'll make it REALLY easy to add more engines.

@kyleabeauchamp

Copy link
Copy Markdown

I believe this will be dependent on the file type as well as the reading and writing mode.

For example, I know that pytables (our HDF5 backend) can sometimes choke when a file is being written and read at the same time.

If you have a clear need for simultaneous read / write, I think you might want to raise an issue on the MDTraj issue tracker asking for advice there. It's possible that some file formats might be feasible with only minor fixes.

Another possibility is to use a sqlite database, which is a pretty lightweight way to have concurrent read / write. Robert's Osprey code uses this for building many Markov state models in parallel and saving them in a database for evaluation (https://github.com/pandegroup/osprey/)

@dwhswenson

Copy link
Copy Markdown
Member Author

Thanks Kyle -- since it sounds like it'll take some more detailed consideration, I'll put an issue up on the MDTraj tracker later, but I'll hold off until I can make this a higher priority. The current status on this was just to make a proof-of-concept. This isn't part of our 1.0 roadmap, but it's something I want to complete this spring.

Since we're using an external program to generate the trajectory, we can't change the output there to sqlite. We really only need the last completed frame every time we poll the file, but the question is how to best obtain that. Anyway, I'll ask over on MDTraj when I know that I can devote more time to it!

@dwhswenson dwhswenson mentioned this pull request Mar 15, 2019
@dwhswenson dwhswenson merged commit 74c195f into openpathsampling:master Dec 8, 2019
@dwhswenson dwhswenson added feature and removed onhold labels Dec 11, 2019
This was referenced Dec 11, 2019
@dwhswenson dwhswenson deleted the external_engine branch January 17, 2021 11:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants