MayaChemTools

   1 package MolecularDescriptors::RotatableBondsDescriptors;
   2 #
   3 # $RCSfile: RotatableBondsDescriptors.pm,v $
   4 # $Date: 2015/02/28 20:49:20 $
   5 # $Revision: 1.18 $
   6 #
   7 # Author: Manish Sud <msud@san.rr.com>
   8 #
   9 # Copyright (C) 2015 Manish Sud. All rights reserved.
  10 #
  11 # This file is part of MayaChemTools.
  12 #
  13 # MayaChemTools is free software; you can redistribute it and/or modify it under
  14 # the terms of the GNU Lesser General Public License as published by the Free
  15 # Software Foundation; either version 3 of the License, or (at your option) any
  16 # later version.
  17 #
  18 # MayaChemTools is distributed in the hope that it will be useful, but without
  19 # any warranty; without even the implied warranty of merchantability of fitness
  20 # for a particular purpose.  See the GNU Lesser General Public License for more
  21 # details.
  22 #
  23 # You should have received a copy of the GNU Lesser General Public License
  24 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
  25 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
  26 # Boston, MA, 02111-1307, USA.
  27 #
  28 
  29 use strict;
  30 use Carp;
  31 use Exporter;
  32 use Scalar::Util ();
  33 use TextUtil ();
  34 use Atom;
  35 use Molecule;
  36 use MolecularDescriptors::MolecularDescriptors;
  37 
  38 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  39 
  40 @ISA = qw(MolecularDescriptors::MolecularDescriptors Exporter);
  41 @EXPORT = qw();
  42 @EXPORT_OK = qw(GetDescriptorNames);
  43 
  44 %EXPORT_TAGS = (all  => [@EXPORT, @EXPORT_OK]);
  45 
  46 # Setup class variables...
  47 my($ClassName, @DescriptorNames);
  48 _InitializeClass();
  49 
  50 # Overload Perl functions...
  51 use overload '""' => 'StringifyRotatableBondsDescriptors';
  52 
  53 # Class constructor...
  54 sub new {
  55   my($Class, %NamesAndValues) = @_;
  56 
  57   # Initialize object...
  58   my $This = $Class->SUPER::new();
  59   bless $This, ref($Class) || $Class;
  60   $This->_InitializeRotatableBondsDescriptors();
  61 
  62   $This->_InitializeRotatableBondsDescriptorsProperties(%NamesAndValues);
  63 
  64   return $This;
  65 }
  66 
  67 # Initialize class ...
  68 sub _InitializeClass {
  69   #Class name...
  70   $ClassName = __PACKAGE__;
  71 
  72   # Descriptor names...
  73   @DescriptorNames = ('RotatableBonds');
  74 
  75 }
  76 
  77 # Get descriptor names as an array.
  78 #
  79 # This functionality can be either invoked as a class function or an
  80 # object method.
  81 #
  82 sub GetDescriptorNames {
  83   return @DescriptorNames;
  84 }
  85 
  86 # Initialize object data...
  87 #
  88 sub _InitializeRotatableBondsDescriptors {
  89   my($This) = @_;
  90 
  91   # Type of MolecularDescriptor...
  92   $This->{Type} = 'RotatableBonds';
  93 
  94   # MayaChemTools rotatable bonds default definition corresponds to modifed
  95   # version of rotatable bonds definition used by Veber et al. [ Ref 92 ]
  96   #
  97   $This->{IgnoreTerminalBonds} = 1;
  98   $This->{IgnoreBondsToTripleBonds} = 1;
  99   $This->{IgnoreAmideBonds} = 1;
 100   $This->{IgnoreThioamideBonds} = 1;
 101   $This->{IgnoreSulfonamideBonds} = 1;
 102 
 103   # Intialize descriptor names and values...
 104   $This->_InitializeDescriptorNamesAndValues(@DescriptorNames);
 105 
 106   return $This;
 107 }
 108 
 109 # Initialize object properties...
 110 #
 111 sub _InitializeRotatableBondsDescriptorsProperties {
 112   my($This, %NamesAndValues) = @_;
 113 
 114   my($Name, $Value, $MethodName);
 115   while (($Name, $Value) = each  %NamesAndValues) {
 116     $MethodName = "Set${Name}";
 117     $This->$MethodName($Value);
 118   }
 119 
 120   return $This;
 121 }
 122 
 123 # Calculate number of rotatable bonds in a molecule...
 124 #
 125 # A rotatable bond is defined as any single bond which is not in a ring
 126 # and involves only non-hydrogen atoms. By default, the following types
 127 # of single bonds are not considered rotatable bonds:
 128 #
 129 #   . Terminal bonds
 130 #   . Bonds attached to triple bonds
 131 #   . Amide C-N bonds
 132 #   . Thioamide C-N bond bonds
 133 #   . Sulfonamide S-N bonds
 134 #
 135 # MayaChemTools rotatable bonds default definition corresponds to modifed
 136 # version of rotatable bonds definition used by Veber et al. [ Ref 92 ]
 137 #
 138 sub GenerateDescriptors {
 139   my($This) = @_;
 140 
 141   # Initialize descriptor values...
 142   $This->_InitializeDescriptorValues();
 143 
 144   # Check availability of molecule...
 145   if (!$This->{Molecule}) {
 146     carp "Warning: ${ClassName}->GenerateDescriptors: $This->{Type} molecular descriptors generation didn't succeed: Molecule data is not available: Molecule object hasn't been set...";
 147     return undef;
 148   }
 149 
 150   # Calculate descriptor values...
 151   if (!$This->_CalculateDescriptorValues()) {
 152     carp "Warning: ${ClassName}->GenerateDescriptors: $This->{Type} molecular descriptors generation didn't succeed: Couldn't calculate RotatableBonds values...";
 153     return undef;
 154   }
 155 
 156   # Set final descriptor values...
 157   $This->_SetFinalDescriptorValues();
 158 
 159   return $This;
 160 }
 161 
 162 # Calculate RotatableBonds value...
 163 #
 164 sub _CalculateDescriptorValues {
 165   my($This) = @_;
 166   my($Bond, $RotatableBonds, $Atom1, $Atom2);
 167 
 168   $RotatableBonds = 0;
 169 
 170   BOND: for $Bond ($This->{Molecule}->GetBonds()) {
 171     # Is it a non-ring ring bond?
 172     if (!$Bond->IsSingle() || $Bond->IsInRing()) {
 173       next BOND;
 174     }
 175 
 176     ($Atom1, $Atom2) = $Bond->GetAtoms();
 177 
 178     # Does bond contain any Hydrogen atoms?
 179     if ($Atom1->IsHydrogen() || $Atom2->IsHydrogen()) {
 180       next BOND;
 181     }
 182 
 183     # Check for terminal bonds...
 184     if ($This->{IgnoreTerminalBonds} && $This->_IsTerminalBond($Atom1, $Atom2)) {
 185       next BOND;
 186     }
 187 
 188     # Check for bonds attached to triple bonds...
 189     if ($This->{IgnoreBondsToTripleBonds} && $This->_IsAttachedToTripleBond($Atom1, $Atom2)) {
 190       next BOND;
 191     }
 192 
 193     # Check for amide bonds...
 194     if ($This->{IgnoreAmideBonds} && $This->_IsAmideBond($Atom1, $Atom2)) {
 195       next BOND;
 196     }
 197 
 198     # Check for amide bonds...
 199     if ($This->{IgnoreThioamideBonds} && $This->_IsThioamideBond($Atom1, $Atom2)) {
 200       next BOND;
 201     }
 202 
 203     # Check for sulfonamide bonds...
 204     if ($This->{IgnoreSulfonamideBonds} && $This->_IsSulfonamideBond($Atom1, $Atom2)) {
 205       next BOND;
 206     }
 207 
 208     $RotatableBonds += 1;
 209   }
 210 
 211   # Track the calculated values...
 212   $This->{RotatableBonds} = $RotatableBonds;
 213 
 214   return $This;
 215 }
 216 
 217 # Is it a terminal bond?
 218 #
 219 sub _IsTerminalBond {
 220   my($This, $Atom1, $Atom2) = @_;
 221 
 222   return ($Atom1->GetAtomicInvariantValue('X') <= 1 || $Atom2->GetAtomicInvariantValue('X') <= 1 ) ? 1 : 0;
 223 }
 224 
 225 # Is it attached to a terminal bond?
 226 #
 227 sub _IsAttachedToTripleBond {
 228   my($This, $Atom1, $Atom2) = @_;
 229 
 230   return ($Atom1->GetAtomicInvariantValue('LBO') == 3 || $Atom2->GetAtomicInvariantValue('LBO') == 3) ? 1 : 0;
 231 }
 232 
 233 # Is it an amide bond?
 234 #
 235 # Amide: R-C(=O)-N(-R)(-R")
 236 #
 237 sub _IsAmideBond {
 238   my($This, $Atom1, $Atom2) = @_;
 239   my($CarbonAtom, $NitrogenAtom);
 240 
 241   ($CarbonAtom, $NitrogenAtom) = (undef, undef);
 242 
 243   if ($Atom1->IsCarbon() && $Atom2->IsNitrogen()) {
 244     ($CarbonAtom, $NitrogenAtom) = ($Atom1, $Atom2);
 245   }
 246   elsif ($Atom2->IsCarbon() && $Atom1->IsNitrogen()) {
 247     ($CarbonAtom, $NitrogenAtom) = ($Atom2, $Atom1);
 248   }
 249 
 250   if (!$CarbonAtom) {
 251     return 0;
 252   }
 253 
 254   return $CarbonAtom->DoesAtomNeighborhoodMatch('C.T3.DB1', ['O', 'N', 'C,H'], ['=', '-', '-']) ? 1 : 0;
 255 }
 256 
 257 # Is it a thioamide bond?
 258 #
 259 # Thioamide: R-C(=S)-N(-R)(-R")
 260 #
 261 sub _IsThioamideBond {
 262   my($This, $Atom1, $Atom2) = @_;
 263   my($CarbonAtom, $NitrogenAtom);
 264 
 265   ($CarbonAtom, $NitrogenAtom) = (undef, undef);
 266 
 267   if ($Atom1->IsCarbon() && $Atom2->IsNitrogen()) {
 268     ($CarbonAtom, $NitrogenAtom) = ($Atom1, $Atom2);
 269   }
 270   elsif ($Atom2->IsCarbon() && $Atom1->IsNitrogen()) {
 271     ($CarbonAtom, $NitrogenAtom) = ($Atom2, $Atom1);
 272   }
 273 
 274   if (!$CarbonAtom) {
 275     return 0;
 276   }
 277 
 278   return $CarbonAtom->DoesAtomNeighborhoodMatch('C.T3.DB1', ['S', 'N', 'C,H'], ['=', '-', '-']) ? 1 : 0;
 279 }
 280 
 281 # Is it a sulfonamide bond?
 282 #
 283 # Sulfonamide: R-S(=O)(=O)-N(-R)(-R")
 284 #
 285 sub _IsSulfonamideBond {
 286   my($This, $Atom1, $Atom2) = @_;
 287   my($SulfurAtom, $NitrogenAtom);
 288 
 289   ($SulfurAtom, $NitrogenAtom) = (undef, undef);
 290 
 291   if ($Atom1->IsSulfur() && $Atom2->IsNitrogen()) {
 292     ($SulfurAtom, $NitrogenAtom) = ($Atom1, $Atom2);
 293   }
 294   elsif ($Atom2->IsSulfur() && $Atom1->IsNitrogen()) {
 295     ($SulfurAtom, $NitrogenAtom) = ($Atom2, $Atom1);
 296   }
 297 
 298   if (!$SulfurAtom) {
 299     return 0;
 300   }
 301 
 302   return $SulfurAtom->DoesAtomNeighborhoodMatch('S.T4.DB2', ['O', 'O', 'N', '!O'], ['=', '=', '-', '-']) ? 1 : 0;
 303 }
 304 
 305 # Setup final descriptor values...
 306 #
 307 sub _SetFinalDescriptorValues {
 308   my($This) = @_;
 309 
 310   $This->{DescriptorsGenerated} = 1;
 311 
 312   $This->SetDescriptorValues($This->{RotatableBonds});
 313 
 314   return $This;
 315 }
 316 
 317 # Return a string containg data for RotatableBondsDescriptors object...
 318 #
 319 sub StringifyRotatableBondsDescriptors {
 320   my($This) = @_;
 321   my($RotatableBondsDescriptorsString);
 322 
 323   # Type of MolecularDescriptors...
 324   $RotatableBondsDescriptorsString = "MolecularDescriptorType: $This->{Type}; IgnoreTerminalBonds: " . ($This->{IgnoreTerminalBonds} ? "Yes" : "No") . "; IgnoreBondsToTripleBonds: " .  ($This->{IgnoreBondsToTripleBonds} ? "Yes" : "No") . "; IgnoreAmideBonds: " .  ($This->{IgnoreAmideBonds} ? "Yes" : "No") . "; IgnoreThioamideBonds: " .  ($This->{IgnoreThioamideBonds} ? "Yes" : "No") . "; IgnoreSulfonamideBonds: " .  ($This->{IgnoreSulfonamideBonds} ? "Yes" : "No");
 325 
 326   # Setup molecular descriptor information...
 327   $RotatableBondsDescriptorsString .= "; " . $This->_StringifyDescriptorNamesAndValues();
 328 
 329   return $RotatableBondsDescriptorsString;
 330 }
 331 
 332 # Is it a RotatableBondsDescriptors object?
 333 sub _IsRotatableBondsDescriptors {
 334   my($Object) = @_;
 335 
 336   return (Scalar::Util::blessed($Object) && $Object->isa($ClassName)) ? 1 : 0;
 337 }
 338