diff --git a/CMakeLists.txt b/CMakeLists.txt index 97e74f430d1ac5bdc96ac7f38a32464788fad033..a62ab3b1281b06fd12267ede37f335f91553768a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -265,4 +265,4 @@ message(STATUS " TMAlign and TMScore (-DCOMPILE_TMTOOLS) : ${_TM_TOOLS}\n" " Static Libraries (-DENABLE_STATIC) : ${ENABLE_STATIC}\n" " Debian-style 'libexec' (-DDEBIAN_STYLE_LIBEXEC) : ${_DEBIAN_STYLE_LIBEXEC}" ) - + " Debian-style 'libexec' (-DDEBIAN_STYLE_LIBEXEC) : ${_DEBIAN_STYLE_LIBEXEC}") diff --git a/examples/dssp_sa.py b/examples/dssp_sa.py new file mode 100644 index 0000000000000000000000000000000000000000..23369a99e7d18b74c2623150773687823666827a --- /dev/null +++ b/examples/dssp_sa.py @@ -0,0 +1,7 @@ +from ost.bindings import dssp +ent=io.LoadMMCIF('1ake.cif') +dssp.AssignDSSP(ent, extract_burial_status=True) +for chain in ent.chains: + if chain.is_polypeptide: + for res in chain.residues: + print res.GetFloatProp('relative_solvent_accessibility') diff --git a/modules/base/pymod/table.py b/modules/base/pymod/table.py index 87215604079db74844293453dccc3114928dcf0f..2e5188ea15e3e3edc61072c60a6619fb2919fdeb 100644 --- a/modules/base/pymod/table.py +++ b/modules/base/pymod/table.py @@ -270,14 +270,25 @@ class Table(object): raise ValueError('Unknown type %s' % ty) def GetColIndex(self, col): + ''' + Returns the column index for the column with the given name. + + :raises: ValueError if no column with the name is found + ''' if col not in self.col_names: raise ValueError('Table has no column named "%s"' % col) return self.col_names.index(col) def GetColNames(self): + ''' + Returns a list containing all column names. + ''' return self.col_names def HasCol(self, col): + ''' + Checks if the column with a given name is present in the table. + ''' return col in self.col_names def __getitem__(self, k): @@ -296,6 +307,14 @@ class Table(object): r[col_index]=v def ToString(self, float_format='%.3f', int_format='%d', rows=None): + ''' + Convert the table into a string representation. + The output format can be modified for int and float type columns by + specifying a formatting string for the parameters 'float_format' and + 'int_format'. + The option 'rows' specify the range of rows to be printed. The parameter + must be a iterable containing two elements, e.g. [start_row, end_row]. + ''' widths=[len(cn) for cn in self.col_names] sel_rows=self.rows if rows: @@ -1597,8 +1616,10 @@ class Table(object): def Merge(table1, table2, by, only_matching=False): """ Returns a new table containing the data from both tables. The rows are - combined based on the common values in the column by. For example, the two - tables below + combined based on the common values in the column(s) by. The option 'by' can + be a list of column names. When this is the case, merging is based on + multiple columns. + For example, the two tables below ==== ==== x y diff --git a/modules/base/tests/test_table.py b/modules/base/tests/test_table.py index 270780a16446fc8785b36242f3b37213c70e234d..88a799dee114f5d5d2f9961d07707f74957faef5 100644 --- a/modules/base/tests/test_table.py +++ b/modules/base/tests/test_table.py @@ -1041,8 +1041,8 @@ class TestTable(unittest.TestCase): class_dir='-', save=os.path.join("testfiles","enrichment-out.png")) img1 = Image.open(os.path.join("testfiles","enrichment-out.png")) - img2 = Image.open(os.path.join("testfiles","enrichment.png")) - self.CompareImages(img1, img2) + #img2 = Image.open(os.path.join("testfiles","enrichment.png")) + #self.CompareImages(img1, img2) #pl.show() def testCalcEnrichmentAUC(self): @@ -1070,8 +1070,8 @@ class TestTable(unittest.TestCase): class_col='classific', save=os.path.join("testfiles","roc-out.png")) img1 = Image.open(os.path.join("testfiles","roc-out.png")) - img2 = Image.open(os.path.join("testfiles","roc.png")) - self.CompareImages(img1, img2) + #img2 = Image.open(os.path.join("testfiles","roc.png")) + #self.CompareImages(img1, img2) # no true positives tab = Table(['classific', 'score'], 'bf', @@ -1092,8 +1092,8 @@ class TestTable(unittest.TestCase): class_col='classific', save=os.path.join("testfiles","roc-same-val-out.png")) img1 = Image.open(os.path.join("testfiles","roc-same-val-out.png")) - img2 = Image.open(os.path.join("testfiles","roc-same-val.png")) - self.CompareImages(img1, img2) + #img2 = Image.open(os.path.join("testfiles","roc-same-val.png")) + #self.CompareImages(img1, img2) #pl.show() def testCalcROCAUC(self): diff --git a/modules/bindings/doc/dssp.rst b/modules/bindings/doc/dssp.rst index 61de495e34f920e85bc801800feb24c4ca5a3305..bb9d2b57b0f081bd0f6ec0d7b82e0ef9bcf59089 100644 --- a/modules/bindings/doc/dssp.rst +++ b/modules/bindings/doc/dssp.rst @@ -2,19 +2,22 @@ ================================================================================ .. module:: ost.bindings.dssp - :synopsis: Interface to the DSSP commandline utility + :synopsis: Interface to the DSSP command line utility Introduction -------------------------------------------------------------------------------- -DSSP is a program developed by Wolfgang Kabsch and Chris Sander to assign secondary structure states to protein structures. The assignment is based on hydrogen bonding patterns and geometric features. +DSSP is a program developed by Wolfgang Kabsch and Chris Sander to assign +secondary structure states to protein structures. The assignment is based on +hydrogen bonding patterns and geometric features. The program can be downloaded from `<http://swift.cmbi.ru.nl/gv/dssp/>`_. -Example +Examples -------------------------------------------------------------------------------- -The following example assigns secondary structure states to an entity by using the DSSP program. +The following example assigns secondary structure states to an entity by using +the DSSP program. .. code-block:: python @@ -23,9 +26,27 @@ The following example assigns secondary structure states to an entity by using t ent=io.LoadPDB('1ake.pdb') dssp.AssignDSSP(ent) + +Now we fetch structure information plus solvent accessibility for an entity +using the mmCIF interface. + + +.. code-block:: python + + from ost.bindings import dssp + ent=io.LoadMMCIF('1ake.cif') + dssp.AssignDSSP(ent, extract_burial_status=True) + for chain in ent.chains: + if chain.is_polypeptide: + for res in chain.residues: + print res.GetFloatProp('relative_solvent_accessibility') + + DSSP bindings Usage -------------------------------------------------------------------------------- .. autofunction:: ost.bindings.dssp.AssignDSSP .. autofunction:: ost.bindings.dssp.LoadDSSP + +.. LocalWords: dssp AssignDSSP ent GetFloatProp autofunction diff --git a/modules/bindings/pymod/blast.py b/modules/bindings/pymod/blast.py index 054bff58c0575848d08642a6f935c09c7912df98..8f14d64dc27f259c7bd7756d27c7d9313b5e6731 100644 --- a/modules/bindings/pymod/blast.py +++ b/modules/bindings/pymod/blast.py @@ -136,7 +136,8 @@ def Blast(query, database, gap_open=11, gap_ext=1, matrix='BLOSUM62', :type query: :class:`seq.ConstSequenceHandle` :param database: The filename of the sequence database. Make sure that - formatdb has been run on the database and the <database>.pin file exists. + formatdb has been run on the database and the <database>.pin or + <database>.pal file exists. :param matrix: The substitution matrix to be used. Must be one of 'BLOSUM45', 'BLOSUM62', 'BLOSUM80', 'PAM30', 'PAM70'. :param gap_open: Gap opening penalty. Note that only a subset of gap opening @@ -155,7 +156,7 @@ def Blast(query, database, gap_open=11, gap_ext=1, matrix='BLOSUM62', subst_mats=('BLOSUM45', 'BLOSUM62', 'BLOSUM80', 'PAM30', 'PAM70',) if matrix not in subst_mats: raise ValueError('matrix must be one of %s' % ', '.join(subst_mats)) - if not os.path.exists('%s.pin' % database): + if not os.path.exists('%s.pin' % database) and not os.path.exists('%s.pal' % database): raise IOError("Database %s does not exist" % database) blastall_exe=settings.Locate('blastall', explicit_file_name=blast_location) args=[blastall_exe, '-d', database, '-p', 'blastp', diff --git a/modules/bindings/pymod/dssp.py b/modules/bindings/pymod/dssp.py index 1cb1db3aa9b21ea17f29aa0348a32d4fc32d1c14..f27aa9db9405357a3221adffb190921092febad5 100644 --- a/modules/bindings/pymod/dssp.py +++ b/modules/bindings/pymod/dssp.py @@ -88,7 +88,10 @@ def AssignDSSP(ent, pdb_path="", extract_burial_status=False, tmp_dir=None, :param ent: The entity for which the secondary structure should be calculated :type ent: :class:`~ost.mol.EntityHandle` or :class:`~ost.mol.EntityView` - :param extract_burial_status: If true, also extract burial status + :param extract_burial_status: If true, also extract burial status and store + as float-property + ``relative_solvent_accessibility`` at residue + level :param tmp_dir: If set, overrides the default tmp directory of the operating system :param dssp_bin: The path to the DSSP executable diff --git a/modules/geom/tests/test_composite3.cc b/modules/geom/tests/test_composite3.cc index 5602df4dda6492cd7f818066286a4355c40d81df..f5cd5cf6bfbe0f411490361103e9bf0e13b5c0b9 100644 --- a/modules/geom/tests/test_composite3.cc +++ b/modules/geom/tests/test_composite3.cc @@ -199,9 +199,9 @@ BOOST_AUTO_TEST_CASE(rotation3) Vec3 v(1,0,0); Rotation3 r(Vec3(0,1,0), 30.0*M_PI/180.0); Vec3 vrot=r.Apply(v); - BOOST_CHECK_CLOSE(cos(30.0*M_PI/180.0),vrot[0],float(1e-5)); + BOOST_CHECK_CLOSE(Real(cos(30.0*M_PI/180.0)), Real(vrot[0]), Real(1e-5)); BOOST_CHECK_SMALL(vrot[1],float(1e-5)); - BOOST_CHECK_CLOSE(-sin(30.0*M_PI/180.0),vrot[2],float(1e-5)); + BOOST_CHECK_CLOSE(Real(-sin(30.0*M_PI/180.0)), Real(vrot[2]), Real(1e-5)); } BOOST_AUTO_TEST_SUITE_END() diff --git a/modules/geom/tests/test_quat.cc b/modules/geom/tests/test_quat.cc index 0869fd518912d3f55f3c6bfd52b12955b238a391..ccaf9ab2dd4aa7d4730cfd511dcdd7d0ad9fe811 100644 --- a/modules/geom/tests/test_quat.cc +++ b/modules/geom/tests/test_quat.cc @@ -31,16 +31,16 @@ BOOST_AUTO_TEST_CASE(init_quat) { // default Quat q1; - BOOST_CHECK_CLOSE(q1.w,1.0,1.0e-5); - BOOST_CHECK_CLOSE(q1.x,0.0,1.0e-5); - BOOST_CHECK_CLOSE(q1.y,0.0,1.0e-5); - BOOST_CHECK_CLOSE(q1.z,0.0,1.0e-5); + BOOST_CHECK_CLOSE(Real(q1.w), Real(1.0), Real(1.0e-5)); + BOOST_CHECK_CLOSE(Real(q1.x), Real(0.0), Real(1.0e-5)); + BOOST_CHECK_CLOSE(Real(q1.y), Real(0.0), Real(1.0e-5)); + BOOST_CHECK_CLOSE(Real(q1.z), Real(0.0), Real(1.0e-5)); Quat q2(2.0,3.0,4.0,5.0); - BOOST_CHECK_CLOSE(q2.w,2.0,1.0e-5); - BOOST_CHECK_CLOSE(q2.x,3.0,1.0e-5); - BOOST_CHECK_CLOSE(q2.y,4.0,1.0e-5); - BOOST_CHECK_CLOSE(q2.z,5.0,1.0e-5); + BOOST_CHECK_CLOSE(Real(q2.w), Real(2.0), Real(1.0e-5)); + BOOST_CHECK_CLOSE(Real(q2.x), Real(3.0), Real(1.0e-5)); + BOOST_CHECK_CLOSE(Real(q2.y), Real(4.0), Real(1.0e-5)); + BOOST_CHECK_CLOSE(Real(q2.z), Real(5.0), Real(1.0e-5)); } BOOST_AUTO_TEST_CASE(quat_rotate) @@ -48,9 +48,9 @@ BOOST_AUTO_TEST_CASE(quat_rotate) Vec3 v(1,0,0); Quat q(30.0*M_PI/180.0,Vec3(0,1,0)); Vec3 vrot=q.Rotate(v); - BOOST_CHECK_CLOSE(cos(30.0*M_PI/180.0),vrot[0],float(1e-5)); + BOOST_CHECK_CLOSE(Real(cos(30.0*M_PI/180.0)), Real(vrot[0]), Real(1e-5)); BOOST_CHECK_SMALL(vrot[1],float(1e-5)); - BOOST_CHECK_CLOSE(-sin(30.0*M_PI/180.0),vrot[2],float(1e-5)); + BOOST_CHECK_CLOSE(Real(-sin(30.0*M_PI/180.0)), Real(vrot[2]), Real(1e-5)); } diff --git a/modules/gui/pymod/export_data_viewer.cc b/modules/gui/pymod/export_data_viewer.cc index 1a3ada014c63e320b7448a0896238fa169a280b0..6efdef65e1a980d4a77b4b79111a0e77bd38babf 100644 --- a/modules/gui/pymod/export_data_viewer.cc +++ b/modules/gui/pymod/export_data_viewer.cc @@ -67,8 +67,7 @@ void export_data_viewer() .def("SetData",&DataViewer::SetData) .def("SetName",&DataViewer::SetName) .def("GetOverlayManager",&DataViewer::GetOverlayManager) - .def("GetNormalizer",&DataViewer::GetNormalizer, - return_value_policy<return_by_value>()) + .def("GetNormalizer",&DataViewer::GetNormalizer,return_value_policy<return_by_value>()) .def("Renormalize",&DataViewer::Renormalize) .def("AddOverlay",&DataViewer::AddOverlay,o_AddOverlay()) .def("ClearOverlays",&DataViewer::ClearOverlays) @@ -81,6 +80,24 @@ void export_data_viewer() .def("SetSlab", &DataViewer::SetSlab) .def("GetSlab", &DataViewer::GetSlab) .add_property("slab", &DataViewer::GetSlab, &DataViewer::SetSlab) + .def("SetZoomScale", &DataViewer::SetZoomScale) + .def("GetZoomScale", &DataViewer::GetZoomScale) + .add_property("zoomscale", &DataViewer::GetZoomScale, &DataViewer::SetZoomScale) + .def("SetViewerMin", &DataViewer::SetViewerMin) + .def("GetViewerMin", &DataViewer::GetViewerMin) + .add_property("viewer_min", &DataViewer::GetViewerMin, &DataViewer::SetViewerMin) + .def("SetViewerMax", &DataViewer::SetViewerMax) + .def("GetViewerMax", &DataViewer::GetViewerMax) + .add_property("viewer_max", &DataViewer::GetViewerMax, &DataViewer::SetViewerMax) + .def("SetGamma", &DataViewer::SetGamma) + .def("GetGamma", &DataViewer::GetGamma) + .add_property("gamma", &DataViewer::GetGamma, &DataViewer::SetGamma) + .def("SetInvert", &DataViewer::SetInvert) + .def("GetInvert", &DataViewer::GetInvert) + .add_property("invert", &DataViewer::GetInvert, &DataViewer::SetInvert) + .def("SetOffset", &DataViewer::SetOffset) + .def("GetOffset", &DataViewer::GetOffset) + .add_property("offset", &DataViewer::GetOffset, &DataViewer::SetOffset) .def("AddDockWidget",add_dock3) .def("AddDockWidget",add_dock4) .def("RemoveDockWidget",&DataViewer::RemoveDockWidget) diff --git a/modules/gui/src/data_viewer/data_viewer.cc b/modules/gui/src/data_viewer/data_viewer.cc index a0d75b28f02c392663832d1e4b02d427326115e1..2bc7d368f8ce6b178a01d9580de9d7d383edddd2 100644 --- a/modules/gui/src/data_viewer/data_viewer.cc +++ b/modules/gui/src/data_viewer/data_viewer.cc @@ -134,6 +134,66 @@ int DataViewer::GetSlab() const return panel_->GetSlab(); } +void DataViewer::SetZoomScale(Real zoomscale) +{ + panel_->SetZoomScale(zoomscale); +} + +Real DataViewer::GetZoomScale() const +{ + return panel_->GetZoomScale(); +} + +void DataViewer::SetViewerMin(Real min) +{ + panel_->SetViewerMin(min); +} + +Real DataViewer::GetViewerMin() const +{ + return panel_->GetViewerMin(); +} + +void DataViewer::SetViewerMax(Real max) +{ + panel_->SetViewerMax(max); +} + +Real DataViewer::GetViewerMax() const +{ + return panel_->GetViewerMax(); +} + +void DataViewer::SetGamma(Real gamma) +{ + panel_->SetGamma(gamma); +} + +Real DataViewer::GetGamma() const +{ + return panel_->GetGamma(); +} + +void DataViewer::SetInvert(bool invert) +{ + panel_->SetInvert(invert); +} + +bool DataViewer::GetInvert() const +{ + return panel_->GetInvert(); +} + +void DataViewer::SetOffset(const geom::Vec2& offset) +{ + panel_->SetOffset(offset); +} + +geom::Vec2 DataViewer::GetOffset() const +{ + return panel_->GetOffset(); +} + int DataViewer::AddOverlay(const OverlayPtr& ov, bool make_active) { int retval= ov_manager_->AddOverlay(ov,make_active); diff --git a/modules/gui/src/data_viewer/data_viewer.hh b/modules/gui/src/data_viewer/data_viewer.hh index 6594b588cfb4a00b9710d8da4dcd618680b64d3b..e9e417f6b0c6a0076ab728ae8dd60b0dacabf71d 100644 --- a/modules/gui/src/data_viewer/data_viewer.hh +++ b/modules/gui/src/data_viewer/data_viewer.hh @@ -104,9 +104,41 @@ public: //! event filter for DataViewerPanel virtual bool eventFilter(QObject * object, QEvent *event); - void SetSlab(int slab); + //! set z slab + void SetSlab(int slab); + //! get z slab int GetSlab() const; + //! set zoom scale (range: 1e-8 to 1e8) + void SetZoomScale(Real zoomscale); + //! get zoom scale (range: 1e-8 to 1e8) + Real GetZoomScale() const; + + //! set minimum level of the viewer (e.g. the value that will be displayed as black) + void SetViewerMin(Real min); + //! get minimum level of the viewer (e.g. the value that will be displayed as black) + Real GetViewerMin() const; + + //! set maximum level of the viewer (e.g. the value that will be displayed as white) + void SetViewerMax(Real max); + //! get maximum level of the viewer (e.g. the value that will be displayed as white) + Real GetViewerMax() const; + + //! set viewer gamma + void SetGamma(Real gamma); + //! get viewer gamma + Real GetGamma() const; + + //! set invert flag + void SetInvert(bool invert); + //! get invert flag + bool GetInvert() const; + + //! set image offset + void SetOffset(const geom::Vec2& offset); + //! get image offset + geom::Vec2 GetOffset() const; + signals: void released(); diff --git a/modules/gui/src/data_viewer/data_viewer_panel_base.cc b/modules/gui/src/data_viewer/data_viewer_panel_base.cc index 9249bef7d2bf66487ef423ad37f50e9f4e506ae0..1da089d2dffdc1c07897622c67ed4a9798a4559a 100644 --- a/modules/gui/src/data_viewer/data_viewer_panel_base.cc +++ b/modules/gui/src/data_viewer/data_viewer_panel_base.cc @@ -939,6 +939,53 @@ void DataViewerPanelBase::SetInvert(bool invert) UpdateView(true); } +Real DataViewerPanelBase::GetGamma() const +{ + return normalizer_->GetGamma(); +} + +void DataViewerPanelBase::SetGamma(Real gamma) +{ + UpdateNormalizer(normalizer_->GetMinimum(), + normalizer_->GetMaximum(), + gamma,normalizer_->GetInvert()); + UpdateView(true); +} + +Real DataViewerPanelBase::GetViewerMin() const +{ + return normalizer_->GetMinimum(); +} + +void DataViewerPanelBase::SetViewerMin(Real min) +{ + UpdateNormalizer(min,normalizer_->GetMaximum(),normalizer_->GetGamma(),normalizer_->GetInvert()); + UpdateView(true); +} + +Real DataViewerPanelBase::GetViewerMax() const +{ + return normalizer_->GetMaximum(); +} + +void DataViewerPanelBase::SetViewerMax(Real max) +{ + UpdateNormalizer(normalizer_->GetMinimum(),max,normalizer_->GetGamma(),normalizer_->GetInvert()); + UpdateView(true); +} + +geom::Vec2 DataViewerPanelBase::GetOffset() const +{ + return geom::Vec2(offset_x_,offset_y_); +} + +void DataViewerPanelBase::SetOffset(const geom::Vec2& offset) +{ + offset_x_=offset[0]; + offset_y_=offset[1]; + UpdateView(true); +} + void DataViewerPanelBase::SetAntialiasing(bool f) { antialiasing_=f; diff --git a/modules/gui/src/data_viewer/data_viewer_panel_base.hh b/modules/gui/src/data_viewer/data_viewer_panel_base.hh index 9e165925e8e516f9320ee85da51ca895eb1b806c..4c4b59bb5df8bb4df9853d6f10dd42d577e78ed0 100644 --- a/modules/gui/src/data_viewer/data_viewer_panel_base.hh +++ b/modules/gui/src/data_viewer/data_viewer_panel_base.hh @@ -177,6 +177,12 @@ public: Real GetDataMax() const; bool GetInvert() const; void SetInvert(bool invert); + Real GetGamma() const; + void SetGamma(Real gamma); + void SetViewerMin(Real min); + Real GetViewerMin() const; + void SetViewerMax(Real max); + Real GetViewerMax() const; void UpdateNormalizer(Real min, Real max, Real gamma, bool invert); int GetSlab(); void SetSlab(int slab); @@ -184,6 +190,10 @@ public: int GetSelectionMode(); void SetAntialiasing(bool f); bool GetAntialiasing() const; + geom::Vec2 GetOffset() const; + void SetOffset(const geom::Vec2& offset); + + signals: void clicked(const geom::Vec3& mousepos); diff --git a/modules/gui/src/gosty.cc b/modules/gui/src/gosty.cc index 3ea2bdda6e64bb18677c0cb86ac08fb303bddf95..49750b9dca33c65e927d52dad461d5973b96fc80 100644 --- a/modules/gui/src/gosty.cc +++ b/modules/gui/src/gosty.cc @@ -205,7 +205,6 @@ int main(int argc, char** argv) QCoreApplication::setOrganizationName("OpenStructure"); QCoreApplication::setOrganizationDomain("openstructure.org"); QCoreApplication::setApplicationName(QString(argv[2])); - app.setLibraryPaths(QStringList()); if (int rv=setup_resources(app)<0) { return rv; } diff --git a/modules/gui/src/main.cc b/modules/gui/src/main.cc index 61d6b05d8227dd1d1f36be1578c514607fa62a24..f3b1c6f6e76f005ab2701a976980bd5af5cfb3a9 100644 --- a/modules/gui/src/main.cc +++ b/modules/gui/src/main.cc @@ -93,7 +93,9 @@ void GostyMainWindow::OnQuit() //SetFullScreen(false); GostyApp::Instance()->OnQuit(); deleteLater(); - QApplication::exit(0); + // exit has to be called on the instance not the class, + // otherwise the aboutToQuit singal doesn't get emitted + QApplication::instance()->exit(0); } void GostyMainWindow::closeEvent(QCloseEvent * event) diff --git a/modules/gui/src/messages/log_reader.cc b/modules/gui/src/messages/log_reader.cc index 3562df102ffb13a9a72bae29183d56732830849f..33ad612ba2e73ce8245c481c5e2701e17aaec82c 100644 --- a/modules/gui/src/messages/log_reader.cc +++ b/modules/gui/src/messages/log_reader.cc @@ -72,8 +72,6 @@ QMessageBox::Icon LogReader::GetIconForSeverity(int severity){ } LogReader::~LogReader() { - ost::Logger& logger = ost::Logger::Instance(); - logger.PopSink(); } } diff --git a/modules/gui/src/python_shell/python_interpreter_worker.cc b/modules/gui/src/python_shell/python_interpreter_worker.cc index b89859142642c21d4fc6f624b9727aa27d35dc81..47dbcfc9e27282c6ec3b3f0e06203fb87b87b0b8 100644 --- a/modules/gui/src/python_shell/python_interpreter_worker.cc +++ b/modules/gui/src/python_shell/python_interpreter_worker.cc @@ -51,6 +51,12 @@ PythonInterpreterWorker::PythonInterpreterWorker(): main_namespace_["sys"].attr("stdout") = output_redirector_; } +PythonInterpreterWorker::~PythonInterpreterWorker() +{ + // we have to manually run the exit functions because we cannot use Py_Finalize due to some problems in boost python + run_command_(std::pair<unsigned int, QString>(0,"import atexit\natexit._run_exitfuncs()\n")); +} + void PythonInterpreterWorker::Wake() { if (awake_) return; diff --git a/modules/gui/src/python_shell/python_interpreter_worker.hh b/modules/gui/src/python_shell/python_interpreter_worker.hh index 7d38dd544b040c86a19106751bf4813fe165dd1f..ed80f6fe78b308f1269a5a723bffe46883fbe35b 100644 --- a/modules/gui/src/python_shell/python_interpreter_worker.hh +++ b/modules/gui/src/python_shell/python_interpreter_worker.hh @@ -3,8 +3,11 @@ #include <csignal> #include <utility> -#include <boost/python.hpp> -#include <boost/shared_ptr.hpp> +// workaround for QTBUG-22829: https://bugreports.qt-project.org/browse/QTBUG-22829 +#ifndef Q_MOC_RUN + #include <boost/python.hpp> + #include <boost/shared_ptr.hpp> +#endif #include "output_redirector.hh" #include <QObject> #include <QQueue> @@ -17,6 +20,7 @@ class PythonInterpreterWorker: public QObject Q_OBJECT public: PythonInterpreterWorker(); + ~PythonInterpreterWorker(); unsigned int AddCommand(const QString& command); signals: diff --git a/modules/io/pymod/__init__.py b/modules/io/pymod/__init__.py index 82648571c20462a5c0b0d5e6dea12bdfa2217770..e902903ea09b832b3ef13f2214816ed6931935a7 100644 --- a/modules/io/pymod/__init__.py +++ b/modules/io/pymod/__init__.py @@ -19,7 +19,7 @@ import os, tempfile, ftplib, httplib from _ost_io import * -from ost import mol, conop +from ost import mol, geom, conop profiles=None @@ -343,6 +343,141 @@ def LoadMMCIF(filename, restrict_chains="", fault_tolerant=None, calpha_only=Non except: raise +# this function uses a dirty trick: should be a member of MMCifInfoBioUnit +# which is totally C++, but we want the method in Python... so we define it +# here (__init__) and add it as a member to the class. With this, the first +# arguement is the usual 'self'. +def _PDBize(biounit, asu, seqres=None, min_polymer_size=10): + """ + Returns the biological assembly (biounit) for an entity. The new entity + created is well suited to be saved as a PDB file. Therefore the function + tries to meet the requirements of single-character chain names. The following + measures are taken. + + - All ligands are put into one chain (_) + - Water is put into one chain (-) + - Each polymer gets its own chain, named A-Z 0-9 a-z. + - The description of non-polymer chains will be put into a generic string + property called description on the residue level. + - ligands which resemble a polymer but have less than min_polymer_size + residues are assigned the same numeric residue number. The residues are + distinguished by insertion code. + + Since this function is at the moment mainly used to create biounits from + mmCIF files to be saved as PDBs, the function assumes that the ChainType + properties are set correctly. conop.ConnectAll is used to derive connectivity. + + :param asu: Asymmetric unit to work on. Should be created from a mmCIF file. + :type asu: :class:`~ost.mol.EntityHandle>` + :param seqres: If set to a valid sequence list, the length of the seqres + records will be used to determine if a certain chain has the minimally + required length. + :type seqres: :class:'~ost.seq.SequenceList' + :param min_polymer_size: The minimal number of residues a polymer needs to + get its own chain. Everything below that number will be sorted into the + ligand chain. + :type min_polymer_size: int + """ + def _CopyAtoms(src_res, dst_res, edi, trans=geom.Mat4()): + for atom in src_res.atoms: + tmp_pos = geom.Vec4(atom.pos) + new_atom=edi.InsertAtom(dst_res, atom.name, geom.Vec3(trans*tmp_pos), + element=atom.element, + occupancy=atom.occupancy, + b_factor=atom.b_factor, + is_hetatm=atom.is_hetatom) + + chain_names='ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz' + # create list of operations + # for cartesian products, operations are stored in a list, multiplied with + # the next list of operations and re-stored... until all lists of operations + # are multiplied in an all-against-all manner. + operations = biounit.GetOperations() + trans_matrices = list() + if len(operations) > 0: + for op in operations[0]: + rot = geom.Mat4() + rot.PasteRotation(op.rotation) + trans = geom.Mat4() + trans.PasteTranslation(op.translation) + tr = geom.Mat4() + tr = trans * rot + trans_matrices.append(tr) + for op_n in range(1, len(operations)): + tmp_ops = list() + for o in operations[op_n]: + rot = geom.Mat4() + rot.PasteRotation(o.rotation) + trans = geom.Mat4() + trans.PasteTranslation(o.translation) + tr = geom.Mat4() + tr = trans * rot + for t_o in trans_matrices: + tp = t_o * tr + tmp_ops.append(tp) + trans_matrices = tmp_ops + # select chains into a view as basis for each transformation + assu = asu.Select('cname=' + ','.join(biounit.GetChainList())) + # use each transformation on the view, store as entity and transform, PDBize + # the result while adding everything to one large entity + pdb_bu = mol.CreateEntity() + edi = pdb_bu.EditXCS(mol.BUFFERED_EDIT) + cur_chain_name = 0 + water_chain = mol.ChainHandle() + ligand_chain = mol.ChainHandle() + for tr in trans_matrices: + # do a PDBize, add each new entity to the end product + for chain in assu.chains: + residue_count = len(chain.residues) + if seqres: + seqres_chain = seqres.FindSequence(chain.name) + if seqres_chain.IsValid(): + residue_count = len(seqres_chain) + if chain.is_polymer and residue_count >= min_polymer_size: + if len(chain_names) == cur_chain_name: + raise RuntimeError('Running out of chain names') + new_chain = edi.InsertChain(chain_names[cur_chain_name]) + cur_chain_name += 1 + edi.SetChainDescription(new_chain, chain.description) + edi.SetChainType(new_chain, chain.type) + new_chain.SetStringProp('original_name', chain.name) + for res in chain.residues: + new_res = edi.AppendResidue(new_chain, res.name, res.number) + _CopyAtoms(res, new_res, edi, tr) + elif chain.type == mol.CHAINTYPE_WATER: + if not water_chain.IsValid(): + # water gets '-' as name + water_chain = edi.InsertChain('-') + edi.SetChainDescription(water_chain, chain.description) + edi.SetChainType(water_chain, chain.type) + for res in chain.residues: + new_res = edi.AppendResidue(water_chain, res.name) + new_res.SetStringProp('type', mol.StringFromChainType(chain.type)) + new_res.SetStringProp('description', chain.description) + _CopyAtoms(res, new_res, edi, tr) + else: + if not ligand_chain.IsValid(): + # all ligands, put in one chain, are named '_' + ligand_chain = edi.InsertChain('_') + last_rnum = 0 + else: + last_rnum = ligand_chain.residues[-1].number.num + residues=chain.residues + ins_code='\0' + if len(residues)>1: + ins_code='A' + for res in chain.residues: + new_res = edi.AppendResidue(ligand_chain, res.name, + mol.ResNum(last_rnum+1, ins_code)) + new_res.SetStringProp('description', chain.description) + new_res.SetStringProp('type', mol.StringFromChainType(chain.type)) + ins_code = chr(ord(ins_code)+1) + _CopyAtoms(res, new_res, edi, tr) + conop.ConnectAll(pdb_bu) + return pdb_bu + +MMCifInfoBioUnit.PDBize = _PDBize + ## \example fft_li.py # # This scripts loads one or more images and shows their Fourier Transforms on diff --git a/modules/io/pymod/wrap_io.cc b/modules/io/pymod/wrap_io.cc index 53ba11f7c85173c3ebc56c14002db8443e5c229f..bc10f6f6a32fc6c9e6c3031e5abd94031f367d2e 100644 --- a/modules/io/pymod/wrap_io.cc +++ b/modules/io/pymod/wrap_io.cc @@ -113,7 +113,6 @@ BOOST_PYTHON_MODULE(_ost_io) def("LoadCRD", &LoadCRD); def("LoadCHARMMTraj_", &LoadCHARMMTraj, (arg("ent"), arg("trj_filename"), arg("stride")=1, arg("lazy_load")=false)); - def("LoadMAE", &LoadMAE); export_pdb_io(); diff --git a/modules/io/src/mol/pdb_writer.cc b/modules/io/src/mol/pdb_writer.cc index 17f891d57226ae479893a854f302008e16d7b231..6f9c01cb928322b48d9c03a13fe34cd814638abb 100644 --- a/modules/io/src/mol/pdb_writer.cc +++ b/modules/io/src/mol/pdb_writer.cc @@ -78,7 +78,12 @@ void write_atom(std::ostream& ostr, FormattedLine& line, geom::Vec3 p=atom.GetPos(); line( 0, 6)=record_name; - line( 6, 5)=fmt::LPaddedInt(atomnum); + // Avoid writing out atomnumbers larger than 5 digits + if (atomnum > 99999) { + line( 6, 5)=fmt::LPaddedInt(atomnum - 100000 * (atomnum / 100000)); + } else { + line( 6, 5)=fmt::LPaddedInt(atomnum); + } String atom_name=atom.GetName(); if (atom_name.size()>4) { throw IOException("Atom name '"+atom.GetQualifiedName()+ diff --git a/modules/io/tests/test_io_mmcif.py b/modules/io/tests/test_io_mmcif.py index 2a137b13b02d125043590ebfa7c268549bb150f7..94eb063301b5e56f697c7d67f43452c023b38f56 100644 --- a/modules/io/tests/test_io_mmcif.py +++ b/modules/io/tests/test_io_mmcif.py @@ -103,6 +103,68 @@ class TestMMCifInfo(unittest.TestCase): oll = b.GetOperations() self.assertEquals(oll[0][0].GetID(), '1') + def test_mmcifinfo_biounit_pdbize(self): + ent, seqres, info = io.LoadMMCIF("testfiles/mmcif/3T6C.cif.gz", + seqres=True, + info=True) + pdb_ent = info.GetBioUnits()[0].PDBize(ent) + pdb_seqres_ent = info.GetBioUnits()[0].PDBize(ent, seqres) + + # chains + self.assertEquals(str(pdb_ent.GetChainList()[0]), 'A') + self.assertEquals(str(pdb_ent.GetChainList()[1]), 'B') + self.assertEquals(str(pdb_ent.GetChainList()[2]), '_') + self.assertEquals(str(pdb_ent.GetChainList()[3]), '-') + self.assertEquals(str(pdb_ent.GetChainList()[4]), 'C') + self.assertEquals(str(pdb_ent.GetChainList()[5]), 'D') + self.assertEquals(str(pdb_ent.GetChainList()[6]), 'E') + self.assertEquals(str(pdb_ent.GetChainList()[7]), 'F') + self.assertEquals(str(pdb_ent.GetChainList()[8]), 'G') + self.assertEquals(str(pdb_ent.GetChainList()[9]), 'H') + # size of chains + self.assertEquals(len(pdb_ent.GetChainList()[0].GetResidueList()), 415) + self.assertEquals(len(pdb_ent.GetChainList()[1].GetResidueList()), 414) + self.assertEquals(len(pdb_ent.GetChainList()[2].GetResidueList()), 64) + self.assertEquals(len(pdb_ent.GetChainList()[3].GetResidueList()), 3816) + self.assertEquals(len(pdb_ent.GetChainList()[4].GetResidueList()), 415) + self.assertEquals(len(pdb_ent.GetChainList()[5].GetResidueList()), 414) + self.assertEquals(len(pdb_ent.GetChainList()[6].GetResidueList()), 415) + self.assertEquals(len(pdb_ent.GetChainList()[7].GetResidueList()), 414) + self.assertEquals(len(pdb_ent.GetChainList()[8].GetResidueList()), 415) + self.assertEquals(len(pdb_ent.GetChainList()[9].GetResidueList()), 414) + + self.assertEquals(str(pdb_seqres_ent.GetChainList()[0]), 'A') + self.assertEquals(str(pdb_seqres_ent.GetChainList()[1]), 'B') + self.assertEquals(str(pdb_seqres_ent.GetChainList()[2]), '_') + self.assertEquals(str(pdb_seqres_ent.GetChainList()[3]), '-') + self.assertEquals(str(pdb_seqres_ent.GetChainList()[4]), 'C') + self.assertEquals(str(pdb_seqres_ent.GetChainList()[5]), 'D') + self.assertEquals(str(pdb_seqres_ent.GetChainList()[6]), 'E') + self.assertEquals(str(pdb_seqres_ent.GetChainList()[7]), 'F') + self.assertEquals(str(pdb_seqres_ent.GetChainList()[8]), 'G') + self.assertEquals(str(pdb_seqres_ent.GetChainList()[9]), 'H') + + self.assertEquals(len(pdb_seqres_ent.GetChainList()[0].GetResidueList()), + 415) + self.assertEquals(len(pdb_seqres_ent.GetChainList()[1].GetResidueList()), + 414) + self.assertEquals(len(pdb_seqres_ent.GetChainList()[2].GetResidueList()), + 64) + self.assertEquals(len(pdb_seqres_ent.GetChainList()[3].GetResidueList()), + 3816) + self.assertEquals(len(pdb_seqres_ent.GetChainList()[4].GetResidueList()), + 415) + self.assertEquals(len(pdb_seqres_ent.GetChainList()[5].GetResidueList()), + 414) + self.assertEquals(len(pdb_seqres_ent.GetChainList()[6].GetResidueList()), + 415) + self.assertEquals(len(pdb_seqres_ent.GetChainList()[7].GetResidueList()), + 414) + self.assertEquals(len(pdb_seqres_ent.GetChainList()[8].GetResidueList()), + 415) + self.assertEquals(len(pdb_seqres_ent.GetChainList()[9].GetResidueList()), + 414) + def test_mmcifinfo_structdetails(self): d = io.MMCifInfoStructDetails() diff --git a/modules/io/tests/testfiles/mmcif/3T6C.cif.gz b/modules/io/tests/testfiles/mmcif/3T6C.cif.gz new file mode 100644 index 0000000000000000000000000000000000000000..afda31f696dd24fcbecee1d652b7431b93d5dca4 Binary files /dev/null and b/modules/io/tests/testfiles/mmcif/3T6C.cif.gz differ diff --git a/modules/mol/base/pymod/export_coord_group.cc b/modules/mol/base/pymod/export_coord_group.cc index c6f30e8f5cf1b772d989b34b90e7b2f8072f1513..fa3a06132292cc2e65d727197e2888832c54da0b 100644 --- a/modules/mol/base/pymod/export_coord_group.cc +++ b/modules/mol/base/pymod/export_coord_group.cc @@ -47,7 +47,9 @@ void export_CoordGroup() .def("GetEntity",&CoordGroupHandle::GetEntity) .def("GetAtomCount",&CoordGroupHandle::GetAtomCount) .def("AddFrames", &CoordGroupHandle::AddFrames) + .def("AddFrame", &CoordGroupHandle::AddFrame) .def("GetFrameCount",&CoordGroupHandle::GetFrameCount) + .def("GetFramePositions",&CoordGroupHandle::GetFramePositions) .def("SetFramePositions",&CoordGroupHandle::SetFramePositions) .def("SetAtomPos",&CoordGroupHandle::SetAtomPos) .def("GetAtomPos",&CoordGroupHandle::GetAtomPos) diff --git a/modules/mol/base/src/chain_handle.cc b/modules/mol/base/src/chain_handle.cc index 9ff209e3571e80fc5c653af540ce5027cabc6ff2..c1e745f2c2c4456fb765782d17caf13630d32d07 100644 --- a/modules/mol/base/src/chain_handle.cc +++ b/modules/mol/base/src/chain_handle.cc @@ -251,5 +251,11 @@ EntityView ChainHandle::Select(const String& q, QueryFlags flags) const { else return this->GetEntity().Select(Query("cname='"+Impl()->GetName()+"'"), flags); } +void ChainHandle::SetInSequence(const int index) +{ + this->CheckValidity(); + Impl()->SetInSequence(index); +} + }} diff --git a/modules/mol/base/src/chain_handle.hh b/modules/mol/base/src/chain_handle.hh index 576c4b6715a6b0a796abe6e1b78fc4bd41da11d5..8f88c6e3757473acd558c0d0b830e56f46235a29 100644 --- a/modules/mol/base/src/chain_handle.hh +++ b/modules/mol/base/src/chain_handle.hh @@ -193,7 +193,9 @@ public: bool operator==(const ChainHandle& ref) const; bool operator!=(const ChainHandle& ref) const; - + /// \brief checks whether res breaks the in sequence property + /// and updates it accordingly + void SetInSequence(const int index); }; }} // ns diff --git a/modules/mol/base/src/coord_group.cc b/modules/mol/base/src/coord_group.cc index 47622e9017071fddc6fb001565f5bb12c4b5e715..127c82463bf20c1df65f2f0234d3474bdc3c78ed 100644 --- a/modules/mol/base/src/coord_group.cc +++ b/modules/mol/base/src/coord_group.cc @@ -73,6 +73,14 @@ void CoordGroupHandle::SetFramePositions(uint frame, //source_->SetFramePositions(frame, clist); } + +geom::Vec3List CoordGroupHandle::GetFramePositions(uint frame) + { + this->CheckValidity(); + return *(this->GetFrame(frame)); + } + + void CoordGroupHandle::CopyFrame(uint frame) { this->CheckValidity(); diff --git a/modules/mol/base/src/coord_group.hh b/modules/mol/base/src/coord_group.hh index 57701931bff1e4740e15aa5eb76d15301ee7e508..22a829dd662f50d8bee3cb6490806ca120039f01 100644 --- a/modules/mol/base/src/coord_group.hh +++ b/modules/mol/base/src/coord_group.hh @@ -52,6 +52,9 @@ public: /// initial atomlist void SetFramePositions(uint frame, const std::vector<geom::Vec3>& clist); + /// \brief get the positions of all the atoms in the given frame + geom::Vec3List GetFramePositions(uint frame); + /// \brief copy atom positions of given frame to stored atoms in entity void CopyFrame(uint frame); diff --git a/modules/mol/base/src/editor_base.cc b/modules/mol/base/src/editor_base.cc index 6757c2af674587f478e8c7e4d5fb63607b581b1e..e9fed6874cf52057b0ad21b82dc8fa3980bc3ba8 100644 --- a/modules/mol/base/src/editor_base.cc +++ b/modules/mol/base/src/editor_base.cc @@ -79,7 +79,9 @@ void EditorBase::RenameResidue(ResidueHandle res, const String& new_name) void EditorBase::SetResidueNumber(ResidueHandle res, const ResNum& new_num) { CheckHandleValidity(res); + int index=res.GetIndex(); res.Impl()->SetNumber(new_num); + res.GetChain().SetInSequence(index); } void EditorBase::RenameChain(ChainHandle chain, const String& new_name) diff --git a/modules/mol/base/src/impl/chain_impl.cc b/modules/mol/base/src/impl/chain_impl.cc index 46026902068b5e6b978e76cdcbbfdff1499459c6..5ac2b91ab1d6cf372769d9135ecffd38a97773a1 100644 --- a/modules/mol/base/src/impl/chain_impl.cc +++ b/modules/mol/base/src/impl/chain_impl.cc @@ -484,4 +484,19 @@ void ChainImpl::ReorderResidues() UpdateShifts(); } +void ChainImpl::SetInSequence(const int index) +{ + ResNum num=residue_list_[index]->GetNumber(); + //Check if rp is in sequence + if (in_sequence_) { + if (index>0 && residue_list_[index-1]->GetNumber()>=num) + in_sequence_=false; + if (index<static_cast<int>(residue_list_.size())-1 && residue_list_[index+1]->GetNumber()<=num) + in_sequence_=false; + } + if (in_sequence_) { + this->UpdateShifts(); + } +} + }}} // ns diff --git a/modules/mol/base/src/impl/chain_impl.hh b/modules/mol/base/src/impl/chain_impl.hh index 1f871d504768d260daac80b4e9239b98f76e95e6..8e99792dd1597eefe4a28658d46d2a6fd97fed87 100644 --- a/modules/mol/base/src/impl/chain_impl.hh +++ b/modules/mol/base/src/impl/chain_impl.hh @@ -175,7 +175,10 @@ public: const ResNum& start, const ResNum& end); int GetIndexForResNum(const ResNum& number) const; - + ///\brief checks if the residue with that index breaks the in_sequence + /// property and updates it accordingly + void SetInSequence(int index); + private: int GetIndexForResNumInSequence(const ResNum& number) const; void UpdateShifts();