In [1]:
import sys, os

# verbose = os.environ.get('RADICAL_PILOT_VERBOSE', 'REPORT')
os.environ['RADICAL_PILOT_VERBOSE'] = 'ERROR'

from adaptivemd import (
    OpenMMEngine,
    AllegroCluster,
    Project,
    Brain,
    File, Directory,
    PyEMMAAnalysis,
    Event, FunctionalEvent,
    LocalJHP, LocalSheep)

import numpy as np


/Users/jan-hendrikprinz/anaconda/lib/python2.7/site-packages/radical/utils/atfork/stdlib_fixer.py:58: UserWarning: logging module already imported before fixup.
  warnings.warn('logging module already imported before fixup.')
/Users/jan-hendrikprinz/anaconda/lib/python2.7/site-packages/radical/utils/atfork/stdlib_fixer.py:65: UserWarning: logging handlers already registered.
  warnings.warn('logging handlers already registered.')

Let's open a project with a UNIQUE name. This will be the name used in the DB so make sure it is new.


In [2]:
project = Project('test')

Set up the project and pick a resource. This should be done only the first time, when the project is created.


In [3]:
# use the resource specified as argument, fall back to localhost
# resource_id = 'local.jhp'

# if resource_id == 'local.jhp':
#     project.initialize(LocalJHP)
# elif resource_id == 'local.sheep':
#     project.initialize(LocalSheep)
# elif resource_id == 'fub.allegro':
#     project.initialize(AllegroCluster)

TaskGenerators

TaskGenerators are instances whose purpose is to create tasks to be executed. This is similar to the way Kernels work. A TaskGenerator will generate Task objects for you which will be translated into a ComputeUnitDescription and executed.

A task generator will be initialized with all parameters needed to make it work and it will now what needs to be staged to be used.

The engine

A task generator that will create jobs to run simulations. Currently it uses a little python script that will excute OpenMM. It required conda to be added to the PATH variable and then it works.


In [4]:
pdb_file = File('file://../files/alanine/alanine.pdb')

engine = OpenMMEngine(
    pdb_file=pdb_file,
    system_file=File('file://../files/alanine/system.xml'),
    integrator_file=File('file://../files/alanine/integrator.xml'),
    args='-r --report-interval 1 -p CPU --store-interval 1')

The modeller

The instance to compute an MSM model of existing trajectories. So far it will only use the trajectories in the current staging area.

[TODO:] Add using all previous existing trajectories


In [5]:
# --------------------------------------------------------------------------
# CREATE THE MODELLER
#   the instance to create msm models
# --------------------------------------------------------------------------
modeller = PyEMMAAnalysis(
    pdb_file=pdb_file,
    source_folder=Directory('staging:///trajs'))

Register (and soon store) these task generators with a name in the project for later usage


In [6]:
# add the task generating capabilities
project.register('engine', engine)
project.register('modeller', modeller)

Opening a project will open the DB and create a RP session to be used


In [7]:
project.open()

In [8]:
scheduler = project.get_scheduler(cores=2)
trajs = project.new_trajectory(pdb_file, 100, 2)
scheduler.submit(trajs)
scheduler.wait()
scheduler.exit()

In [12]:
print project.files


<Bundle with 2 file(s) @ 0x10eb3aa10>

In [61]:
def strategy():
    # create a new scheduler
    local_scheduler = project.get_scheduler(cores=2)
    # run 10 trajs of length 100 in parallel
    tasks = local_scheduler.submit(project.new_ml_trajectory(
        length=100, number=10))
    # continue (all tasks need to be done)
    yield tasks.is_done()
    # close scheduler when job is done
    local_scheduler.exit()

In [66]:
ev = FunctionalEvent(strategy())

In [67]:
project.add_event(ev)


Out[67]:
<adaptivemd.event.FunctionalEvent at 0x10faf6890>

In [120]:
print '# of files', len(project.files)
for f in project.files:
    print f.url


# of files 52
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0001/staging_area/trajs/00000004.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0001/staging_area/trajs/00000002.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0001/staging_area/trajs/00000008.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0002/staging_area/trajs/00000015.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0004/staging_area/trajs/00000035.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0002/staging_area/trajs/00000016.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0004/staging_area/trajs/00000036.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0004/staging_area/trajs/00000037.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0005/staging_area/trajs/00000047.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0005/staging_area/trajs/00000044.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0001/staging_area/trajs/00000005.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0004/staging_area/trajs/00000041.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0005/staging_area/trajs/00000049.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0005/staging_area/trajs/00000045.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0002/staging_area/trajs/00000012.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0000/staging_area/trajs/00000000.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0002/staging_area/trajs/00000013.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0003/staging_area/trajs/00000026.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0002/staging_area/trajs/00000014.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0005/staging_area/trajs/00000046.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0003/staging_area/trajs/00000025.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0004/staging_area/trajs/00000033.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0002/staging_area/trajs/00000020.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0001/staging_area/trajs/00000006.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0003/staging_area/trajs/00000030.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0005/staging_area/trajs/00000043.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0003/staging_area/trajs/00000022.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0004/staging_area/trajs/00000039.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0003/staging_area/trajs/00000028.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0003/staging_area/trajs/00000024.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0001/staging_area/trajs/00000007.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0003/staging_area/trajs/00000027.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0004/staging_area/trajs/00000038.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0003/staging_area/trajs/00000031.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0004/staging_area/trajs/00000034.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0005/staging_area/trajs/00000050.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0004/staging_area/trajs/00000032.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0002/staging_area/trajs/00000017.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0001/staging_area/trajs/00000003.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0002/staging_area/trajs/00000018.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0005/staging_area/trajs/00000042.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0000/staging_area/trajs/00000001.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0005/staging_area/trajs/00000048.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0001/staging_area/trajs/00000009.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0003/staging_area/trajs/00000023.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0002/staging_area/trajs/00000019.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0001/staging_area/trajs/00000011.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0004/staging_area/trajs/00000040.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0001/staging_area/trajs/00000010.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0003/staging_area/trajs/00000029.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0002/staging_area/trajs/00000021.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0016-pilot.0005/staging_area/trajs/00000051.dcd

In [121]:
for e in project._events:
    print len(e._finish_conditions)

In [122]:
project.close()

To actually run simulations you need to have a scheduler (maybe a better name?). This instance can execute tasks or more precise you can use it to submit tasks which will be converted to ComputeUnitDescriptions and executed on the cluster previously chosen.


In [15]:
scheduler = project.get_scheduler(cores=2)

Now we are good to go and can run a first simulation

This works by creating a Trajectory object with a filename, a length and an initial frame. Then the engine will take this information and create a real trajectory with exactly this name, this initil frame and the given length.

Since this is such a common task you can also submit just a Trajectory without the need tp convert it to a Task first (which the engine can also do).

Out project can create new names automatically and so we want 4 new trajectories of length 100 and starting at the existing pdb_file we use to initialize the engine.


In [16]:
trajs = project.new_trajectory(pdb_file, 100, 4)

In [17]:
t = engine.task_run_trajectory(trajs[0])

In [18]:
scheduler.submit(t)


Out[18]:
[<adaptivemd.task.Task at 0x10f6b5550>]

In [23]:
from adaptivemd import Trajectory

In [20]:
for f in project.files:
    print f


shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0007-pilot.0001/staging_area/trajs/00000000.dcd

In [46]:
frame = f[17]

In [47]:
t2 = engine.task_run_trajectory(project.new_trajectory(f[17], 50))

In [48]:
scheduler.submit(t2)


Out[48]:
[<adaptivemd.task.Task at 0x10f8633d0>]

Once the trajectories exist these objects will be saved to the database. It might be a little confusing to have objects before they exist, but this way you can actually work with these trajectories like referencing even before they exist.

This would allow to write now a function that triggers when the trajectory comes into existance. But we are not doing this right now.

Let's submit and see


In [13]:
trajs


Out[13]:
[Trajectory('alanine.pdb' >> 00000000.dcd[0..100]),
 Trajectory('alanine.pdb' >> 00000001.dcd[0..100]),
 Trajectory('alanine.pdb' >> 00000002.dcd[0..100]),
 Trajectory('alanine.pdb' >> 00000003.dcd[0..100])]

In [31]:
scheduler.generators


Out[31]:
{'engine': <adaptivemd.engine.OpenMMEngine at 0x10ed46e90>,
 'modeller': <adaptivemd.analysis.PyEMMAAnalysis at 0x1069f58d0>}

In [14]:
# submit the trajectories
scheduler.submit(trajs)


Out[14]:
[<adaptivemd.task.Task at 0x10f825210>,
 <adaptivemd.task.Task at 0x10f825750>,
 <adaptivemd.task.Task at 0x10f825990>,
 <adaptivemd.task.Task at 0x10f825d50>]

Wait is dangerous since it is blocking and you cannot do anything until all tasks are finished. Normally you do not need it. Especially in interactive sessions.


In [12]:
scheduler.wait()

Look at all the files our project now contains.


In [58]:
for f in project.files:
    print f.url


shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0003-pilot.0000/staging_area/trajs/00000010.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0003-pilot.0000/staging_area/trajs/00000004.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0003-pilot.0000/staging_area/trajs/00000003.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0003-pilot.0000/staging_area/trajs/00000007.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0003-pilot.0000/staging_area/trajs/00000001.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0003-pilot.0000/staging_area/trajs/00000011.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0003-pilot.0000/staging_area/trajs/00000000.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0003-pilot.0000/staging_area/trajs/00000002.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0003-pilot.0000/staging_area/trajs/00000009.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0003-pilot.0000/staging_area/trajs/00000008.dcd
shared://rp.session.Stevie.fritz.box.jan-hendrikprinz.017217.0003-pilot.0000/staging_area/trajs/00000012.dcd
DONE!!!

Great! That was easy (I hope you agree).

Events

A new concept. Tasks are great and do work for us. But so far we needed to submit tasks ourselves. In adaptive simulations we want this to happen automatically. To help with some of this events exist. This are basically a task_generator coupled with conditions on when to be executed.

Let's write a little task generator (in essence a function that returns tasks)


In [51]:
def task_generator():
    return [
        engine.task_run_trajectory(traj) for traj in
        project.new_ml_trajectory(100, 2)]

In [52]:
task_generator()


Out[52]:
[<adaptivemd.task.Task at 0x10f863990>, <adaptivemd.task.Task at 0x10f843c90>]

Now create an event.


In [53]:
ev = Event().on(project.on_ntraj(range(4, 12, 2))).do(task_generator)

.on specifies when something should be executed. In our case when the project has a number of trajectories (ntraj) of being one of range(4, 24, 2) which is [4, 6, 8, 10, ...]

.do specifies the function to be called.

The concept is borrowed from event based languages like often used in JavaScript.

You can build quite complex execution patterns with this. An event for example also knows when it is finished and this can be used as another trigger.


In [54]:
def hello():
    print 'DONE!!!'
    return []  # todo: allow for None here

finished = Event().on(ev.on_tasks_finished()).do(hello)

In [55]:
scheduler.add_event(ev)
scheduler.add_event(finished)


Out[55]:
<adaptivemd.event.Event at 0x10f7f3310>

All events and tasks run parallel or at least get submitted and queue for execution in parallel. RP takes care of the actual execution.

So for now lets run more trajectories and schedule computation of models in regular intervals.


In [74]:
scheduler.add_event(
    Event().on(project.on_ntraj(range(4, 50, 2))).do(task_generator)
)
scheduler.add_event(
    Event()
    .on(project.on_ntraj(10))
    .do(modeller.task_run_msm)
    .repeat().until(project.on_ntraj(20)))  # todo: change that this will stop when the first event is done


Out[74]:
<adaptivemd.event.Event at 0x10f8c7f90>

In [77]:
project.models[0]['msm']


Out[77]:
{u'C': [[157.0, 0.0, 23.0, 17.0, 10.0],
  [0.0, 162.0, 16.0, 2.0, 2.0],
  [28.0, 18.0, 300.0, 21.0, 16.0],
  [12.0, 2.0, 24.0, 211.0, 0.0],
  [12.0, 2.0, 24.0, 0.0, 361.0]],
 u'P': [[0.7584541057287958,
   0.0,
   0.12391141040631883,
   0.07223079655322646,
   0.045403687311658954],
  [0.0,
   0.8901098831651435,
   0.09007097537774184,
   0.010874420491472532,
   0.008944720965642172],
  [0.06618887201079533,
   0.04597149430974188,
   0.7832898157767418,
   0.060232583164306,
   0.044317234738415014],
  [0.056418574445790015,
   0.008115885323985233,
   0.08807598595491802,
   0.8473895542753067,
   0.0],
  [0.031582548442256775,
   0.005945014516373964,
   0.05771052446733235,
   0.0,
   0.9047619125740369]],
 u'lagtime': 2}

In [72]:
bedingung = project.on_ntraj(10)

In [73]:
if bedingung():
    print 'True'


True

In [71]:
len(project.trajectories)


Out[71]:
13

.repeat means to redo the same task when the last is finished (it will just append an infinite list of conditions to keep on running).

.until specifies a termination condition. The event will not be executed once this condition is met. Makes most sense if you use .repeat or if the trigger condition and stopping should be independent. You might say, run 100 times unless you have a good enough model.


In [34]:
print project.files


<Bundle with 20 file(s) @ 0x1065c8b50>

In [58]:
scheduler.wait()

In [61]:
from adaptivemd import FunctionalEvent

In [59]:
def strategy():
    # create a new scheduler
    local_scheduler = project.get_scheduler(cores=2)
    # run 10 trajs of length 100 in parallel
    tasks = scheduler.submit(project.new_ml_trajectory(
        length=100, number=10))
    # wait until this is finished and specify a condition on when to
    # continue (all tasks need to be done)
    yield [t.is_done for t in tasks]
    # close scheduler when job is done
    local_scheduler.exit()
    # yield a condition on when to be done. Nothing since we are
    # done already
    yield []

In [63]:
scheduler.add_event(FunctionalEvent(strategy))


Out[63]:
<adaptivemd.event.FunctionalEvent at 0x10f843b10>

In [71]:
scheduler.add_event(FunctionalEvent(strategy))


Out[71]:
<adaptivemd.event.FunctionalEvent at 0x10f843490>

In [73]:
scheduler._events


Out[73]:
[]

In [74]:
ev = FunctionalEvent(strategy)

In [76]:
ev._current_when

In [68]:
project.schedulers


Out[68]:
{<adaptivemd.scheduler.Scheduler at 0x10f70dc10>}

In [60]:
print project.files
print len(project.models)


<Bundle with 50 file(s) @ 0x1065c8b50>
5

The brain

The brain is just a collection of events. This makes it reuseable and easy to extend.


In [77]:
project.close()

In [ ]: