Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members

buildable_monomer.h

Go to the documentation of this file.
00001 // -*- mode: c++; -*-
00002 //
00003 //The Biomolecule Toolkit (BTK) is a C++ library for use in the
00004 //modeling, analysis, and design of biological macromolecules.
00005 //Copyright (C) 2004, Christopher Saunders <ctsa@users.sourceforge.net>
00006 //
00007 //This program is free software; you can redistribute it and/or modify
00008 //it under the terms of the GNU Lesser General Public License as published
00009 //by the Free Software Foundation; either version 2.1 of the License, or (at
00010 //your option) any later version.
00011 //
00012 //This program is distributed in the hope that it will be useful,  but
00013 //WITHOUT ANY WARRANTY; without even the implied warranty of
00014 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 //Lesser General Public License for more details. 
00016 //
00017 //You should have received a copy of the GNU Lesser General Public License 
00018 //along with this program; if not, write to the Free Software Foundation, 
00019 //Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00020 //
00021 
00025 
00026 
00027 #ifndef BTK_BUILDABLE_MONOMER_H
00028 #define BTK_BUILDABLE_MONOMER_H
00029 
00030 
00031 #include "buildable_atom.h"
00032 #include "buildable_atom_algorithms.h"
00033 #include "buildable_atom_group_concept.h"
00034 #include "buildable_monomer_family_pattern.h"
00035 #include "monomer.h"
00036 
00037 #include <boost/concept_check.hpp>
00038 #include <boost/static_assert.hpp>
00039 #include <boost/type_traits.hpp>
00040 
00041 #include <cassert>
00042 
00043 #include <string>
00044 #include <utility>
00045 
00046 
00047 #include <iostream>
00048 
00049 namespace BTK{
00050 
00051 
00064   template <typename AtomType>
00065   class BuildableMonomer : public Monomer<AtomType>, public BuildableAtomGroupConcept {
00066     BOOST_CLASS_REQUIRE2(AtomType, BuildableAtom, boost, ConvertibleConcept);
00067 
00068     typedef Monomer<AtomType> base_type;
00069     typedef BuildableMonomer<AtomType> self_type;
00070 
00071     typedef BuildableMonomerFamilyPattern pattern_t;
00072   public:
00073     typedef self_type buildable_monomer_types;
00074 
00076 
00077     typedef typename base_type::value_type value_type;
00078     typedef typename base_type::reference reference;
00079     typedef typename base_type::const_reference const_reference;
00080     typedef typename base_type::pointer pointer;
00081     typedef typename base_type::const_pointer const_pointer;
00082     typedef typename base_type::size_type size_type;
00083     typedef typename base_type::iterator iterator;
00084     typedef typename base_type::const_iterator const_iterator;
00086 
00088 
00089     typedef value_type atom_type;
00090     typedef iterator atom_iterator;
00091     typedef const_iterator const_atom_iterator;
00093 
00094     typedef std::map<ATOM::index_t,pointer> atom_index_map_t;
00095 
00096     typedef pattern_t::types::monomer_atom_idx_t monomer_atom_idx_t;
00097 
00098  
00104     BuildableMonomer(const BuildableMonomerFamilyPattern& family_pattern) 
00105       : _family_pattern(family_pattern) {}
00106     
00111     template <typename AtomIterator>
00112     BuildableMonomer(AtomIterator first,
00113                      AtomIterator last,
00114                      self_type* prev_monomer,
00115                      self_type* next_monomer,
00116                      const AtomGroupConcept::group_variant_container_t& modifiers,
00117                      const BuildableMonomerFamilyPattern& family_pattern) 
00118       : base_type(first,last), 
00119         _prev_monomer(prev_monomer), 
00120         _next_monomer(next_monomer), 
00121         _group_index(GROUP::name3_to_index(first->group_name3())),
00122         _group_variants(modifiers),
00123         _family_pattern(family_pattern)
00124     {
00125       set_buildable_group();
00126       initialize_atoms();
00127       initialize_bonds();
00128       if(_prev_monomer) _prev_monomer->set_next_monomer(this);
00129       if(_next_monomer) _next_monomer->set_prev_monomer(this);
00130     }
00131     
00134     BuildableMonomer(const self_type& source)
00135       : base_type(source), 
00136         _prev_monomer(0),
00137         _next_monomer(0),
00138         _group_index(source._group_index),
00139         _group_variants(source._group_variants),
00140         _family_pattern(source._family_pattern)
00141     {
00142       set_buildable_group();
00143       initialize_bonds();
00144     }
00145     
00146     template <typename T2>
00147     BuildableMonomer(const BuildableMonomer<T2>& source)
00148       : base_type(source),
00149         _prev_monomer(0),
00150         _next_monomer(0),
00151         _group_index(source._group_index),
00152         _group_variants(source._group_variants),
00153         _family_pattern(source._family_pattern)
00154     {
00155       set_buildable_group();
00156       initialze_bonds();
00157     }
00158 
00159 
00163     self_type& 
00164     operator=(const self_type& rhs) 
00165     {
00166       if (&rhs == this) return *this;
00167       base_type::operator=(rhs);
00168       _prev_monomer = 0;
00169       _next_monomer = 0;
00170       _group_index = rhs._group_index;
00171       _group_variants = rhs._group_variants;
00172       _family_pattern = rhs._family_pattern; 
00173 
00174       // buildable atoms should erase their own bonds when copied
00175       // so it should be as simple of as reinitializing bonds
00176       set_buildable_group();
00177       initialize_bonds();
00178 
00179       return *this;
00180     }
00181 
00182     template <typename T2>
00183     self_type& 
00184     operator=(const BuildableMonomer<T2>& rhs) 
00185     {
00186       base_type::operator=(rhs);
00187       _prev_monomer = 0;
00188       _next_monomer = 0;
00189       _group_index = rhs._group_index;
00190       _family_pattern = rhs._family_pattern;
00191  
00192       set_buildable_group();
00193       initialize_bonds();
00194 
00195       return *this;
00196     }
00197 
00199     // update atom group interface
00200     //
00201     virtual 
00202     GROUP::index_t 
00203     group_index() const 
00204     {
00205       return _group_index;
00206     }
00207 
00208     virtual 
00209     const AtomGroupConcept::group_variant_container_t& 
00210     group_variants() const 
00211     {
00212       return _group_variants;
00213     }
00214 
00215 
00216     virtual 
00217     const std::string& 
00218     group_name3() const 
00219     { 
00220       return GROUP::index_to_name3(group_index()); 
00221     }
00222     
00224     // initial definition from monomer
00225     //
00226     virtual 
00227     char 
00228     group_name1() const 
00229     { 
00230       return GROUP::index_to_name1(group_index()); 
00231     }
00232 
00234     //
00235     void
00236     insert_group_variant(GROUP_VARIANT::index_t v)
00237     {
00239       _group_variants.insert(v);
00240     }
00241 
00242     void
00243     erase_group_variant(GROUP_VARIANT::index_t v)
00244     {
00245       _group_variants.erase(v);
00246     }
00247 
00250 
00251 
00252 
00253 
00254 
00255     reference 
00256     atom(monomer_atom_idx_t ma) 
00257     {
00258       pointer a = atom_pointer(ma);
00259       assert(a);
00260       return *a;
00261     }
00262 
00263     const_reference 
00264     atom(monomer_atom_idx_t ma) const 
00265     {
00266       const_pointer a = atom_pointer(ma);
00267       assert(a);
00268       return *a;
00269     }
00271 
00273 
00274 
00275     reference 
00276     atom(ATOM::index_t atom_index) 
00277     {
00278       pointer a = atom_pointer(atom_index);
00279       assert(a);
00280       return *a;
00281     }
00282 
00283     const_reference 
00284     atom(ATOM::index_t atom_index) const 
00285     {
00286       const_pointer a = atom_pointer(atom_index);
00287       assert(a);
00288       return *a;
00289     }
00291 
00298     double 
00299     torsion_angle(TORSION::index_t t) const 
00300     {
00301       const pattern_t::types::torsion_atom_t& an = _family_pattern.torsion_atoms(group_index(),t);
00302       return torsion_angle_impl(an);
00303     }
00304 
00305     void 
00306     set_torsion_angle(TORSION::index_t t,
00307                       double angle) 
00308     {
00309       const pattern_t::types::torsion_atom_t& an = _family_pattern.torsion_atoms(group_index(),t);
00310       double delta_angle = angle - torsion_angle_impl(an);
00311 
00312       reference start    = atom(boost::get<2>(an));
00313       reference boundary = atom(boost::get<1>(an));
00314 
00315       restricted_rotate(start,boundary,delta_angle);
00316     }
00317 
00318 
00319     // this definition completes buildable atom group concept interface:
00320     // Doxygen comments are in the concept class
00321     //  
00322     virtual 
00323     bool 
00324     build_atom(const ATOM::index_t atom_index,
00325                bool is_bootstrap) 
00326     {
00327       // if source atom isn't assigned yet, then it can't be built
00328       //
00329       pointer build_atom_ptr = atom_pointer(atom_index);
00330       if(!build_atom_ptr) return false;
00331 
00332       // try to build from tetrads in this monomer
00333       //
00334       bool result = find_tetrads_and_build_atom(std::make_pair(0,atom_index),
00335                                                 build_atom_ptr,
00336                                                 is_bootstrap);
00337       if(result) return true;
00338 
00339       // if that fails, try to build from tetrads in neighboring monomers
00340       //
00341       if(_prev_monomer) {
00342         result = _prev_monomer->find_tetrads_and_build_atom(std::make_pair(1,atom_index),
00343                                                             build_atom_ptr,
00344                                                             is_bootstrap);
00345         if(result) return true;
00346       }
00347 
00348       if(_next_monomer) {
00349         result = _next_monomer->find_tetrads_and_build_atom(std::make_pair(-1,atom_index),
00350                                                             build_atom_ptr,
00351                                                             is_bootstrap);
00352         if(result) return true;
00353       }
00354 
00355       return false;
00356     }
00357 
00358 
00359   private:
00360 
00361     // internal atom lookup functions --
00362     //
00363     // what distinguishes these from the public atom functions is that lookup of an atom
00364     // that does not exist is not considered an error, this is because the buildable monomer class
00365     //  needs to lookup atoms that may not exist as a regular part of it's build routines.
00366     // 
00367     pointer 
00368     atom_pointer(monomer_atom_idx_t ma) 
00369     {
00370       int monomer_difference = ma.first;
00371       ATOM::index_t atom_index = ma.second;
00372       if(monomer_difference==0) {
00373         return atom_pointer(atom_index);
00374       } else if(monomer_difference<0) {
00375         if(! _prev_monomer) return 0;
00376         else return _prev_monomer->atom_pointer(std::make_pair(monomer_difference+1,atom_index));
00377       } else {
00378         if(! _next_monomer) return 0;
00379         else return _next_monomer->atom_pointer(std::make_pair(monomer_difference-1,atom_index));
00380       }
00381     }
00382 
00383     const_pointer 
00384     atom_pointer(monomer_atom_idx_t ma) const 
00385     {
00386       int monomer_difference = ma.first;
00387       ATOM::index_t atom_index = ma.second;
00388       if(monomer_difference==0) {
00389         return atom_pointer(atom_index);
00390       } else if(monomer_difference<0) {
00391         if(! _prev_monomer) return 0;
00392         else return _prev_monomer->atom_pointer(std::make_pair(monomer_difference+1,atom_index));
00393       } else {
00394         if(! _next_monomer) return 0;
00395         else return _next_monomer->atom_pointer(std::make_pair(monomer_difference-1,atom_index));
00396       }
00397     }
00398 
00399     pointer 
00400     atom_pointer(ATOM::index_t atom_index) 
00401     {
00402       typename atom_index_map_t::iterator a = _atom_index_to_atom_map.find(atom_index);
00403       if(a ==_atom_index_to_atom_map.end()) return 0;
00404       else return a->second;
00405     }
00406 
00407     const_pointer 
00408     atom_pointer(ATOM::index_t atom_index) const 
00409     {
00410       typename atom_index_map_t::const_iterator a = _atom_index_to_atom_map.find(atom_index);
00411       if(a ==_atom_index_to_atom_map.end()) return 0;
00412       else return a->second;
00413     }
00414 
00415 
00416     // given two atom indices, this function tries to find the bond length from the 
00417     // tetrads, if they are adjacent and if an appropriate tetrad exists. This function
00418     // was written for the convenience of the bootsrap build procedure
00419     //
00420     double
00421     get_bond_length_from_tetrads(monomer_atom_idx_t ma1,
00422                                  monomer_atom_idx_t ma2)
00423     {
00424       typedef pattern_t::types::tetrad_container_t tc_t;
00425 
00426       tc_t tc;
00427       double result = -1.;
00428       
00429       tc = _family_pattern.tetrads(group_index(),group_variants(),ma1);
00430       result = get_bond_length_from_tetrad_container(tc,ma2);
00431  
00432       if(result >= 0.) return result;
00433 
00434       tc = _family_pattern.tetrads(group_index(),group_variants(),ma2);
00435       result = get_bond_length_from_tetrad_container(tc,ma1);
00436       
00437       return result;
00438     }
00439 
00440     //  just grab a bond length from tetrads, used during bootstrap
00441     // build
00442     //
00443     double
00444     get_bond_length_from_tetrad_container(const pattern_t::types::tetrad_container_t& tc,
00445                                           const monomer_atom_idx_t& ma)
00446     {
00447       pattern_t::types::tetrad_container_t::const_iterator ti=tc.begin(),ti_end=tc.end();
00448       for(; ti != ti_end ; ++ti ){   
00449         if(ti->atom_index3()==ma) return ti->len34();
00450       }
00451       return -1.;
00452     }
00453 
00454     // convenient aggragate function for the build_atom procedure
00455     //
00456     bool
00457     find_tetrads_and_build_atom(monomer_atom_idx_t ma,
00458                                 pointer build_atom_ptr,
00459                                 bool is_bootstrap)
00460     {
00461       typedef pattern_t::types::tetrad_container_t tc_t;
00462       tc_t tc = _family_pattern.tetrads(group_index(),group_variants(), ma);
00463 
00464       return build_atom_from_tetrad_container(tc,build_atom_ptr,is_bootstrap);
00465     }
00466    
00467     // search through tetrads and try to build the build_atom from them
00468     //
00469     bool
00470     build_atom_from_tetrad_container(const pattern_t::types::tetrad_container_t& tc,
00471                                      pointer build_atom_ptr,
00472                                      bool is_bootstrap)
00473     {
00474       // for the build to work right, we must use buildable improper
00475       // torsion tetrads (pass 0) before buildable real torsion tetrads (pass 1)
00476       //
00477       for(unsigned pass=0;pass<2;++pass){
00478         pattern_t::types::tetrad_container_t::const_iterator ti=tc.begin(),ti_end=tc.end();
00479         for(; ti != ti_end ; ++ti ){
00480           if((pass == 0) && (ti->is_real_torsion())) continue;
00481           if((pass == 1) && (!ti->is_real_torsion())) continue;
00482           bool result = build_atom_from_tetrad(*ti,build_atom_ptr,is_bootstrap);
00483           if (result) return true;
00484         }
00485       }
00486       return false;
00487     }
00488 
00489 
00490     // try to build atom from a tetrad 
00491     //
00492     bool
00493     build_atom_from_tetrad(const AtomIndexTetrad& t,
00494                            pointer build_atom_ptr,
00495                            bool is_bootstrap)
00496     {
00498       // can a build be made from this tetrad?
00499       // check: 1) tetrad atoms are assigned and
00500       //        2) are built
00501       //
00502       const_pointer atom_ptr3 = atom_pointer(t.atom_index3());
00503       if(!atom_ptr3) return false;
00504       if(!is_bootstrap && !atom_ptr3->is_built()) return false;
00505       const_pointer atom_ptr2 = atom_pointer(t.atom_index2());
00506       if(!atom_ptr2) return false;
00507       if(!is_bootstrap && !atom_ptr2->is_built()) return false;
00508       
00509       if(!is_bootstrap){
00510         const_pointer atom_ptr1 = atom_pointer(t.atom_index1());
00511         if(!atom_ptr1) return false;
00512         if(!atom_ptr1->is_built()) return false;
00513 
00514         // regular tetrad build
00515         //
00516         build_atom_ptr->
00517           set_position(set_vector_from_dihedral(atom_ptr3->position(),
00518             atom_ptr2->position(),
00519             atom_ptr1->position(),
00520             t.len34(),
00521             t.ang234(),
00522             t.dih1234()));
00523         build_atom_ptr->set_is_built(true);
00524 
00525       } else {
00526 
00527         // build atoms 4,3,2 from scratch under length and angle constraints -
00528         // this should only occur to bootstrap a build of a completely new 
00529         // molecule
00530         //
00531         double len23 = get_bond_length_from_tetrads(t.atom_index3(),t.atom_index2());
00532         if( len23 <= 0.) return false;
00533         build_atom_ptr->set_position(new_vector(t.len34(),0.,0.));
00534         build_atom_ptr->set_is_built(true);
00535         atom_ptr3->set_position(new_vector(0.,0.,0.));
00536         atom_ptr3->set_is_built(true);
00537         atom_ptr2->set_position(new_vector(cos(t.ang234())*len23,sin(t.ang234())*len23,0.));
00538         atom_ptr2->set_is_built(true);
00539       }
00540       return true;
00541     }
00542 
00543 
00545     // update group pointers in buildable_atoms:
00546     void 
00547     set_buildable_group()
00548     {
00549       iterator i=begin(),i_end=end();
00550       for(;i!=i_end;++i) i->set_buildable_group(*this);
00551     }
00552 
00553     double 
00554     torsion_angle_impl(const pattern_t::types::torsion_atom_t& an) const 
00555     {
00556       return point_dihedral( atom(boost::get<0>(an)).position(),
00557                              atom(boost::get<1>(an)).position(),
00558                              atom(boost::get<2>(an)).position(),
00559                              atom(boost::get<3>(an)).position());
00560     }
00561 
00562     void 
00563     initialize_bonds() 
00564     {
00565       typedef pattern_t::types::bond_container_t bc_t;  
00566       bc_t bc = _family_pattern.bonds(group_index(),group_variants());
00567 
00568       std::cerr << "init bonds: group_num: " << group_num() << std::endl;
00569 
00570       bc_t::const_iterator bi=bc.begin(),bi_end=bc.end();
00571       for(; bi != bi_end; ++bi){
00572         pointer a1 = atom_pointer(bi->atom_index1());
00573         if(!a1) continue;
00574         pointer a2 = atom_pointer(bi->atom_index2());
00575         if(!a2) continue;
00576         std::cerr << "creating bond: atom1: " << *a1 << std::endl;
00577         std::cerr << "creating bond: atom2: " << *a2 << std::endl;
00578 
00579         add_bond(*a1,*a2);
00580       }
00581     }
00582 
00583     void 
00584     set_next_monomer(self_type* next_monomer)
00585     {
00586       _next_monomer = next_monomer;
00587     }
00588 
00589     void 
00590     set_prev_monomer(self_type* prev_monomer)
00591     {
00592       _prev_monomer = prev_monomer;
00593     }
00594 
00595     void 
00596     initialize_atoms() 
00597     {
00598       pattern_t::types::atom_container_t ac = _family_pattern.atoms(group_index(),group_variants());
00599 
00600       std::cerr << "init atoms: group_num: " << group_num() << std::endl;
00601 
00602       // assign the atoms that are expected
00603       for(atom_iterator i=atom_begin();i != atom_end(); ++i){
00604         ATOM::index_t atom_index = i->atom_index();
00605 
00606         if( ac.find(atom_index) == ac.end() ){
00607           // throwing away input atom -- add some notification options here
00608           std::cerr << "throwing away atom: " << i->atom_name() << std::endl;
00609           i = erase(i) - 1;
00610         } else {
00611           // allow atom in monomer
00612           std::cerr << "adding atom: " << i->atom_name() << std::endl;
00613           _atom_index_to_atom_map[ atom_index ] = &(*i);
00614           ac.erase(atom_index);
00615 
00616           i->set_is_built(true);
00617         }
00618       }
00619 
00620       // add missing atoms
00621       pattern_t::types::atom_container_t::const_iterator i=ac.begin(), i_end=ac.end();
00622       for(;i!=i_end;++i){
00623         shallow_push_back(new atom_type());
00624         back().set_atom_index(*i);
00625         _atom_index_to_atom_map[ *i ] = &(back());
00626 
00627         // new atoms are not built yet
00628         back().set_is_built(false);
00629         back().set_group(*this);
00630         back().set_buildable_group(*this);
00631         std::cerr << "adding new atom: " << back().atom_name() << std::endl;
00632       }
00633     }
00634 
00635 
00636   private:
00637     self_type* _prev_monomer;
00638     self_type* _next_monomer;
00639 
00640     atom_index_map_t _atom_index_to_atom_map;
00641 
00642     GROUP::index_t _group_index;
00643 
00644     AtomGroupConcept::group_variant_container_t _group_variants;
00645 
00646     const pattern_t& _family_pattern;
00647 
00648   };
00649 } // namespace BTK
00650 
00651 
00652 
00653 #endif

Generated on Wed Apr 14 00:43:16 2004 for BTK by doxygen 1.3.6