Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,53 @@ and generally speaking the performance hit for python vs. C++ isn't prohibitive.
resources for developing with LOOS on the [GitHub wiki](https://github.com/GrossfieldLab/loos/wiki),
particularly the [Tutorials for Developers](https://github.com/GrossfieldLab/loos/wiki/Tutorials-for-Developers).

## Build commands for developers

Assuming you've already set up your environment following the install process,
you can rebuild into the same env by doing the following:

The build is driven by CMake; commands below assume an out-of-tree `build/`
directory (see [INSTALL.md](INSTALL.md)). Substitute your build path if
different.

Rebuild a single tool (after edits under `Tools/` or `Packages/`):

```bash
cmake --build build/ --target <tool-name>
```

Only that executable relinks; `libloos` is left alone unless it was already
stale.

Rebuild the core library and everything that links against it (after edits
under `src/`):

```bash
cmake --build build/ -j$(nproc)
```

Use `--target loos` to relink just `libloos` without touching the tools.

Rebuild the PyLOOS bindings (after edits to `src/loos.i`, wrapped C++, or the
pure-Python sources under `loos/src/loos/`):

```bash
cmake --build build/ --target loos_python -j$(nproc)
```

The `loos_python` target depends on `pyloos`, so this regenerates `_pyloos.so`
and `loos.py` via SWIG and then re-stages the Python package into
`build/src/pyloos/`. The source tree's `loos/` directory is *not* directly
importable — it lacks the SWIG outputs — so the editable install must point at
the staged build copy:

```bash
pip install -e build/src/pyloos/
```

Run this once. After that, the `cmake --build` command above is enough to pick
up subsequent edits; no reinstall needed.

### Release 4.1.0

This release includes a number of fixes related to issues listed on github. Added
Expand Down
64 changes: 51 additions & 13 deletions loos/src/loos/pyloos/trajectories.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Python-based trajectory classes that wrap loos.Trajectory objects

"""
import sys
import loos
import copy

Expand All @@ -11,12 +12,13 @@
# a loos::Trajectory. The behavior of the trajectory can be controlled
# through passed keywords,
#
# Keyword | Description
# -----------|------------------------------------------------------------------------------
# skip=n | Skip the first n-frames of the wrapped trajectory
# stride=n | Step through the wrapped trajectory n-frames at a time
# iterator=i | Use the python iterator object i to select frames from the wrapped trajectory
# subset=s | Use 's' to select a subset of the model to use for each frame
# Keyword | Description
# --------------|------------------------------------------------------------------------------
# skip=n | Skip the first n-frames of the wrapped trajectory
# stride=n | Step through the wrapped trajectory n-frames at a time
# iterator=i | Use the python iterator object i to select frames from the wrapped trajectory
# subset=s | Use 's' to select a subset of the model to use for each frame
# update_full=b | If False, only update coords for the subset each frame (faster, but other selections from the model won't see updates). Default True.
#
# Remember that all atoms are shared. If you want to decouple the
# trajectory from other groups, pass it a copy of the model.
Expand Down Expand Up @@ -59,10 +61,11 @@ class Trajectory(object):
>>> traj = loos.pyloos.Trajectory('foo.dcd', model)

keyword args:
skip = # of frames to skip from start
stride = # of frames to step through
iterator = Python iterator used to pick frame (overrides skip and stride)
subset = Selection used to pick subset for each frame
skip = # of frames to skip from start
stride = # of frames to step through
iterator = Python iterator used to pick frame (overrides skip and stride)
subset = Selection used to pick subset for each frame
update_full = If False, only update subset coords each frame (default True)

See the Doxygen documentation for more details.
"""
Expand All @@ -73,6 +76,8 @@ def __init__(self, fname, model, **kwargs):
self._skip = 0
self._stride = 1
self._iterator = None
self._update_full = kwargs.get('update_full', True)
self._suppress_update_full_warning = kwargs.get('suppress_update_full_warning', False)

if 'skip' in kwargs:
self._skip = kwargs['skip']
Expand All @@ -89,6 +94,18 @@ def __init__(self, fname, model, **kwargs):
self._fname = fname
self._traj = loos.createTrajectory(fname, model)

if self._update_full:
self._target = self._model
else:
self._target = self._subset
if not self._suppress_update_full_warning:
sys.stderr.write(
"Warning- pyloos.Trajectory: update_full=False means the model "
"you instantiated the trajectory object with will go stale; "
"use traj_object.refreshModel() to update it explicitly.\n"
)

self._model_dirty = False
self._stale = 1
self._initFrameList()

Expand Down Expand Up @@ -130,6 +147,8 @@ def setSubset(self, selection):
The selection is a LOOS selection string.
"""
self._subset = loos.selectAtoms(self._model, selection)
if not self._update_full:
self._target = self._subset


def __iter__(self):
Expand Down Expand Up @@ -182,9 +201,24 @@ def readFrame(self, i):
if (i < 0 or i >= len(self._framelist)):
raise IndexError
self._traj.readFrame(self._framelist[i])
self._traj.updateGroupCoords(self._model)
self._traj.updateGroupCoords(self._target)
if not self._update_full:
self._model_dirty = True
return(self._subset)


def refreshModel(self):
"""
Update the full model's coordinates from the trajectory's current frame.
Only relevant in update_full=False mode, where the per-frame update
touches only the subset. No-op if the model is already current.
Returns the model AtomicGroup.
"""
if self._model_dirty:
self._traj.updateGroupCoords(self._model)
self._model_dirty = False
return(self._model)

def frame(self):
"""Return the current frame (subset)"""
return(self._subset)
Expand Down Expand Up @@ -232,9 +266,11 @@ def _getSlice(self, s):
ensemble = []
for i in indices:
self._traj.readFrame(self._framelist[i])
self._traj.updateGroupCoords(self._model)
self._traj.updateGroupCoords(self._target)
dup = self._subset.copy()
ensemble.append(dup)
if not self._update_full and indices:
self._model_dirty = True
return(ensemble)


Expand All @@ -251,7 +287,9 @@ def __getitem__(self, i):
if (i >= len(self._framelist) or i < 0):
raise IndexError
self._traj.readFrame(self._framelist[i])
self._traj.updateGroupCoords(self._model)
self._traj.updateGroupCoords(self._target)
if not self._update_full:
self._model_dirty = True
return(self._subset)


Expand Down
Loading