diff --git a/CMakeLists.txt b/CMakeLists.txt index 82b1b67d718e2b0e6f3b8ff1a7e1485772f9995a..592751d5f7278970a2d37119700ec84c1f0508c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,8 @@ else() set(_PROFILE OFF) endif() +add_definitions(-DEIGEN2_SUPPORT) + if (COMPOUND_LIB) set(_COMP_LIB "${COMPOUND_LIB}") if (NOT IS_ABSOLUTE "${COMPOUND_LIB}") @@ -251,6 +253,7 @@ include_directories(${Boost_INCLUDE_DIRS} ${EIGEN2_INCLUDE_DIR} ${TIFF_INCLUDE_DIR} ${SPNAV_INCLUDE_DIR} + ${PNG_INCLUDE_DIR} ) if (UNIX) SET(CMAKE_SKIP_BUILD_RPATH FALSE) diff --git a/build_configs/darwin_homebrew.txt b/build_configs/darwin_homebrew.txt new file mode 100644 index 0000000000000000000000000000000000000000..c88a16256e5040d3cf15c1c4e288ea84ed3f3b9c --- /dev/null +++ b/build_configs/darwin_homebrew.txt @@ -0,0 +1,2 @@ +set(PNG_INCLUDE_DIR "/usr/X11/include" CACHE PATH "include path for system libpng") +set(EIGEN2_INCLUDE_DIR "/usr/local/include/eigen3" CACHE PATH "Eigen3-compatible include path") diff --git a/cmake_support/FindBoost.cmake b/cmake_support/FindBoost.cmake index 68064ebf3c40c42cd6d29630b3c7009c6ed35350..e784de62ff5b451435a10116c3b8ea2c196a4191 100644 --- a/cmake_support/FindBoost.cmake +++ b/cmake_support/FindBoost.cmake @@ -271,9 +271,9 @@ else(Boost_FIND_VERSION_EXACT) # The user has not requested an exact version. Among known # versions, find those that are acceptable to the user request. set(_Boost_KNOWN_VERSIONS ${Boost_ADDITIONAL_VERSIONS} - "1.41.0" "1.41" "1.40.0" "1.40" "1.39.0" "1.39" "1.38.0" "1.38" "1.37.0" - "1.37" "1.36.1" "1.36.0" "1.36" "1.35.1" "1.35.0" "1.35" "1.34.1" "1.34.0" - "1.34" "1.33.1" "1.33.0" "1.33") + "1.46" "1.45" "1.44" "1.43" "1.42" "1.41.0" "1.41" "1.40.0" "1.40" "1.39.0" + "1.39" "1.38.0" "1.38" "1.37.0" "1.37" "1.36.1" "1.36.0" "1.36" "1.35.1" + "1.35.0" "1.35" "1.34.1" "1.34.0" "1.34" "1.33.1" "1.33.0" "1.33") set(_boost_TEST_VERSIONS) if(Boost_FIND_VERSION) set(_Boost_FIND_VERSION_SHORT "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") diff --git a/cmake_support/FindPython.cmake b/cmake_support/FindPython.cmake index d742712452029bdb7035ba36c4a9d72660aa0ded..99faf54d8e293f4b57fd808a0af750a900bc97b7 100644 --- a/cmake_support/FindPython.cmake +++ b/cmake_support/FindPython.cmake @@ -17,7 +17,7 @@ # Author: Marco Biasini #------------------------------------------------------------------------------- -set(PYTHON_VERSIONS 2.6 2.5 2.4 2.3 2.2 ) +set(PYTHON_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 ) set(PYTHON_MIN_VERSION 2.2.1) #------------------------------------------------------------------------------- diff --git a/deployment/linux/create_bundle.py b/deployment/linux/create_bundle.py index 43e980f9dbfed5f355ead57d1501823d5b15e5cd..cf0ce5f6103cb48a99632a732d6672c88895c070 100644 --- a/deployment/linux/create_bundle.py +++ b/deployment/linux/create_bundle.py @@ -12,7 +12,6 @@ if len(sys.argv) < 2: print 'usage: create_bundle.py additional_label' sys.exit() -boost_string='\".so.1.40.0\"' system_python_version='python2.6' system_python_bin='/usr/bin/'+system_python_version system_python_libs='/usr/lib/'+system_python_version @@ -21,7 +20,7 @@ second_system_python_libs='/usr/lib/pymodules/'+system_python_version python_bin_in_bundle='python' qt4_plugins='/usr/lib/qt4/plugins' additional_label=sys.argv[1] -list_of_excluded_libraries=['ld-linux','libexpat','libgcc_s','libglib','cmov','libice','libSM','libX','libg','libGL.so','libfontconfig','libfreetype','libdrm','libxcb','libICE'] +list_of_excluded_libraries=['ld-linux','libexpat','libgcc_s','libglib','cmov','libice','libSM','libX','libg','libGL.so','libfontconfig','libfreetype','libdrm','libxcb','libICE','libnvidia','libc'] currdir=os.getcwd() if currdir.find('deployment')==-1 or currdir.find('linux')==-1: print '\n' @@ -41,9 +40,8 @@ else: libdir='lib' archstring='32bit' date_pattern='%Y-%b-%d' -build=str(datetime.datetime.now()) -stamp=datetime.datetime.strptime(build, date_pattern) -directory_name='openstructure-linux-'+archstring+'-'+additional_label+stamp +build=datetime.date.today() +directory_name='openstructure-linux-'+archstring+'-'+additional_label+'-'+str(build) print 'Hardcoding package python binary path in openstructure executables' subprocess.call('mv scripts/ost.in scripts/ost.in.backup',shell=True,cwd='../../') subprocess.call('sed "s/@PYTHON_BINARY@/\$DNG_ROOT\/bin\/'+python_bin_in_bundle+'/g" scripts/ost.in.backup > scripts/ost.in.prepreprepre',shell=True,cwd='../../') @@ -60,12 +58,14 @@ subprocess.call('sed "s/\#export QT_PLUGIN_PATH/ export QT_PLUGIN_PATH/g" script #subprocess.call('wget ftp://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif', shell=True, cwd='../../') #print 'Compiling Openstructure' #subprocess.call('cmake ./ -DCMAKE_BUILD_TYPE=Release -DPREFIX='+directory_name+' -DBoost_COMPILER='+boost_string+'-DENABLE_IMG=OFF -DENABLE_UI=OFF -DENABLE_GFX=OFF', shell=True,cwd='../../') +#subprocess.call('cmake ./ -DCMAKE_BUILD_TYPE=Release -DPREFIX='+directory_name+' s-DENABLE_IMG=OFF -DENABLE_UI=OFF -DENABLE_GFX=OFF', shell=True,cwd='../../') #subprocess.call('make -j5',shell=True,cwd='../../') #print 'Converting Chemlib dictionary' #subprocess.call('stage/bin/chemdict_tool create components.cif compounds.chemlib', shell=True, cwd='../../') #print '\nStaging Chemlib dictionary' print 'Compiling Openstructure' -subprocess.call('cmake ./ -DCMAKE_BUILD_TYPE=Release -DPREFIX='+directory_name+' -DBoost_COMPILER='+boost_string+' -DCOMPOUND_LIB=ChemLib/compounds.chemlib -DENABLE_IMG=ON -DENABLE_UI=ON -DENABLE_GFX=ON -DOPTIMIZE=ON',shell=True,cwd='../../') +#subprocess.call('cmake ./ -DCMAKE_BUILD_TYPE=Release -DPREFIX='+directory_name+' -DBoost_COMPILER='+boost_string+' -DCOMPOUND_LIB=ChemLib/compounds.chemlib -DENABLE_IMG=ON -DENABLE_UI=ON -DENABLE_GFX=ON -DOPTIMIZE=ON',shell=True,cwd='../../') +subprocess.call('cmake ./ -DCMAKE_BUILD_TYPE=Release -DPREFIX='+directory_name+' -DCOMPOUND_LIB=ChemLib/compounds.chemlib -DENABLE_IMG=ON -DENABLE_UI=ON -DENABLE_GFX=ON -DOPTIMIZE=ON',shell=True,cwd='../../') subprocess.call('make -j2',shell=True,cwd='../../') print 'Removing obsolete packages and package directory' subprocess.call('rm -fr openstructure-linux*',shell=True,cwd='../../') diff --git a/modules/base/src/test_utils/compare_files.cc b/modules/base/src/test_utils/compare_files.cc index 30aaf652cdb7f7ee772471875f4770a929464eee..f28821e686e4e7745d1de9b359f441ca3d99aea4 100644 --- a/modules/base/src/test_utils/compare_files.cc +++ b/modules/base/src/test_utils/compare_files.cc @@ -25,7 +25,16 @@ namespace ost { bool compare_files(const String& test, const String& gold_standard) { std::ifstream test_stream(test.c_str()); + if (!test_stream) { + std::cerr << "output file '" << test << "' doesn't exist" << std::endl; + return false; + } std::ifstream gold_stream(gold_standard.c_str()); + if (!gold_stream) { + std::cerr << "gold standard file '" << gold_standard + << "' doesn't exist" << std::endl; + return false; + } String test_line, gold_line; while (true) { bool test_end=std::getline(test_stream, test_line) != 0; diff --git a/modules/bindings/pymod/naccess.py b/modules/bindings/pymod/naccess.py index f18d8e9a6029ffd824393e8eb00239a7452d1c6f..afb58c4bac3c59190ff4c5a3a1c880dfb1be2455 100644 --- a/modules/bindings/pymod/naccess.py +++ b/modules/bindings/pymod/naccess.py @@ -75,7 +75,7 @@ def _ParseAsaFile(entity, file, asa_atom): res_number = l[22:27] asa = l[54:63] atom_name = atom_name.strip() - chain_id = chain_id.strip() + chain_id = chain_id res_number = res_number.strip() asa = asa.strip() #print "res_number:", res_number @@ -88,7 +88,10 @@ def _ParseAsaFile(entity, file, asa_atom): resNum = mol.ResNum(int(di["num"]), di["ins"]) #print res_number, resNum.num, resNum.ins a = entity.FindAtom(chain_id, resNum, atom_name) - a.SetFloatProp(asa_atom, float(asa)) + if(a.IsValid()): + a.SetFloatProp(asa_atom, float(asa)) + else: + print chain_id, resNum, atom_name ## \brief Reads Area file (.rsa) and attach asa (absolute + relative) per residue to an entitiy # diff --git a/modules/bindings/pymod/tmtools.py b/modules/bindings/pymod/tmtools.py index 04db235931de9885850cc2c412cb8ed7038c6399..522a2dd559e31fb6656dca3ad20dc9a42d360722 100644 --- a/modules/bindings/pymod/tmtools.py +++ b/modules/bindings/pymod/tmtools.py @@ -68,7 +68,7 @@ def _ParseTmAlign(lines): alignment = seq.CreateAlignment() alignment.AddSequence(seq2) alignment.AddSequence(seq1) - return TMAlignResult(rmsd, aln_length, tm_score, tf, seq2, alignment) + return TMAlignResult(rmsd, tm_score, aln_length, tf, seq2, alignment) def _RunTmAlign(tmalign, tmp_dir): model1_filename=os.path.join(tmp_dir, 'model01.pdb') diff --git a/modules/conop/doc/conop.rst b/modules/conop/doc/conop.rst index 8eed48919c547cadf4465a44d0d0388176c1e532..b8dc369dc4663a13593a6c2ac406aed1f3e58d95 100644 --- a/modules/conop/doc/conop.rst +++ b/modules/conop/doc/conop.rst @@ -258,8 +258,14 @@ The CompoundLib may be created from a MM CIF dictionary. The latest dictionary can be found on the `wwPDB site <http://www.wwpdb.org/ccd.html>`_. After downloading the file in MM CIF use the :program:`chemdict_tool` to convert -the MM CIF dictionary into our internal format. +the MM CIF dictionary into our internal format. .. code-block:: bash chemdict_tool create <components.cif> <compounds.chemlib> + +If you are working with CHARMM trajectory files, you will also have to add the definitions for CHARMM. Assuming your are in the top-level source directory of OpenStructure, this can be achieved by: + +.. code-block:: bash + + chemdict_tool update modules/conop/data/charmm.cif <compounds.chemlib> charmm diff --git a/modules/conop/pymod/export_compound.cc b/modules/conop/pymod/export_compound.cc index 6e95a0c246ebf854506e478cff94eaac91832bcb..d39a05a840570f31e466fee3757ab9ed7e3c8882 100644 --- a/modules/conop/pymod/export_compound.cc +++ b/modules/conop/pymod/export_compound.cc @@ -20,39 +20,105 @@ #include <boost/python/register_ptr_to_python.hpp> #include <boost/python/suite/indexing/vector_indexing_suite.hpp> using namespace boost::python; + #include <ost/conop/compound.hh> #include <ost/conop/compound_lib.hh> - +using namespace ost::mol; using namespace ost::conop; +namespace { + +Compound::Dialect tr_dialect(const String& dialect) +{ + if (dialect=="PDB") { + return Compound::PDB; + } + if (dialect=="CHARMM") { + return Compound::CHARMM; + } + if (dialect=="OPLS") { + return Compound::OPLS; + } + if (dialect=="AMBER") { + return Compound::AMBER; + } + std::stringstream ss; + ss << "unknown compound dialect '" << dialect << "'"; + throw std::runtime_error(ss.str()); +} + +void set_dialect(CompoundPtr compound, const String& dialect) +{ + compound->SetDialect(tr_dialect(dialect)); +} + +char get_chemclass(CompoundPtr compound) +{ + return char(compound->GetChemClass()); +} + +void set_chemclass(CompoundPtr compound, char cc) +{ + compound->SetChemClass(ChemClass(cc)); +} + +CompoundPtr find_compound(CompoundLibPtr comp_lib, + const String& tlc, const String& dialect) +{ + return comp_lib->FindCompound(tlc, tr_dialect(dialect)); +} + +} void export_Compound() { - class_<Compound>("Compound", no_init) + + class_<Compound, CompoundPtr>("Compound", no_init) .def("GetID", &Compound::GetID, return_value_policy<copy_const_reference>()) .def("SetOneLetterCode", &Compound::SetOneLetterCode) .def("GetOneLetterCode", &Compound::GetOneLetterCode) + + .add_property("three_letter_code", make_function(&Compound::GetID, return_value_policy<copy_const_reference>())) + .add_property("id", make_function(&Compound::GetID, return_value_policy<copy_const_reference>())) .add_property("one_letter_code", &Compound::GetOneLetterCode, - &Compound::SetOneLetterCode) + &Compound::SetOneLetterCode) .def("GetAtomSpecs", &Compound::GetAtomSpecs, return_value_policy<copy_const_reference>()) + .def("bond_specs", make_function(&Compound::GetBondSpecs, + return_value_policy<copy_const_reference>())) + .def("atom_specs", make_function(&Compound::GetAtomSpecs, + return_value_policy<copy_const_reference>())) + .def("AddAtom", &Compound::AddAtom) + .def("AddBond", &Compound::AddBond) + .def("IsPeptideLinking", &Compound::IsPeptideLinking) + .add_property("chem_class", &get_chemclass, + &set_chemclass) + .add_property("formula",make_function(&Compound::GetFormula, + return_value_policy<copy_const_reference>()), + &Compound::SetFormula) + .add_property("dialect", &Compound::GetDialectAsString, + &set_dialect) ; class_<AtomSpec>("AtomSpec", no_init) .def_readonly("element", &AtomSpec::element) - .def_readonly("name", &AtomSpec::name) + .def_readonly("name", &AtomSpec::name) .def_readonly("alt_name", &AtomSpec::alt_name) - .def_readonly("is_leaving", &AtomSpec::is_leaving) + .def_readonly("is_leaving", &AtomSpec::is_leaving) + .def_readonly("is_aromatic", &AtomSpec::is_aromatic) + .def_readonly("ordinal", &AtomSpec::ordinal) ; class_<BondSpec>("BondSpec", no_init) .def_readonly("atom_one", &BondSpec::atom_one) .def_readonly("atom_two", &BondSpec::atom_two) + .def_readonly("border", &BondSpec::order) + ; - register_ptr_to_python<CompoundPtr>(); - + class_<CompoundLib>("CompoundLib", no_init) .def("Load", &CompoundLib::Load, arg("readonly")=true).staticmethod("Load") - .def("FindCompound", &CompoundLib::FindCompound) + .def("FindCompound", &find_compound, + (arg("tlc"), arg("dialect")="PDB")) .def("ClearCache", &CompoundLib::ClearCache) ; diff --git a/modules/conop/src/compound_lib.cc b/modules/conop/src/compound_lib.cc index fd5b76631fa391b57d8291f35e2a81497193a068..ae66e66064d7193e95f2d9c0492bd27d39144216 100644 --- a/modules/conop/src/compound_lib.cc +++ b/modules/conop/src/compound_lib.cc @@ -156,10 +156,10 @@ void CompoundLib::AddCompound(const CompoundPtr& compound) sqlite3_bind_int(stmt, 5, a.is_aromatic); sqlite3_bind_int(stmt, 6, 0); sqlite3_bind_int(stmt, 7, a.is_leaving); - sqlite3_bind_int(stmt, 8, i-al.begin()); + sqlite3_bind_int(stmt, 8, a.ordinal); retval=sqlite3_step(stmt); assert(retval==SQLITE_DONE); - atom_ids[i-al.begin()]=sqlite3_last_insert_rowid(conn_); + atom_ids[a.ordinal]=sqlite3_last_insert_rowid(conn_); } else { LOG_ERROR(sqlite3_errmsg(conn_)); } diff --git a/modules/doc/contributing.rst b/modules/doc/contributing.rst index a698032336c1157391ed64abbe726d4959bbbcc8..a614f81b97387ebeb43e158ccc19ef5725e6f0db 100644 --- a/modules/doc/contributing.rst +++ b/modules/doc/contributing.rst @@ -42,24 +42,33 @@ From now on, all your work will be carried out in my_branch. Make your changes a Writing Good Commit Messages ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Your commit message should have a one-line description that summarize the change and optionally a more detailed description of what the changes imply. An example from the commit history. The one-liner and the detailed description are separated by an empty line. The reason for this format is that the one-line description will be used as the subject line for the patches generated by format-patch and the ones sent to the commit mailing lists. People can quickly see if the change is of interest to that they can savely ignore the e-mail. +Your commit message should have a one-line description that summarize the change and optionally a more detailed description of what the changes imply. An example from the commit history. + +:: + + improve warning when using generic property of string type in query + + Fixes BZDNG-204 + + +The one-liner and the detailed description are separated by an empty line. The reason for this format is that the one-line description will be used as the subject line for the patches generated by format-patch and the ones sent to the commit mailing lists. People can quickly see if the change is of interest to that they can savely ignore the e-mail. Additionally, they also come in handy when using the --online option of ``git log``. Writing Documentation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -OpenStructure uses `sphinx <http://sphinx.pocoo.org>`_ as the documentation generator. The main part of the documentation each module resides in files with the ``.rst`` extension in a sub-folder called doc. +OpenStructure uses `sphinx <http://sphinx.pocoo.org>`_ as the documentation generator. The main part of the documentation of each module resides in files with the ``.rst`` extension (a markup language called `reStructuredText <http://docutils.sourceforge.net/docs/user/rst/quickref.html#literal-blocks>`_) in a sub-folder called doc. -To convert the .rst files to html use the doc/make.py script: +From the toplevel directory of the git repository convert the .rst files to html by using the doc/make.py script : .. code-block:: bash ost doc/make.py -The script first recursively searches for modified ``.rst`` files, starting at the modules directory and copies the files that have changed to ``doc/source``. It also copies images to the source directory. Then it runs sphinx to convert the documentation to html. If no further options are given to the script, the html documentation is generated. The HTML, CSS and static media files will be put into ``doc/html/build``. +The script first recursively searches for modified ``.rst`` files, starting at the modules directory and copies the files that have changed to ``doc/source``. It also copies images to the source directory. Then it runs sphinx to convert the documentation to html. If no further options are given to the script, the html documentation is generated. The HTML, CSS and static media files will be put into ``doc/build/html``. -For classes and functions written in Python, it is possible to tell sphinx to extract the documentation directly from the doc-string. For example, to get the documentation for :func:`~ost.io.LoadPDB`, you can use: +For classes and functions written in Python, it is possible to tell sphinx to extract the documentation directly from the doc-string. For example, to get the documentation for :func:`~ost.io.LoadPDB`, you can use: .. code-block:: rest @@ -99,4 +108,4 @@ If you got a patch from someone else and would like to use apply it to your repo .. code-block:: bash - git am < changeset.diff \ No newline at end of file + git am < changeset.diff diff --git a/modules/doc/install.rst b/modules/doc/install.rst index 525561543c3cb201d7ff8ed417a7fd86041a3fa0..76191a96c62dede580d7eaecae88816645872d1d 100644 --- a/modules/doc/install.rst +++ b/modules/doc/install.rst @@ -70,6 +70,26 @@ OpenStructure uses `git` as the revision control system. The main repository can The above command will clone OpenStructre into the directory called `directory-name`. If omitted, the directory will be called ost. Alternatively, you might consider getting one of the nightly source code snapshots from the `downloads section <http://www.openstructure.org/downloads/>`_. +.. note:: + + Some version of curl have have trouble with the certificate of the + OpenStructure git server and fail to clone the repository. To work around + this, disable the SSL certificate verification with the following command: + + .. code-block:: bash + + git config --global http.sslVerify false + + +Picking the right branch +-------------------------------------------------------------------------------- + +By default you are checking out the master branch. Master is, by definition a stable branch. It always points to the latest release. However, there are several other branches at your disposal. The main development is happening in the develop branch. It contains the newest features and bug fixes. However, we dont't make any guarantees that the develop branch is bug free and doesn't contain major bugs. After all, it's in constant flux. If you are developing new features, start your feature branch off develop. Besides that, there are several smaller features branches that are used to group together commits for one specific features. To change to a specific branch, use + +.. code-block:: bash + + git checkout <branch-name> + Configuring -------------------------------------------------------------------------------- @@ -162,7 +182,6 @@ run multiple jobs at once. On Windows run 'Build OpenStructure' from the build menu. - What's next? -------------------------------------------------------------------------------- @@ -179,3 +198,14 @@ or, to start the command-line interpreter: stage/bin/ost If you repeatedly use OpenStructure, it is recommended to add /path/to/dng/stage/bin to your path. + +Getting the newest changes +-------------------------------------------------------------------------------- + +To get the newest changes from the central git repository, enter + +.. code-block:: bash + + git pull + +in your terminal. This will fetch the newest changes. diff --git a/modules/gfx/pymod/export_entity.cc b/modules/gfx/pymod/export_entity.cc index 78dd67f09d990983f4ccffffdf7ba37eb3758617..c17fe7b3dcde4a9efb9cc58d6f1e47dbdad72160 100644 --- a/modules/gfx/pymod/export_entity.cc +++ b/modules/gfx/pymod/export_entity.cc @@ -241,6 +241,11 @@ RenderOptionsPtr ent_ltrace_opts(Entity* ent) void set_selection(Entity* ent, object sel) { + object none; + if (sel==none) { + ent->SetSelection(ent->GetView().CreateEmptyView()); + return; + } try { String sel_string=extract<String>(sel); ent->SetSelection(ent->GetView().Select(sel_string)); diff --git a/modules/gfx/src/impl/backbone_trace.cc b/modules/gfx/src/impl/backbone_trace.cc index b890d76b4763cb48a63e4895d4f55b266d1c31b8..a872c44c3e932ad368c990e15708ff93d23b835b 100644 --- a/modules/gfx/src/impl/backbone_trace.cc +++ b/modules/gfx/src/impl/backbone_trace.cc @@ -32,14 +32,18 @@ namespace { bool in_sequence(const mol::ResidueHandle& r1, const mol::ResidueHandle& r2, bool seqhack) { if(!r1.IsValid() || !r2.IsValid()) return false; - if(r1.GetChain()!=r2.GetChain()) return false; - mol::ResNum n1 = r1.GetNumber(); - mol::ResNum n2 = r2.GetNumber(); - if(n2.GetInsCode()!='\0') { - if(n1.NextInsertionCode()==n2) return true; + if(seqhack) { + if(r1.GetChain()!=r2.GetChain()) return false; + mol::ResNum n1 = r1.GetNumber(); + mol::ResNum n2 = r2.GetNumber(); + if(n2.GetInsCode()!='\0') { + if(n1.NextInsertionCode()==n2) return true; + } + if(mol::InSequence(r1,r2)) return true; + if(n1.GetNum()+1==n2.GetNum()) return true; + } else { + return mol::InSequence(r1,r2); } - if(mol::InSequence(r1,r2)) return true; - if(seqhack && n1.GetNum()+1==n2.GetNum()) return true; return false; } @@ -236,11 +240,21 @@ BackboneTrace BackboneTrace::CreateSubset(const mol::EntityView& subview) const NodeEntryList& nlist=*nitnit; for(NodeEntryList::const_iterator nit=nlist.begin();nit!=nlist.end();++nit) { if(subview.FindAtom(nit->atom).IsValid()) { + if(!new_nlist.empty()) { + if(!in_sequence(new_nlist.back().atom.GetResidue(),nit->atom.GetResidue(),seq_hack_)) { + if(new_nlist.size()>1) { + nrvo.node_list_list_.push_back(new_nlist); + } + new_nlist.clear(); + } + } new_nlist.push_back(*nit); } } if(!new_nlist.empty()) { - nrvo.node_list_list_.push_back(new_nlist); + if(new_nlist.size()>1) { + nrvo.node_list_list_.push_back(new_nlist); + } } } return nrvo; diff --git a/modules/gfx/src/impl/cartoon_renderer.cc b/modules/gfx/src/impl/cartoon_renderer.cc index d9b4577ddbb2e24b8367bc8d15d291ead0b29dcd..e2f6071f5baa78ee4337b09eeb5ec4e045c03b0a 100644 --- a/modules/gfx/src/impl/cartoon_renderer.cc +++ b/modules/gfx/src/impl/cartoon_renderer.cc @@ -51,6 +51,27 @@ void CartoonRenderer::SetForceTube(bool force_tube) force_tube_ = force_tube; } +geom::AlignedCuboid CartoonRenderer::GetBoundingBox() const +{ + geom::Vec3 mmin(std::numeric_limits<float>::max(), + std::numeric_limits<float>::max(), + std::numeric_limits<float>::max()); + geom::Vec3 mmax(-std::numeric_limits<float>::max(), + -std::numeric_limits<float>::max(), + -std::numeric_limits<float>::max()); + + assert(!(state_ & DIRTY_VIEW)); + for(unsigned int llc=0;llc<spline_list_list_.size();++llc) { + SplineEntryList slist = spline_list_list_[llc]; + for(unsigned int lc=0;lc<slist.size();++lc) { + mmin=geom::Min(mmin, slist[lc].position); + mmax=geom::Max(mmax, slist[lc].position); + } + } + + return geom::AlignedCuboid(mmin, mmax); +} + void CartoonRenderer::PrepareRendering() { TraceRendererBase::PrepareRendering(); @@ -302,8 +323,11 @@ void CartoonRenderer::rebuild_spline_obj(IndexedVertexArray& va, options_->GetStrandThickness()+factor, options_->GetStrandProfileType(), options_->GetStrandEcc())); // profile 2 = strand - profiles.push_back(profiles.back()); // profile 3==2, strand - + TraceProfile prof=profiles.back(); +// do not ever change this back to profiles.push_back(profiles.back()); it segfaults on windows +// or you will meet two new friends of yours :) +// looks like a compiler bug + profiles.push_back(prof); // profile 3==2, strand profiles.push_back(get_circ_profile(detail, 1.7*options_->GetStrandWidth()+factor, 1.1*options_->GetStrandThickness()+factor, diff --git a/modules/gfx/src/impl/cartoon_renderer.hh b/modules/gfx/src/impl/cartoon_renderer.hh index 59be06b598c0f89723baf5fde722200f56c344f8..1d60eec76b775923e6b51ddc98ca8f815add45e0 100644 --- a/modules/gfx/src/impl/cartoon_renderer.hh +++ b/modules/gfx/src/impl/cartoon_renderer.hh @@ -41,6 +41,8 @@ class DLLEXPORT_OST_GFX CartoonRenderer: public TraceRendererBase { public: CartoonRenderer(BackboneTrace* trace, bool force_tube=false); + virtual geom::AlignedCuboid GetBoundingBox() const; + virtual void PrepareRendering(); virtual bool CanSetOptions(RenderOptionsPtr& render_options); diff --git a/modules/gui/pymod/scene/presets.xml b/modules/gui/pymod/scene/presets.xml index 4659e4e26f3ee17c6555e0edc5e4938f9943161c..fb92d6da8908c257b0ba58727cc8af0253da06a1 100644 --- a/modules/gui/pymod/scene/presets.xml +++ b/modules/gui/pymod/scene/presets.xml @@ -35,7 +35,7 @@ <Op ClassName="UniformColorOp" Index="5"> <ColorOp>3 0 ishetatm=1 and ele=C</ColorOp>0 1 0 1</Op> </Preset> - <Preset Name="Property"> + <Preset Name="Residue Type"> <Op ClassName="UniformColorOp" Index="0"> <ColorOp>3 0 rname=GLY,ALA,VAL,LEU,ILE</ColorOp>0.658824 0.658824 0.658824 1</Op> <Op ClassName="UniformColorOp" Index="1"> diff --git a/modules/gui/src/python_shell/python_shell_widget.cc b/modules/gui/src/python_shell/python_shell_widget.cc index f94f909c821dd60c7a321b25abdd9ac9fad8777b..ef3e9709067f206ba21a79f4f9c327033094343c 100644 --- a/modules/gui/src/python_shell/python_shell_widget.cc +++ b/modules/gui/src/python_shell/python_shell_widget.cc @@ -474,6 +474,7 @@ void PythonShellWidget::OnExecuteStateEntered() set_block_type_(block_edit_start_,textCursor().block(),BLOCKTYPE_CODE); insertPlainText(QString(QChar::ParagraphSeparator)); QString command=GetCommand(); + QString command_trimmed=command.trimmed(); if (command_trimmed.size()>0) { unsigned int id=PythonInterpreter::Instance().RunCommand(command); @@ -482,7 +483,6 @@ void PythonShellWidget::OnExecuteStateEntered() insertPlainText(QString(QChar::ParagraphSeparator)); } block_edit_start_=textCursor().block(); - } @@ -737,6 +737,34 @@ QTextBlock PythonShellWidget::GetEditStartBlock() void PythonShellWidget::keyPressEvent(QKeyEvent* event) { + // BZDNG-238 + // Letting Qt do the handling of the backspace key leads to a crash when + // editing a multiline block mode and doing the following: + // + // (a) Hit Ctrl+A + // (b) Hit Backspace|Delete + // (c) Hit Return + // + // If we emulate the deletion of the text manually all is fine. + if (event->key()==Qt::Key_Backspace || event->key()==Qt::Key_Delete) { + QTextCursor cursor=this->textCursor(); + if (cursor.hasSelection()) { + cursor.removeSelectedText(); + } else { + if (cursor.position()>this->GetEditStartBlock().position()) { + if (event->key()==Qt::Key_Backspace) { + cursor.deletePreviousChar(); + } else { + cursor.deleteChar(); + } + } + } + QTextCursor tc=this->textCursor(); + tc.setPosition(block_edit_start_.position()); + block_edit_start_=tc.block(); + event->accept(); + return; + } // BZDNG-173 if (event->key()==Qt::Key_Left) { if (this->textCursor().position()==GetEditStartBlock().position() || @@ -746,9 +774,11 @@ void PythonShellWidget::keyPressEvent(QKeyEvent* event) } } if (this->handle_custom_commands_(event)){ + event->accept(); return; } if (this->handle_completion_(event)){ + event->accept(); return; } QPlainTextEdit::keyPressEvent(event); diff --git a/modules/io/src/mol/entity_io_crd_handler.cc b/modules/io/src/mol/entity_io_crd_handler.cc index bee473f9dd1f7b573c067cb0e4c92f07c9e34a80..8b0ceb837058b498a5cd21d7529f9590f7279aa8 100644 --- a/modules/io/src/mol/entity_io_crd_handler.cc +++ b/modules/io/src/mol/entity_io_crd_handler.cc @@ -223,7 +223,11 @@ CRDWriter::CRDWriter(std::ostream& ostream) : {} CRDWriter::CRDWriter(const boost::filesystem::path& filename) : +#if BOOST_FILESYSTEM_VERSION==3 + outfile_(filename.string().c_str()), outstream_(outfile_), +#else outfile_(filename.file_string().c_str()), outstream_(outfile_), +#endif atom_count_(0) {} diff --git a/modules/io/src/mol/pdb_writer.cc b/modules/io/src/mol/pdb_writer.cc index 6f180688d94603f5096aff7a1e046f2c32633658..3fe570a5c8afc87782cadd58bfdb29d2070f02a3 100644 --- a/modules/io/src/mol/pdb_writer.cc +++ b/modules/io/src/mol/pdb_writer.cc @@ -329,7 +329,11 @@ PDBWriter::PDBWriter(std::ostream& stream, const IOProfile& profile): PDBWriter::PDBWriter(const boost::filesystem::path& filename, const IOProfile& profile): +#if BOOST_FILESYSTEM_VERSION==3 + outfile_(filename.string().c_str()), outstream_(outfile_), +#else outfile_(filename.file_string().c_str()), outstream_(outfile_), +#endif mol_count_(0), line_(80), multi_model_(false), charmm_style_(profile.dialect=="CHARMM"), is_pqr_(false), profile_(profile) diff --git a/modules/io/src/mol/sdf_writer.cc b/modules/io/src/mol/sdf_writer.cc index 01b1381b070dc16255cf04975e9605cc9fb68425..70d61f636fe9b97487b02069f1754f9f6b3279c9 100644 --- a/modules/io/src/mol/sdf_writer.cc +++ b/modules/io/src/mol/sdf_writer.cc @@ -95,16 +95,27 @@ SDFWriter::SDFWriter(const String& filename) : outfile_(filename.c_str()), ostr_(outfile_), counter_(0) { } -SDFWriter::SDFWriter(const boost::filesystem::path& filename) - : outfile_(filename.file_string().c_str()), ostr_(outfile_), counter_(0) { +SDFWriter::SDFWriter(const boost::filesystem::path& filename): +#if BOOST_FILESYSTEM_VERSION==3 + outfile_(filename.string().c_str()), +#else + outfile_(filename.file_string().c_str()), +#endif + ostr_(outfile_), counter_(0) { } void SDFWriter::Write(const mol::EntityView& ent) { + if (!ostr_) { + throw IOException("Can't write SDF file. Bad output stream"); + } mol::EntityView non_const_view = ent; non_const_view.Apply(*this); } void SDFWriter::Write(const mol::EntityHandle& ent) { + if (!ostr_) { + throw IOException("Can't write SDF file. Bad output stream"); + } mol::EntityView non_const_view = ent.CreateFullView(); non_const_view.Apply(*this); } diff --git a/modules/io/tests/test_io_sdf.cc b/modules/io/tests/test_io_sdf.cc index 60861a9abb909906e4bdb8b5f444f81fa9b84f48..bd62e05280eff093f51133ad7f26a9fa8cdc602a 100644 --- a/modules/io/tests/test_io_sdf.cc +++ b/modules/io/tests/test_io_sdf.cc @@ -147,8 +147,8 @@ BOOST_AUTO_TEST_CASE(write_sdf) sdfh.Import(eh,"testfiles/sdf/compound.sdf"); SaveEntity(eh, "testfiles/sdf/compound-out.sdf"); } - BOOST_CHECK(compare_files("testfiles/sdf/compound.sdf", - "testfiles/sdf/compound-out.sdf")); + BOOST_CHECK(compare_files("testfiles/sdf/compound-out.sdf", + "testfiles/sdf/compound.sdf")); } BOOST_AUTO_TEST_CASE(write_sdf_view) @@ -162,8 +162,8 @@ BOOST_AUTO_TEST_CASE(write_sdf_view) mol::EntityView ev = eh.Select("(ele=C or ele=N) and aname!='1'"); SaveEntity(ev, "testfiles/sdf/compound-view-out.sdf"); } - BOOST_CHECK(compare_files("testfiles/sdf/compound-view.sdf", - "testfiles/sdf/compound-view-out.sdf")); + BOOST_CHECK(compare_files("testfiles/sdf/compound-view-out.sdf", + "testfiles/sdf/compound-view.sdf")); } BOOST_AUTO_TEST_CASE(nonexisting_file) diff --git a/modules/mol/base/doc/editors.rst b/modules/mol/base/doc/editors.rst index ca9856360f16c1261181695da9e2af5ddc51d7c1..c4241b8cad54deaa1ef7701601aa2e50f752d0b7 100644 --- a/modules/mol/base/doc/editors.rst +++ b/modules/mol/base/doc/editors.rst @@ -3,9 +3,10 @@ Editors .. currentmodule:: ost.mol -The structure, topology and connectivity of entities is edited via editors. This -includes operations such as changing atom positions, connecting atoms with bonds -as well as adding and removing chains, residues and atoms. +The structure, topology and connectivity of :class:`entities <EntityHandle>` is +edited via editors. This includes operations such as changing atom positions, +connecting atoms with bonds as well as adding and removing chains, residues and +atoms. There are two flavors of editors, one for the internal coordinate system (:class:`ICSEditor`) and one for the external coordinate system (:class:`XCSEditor`). Edit Modes -------------------------------------------------------------------------------- @@ -112,8 +113,8 @@ euclidian space. .. method:: ApplyTransform(transform) - Apply a transformation the entity transform. The entity transform is a - global transformation applied to all atoms. + Apply a transformation to the entity. The transformation is applied to all + atoms positions. :param transform: The transformation to be applied :type transform: :class:`geom.Mat4` @@ -149,17 +150,88 @@ euclidian space. Editor for the Internal Coordinate System -------------------------------------------------------------------------------- + The :class:`ICSEditor` is used to manipulate the internal coordinate system that -is defined by bond lengths and angles. By default the internal coordinate system -is not calculates. However, upon requesting an :class:`ICSEditor` for the first -time, the internal coordinate system is initialized. This involves the build-up -of a directed-graph for the bond network as well as calculating the internal -coordinate matrices. +is defined by bond lengths and angles. You can create an editor with the +:class:`~EntityHandle.EditICS` method of the :class:`EntityHandle`. The use :class:`XCSEditor` and :class:`ICSEditor` are mutually exclusive. This means that whenever a :class:`XCSEditor` has pending changes, the results of using an :class:`ICSEditor` is undefined and vice versa. +.. note:: + + For speed reasons, the internal coordinate system is not initialised until the + first call to :meth:`EntityHandle.EditICS`. This involves the build-up of a + directed-graph for the bond network as well as calculating the internal + coordinate matrices. + .. class:: ICSEditor - Inherits :class:`EditorBase` + Inherits :class:`EditorBase` + + .. method:: SetTorsionAngle(torsion, angle) + + Set the angle of the given torsion. If the edit mode of the editor is set + to buffered, the external coordinates remain unchanged. If set to + unbuffered, the external coordinates are immediately recalculated. + + :see: :meth:`UpdateICS` + + :param torsion: A valid torsion + + :type torsion: :class:`TorsionHandle` + + :param angle: The angle in radians + + :type angle: :class:`float` + + :raises: :exc:`RuntimeError` when the torsion handle is invalid + + .. method:: UpdateXCS() + + Apply all remaining changes to the internal coordinate system and + recalculate external coordinates. In unbuffered edit mode, calling this + method has no effect. + + + .. method:: SetBondLength(bond, length) + + Sets the length of a bond. If the edit mode of the editor is set + to buffered, the external coordinates remain unchanged. If set to + unbuffered, the external coordinates are immediately recalculated. + + :see: :meth:`UpdateICS` + + :param bond: A valid bond handle + + :type bond: :class:`BondHandle` + + :param length: The bond length in Angstroem. + + :type length: :class:`float` + + :raises: :exc:`RuntimeError` when the bond handle is invalid + + .. method:: SetAngle(atom1, atom2, atom3, angle) + + Sets the angle between 3 atoms. The first atom must be connected to the + second, the second to the third with a bond. If the edit mode of the editor + is set to buffered, the external coordinates remain unchanged. If set to + unbuffered, the external coordinates are immediately recalculated. + + :see: :meth:`UpdateICS` + + :param atom1: The first atom. Must be valid + :type atom1: :class:`AtomHandle` + + :param atom2: The second atom. Must be valid + :type atom2: :class:`AtomHandle` + + :param atom3: The third atom. Must be valid + :type atom3: :class:`AtomHandle` + + :param angle: The angle in radians + + :raises: :exc:`RuntimeError` when one of the atoms is invalid or there is no + bond between atom1 and atom2 or atom2 and atom3. \ No newline at end of file diff --git a/modules/mol/base/doc/entity.rst b/modules/mol/base/doc/entity.rst index 79df5fcf21f9bf6e9daf647b9177204124dc73cc..34edb07aa1b24c7d2b1dfccd72f137db926dee1e 100644 --- a/modules/mol/base/doc/entity.rst +++ b/modules/mol/base/doc/entity.rst @@ -620,9 +620,11 @@ The Handle Classes :type: :class:`ResidueHandle` - .. attribute:: is_hetatm + .. attribute:: is_hetatom - Indicates whether this atom is a hetatm. + Indicates whether this atom is a *HETATM*. When loading a structure from a + PDB file, all non-standard aminoacid and nucleotide atoms as well as ligands + are marked as HETATM. .. attribute:: bonds @@ -740,7 +742,7 @@ The Handle Classes .. method:: IsHetAtom() - See :attr:`is_hetatm` + See :attr:`is_hetatom` :rtype: bool diff --git a/modules/mol/base/pymod/export_atom.cc b/modules/mol/base/pymod/export_atom.cc index 5891f4c10d8bdb34bfc7303a392049cf543e09dc..48695455dd9a816476e543ffdb89d24f26c4b51d 100644 --- a/modules/mol/base/pymod/export_atom.cc +++ b/modules/mol/base/pymod/export_atom.cc @@ -50,7 +50,6 @@ void export_Atom() return_value_policy<copy_const_reference>()), &AtomBase::SetName) .add_property("index", &AtomBase::GetIndex) - .def("GetRadius", &AtomBase::GetRadius) .def("GetElement", &AtomBase::GetElement, return_value_policy<copy_const_reference>()) @@ -85,6 +84,7 @@ void export_Atom() .def("GetBondList", &AtomHandle::GetBondList) .def("GetBondCount", &AtomHandle::GetBondCount) .def("GetEntity", &AtomHandle::GetEntity) + .add_property("bonds", &AtomHandle::GetBondList) .def("GetHandle", &AtomHandle::GetHandle) .add_property("handle", &AtomHandle::GetHandle) .add_property("entity", &AtomHandle::GetEntity) diff --git a/modules/mol/base/pymod/export_bond.cc b/modules/mol/base/pymod/export_bond.cc index 7309ef939edb58d4609df9618d58c504ee5f7664..b5da041244cd0ec9dfc204f9c173d309adc90565 100644 --- a/modules/mol/base/pymod/export_bond.cc +++ b/modules/mol/base/pymod/export_bond.cc @@ -26,7 +26,9 @@ using namespace boost::python; using namespace ost; using namespace ost::mol; + #include <ost/export_helper/generic_property_def.hh> +#include <ost/export_helper/vector.hh> void export_Bond() { @@ -38,8 +40,6 @@ void export_Bond() make_function(&BondHandle::GetFirst)) .add_property("second", make_function(&BondHandle::GetSecond)) - .add_property("other", - make_function(&BondHandle::GetOther)) .add_property("length", &BondHandle::GetLength) .add_property("bond_order", @@ -59,6 +59,7 @@ void export_Bond() generic_prop_def<BondHandle>(bond_handle); class_<BondHandleList>("BondHandleList", no_init) .def(vector_indexing_suite<BondHandleList>()) + .def(ost::VectorAdditions<BondHandleList>()) ; def("BondExists", &BondExists); } diff --git a/modules/mol/base/pymod/export_entity.cc b/modules/mol/base/pymod/export_entity.cc index 34a8adcf80163945bd1ab6cd4e29145c3fbb1b3b..163918c75642b0e1da67336dcad2619e30c84da8 100644 --- a/modules/mol/base/pymod/export_entity.cc +++ b/modules/mol/base/pymod/export_entity.cc @@ -81,8 +81,8 @@ void export_Entity() generic_prop_def<EntityBase>(ent_base); class_<EntityHandle, bases<EntityBase> >("EntityHandle", init<>()) - .def("Select",select_query, arg("flags")=0) - .def("Select",select_string, arg("flags")=0) + .def("Select",select_query, (arg("query"), arg("flags")=0)) + .def("Select",select_string, (arg("query"), arg("flags")=0)) .def("FindChain", &EntityHandle::FindChain) .def("FindResidue", &EntityHandle::FindResidue) .def("FindAtom", &EntityHandle::FindAtom) diff --git a/modules/mol/base/src/impl/chain_impl.cc b/modules/mol/base/src/impl/chain_impl.cc index 456255c3c7217bd495845d7e6c6df9e89a324f30..8388c00ea28a4f244ac28389c564d155bf596cc8 100644 --- a/modules/mol/base/src/impl/chain_impl.cc +++ b/modules/mol/base/src/impl/chain_impl.cc @@ -154,7 +154,7 @@ void ChainImpl::DeleteAllResidues() { } void ChainImpl::DeleteResidue(const ResNum& number) { - int index=this->GetIndex(number); + int index=this->GetIndexForResNum(number); if (index>=0) { ResidueImplPtr r=residue_list_[index]; r->DeleteAllAtoms(); @@ -166,7 +166,13 @@ void ChainImpl::DeleteResidue(const ResNum& number) { void ChainImpl::DeleteResidue(const ResidueImplPtr& residue) { if (residue->GetChain().get()!=this) return; - this->DeleteResidue(residue->GetNumber()); + int index=this->GetIndex(residue); + if (index>=0) { + ResidueImplPtr r=residue_list_[index]; + r->DeleteAllAtoms(); + residue_list_.erase(residue_list_.begin()+index); + this->UpdateShifts(); + } } ResidueImplPtr ChainImpl::AppendResidue(const ResidueKey& key, @@ -220,7 +226,7 @@ ResidueImplPtr ChainImpl::GetPrev(const ResidueImplPtr& r) const { if (!r) return ResidueImplPtr(); - int index=this->GetIndex(r->GetNumber())-1; + int index=this->GetIndex(r)-1; if (index>-1 && index<static_cast<int>(residue_list_.size())-1) { return residue_list_[index]; } @@ -256,7 +262,7 @@ ResidueImplPtr ChainImpl::GetNext(const ResidueImplPtr& r) const { if (!r) return ResidueImplPtr(); - int index=this->GetIndex(r->GetNumber())+1; + int index=this->GetIndex(r)+1; if (index>0 && index<=static_cast<int>(residue_list_.size())-1) { return residue_list_[index]; } @@ -282,7 +288,7 @@ void ChainImpl::Apply(EntityVisitor& v) ResidueImplPtr ChainImpl::FindResidue(const ResNum& number) const { - int index=this->GetIndex(number); + int index=this->GetIndexForResNum(number); bool invalid=index<0 || index>static_cast<int>(residue_list_.size())-1; return invalid ? ResidueImplPtr() : residue_list_[index]; } @@ -301,36 +307,63 @@ EntityImplPtr ChainImpl::GetEntity() const { return ent_.lock(); } - -int ChainImpl::GetIndex(const ResNum& number) const +int ChainImpl::GetIndexForResNum(const ResNum& number) const { - if (in_sequence_) { - int pos=number.GetNum()-1; - std::list<Shift>::const_iterator i; - for (i=shifts_.begin(); i!=shifts_.end(); ++i) { - const Shift& s=*i; - if (pos<s.start) { - break; - } else if (pos<s.start+s.shift) { - return -1; - } - pos-=s.shift; - } - while (pos>=0 && pos<static_cast<int>(residue_list_.size()) && - residue_list_[pos]->GetNumber()<number) { - pos++; - } - if (pos<0 || pos>=static_cast<int>(residue_list_.size())) { - return -1; - } - assert(residue_list_[pos]->GetNumber()==number); - return pos; + return this->GetIndexForResNumInSequence(number); } else { - ResidueImplList::const_iterator k; + ResidueImplList::const_iterator k; k=std::find_if(residue_list_.begin(), residue_list_.end(), bind(&ResidueImpl::GetNumber, _1)==number); + + if (k==residue_list_.end()) + return -1; + int pos=std::distance(residue_list_.begin(), k); + assert(residue_list_[pos]->GetNumber()==number); + return pos; + } +} + +int ChainImpl::GetIndexForResNumInSequence(const ResNum& number) const +{ + int pos=number.GetNum()-1; + std::list<Shift>::const_iterator i; + for (i=shifts_.begin(); i!=shifts_.end(); ++i) { + const Shift& s=*i; + if (pos<s.start) { + break; + } else if (pos<s.start+s.shift) { + return -1; + } + pos-=s.shift; + } + while (pos>=0 && pos<static_cast<int>(residue_list_.size()) && + residue_list_[pos]->GetNumber()<number) { + pos++; + } + if (pos<0 || pos>=static_cast<int>(residue_list_.size())) { + return -1; + } + assert(residue_list_[pos]->GetNumber()==number); + return pos; +} + +int ChainImpl::GetIndex(const ResidueImplPtr& res) const +{ + if (!res) { + return -1; + } + ResNum number=res->GetNumber(); + if (in_sequence_) { + return this->GetIndexForResNumInSequence(number); + } else { + ResidueImplList::const_iterator k=residue_list_.begin()-1; + do { + k=std::find_if(k+1, residue_list_.end(), + bind(&ResidueImpl::GetNumber, _1)==number); + } while(k!=residue_list_.end() && (*k)!=res); + if (k==residue_list_.end()) return -1; int pos=std::distance(residue_list_.begin(), k); @@ -343,7 +376,7 @@ void ChainImpl::AssignSecondaryStructure(SecStructure ss, const ResNum& start, const ResNum& end) { - int start_index=this->GetIndex(start); + int start_index=this->GetIndexForResNum(start); int i=start_index; bool found_end=false; if (i>=0) { diff --git a/modules/mol/base/src/impl/chain_impl.hh b/modules/mol/base/src/impl/chain_impl.hh index cf7c1b8389564675ac776a5d1493cd28d4c90b13..d7d2ca64beeb0f464263c8ddedd9f3da8be5a2ae 100644 --- a/modules/mol/base/src/impl/chain_impl.hh +++ b/modules/mol/base/src/impl/chain_impl.hh @@ -91,7 +91,7 @@ public: ResidueImplPtr FindResidue(const ResNum& number) const; AtomImplPtr FindAtom(const ResNum& number, - const String& atom_name) const; + const String& atom_name) const; //! Get number of residues of this chain int GetResidueCount() const; @@ -114,12 +114,14 @@ public: void ReorderResidues(); - int GetIndex(const ResNum& number) const; + int GetIndex(const ResidueImplPtr& res) const; + void AssignSecondaryStructure(SecStructure ss, + const ResNum& start, + const ResNum& end); + int GetIndexForResNum(const ResNum& number) const; - void AssignSecondaryStructure(SecStructure ss, - const ResNum& start, - const ResNum& end); private: + int GetIndexForResNumInSequence(const ResNum& number) const; void UpdateShifts(); typedef struct { int start; diff --git a/modules/mol/base/src/impl/entity_impl.cc b/modules/mol/base/src/impl/entity_impl.cc index eb85cef7925ccc283ba17aee993bb2bdd0ecb496..4e311ddc0ad5b0bc01d165d6778865f27dcf09cf 100644 --- a/modules/mol/base/src/impl/entity_impl.cc +++ b/modules/mol/base/src/impl/entity_impl.cc @@ -770,7 +770,7 @@ void EntityImpl::SetTransform(const geom::Mat4 transfmat) identity_transf_ = false; } this->UpdateTransformedPos(); - this->MarkXCSDirty(); + this->MarkOrganizerDirty(); } void EntityImpl::AttachObserver(const EntityObserverPtr& o) @@ -1049,6 +1049,7 @@ void EntityImpl::UpdateOrganizer() e=atom_map_.end(); i!=e; ++i) { atom_organizer_.Add(i->second, i->second->GetPos()); } + dirty_flags_&=~DirtyOrganizer; } void EntityImpl::IncXCSEditorCount() diff --git a/modules/mol/base/src/impl/query_impl.cc b/modules/mol/base/src/impl/query_impl.cc index 463daac1c6284aa39b8e436510eab3601d62ebca..a7935dae11ba177991613d3329b950383840ed74 100644 --- a/modules/mol/base/src/impl/query_impl.cc +++ b/modules/mol/base/src/impl/query_impl.cc @@ -1037,7 +1037,7 @@ Node* QueryImpl::ParseWithinExpr(QueryLexer& lexer) { geom::Vec3 point; if (this->ParsePoint(lexer, point)) { ParamType pt(WithinParam(point, rv*rv)); - CompOP comp_op= COP_LE; + CompOP comp_op=COP_LE; if (inversion_stack_.back()) comp_op=COP_GE; SelNode* within_node=new SelNode(Prop(Prop::WITHIN, Prop::VEC_DIST, @@ -1077,8 +1077,11 @@ Node* QueryImpl::ParseWithinExpr(QueryLexer& lexer) { ParamType pt(WithinParam(bracketed_expr_.size()-1, rv*rv)); inversion_stack_.pop_back(); CompOP comp_op= COP_LE; - if (inversion_stack_.back()) + if (inversion_stack_.back()) { + std::cout << "INV" << std::endl; comp_op=COP_GE; + } + SelNode* within_node=new SelNode(Prop(Prop::WITHIN, Prop::VEC_DIST, Prop::ATOM), comp_op, pt); diff --git a/modules/mol/base/src/impl/residue_impl.cc b/modules/mol/base/src/impl/residue_impl.cc index 3b8bd2ace4317b9761713dddfe4e91bde50ee519..5565a3cf9279ab84a0c9d44a2bcf0876f446ae4e 100644 --- a/modules/mol/base/src/impl/residue_impl.cc +++ b/modules/mol/base/src/impl/residue_impl.cc @@ -516,7 +516,8 @@ void ResidueImpl::AddAltAtomPos(const String& group, } int ResidueImpl::GetIndex() const { - return this->GetChain()->GetIndex(this->GetNumber()); + ResidueImplPtr res_impl=const_cast<ResidueImpl*>(this)->shared_from_this(); + return this->GetChain()->GetIndex(res_impl); } bool ResidueImpl::HasAltAtomGroup(const String& group) const { diff --git a/modules/mol/base/src/query_state.cc b/modules/mol/base/src/query_state.cc index 2f04aeecc9c9d02ef318e6b22cb20b5702a87e22..ad6ab0f126d5972517a27fa8a0b4f8fc02985e53 100644 --- a/modules/mol/base/src/query_state.cc +++ b/modules/mol/base/src/query_state.cc @@ -72,7 +72,7 @@ bool QueryState::do_within(const geom::Vec3& pos, const impl::WithinParam& p, if (geom::Dot(d, d) <= p.GetRadiusSquare()) { return true; } - } else if (geom::Dot(d, d) > p.GetRadiusSquare()) { + } else if (geom::Dot(d, d) < p.GetRadiusSquare()) { return false; } } diff --git a/modules/mol/base/tests/test_entity.cc b/modules/mol/base/tests/test_entity.cc index 646b75f74e2b3f4b1e892cb4a6033cca5f2e5db1..0c6bbe13a74bf0fae6c29bac83b4c6eea459692f 100644 --- a/modules/mol/base/tests/test_entity.cc +++ b/modules/mol/base/tests/test_entity.cc @@ -98,6 +98,16 @@ BOOST_AUTO_TEST_CASE(throw_invalid_ent_view) BOOST_CHECK_NO_THROW(CheckHandleValidity(ent.CreateEmptyView())); } +BOOST_AUTO_TEST_CASE(bzdng250) +{ + EntityHandle eh=make_test_entity(); + eh.EditXCS().ApplyTransform(geom::Mat4(-1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0,-1, 0, + 0, 0, 0, 1)); + BOOST_CHECK_NO_THROW(eh.FindResidue("A", 1).FindTorsion("PHI").GetAngle()); +} + BOOST_AUTO_TEST_CASE(entity_creator) { EntityHandle eh = CreateEntity(); diff --git a/modules/mol/base/tests/test_query.cc b/modules/mol/base/tests/test_query.cc index e8d56b6a1ee8873f168631cfd8056790e0112483..25d0284e64a3f7678a69b2c073bfb2a721010982 100644 --- a/modules/mol/base/tests/test_query.cc +++ b/modules/mol/base/tests/test_query.cc @@ -76,13 +76,13 @@ void ensure_counts(EntityHandle e, const String& qs, int cc, int rc, int ac) { BOOST_CHECK_NO_THROW(v=e.Select(qs)); BOOST_CHECK_MESSAGE(v.GetChainCount()==cc, "wrong chain count " << v.GetChainCount() - << " for query String " << qs); + << " for query string " << qs); BOOST_CHECK_MESSAGE(v.GetResidueCount()==rc, "wrong residue count " << v.GetResidueCount() << - " for query String " << qs); + " for query string " << qs); BOOST_CHECK_MESSAGE(v.GetAtomCount()==ac, "wrong atom count " << v.GetAtomCount() << - " for query String " << qs); + " for query string " << qs); } void ensure_counts_v(EntityView src, const String& qs, @@ -208,6 +208,9 @@ BOOST_AUTO_TEST_CASE(test_query_eval) ensure_counts(e, "rtype=C", 1, 3, 27); ensure_counts(e, "not (aname=CA and not aname=CA)", 1, 3, 27); ensure_counts(e, "3 <> {21.5,35,57.0}", 1, 2, 5); + ensure_counts(e, "not 3 <> {21.5,35,57.0}", 1, 3, 22); + ensure_counts(e, "3 <> {21.5,35,57} and not 0.5 <> {21.5,35,57} ", 1, 2, 4); + ensure_counts(e, "not 0.5 <> [rnum=3]", 1, 2, 19); ensure_counts(e, "1 <> {0,0,0}", 0, 0, 0); ensure_counts(e, "gatestpropa:0=1", 1, 1, 1); ensure_counts(e, "gatestpropa:1.0=1", 1, 3, 27); diff --git a/modules/mol/base/tests/test_residue.cc b/modules/mol/base/tests/test_residue.cc index a5a31a2fce8d169ac061fb1a47f6bd8e21deee09..3451f6f5bfc001e7bc23aa4458c602dbb8bf3ff1 100644 --- a/modules/mol/base/tests/test_residue.cc +++ b/modules/mol/base/tests/test_residue.cc @@ -46,6 +46,22 @@ BOOST_AUTO_TEST_CASE(test_in_sequence) } +BOOST_AUTO_TEST_CASE(test_res_index_bzdng227) +{ + std::cout << "HERE" << std::endl; + EntityHandle eh=CreateEntity(); + XCSEditor e=eh.EditXCS(); + ChainHandle ch1=e.InsertChain("A"); + ResidueHandle ra = e.AppendResidue(ch1, "A", 1); + ResidueHandle rb = e.AppendResidue(ch1, "B", 2); + ResidueHandle rc = e.AppendResidue(ch1, "C", 1); + + BOOST_CHECK_EQUAL(ra.GetIndex(), 0); + BOOST_CHECK_EQUAL(rb.GetIndex(), 1); + BOOST_CHECK_EQUAL(rc.GetIndex(), 2); +} + + BOOST_AUTO_TEST_CASE(throw_invalid_res_handle) { ChainHandle chain; diff --git a/modules/qa/pymod/CMakeLists.txt b/modules/qa/pymod/CMakeLists.txt index a63e9c2d9bc05f8a671c8bb172aac63cf7c8ccd5..c9681924294521ffbe8119f585f24bb9e7a3f120 100644 --- a/modules/qa/pymod/CMakeLists.txt +++ b/modules/qa/pymod/CMakeLists.txt @@ -3,6 +3,7 @@ set(OST_QA_PYMOD_SOURCES export_torsion.cc export_packing.cc export_reduced.cc + export_utilities.cc wrap_qa.cc export_clash.cc ) diff --git a/modules/qa/pymod/export_utilities.cc b/modules/qa/pymod/export_utilities.cc new file mode 100644 index 0000000000000000000000000000000000000000..31a6f2ab8d5bd954b75c9f2829a8753b2840fbc5 --- /dev/null +++ b/modules/qa/pymod/export_utilities.cc @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +// 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> +#include <ost/qa/amino_acids.hh> +using namespace boost::python; +using namespace ost::qa; + + +void export_Utilties() +{ + + def ("ResidueToAminoAcid",&ResidueToAminoAcid); + def ("AminoAcidToResidueName",&AminoAcidToResidueName); + def ("OneLetterCodeToResidueName",&OneLetterCodeToResidueName); + def ("ResidueNameToOneLetterCode",&ResidueNameToOneLetterCode); + def ("OneLetterCodeToAminoAcid",&OneLetterCodeToAminoAcid); + +} \ No newline at end of file diff --git a/modules/qa/pymod/wrap_qa.cc b/modules/qa/pymod/wrap_qa.cc index 6c4e6fcacdd978542be34a4e6782ee963131d9f5..14c66d90e3b2ebce817671682f49dc93bea624b0 100644 --- a/modules/qa/pymod/wrap_qa.cc +++ b/modules/qa/pymod/wrap_qa.cc @@ -18,11 +18,13 @@ //------------------------------------------------------------------------------ #include <boost/python.hpp> + void export_Torsion(); void export_Interaction(); void export_Packing(); void export_Clash(); void export_Reduced(); +void export_Utilties(); BOOST_PYTHON_MODULE(_qa) { export_Torsion(); @@ -30,4 +32,5 @@ BOOST_PYTHON_MODULE(_qa) export_Packing(); export_Clash(); export_Reduced(); + export_Utilties(); } diff --git a/modules/qa/src/amino_acids.cc b/modules/qa/src/amino_acids.cc index 1dfefe0c5b3800c6afe62330ea5a75dc9725c6dd..7111844e3e4035c5fb3d255c23c0c4174c89cb76 100644 --- a/modules/qa/src/amino_acids.cc +++ b/modules/qa/src/amino_acids.cc @@ -174,6 +174,73 @@ String OneLetterCodeToResidueName(char olc) } } +char ResidueNameToOneLetterCode(String rn) +{ + String upper_rn=rn; + std::transform(rn.begin(),rn.end(),rn.begin(),toupper); + if (upper_rn == "ALA") { + return 'A'; + } + if (upper_rn == "ARG") { + return 'R'; + } + if (upper_rn == "ASN") { + return 'N'; + } + if (upper_rn == "ASP") { + return 'D'; + } + if (upper_rn == "GLN") { + return 'Q'; + } + if (upper_rn == "GLU") { + return 'E'; + } + if (upper_rn == "LYS") { + return 'K'; + } + if (upper_rn == "SER") { + return 'S'; + } + if (upper_rn == "CYS") { + return 'C'; + } + if (upper_rn == "TYR") { + return 'Y'; + } + if (upper_rn == "TRP") { + return 'W'; + } + if (upper_rn == "THR") { + return 'T'; + } + if (upper_rn == "VAL") { + return 'V'; + } + if (upper_rn == "ILE") { + return 'I'; + } + if (upper_rn == "MET") { + return 'M'; + } + if (upper_rn == "LEU") { + return 'L'; + } + if (upper_rn == "GLY") { + return 'G'; + } + if (upper_rn == "PRO") { + return 'P'; + } + if (upper_rn == "HIS") { + return 'H'; + } + if (upper_rn == "PHE") { + return 'F'; + } + return 'X'; +} + AminoAcid OneLetterCodeToAminoAcid(char olc) { char upper_olc=toupper(olc); diff --git a/modules/qa/src/amino_acids.hh b/modules/qa/src/amino_acids.hh index 309726fe6f17674fb570bf18d376c452e32f2edd..03521fa40eb3fcd3c9fa3770d0b73693f39cc2ba 100644 --- a/modules/qa/src/amino_acids.hh +++ b/modules/qa/src/amino_acids.hh @@ -54,6 +54,8 @@ DLLEXPORT_OST_QA String OneLetterCodeToResidueName(char olc); DLLEXPORT_OST_QA AminoAcid OneLetterCodeToAminoAcid(char olc); +char DLLEXPORT_OST_QA ResidueNameToOneLetterCode(String rn); + class AminoAcidSetIterator : public std::iterator<std::forward_iterator_tag, AminoAcid> { public: diff --git a/modules/seq/base/pymod/export_sequence.cc b/modules/seq/base/pymod/export_sequence.cc index 454245778ff6b6ca0b03dfa394d4830cb50e3394..87345ad2a597a038c36a75c9a877136f03822a96 100644 --- a/modules/seq/base/pymod/export_sequence.cc +++ b/modules/seq/base/pymod/export_sequence.cc @@ -208,6 +208,7 @@ void const_seq_handle_def(O& bp_class) .def("GetLength", &C::GetLength) .def("GetResidue", &C::GetResidue) .def("GetOneLetterCode", &C::GetOneLetterCode) + .def("__iter__", iterator<C>()) .def("__getitem__", &C::GetOneLetterCode) .def("GetOffset", &C::GetOffset) .def("Copy", &C::Copy) @@ -287,6 +288,9 @@ void export_sequence() class_<SeqListIter>("SeqListIter", no_init) .def("next", &SeqListIter::next) ; + to_python_converter<std::pair<mol::EntityView, mol::EntityView>, + PairToTupleConverter<mol::EntityView, mol::EntityView> >(); + class_<AlignmentHandle>("AlignmentHandle", init<>()) .def("GetCount", &AlignmentHandle::GetCount) .add_property("sequence_count", &AlignmentHandle::GetCount) @@ -357,8 +361,7 @@ void export_sequence() .def("__getitem__", &do_slice_b) ; implicitly_convertible<SequenceList, ConstSequenceList>(); - to_python_converter<std::pair<mol::EntityView, mol::EntityView>, - PairToTupleConverter<mol::EntityView, mol::EntityView> >(); + def("CreateSequenceList", &CreateSequenceList); def("SequenceFromChain", seq_from_chain_a); def("SequenceFromChain", seq_from_chain_b); diff --git a/modules/seq/base/src/sequence_handle.cc b/modules/seq/base/src/sequence_handle.cc index 6991a14f76b2988f814e5b5d04252cf7e6536699..3065ae9f06af335c97a88e35742368ddc775037a 100644 --- a/modules/seq/base/src/sequence_handle.cc +++ b/modules/seq/base/src/sequence_handle.cc @@ -58,6 +58,8 @@ char ConstSequenceHandle::operator[](int index) const } + + void ConstSequenceHandle::CheckValidity() const { if (!impl_) { @@ -380,4 +382,11 @@ const GenericPropContainerImpl* SequenceHandle::GpImpl() const { return Impl().get(); } + +char SequenceHandle::operator[](size_t index) const +{ + this->CheckValidity(); + return this->GetString()[index]; +} + }} diff --git a/modules/seq/base/src/sequence_handle.hh b/modules/seq/base/src/sequence_handle.hh index 8d370e59e58f85e82c5e6f4e4346ff4909842020..d6fb0ab3ea438b3655594f8863c78c676f28abc0 100644 --- a/modules/seq/base/src/sequence_handle.hh +++ b/modules/seq/base/src/sequence_handle.hh @@ -49,6 +49,9 @@ public: friend class AlignmentHandle; friend class ConstSequenceList; friend class SequenceList; + + typedef String::const_iterator iterator; + /// \brief create invalid sequence handle /// /// \sa IsValid() @@ -118,6 +121,8 @@ public: char operator[](int index) const; + iterator begin() const { return this->GetString().begin(); } + iterator end() const { return this->GetString().end(); } /// \brief whether the sequence is valid bool IsValid() const; @@ -159,6 +164,7 @@ private: class DLLEXPORT_OST_SEQ SequenceHandle : public GenericPropContainer<SequenceHandle> { public: + typedef String::const_iterator iterator; friend class GenericPropContainer<SequenceHandle>; friend class SequenceList; @@ -255,6 +261,12 @@ public: void SetOneLetterCode(int position, char new_char); + + char operator[](size_t index) const; + + iterator begin() const { return this->GetString().begin(); } + iterator end() const { return this->GetString().end(); } + operator ConstSequenceHandle() const; /// \brief attach entity view to sequence /// diff --git a/modules/seq/base/tests/test_seq.py b/modules/seq/base/tests/test_seq.py index 80f13e364c07e3ba9665f34e62a462af79ae79ec..9ae40d5fc98cba9e64d15efe67dabd0978fc718b 100644 --- a/modules/seq/base/tests/test_seq.py +++ b/modules/seq/base/tests/test_seq.py @@ -30,7 +30,10 @@ class TestSeq(unittest.TestCase): string_b=''.join([r.one_letter_code for r in b.residues]) self.assertEqual(string_a, 'ABCDFGH') self.assertEqual(string_b, 'ABCDFGH') - + def testSeqIterBZDNG148(self): + s=seq.CreateSequence('A', 'abcdef') + for x in s: + pass def testViewsFromSequences_02(self): seq_a=seq.CreateSequence("A", "ABCD-FGH") seq_a.AttachView(self.ent.Select('rname=A,B,C,D,F,G,H'))