MayaChemTools

   1 package MolecularDescriptors::TPSADescriptors;
   2 #
   3 # $RCSfile: TPSADescriptors.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 MathUtil ();
  35 use Atom;
  36 use Molecule;
  37 use MolecularDescriptors::MolecularDescriptors;
  38 use AtomTypes::TPSAAtomTypes;
  39 
  40 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  41 
  42 @ISA = qw(MolecularDescriptors::MolecularDescriptors Exporter);
  43 @EXPORT = qw();
  44 @EXPORT_OK = qw(GetDescriptorNames);
  45 
  46 %EXPORT_TAGS = (all  => [@EXPORT, @EXPORT_OK]);
  47 
  48 # Setup class variables...
  49 my($ClassName, @DescriptorNames);
  50 _InitializeClass();
  51 
  52 # Overload Perl functions...
  53 use overload '""' => 'StringifyTPSADescriptors';
  54 
  55 # Class constructor...
  56 sub new {
  57   my($Class, %NamesAndValues) = @_;
  58 
  59   # Initialize object...
  60   my $This = $Class->SUPER::new();
  61   bless $This, ref($Class) || $Class;
  62   $This->_InitializeTPSADescriptors();
  63 
  64   $This->_InitializeTPSADescriptorsProperties(%NamesAndValues);
  65 
  66   return $This;
  67 }
  68 
  69 # Initialize class ...
  70 sub _InitializeClass {
  71   #Class name...
  72   $ClassName = __PACKAGE__;
  73 
  74   # Descriptor names...
  75   @DescriptorNames = ('TPSA');
  76 
  77 }
  78 
  79 # Get descriptor names as an array.
  80 #
  81 # This functionality can be either invoked as a class function or an
  82 # object method.
  83 #
  84 sub GetDescriptorNames {
  85   return @DescriptorNames;
  86 }
  87 
  88 # Initialize object data...
  89 #
  90 sub _InitializeTPSADescriptors {
  91   my($This) = @_;
  92 
  93   # Type of MolecularDescriptor...
  94   $This->{Type} = 'TPSA';
  95 
  96   # By default, TPSA atom contributions from Phosphorus and Sulfur atoms
  97   # are not included during TPSA calculations. [ Ref 91 ]
  98   #
  99   $This->{IgnorePhosphorus} = 1;
 100   $This->{IgnoreSulfur} = 1;
 101 
 102   # TPSA atom types assigned to appropriate atoms...
 103   %{$This->{AtomTypes}} = ();
 104 
 105   # Intialize descriptor names and values...
 106   $This->_InitializeDescriptorNamesAndValues(@DescriptorNames);
 107 
 108   return $This;
 109 }
 110 
 111 # Initialize object properties...
 112 #
 113 sub _InitializeTPSADescriptorsProperties {
 114   my($This, %NamesAndValues) = @_;
 115 
 116   my($Name, $Value, $MethodName);
 117   while (($Name, $Value) = each  %NamesAndValues) {
 118     $MethodName = "Set${Name}";
 119     $This->$MethodName($Value);
 120   }
 121 
 122   return $This;
 123 }
 124 
 125 # Calculate Topological Polar Surface Area (TPSA) value [ Ref 90-91 ] for molecule...
 126 #
 127 # Methodology:
 128 #   . Assign TPSA atom types [ Ref 90-91 ] to Nitrogen and Oxygen
 129 #     atoms with optional assignment to Phosphorus and Sulfur atoms.
 130 #   . Calculate TPSA value adding contribution of appropriate atom types.
 131 #
 132 sub GenerateDescriptors {
 133   my($This) = @_;
 134 
 135   # Initialize descriptor values...
 136   $This->_InitializeDescriptorValues();
 137 
 138   # Check availability of molecule...
 139   if (!$This->{Molecule}) {
 140     carp "Warning: ${ClassName}->GenerateDescriptors: $This->{Type} molecular descriptors generation didn't succeed: Molecule data is not available: Molecule object hasn't been set...";
 141     return undef;
 142   }
 143 
 144   # Cache appropriate molecule data...
 145   $This->_SetupMoleculeDataCache();
 146 
 147   # Assign TPSA atom types...
 148   if (!$This->_AssignAtomTypes()) {
 149     carp "Warning: ${ClassName}->GenerateDescriptors: $This->{Type} molecular descriptors generation didn't succeed: Couldn't assign valid TPSA atom types to appropriate atoms...";
 150     return undef;
 151   }
 152 
 153   # Calculate descriptor values...
 154   if (!$This->_CalculateDescriptorValues()) {
 155     carp "Warning: ${ClassName}->GenerateDescriptors: $This->{Type} molecular descriptors generation didn't succeed: Couldn't calculate TPSA values corresponding to assigned TPSA atom types...";
 156     return undef;
 157   }
 158 
 159   # Set final descriptor values...
 160   $This->_SetFinalDescriptorValues();
 161 
 162   # Clear cached molecule data...
 163   $This->_ClearMoleculeDataCache();
 164 
 165   return $This;
 166 }
 167 
 168 # Assign TPSA atom types..
 169 #
 170 sub _AssignAtomTypes {
 171   my($This) = @_;
 172   my($TPSAAtomTypes, $Atom, $AtomID);
 173 
 174   %{$This->{AtomTypes}} = ();
 175 
 176   # Assign atom types...
 177   $TPSAAtomTypes = new AtomTypes::TPSAAtomTypes('Molecule' => $This->{Molecule}, 'IgnorePhosphorus' => $This->{IgnorePhosphorus}, 'IgnoreSulfur' => $This->{IgnoreSulfur});
 178   $TPSAAtomTypes->AssignAtomTypes();
 179 
 180   # Make sure TPSA atom types assignment is successful...
 181   if (!$TPSAAtomTypes->IsAtomTypesAssignmentSuccessful()) {
 182     return undef;
 183   }
 184 
 185   # Collect assigned atom types...
 186   for $Atom (@{$This->{Atoms}}) {
 187     $AtomID = $Atom->GetID();
 188     $This->{AtomTypes}{$AtomID} = $TPSAAtomTypes->GetAtomType($Atom);
 189   }
 190 
 191   return $This;
 192 }
 193 
 194 # Calculate TPSA value...
 195 #
 196 sub _CalculateDescriptorValues {
 197   my($This) = @_;
 198   my($Atom, $AtomID, $TPSA, $TPSAContribution, $TPSADataRef, $AtomType);
 199 
 200   $TPSA = 0;
 201 
 202   # Get TPSA atom types data...
 203   $TPSADataRef = AtomTypes::TPSAAtomTypes::GetTPSAAtomTypesData();
 204 
 205   ATOM: for $Atom (@{$This->{Atoms}}) {
 206     $AtomID = $Atom->GetID();
 207     $AtomType = $This->{AtomTypes}{$AtomID};
 208 
 209     # Ignore inappropriate atoms...
 210     if ($AtomType =~ /^None$/i) {
 211       next ATOM;
 212     }
 213 
 214     $TPSAContribution = 0.0;
 215 
 216     if ($AtomType =~ /^(N|O)$/i) {
 217       # TPSA contributions for Nitrogen and Oxygen atoms not explicity defined using atom
 218       # environments in Table 1 [ Ref 90 ]
 219       if ($AtomType =~ /^N$/i) {
 220         # N = 30.5 - X*8.2 + H*1.5 or 0.0 for negative value
 221         $TPSAContribution = 30.5 - $Atom->GetAtomicInvariantValue('X') * 8.2 + $Atom->GetAtomicInvariantValue('H') * 1.5;
 222       }
 223       elsif ($AtomType =~ /^O$/i) {
 224         # O = 28.5 - X*8.6 + H*1.5 or 0.0 for negative value
 225         $TPSAContribution = 28.5 - $Atom->GetAtomicInvariantValue('X') * 8.6 + $Atom->GetAtomicInvariantValue('H') * 1.5;
 226       }
 227       if ($TPSAContribution < 0.0) {
 228         $TPSAContribution = 0.0;
 229       }
 230     }
 231     elsif (exists $TPSADataRef->{DataCol3}{$AtomType}) {
 232       # Data for TPSA contribution is in column number 3...
 233       $TPSAContribution = $TPSADataRef->{DataCol3}{$AtomType};
 234     }
 235     else {
 236       # No TPSA data for assigned atom type...
 237       return undef;
 238     }
 239     $TPSA += $TPSAContribution;
 240   }
 241 
 242   # Track the calculated values...
 243   $This->{TPSA} = MathUtil::round($TPSA, 2);
 244 
 245   return $This;
 246 }
 247 
 248 # Setup final descriptor values...
 249 #
 250 sub _SetFinalDescriptorValues {
 251   my($This) = @_;
 252 
 253   $This->{DescriptorsGenerated} = 1;
 254 
 255   $This->SetDescriptorValues($This->{TPSA});
 256 
 257   return $This;
 258 }
 259 
 260 # Cache  appropriate molecule data...
 261 #
 262 sub _SetupMoleculeDataCache {
 263   my($This) = @_;
 264 
 265   @{$This->{Atoms}} = $This->GetMolecule()->GetAtoms();
 266 
 267   return $This;
 268 }
 269 
 270 # Clear cached molecule data...
 271 #
 272 sub _ClearMoleculeDataCache {
 273   my($This) = @_;
 274 
 275   @{$This->{Atoms}} = ();
 276 
 277   return $This;
 278 }
 279 
 280 # Return a string containg data for TPSADescriptors object...
 281 #
 282 sub StringifyTPSADescriptors {
 283   my($This) = @_;
 284   my($TPSADescriptorsString);
 285 
 286   # Type of MolecularDescriptors...
 287   $TPSADescriptorsString = "MolecularDescriptorType: $This->{Type}; IgnorePhosphorus: " . ($This->{IgnorePhosphorus} ? "Yes" : "No") . "; IgnoreSulfur: " .  ($This->{IgnoreSulfur} ? "Yes" : "No");
 288 
 289   # Setup molecular descriptor information...
 290   $TPSADescriptorsString .= "; " . $This->_StringifyDescriptorNamesAndValues();
 291 
 292   return $TPSADescriptorsString;
 293 }
 294 
 295 # Is it a TPSADescriptors object?
 296 sub _IsTPSADescriptors {
 297   my($Object) = @_;
 298 
 299   return (Scalar::Util::blessed($Object) && $Object->isa($ClassName)) ? 1 : 0;
 300 }
 301