Molmodel
|
00001 #ifndef SimTK_MOLMODEL_COMPOUND_H_ 00002 #define SimTK_MOLMODEL_COMPOUND_H_ 00003 00004 /* -------------------------------------------------------------------------- * 00005 * SimTK Core: SimTK Molmodel * 00006 * -------------------------------------------------------------------------- * 00007 * This is part of the SimTK Core biosimulation toolkit originating from * 00008 * Simbios, the NIH National Center for Physics-Based Simulation of * 00009 * Biological Structures at Stanford, funded under the NIH Roadmap for * 00010 * Medical Research, grant U54 GM072970. See https://simtk.org. * 00011 * * 00012 * Portions copyright (c) 2007-2008 Stanford University and the Authors. * 00013 * Authors: Michael Sherman, Christopher Bruns * 00014 * Contributors: * 00015 * * 00016 * Permission is hereby granted, free of charge, to any person obtaining a * 00017 * copy of this software and associated documentation files (the "Software"), * 00018 * to deal in the Software without restriction, including without limitation * 00019 * the rights to use, copy, modify, merge, publish, distribute, sublicense, * 00020 * and/or sell copies of the Software, and to permit persons to whom the * 00021 * Software is furnished to do so, subject to the following conditions: * 00022 * * 00023 * The above copyright notice and this permission notice shall be included in * 00024 * all copies or substantial portions of the Software. * 00025 * * 00026 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 00027 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 00028 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * 00029 * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 00030 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 00031 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * 00032 * USE OR OTHER DEALINGS IN THE SOFTWARE. * 00033 * -------------------------------------------------------------------------- */ 00034 00035 00036 #include "SimTKsimbody.h" 00037 00038 #include "molmodel/internal/common.h" 00039 #include "DuMMForceFieldSubsystem.h" 00040 #include "molmodel/internal/Pdb.h" 00041 #include "molmodel/internal/Superpose.h" 00042 #include "molmodel/internal/units.h" 00043 #include <map> 00044 00045 #include <iosfwd> // declare ostream without all the definitions 00046 00047 namespace SimTK { 00048 class CompoundSystem; 00049 00050 // Because of private data, put Compound implementation behind the curtain 00051 class Compound; 00052 class CompoundRep; 00053 00054 // Make sure class is instantiated just once in the library 00055 // #ifndef DO_INSTANTIATE_COMPOUND_PIMPL_HANDLE 00056 // template class SimTK_MOLMODEL_EXPORT PIMPLHandle<Compound, CompoundRep>; 00057 // #endif 00058 00062 namespace BondMobility { 00070 enum Mobility { 00071 Free = 1, 00072 Torsion = 2, 00073 Rigid = 3 00074 }; 00075 static Mobility Default = Torsion; 00076 } 00077 00084 class SimTK_MOLMODEL_EXPORT Compound : public PIMPLHandle<Compound,CompoundRep> { 00085 public: 00086 00087 enum MatchStratagem { 00088 Match_Exact, //< Try to match input atom positions precisely 00089 Match_Idealized, //< Try to match atom positions with idealized geometry 00090 Match_TopologyOnly //< Don't match atom positions, only topology 00091 }; 00092 00095 00101 typedef String Name; 00102 00116 typedef String AtomName; 00117 00128 typedef String BondCenterName; 00129 00136 typedef String DihedralName; 00137 00148 typedef String BondCenterPathName; 00149 00163 typedef String AtomPathName; 00164 00165 // Unique classes which behave like type-safe ints. These are local 00166 // to Compound. 00167 00173 // SimTK_DEFINE_UNIQUE_LOCAL_INDEX_TYPE(Compound,Index); 00174 00175 00181 SimTK_DEFINE_UNIQUE_LOCAL_INDEX_TYPE(Compound,AtomIndex); 00182 00188 SimTK_DEFINE_UNIQUE_LOCAL_INDEX_TYPE(Compound,LocalAtomIndex); 00189 00195 SimTK_DEFINE_UNIQUE_LOCAL_INDEX_TYPE(Compound,BondCenterIndex); 00196 00202 SimTK_DEFINE_UNIQUE_LOCAL_INDEX_TYPE(Compound,BondIndex); 00203 00205 typedef std::map<AtomIndex, Vec3> AtomTargetLocations; 00206 00207 class SingleAtom; 00208 00210 00211 00214 00220 Compound(); 00221 00229 explicit Compound(const Name& name 00230 ); 00231 00235 int getNumAtoms() const; 00236 00238 size_t getNumBondCenters() const; 00239 00241 size_t getNumBondCenters(Compound::AtomIndex atomIndex) const; 00242 00244 size_t getNumBonds() const; 00245 00247 // int getNumSubcompounds() const; 00248 00250 bool hasAtom(const AtomPathName& name 00251 ) const; 00252 00254 bool hasBondCenter(const BondCenterPathName& bondCenter 00255 ) const; 00256 00258 // bool hasSubcompound(const Name& name ///< name of the subcompound relative to this compound. 00259 // ) const; 00260 00262 Compound::AtomIndex getBondAtomIndex( 00263 Compound::BondIndex bondIndex, 00264 int which 00265 ) const; 00266 00267 00273 Compound& setBaseAtom( 00274 const Compound::AtomName& name, 00275 const Element& element, 00276 const Transform& location = Vec3(0) 00277 ); 00283 Compound& setBaseAtom( 00284 const Compound::AtomName& name, 00285 const Biotype& biotype, 00286 const Transform& location = Vec3(0) 00287 ); 00288 00295 Compound& setBaseAtom( 00296 const Compound::SingleAtom& c, 00297 const Transform& = Transform() 00298 ); 00299 00305 Compound& setBaseCompound( 00306 const Compound::Name& n, 00307 const Compound& c, 00308 const Transform& location = Transform() 00309 ); 00310 00317 Compound& bondAtom( 00318 const Compound::SingleAtom& c, 00319 const BondCenterPathName& parentBondName, 00320 mdunits::Length distance, 00321 Angle dihedral = 0, 00322 BondMobility::Mobility = BondMobility::Default 00323 ); 00324 00333 Compound& bondAtom( 00334 const Compound::SingleAtom& c, 00335 const BondCenterPathName& parentBondName 00336 ); 00337 00343 Compound& bondCompound( 00344 const Compound::Name& n, 00345 const Compound& c, 00346 const BondCenterPathName& parentBondName, 00347 mdunits::Length distance, 00348 Angle dihedral = 180*Deg2Rad, 00349 BondMobility::Mobility mobility = BondMobility::Default 00350 ); 00351 00361 Compound& bondCompound( 00362 const Compound::Name& n, 00363 const Compound& c, 00364 const BondCenterPathName& parentBondName 00365 ); 00366 00376 Compound& bondCompound( 00377 const Compound::Name& n, 00378 const Compound& c, 00379 const BondCenterPathName& parentBondName, 00380 BondMobility::Mobility mobility 00381 ); 00382 00390 Compound& setInboardBondCenter( 00391 const Compound::BondCenterName& centerName 00392 ); 00393 00399 Compound& convertInboardBondCenterToOutboard(); 00400 00406 Compound& addFirstBondCenter( 00407 const Compound::BondCenterName& centerName, 00408 const Compound::AtomPathName& atomName 00409 ); 00410 00417 Compound& addSecondBondCenter( 00418 const Compound::BondCenterName& centerName, 00419 const Compound::AtomName& atomName, 00420 Angle bondAngle1 00421 ); 00422 00433 Compound& addPlanarBondCenter( 00434 const Compound::BondCenterName& centerName, 00435 const Compound::AtomName& atomName, 00436 Angle bondAngle1, 00437 Angle bondAngle2 00438 ); 00439 00449 Compound& addRightHandedBondCenter( 00450 const Compound::BondCenterName& centerName, 00451 const Compound::AtomName& atomName, 00452 Angle bondAngle1, 00453 Angle bondAngle2 00454 ); 00455 00465 Compound& addLeftHandedBondCenter( 00466 const Compound::BondCenterName& centerName, 00467 const Compound::AtomName& atomName, 00468 Angle bondAngle1, 00469 Angle bondAngle2 00470 ); 00471 00483 Compound& addRingClosingBond( 00484 const Compound::BondCenterPathName& centerName1, 00485 const Compound::BondCenterPathName& centerName2, 00486 mdunits::Length bondLength, 00487 Angle dihedral = 180*Deg2Rad, 00488 BondMobility::Mobility mobility = BondMobility::Default 00489 ); 00490 00502 Compound& addRingClosingBond( 00503 const Compound::BondCenterPathName& centerName1, 00504 const Compound::BondCenterPathName& centerName2 00505 ); 00506 00508 //const Compound& getSubcompound(Compound::Index ///< integer index of subcompound 00509 // ) const; 00510 00512 //Compound& updSubcompound(Compound::Index ///< integer index of subcompound 00513 // ); 00514 00516 const Compound& getSubcompound(const Compound::Name& subcompoundName 00517 ) const; 00518 00520 Compound& updSubcompound(const Compound::Name& subcompoundName 00521 ); 00522 00524 // end topology methods 00525 00526 00529 00535 Vec3 calcDefaultAtomLocationInGroundFrame(const AtomPathName& atomName 00536 ) const; 00537 00538 Vec3 calcDefaultAtomLocationInCompoundFrame(const AtomPathName& atomName 00539 ) const; 00540 00550 Compound& setDefaultInboardBondLength(mdunits::Length 00551 ); 00552 00561 Compound& setDefaultInboardDihedralAngle(Angle 00562 ); 00563 00572 Compound& setDefaultBondAngle( 00573 Angle angle, 00574 const AtomPathName& atom1, 00575 const AtomPathName& atom2, 00576 const AtomPathName& atom3 00577 ); 00578 00584 Compound& setDefaultBondLength( 00585 mdunits::Length length, 00586 const AtomPathName& atom1, 00587 const AtomPathName& atom2 00588 ); 00589 00595 Compound& setDefaultDihedralAngle( 00596 const DihedralName& dihedralName, 00597 Angle angleInRadians 00598 ); 00599 00600 Compound& setDefaultDihedralAngle( 00601 Angle angle, 00602 Compound::AtomIndex atom1, 00603 Compound::AtomIndex atom2, 00604 Compound::AtomIndex atom3, 00605 Compound::AtomIndex atom4 00606 ); 00607 00608 Compound& setDefaultDihedralAngle( 00609 Angle angle, 00610 const Compound::AtomName& atom1, 00611 const Compound::AtomName& atom2, 00612 const Compound::AtomName& atom3, 00613 const Compound::AtomName& atom4 00614 ); 00615 00621 Angle calcDefaultDihedralAngle( 00622 const DihedralName& dihedralName 00623 ) const; 00624 00632 Compound& setDihedralAngle( 00633 State& state, 00634 const DihedralName& dihedralName, 00635 Angle 00636 ); 00637 00643 Angle calcDihedralAngle( 00644 const State& state, 00645 const DihedralName& dihedralName 00646 ) const; 00647 00649 Transform calcDefaultAtomFrameInCompoundFrame(Compound::AtomIndex 00650 ) const; 00651 00655 Vec3 calcAtomLocationInGroundFrame( 00656 const State& state, 00657 Compound::AtomIndex atomId 00658 ) const; 00659 00660 Vec3 calcAtomLocationInCompoundFrame( 00661 const State& state, 00662 Compound::AtomIndex atomId 00663 ) const; 00664 00668 Vec3 calcAtomVelocityInGroundFrame( 00669 const State& state, 00670 Compound::AtomIndex atomId 00671 ) const; 00672 00676 Vec3 calcAtomAccelerationInGroundFrame( 00677 const State& state, 00678 Compound::AtomIndex atomId 00679 ) const; 00680 00684 Transform getSubcompoundFrameInParentFrame( 00685 const Compound::Name& subcompoundName 00686 ) const; 00687 00693 virtual AtomTargetLocations createAtomTargets(const class PdbStructure& targetStructure) const; 00694 virtual AtomTargetLocations createAtomTargets(const class PdbChain& targetChain) const; 00695 virtual AtomTargetLocations createAtomTargets(const class PdbResidue& targetResidue) const; 00696 00704 Compound& matchDefaultAtomChirality( 00705 const AtomTargetLocations& atomTargets, 00706 Angle planarityTolerance = 90.0 * Deg2Rad, 00707 bool flipAll = true 00708 ); 00709 Compound& matchDefaultBondLengths(const AtomTargetLocations& atomTargets); 00710 Compound& matchDefaultBondAngles(const AtomTargetLocations& atomTargets); 00711 00712 enum PlanarBondMatchingPolicy {KeepPlanarBonds, DistortPlanarBonds, FlipPlanarBonds}; 00713 Compound& matchDefaultDihedralAngles( 00714 const AtomTargetLocations& atomTargets, 00715 PlanarBondMatchingPolicy policy = FlipPlanarBonds 00716 ); 00717 00718 Compound& matchDefaultTopLevelTransform(const AtomTargetLocations& atomTargets); 00719 TransformAndResidual getTransformAndResidual(const Compound::AtomTargetLocations& atomTargets) const; 00720 00722 Compound& matchDefaultConfiguration( 00723 const AtomTargetLocations& atomTargets, 00724 MatchStratagem matchStratagem = Match_Exact) 00725 { 00726 if (matchStratagem == Compound::Match_TopologyOnly) 00727 // do nothing, topology is already there 00728 return *this; 00729 00730 else if (matchStratagem == Compound::Match_Exact) 00731 { 00732 // low tolerance breaks planarity just about everywhere 00733 matchDefaultAtomChirality(atomTargets, 0.01, false); 00734 00735 matchDefaultBondLengths(atomTargets); 00736 matchDefaultBondAngles(atomTargets); 00737 00738 // Set dihedral angles even when bonded atoms are planar 00739 matchDefaultDihedralAngles(atomTargets, Compound::DistortPlanarBonds); 00740 00741 matchDefaultTopLevelTransform(atomTargets); 00742 00743 // No further optimization should be needed 00744 00745 return *this; 00746 } 00747 00748 else if (matchStratagem == Compound::Match_Idealized) 00749 { 00750 // Break planarity constraint only when input atoms are 90 degrees out of plane 00751 matchDefaultAtomChirality(atomTargets, 90*Deg2Rad, true); 00752 00753 // Avoid setting non zero/180 dihedral angles on bonded planar atoms 00754 matchDefaultDihedralAngles(atomTargets, Compound::FlipPlanarBonds); 00755 00756 matchDefaultTopLevelTransform(atomTargets); 00757 00758 // At this point the structure match is approximate and may have 00759 // many bad contacts. Optimization is needed 00760 // TODO - ObservedPointFitter on internal coordinates 00761 fitDefaultConfiguration(atomTargets, 0.005); 00762 00763 return *this; 00764 } 00765 00766 else assert(false); // unknown match stratagem 00767 00768 return *this; 00769 } 00770 00772 Compound& fitDefaultConfiguration( 00773 const AtomTargetLocations& atomTargets, 00774 SimTK::Real targetRms); 00775 00777 const Compound& populateDefaultPdbChain( 00778 class PdbChain&, 00779 int& defaultNextResidueNumber, 00780 const Transform& transform = Transform()) const; 00781 00783 const Compound& populatePdbChain( 00784 const State& state, 00785 class PdbChain&, 00786 int& defaultNextResidueNumber, 00787 const Transform& transform = Transform()) const; 00788 00794 std::ostream& writeDefaultPdb( 00795 std::ostream& os, 00796 const Transform& transform = Transform() 00797 ) const; 00798 00804 void writeDefaultPdb( 00805 const char* outFileName, 00806 const Transform& transform 00807 ) const; 00808 00816 std::ostream& writeDefaultPdb( 00817 std::ostream& os, 00818 int& nextAtomSerialNumber, 00819 const Transform& transform = Transform() 00820 ) const; 00821 00827 std::ostream& writePdb( 00828 const State& state, 00829 std::ostream& os, 00830 const Transform& transform = Transform() 00831 ) const; 00832 00833 00841 std::ostream& writePdb( 00842 const State& state, 00843 std::ostream& os, 00844 int& nextAtomSerialNumber, 00845 const Transform& transform = Transform() 00846 ) const; 00847 00849 // end configuration section 00850 00851 00854 00864 Compound& setCompoundName(const Name& 00865 ); 00866 00867 00869 const Name& getCompoundName() const; 00870 00879 Compound& addCompoundSynonym(const Name& 00880 ); 00881 00886 const AtomPathName getAtomName(Compound::AtomIndex 00887 ) const; 00888 00890 const Element& getAtomElement(Compound::AtomIndex 00891 ) const; 00892 00893 const Element& getAtomElement(const Compound::AtomName& 00894 ) const; 00895 00899 Compound& nameAtom( 00900 const Compound::AtomName& newName, 00901 const AtomPathName& oldName 00902 ); 00903 00907 Compound& nameAtom( 00908 const Compound::AtomName& newName, 00909 const AtomPathName& oldName, 00910 BiotypeIndex biotype 00911 ); 00912 00923 Compound& defineDihedralAngle( 00924 const Compound::DihedralName& angleName, 00925 const Compound::AtomPathName& atom1, 00926 const Compound::AtomPathName& atom2, 00927 const Compound::AtomPathName& atom3, 00928 const Compound::AtomPathName& atom4, 00929 Angle offset = 0*Deg2Rad 00930 ); 00931 00946 Compound& defineDihedralAngle( 00947 const Compound::DihedralName& angleName, 00948 const Compound::BondCenterPathName& bond1, 00949 const Compound::BondCenterPathName& bond2, 00950 Angle offset = 0*Deg2Rad 00951 ); 00952 00958 Compound& setPdbResidueNumber(int resNum); 00959 00961 int getPdbResidueNumber() const; 00962 00968 Compound& setPdbResidueName(const String& resName); 00969 00971 const String& getPdbResidueName() const; 00972 00978 Compound& setPdbChainId(char chainId 00979 ); 00980 00982 char getPdbChainId() const; 00983 00989 Compound& nameBondCenter( 00990 const Compound::BondCenterName& newName, 00991 const BondCenterPathName& oldName 00992 ); 00993 00999 Compound& inheritAtomNames(const Compound::Name& 01000 ); 01001 01002 Compound& inheritCompoundSynonyms(const Compound& otherCompound); 01003 01009 Compound& inheritBondCenterNames(const Compound::Name& 01010 ); 01011 01013 Compound::AtomIndex getAtomIndex(const Compound::AtomPathName& 01014 ) const; 01015 01017 // end nomenclature methods 01018 01019 01022 01028 //void setCompoundSystem(CompoundSystem& system, ///< The CompoundSystem that will take ownership of this Compound. 01029 // Compound::Index); ///< The index within the new owner CompoundSystem that this Compound will have. 01030 01031 void setMultibodySystem(MultibodySystem& system); 01032 01038 Compound& setBondMobility( 01039 BondMobility::Mobility mobility, 01040 const AtomPathName& atom1, 01041 const AtomPathName& atom2 01042 ); 01043 01049 Compound& setBondMobility( 01050 BondMobility::Mobility mobility, 01051 Compound::BondIndex bondIndex 01052 ); 01053 01061 Compound & setCompoundBondMobility(BondMobility::Mobility mobility); 01062 01070 MobilizedBodyIndex getAtomMobilizedBodyIndex(Compound::AtomIndex 01071 ) const; 01072 01080 Vec3 getAtomLocationInMobilizedBodyFrame(Compound::AtomIndex 01081 ) const; 01082 01088 Compound& setBiotypeIndex( 01089 const Compound::AtomPathName& atomName, 01090 BiotypeIndex biotype 01091 ); 01092 01093 Compound& setAtomBiotype( 01094 const Compound::AtomPathName& atomName, 01095 const String& biotypeResidueName, 01096 const String& biotypeAtomName, 01097 SimTK::Ordinality::Residue ordinality = SimTK::Ordinality::Any 01098 ) 01099 { 01100 Compound::AtomIndex atomIndex = getAtomIndex(atomName); 01101 01102 if ( ! Biotype::exists(biotypeResidueName, biotypeAtomName, ordinality) ) 01103 Biotype::defineBiotype( 01104 getAtomElement(atomIndex), 01105 getNumBondCenters(atomIndex), 01106 biotypeResidueName, 01107 biotypeAtomName, 01108 ordinality 01109 ); 01110 01111 const Biotype& biotype = Biotype::get(biotypeResidueName, biotypeAtomName, ordinality); 01112 01113 assert( biotype.getElement() == getAtomElement(atomIndex) ); 01114 assert( biotype.getValence() == getNumBondCenters(atomIndex) ); 01115 01116 BiotypeIndex biotypeIndex = biotype.getIndex(); 01117 setBiotypeIndex(atomName, biotypeIndex); 01118 01119 return *this; 01120 } 01121 01123 BiotypeIndex getAtomBiotypeIndex(Compound::AtomIndex 01124 ) const; 01125 01126 // RUNTIME INTERFACE 01127 01135 DuMM::AtomIndex getDuMMAtomIndex(Compound::AtomIndex) const; 01136 01138 // end simulation methods 01139 01141 Compound& setTopLevelTransform(const Transform& transform); 01142 01144 const Transform& getTopLevelTransform() const; 01145 01146 01147 01148 protected: 01149 01153 void setDuMMAtomIndex( 01154 Compound::AtomIndex, 01155 DuMM::AtomIndex 01156 ); 01157 01158 explicit Compound(CompoundRep* ip); 01159 friend class CompoundSystem; 01160 01161 private: 01162 // OBSOLETE: use getNumAtoms() 01163 int getNAtoms() const {return getNumAtoms();} 01164 // OBSOLETE: use getNumBondCenters() 01165 size_t getNBondCenters() const {return getNumBondCenters();} 01166 // OBSOLETE: use getNumBondCenters() 01167 size_t getNBondCenters(Compound::AtomIndex atomIndex) const {return getNumBondCenters(atomIndex);} 01168 // OBSOLETE: use getNumBonds() 01169 size_t getNBonds() const {return getNumBonds();} 01170 }; 01171 01172 01180 SimTK_MOLMODEL_EXPORT std::ostream& operator<<(std::ostream& o, const Compound& c); 01181 01191 class Compound::SingleAtom : public Compound { 01192 public: 01193 SingleAtom( 01194 const Compound::AtomName& atomName, 01195 const Element& element 01196 ) 01197 { 01198 setBaseAtom( atomName, element ); 01199 01200 setCompoundName("SingleAtom"); // should be overridden by derived class constructors 01201 } 01202 }; 01203 01204 01219 class UnivalentAtom : public Compound::SingleAtom { 01220 public: 01221 UnivalentAtom( 01222 const Compound::AtomName& atomName, 01223 const Element& element 01224 ) 01225 : Compound::SingleAtom(atomName, element) 01226 { 01227 addFirstBondCenter( "bond", atomName); 01228 setInboardBondCenter("bond"); 01229 01230 setCompoundName("UnivalentAtom"); // should be overridden by derived class constructors 01231 } 01232 }; 01233 01234 01240 class BivalentAtom : public Compound::SingleAtom { 01241 public: 01242 BivalentAtom( 01243 const Compound::AtomName& atomName, 01244 const Element& element, 01245 Angle angle = 180*Deg2Rad 01246 ) 01247 : Compound::SingleAtom(atomName, element) 01248 { 01249 // BondCenter1 dihedral will be relative to BondCenter2 01250 addFirstBondCenter( "bond1", atomName); 01251 // conversely, bond center 2 dihedral is relative to bond center 1 01252 addSecondBondCenter( "bond2", atomName, angle); 01253 setInboardBondCenter("bond1"); // without loss of generality 01254 01255 setCompoundName("BivalentAtom"); // should be overridden by derived class constructors 01256 } 01257 }; 01258 01259 01266 class TrivalentAtom : public Compound::SingleAtom { 01267 public: 01268 TrivalentAtom( 01269 const Compound::AtomName& atomName, 01270 const Element& element, 01271 Angle angle1 = 120*Deg2Rad, 01272 Angle angle2 = 120*Deg2Rad 01273 ) 01274 : Compound::SingleAtom(atomName, element) 01275 { 01276 // BondCenter1 dihedral will be relative to BondCenter2 01277 addFirstBondCenter( "bond1", atomName ); 01278 // bond centers 2 and 3 dihedrals relative to bond center 1 01279 addSecondBondCenter( "bond2", atomName, angle1); 01280 addPlanarBondCenter( "bond3", atomName, angle2, 360*Deg2Rad - angle1 - angle2); 01281 01282 // Choice of inboard bond may differ from bond priority - user may change this 01283 setInboardBondCenter("bond1"); 01284 01285 setCompoundName("TrivalentAtom"); // should be overridden by derived class constructors 01286 } 01287 }; 01288 01294 class QuadrivalentAtom : public Compound::SingleAtom { 01295 public: 01296 QuadrivalentAtom( 01297 const Compound::AtomName& atomName, 01298 const Element& element 01299 ) 01300 : Compound::SingleAtom(atomName, element) 01301 { 01302 static const Angle TetrahedralAngle = 109.47 * Deg2Rad; 01303 01304 // BondCenter1 dihedral will be relative to BondCenter2 01305 // Using Rotation() constructor that takes x axis and approximate y axis 01306 addFirstBondCenter( "bond1", atomName ); 01307 // bond centers 2, 3, and 4 dihedrals will be relative to bond1 01308 addSecondBondCenter( "bond2", atomName, TetrahedralAngle ); 01309 addLeftHandedBondCenter( "bond3", atomName, TetrahedralAngle, TetrahedralAngle ); 01310 addRightHandedBondCenter( "bond4", atomName, TetrahedralAngle, TetrahedralAngle ); 01311 01312 // Choice of inboard bond may differ from bond priority - user may change this 01313 setInboardBondCenter("bond1"); 01314 01315 // default dihedral should be left blank, so it could be 01316 // defined from the other side. 01317 // the ultimate default will be 180 degrees anyway. 01318 // setDefaultInboardDihedralAngle(180*Deg2Rad); 01319 01320 setCompoundName("QuadrivalentAtom"); // should be overridden by derived class constructors 01321 } 01322 01323 QuadrivalentAtom( 01324 const Compound::AtomName& atomName, 01325 const Element& element, 01326 Angle bond12Angle, 01327 Angle bond13Angle, 01328 Angle bond14Angle, 01329 Angle dihedral3, 01330 Angle dihedral4 01331 ) 01332 : Compound::SingleAtom(atomName, element) 01333 { 01334 // BondCenter1 dihedral will be relative to BondCenter2 01335 // Using Rotation() constructor that takes x axis and approximate y axis 01336 addFirstBondCenter( "bond1", atomName ); 01337 // bond centers 2, 3, and 4 dihedrals will be relative to bond1 01338 addSecondBondCenter( "bond2", atomName, bond12Angle ); 01339 01340 // Compute bond23Angle and bond24Angle 01341 SimTK::Vec3 v1(0,0,1); 01342 SimTK::Vec3 v2 = SimTK::Rotation(bond12Angle, ZAxis) * SimTK::Vec3(0,0,1); 01343 SimTK::Vec3 v3 = SimTK::Rotation(dihedral3, YAxis) * SimTK::Rotation(bond12Angle, ZAxis) * SimTK::Vec3(0,0,1); 01344 SimTK::Vec3 v4 = SimTK::Rotation(dihedral4, YAxis) * SimTK::Rotation(bond12Angle, ZAxis) * SimTK::Vec3(0,0,1); 01345 01346 Angle bond23Angle = std::acos(SimTK::dot(v2, v3)); 01347 Angle bond24Angle = std::acos(SimTK::dot(v2, v4)); 01348 01349 // restrict angle range to (-Pi,Pi) 01350 while (dihedral3 > Pi) dihedral3 -= 2.0*Pi; 01351 while (dihedral3 <= -Pi) dihedral3 += 2.0*Pi; 01352 while (dihedral4 > Pi) dihedral4 -= 2.0*Pi; 01353 while (dihedral4 <= -Pi) dihedral4 += 2.0*Pi; 01354 01355 if (dihedral3 > 0) 01356 addLeftHandedBondCenter( "bond3", atomName, bond13Angle, bond23Angle ); 01357 else 01358 addRightHandedBondCenter( "bond3", atomName, bond13Angle, bond23Angle ); 01359 01360 if (dihedral4 > 0) 01361 addLeftHandedBondCenter( "bond4", atomName, bond14Angle, bond24Angle ); 01362 else 01363 addRightHandedBondCenter( "bond4", atomName, bond14Angle, bond24Angle ); 01364 01365 // Choice of inboard bond may differ from bond priority - user may change this 01366 setInboardBondCenter("bond1"); 01367 01368 // default dihedral should be left blank, so it could be 01369 // defined from the other side. 01370 // the ultimate default will be 180 degrees anyway. 01371 // setDefaultInboardDihedralAngle(180*Deg2Rad); 01372 01373 setCompoundName("QuadrivalentAtom"); // should be overridden by derived class constructors 01374 } 01375 }; 01376 01377 01381 class AliphaticHydrogen : public UnivalentAtom { 01382 public: 01383 explicit AliphaticHydrogen(const AtomName& atomName = "H" 01384 ) 01385 : UnivalentAtom(atomName, Element::Hydrogen()) 01386 { 01387 setDefaultInboardBondLength(0.1112); // for bonding to aliphatic carbon 01388 01389 setCompoundName("AliphaticHydrogenAtom"); 01390 } 01391 }; 01392 01393 01399 class AliphaticCarbon : public QuadrivalentAtom { 01400 public: 01401 explicit AliphaticCarbon(const AtomName& atomName = "C" 01402 ) 01403 : QuadrivalentAtom(atomName, Element::Carbon()) 01404 { 01405 // In case this bonds to another aliphatic carbon 01406 setDefaultInboardBondLength(0.15620); // for bonding to another aliphatic carbon 01407 01408 setCompoundName("AliphaticCarbon"); 01409 } 01410 }; 01411 01412 01416 class MethyleneGroup : public Compound { 01417 public: 01418 MethyleneGroup() { 01419 static const mdunits::Length C_Hdistance = 0.1112; // nanometers 01420 01421 setBaseAtom(AliphaticCarbon("C")); 01422 bondAtom(AliphaticHydrogen("H1"), "C/bond3"); 01423 bondAtom(AliphaticHydrogen("H2"), "C/bond4"); 01424 nameBondCenter("bond1", "C/bond1"); 01425 nameBondCenter("bond2", "C/bond2"); 01426 01427 setDefaultInboardBondLength(0.15620); // for bonding to another aliphatic carbon 01428 01429 setCompoundName("MethyleneGroup"); 01430 } 01431 }; 01432 01433 01437 class MethylGroup : public Compound { 01438 public: 01439 MethylGroup() { 01440 setBaseAtom(AliphaticCarbon("C")); 01441 bondAtom(AliphaticHydrogen("H1"), "C/bond2"); 01442 bondAtom(AliphaticHydrogen("H2"), "C/bond3"); 01443 bondAtom(AliphaticHydrogen("H3"), "C/bond4"); 01444 nameBondCenter("bond", "C/bond1"); 01445 01446 setDefaultInboardBondLength(0.15620); // for bonding to another aliphatic carbon 01447 setCompoundName("MethylGroup"); 01448 } 01449 }; 01450 01457 class AromaticSixMemberedCHGroup : public Compound { 01458 public: 01459 AromaticSixMemberedCHGroup() { 01460 static const mdunits::Length C_Hdistance = 0.1080; // in nanometers, from tinker amber99.dat 01461 static const mdunits::Length C_Cdistance = 0.1400; // in nanometers, from tinker amber99.dat 01462 01463 setBaseAtom( TrivalentAtom("C", Element::Carbon(), 120*Deg2Rad, 120*Deg2Rad) ); 01464 bondAtom( UnivalentAtom("H", Element::Hydrogen()), "C/bond3", C_Hdistance); 01465 01466 // remember to change default length for bonding other other things 01467 setDefaultInboardBondLength(C_Cdistance); // for bonding to other aromatic CH 01468 01469 setCompoundName("AromaticSixMemberedCHGroup"); 01470 } 01471 }; 01472 01473 01477 class AlcoholOHGroup : public Compound { 01478 public: 01479 AlcoholOHGroup() { 01480 static const mdunits::Length O_Hdistance = 0.0960; // nanometers 01481 01482 setBaseAtom( BivalentAtom("O", Element::Oxygen(), 108.50 * Deg2Rad) ); 01483 01484 bondAtom( UnivalentAtom("H", Element::Hydrogen()), "O/bond2", O_Hdistance ); 01485 nameBondCenter("bond", "O/bond1"); 01486 01487 // In case of bonding to aliphatic carbon 01488 setDefaultInboardBondLength(0.1410); // for bonding to aliphatic carbon 01489 01490 setCompoundName("AlcoholOHGroup"); 01491 } 01492 }; 01493 01494 01498 class PrimaryAmineGroup : public Compound { 01499 public: 01500 PrimaryAmineGroup() { 01501 static const mdunits::Length H_Ndistance = 0.1010; // nanometers 01502 static const mdunits::Length N_Cdistance = 0.1471; // in nanometers, for bonding to aliphatic carbon 01503 01504 setBaseAtom( QuadrivalentAtom("N", Element::Nitrogen()) ); 01505 bondAtom( UnivalentAtom("H1", Element::Hydrogen()), "N/bond2", H_Ndistance); 01506 bondAtom( UnivalentAtom("H2", Element::Hydrogen()), "N/bond3", H_Ndistance); 01507 bondAtom( UnivalentAtom("H3", Element::Hydrogen()), "N/bond4", H_Ndistance); 01508 01509 setDefaultInboardBondLength(N_Cdistance); // for bonding to aliphatic carbon 01510 } 01511 }; 01512 01513 01517 class CarboxylateGroup : public Compound { 01518 public: 01519 CarboxylateGroup() { 01520 // parameters from Tinker amber99.param 01521 static const mdunits::Length O_Cdistance = 0.1250; // nanometers 01522 static const mdunits::Length C_CtDistance = 0.15220; // nanometers 01523 static const Angle O_C_Oangle = 126*Deg2Rad; 01524 01525 // we actually use the inboard-C-O angle during construction 01526 static const Angle O_C_CtAngle = 180*Deg2Rad - 0.5*O_C_Oangle; 01527 01528 setBaseAtom( TrivalentAtom("C", Element::Carbon(), O_C_CtAngle, O_C_CtAngle) ); 01529 bondAtom( UnivalentAtom("O1", Element::Oxygen()), "C/bond2", O_Cdistance); 01530 bondAtom( UnivalentAtom("O2", Element::Oxygen()), "C/bond3", O_Cdistance); 01531 01532 setDefaultInboardBondLength(C_CtDistance); 01533 01534 nameBondCenter("bond", "C/bond1"); 01535 } 01536 }; 01537 01549 class SimTK_MOLMODEL_EXPORT Molecule : public Compound { 01550 public: 01551 Molecule(); 01552 SimTK_INSERT_DERIVED_HANDLE_DECLARATIONS(Molecule, CompoundRep, Compound); 01553 protected: 01554 explicit Molecule(CompoundRep* rep); 01555 }; 01556 01557 01561 class Argon : public Molecule { 01562 public: 01563 Argon() { 01564 setPdbResidueName("AR "); 01565 01566 setBaseAtom( "Ar", Biotype::Argon() ); 01567 01568 setCompoundName("Argon"); 01569 } 01570 }; 01571 01572 01576 class Methane : public Molecule { 01577 public: 01578 Methane() 01579 { 01580 setBaseCompound("methyl", MethylGroup()); 01581 inheritAtomNames("methyl"); 01582 01583 // Ordinarily, methyl group bonds to aliphatic carbon, 01584 // and has a default bond length to match. 01585 // Here we turn off the methyl inboard bond, so the 01586 // AliphaticHydrogen will, as desired, dictate the bond length 01587 convertInboardBondCenterToOutboard(); 01588 01589 bondAtom(AliphaticHydrogen("H4"), "methyl/bond", 0.1112); 01590 01591 setBiotypeIndex( "C", Biotype::MethaneC().getIndex() ); 01592 setBiotypeIndex( "H1", Biotype::MethaneH().getIndex() ); 01593 setBiotypeIndex( "H2", Biotype::MethaneH().getIndex() ); 01594 setBiotypeIndex( "H3", Biotype::MethaneH().getIndex() ); 01595 setBiotypeIndex( "H4", Biotype::MethaneH().getIndex() ); 01596 01597 setCompoundName("Methane"); 01598 01599 01600 } 01601 }; 01602 01606 class Ethane : public Molecule { 01607 public: 01608 Ethane() 01609 { 01610 setPdbResidueName("EHN"); 01611 01612 setBaseCompound("methyl1", MethylGroup()); 01613 nameAtom("C1", "methyl1/C", Biotype::EthaneC().getIndex() ); 01614 nameAtom("H1", "methyl1/H1", Biotype::EthaneH().getIndex() ); 01615 nameAtom("H2", "methyl1/H2", Biotype::EthaneH().getIndex() ); 01616 nameAtom("H3", "methyl1/H3", Biotype::EthaneH().getIndex() ); 01617 01618 // This first methyl is a base, not a decoration 01619 convertInboardBondCenterToOutboard(); 01620 01621 bondCompound("methyl2", MethylGroup(), "methyl1/bond"); 01622 01623 nameAtom("C2", "methyl2/C", Biotype::EthaneC().getIndex() ); 01624 nameAtom("H4", "methyl2/H1", Biotype::EthaneH().getIndex() ); 01625 nameAtom("H5", "methyl2/H2", Biotype::EthaneH().getIndex() ); 01626 nameAtom("H6", "methyl2/H3", Biotype::EthaneH().getIndex() ); 01627 01628 defineDihedralAngle("torsion", "H1", "C1", "C2", "H4"); 01629 01630 setDefaultTorsionAngle(180*Deg2Rad); 01631 // setBondRotatable(false, "C1", "C2"); 01632 01633 setCompoundName("Ethane"); 01634 01635 } 01636 01642 Ethane& setDefaultTorsionAngle(Angle angle 01643 ) { 01644 setDefaultDihedralAngle("torsion", angle); 01645 01646 return *this; 01647 } 01648 01652 Angle calcDefaultTorsionAngle() const { 01653 return calcDefaultDihedralAngle("torsion"); 01654 } 01655 }; 01656 01663 class BiopolymerResidueRep; 01664 // class SimTK_MOLMODEL_EXPORT BiopolymerResidue : public Compound { 01665 class SimTK_MOLMODEL_EXPORT BiopolymerResidue : public Compound { 01666 public: 01670 BiopolymerResidue( 01671 const Compound::Name& residueTypeName, 01672 const String& threeLetterCode, 01673 char oneLetterCode 01674 ); 01675 01679 BiopolymerResidue& setOneLetterCode(char olc 01680 ); 01681 01685 BiopolymerResidue& setThreeLetterCode(const String& tlc 01686 ); 01687 01691 BiopolymerResidue& setResidueTypeName(const String& name 01692 ); 01693 01694 char getOneLetterCode() const; 01695 const String& getThreeLetterCode() const; 01696 const String& getResidueTypeName() const; 01697 01707 bool assignBiotypes( 01708 Ordinality::Residue ordinality = Ordinality::Any 01709 ); 01710 01711 Compound::AtomIndex getParentCompoundAtomIndex(AtomIndex residueAtomIndex) const; 01712 01713 SimTK_INSERT_DERIVED_HANDLE_DECLARATIONS(BiopolymerResidue,BiopolymerResidueRep,Compound); 01714 }; 01715 01716 class BiopolymerRep; 01717 01718 // This class to point to residue atoms in a Biopolymer 01719 class ResidueInfo { 01720 public: 01724 SimTK_DEFINE_UNIQUE_LOCAL_INDEX_TYPE(ResidueInfo,Index); 01725 SimTK_DEFINE_UNIQUE_LOCAL_INDEX_TYPE(ResidueInfo,AtomIndex); 01726 01727 class AtomInfo { 01728 public: 01729 friend class ResidueInfo; 01730 01731 AtomInfo(Compound::AtomIndex index, const Compound::AtomName& name) 01732 : pdbAtomName(name), biopolymerAtomIndex(index) 01733 { 01734 synonyms.insert(name); 01735 } 01736 01737 const std::set<Compound::AtomName>& getNames() const { 01738 return synonyms; 01739 } 01740 01741 private: 01742 Compound::AtomIndex biopolymerAtomIndex; 01743 String pdbAtomName; 01744 std::set<Compound::AtomName> synonyms; 01745 }; 01746 01747 01748 ResidueInfo( 01749 ResidueInfo::Index ix, 01750 const Compound::Name& name, 01751 const BiopolymerResidue& res, 01752 Compound::AtomIndex atomOffset, 01753 char insertionCode = ' '); 01754 01755 AtomIndex addAtom(Compound::AtomIndex index, const Compound::AtomName& name) { 01756 ResidueInfo::AtomIndex answer(atoms.size()); 01757 atoms.push_back(AtomInfo(index, name)); 01758 atomIdsByName[name] = answer; 01759 return answer; 01760 } 01761 01762 size_t getNumAtoms() const { 01763 return atoms.size(); 01764 } 01765 01766 const AtomInfo& getAtomInfo(AtomIndex a) const { 01767 return atoms[a]; 01768 } 01769 AtomInfo& updAtomInfo(AtomIndex a) { 01770 return atoms[a]; 01771 } 01772 01773 const std::set<Compound::Name>& getNames() const {return synonyms;} 01774 01775 const Compound::Name& getPdbResidueName() const { 01776 return pdbResidueName; 01777 } 01778 01779 const int getPdbResidueNumber() const { 01780 return pdbResidueNumber; 01781 } 01782 01783 const char getPdbInsertionCode() const { 01784 return pdbInsertionCode; 01785 } 01786 01787 Compound::AtomIndex getAtomIndex(ResidueInfo::AtomIndex a) const { 01788 return atoms[a].biopolymerAtomIndex; 01789 } 01790 01791 Compound::AtomIndex getAtomIndex(Compound::AtomName a) const { 01792 return atoms[atomIdsByName.find(a)->second].biopolymerAtomIndex; 01793 } 01794 01795 const String& getAtomName(ResidueInfo::AtomIndex a) const { 01796 return atoms[a].pdbAtomName; 01797 } 01798 01799 const std::set<Compound::AtomName>& getAtomSynonyms(ResidueInfo::AtomIndex a) const { 01800 return atoms[a].synonyms; 01801 } 01802 01803 const Compound::Name& getName() const {return nameInCompound;} 01804 01805 ResidueInfo& setPdbResidueNumber(int num) { 01806 pdbResidueNumber = num; 01807 return *this; 01808 } 01809 01810 ResidueInfo::Index getIndex() const {return index;} 01811 01812 private: 01813 ResidueInfo::Index index; 01814 Compound::Name nameInCompound; 01815 Compound::Name pdbResidueName; 01816 std::set<Compound::Name> synonyms; 01817 int pdbResidueNumber; 01818 char pdbInsertionCode; 01819 std::vector<AtomInfo> atoms; 01820 std::map<const Compound::Name, AtomIndex> atomIdsByName; 01821 // TODO - put private data in ResidueInfoRep 01822 }; 01823 01832 class SimTK_MOLMODEL_EXPORT Biopolymer : public Molecule 01833 { 01834 public: 01838 typedef String Sequence; 01839 01843 Biopolymer(); 01844 01848 int getNumResidues() const; 01849 01855 const ResidueInfo& getResidue( 01856 ResidueInfo::Index residueIndex 01857 ) const; 01858 01864 ResidueInfo& updResidue( 01865 ResidueInfo::Index residueIndex 01866 ); 01867 01871 const ResidueInfo& getResidue( 01872 Compound::Name residueName 01873 ) const; 01874 01878 ResidueInfo& updResidue( 01879 Compound::Name residueName 01880 ); 01881 01887 const Compound::Name& getResidueName( 01888 ResidueInfo::Index residueIndex 01889 ) const; 01890 01891 // BiopolymerResidue createResidueCompound(ResidueInfo::Index r) const; 01892 01899 Biopolymer& renumberPdbResidues(int firstPdbResidueNumber); 01900 01901 bool assignResidueBiotypes(ResidueInfo::Index, Ordinality::Residue); 01902 01910 void assignBiotypes(); 01911 01915 ResidueInfo::Index appendResidue( 01916 const Compound::Name& resName, 01917 const BiopolymerResidue& residue 01918 ); 01919 01923 ResidueInfo::Index appendResidue( 01924 const Compound::Name& resName, 01925 const BiopolymerResidue& residue, 01926 BondMobility::Mobility mobility 01927 ); 01928 01929 Biopolymer& setResidueBondMobility(ResidueInfo::Index, BondMobility::Mobility); 01930 MobilizedBodyIndex getResidueAtomMobilizedBodyIndex(ResidueInfo::Index res, ResidueInfo::AtomIndex a) const { 01931 return getAtomMobilizedBodyIndex(getResidue(res).getAtomIndex(a)); 01932 } 01933 Vec3 getResidueAtomLocationInMobilizedBodyFrame(ResidueInfo::Index res, ResidueInfo::AtomIndex a) const { 01934 return getAtomLocationInMobilizedBodyFrame(getResidue(res).getAtomIndex(a)); 01935 } 01936 01937 virtual AtomTargetLocations createAtomTargets(const class PdbStructure& targetStructure) const; 01938 virtual AtomTargetLocations createAtomTargets(const class PdbChain& targetChain) const; 01939 01940 SimTK_INSERT_DERIVED_HANDLE_DECLARATIONS(Biopolymer, BiopolymerRep, Molecule); 01941 01942 // OBSOLETE; TODO: remove in SimTK 2.0 01943 int getNResidues() const {return getNumResidues();} 01944 01945 private: 01946 }; 01947 01948 01949 } // namespace SimTK 01950 01951 #endif // SimTK_MOLMODEL_COMPOUND_H_