diff --git a/CMakeLists.txt b/CMakeLists.txt index 00054ead6a5fe2a5bdea7ba0526d34be02046c74..cfebaa1b5068363a4433c737cb9947ccb1e5d320 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,8 @@ option(ENABLE_GFX "whether graphics support should be enabled" ON) option(ENABLE_IMG "whether the image processing module should be compiled" ON) +option(USE_NUMPY "whether numpy support is added" + OFF) option(USE_DOUBLE_PRECISION "whether to compile in double precision" OFF) option(ENABLE_SPNAV "whether 3DConnexion devices should be supported" @@ -87,6 +89,11 @@ if (USE_SHADER) else() set(_SHADER OFF) endif() +if (USE_NUMPY) + set(_NUMPY ON) +else() + set(_NUMPY OFF) +endif() if (COMPILE_TMTOOLS) set(_TM_TOOLS ON) else() @@ -143,6 +150,10 @@ find_package(PNG REQUIRED) find_package(Eigen 2.0.0 REQUIRED) find_package(Python 2.4 REQUIRED) +if(USE_NUMPY) + find_package(Numpy REQUIRED) +endif() + if (ENABLE_IMG) find_package(FFTW REQUIRED) find_package(TIFF REQUIRED) @@ -177,6 +188,10 @@ include_directories(${Boost_INCLUDE_DIRS} ${SPNAV_INCLUDE_DIR} ${PNG_INCLUDE_DIR} ) +if(USE_NUMPY) +include_directories(${PYTHON_NUMPY_INCLUDE_DIR}) +endif() + if (UNIX) SET(CMAKE_SKIP_BUILD_RPATH FALSE) SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) @@ -209,6 +224,7 @@ message(STATUS " OpenGL support (-DENABLE_GFX) : ${_OPENGL}\n" " Image Processing support (-DENABLE_IMG) : ${_IMG}\n" " Shader support (-DUSE_SHADER) : ${_SHADER}\n" + " Numpy support (-DUSE_NUMPY) : ${_NUMPY}\n" " Optimize (-DOPTIMIZE) : ${_OPT}\n" " Profiling support (-DPROFILE) : ${_PROFILE}\n" " Double Precision (-DUSE_DOUBLE_PRECISION) : ${_DOUBLE_PREC}\n" diff --git a/cmake_support/FindNumpy.cmake b/cmake_support/FindNumpy.cmake new file mode 100644 index 0000000000000000000000000000000000000000..6348b9c91a934e4c01edac011cc861adc9fd059a --- /dev/null +++ b/cmake_support/FindNumpy.cmake @@ -0,0 +1,32 @@ +if (PYTHON_NUMPY_INCLUDE_DIR) + # in cache already + set (PYTHON_NUMPY_FIND_QUIETLY TRUE) +endif (PYTHON_NUMPY_INCLUDE_DIR) + +#INCLUDE(FindPython) + +IF(PYTHON_BINARY) + EXEC_PROGRAM ("${PYTHON_BINARY}" + ARGS "-c 'import numpy; print numpy.get_include()'" + OUTPUT_VARIABLE PYTHON_NUMPY_INCLUDE_DIR + RETURN_VALUE PYTHON_NUMPY_NOT_FOUND) + + if (PYTHON_NUMPY_INCLUDE_DIR) + set (PYTHON_NUMPY_FOUND TRUE) + set (PYTHON_NUMPY_INCLUDE_DIR ${PYTHON_NUMPY_INCLUDE_DIR} CACHE STRING "Numpy include path") + else (PYTHON_NUMPY_INCLUDE_DIR) + set(PYTHON_NUMPY_FOUND FALSE) + endif (PYTHON_NUMPY_INCLUDE_DIR) +ENDIF(PYTHON_BINARY) + +if (PYTHON_NUMPY_FOUND) + if (NOT PYTHON_NUMPY_FIND_QUIETLY) + message (STATUS "Numpy headers found") + endif (NOT PYTHON_NUMPY_FIND_QUIETLY) +else (PYTHON_NUMPY_FOUND) + if (PYTHON_NUMPY_FIND_REQUIRED) + message (FATAL_ERROR "Numpy headers missing") + endif (PYTHON_NUMPY_FIND_REQUIRED) +endif (PYTHON_NUMPY_FOUND) + +MARK_AS_ADVANCED (PYTHON_NUMPY_INCLUDE_DIR) \ No newline at end of file diff --git a/deployment/linux/create_bundle.py b/deployment/linux/create_bundle.py index cf0ce5f6103cb48a99632a732d6672c88895c070..dbb88bb70feaa46329922ba30e3efefaea0b89fb 100644 --- a/deployment/linux/create_bundle.py +++ b/deployment/linux/create_bundle.py @@ -8,11 +8,11 @@ import datetime # custom parameters -if len(sys.argv) < 2: - print 'usage: create_bundle.py additional_label' +if len(sys.argv) < 3: + print 'usage: create_bundle.py additional_label system_python_version' sys.exit() -system_python_version='python2.6' +system_python_version=sys.argv[2] system_python_bin='/usr/bin/'+system_python_version system_python_libs='/usr/lib/'+system_python_version second_system_python_libs_flag=True diff --git a/modules/config/CMakeLists.txt b/modules/config/CMakeLists.txt index ddf07651188d815e51ae669972981c4aeab469c1..65c9ca6bebf69a4def544c5c58dfc50be04ee98d 100644 --- a/modules/config/CMakeLists.txt +++ b/modules/config/CMakeLists.txt @@ -5,14 +5,20 @@ dllexport.hh version.hh ) - set(animations_enabled 0) + if (USE_SHADER) set(shader_support 1) else() set(shader_support 0) endif() +if (USE_NUMPY) + set(numpy_support 1) +else() + set(numpy_support 0) +endif() + if (PROFILE) set(profiling_enabled 1) else() diff --git a/modules/config/config.hh.in b/modules/config/config.hh.in index 0095327dd737efa71141f72144cf9d8b5bfed213..88653c1e8df5bc5f75bf99dd6554c5a25c5ffaa6 100644 --- a/modules/config/config.hh.in +++ b/modules/config/config.hh.in @@ -31,4 +31,5 @@ #define OST_STATIC_PROPERTY_WORKAROUND @static_props@ #define OST_SPNAV_ENABLED @spnav_enabled@ #define OST_FFT_USE_THREADS @fftw_use_threads@ +#define OST_NUMPY_SUPPORT_ENABLED @numpy_support@ #endif diff --git a/modules/geom/src/vec3.hh b/modules/geom/src/vec3.hh index ec9a6cb75d2b269bc229ef0a2311bdc9fe15b6da..db2b8bb7097dc76d0b74c7906a0ea4a63bda5929 100644 --- a/modules/geom/src/vec3.hh +++ b/modules/geom/src/vec3.hh @@ -205,7 +205,7 @@ public: Vec3List(base_type::iterator b, base_type::iterator e): base_type(b, e) { } Vec3List(const Vec3List& rhs) : base_type(rhs) { } - + Vec3List(const base_type& rhs) : base_type(rhs) { } Vec3List& operator=(const Vec3List& rhs) { base_type::operator=(rhs); diff --git a/modules/gui/doc/dialogs.rst b/modules/gui/doc/dialogs.rst new file mode 100644 index 0000000000000000000000000000000000000000..a2bc2a7f239fa296a00bc0658bd2760ea6380a1b --- /dev/null +++ b/modules/gui/doc/dialogs.rst @@ -0,0 +1,25 @@ +Dialogs +================================================================================ +.. currentmodule:: ost.gui + +OpenStructure provides several :class:`Dialogs` which can be called from its +many menus in the top bar. + + +.. image:: images/100208_Dialogs.png + +Scene Menu +-------------------------------------------------------------------------------- + + +Superpose +^^^^^^^^^ + + Structurally superpose two entities. + + .. image:: images/100624_superpose_dialog.png + + The ``Superpose`` entry in the ``Scene`` menu is only accessible if two + instances of the graphical :class:`~ost.gfx.Entity` are selected. + + .. autoclass:: ost.gui.dng.superpositiondialog.SuperpositionDialog diff --git a/modules/gui/doc/gui.rst b/modules/gui/doc/gui.rst index 675bf6b139294abb9507955d9e4b1978ffb075b7..19a407ac087b2ea40dd5c3803a599a68e3730d4d 100644 --- a/modules/gui/doc/gui.rst +++ b/modules/gui/doc/gui.rst @@ -19,4 +19,4 @@ C++ Qt widgets as well as with PyQt widgets. Learn more about :doc:`python_cpp`. tools python_shell sequence_viewer - + dialogs diff --git a/modules/gui/doc/images/100208_Dialogs.png b/modules/gui/doc/images/100208_Dialogs.png new file mode 100644 index 0000000000000000000000000000000000000000..f42f8809a3848f01390db42a71dbcc96bba53a01 Binary files /dev/null and b/modules/gui/doc/images/100208_Dialogs.png differ diff --git a/modules/gui/doc/images/100624_superpose_dialog.png b/modules/gui/doc/images/100624_superpose_dialog.png new file mode 100644 index 0000000000000000000000000000000000000000..c01e657c23b0d60f6d08af94d632e95b0b74f6d3 Binary files /dev/null and b/modules/gui/doc/images/100624_superpose_dialog.png differ diff --git a/modules/gui/pymod/CMakeLists.txt b/modules/gui/pymod/CMakeLists.txt index dc632913113930804afd77130237c76850ad8edf..9a623a9a1877f68e6aa7ff1f39229489acee84bd 100644 --- a/modules/gui/pymod/CMakeLists.txt +++ b/modules/gui/pymod/CMakeLists.txt @@ -90,6 +90,7 @@ set(OST_GUI_PYMOD_MODULES set(OST_GUI_PYMOD_DNG_MODULES __init__.py termuse.py + superpositiondialog.py init.py menu.py ) diff --git a/modules/gui/pymod/__init__.py b/modules/gui/pymod/__init__.py index c543655248a41ba9543326e84e15c7a4b6a249d8..a63b91820c28a4eeb9b03a7c0eb916b99fcc84b9 100644 --- a/modules/gui/pymod/__init__.py +++ b/modules/gui/pymod/__init__.py @@ -184,7 +184,27 @@ class OneOf: if isinstance(node, cl): return True return False - + +class TwoOf: + def __init__(self, *classes): + self.classes=classes + def __call__(self): + sel=SceneSelection.Instance() + act_count=sel.GetActiveNodeCount() + if act_count<2: + return False + found=0 + for i in range(0, act_count): + node=sel.GetActiveNode(i) + for cl in self.classes: + if isinstance(node, cl): + found += 1 + if found > 2: + return False + if found == 2: + return True + return False + class ManyOf: def __init__(self, *classes): self.classes=classes diff --git a/modules/gui/pymod/dng/init.py b/modules/gui/pymod/dng/init.py index 661ddadc40d4c2d02c2d90588a5bc3d625437908..d46af73d8e1a93678a576698e06bdd69b552b84c 100644 --- a/modules/gui/pymod/dng/init.py +++ b/modules/gui/pymod/dng/init.py @@ -21,6 +21,7 @@ from ost.gui.init_spacenav import _InitSpaceNav from ost.gui.init_context_menu import _InitContextMenu from ost.gui.init_splash import _InitSplash from ost.gui.dng import termuse +from ost.gui.dng import superpositiondialog import ost.gui.dng.menu from PyQt4.QtGui import * def _my_exit(code): diff --git a/modules/gui/pymod/dng/menu.py b/modules/gui/pymod/dng/menu.py index c2b672c2b28e7a11a9855eec4aff08c722845016..de943d3225a2c25ea3f6a42b0aefbb6969e3f9ad 100644 --- a/modules/gui/pymod/dng/menu.py +++ b/modules/gui/pymod/dng/menu.py @@ -1,9 +1,12 @@ from PyQt4.QtCore import * from PyQt4.QtGui import * -from ost import gui, gfx, io +from ost import * +from ost import gui from ost.gui.scene.loader_manager_widget import LoaderManagerWidget from ost.gui.init_splash import _InitSplash from ost.gui.dng import termuse +from ost.gui.dng import superpositiondialog + import sys class FileMenu(QMenu): def __init__(self, parent=None): @@ -134,6 +137,8 @@ class SceneMenu(QMenu): enabled=gui.ManyOf(gfx.GfxObj)) gui.AddMenuAction(self, 'Fit To Screen', self._FitToScreen, enabled=gui.OneOf(gfx.Entity)) + gui.AddMenuAction(self, 'Superpose', self._SuperposeDialog, + enabled=gui.TwoOf(gfx.Entity)) gui.AddMenuAction(self, 'Save Snapshot', self._ExportScene) gui.AddMenuAction(self, 'Scene Clipping', self._ClipScene, shortcut='Ctrl+Shift+C') @@ -169,7 +174,31 @@ class SceneMenu(QMenu): def _FitToScreen(self): sel=gui.SceneSelection.Instance() gfx.FitToScreen(sel.GetActiveNode(0)) - + + def _SuperposeDialog(self): + sel=gui.SceneSelection.Instance() + act_count=sel.GetActiveNodeCount() + # we now that there have to be 2 gfx.Entities, because of using TwoOf to + # enable menu entry! + i = 0; + gfx_ent_1 = sel.GetActiveNode(i) + while not isinstance(gfx_ent_1, gfx.Entity): + i += 1 + gfx_ent_1 = sel.GetActiveNode(i) + i += 1 + gfx_ent_2 = sel.GetActiveNode(i) + while not isinstance(gfx_ent_2, gfx.Entity): + i += 1 + gfx_ent_2 = sel.GetActiveNode(i) + sd = superpositiondialog.SuperpositionDialog(gfx_ent_1, gfx_ent_2) + if sd.reference == 0: + gfx_ent_1.UpdatePositions() + gfx.Scene().CenterOn(gfx_ent_1) + else: + gfx_ent_2.UpdatePositions() + gfx.Scene().CenterOn(gfx_ent_2) + LogScript('RMSD: %.3f'%sd.rmsd) + class WindowMenu(QMenu): def __init__(self, parent=None): QMenu.__init__(self, parent) diff --git a/modules/gui/pymod/dng/superpositiondialog.py b/modules/gui/pymod/dng/superpositiondialog.py new file mode 100644 index 0000000000000000000000000000000000000000..f426bc3307ac8af3412fb3b373e322a96f411662 --- /dev/null +++ b/modules/gui/pymod/dng/superpositiondialog.py @@ -0,0 +1,282 @@ +#------------------------------------------------------------------------------ +# This file is part of the OpenStructure project <www.openstructure.org> +# +# Copyright (C) 2008-2011 by the OpenStructure authors +# +# This library is free software; you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 3.0 of the License, or (at your option) +# any later version. +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +#------------------------------------------------------------------------------ +# +# Authors: Stefan Bienert +# +from PyQt4.QtCore import * +from PyQt4.QtGui import * +from ost.mol.alg import Superpose +from ost import mol + +class ChainComboBox(QComboBox): + def __init__(self, ent, parent=None): + # class variables + self.all_chains = 'All' + QComboBox.__init__(self, parent) + self.entity = ent + self.addItem(self.all_chains) + for chain in self.entity.chains: + self.addItem(chain.name) + if self.count()>0: + self.setCurrentIndex(0) + + def SetItems(self, ent): + self.clear() + self.entity = ent + self.addItem(self.all_chains) + for chain in self.entity.chains: + self.addItem(chain.name) + if self.count()>0: + self.setCurrentIndex(0) + return + + def _GetSelectedChain(self): + if self.currentIndex() == -1: + return mol.EntityHandle() + elif self.currentText() == self.all_chains: + return self.entity + return self.entity.Select('cname=' + str(self.currentText())) + + def _SetSelectedChain(self, chain): + if hasattr(chain, 'name'): + name = chain.name + else: + name = str(chain) + for i in range(self.count()): + if self.itemText(i) == name: + self.setCurrentIndex(i) + break + selected_chain = property(_GetSelectedChain, _SetSelectedChain) + +class SuperpositionDialog(QDialog): + """ + Provides a graphical user interface to structurally superpose two entities. + Uses function :func:`~ost.mol.alg.Superpose`. The RMSD of two superposed + molecules will be stored in attribute ``rmsd``. An index for the selected + reference molecule will be stored in attribute ``reference``. + + :param ent_one: The first entity + :type ent_one: :class:`~ost.mol.EntityView`, :class:`~ost.mol.EntityHandle` + or :class:`~ost.gfx.Entity` + :param ent_two: The second entity + :type ent_two: :class:`~ost.mol.EntityView`, :class:`~ost.mol.EntityHandle` + or :class:`~ost.gfx.Entity` + + **Example Usage:** + + .. code-block:: python + + e1=io.LoadPDB('examples/code_fragments/entity/pdb1ake.ent') + e2=io.LoadPDB('examples/code_fragments/entity/pdb4ake.ent') + + sd = superpositiondialog.SuperpositionDialog(e1, e2) + + g1=gfx.Entity('G1', e1) + g2=gfx.Entity('G2', e2) + scene.Add(g1) + scene.Add(g2) + + if sd.reference == 0: + scene.CenterOn(g1) + else: + scene.CenterOn(g2) + + LogScript('RMSD: %.3f'%sd.rmsd) + """ + + def __init__(self, ent_one, ent_two, parent=None): + # class variables + self.rmsd = 0.0 + self._mmethod_dict = {'number': 'number', + 'index': 'index', + 'local alignment': 'local-aln', + 'global alignment': 'global-aln'} + QDialog.__init__(self, parent) + self.setWindowTitle('Superpose structures') + if not isinstance(ent_one, mol.EntityHandle) and \ + not isinstance(ent_one, mol.EntityView): + n_one = ent_one.GetName() + self.ent_one = ent_one.GetView() + else: + if isinstance(ent_one, mol.EntityHandle): + n_one = ent_one.GetName() + elif isinstance(ent_one, mol.EntityView): + n_one = ent_one.GetHandle().GetName() + self.ent_one = ent_one + if len(n_one) == 0: + n_one = '1' + if not isinstance(ent_two, mol.EntityHandle) and \ + not isinstance(ent_two, mol.EntityView): + n_two = ent_two.GetName() + self.ent_two = ent_two.GetView() + else: + if isinstance(ent_two, mol.EntityHandle): + n_two = ent_two.GetName() + elif isinstance(ent_two, mol.EntityView): + n_two = ent_two.GetHandle().GetName() + self.ent_two = ent_two + if len(n_two) == 0: + n_two = '2' + if n_one == n_two: + n_one = n_one + ' 1' + n_two = n_two + ' 2' + layout = QGridLayout(self) + # select reference molecule + self.reference = 0; + self._reference = self._ReferenceSelection(n_one, n_two) + grow = 0 + layout.addWidget(QLabel("reference"), grow, 0) + layout.addWidget(self._reference, grow, 1) + grow += 1 + # chains + self._chain_one = ChainComboBox(self.ent_one, self) + self._chain_two = ChainComboBox(self.ent_two, self) + layout.addWidget(QLabel("reference chain"), grow, 0) + layout.addWidget(self._chain_one, grow, 1) + grow += 1 + layout.addWidget(QLabel("chain"), grow, 0) + layout.addWidget(self._chain_two, grow, 1) + grow += 1 + # link chain and reference selection + QObject.connect(self._reference, + SIGNAL('currentIndexChanged(int)'), + self._ChangeChainSelection) + # match methods + self._methods = self._MatchMethods() + layout.addWidget(QLabel('match residues by'), grow, 0) + grow += 1 + layout.addWidget(self._methods) + # atoms + self._atoms = self._FetchAtoms(self._methods.size(), + self.ent_one, + self.ent_two) + self._atmselectbx, self._atmselectgrp = self._AtomSelectionBox() + layout.addWidget(self._atmselectbx, grow, 1) + grow += 1 + # buttons + ok_button = QPushButton("Superpose") + QObject.connect(ok_button, SIGNAL('clicked()'), self.accept) + cancel_button = QPushButton("Cancel") + hbox_layout = QHBoxLayout() + hbox_layout.addStretch(1) + layout.addLayout(hbox_layout, grow, 0, 1, 2) + grow += 1 + QObject.connect(cancel_button, SIGNAL('clicked()'), self.reject) + QObject.connect(self, SIGNAL('accepted()'), self._Superpose) + hbox_layout.addWidget(cancel_button, 0) + hbox_layout.addWidget(ok_button, 0) + ok_button.setDefault(True) + self.exec_() + + def _Superpose(self): + view_one = self._chain_one.selected_chain + view_two = self._chain_two.selected_chain + atoms = self._GetAtomSelection() + sp = Superpose(view_one, view_two, + self._mmethod_dict[str(self._methods.currentText())], + atoms) + self.rmsd = sp.rmsd + + def _toggle_atoms(self, checked): + if checked: + self._atoms.setEnabled(True) + else: + self._atoms.setEnabled(False) + + def _AtomSelectionBox(self): + bt1 = QRadioButton('All') + bt2 = QRadioButton('Backbone') + bt3 = QRadioButton('CA') + self.cstmbtntxt = 'Custom' + custom_rbutton = QRadioButton(self.cstmbtntxt) + group = QButtonGroup() + group.addButton(bt1) + group.addButton(bt2) + group.addButton(bt3) + group.addButton(custom_rbutton) + bt1.setChecked(True) + vbox_layout = QVBoxLayout() + vbox_layout.addWidget(bt1) + vbox_layout.addWidget(bt2) + vbox_layout.addWidget(bt3) + vbox_layout.addWidget(custom_rbutton) + vbox_layout.addWidget(self._atoms) + QObject.connect(custom_rbutton, SIGNAL('toggled(bool)'), self._toggle_atoms) + box = QGroupBox("atom selection") + box.setLayout(vbox_layout) + return box, group + + def _GetAtomSelection(self): + checkedbtn = self._atmselectgrp.checkedButton() + if str(checkedbtn.text()) != self.cstmbtntxt: + return str(checkedbtn.text()) + slctn_model = self._atoms.selectionModel() + dt_model = slctn_model.model() + atms = list() + for idx in slctn_model.selectedRows(): + slctn = dt_model.data(idx, Qt.DisplayRole).toString() + atms.append(str(slctn)) + return atms + + def _FetchAtoms(self, dim, ent_a, ent_b): + # fetch list of atoms: only those which are in both entities are considered + atm_dict = {} + for atm in ent_a.GetAtomList(): + atm_dict[atm.name] = 0 + for atm in ent_b.GetAtomList(): + if atm.name in atm_dict: + atm_dict[atm.name] = 1 + atmlst = QStringList() + for atm in sorted(atm_dict.keys()): + if atm_dict[atm]: + atmlst.append(atm) + elems = QStringListModel(atmlst) + atoms = QListView(self) + dim.setHeight(3*dim.height()) + atoms.setFixedSize(dim) + atoms.setModel(elems) + atoms.setSelectionMode(QAbstractItemView.MultiSelection) + atoms.setEditTriggers(QAbstractItemView.NoEditTriggers) + atoms.setEnabled(False) + return atoms + + def _ReferenceSelection(self, name_a, name_b): + cbox = QComboBox() + cbox.addItem(name_a) + cbox.addItem(name_b) + if cbox.count() > 0: + cbox.setCurrentIndex(0) + return cbox + + def _ChangeChainSelection(self, index): + if index == 0: + self._chain_one.SetItems(self.ent_one) + self._chain_two.SetItems(self.ent_two) + self.reference = 0; + elif index == 1: + self._chain_one.SetItems(self.ent_two) + self._chain_two.SetItems(self.ent_one) + self.reference = 1; + return + + def _MatchMethods(self): + methods=QComboBox(self) + for method in sorted(self._mmethod_dict): + methods.addItem(method) + return methods diff --git a/modules/img/alg/pymod/wrap_alg.cc b/modules/img/alg/pymod/wrap_alg.cc index f0faf8c13e1b73f1b2d0266a28978c4cb1c6ba37..c141fe11310076374194677f601e98a1929eb446 100644 --- a/modules/img/alg/pymod/wrap_alg.cc +++ b/modules/img/alg/pymod/wrap_alg.cc @@ -187,12 +187,12 @@ BOOST_PYTHON_MODULE(_ost_img_alg) .def(self_ns::str(self)) ; class_<StatMinMax, bases<NonModAlgorithm> >("StatMinMax", init<>() ) - .def("GetMinimum",&Stat::GetMinimum) - .def("GetMinimumPosition",&Stat::GetMinimumPosition) - .def("SetMinimum",&Stat::SetMinimum) - .def("GetMaximum",&Stat::GetMaximum) - .def("GetMaximumPosition",&Stat::GetMaximumPosition) - .def("SetMaximum",&Stat::SetMaximum) + .def("GetMinimum",&StatMinMax::GetMinimum) + .def("GetMinimumPosition",&StatMinMax::GetMinimumPosition) + .def("SetMinimum",&StatMinMax::SetMinimum) + .def("GetMaximum",&StatMinMax::GetMaximum) + .def("GetMaximumPosition",&StatMinMax::GetMaximumPosition) + .def("SetMaximum",&StatMinMax::SetMaximum) .def(self_ns::str(self)) ; diff --git a/modules/img/alg/tests/test_stat.cc b/modules/img/alg/tests/test_stat.cc index b34689ec9e9a802feb3750234d63a6b613cbd619..6f74a044a0d8f600ae95debcac1984581d25e2d7 100644 --- a/modules/img/alg/tests/test_stat.cc +++ b/modules/img/alg/tests/test_stat.cc @@ -49,14 +49,8 @@ void test() { Stat stat; im.Apply(stat); - - std::ostringstream msg; - - msg << "expected 5.0 as mean but found " << stat.GetMean(); - BOOST_CHECK_MESSAGE(stat.GetMean()==5.0,msg.str()); - msg.str(""); - msg << "expected 2.73861 as stdev but found " << stat.GetStandardDeviation(); - BOOST_CHECK_MESSAGE((stat.GetStandardDeviation()-2.73861)<1e-5,msg.str()); + BOOST_CHECK_CLOSE(stat.GetMean(),5.0,0.0001); + BOOST_CHECK_CLOSE(stat.GetStandardDeviation(),2.58198889747,0.0001); } diff --git a/modules/index.rst b/modules/index.rst index 8cc338a82b9480f516d927e48b3894b80b61e8d0..afc2142cfb81f0b06d9c83755207b29523132d7a 100644 --- a/modules/index.rst +++ b/modules/index.rst @@ -41,7 +41,9 @@ For Starters Molecules -------------------------------------------------------------------------------- -**Overview**: :doc:`molecules intro <intro-01>` | :doc:`mol overview <mol/base/mol>` | :doc:`graphical entity<gfx/entity>` | :doc:`entity <mol/base/entity>` | :doc:`queries <mol/base/query>` +**Overview**: :doc:`molecules intro <intro-01>` | :doc:`mol overview <mol/base/mol>` | :doc:`graphical entity<gfx/entity>` | :doc:`entity <mol/base/entity>` | :doc:`queries <mol/base/query>` | :doc:`algorithms <mol/alg/molalg>` + +**Trajectories**: :doc:`basics <mol/base/traj>` | :ref:`analysis <traj-analysis>` **Input/Output**: :ref:`loading and saving molecules <mol-io>` diff --git a/modules/io/src/mol/dcd_io.cc b/modules/io/src/mol/dcd_io.cc index 3fdb02f55727260e8679c0ac30e922d10e8d78c6..e5f48a93d4486e2de8c358ebb310dfb589f3d9e6 100644 --- a/modules/io/src/mol/dcd_io.cc +++ b/modules/io/src/mol/dcd_io.cc @@ -184,7 +184,7 @@ bool read_frame(std::istream& istream, const DCDHeader& header, } -mol::CoordGroupHandle load_dcd(const mol::AtomHandleList& alist2, +mol::CoordGroupHandle load_dcd(const mol::AtomHandleList& alist, // this atom list is already sorted! const String& trj_fn, unsigned int stride) { @@ -196,10 +196,6 @@ mol::CoordGroupHandle load_dcd(const mol::AtomHandleList& alist2, } Profile profile_load("LoadCHARMMTraj"); - mol::AtomHandleList alist(alist2); - std::sort(alist.begin(),alist.end(),less_index); - - DCDHeader header; bool swap_flag=false, skip_flag=false, gap_flag=false; read_dcd_header(istream, header, swap_flag, skip_flag, gap_flag); diff --git a/modules/io/src/mol/sdf_writer.cc b/modules/io/src/mol/sdf_writer.cc index 9f3154e9b99f91a47354a7dcb2f9ccf31cd1b758..40c0660153853bc5edbfeb8e94384194a8daf63b 100644 --- a/modules/io/src/mol/sdf_writer.cc +++ b/modules/io/src/mol/sdf_writer.cc @@ -27,6 +27,7 @@ #include <ost/mol/chain_view.hh> #include <ost/mol/bond_handle.hh> #include <boost/regex.hpp> +#include <boost/bind.hpp> namespace ost { namespace io { @@ -38,7 +39,7 @@ namespace { public: SDFAtomWriter(std::ostream& ostream, std::map<long, int>& atom_indices) : ostr_(ostream), atom_indices_(atom_indices), counter_(0) { - atom_indices_.clear(); + atom_indices_.clear(); } private: public: @@ -60,23 +61,61 @@ namespace { class SDFBondWriter : public mol::EntityViewVisitor { public: - SDFBondWriter(std::ostream& ostream, std::map<long, int>& atom_indices) + SDFBondWriter(std::ostream& ostream, + const std::map<long, int>& atom_indices) : ostr_(ostream), atom_indices_(atom_indices), counter_(0) { } private: + // compare two atoms according to their indices (used for sorting) + bool CompareAtomIdx(const mol::AtomView& first, + const mol::AtomView& second) { + std::map<long, int>::const_iterator aidx_first( + atom_indices_.find(first.GetHashCode())); + std::map<long, int>::const_iterator aidx_second( + atom_indices_.find(second.GetHashCode())); + + if(aidx_first==atom_indices_.end() || aidx_second==atom_indices_.end()) { + throw IOException("Cannot write bond: atom idx not found for sorting"); + } + return (aidx_first->second < aidx_second->second); + } + public: virtual bool VisitAtom(const mol::AtomView& atom) { - counter_++; + ++counter_; // current atom index + + // get all neighboring atoms and sort them according to their atom index mol::AtomViewList atoms = atom.GetBondPartners(); - mol::AtomViewList::iterator atom_iter = atoms.begin(); - for(; atom_iter != atoms.end(); ++atom_iter) { - int atom_index = atom_indices_.find((*atom_iter).GetHashCode())->second; - if(atom_index > counter_) { - int type = 1; - mol::BondHandle bond = atom.GetHandle().FindBondToAtom(atom_iter->GetHandle()); - if(bond.IsValid()) type = bond.GetBondOrder(); + std::sort(atoms.begin(), atoms.end(), bind(&SDFBondWriter::CompareAtomIdx, + this, _1, _2)); + + // iterate all neighboring atoms and print bonds to all atoms with index + // larger than current atom index + for(mol::AtomViewList::iterator atom_iter = atoms.begin(); + atom_iter != atoms.end(); ++atom_iter) { + std::map<long, int>::const_iterator aidx( + atom_indices_.find((*atom_iter).GetHashCode())); + + // check if index was found + if(aidx==atom_indices_.end()) { + throw IOException("Cannot write bond between " + + atom.GetQualifiedName() + " and " + + atom_iter->GetQualifiedName() + + ": atom index not found"); + } + + // only print bonds to atoms with larger index than current index + if(aidx->second > counter_) { + mol::BondHandle bond(atom.GetHandle().FindBondToAtom( + atom_iter->GetHandle())); + if(!bond.IsValid()) { + throw IOException("Bond is invalid between " + + atom.GetQualifiedName() + " and " + + atom_iter->GetQualifiedName()); + } + int type = bond.GetBondOrder(); ostr_ << format("%3i") % counter_ - << format("%3i") % atom_index + << format("%3i") % aidx->second << format("%3i") % type << " 0 0 0" << std::endl; @@ -87,17 +126,17 @@ namespace { private: std::ostream& ostr_; - std::map<long, int>& atom_indices_; + const std::map<long, int>& atom_indices_; int counter_; }; } SDFWriter::SDFWriter(std::ostream& ostream) - : outfile_(), ostr_(ostream), counter_(0) { + : outfile_(), ostr_(ostream), counter_(0), atom_indices_() { } SDFWriter::SDFWriter(const String& filename) - : outfile_(filename.c_str()), ostr_(outfile_), counter_(0) { + : outfile_(filename.c_str()), ostr_(outfile_), counter_(0), atom_indices_() { } SDFWriter::SDFWriter(const boost::filesystem::path& filename): @@ -106,7 +145,7 @@ SDFWriter::SDFWriter(const boost::filesystem::path& filename): #else outfile_(filename.file_string().c_str()), #endif - ostr_(outfile_), counter_(0) { + ostr_(outfile_), counter_(0), atom_indices_() { } void SDFWriter::Write(const mol::EntityView& ent) { diff --git a/modules/mol/alg/doc/molalg.rst b/modules/mol/alg/doc/molalg.rst index 578d9d1d1a20c924416e5d6eeb66bc14d822ca2d..4730eec073af926ec47ef043930e75f1685515fb 100644 --- a/modules/mol/alg/doc/molalg.rst +++ b/modules/mol/alg/doc/molalg.rst @@ -82,3 +82,137 @@ The following function detects steric clashes in atomic structures. Two atoms ar :returns: The filtered :class:`~ost.mol.EntityView` +.. _traj-analysis: + +Trajectory Analysis +-------------------------------------------------------------------------------- + +This is a set of functions used for basic trajectory analysis such as extracting +positions, distances, angles and RMSDs. The organization is such that most +functions have their counterpart at the individual :class:`frame level +<ost.mol.CoordFrame>` so that they can also be called on one frame instead +of the whole trajectory. + +All these functions have a "stride" argument that defaults to stride=1, which is +used to skip frames in the analysis. + + +.. function:: AnalyzeAtomPos(traj, atom1, stride=1) + + This function extracts the position of an atom from a trajectory. It returns + a vector containing the position of the atom for each analyzed frame. + + :param traj: The trajectory to be analyzed. + :type traj: :class:`~ost.mol.CoordGroupHandle` + :param atom1: The :class:`~ost.mol.AtomHandle`. + :param stride: Size of the increment of the frame's index between two + consecutive frames analyzed. + + +.. function:: AnalyzeCenterOfMassPos(traj, sele, stride=1) + + This function extracts the position of the center-of-mass of a selection + (:class:`~ost.mol.EntityView`) from a trajectory and returns it as a vector. + + :param traj: The trajectory to be analyzed. + :type traj: :class:`~ost.mol.CoordGroupHandle` + :param sele: The selection from which the center of mass is computed + :type sele: :class:`~ost.mol.EntityView`. + :param stride: Size of the increment of the frame's index between two + consecutive frames analyzed. + + +.. function:: AnalyzeDistanceBetwAtoms(traj, atom1, atom2, stride=1) + + This function extracts the distance between two atoms from a trajectory + and returns it as a vector. + + :param traj: The trajectory to be analyzed. + :type traj: :class:`~ost.mol.CoordGroupHandle` + :param atom1: The first :class:`~ost.mol.AtomHandle`. + :param atom2: The second :class:`~ost.mol.AtomHandle`. + :param stride: Size of the increment of the frame's index between two + consecutive frames analyzed. + + +.. function:: AnalyzeAngle(traj, atom1, atom2, atom3, stride=1) + + This function extracts the angle between three atoms from a trajectory + and returns it as a vector. The second atom is taken as being the central + atom, so that the angle is between the vectors (atom1.pos-atom2.pos) and + (atom3.pos-atom2.pos). + + :param traj: The trajectory to be analyzed. + :type traj: :class:`~ost.mol.CoordGroupHandle` + :param atom1: The first :class:`~ost.mol.AtomHandle`. + :param atom2: The second :class:`~ost.mol.AtomHandle`. + :param atom3: The third :class:`~ost.mol.AtomHandle`. + :param stride: Size of the increment of the frame's index between two + consecutive frames analyzed. + + +.. function:: AnalyzeDihedralAngle(traj, atom1, atom2, atom3, atom4, stride=1) + + This function extracts the dihedral angle between four atoms from a trajectory + and returns it as a vector. The angle is between the planes containing the + first three and the last three atoms. + + :param traj: The trajectory to be analyzed. + :type traj: :class:`~ost.mol.CoordGroupHandle` + :param atom1: The first :class:`~ost.mol.AtomHandle`. + :param atom2: The second :class:`~ost.mol.AtomHandle`. + :param atom3: The third :class:`~ost.mol.AtomHandle`. + :param atom4: The fourth :class:`~ost.mol.AtomHandle`. + :param stride: Size of the increment of the frame's index between two + consecutive frames analyzed. + +.. function:: AnalyzeDistanceBetwCenterOfMass(traj, sele1, sele2, stride=1) + + This function extracts the distance between the center-of-mass of two + selections (:class:`~ost.mol.EntityView`) from a trajectory and returns it as + a vector. + + :param traj: The trajectory to be analyzed. + :type traj: :class:`~ost.mol.CoordGroupHandle` + :param sele1: The selection from which the first center of mass is computed + :type sele1: :class:`~ost.mol.EntityView`. + :param sele2: The selection from which the second center of mass is computed + :type sele2: :class:`~ost.mol.EntityView`. + :param stride: Size of the increment of the frame's index between two + consecutive frames analyzed. + + +.. function:: AnalyzeRMSD(traj, reference_view, sele_view) + + This function extracts the rmsd between two :class:`~ost.mol.EntityView` and + returns it as a vector. The views don't have to be from the same entity. The + reference positions are taken directly from the reference_view, evaluated only + once. The positions from the sele_view are evaluated for each frame. + If you want to compare to frame i of the trajectory t, first use + t.CopyFrame(i) for example: + + .. code-block:: python + + eh=io.LoadPDB(...) + t=io.LoadCHARMMTraj(eh,...) + sele=eh.Select(...) + t.CopyFrame(0) + mol.alg.AnalyzeRMSD(t,sele,sele) + + :param traj: The trajectory to be analyzed. + :type traj: :class:`~ost.mol.CoordGroupHandle` + :param reference_view: The selection used as reference structure + :type reference_view: :class:`~ost.mol.EntityView`. + :param sele_view: The selection compared to the reference_view + :type sele_view: :class:`~ost.mol.EntityView`. + :param stride: Size of the increment of the frame's index between two + consecutive frames analyzed. + + + + + + + + + diff --git a/modules/mol/alg/pymod/CMakeLists.txt b/modules/mol/alg/pymod/CMakeLists.txt index 2fbf108cbe9133fcab98cd55b30fb99c74dabd2a..0ffb3f65183cb217c5fcfe6b1093a884ea42bca9 100644 --- a/modules/mol/alg/pymod/CMakeLists.txt +++ b/modules/mol/alg/pymod/CMakeLists.txt @@ -2,6 +2,7 @@ set(OST_MOL_ALG_PYMOD_SOURCES wrap_mol_alg.cc export_svd_superpose.cc export_clash.cc + export_trajectory_analysis.cc ) set(OST_MOL_ALG_PYMOD_MODULES diff --git a/modules/mol/alg/pymod/export_superpose_frames.cc b/modules/mol/alg/pymod/export_superpose_frames.cc new file mode 100644 index 0000000000000000000000000000000000000000..e1d55652052388dbf7721f6d030fbe6ef0cbe79f --- /dev/null +++ b/modules/mol/alg/pymod/export_superpose_frames.cc @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ + +/* + * Author Marco Biasini + */ +#include <boost/python.hpp> +using namespace boost::python; +#include <ost/mol/alg/superpose_frames.hh> + +using namespace ost; +using namespace ost::mol::alg; + +void export_SuperposeFrames() +{ + def("SuperposeFrames", &SuperposeFrames); +} + diff --git a/modules/mol/alg/pymod/export_trajectory_analysis.cc b/modules/mol/alg/pymod/export_trajectory_analysis.cc new file mode 100644 index 0000000000000000000000000000000000000000..61e153bb3f060f61937bb75d8ebb4458d6edcb1b --- /dev/null +++ b/modules/mol/alg/pymod/export_trajectory_analysis.cc @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2011 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ +#include <boost/python.hpp> +using namespace boost::python; + +#include <ost/mol/alg/trajectory_analysis.hh> + +using namespace ost; +using namespace ost::mol::alg; + +//"thin wrappers" for default parameters +/* +BOOST_PYTHON_FUNCTION_OVERLOADS(extractapos, ExtractAtomPosition, 2, 3) +BOOST_PYTHON_FUNCTION_OVERLOADS(extractcmpos, ExtractCMPosition, 2, 3) +BOOST_PYTHON_FUNCTION_OVERLOADS(extractdist, ExtractDistance, 3, 4) +BOOST_PYTHON_FUNCTION_OVERLOADS(extractang, ExtractAngle, 4, 5) +BOOST_PYTHON_FUNCTION_OVERLOADS(extractdih, ExtractDihedral, 5, 6) +BOOST_PYTHON_FUNCTION_OVERLOADS(extractcmdist, ExtractCMDistance, 3, 4) +BOOST_PYTHON_FUNCTION_OVERLOADS(extractrmsd, ExtractRMSD, 3, 4) +*/ +void export_TrajectoryAnalysis() +{ + def("AnalyzeAtomPos",&AnalyzeAtomPos, (arg("traj"), arg("atom"), arg("stride")=1)); + def("AnalyzeCenterOfMassPos",&AnalyzeCenterOfMassPos, (arg("traj"), arg("selection"), arg("stride")=1)); + def("AnalyzeDistanceBetwAtoms",&AnalyzeDistanceBetwAtoms, (arg("traj"), arg("atom"), arg("atom"), arg("stride")=1)); + def("AnalyzeAngle",&AnalyzeAngle, (arg("traj"), arg("atom"), arg("atom"), arg("atom"), arg("stride")=1)); + def("AnalyzeDihedralAngle",&AnalyzeDihedralAngle, (arg("traj"), arg("atom"), arg("atom"), arg("atom"), arg("atom"), arg("stride")=1)); + def("AnalyzeDistanceBetwCenterOfMass",&AnalyzeDistanceBetwCenterOfMass, (arg("traj"), arg("selection"), arg("selection"), arg("stride")=1)); + def("AnalyzeRMSD",&AnalyzeRMSD, (arg("traj"), arg("reference_view"), arg("selection"), arg("stride")=1)); +} diff --git a/modules/mol/alg/pymod/wrap_mol_alg.cc b/modules/mol/alg/pymod/wrap_mol_alg.cc index 82803c983ac9eed3ecc0364326310476be57ece9..48e19d84fc7b35e599454f809c07b27abcf1c461 100644 --- a/modules/mol/alg/pymod/wrap_mol_alg.cc +++ b/modules/mol/alg/pymod/wrap_mol_alg.cc @@ -26,7 +26,8 @@ using namespace boost::python; using namespace ost; void export_svdSuperPose(); - +void export_TrajectoryAnalysis(); +void export_Clash(); #if OST_IMG_ENABLED void export_entity_to_density(); #endif @@ -42,6 +43,7 @@ mol::EntityView (*fc_b)(const mol::EntityHandle&, Real, bool)=&mol::alg::FilterC BOOST_PYTHON_MODULE(_ost_mol_alg) { export_svdSuperPose(); + export_TrajectoryAnalysis(); #if OST_IMG_ENABLED export_entity_to_density(); #endif diff --git a/modules/mol/alg/src/CMakeLists.txt b/modules/mol/alg/src/CMakeLists.txt index ae27e33e6f0160d5556d0028cc3d75fe32e16c62..1bd52057e93d59a5de0ec09edab397b5bc812261 100644 --- a/modules/mol/alg/src/CMakeLists.txt +++ b/modules/mol/alg/src/CMakeLists.txt @@ -7,6 +7,7 @@ set(OST_MOL_ALG_HEADERS filter_clashes.hh construct_cbeta.hh clash_score.hh + trajectory_analysis.hh ) set(OST_MOL_ALG_SOURCES @@ -17,6 +18,7 @@ set(OST_MOL_ALG_SOURCES superpose_frames.cc filter_clashes.cc construct_cbeta.cc + trajectory_analysis.cc ) set(MOL_ALG_DEPS ost_mol ost_seq) diff --git a/modules/mol/alg/src/filter_clashes.cc b/modules/mol/alg/src/filter_clashes.cc index bfb435c2f2f06d97dba79180591d057af380fe62..0fbca1696e5bc3ef1196f6d2a4863a1b0d72dcef 100644 --- a/modules/mol/alg/src/filter_clashes.cc +++ b/modules/mol/alg/src/filter_clashes.cc @@ -132,6 +132,7 @@ EntityView FilterClashes(const EntityView& ent, Real tolerance, filtered.AddAtom(atom); } } + continue; } filtered.AddResidue(res, ViewAddFlag::INCLUDE_ATOMS); } diff --git a/modules/mol/alg/src/trajectory_analysis.cc b/modules/mol/alg/src/trajectory_analysis.cc new file mode 100644 index 0000000000000000000000000000000000000000..c8660fc99d1ae118daac98fe802c5fe8ad29564a --- /dev/null +++ b/modules/mol/alg/src/trajectory_analysis.cc @@ -0,0 +1,157 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2011 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ + +/* + * Author Niklaus Johner + */ +#include <stdexcept> +#include <ost/base.hh> +#include <ost/geom/vec3.hh> +#include <ost/base.hh> +#include <ost/geom/geom.hh> +#include <ost/mol/entity_view.hh> +#include <ost/mol/coord_group.hh> +#include "trajectory_analysis.hh" + + +namespace ost { namespace mol { namespace alg { + +geom::Vec3List AnalyzeAtomPos(const CoordGroupHandle& traj, const AtomHandle& a1, unsigned int stride) +//This function extracts the position of an atom from a trajectory and returns it as a vector of geom::Vec3 +{ + CheckHandleValidity(traj); + geom::Vec3List pos; + pos.reserve(ceil(traj.GetFrameCount()/float(stride))); + int i1=a1.GetIndex(); + for (size_t i=0; i<traj.GetFrameCount(); i+=stride) { + CoordFramePtr frame=traj.GetFrame(i); + pos.push_back(frame->GetAtomPos(i1)); + } + return pos; +} + +std::vector<Real> AnalyzeDistanceBetwAtoms(const CoordGroupHandle& traj, const AtomHandle& a1, const AtomHandle& a2, + unsigned int stride) +//This function extracts the distance between two atoms from a trajectory and returns it as a vector +{ + CheckHandleValidity(traj); + std::vector<Real> dist; + dist.reserve(ceil(traj.GetFrameCount()/float(stride))); + int i1=a1.GetIndex(); + int i2=a2.GetIndex(); + for (size_t i=0; i<traj.GetFrameCount(); i+=stride) { + CoordFramePtr frame=traj.GetFrame(i); + dist.push_back(frame->GetDistanceBetwAtoms(i1,i2)); + } + return dist; +} + +std::vector<Real> AnalyzeAngle(const CoordGroupHandle& traj, const AtomHandle& a1, const AtomHandle& a2, + const AtomHandle& a3, unsigned int stride) +//This function extracts the angle between three atoms from a trajectory and returns it as a vector +{ + CheckHandleValidity(traj); + std::vector<Real> ang; + ang.reserve(ceil(traj.GetFrameCount()/float(stride))); + int i1=a1.GetIndex(),i2=a2.GetIndex(),i3=a3.GetIndex(); + for (size_t i=0; i<traj.GetFrameCount(); i+=stride) { + CoordFramePtr frame=traj.GetFrame(i); + ang.push_back(frame->GetAngle(i1,i2,i3)); + } + return ang; +} + +std::vector<Real> AnalyzeDihedralAngle(const CoordGroupHandle& traj, const AtomHandle& a1, const AtomHandle& a2, + const AtomHandle& a3, const AtomHandle& a4, unsigned int stride) +//This function extracts the dihedral angle between four atoms from a trajectory and returns it as a vector +{ + CheckHandleValidity(traj); + std::vector<Real> ang; + ang.reserve(ceil(traj.GetFrameCount()/float(stride))); + int i1=a1.GetIndex(),i2=a2.GetIndex(),i3=a3.GetIndex(),i4=a4.GetIndex(); + for (size_t i=0; i<traj.GetFrameCount(); i+=stride) { + CoordFramePtr frame=traj.GetFrame(i); + ang.push_back(frame->GetDihedralAngle(i1,i2,i3,i4)); + } + return ang; +} + +geom::Vec3List AnalyzeCenterOfMassPos(const CoordGroupHandle& traj, const EntityView& Sele,unsigned int stride) +//This function extracts the position of the CenterOfMass of a selection (entity view) from a trajectory +//and returns it as a vector. + { + CheckHandleValidity(traj); + geom::Vec3List pos; + pos.reserve(ceil(traj.GetFrameCount()/float(stride))); + std::vector<unsigned long> indices; + std::vector<Real> masses; + GetIndicesAndMasses(Sele, indices, masses); + for (size_t i=0; i<traj.GetFrameCount(); i+=stride) { + CoordFramePtr frame=traj.GetFrame(i); + pos.push_back(frame->GetCenterOfMassPos(indices,masses)); + } + return pos; +} + +std::vector<Real> AnalyzeDistanceBetwCenterOfMass(const CoordGroupHandle& traj, const EntityView& Sele1, + const EntityView& Sele2, unsigned int stride) +//This function extracts the distance between the CenterOfMass of two selection (entity views) from a trajectory +//and returns it as a vector. + { + CheckHandleValidity(traj); + std::vector<Real> dist; + dist.reserve(ceil(traj.GetFrameCount()/float(stride))); + std::vector<unsigned long> indices1,indices2; + std::vector<Real> masses1,masses2; + GetIndicesAndMasses(Sele1, indices1, masses1); + GetIndicesAndMasses(Sele2, indices2, masses2); + for (size_t i=0; i<traj.GetFrameCount(); i+=stride) { + CoordFramePtr frame=traj.GetFrame(i); + dist.push_back(frame->GetDistanceBetwCenterOfMass(indices1,masses1,indices2,masses2)); + } + return dist; +} + +std::vector<Real> AnalyzeRMSD(const CoordGroupHandle& traj, const EntityView& reference_view, + const EntityView& sele_view, unsigned int stride) +// This function extracts the rmsd between two entity views and returns it as a vector +// The views don't have to be from the same entity +// If you want to compare to frame i of the trajectory t, first use t.CopyFrame(i) for example: +// eh=io.LoadPDB(...),t=io.LoadCHARMMTraj(eh,...);Sele=eh.Select(...);t.CopyFrame(0);mol.alg.AnalyzeRMSD(t,Sele,Sele) + { + CheckHandleValidity(traj); + int count_ref=reference_view.GetAtomCount(); + int count_sele=sele_view.GetAtomCount(); + if (count_ref!=count_sele){ + throw std::runtime_error("atom counts of the two views are not equal"); + } + std::vector<Real> rmsd; + rmsd.reserve(ceil(traj.GetFrameCount()/float(stride))); + std::vector<unsigned long> sele_indices; + std::vector<geom::Vec3> ref_pos; + GetIndices(reference_view, sele_indices); + GetPositions(sele_view, ref_pos); + for (size_t i=0; i<traj.GetFrameCount(); i+=stride) { + CoordFramePtr frame=traj.GetFrame(i); + rmsd.push_back(frame->GetRMSD(ref_pos,sele_indices)); + } + return rmsd; +} + +}}} //ns diff --git a/modules/mol/alg/src/trajectory_analysis.hh b/modules/mol/alg/src/trajectory_analysis.hh new file mode 100644 index 0000000000000000000000000000000000000000..d2947e63b52a499e84569695e3bfe9f7b6af51a2 --- /dev/null +++ b/modules/mol/alg/src/trajectory_analysis.hh @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2011 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ + +/* + * Niklaus Johner + */ +#ifndef OST_TRAJECTORY_ANALYSIS_HH +#define OST_TRAJECTORY_ANALYSIS_HH + +#include <ost/mol/alg/module_config.hh> + +#include <ost/base.hh> +#include <ost/geom/geom.hh> +#include <ost/mol/entity_view.hh> +#include <ost/mol/coord_group.hh> + + +namespace ost { namespace mol { namespace alg { + + geom::Vec3List DLLEXPORT_OST_MOL_ALG AnalyzeAtomPos(const CoordGroupHandle& traj, const AtomHandle& a1,unsigned int stride=1); + geom::Vec3List DLLEXPORT_OST_MOL_ALG AnalyzeCenterOfMassPos(const CoordGroupHandle& traj, const EntityView& sele,unsigned int stride=1); + std::vector<Real> DLLEXPORT_OST_MOL_ALG AnalyzeDistanceBetwAtoms(const CoordGroupHandle& traj, const AtomHandle& a1, const AtomHandle& a2,unsigned int stride=1); + std::vector<Real> DLLEXPORT_OST_MOL_ALG AnalyzeAngle(const CoordGroupHandle& traj, const AtomHandle& a1, const AtomHandle& a2, const AtomHandle& a3,unsigned int stride=1); + std::vector<Real> DLLEXPORT_OST_MOL_ALG AnalyzeDistanceBetwCenterOfMass(const CoordGroupHandle& traj, const EntityView& sele1, const EntityView& sele2,unsigned int stride=1); + std::vector<Real> DLLEXPORT_OST_MOL_ALG AnalyzeDihedralAngle(const CoordGroupHandle& traj, const AtomHandle& a1, const AtomHandle& a2, const AtomHandle& a3, const AtomHandle& a4,unsigned int stride=1); + std::vector<Real> DLLEXPORT_OST_MOL_ALG AnalyzeRMSD(const CoordGroupHandle& traj, const EntityView& reference_view, const EntityView& sele,unsigned int stride=1); + + +}}}//ns +#endif diff --git a/modules/mol/alg/tests/CMakeLists.txt b/modules/mol/alg/tests/CMakeLists.txt index 09d1934f76b97f775c01381c741d1a9c33a530f5..1008a3578e384b05160bf5ea4a127d1be693b349 100644 --- a/modules/mol/alg/tests/CMakeLists.txt +++ b/modules/mol/alg/tests/CMakeLists.txt @@ -4,5 +4,5 @@ set(OST_MOL_ALG_UNIT_TESTS test_convenient_superpose.py ) -ost_unittest(mol_alg "${OST_MOL_ALG_UNIT_TESTS}") +ost_unittest(MODULE mol_alg SOURCES "${OST_MOL_ALG_UNIT_TESTS}") diff --git a/modules/mol/base/doc/entity.rst b/modules/mol/base/doc/entity.rst index 4520df521aa86b3f51c8e61bd59a03864903a76b..1ee9e6bdae35cce7abfe51d84e0315a354bc25da 100644 --- a/modules/mol/base/doc/entity.rst +++ b/modules/mol/base/doc/entity.rst @@ -583,7 +583,18 @@ The Handle Classes .. attribute:: pos - The atom's position in global coordinates. Also available as :meth:`GetPos`. + The atom's position in global coordinates, transformed by the entity + transformation. Also available as :meth:`GetPos`. + + Read-only. + + :type: :class:`~ost.geom.Vec3` + + .. attribute:: original_pos + + The atom's untransformed position in global coordinates. Also available as + :meth:`GetOriginalPos`. + Read-only. :type: :class:`~ost.geom.Vec3` diff --git a/modules/mol/base/doc/mol.rst b/modules/mol/base/doc/mol.rst index 1ac7e3f2691b0a28cd299f7176ffa43e8bb4451b..976c2c8aa1ced240e5c461fb7f46745c60d0b36a 100644 --- a/modules/mol/base/doc/mol.rst +++ b/modules/mol/base/doc/mol.rst @@ -12,4 +12,5 @@ The mol module implements data structures to work with molecular datasets. At it entity editors query - surface \ No newline at end of file + surface + traj \ No newline at end of file diff --git a/modules/mol/base/doc/traj.rst b/modules/mol/base/doc/traj.rst new file mode 100644 index 0000000000000000000000000000000000000000..41730915f3efd9c94fc6fe59598f01f9a4125812 --- /dev/null +++ b/modules/mol/base/doc/traj.rst @@ -0,0 +1,220 @@ +Trajectories +================================================================================ + +.. currentmodule:: ost.mol + + +.. function:: CreateCoordGroup(atoms) + + :param atoms: List of atoms. All atoms must be from the same entity. + :type atoms: :class:`AtomHandleList` + + :rtype: :class:`CoordGroupHandle` + :returns: A coord group with zero frames + +.. class:: CoordGroupHandle + + A collection of coordinate frames, e.g. an MD trajectory. Create with + :func:`CreateCoordGroup`. + + + .. attribute:: entity + + The attached entity. + + :type: :class:`EntityHandle` + + .. attribute:: atoms + + The atoms of this coord group. The order of atoms is the same as the + positions in the coord frames. All atoms are from the same entity. + + :type: :class:`AtomHandleList` + .. method:: AddFrames(frames) + + Combine two trajectories by appending the frames of the second to the first + :param frames: a valid coord group + :type frames: :class:`CoordGroupHandle` + + .. method:: Capture() + + Record the atom positions of the entity attached to this coord group in a + new coordinate frame. Note that the atom positions transformed by the entity + transform will be stored. Only available for mutable coord groups. + + :see: :attr:`AtomHandle.pos` + + .. method:: CaptureInto(frame_index) + + Same as :meth:`Capture`, but doesn't create a new frame and stores the + coordinates directly into frame with index *frame_index*. Only available for + mutable coord groups. + + :param frame_index: index of the frame + :type frame_index: int + + .. method:: CopyFrame(frame_index) + + Copies the coordinates of frame with index *frame_index* to the attached + entity. + + :param frame_index: index of the frame + :type frame_index: int + + .. method:: Filter(view) + + Returns a new trajectory containing only coordinates of the atoms in view. + Useful to remove water and other solvent molecules from a trajectory to + save memory. + + :param view: a valid entity view + :type view: :class:`EntityView` + :rtype: :class:`CoordGroupHandle` + + .. method:: GetAtomCount() + + Returns the number of atoms in the coord group + + :rtype: int + + + .. method:: GetAtomList() + + Returns the atoms of the coord group in the same order they appear in the + coordinate frames. + + :rtype: :class:`AtomHandleList` + + .. method:: GetAtomPos(frame_index, atom) + + Get position of *atom* in frame with index *frame_index*. + + + :param frame_index: frame index + :type frame_index: int + :param atom: A valid atom + :type atom: :class:`AtomHandle` + :rtype: :class:`Vec3` + + .. method:: GetEntity() + + Returns the attached entity + + :rtype: :class:`EntityHandle` + + .. method:: GetFrameCount() + + Returns the number of frames of this coord group + + :rtype: int + + .. method:: IsValid() + + Whether this coord group is valid + + :rtype: bool + + .. method:: SetAtomPos(frame_index, atom, pos) + + Set position of *atom* in frame with index *frame_index* to *pos* + + :param frame_index: index of the frame + :type frame_index: int + :param atom: a valid atom + :type atom: :class:`AtomHandle` + :param pos: new position of the atom + :type pos: :class:`Vec3` + + .. method:: SetFramePositions(frame_index, positions) + + Set the frame positions of frame with index *frame_index*. Order and count + of positions must match :attr:`atoms`. + + :param frame_index: index of frame + :type frame_index: int + :param positions: list of positions + :type positions: :class:`~ost.geom.Vec3List` + + +.. class:: CoordFrame + + A single frame of coordinates in a :class:`CoordGroupHandle`. + + .. method:: GetAngle(atom1, atom2, atom3) + + :param atom1: first atom + :type atom1: :class:`AtomHandle` + :param atom2: second (central) atom + :type atom2: :class:`AtomHandle` + :param atom3: third atom + :type atom3: :class:`AtomHandle` + + :returns: the angle in radians between the 3 atoms + :rtype: float + + .. method:: GetAtomPos(atom) + + Returns the position of the atom in the coord frame + + :param atom: A valid atom handle + :type atom: :class:`AtomHandle` + + + + :rtype: :class:`Vec3` + + .. method:: GetCenterOfMassPos(view) + + + :param view: A valid entity view + :type view: :class:`EntityView` + :rtype: :class:`Vec3` + + .. method:: GetDihedralAngle(atom1, atom2, atom3, atom4) + + Get dihedral angle of the four atoms. + + :param atom1: First atom. Must be valid + :type atom1: :class:`AtomHandle` + :param atom2: Second atom. Must be valid + :type atom2: :class:`AtomHandle` + :param atom3: Third atom. Must be valid + :type atom3: :class:`AtomHandle` + :param atom3: Fourth atom. Must be valid + :type atom3: :class:`AtomHandle` + + :rtype: float + + .. method:: GetDistanceBetwAtoms(atom1, atom2) + + Get distance in (Angstroem) between *atom1* and *atom2* in coord frame. + + :param atom1: First atom. Must be valid + :type atom1: :class:`AtomHandle` + :param atom2: Second atom. Must be valid + :type atom2: :class:`AtomHandle` + :rtype: float + + .. method:: GetDistanceBetwCenterOfMass(view1, view2) + + Get distance between center of mass of the first selection and the second. + + :param view1: First view. Must be valid + :type view1: :class:`EntityView` + :param view2: Second view. Must be valid + :type view2: :class:`EntityView` + :rtype: float + + .. method:: GetRMSD(view1, view2) + + Get RMSD between two views in the coord frame. The coordinates of the views + are taken as is without superposition. The two views must have the same + number of atoms. Atoms are matches as they appear in + :attr:`EntityView.atoms`. + + :param view1: First view. Must be valid + :type view1: :class:`EntityView` + :param view2: Second view. Must be valid + :type view2: :class:`EntityView` + :rtype: float + diff --git a/modules/mol/base/pymod/CMakeLists.txt b/modules/mol/base/pymod/CMakeLists.txt index 29c336dca643d9bbafac80ad9fb5e3959e6ef48c..87369f260e9e199fbcd107304f729f616d0d45c6 100644 --- a/modules/mol/base/pymod/CMakeLists.txt +++ b/modules/mol/base/pymod/CMakeLists.txt @@ -5,6 +5,7 @@ export_bond.cc export_chain.cc export_chain_view.cc export_coord_group.cc +export_coord_frame.cc export_editors.cc export_entity.cc export_entity_view.cc diff --git a/modules/mol/base/pymod/__init__.py b/modules/mol/base/pymod/__init__.py index 75c503acf6f3ec1d787879f494bece9bf00e4359..8eb77fa6d3055f6259d7d1aa4c31ccffb9da7098 100644 --- a/modules/mol/base/pymod/__init__.py +++ b/modules/mol/base/pymod/__init__.py @@ -32,4 +32,4 @@ def MergeCoordGroups(*coord_groups): cg=CreateCoordGroup(coord_groups[0].atoms) for coord_group in coord_groups: cg.AddFrames(coord_group) - return cg \ No newline at end of file + return cg diff --git a/modules/mol/base/pymod/export_atom.cc b/modules/mol/base/pymod/export_atom.cc index 42e18e0ce5f720e439429536192f10576608c5bd..f232d498cc3f52d61419d0c441c59e530470f737 100644 --- a/modules/mol/base/pymod/export_atom.cc +++ b/modules/mol/base/pymod/export_atom.cc @@ -53,6 +53,9 @@ void export_Atom() .add_property("pos", make_function(&AtomBase::GetPos, return_value_policy<copy_const_reference>())) + .add_property("original_pos", + make_function(&AtomBase::GetOriginalPos, + return_value_policy<copy_const_reference>())) .add_property("name", make_function(&AtomBase::GetName, return_value_policy<copy_const_reference>()), diff --git a/modules/mol/base/pymod/export_coord_frame.cc b/modules/mol/base/pymod/export_coord_frame.cc new file mode 100644 index 0000000000000000000000000000000000000000..16665e0bb1ea3759f7cbcc62da1e2a4931df6aa4 --- /dev/null +++ b/modules/mol/base/pymod/export_coord_frame.cc @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2011 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ +#include <boost/python.hpp> +using namespace boost::python; + +#include <ost/mol/coord_frame.hh> +#include <ost/geom/vec3.hh> +#include <ost/mol/entity_handle.hh> + +using namespace ost; +using namespace ost::mol; + +geom::Vec3 (CoordFrame::*get_atom_pos)(const AtomHandle& atom) = &CoordFrame::GetAtomPos; +Real (CoordFrame::*get_dist_atom)(const AtomHandle& a1, const AtomHandle& a2) = &CoordFrame::GetDistanceBetwAtoms; +Real (CoordFrame::*get_angle)(const AtomHandle& a1, const AtomHandle& a2, const AtomHandle& a3) = &CoordFrame::GetAngle; +Real (CoordFrame::*get_dihedral)(const AtomHandle& a1, const AtomHandle& a2, const AtomHandle& a3, const AtomHandle& a4) = &CoordFrame::GetDihedralAngle; +geom::Vec3 (CoordFrame::*get_cm)(const mol::EntityView& sele) = &CoordFrame::GetCenterOfMassPos; +Real (CoordFrame::*get_dist_cm)(const mol::EntityView& sele1, const mol::EntityView& sele2) = &CoordFrame::GetDistanceBetwCenterOfMass; +Real (CoordFrame::*get_rmsd)(const mol::EntityView& Reference_View, const mol::EntityView& sele_View) = &CoordFrame::GetRMSD; + + +void export_CoordFrame() +{ + class_<CoordFrame>("CoordFrame",no_init) + .def("GetAtomPos", get_atom_pos) + .def("GetDistanceBetwAtoms", get_dist_atom) + .def("GetAngle", get_angle) + .def("GetDihedralAngle", get_dihedral) + .def("GetCenterOfMassPos", get_cm) + .def("GetDistanceBetwCenterOfMass", get_dist_cm) + .def("GetRMSD",get_rmsd) + ; + def("CreateCoordFrame",CreateCoordFrame); +} diff --git a/modules/mol/base/pymod/export_coord_group.cc b/modules/mol/base/pymod/export_coord_group.cc index ebd0f1f33daa0fc703d92f4e5351626741b52f61..794db5363c6ae050262e51c29608977ef83d569a 100644 --- a/modules/mol/base/pymod/export_coord_group.cc +++ b/modules/mol/base/pymod/export_coord_group.cc @@ -53,6 +53,7 @@ void export_CoordGroup() .def("GetAtomPos",&CoordGroupHandle::GetAtomPos) .def("CopyFrame",&CoordGroupHandle::CopyFrame) .add_property("atoms", &CoordGroupHandle::GetAtomList) + .add_property("entity", &CoordGroupHandle::GetEntity) .def("IsValid", &CoordGroupHandle::IsValid) .def("Capture", capture1) .def("Capture", capture2) diff --git a/modules/mol/base/pymod/export_editors.cc b/modules/mol/base/pymod/export_editors.cc index 0b469fec3909ddcf45ccf9bd4f4e4e3b5d0b4c18..34d3a7fe8960cba5019702873fca197995f22eb0 100644 --- a/modules/mol/base/pymod/export_editors.cc +++ b/modules/mol/base/pymod/export_editors.cc @@ -26,6 +26,10 @@ using namespace boost::python; using namespace ost; using namespace ost::mol; +#if OST_NUMPY_SUPPORT_ENABLED +#include <numpy/arrayobject.h> +#endif + namespace { BondHandle (EditorBase::*connect_a)(const AtomHandle&, @@ -53,11 +57,143 @@ void (ICSEditor::*rotate_torsion_a)(TorsionHandle, Real)=&ICSEditor::RotateTorsi void (ICSEditor::*rotate_torsion_b)(const AtomHandle&, const AtomHandle&, const AtomHandle&, const AtomHandle&, Real)=&ICSEditor::RotateTorsionAngle; - + +#if OST_NUMPY_SUPPORT_ENABLED +template<typename T, bool O> +void set_pos2_nc_t(XCSEditor& e, const AtomHandleList& alist, PyArrayObject* na) +{ + size_t count=0; + for(AtomHandleList::const_iterator ait=alist.begin();ait!=alist.end();++ait,++count) { + if(O) { + e.SetAtomOriginalPos(*ait,geom::Vec3(static_cast<Real>(*reinterpret_cast<T*>(PyArray_GETPTR2(na,count,0))), + static_cast<Real>(*reinterpret_cast<T*>(PyArray_GETPTR2(na,count,1))), + static_cast<Real>(*reinterpret_cast<T*>(PyArray_GETPTR2(na,count,2))))); + } else { + e.SetAtomTransformedPos(*ait,geom::Vec3(static_cast<Real>(*reinterpret_cast<T*>(PyArray_GETPTR2(na,count,0))), + static_cast<Real>(*reinterpret_cast<T*>(PyArray_GETPTR2(na,count,1))), + static_cast<Real>(*reinterpret_cast<T*>(PyArray_GETPTR2(na,count,2))))); + } + } +} + +template<bool O> +void set_pos2_t(XCSEditor& e, const AtomHandleList& alist, object pyobj) +{ + size_t acount = alist.size(); + + if(!PyArray_Check(pyobj.ptr())) { + throw std::runtime_error("expected a numpy array"); + return; + } + PyArrayObject* na=reinterpret_cast<PyArrayObject*>(pyobj.ptr()); + + if(PyArray_NDIM(na)!=2 || PyArray_DIM(na,0)!=int(acount) || PyArray_DIM(na,1)!=3) { + throw std::runtime_error("excpected a numpy array of shape (NAtoms, 3)"); + return; + } + + if(PyArray_ISCONTIGUOUS(na)) { + if(PyArray_TYPE(na)==NPY_FLOAT) { + if(O) { + e.SetAtomOriginalPos(alist,reinterpret_cast<float*>(PyArray_DATA(na))); + } else { + e.SetAtomTransformedPos(alist,reinterpret_cast<float*>(PyArray_DATA(na))); + } + } else if(PyArray_TYPE(na)==NPY_DOUBLE) { + if(O) { + e.SetAtomOriginalPos(alist,reinterpret_cast<double*>(PyArray_DATA(na))); + } else { + e.SetAtomTransformedPos(alist,reinterpret_cast<double*>(PyArray_DATA(na))); + } + } else { + throw std::runtime_error("expected a numpy array of type float or double"); + return; + } + } else { + // non-contiguous +#if 0 + throw std::runtime_error("expected contiguous numpy array"); +#else + if(PyArray_TYPE(na)==NPY_FLOAT) { + set_pos2_nc_t<float,O>(e,alist,na); + } else if(PyArray_TYPE(na)==NPY_DOUBLE) { + set_pos2_nc_t<double,O>(e,alist,na); + } else { + throw std::runtime_error("expected a numpy array of type float or double"); + return; + } +#endif + } +} +#endif + +void set_pos(XCSEditor& e, object o1, object o2, bool trans) +{ + extract<AtomHandle> eah(o1); + extract<geom::Vec3> ev3(o2); + if(eah.check() && ev3.check()) { + if(trans) { + e.SetAtomTransformedPos(eah(),ev3()); + } else { + e.SetAtomOriginalPos(eah(),ev3()); + } + return; + } + +#if OST_NUMPY_SUPPORT_ENABLED + + extract<AtomHandleList> eal(o1); + if(eal.check()) { + if(trans) { + set_pos2_t<false>(e,eal(),o2); + } else { + set_pos2_t<true>(e,eal(),o2); + } + return; + } + + std::map<unsigned long,AtomHandle> amap; + EntityHandle eh=e.GetEntity(); + for(AtomHandleIter ait=eh.AtomsBegin(), aite=eh.AtomsEnd(); ait!=aite; ++ait) { + amap[(*ait).GetIndex()]=*ait; + } + + AtomHandleList alist; + for(int i=0;i<len(o1);++i) { + int gid = extract<int>(o1[i]); + std::map<unsigned long,AtomHandle>::iterator ait=amap.find(static_cast<unsigned long>(gid)); + alist.push_back(ait==amap.end() ? AtomHandle() : ait->second); + } + + if(trans) { + set_pos2_t<false>(e,alist,o2); + } else { + set_pos2_t<true>(e,alist,o2); + } + +#else + throw std::runtime_error("SetAtom*Pos(...,ndarray) not available, because numpy support not compiled in"); +#endif +} + +void set_o_pos(XCSEditor& e, object o1, object o2) +{ + set_pos(e,o1,o2,false); +} + +void set_t_pos(XCSEditor& e, object o1, object o2) +{ + set_pos(e,o1,o2,true); +} + } void export_Editors() -{ +{ +#if OST_NUMPY_SUPPORT_ENABLED + import_array(); +#endif + class_<EditorBase>("EditorBase", no_init) .def("InsertChain", &EditorBase::InsertChain) .def("InsertAtom", &EditorBase::InsertAtom, @@ -84,8 +220,9 @@ void export_Editors() ; class_<XCSEditor, bases<EditorBase> >("XCSEditor", no_init) - .def("SetAtomPos", &XCSEditor::SetAtomPos) - .def("SetAtomOriginalPos", &XCSEditor::SetAtomOriginalPos) + .def("SetAtomPos", set_t_pos) + .def("SetAtomTransformedPos", set_t_pos) + .def("SetAtomOriginalPos", set_o_pos) .def("ApplyTransform", &XCSEditor::ApplyTransform) .def("SetTransform", &XCSEditor::SetTransform) .def("UpdateICS", &XCSEditor::UpdateICS) diff --git a/modules/mol/base/pymod/export_entity.cc b/modules/mol/base/pymod/export_entity.cc index 163918c75642b0e1da67336dcad2619e30c84da8..6ae3727031bf27cd0ced5adcb638d20f0d7b83e2 100644 --- a/modules/mol/base/pymod/export_entity.cc +++ b/modules/mol/base/pymod/export_entity.cc @@ -30,6 +30,10 @@ using namespace ost::mol; #include <ost/export_helper/generic_property_def.hh> +#if OST_NUMPY_SUPPORT_ENABLED +#include <numpy/arrayobject.h> +#endif + namespace { EntityHandle create1() { return CreateEntity(); } @@ -64,11 +68,55 @@ ICSEditor depr_request_ics_editor(EntityHandle e, EditMode m) return e.EditICS(m); } +bool less_index(const mol::AtomHandle& a1, const mol::AtomHandle& a2) +{ + return a1.GetIndex()<a2.GetIndex(); +} + + +PyObject* get_pos2(EntityHandle& entity, bool id_sorted) +{ +#if OST_NUMPY_SUPPORT_ENABLED + npy_intp dims[]={entity.GetAtomCount(),3}; + PyObject* na = PyArray_SimpleNew(2,dims,NPY_FLOAT); + npy_float* nad = reinterpret_cast<npy_float*>(PyArray_DATA(na)); + if(id_sorted) { + AtomHandleList alist = entity.GetAtomList(); + std::sort(alist.begin(),alist.end(),less_index); + for(AtomHandleList::const_iterator it=alist.begin();it!=alist.end();++it,nad+=3) { + geom::Vec3 pos=(*it).GetPos(); + nad[0]=static_cast<npy_float>(pos[0]); + nad[1]=static_cast<npy_float>(pos[1]); + nad[2]=static_cast<npy_float>(pos[2]); + } + } else { + for(AtomHandleIter it=entity.AtomsBegin();it!=entity.AtomsEnd();++it,nad+=3) { + geom::Vec3 pos=(*it).GetPos(); + nad[0]=static_cast<npy_float>(pos[0]); + nad[1]=static_cast<npy_float>(pos[1]); + nad[2]=static_cast<npy_float>(pos[2]); + } + } + return na; +#else + throw std::runtime_error("GetPositions disabled, since numpy support is not compiled in"); + return 0; +#endif +} +PyObject* get_pos1(EntityHandle& entity) +{ + return get_pos2(entity,true); } +} // ns + void export_Entity() { +#if OST_NUMPY_SUPPORT_ENABLED + import_array(); +#endif + class_<EntityBase> ent_base("EntityBase", no_init); ent_base .def(self_ns::str(self)) @@ -139,6 +187,11 @@ void export_Entity() .def("IsTransformationIdentity",&EntityHandle::IsTransformationIdentity) .def(self==self) .def(self!=self) +#if OST_NUMPY_SUPPORT_ENABLED + .def("GetPositions",get_pos1) + .def("GetPositions",get_pos2) + .add_property("positions",get_pos1) +#endif ; def("CreateEntity",create1); diff --git a/modules/mol/base/pymod/wrap_mol.cc b/modules/mol/base/pymod/wrap_mol.cc index 0ab6b45681dfc9fd1d6f3c272407c56dff3e4cee..f29d1377f4bc0ccf14289b50df67e994208e99e5 100644 --- a/modules/mol/base/pymod/wrap_mol.cc +++ b/modules/mol/base/pymod/wrap_mol.cc @@ -39,6 +39,7 @@ void export_AtomView(); void export_ResidueView(); void export_Editors(); void export_CoordGroup(); +void export_CoordFrame(); void export_PropertyID(); void export_BoundingBox(); void export_QueryViewWrapper(); @@ -65,6 +66,7 @@ BOOST_PYTHON_MODULE(_ost_mol) export_EntityView(); export_Editors(); export_CoordGroup(); + export_CoordFrame(); export_PropertyID(); export_BoundingBox(); export_QueryViewWrapper(); diff --git a/modules/mol/base/src/atom_base.cc b/modules/mol/base/src/atom_base.cc index f25d40135a9770c0d9fc1fbad7c5641ed98c5e36..642ea5aa93baad015633ab13caedbb2f7e3f704d 100644 --- a/modules/mol/base/src/atom_base.cc +++ b/modules/mol/base/src/atom_base.cc @@ -42,25 +42,25 @@ const GenericPropContainerImpl* AtomBase::GpImpl() const const String& AtomBase::GetName() const { this->CheckValidity(); - return impl_->GetName(); + return impl_->Name(); } void AtomBase::SetName(const String& atom_name) { this->CheckValidity(); - return impl_->SetName(atom_name); + impl_->Name()=atom_name; } const geom::Vec3& AtomBase::GetPos() const { this->CheckValidity(); - return impl_->GetPos(); + return impl_->TransformedPos(); } const geom::Vec3& AtomBase::GetOriginalPos() const { this->CheckValidity(); - return impl_->GetOriginalPos(); + return impl_->OriginalPos(); } geom::Vec3 AtomBase::GetAltPos(const String& alt_group) const diff --git a/modules/mol/base/src/coord_frame.cc b/modules/mol/base/src/coord_frame.cc index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..80105c128fb3805765c0ccdd7c2f6f5095242ea6 100644 --- a/modules/mol/base/src/coord_frame.cc +++ b/modules/mol/base/src/coord_frame.cc @@ -0,0 +1,183 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2011 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ + +/* + Author: Niklaus Johner + */ + +#include <ost/invalid_handle.hh> +#include <ost/integrity_error.hh> +#include <ost/log.hh> +#include <ost/mol/in_mem_coord_source.hh> +#include <ost/mol/view_op.hh> +#include <ost/mol/mol.hh> +#include "coord_frame.hh" + +namespace ost { namespace mol { + + CoordFrame CreateCoordFrame(const geom::Vec3List& atom_pos) + { + return CoordFrame(atom_pos); + } + + geom::Vec3 CoordFrame::GetAtomPos(const AtomHandle& atom){ + //Returns the position of the atom in this frame + return this->GetAtomPos(atom.GetIndex()); + } + geom::Vec3 CoordFrame::GetAtomPos(int i1){ + //Returns the position in this frame of the atom with index i1 + return (*this)[i1]; + } + + Real CoordFrame::GetDistanceBetwAtoms(const AtomHandle& a1, const AtomHandle& a2){ + //Return the distance in this frame between two atoms + return this->GetDistanceBetwAtoms(a1.GetIndex(),a2.GetIndex()); + } + Real CoordFrame::GetDistanceBetwAtoms(int i1, int i2){ + //Return the distance in this frame between the two atoms with indices i1 and i2 + return geom::Distance((*this)[i1],(*this)[i2]); + } + + Real CoordFrame::GetAngle(const AtomHandle& a1, const AtomHandle& a2, const AtomHandle& a3){ + //Returns the Angle between the three atoms, a2 being considered as the central atom + //i.e the angle between the vector (a1.pos-a2.pos) and (a3.pos-a2.pos) + return this->GetAngle(a1.GetIndex(),a2.GetIndex(),a3.GetIndex()); + } + Real CoordFrame::GetAngle(int i1, int i2, int i3){ + //Returns the angl between the three atoms with indices i1,i2,i3 + return geom::Angle((*this)[i1]-(*this)[i2],(*this)[i3]-(*this)[i2]); + } + + Real CoordFrame::GetDihedralAngle(const AtomHandle& a1, const AtomHandle& a2, + const AtomHandle& a3, const AtomHandle& a4){ + //Returns the Dihedral angle between the four atoms a1,a2,a3,a4 + return this->GetDihedralAngle(a1.GetIndex(),a2.GetIndex(),a3.GetIndex(),a4.GetIndex()); + } + Real CoordFrame::GetDihedralAngle(int i1, int i2, int i3, int i4){ + //Returns the Dihedral angle between the four atoms with indices i1,i2,i3,i4 + return geom::DihedralAngle((*this)[i1],(*this)[i2],(*this)[i3],(*this)[i4]); + } + + void GetIndices(const EntityView& sele, std::vector<unsigned long>& indices){ + // This function returns a vector containing the atom indices of the atoms in an EntityView + // It is used to accelerate the extraction of information from a trajectory + AtomViewList atoms=sele.GetAtomList(); + indices.reserve(atoms.size()); + for (AtomViewList::const_iterator i=atoms.begin(), + e=atoms.end(); i!=e; ++i) { + indices.push_back(i->GetIndex()); + } + } + + void GetMasses(const EntityView& sele, std::vector<Real>& masses){ + // This function returns a vector containing the atom masses of the atoms in an EntityView + // It is used together with GetIndices to accelerate the extraction of RMSD from a trajectory + Real mass_tot=0.0; + AtomViewList atoms=sele.GetAtomList(); + masses.reserve(atoms.size()); + for (AtomViewList::const_iterator i=atoms.begin(), + e=atoms.end(); i!=e; ++i) { + masses.push_back(i->GetMass()); + mass_tot=mass_tot+i->GetMass(); + } + for (std::vector<Real>::iterator + j=masses.begin(), e2=masses.end(); j!=e2; ++j) { + (*j)/=mass_tot; + } + } + + + void GetIndicesAndMasses(const EntityView& sele, std::vector<unsigned long>& indices,std::vector<Real>& masses){ + GetIndices(sele, indices); + GetMasses(sele, masses); + } + + void GetPositions(const EntityView& sele, std::vector<geom::Vec3>& ref_pos){ + //Returns the positions of all the atoms in the EntityView + ref_pos.reserve(sele.GetAtomCount()); + for (mol::AtomViewIter a=sele.AtomsBegin(),e=sele.AtomsEnd(); a!=e; ++a) { + ref_pos.push_back((*a).GetPos()); + } + } + + geom::Vec3 CoordFrame::GetCenterOfMassPos(const EntityView& sele){ + //Returns the position of the centor of mass of the atoms in the EntityView + std::vector<unsigned long> indices; + std::vector<Real> masses; + GetIndicesAndMasses(sele,indices,masses); + return this->GetCenterOfMassPos(indices,masses); + } + + geom::Vec3 CoordFrame::GetCenterOfMassPos(std::vector<unsigned long>& indices,std::vector<Real>& masses){ + //Returns the position of the centor of mass of the atoms from which the indices and masses are passed + //as vectors in argument + geom::Vec3 v; + for (unsigned int i=0,e=indices.size();i!=e; i++) { + v+=masses[i]*(*this)[indices[i]]; + } + return v; + } + + Real CoordFrame::GetDistanceBetwCenterOfMass(const EntityView& sele1,const EntityView& sele2){ + //Returns the distance between the centers of mass of the two EntityViews + std::vector<unsigned long> indices1,indices2; + std::vector<Real> masses1,masses2; + GetIndicesAndMasses(sele1,indices1,masses1); + GetIndicesAndMasses(sele2,indices2,masses2); + return this->GetDistanceBetwCenterOfMass(indices1,masses1,indices2,masses2); + } + + Real CoordFrame::GetDistanceBetwCenterOfMass(std::vector<unsigned long>& indices1,std::vector<Real>& masses1, + std::vector<unsigned long>& indices2,std::vector<Real>& masses2){ + //Returns the distance between the centers of mass of the two groups of atoms from which the + //indices and masses are given as vectors as argument + geom::Vec3 v1=this->GetCenterOfMassPos(indices1, masses1); + geom::Vec3 v2=this->GetCenterOfMassPos(indices2, masses2); + return geom::Distance(v1,v2); + } + + Real CoordFrame::GetRMSD(const std::vector<geom::Vec3>& ref_pos,const std::vector<unsigned long>& indices_sele){ + //Returns the RMSD between the positions of the atoms whose indices are given in indices_sele and the positions + //given in ref_pos + Real rmsd=0.0,val; + for (unsigned int i1=0; i1!=indices_sele.size(); ++i1) { + geom::Vec3 av_sele=(*this)[indices_sele[i1]]; + geom::Vec3 av_ref=ref_pos[i1]; + val=geom::Length2(av_ref-av_sele); + rmsd+=val; + } + return pow(rmsd/indices_sele.size(),0.5); + } + + Real CoordFrame::GetRMSD(const EntityView& reference_view,const EntityView& sele_view){ + //Return the rmsd between two EntityViews. The reference positions are taken directly from the reference_view + //whereas they are taken from this CoordFrame for the sele_view + int count_ref=reference_view.GetAtomCount(); + int count_sele=sele_view.GetAtomCount(); + if (count_ref!=count_sele){ + throw std::runtime_error("atom counts of the two views are not equal"); + } + std::vector<unsigned long> indices_sele; + std::vector<geom::Vec3> ref_pos; + GetIndices(sele_view,indices_sele); + GetPositions(reference_view,ref_pos); + return this->GetRMSD(ref_pos,indices_sele); + } + +}}//ns \ No newline at end of file diff --git a/modules/mol/base/src/coord_frame.hh b/modules/mol/base/src/coord_frame.hh index c55b855a45ee8508aacece0145a04678dcd68ef0..c856e583c180bf9dbb73cbbf6ac179f26dbdd466 100644 --- a/modules/mol/base/src/coord_frame.hh +++ b/modules/mol/base/src/coord_frame.hh @@ -20,19 +20,55 @@ #define OST_MOL_COORD_FRAME_HH /* - Author: Marco Biasini + Author: Marco Biasini and Niklaus Johner */ #include <boost/shared_ptr.hpp> #include <ost/geom/geom.hh> #include <ost/mol/module_config.hh> +#include <ost/mol/entity_view.hh> +#include "atom_handle.hh" namespace ost { namespace mol { - -typedef std::vector<geom::Vec3> CoordFrame; +class DLLEXPORT_OST_MOL CoordFrame : public geom::Vec3List{ +public: + typedef geom::Vec3List base_type; + CoordFrame() : base_type() {} + + CoordFrame(size_t size, const geom::Vec3& value=geom::Vec3()) : base_type(size, value) {} + CoordFrame(base_type::iterator b, base_type::iterator e): base_type(b, e) { } + CoordFrame(const base_type& rhs) : base_type(rhs) { } + CoordFrame(const std::vector<geom::Vec3>& rhs) : base_type(rhs) { } + + geom::Vec3 GetAtomPos(const AtomHandle& atom); + geom::Vec3 GetAtomPos(int atom_index); + Real GetDistanceBetwAtoms(const AtomHandle& a1, const AtomHandle& a2); + Real GetDistanceBetwAtoms(int atom1_index, int atom2_index); + Real GetAngle(const AtomHandle& a1, const AtomHandle& a2, const AtomHandle& a3); + Real GetAngle(int atom1_index, int atom2_index, int atom3_index); + Real GetDihedralAngle(const AtomHandle& a1, const AtomHandle& a2, const AtomHandle& a3, const AtomHandle& a4); + Real GetDihedralAngle(int a1_index, int a2_index, int a3_index, int a4_index); + geom::Vec3 GetCenterOfMassPos(const mol::EntityView& sele); + geom::Vec3 GetCenterOfMassPos(std::vector<unsigned long>& indices, std::vector<Real>& masses); + Real GetDistanceBetwCenterOfMass(const mol::EntityView& sele1, const mol::EntityView& sele2); + Real GetDistanceBetwCenterOfMass(std::vector<unsigned long>& indices1, std::vector<Real>& masses1, + std::vector<unsigned long>& indices2, std::vector<Real>& masses2); + Real GetRMSD(const std::vector<geom::Vec3>& ref_pos, const std::vector<unsigned long>& indices_sele); + Real GetRMSD(const mol::EntityView& Reference_View, const mol::EntityView& sele_View); +}; + + void GetIndices(const EntityView& sele, std::vector<unsigned long>& indices); + void GetMasses(const EntityView& sele, std::vector<Real>& masses); + void GetIndicesAndMasses(const EntityView& sele, std::vector<unsigned long>& indices,std::vector<Real>& masses); + void GetPositions(const EntityView& sele, std::vector<geom::Vec3>& ref_pos); + typedef boost::shared_ptr<CoordFrame> CoordFramePtr; typedef std::vector<CoordFramePtr> CoordFrameList; +// factory method +// create a frame froma Vec3List containing the positions of the atoms + DLLEXPORT_OST_MOL CoordFrame CreateCoordFrame(const geom::Vec3List& atom_pos); + }} #endif diff --git a/modules/mol/base/src/coord_group.cc b/modules/mol/base/src/coord_group.cc index a68985d6ceab558e821b6d6f05dfb8eae19cc00b..f92c58e22b44f9dc4cd81753e288acefd164be9a 100644 --- a/modules/mol/base/src/coord_group.cc +++ b/modules/mol/base/src/coord_group.cc @@ -24,6 +24,7 @@ #include <ost/mol/mol.hh> #include "coord_group.hh" + namespace ost { namespace mol { CoordGroupHandle CreateCoordGroup(const AtomHandleList& atomlist) @@ -83,8 +84,9 @@ CoordGroupHandle::operator bool() const return this->IsValid(); } -void CoordGroupHandle::AddFrame(const std::vector<geom::Vec3>& clist) -{ +//void CoordGroupHandle::AddFrame(const std::vector<geom::Vec3>& clist) + void CoordGroupHandle::AddFrame(const geom::Vec3List& clist) + { this->CheckValidity(); if (source_->IsMutable()) { source_->AddFrame(clist); @@ -203,5 +205,6 @@ CoordGroupHandle CoordGroupHandle::Filter(const EntityView& selected) const } return filtered_cg; } - + + }} // ns diff --git a/modules/mol/base/src/coord_group.hh b/modules/mol/base/src/coord_group.hh index a3e582b15c12bfcc787d21a30b743cc2c04c1488..2b6d6fe7f4c40a68e323151f299ffeb184943e45 100644 --- a/modules/mol/base/src/coord_group.hh +++ b/modules/mol/base/src/coord_group.hh @@ -25,7 +25,6 @@ #include <vector> #include <boost/shared_array.hpp> - #include "atom_handle.hh" #include "coord_source.hh" @@ -65,7 +64,8 @@ public: void Capture(uint frame); /// \brief add frame - void AddFrame(const std::vector<geom::Vec3>& clist); + //void AddFrame(const std::vector<geom::Vec3>& clist); + void AddFrame(const geom::Vec3List& clist); void AddFrames(const CoordGroupHandle& cg); /// \brief set an indidivial atom position in the given frame @@ -88,9 +88,10 @@ public: CoordGroupHandle Filter(const EntityView& selected) const; CoordGroupHandle(CoordSourcePtr source); + + private: void CheckValidity() const; - CoordSourcePtr source_; }; diff --git a/modules/mol/base/src/editor_base.cc b/modules/mol/base/src/editor_base.cc index c5eed6d60790041bff56e16e0751fe63da9db0f6..7718234673d7e35c33aee25b113a33e1c2dc2d54 100644 --- a/modules/mol/base/src/editor_base.cc +++ b/modules/mol/base/src/editor_base.cc @@ -149,7 +149,7 @@ void EditorBase::ReorderAllResidues() void EditorBase::RenameAtom(AtomHandle atom, const String& new_name) { CheckHandleValidity(atom); - atom.Impl()->SetName(new_name); + atom.Impl()->Name()=new_name; } BondHandle EditorBase::Connect(const AtomHandle& first, @@ -202,11 +202,6 @@ TorsionHandle EditorBase::AddTorsion(const String& name, const AtomHandle& a1, } -EditMode EditorBase::GetMode() const -{ - return mode_; -} - void EditorBase::UpdateTrace() { if (mode_==UNBUFFERED_EDIT) { diff --git a/modules/mol/base/src/editor_base.hh b/modules/mol/base/src/editor_base.hh index e9409ecd31b4a8d53e25455045f91192856ffbec..48bf067bd19ea8c1957d60fe3ba3c439f86b4917 100644 --- a/modules/mol/base/src/editor_base.hh +++ b/modules/mol/base/src/editor_base.hh @@ -192,8 +192,11 @@ public: void ReorderAllResidues(); /// \brief Get edit mode of editor - EditMode GetMode() const; + EditMode GetMode() const {return mode_;} + /// \ brief return entity this editor works on + EntityHandle GetEntity() const {return ent_;} + /// \brief change the name of the atom to the new name void RenameAtom(AtomHandle atom, const String& new_name); protected: diff --git a/modules/mol/base/src/entity_handle.hh b/modules/mol/base/src/entity_handle.hh index 559a2cf109fd1a1089d38ead2b60bc4781249584..fff9f6efc306b77df8ca9aa6f6b804f1480329c0 100644 --- a/modules/mol/base/src/entity_handle.hh +++ b/modules/mol/base/src/entity_handle.hh @@ -137,7 +137,7 @@ public: /// /// The two iterators returned by ResiduesBegin() and ResiduesEnd() form a /// half-closed range. It is cheaper to cache the iterator returned by - /// ResiduesEnd() than to call ResiduesEnd() after very loop, i.e. like + /// ResiduesEnd() than to call ResiduesEnd() after every loop, i.e. like /// \code /// // e is an instance of EntityHandle /// for (ResidueHandleIter i=e.ResiduesBegin(), x=e.ResiduesEnd(); i!=x; ++i) { diff --git a/modules/mol/base/src/impl/atom_impl.cc b/modules/mol/base/src/impl/atom_impl.cc index bf66239bb46741d3de82d4dbd2a1384717f59a46..4f7f059b818eda692de6447a9b3d2b5d547037e7 100644 --- a/modules/mol/base/src/impl/atom_impl.cc +++ b/modules/mol/base/src/impl/atom_impl.cc @@ -94,11 +94,11 @@ void AtomImpl::TraceDirectionality(FragmentImplP frag, ConnectorImplP conn, #if !defined(NDEBUG) if (conn->GetFirst()==shared_from_this()) { LOG_TRACE("dir:" << String(n,' ') << " atom " << res_.lock()->GetNumber() - << "." << GetName() << " [" << conn->GetSecond()->GetQualifiedName() + << "." << Name() << " [" << conn->GetSecond()->GetQualifiedName() << " ]"); } else { LOG_TRACE("dir:" << String(n,' ') << " atom " << res_.lock()->GetNumber() - << "." << GetName() << " [" << conn->GetFirst()->GetQualifiedName() + << "." << Name() << " [" << conn->GetFirst()->GetQualifiedName() << " ]"); } @@ -106,7 +106,7 @@ void AtomImpl::TraceDirectionality(FragmentImplP frag, ConnectorImplP conn, #endif } else { LOG_TRACE("dir:" << String(n,' ') << " atom " << res_.lock()->GetNumber() - << "." << GetName() << " [ ]"); + << "." << Name() << " [ ]"); } // presence of a primary connector indicates ring closure @@ -195,7 +195,7 @@ void AtomImpl::UpdateFromXCS() // stack before calling UpdateFromICS() on the next atom. { // Derive direction and length of connector from atom positions. - geom::Vec3 global_d=((*i)->GetSecond()->GetOriginalPos()-this->GetOriginalPos()); + geom::Vec3 global_d=((*i)->GetSecond()->OriginalPos()-this->OriginalPos()); // Set direction and length of connector. Direction is relative to // local coordinate system of this atom. // Note the order of arguments for the matrix multiplication. This is the @@ -224,7 +224,7 @@ std::ostream& operator<<(std::ostream& o, const AtomImplPtr ap) { o << ap->GetResidue()->GetChain()->GetName() << "."; o << ap->GetResidue()->GetKey() << ap->GetResidue()->GetNumber() << "."; - o << ap->GetName(); + o << ap->Name(); return o; } @@ -257,7 +257,7 @@ ConnectorImplP GetConnector(const AtomImplPtr& a, const AtomImplPtr& b) { } String AtomImpl::GetQualifiedName() const { - return this->GetResidue()->GetQualifiedName()+"."+this->GetName(); + return this->GetResidue()->GetQualifiedName()+"."+this->Name(); } void AtomImpl::DeleteAllConnectors() { diff --git a/modules/mol/base/src/impl/atom_impl.hh b/modules/mol/base/src/impl/atom_impl.hh index 963f5ab60a3b0a1c5a8ccf714f0d5860e275799c..b342c526ae56bc5acdfbef3942255c7ff0a9f69c 100644 --- a/modules/mol/base/src/impl/atom_impl.hh +++ b/modules/mol/base/src/impl/atom_impl.hh @@ -56,21 +56,21 @@ public: ~AtomImpl(); void Apply(EntityVisitor& h); - const String& GetName() const {return name_;} - - void SetName(const String& atom_name) { - name_=atom_name; - } + // for efficiency reasons, the simple setter/getter methods are + // replaced by direct access - this is the impl layer after all + const String& Name() const {return name_;} + String& Name() {return name_;} - const geom::Vec3& GetPos() const {return tf_pos_;} + // DEPRECATED + const String& GetName() const {return name_;} - const geom::Vec3& GetOriginalPos() const {return pos_;} + const geom::Vec3& TransformedPos() const {return tf_pos_;} + geom::Vec3& TransformedPos() {return tf_pos_;} - void SetTransformedPos(const geom::Vec3& pos) { tf_pos_=pos; } + const geom::Vec3& OriginalPos() const {return pos_;} + geom::Vec3& OriginalPos() {return pos_;} - void SetOriginalPos(const geom::Vec3& pos) { pos_=pos; } - ResidueImplPtr GetResidue() const; void SetPrimaryConnector(const ConnectorImplP& bp) { diff --git a/modules/mol/base/src/impl/chain_impl.cc b/modules/mol/base/src/impl/chain_impl.cc index e0f51ada14d03f8b6fee8457c71aa8536471caf7..421f98dd4a43bafb12537e1649b51aba49abb9d3 100644 --- a/modules/mol/base/src/impl/chain_impl.cc +++ b/modules/mol/base/src/impl/chain_impl.cc @@ -420,8 +420,8 @@ geom::AlignedCuboid ChainImpl::GetBounds() const ResidueImplPtr r=*i; for (AtomImplList::iterator j=r->GetAtomList().begin(); j!=r->GetAtomList().end(); ++j) { - mmin=geom::Min(mmin, (*j)->GetPos()); - mmax=geom::Max(mmax, (*j)->GetPos()); + mmin=geom::Min(mmin, (*j)->TransformedPos()); + mmax=geom::Max(mmax, (*j)->TransformedPos()); atoms=true; } } @@ -441,7 +441,7 @@ geom::Vec3 ChainImpl::GetCenterOfAtoms() const ResidueImplPtr r=*i; for (AtomImplList::iterator j=r->GetAtomList().begin(); j!=r->GetAtomList().end(); ++j) { - sum+=(*j)->GetPos(); + sum+=(*j)->TransformedPos(); } } sum/=this->GetAtomCount(); @@ -459,7 +459,7 @@ geom::Vec3 ChainImpl::GetCenterOfMass() const ResidueImplPtr r=*i; for (AtomImplList::iterator j=r->GetAtomList().begin(); j!=r->GetAtomList().end(); ++j) { - center+=(*j)->GetPos() * (*j)->GetMass(); + center+=(*j)->TransformedPos() * (*j)->GetMass(); } } center/=mass; diff --git a/modules/mol/base/src/impl/connector_impl.cc b/modules/mol/base/src/impl/connector_impl.cc index dd4b285da0903649afb63cda9c9c4bab815e804b..8bafe009b6a110edecd96cadc3492ed348dc1f19 100644 --- a/modules/mol/base/src/impl/connector_impl.cc +++ b/modules/mol/base/src/impl/connector_impl.cc @@ -77,14 +77,14 @@ geom::Mat3 find_rotation(const geom::Vec3& d) { geom::Vec3 ConnectorImpl::GetPos() const { - return (GetFirst()->GetPos()+GetSecond()->GetPos())*0.5; + return (GetFirst()->TransformedPos()+GetSecond()->TransformedPos())*0.5; } Real ConnectorImpl::GetLength() const { Real length; if (this->GetFirst()->GetEntity()->HasICS()==false) { - length=geom::Distance(this->GetFirst()->GetOriginalPos(),this->GetSecond()->GetOriginalPos()); + length=geom::Distance(this->GetFirst()->OriginalPos(),this->GetSecond()->OriginalPos()); } else { length=len_; } @@ -110,8 +110,8 @@ bool ConnectorImpl::IsConnectorOf(const AtomImplPtr& a, geom::Vec3 ConnectorImpl::GetOriginalPos() const { - return (this->GetFirst()->GetOriginalPos()+ - this->GetSecond()->GetOriginalPos())*0.5; + return (this->GetFirst()->OriginalPos()+ + this->GetSecond()->OriginalPos())*0.5; } void ConnectorImpl::Switch() diff --git a/modules/mol/base/src/impl/dihedral.cc b/modules/mol/base/src/impl/dihedral.cc index 3580829b198937ec8523481f041ed48b97f38faf..cac771039b96ae38e478edb7c9a596e337bd869c 100644 --- a/modules/mol/base/src/impl/dihedral.cc +++ b/modules/mol/base/src/impl/dihedral.cc @@ -46,8 +46,8 @@ Dihedral::Dihedral(const AtomImplList& atoms) Real Dihedral::GetAngleXCS() const { - return geom::DihedralAngle(atoms_[0]->GetPos(), atoms_[1]->GetPos(), - atoms_[2]->GetPos(), atoms_[3]->GetPos()); + return geom::DihedralAngle(atoms_[0]->TransformedPos(), atoms_[1]->TransformedPos(), + atoms_[2]->TransformedPos(), atoms_[3]->TransformedPos()); } Real Dihedral::GetAngleICS() const { diff --git a/modules/mol/base/src/impl/entity_impl.cc b/modules/mol/base/src/impl/entity_impl.cc index 26709b43130b4119502ccc41a3d7d2af8814d9c2..1441af7cc3a079e5d08589951aff5e8f7be14e76 100644 --- a/modules/mol/base/src/impl/entity_impl.cc +++ b/modules/mol/base/src/impl/entity_impl.cc @@ -270,10 +270,10 @@ geom::AlignedCuboid EntityImpl::GetBounds() const if (this->GetAtomCount()>0) { geom::Vec3 mmin, mmax; AtomImplMap::const_iterator it=atom_map_.begin(); - mmin=mmax=it->second->GetPos(); + mmin=mmax=it->second->TransformedPos(); for (++it; it!=atom_map_.end();++it) { - mmin=geom::Min(mmin,it->second->GetPos()); - mmax=geom::Max(mmax,it->second->GetPos()); + mmin=geom::Min(mmin,it->second->TransformedPos()); + mmax=geom::Max(mmax,it->second->TransformedPos()); } return geom::AlignedCuboid(mmin, mmax); } else { @@ -287,7 +287,7 @@ geom::Vec3 EntityImpl::GetCenterOfAtoms() const { if (this->GetAtomCount()>0) { for (AtomImplMap::const_iterator it = atom_map_.begin(); it!=atom_map_.end();++it) { - center+=it->second->GetPos(); + center+=it->second->TransformedPos(); } center/=static_cast<Real>(atom_map_.size()); } @@ -299,7 +299,7 @@ geom::Vec3 EntityImpl::GetCenterOfMass() const { Real mass = this->GetMass(); if (this->GetAtomCount()>0 && mass>0) { for(AtomImplMap::const_iterator it = atom_map_.begin();it!=atom_map_.end();++it) { - center+=it->second->GetPos()*it->second->GetMass(); + center+=it->second->TransformedPos()*it->second->GetMass(); } center/=mass; } @@ -326,12 +326,12 @@ AtomImplPtr EntityImpl::CreateAtom(const ResidueImplPtr& rp, #else AtomImplPtr ap(new AtomImpl(shared_from_this(), rp, name, pos, ele, next_index_++)); #endif - if (identity_transf_ == false) { + if (!identity_transf_) { geom::Vec3 transformed_pos = geom::Vec3(transformation_matrix_*geom::Vec4(pos)); - ap->SetTransformedPos(transformed_pos); + ap->TransformedPos()=transformed_pos; atom_organizer_.Add(ap,transformed_pos); } else { - ap->SetTransformedPos(pos); + ap->TransformedPos()=pos; atom_organizer_.Add(ap,pos); } atom_map_.insert(AtomImplMap::value_type(ap.get(),ap)); @@ -498,8 +498,8 @@ Real EntityImpl::GetAngleXCS(const AtomImplPtr& a1, const AtomImplPtr& a2, ConnectorImplP c23=GetConnector(a2, a3); if (c12 && c12->GetFirst() && c12->GetSecond()) { if (c23 && c23->GetFirst() && c23->GetSecond()) { - return Angle(a2->GetPos()-a1->GetPos(), - a2->GetPos()-a3->GetPos()); + return Angle(a2->TransformedPos()-a1->TransformedPos(), + a2->TransformedPos()-a3->TransformedPos()); } else { AtomHandle ah2(a2), ah3(a3); throw NotConnectedError(ah2, ah3); @@ -765,12 +765,7 @@ void EntityImpl::SetTransform(const geom::Mat4 transfmat) { transformation_matrix_=transfmat; inverse_transformation_matrix_=Invert(transformation_matrix_); - geom::Mat4 identity = geom::Mat4(); - if (transformation_matrix_ == identity) { - identity_transf_ = true; - } else { - identity_transf_ = false; - } + identity_transf_ = (transformation_matrix_==geom::Mat4()); this->UpdateTransformedPos(); this->MarkOrganizerDirty(); } @@ -1049,7 +1044,7 @@ void EntityImpl::UpdateOrganizer() atom_organizer_.Clear(); for (AtomImplMap::const_iterator i=atom_map_.begin(), e=atom_map_.end(); i!=e; ++i) { - atom_organizer_.Add(i->second, i->second->GetPos()); + atom_organizer_.Add(i->second, i->second->TransformedPos()); } dirty_flags_&=~DirtyOrganizer; } @@ -1189,7 +1184,7 @@ void EntityImpl::RenameChain(ChainImplPtr chain, const String& new_name) void EntityImpl::UpdateTransformedPos(){ for(AtomImplMap::iterator it = atom_map_.begin();it!=atom_map_.end();++it) { - it->second->SetTransformedPos(geom::Vec3(transformation_matrix_*geom::Vec4(it->second->GetOriginalPos()))); + it->second->TransformedPos()=geom::Vec3(transformation_matrix_*geom::Vec4(it->second->OriginalPos())); } } diff --git a/modules/mol/base/src/impl/query_ast.cc b/modules/mol/base/src/impl/query_ast.cc index 697ff173f1271b36e576d37acff20e9e50df5d58..ea96a485877b9c01226f4acdfa94e69c526fcb99 100644 --- a/modules/mol/base/src/impl/query_ast.cc +++ b/modules/mol/base/src/impl/query_ast.cc @@ -120,6 +120,7 @@ StringOrRegexParam::StringOrRegexParam(): StringOrRegexParam::StringOrRegexParam(const String& s): is_regex_(false),r_(),s_(s) { + String special("[]{}()"); for(String::const_iterator it=s.begin();it!=s.end();++it) { if((*it)=='?' || (*it)=='*') { is_regex_=true; @@ -130,12 +131,16 @@ StringOrRegexParam::StringOrRegexParam(const String& s): if(is_regex_) { std::ostringstream e; for(String::const_iterator it=s.begin();it!=s.end();++it) { - if((*it)=='?') { - e << "."; - } else if((*it)=='*') { - e << ".*"; + + if((*it)=='?' && (it==s.begin() || (*(it-1))!='\\')) { + e << "."; + } else if((*it)=='*' && (it==s.begin() || (*(it-1))!='\\')) { + e << ".*"; } else { - e << *it; + if (special.find(*it)!=String::npos) { + e << '\\'; + } + e << *it; } } //std::cerr << "assembling regex [" << e.str() << "]... "; diff --git a/modules/mol/base/src/impl/query_impl.cc b/modules/mol/base/src/impl/query_impl.cc index cc5f80240bd1ddaff070ea42d518891c84419772..a70cfa813b39d63d9337cfb6135846d63796f8fb 100644 --- a/modules/mol/base/src/impl/query_impl.cc +++ b/modules/mol/base/src/impl/query_impl.cc @@ -148,7 +148,7 @@ QueryToken QueryLexer::LexNumericToken() { } bool is_ident_or_str(char c) { - static String allowed_chars("_*?"); + static String allowed_chars("_*?\\"); return isalnum(c) || allowed_chars.find_first_of(c)!=String::npos; } @@ -158,7 +158,8 @@ QueryToken QueryLexer::LexIdentOrStringToken() { bool force_string=false; while (current_<query_string_.length() && is_ident_or_str(query_string_[current_])) { - if (query_string_[current_]=='*' || query_string_[current_]=='?') { + if (query_string_[current_]=='*' || query_string_[current_]=='?' || + query_string_[current_]=='\\') { force_string=true; } current_++; diff --git a/modules/mol/base/src/impl/residue_impl.cc b/modules/mol/base/src/impl/residue_impl.cc index cf4729239627e27f7f21477d7bbe7e9775ae2689..d8ce7f6d3f97b6c0bfe9e452d0c2760d54bbd01c 100644 --- a/modules/mol/base/src/impl/residue_impl.cc +++ b/modules/mol/base/src/impl/residue_impl.cc @@ -60,8 +60,8 @@ AtomImplPtr ResidueImpl::InsertAtom(const String& name, AtomImplPtr ResidueImpl::InsertAtom(const AtomImplPtr& atom) { - AtomImplPtr dst_atom=this->InsertAtom(atom->GetName(), - atom->GetPos(), + AtomImplPtr dst_atom=this->InsertAtom(atom->Name(), + atom->TransformedPos(), atom->GetElement()); dst_atom->Assign(*atom.get()); @@ -166,12 +166,12 @@ AtomImplPtr ResidueImpl::GetCentralAtom() const if (chem_class_.IsNucleotideLinking()) { for (AtomImplList::const_iterator it=atom_list_.begin(); it!=atom_list_.end();++it) { - if((*it)->GetName()=="P") return *it; + if((*it)->Name()=="P") return *it; } } else if (chem_class_.IsPeptideLinking()) { for (AtomImplList::const_iterator it=atom_list_.begin(); it!=atom_list_.end();++it) { - if((*it)->GetName()=="CA") return *it; + if((*it)->Name()=="CA") return *it; } } @@ -217,14 +217,14 @@ geom::Vec3 ResidueImpl::GetCentralNormal() const AtomImplPtr a1 = FindAtom("C"); AtomImplPtr a2 = FindAtom("O"); if(a1 && a2) { - nrvo = geom::Normalize(a2->GetPos()-a1->GetPos()); + nrvo = geom::Normalize(a2->TransformedPos()-a1->TransformedPos()); } else { a1 = FindAtom("CB"); a2 = FindAtom("CA"); if(a1 && a2) { - nrvo = geom::Normalize(a2->GetPos()-a1->GetPos()); + nrvo = geom::Normalize(a2->TransformedPos()-a1->TransformedPos()); } else { - geom::Vec3 v0=GetCentralAtom()->GetPos(); + geom::Vec3 v0=GetCentralAtom()->TransformedPos(); nrvo=geom::Cross(geom::Normalize(v0), geom::Normalize(geom::Vec3(-v0[2],v0[0],v0[1]))); LOG_VERBOSE("warning: could not find atoms for proper central normal calculation"); @@ -235,9 +235,9 @@ geom::Vec3 ResidueImpl::GetCentralNormal() const AtomImplPtr a2 = FindAtom("OP1"); AtomImplPtr a3 = FindAtom("OP2"); if(a1 && a2 && a3) { - nrvo = geom::Normalize(a1->GetPos()-(a2->GetPos()+a3->GetPos())*.5); + nrvo = geom::Normalize(a1->TransformedPos()-(a2->TransformedPos()+a3->TransformedPos())*.5); } else { - geom::Vec3 v0=GetCentralAtom()->GetPos(); + geom::Vec3 v0=GetCentralAtom()->TransformedPos(); nrvo=geom::Cross(geom::Normalize(v0), geom::Normalize(geom::Vec3(-v0[2],v0[0],v0[1]))); LOG_VERBOSE("warning: could not find atoms for proper central normal calculation"); @@ -251,7 +251,7 @@ AtomImplPtr ResidueImpl::FindAtom(const String& aname) const { for (AtomImplList::const_iterator it=atom_list_.begin(); it!=atom_list_.end();++it) { - if ((*it)->GetName()==aname) { + if ((*it)->Name()==aname) { return *it; } } @@ -366,18 +366,25 @@ void ResidueImpl::DeleteAtom(const AtomImplPtr& atom) { } } +namespace { + struct aname_matcher { + aname_matcher(const String& n): aname(n) {} + bool operator()(AtomImplPtr& a) {return a->Name()==aname;} + String aname; + }; +} + void ResidueImpl::DeleteAtoms(const String& atom_name) { AtomImplList::iterator i=atom_list_.begin(); for (; i!=atom_list_.end(); ++i) { - if ((*i)->GetName()==atom_name) { + if ((*i)->Name()==atom_name) { (*i)->DeleteAllTorsions(); (*i)->DeleteAllConnectors(); this->GetEntity()->DeleteAtom(*i); } } AtomImplList::iterator new_end; - new_end=std::remove_if(atom_list_.begin(), atom_list_.end(), - bind(&AtomImpl::GetName, _1)==atom_name); + new_end=std::remove_if(atom_list_.begin(), atom_list_.end(), aname_matcher(atom_name)); atom_list_.erase(new_end, atom_list_.end()); } @@ -452,10 +459,10 @@ geom::AlignedCuboid ResidueImpl::GetBounds() const if (atom_list_.size()>0) { AtomImplList::const_iterator i=atom_list_.begin(); - mmin=mmax=(*i)->GetPos(); + mmin=mmax=(*i)->TransformedPos(); for (++i; i!=atom_list_.end(); ++i) { - mmax=geom::Max(mmax,(*i)->GetPos()); - mmin=geom::Min(mmin,(*i)->GetPos()); + mmax=geom::Max(mmax,(*i)->TransformedPos()); + mmin=geom::Min(mmin,(*i)->TransformedPos()); } return geom::AlignedCuboid(mmin, mmax); } else { @@ -469,7 +476,7 @@ geom::Vec3 ResidueImpl::GetCenterOfAtoms() const if (!atom_list_.empty()) { for (AtomImplList::const_iterator i=atom_list_.begin(); i!=atom_list_.end(); ++i) { - sum+=(*i)->GetPos(); + sum+=(*i)->TransformedPos(); } sum/=atom_list_.size(); } @@ -483,7 +490,7 @@ geom::Vec3 ResidueImpl::GetCenterOfMass() const if (this->GetAtomCount() > 0 && mass > 0) { for (AtomImplList::const_iterator i=atom_list_.begin(); i!=atom_list_.end(); ++i) { - center+=(*i)->GetPos()*(*i)->GetMass(); + center+=(*i)->TransformedPos()*(*i)->GetMass(); } } return center/mass; @@ -566,7 +573,7 @@ bool ResidueImpl::SwitchAtomPos(const String& group) { for (; k!=gr.atoms.end(); ++k) { AtomGroupEntry& entry=*k; assert(!entry.atom.expired()); - entry.pos=entry.atom.lock()->GetOriginalPos(); + entry.pos=entry.atom.lock()->OriginalPos(); } } AtomGroup& agr=i->second; @@ -575,11 +582,11 @@ bool ResidueImpl::SwitchAtomPos(const String& group) { AtomGroupEntry& entry=*j; assert(!entry.atom.expired()); - entry.atom.lock()->SetOriginalPos(entry.pos); + entry.atom.lock()->OriginalPos()=entry.pos; EntityHandle ent = entry.atom.lock()->GetEntity(); geom::Mat4 transf_matrix = ent.GetTransformationMatrix(); geom::Vec3 transf_pos = geom::Vec3(transf_matrix*geom::Vec4(entry.pos)); - entry.atom.lock()->SetTransformedPos(transf_pos); + entry.atom.lock()->TransformedPos()=transf_pos; } curr_group_=group; return true; diff --git a/modules/mol/base/src/query_state.cc b/modules/mol/base/src/query_state.cc index b90767a7e20de61fad90328283940bbc9e0da2f2..d8d4da028c2f727bde33cb8305a7bf8ae09a0b08 100644 --- a/modules/mol/base/src/query_state.cc +++ b/modules/mol/base/src/query_state.cc @@ -319,7 +319,7 @@ boost::logic::tribool QueryState::EvalAtom(const AtomImplPtr& a) { int int_value; switch (ss.sel_id) { case Prop::ANAME: - str_value = a->GetName(); + str_value = a->Name(); s_[*i] = cmp_string(ss.comp_op,str_value, boost::get<StringOrRegexParam>(ss.param)); break; @@ -328,17 +328,17 @@ boost::logic::tribool QueryState::EvalAtom(const AtomImplPtr& a) { s_[*i]=cmp_num<int>(ss.comp_op, int_value,boost::get<int>(ss.param)); break; case Prop::AX: - float_value=(a->GetPos())[0]; + float_value=(a->TransformedPos())[0]; s_[*i]=cmp_num<Real>(ss.comp_op, float_value, boost::get<float>(ss.param)); break; case Prop::AY: - float_value=(a->GetPos())[1]; + float_value=(a->TransformedPos())[1]; s_[*i]=cmp_num<Real>(ss.comp_op, float_value, boost::get<float>(ss.param)); break; case Prop::AZ: - float_value=(a->GetPos())[2]; + float_value=(a->TransformedPos())[2]; s_[*i]=cmp_num<Real>(ss.comp_op, float_value, boost::get<float>(ss.param)); break; @@ -358,7 +358,7 @@ boost::logic::tribool QueryState::EvalAtom(const AtomImplPtr& a) { boost::get<float>(ss.param)); break; case Prop::WITHIN: - s_[*i]= this->do_within(a->GetPos(), + s_[*i]= this->do_within(a->TransformedPos(), boost::get<WithinParam>(ss.param), ss.comp_op); break; diff --git a/modules/mol/base/src/xcs_editor.cc b/modules/mol/base/src/xcs_editor.cc index f5a35fa66dda31b0230f5ee06db98b2b7688eb25..0c2454b187c8d29902b8380e4caf3b7969db3fe5 100644 --- a/modules/mol/base/src/xcs_editor.cc +++ b/modules/mol/base/src/xcs_editor.cc @@ -70,33 +70,121 @@ XCSEditor& XCSEditor::operator=(const XCSEditor& rhs) return *this; } -void XCSEditor::SetAtomPos(const AtomHandle& atom, - const geom::Vec3& position) +void XCSEditor::SetAtomTransformedPos(const AtomHandle& atom, + const geom::Vec3& position) { CheckHandleValidity(atom); - atom.Impl()->SetTransformedPos(position); - geom::Mat4 inv_transformation_matrix = ent_.Impl()->GetInvTransfMatrix(); - geom::Vec3 original_pos = geom::Vec3(inv_transformation_matrix*geom::Vec4(position)); - atom.Impl()->SetOriginalPos(original_pos); + atom.Impl()->TransformedPos()=position; + if(ent_.Impl()->IsTransfIdentity()) { + atom.Impl()->OriginalPos()=position; + } else { + atom.Impl()->OriginalPos() = geom::Vec3(ent_.Impl()->GetInvTransfMatrix()*geom::Vec4(position)); + } ent_.Impl()->MarkICSDirty(); ent_.Impl()->MarkOrganizerDirty(); this->Update(); } +namespace { + template<typename T> + void set_transformed_pos(impl::EntityImpl* ent, const AtomHandleList& alist, T *positions) + { + bool has_tf=ent->IsTransfIdentity(); + for(AtomHandleList::const_iterator ait=alist.begin();ait!=alist.end();++ait) { + if(ait->IsValid()) { + ait->Impl()->TransformedPos()[0]=static_cast<Real>(positions[0]); + ait->Impl()->TransformedPos()[1]=static_cast<Real>(positions[1]); + ait->Impl()->TransformedPos()[2]=static_cast<Real>(positions[2]); + if(has_tf) { + ait->Impl()->OriginalPos()=ait->Impl()->TransformedPos(); + } else { + ait->Impl()->OriginalPos() = geom::Vec3(ent->GetInvTransfMatrix()*geom::Vec4(ait->Impl()->TransformedPos())); + } + } + positions+=3; + } + ent->MarkICSDirty(); + ent->MarkOrganizerDirty(); + } +} // anon ns + +void XCSEditor::SetAtomTransformedPos(const AtomHandleList& alist, float *positions) +{ + set_transformed_pos<float>(ent_.Impl().get(),alist,positions); + this->Update(); +} + +void XCSEditor::SetAtomTransformedPos(const AtomHandleList& alist, double *positions) +{ + set_transformed_pos<double>(ent_.Impl().get(),alist,positions); + this->Update(); +} void XCSEditor::SetAtomOriginalPos(const AtomHandle& atom, - const geom::Vec3& position) + const geom::Vec3& position) { CheckHandleValidity(atom); - atom.Impl()->SetOriginalPos(position); - geom::Mat4 transformation_matrix = atom.GetEntity().GetTransformationMatrix(); - geom::Vec3 transformed_pos = geom::Vec3(transformation_matrix*geom::Vec4(position)); - atom.Impl()->SetTransformedPos(transformed_pos); + atom.Impl()->OriginalPos()=position; + if(ent_.Impl()->IsTransfIdentity()) { + atom.Impl()->TransformedPos()=position; + } else { + atom.Impl()->TransformedPos() = geom::Vec3(ent_.Impl()->GetTransfMatrix()*geom::Vec4(position)); + } ent_.Impl()->MarkICSDirty(); ent_.Impl()->MarkOrganizerDirty(); this->Update(); } +namespace { + template<typename T> + void set_original_pos(impl::EntityImpl* ent, const AtomHandleList& alist, T *positions) + { + bool has_tf=ent->IsTransfIdentity(); + for(AtomHandleList::const_iterator ait=alist.begin();ait!=alist.end();++ait) { + if(ait->IsValid()) { + ait->Impl()->OriginalPos()[0]=static_cast<Real>(positions[0]); + ait->Impl()->OriginalPos()[1]=static_cast<Real>(positions[1]); + ait->Impl()->OriginalPos()[2]=static_cast<Real>(positions[2]); + if(has_tf) { + ait->Impl()->TransformedPos()=ait->Impl()->OriginalPos(); + } else { + ait->Impl()->TransformedPos() = geom::Vec3(ent->GetTransfMatrix()*geom::Vec4(ait->Impl()->OriginalPos())); + } + } + positions+=3; + } + ent->MarkICSDirty(); + ent->MarkOrganizerDirty(); + } +} // anon ns + +void XCSEditor::SetAtomOriginalPos(const AtomHandleList& alist, float *positions) +{ + set_original_pos<float>(ent_.Impl().get(),alist,positions); + this->Update(); +} + +void XCSEditor::SetAtomOriginalPos(const AtomHandleList& alist, double *positions) +{ + set_original_pos<double>(ent_.Impl().get(),alist,positions); + this->Update(); +} + +void XCSEditor::SetAtomPos(const AtomHandle& atom, const geom::Vec3& position) +{ + this->SetAtomTransformedPos(atom,position); +} + +void XCSEditor::SetAtomPos(const AtomHandleList& alist, float *positions) +{ + this->SetAtomTransformedPos(alist,positions); +} + +void XCSEditor::SetAtomPos(const AtomHandleList& alist, double *positions) +{ + this->SetAtomTransformedPos(alist,positions); +} + void XCSEditor::ApplyTransform(const geom::Mat4& transform) { ent_.Impl()->ApplyTransform(transform); diff --git a/modules/mol/base/src/xcs_editor.hh b/modules/mol/base/src/xcs_editor.hh index 4b89083c6f82b5952a00270683a82bfddeada13c..73d96a652829932c469a6a0382093de7fd53b5f4 100644 --- a/modules/mol/base/src/xcs_editor.hh +++ b/modules/mol/base/src/xcs_editor.hh @@ -51,11 +51,47 @@ public: void SetAtomOriginalPos(const AtomHandle& atom, const geom::Vec3& position); + /// \brief numpy float interface + /// + /// the passed in float array must have a length of 3*alist.size() + void SetAtomOriginalPos(const AtomHandleList& alist, + float *positions); + + /// \brief numpy double interface + /// + /// the passed in double array must have a length of 3*alist.size() + void SetAtomOriginalPos(const AtomHandleList& alist, + double *positions); + /// \brief set transformed position of atom /// /// This function also updates the original coordinates + void SetAtomTransformedPos(const AtomHandle& atom, + const geom::Vec3& position); + + /// \brief numpy float interface + /// + /// the passed in float array must have a length of 3*alist.size() + void SetAtomTransformedPos(const AtomHandleList& alist, + float *positions); + + /// \brief numpy double interface + /// + /// the passed in double array must have a length of 3*alist.size() + void SetAtomTransformedPos(const AtomHandleList& alist, + double *positions); + + /// \brief same as SetAtomTransformedPos(AtomHandle, geom::Vec3) void SetAtomPos(const AtomHandle& atom, - const geom::Vec3& position); + const geom::Vec3& position); + + /// \brief same as SetTransformedPos(AtomHandleList,float*) + void SetAtomPos(const AtomHandleList& alist, + float *positions); + + /// \brief same as SetTransformedPos(AtomHandleList,double*) + void SetAtomPos(const AtomHandleList& alist, + double *positions); /// \brief apply additional transformation to all atoms /// @@ -69,6 +105,7 @@ public: /// \brief immediately update internal coordinate system void UpdateICS(); + protected: XCSEditor(const EntityHandle& ent, EditMode mode); diff --git a/modules/mol/base/tests/CMakeLists.txt b/modules/mol/base/tests/CMakeLists.txt index e5d1c868ca25f6b2d138e176b37ea71b806458f8..b9771e0c30ec443cba99f7cc35ee8cf6ca773a9a 100644 --- a/modules/mol/base/tests/CMakeLists.txt +++ b/modules/mol/base/tests/CMakeLists.txt @@ -15,7 +15,7 @@ set(OST_MOL_BASE_UNIT_TESTS tests.cc ) -ost_unittest(mol "${OST_MOL_BASE_UNIT_TESTS}") +ost_unittest(MODULE mol SOURCES "${OST_MOL_BASE_UNIT_TESTS}") # for valgrind debugging # executable(NAME test_query_standalone SOURCES test_query_standalone.cc DEPENDS_ON mol) diff --git a/modules/mol/base/tests/test_numpy.py b/modules/mol/base/tests/test_numpy.py new file mode 100644 index 0000000000000000000000000000000000000000..1255425f85ad0bfed89b238f7264d7ec394b367d --- /dev/null +++ b/modules/mol/base/tests/test_numpy.py @@ -0,0 +1,61 @@ +import sys,unittest +sys.path.append("../../../../stage/lib/openstructure") +sys.path.append("../../../../stage/lib64/openstructure") +from ost import * +import numpy + +def v2v(v): + return geom.Vec3(float(v[0]),float(v[1]),float(v[2])) + +def dd(v1,v2): + return geom.Distance(v1,v2)<1e-8 + +class TestNumpy(unittest.TestCase): + def setUp(self): + pass + + def test_(self): + entity=mol.CreateEntity() + ed=entity.EditXCS() + ch=ed.InsertChain("X") + re=ed.AppendResidue(ch,"ALA") + a0=ed.InsertAtom(re,"A",geom.Vec3(0,0,0)) + self.assertEqual(a0.GetIndex(),0) + a1=ed.InsertAtom(re,"B",geom.Vec3(1,0,0)) + self.assertEqual(a1.GetIndex(),1) + a2=ed.InsertAtom(re,"C",geom.Vec3(2,0,0)) + self.assertEqual(a2.GetIndex(),2) + a3=ed.InsertAtom(re,"D",geom.Vec3(3,0,0)) + self.assertEqual(a3.GetIndex(),3) + + self.assertTrue(dd(a0.pos,geom.Vec3(0,0,0))) + self.assertTrue(dd(a1.pos,geom.Vec3(1,0,0))) + self.assertTrue(dd(a2.pos,geom.Vec3(2,0,0))) + self.assertTrue(dd(a3.pos,geom.Vec3(3,0,0))) + + ed.SetAtomTransformedPos(entity.GetAtomList(), + numpy.array([[0,1,0],[0,2,0],[0,3,0],[0,4,0]], dtype=numpy.float32)) + + self.assertTrue(dd(a0.pos,geom.Vec3(0,1,0))) + self.assertTrue(dd(a1.pos,geom.Vec3(0,2,0))) + self.assertTrue(dd(a2.pos,geom.Vec3(0,3,0))) + self.assertTrue(dd(a3.pos,geom.Vec3(0,4,0))) + + na=entity.positions + + self.assertTrue(dd(v2v(na[0]),geom.Vec3(0,1,0))) + self.assertTrue(dd(v2v(na[1]),geom.Vec3(0,2,0))) + self.assertTrue(dd(v2v(na[2]),geom.Vec3(0,3,0))) + self.assertTrue(dd(v2v(na[3]),geom.Vec3(0,4,0))) + + ed.SetAtomTransformedPos([3,99,2], + numpy.array([[0,0,-3],[-1,-1,-1],[0,0,-2]], dtype=numpy.float32)) + + self.assertTrue(dd(a0.pos,geom.Vec3(0,1,0))) + self.assertTrue(dd(a1.pos,geom.Vec3(0,2,0))) + self.assertTrue(dd(a2.pos,geom.Vec3(0,0,-2))) + self.assertTrue(dd(a3.pos,geom.Vec3(0,0,-3))) + +if __name__== '__main__': + unittest.main() + diff --git a/modules/seq/alg/src/merge_pairwise_alignments.cc b/modules/seq/alg/src/merge_pairwise_alignments.cc index 5636f32c97af7b96297663f75d6456abf954a4d4..d5da17127fc3e5233552a721d12acdaa1f1eb0f5 100644 --- a/modules/seq/alg/src/merge_pairwise_alignments.cc +++ b/modules/seq/alg/src/merge_pairwise_alignments.cc @@ -55,7 +55,8 @@ void update_shifts(const AlignmentHandle& aln, res_index=-1; } else if (i > 0) { - res_index=s1.GetResidueIndex(i-1); + res_index=s1.GetResidueIndex(i-1)-s1.GetOffset(); +// res_index=s1.GetResidueIndex(i-1); } ShiftMap::iterator p=shifts.find(res_index); if (p!=shifts.end()) { @@ -111,7 +112,8 @@ SequenceHandle realign_sequence(const AlignmentHandle& aln, p=shifts.find(-1); } else if (i>0 && s1.GetOneLetterCode(i-1)!='-') { - p=shifts.find(s1.GetResidueIndex(i-1)); + p=shifts.find(s1.GetResidueIndex(i-1)-s1.GetOffset()); +// p=shifts.find(s1.GetResidueIndex(i-1)); } if (p!=shifts.end()) { int d=p->second-shift; @@ -139,11 +141,16 @@ AlignmentHandle MergePairwiseAlignments(const AlignmentList& pairwise_alns, update_shifts(*i, ref_seq, shifts); } + AlignmentHandle merged=CreateAlignment(); merged.AddSequence(shift_reference(ref_seq, shifts)); + size_t ref_len=merged.GetSequence(0).GetLength(); for (AlignmentList::const_iterator i=pairwise_alns.begin(), e=pairwise_alns.end(); i!=e; ++i) { SequenceHandle new_seq=realign_sequence(*i, shifts); + for (size_t j=new_seq.GetLength(); j<ref_len; ++j) { + new_seq.Append('-'); + } merged.AddSequence(new_seq); } return merged; diff --git a/modules/seq/alg/tests/CMakeLists.txt b/modules/seq/alg/tests/CMakeLists.txt index f6d8ebe1493d5198882f57f101956baa8e6ff830..9933524408a7fd8bcf4107c72217fe6632b7f3d3 100644 --- a/modules/seq/alg/tests/CMakeLists.txt +++ b/modules/seq/alg/tests/CMakeLists.txt @@ -7,5 +7,5 @@ set(OST_SEQ_ALG_UNIT_TESTS test_global_align.py ) -ost_unittest(seq_alg "${OST_SEQ_ALG_UNIT_TESTS}") +ost_unittest(MODULE seq_alg SOURCES "${OST_SEQ_ALG_UNIT_TESTS}") diff --git a/modules/seq/alg/tests/test_merge_pairwise_alignments.cc b/modules/seq/alg/tests/test_merge_pairwise_alignments.cc index 3f67ac5d161840199ac352ffb09d5bf7c883603d..f89715adeccc627198420c1fc80826502db617a6 100644 --- a/modules/seq/alg/tests/test_merge_pairwise_alignments.cc +++ b/modules/seq/alg/tests/test_merge_pairwise_alignments.cc @@ -107,4 +107,30 @@ BOOST_AUTO_TEST_CASE(merge_pairwise_alignments_three) BOOST_CHECK_EQUAL(seqs[1].GetString(), "xyabcdefghijk"); BOOST_CHECK_EQUAL(seqs[2].GetString(), "-zabcdefghijk"); } + +BOOST_AUTO_TEST_CASE(merge_pairwise_alignments_four) +{ + SequenceHandle ref=CreateSequence("REF", "abcdefghijk"); + SequenceHandle s1=CreateSequence("S1", "abcdefghijk--"); + SequenceHandle s2=CreateSequence("S2", "abcdefghijkxy"); + AlignmentHandle aln1=CreateAlignment(); + aln1.AddSequence(s1); + aln1.AddSequence(s2); + + SequenceHandle s3=CreateSequence("S1", "-abcdefghijk"); + SequenceHandle s4=CreateSequence("S2", "zabcdefghijk"); + + AlignmentHandle aln2=CreateAlignment(); + aln2.AddSequence(s3); + aln2.AddSequence(s4); + AlignmentList l; + l.push_back(aln1); + l.push_back(aln2); + AlignmentHandle m=alg::MergePairwiseAlignments(l, ref); + ConstSequenceList seqs=m.GetSequences(); + BOOST_CHECK_EQUAL(seqs[0].GetString(), "-abcdefghijk--"); + BOOST_CHECK_EQUAL(seqs[1].GetString(), "-abcdefghijkxy"); + BOOST_CHECK_EQUAL(seqs[2].GetString(), "zabcdefghijk--"); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/modules/seq/base/pymod/export_sequence.cc b/modules/seq/base/pymod/export_sequence.cc index df18efd0db8a778a6779d2082a674732a214eb59..0cb3f4df3d62de4a2b6311b8effa132c714c300f 100644 --- a/modules/seq/base/pymod/export_sequence.cc +++ b/modules/seq/base/pymod/export_sequence.cc @@ -341,7 +341,7 @@ void export_sequence() .def("GetLength", &AlignmentHandle::GetLength) .def("__len__", &AlignmentHandle::GetLength) .def("GetSequences", &AlignmentHandle::GetSequences) - .def("GetCoverage", &AlignmentHandle::GetSequences) + .def("GetCoverage", &AlignmentHandle::GetCoverage) .def("AttachView", attach_view_a) .def("AttachView", attach_view_b) .def("Cut", &AlignmentHandle::Cut) diff --git a/modules/seq/base/tests/CMakeLists.txt b/modules/seq/base/tests/CMakeLists.txt index 528cb936ddae91eabe14d1b06c6aa743de7e29ac..645dba066e39c51c1fc0b9211228e8490ed85a07 100644 --- a/modules/seq/base/tests/CMakeLists.txt +++ b/modules/seq/base/tests/CMakeLists.txt @@ -7,5 +7,5 @@ set(OST_SEQ_UNIT_TESTS tests.cc ) -ost_unittest(seq "${OST_SEQ_UNIT_TESTS}") +ost_unittest(MODULE seq SOURCES "${OST_SEQ_UNIT_TESTS}")