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