       1 package MolecularDescriptors::SLogPAndSMRDescriptors;
       2 #
       3 # $RCSfile: SLogPAndSMRDescriptors.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::SLogPAtomTypes;
      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 '""' => 'StringifySLogPAndSMRDescriptors';
      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->_InitializeSLogPAndSMRDescriptors();
      63
      64   $This->_InitializeSLogPAndSMRDescriptorsProperties(%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 = ('SLogP', 'SMR');
      76 }
      77
      78 # Get descriptor names as an array.
      79 #
      80 # This functionality can be either invoked as a class function or an
      81 # object method.
      82 #
      83 sub GetDescriptorNames {
      84   return @DescriptorNames;
      85 }
      86
      87 # Initialize object data...
      88 #
      89 sub _InitializeSLogPAndSMRDescriptors {
      90   my($This) = @_;
      91
      92   # Type of MolecularDescriptor...
      93   $This->{Type} = 'SLogPAndSMR';
      94
      95   # SLogPAndSMR atom types assigned to hydrogen and non-hydrogen atoms...
      96   %{$This->{AtomTypes}} = ();
      97
      98   # Intialize descriptor names and values...
      99   $This->_InitializeDescriptorNamesAndValues(@DescriptorNames);
     100
     101   return $This;
     102 }
     103
     104 # Initialize object properties...
     105 #
     106 sub _InitializeSLogPAndSMRDescriptorsProperties {
     107   my($This, %NamesAndValues) = @_;
     108
     109   my($Name, $Value, $MethodName);
     110   while (($Name, $Value) = each  %NamesAndValues) {
     111     $MethodName = "Set${Name}";
     112     $This->$MethodName($Value);
     113   }
     114
     115   return $This;
     116 }
     117
     118
     119 # Calculate SLogPAndSMR value [ Ref 89 ] for a molecule...
     120 #
     121 # Methodology:
     122 #   . Assign SLogP atom types to all atoms.
     123 #   . Calculate SLogP and SMR value by adding contribution of each atom type.
     124 #
     125 # Caveats:
     126 #   . All hydrogens must be added to molecule before calling GenerateDescriptors.
     127 #
     128 sub GenerateDescriptors {
     129   my($This) = @_;
     130
     131   # Initialize descriptor values...
     132   $This->_InitializeDescriptorValues();
     133
     134   # Check availability of molecule...
     135   if (!$This->{Molecule}) {
     136     carp "Warning: ${ClassName}->GenerateDescriptors: $This->{Type} molecular descriptors generation didn't succeed: Molecule data is not available: Molecule object hasn't been set...";
     137     return undef;
     138   }
     139
     140   # Cache appropriate molecule data...
     141   $This->_SetupMoleculeDataCache();
     142
     143   # Assign SLogP atom types...
     144   if (!$This->_AssignAtomTypes()) {
     145     carp "Warning: ${ClassName}->GenerateDescriptors: $This->{Type} molecular descriptors generation didn't succeed: Couldn't assign valid SLogPAndSMR atom types to all atoms...";
     146     return undef;
     147   }
     148
     149   # Calculate descriptor values...
     150   if (!$This->_CalculateDescriptorValues()) {
     151     carp "Warning: ${ClassName}->GenerateDescriptors: $This->{Type} molecular description generation didn't succeed: Couldn't calculate SLogPAndSMR values corresponding to assigned SLogP atom types...";
     152     return undef;
     153   }
     154
     155   # Set final descriptor values...
     156   $This->_SetFinalDescriptorValues();
     157
     158   # Clear cached molecule data...
     159   $This->_ClearMoleculeDataCache();
     160
     161   return $This;
     162 }
     163
     164 # Assign SLogPAndSMR atom types..
     165 #
     166 sub _AssignAtomTypes {
     167   my($This) = @_;
     168   my($SLogPAtomTypes, $Atom, $AtomID);
     169
     170   %{$This->{AtomTypes}} = ();
     171
     172   # Assign atom types...
     173   $SLogPAtomTypes = new AtomTypes::SLogPAtomTypes('Molecule' => $This->{Molecule}, 'IgnoreHydrogens' => 0);
     174   $SLogPAtomTypes->AssignAtomTypes();
     175
     176   # Make sure SLogP atom types assignment is successful...
     177   if (!$SLogPAtomTypes->IsAtomTypesAssignmentSuccessful()) {
     178     return undef;
     179   }
     180
     181   # Collect assigned atom types...
     182   for $Atom (@{$This->{Atoms}}) {
     183     $AtomID = $Atom->GetID();
     184     $This->{AtomTypes}{$AtomID} = $SLogPAtomTypes->GetAtomType($Atom);
     185   }
     186
     187   return $This;
     188 }
     189
     190 # Calculate SLogP and SMR values...
     191 #
     192 sub _CalculateDescriptorValues {
     193   my($This) = @_;
     194   my($SLogP, $SMR, $AtomID, $SLogPAndSMRDataRef, $AtomType);
     195
     196   $SLogP = 0; $SMR = 0;
     197
     198   # Get SLogP and SMR atom types data...
     199   $SLogPAndSMRDataRef = AtomTypes::SLogPAtomTypes::GetSLogPAtomTypesData();
     200
     201   for $AtomID (keys %{$This->{AtomTypes}}) {
     202     $AtomType = $This->{AtomTypes}{$AtomID};
     203
     204     # Makes sure data for SLogp and SMR contribution exists for atom type...
     205     if (!(exists($SLogPAndSMRDataRef->{DataCol4}{$AtomType}) && exists($SLogPAndSMRDataRef->{DataCol5}{$AtomType}))) {
     206       return undef;
     207     }
     208
     209     # Data for SLogP contribution is in column number 4...
     210     $SLogP += $SLogPAndSMRDataRef->{DataCol4}{$AtomType};
     211
     212     # Data for SMR contribution is in column number 5...
     213     $SMR += $SLogPAndSMRDataRef->{DataCol5}{$AtomType};
     214   }
     215
     216   # Track the calculated values...
     217   $This->{SLogP} = MathUtil::round($SLogP, 2);
     218   $This->{SMR} = MathUtil::round($SMR, 2);
     219
     220   return $This;
     221 }
     222
     223 # Setup final descriptor values...
     224 #
     225 sub _SetFinalDescriptorValues {
     226   my($This) = @_;
     227
     228   $This->{DescriptorsGenerated} = 1;
     229
     230   $This->SetDescriptorValues($This->{SLogP}, $This->{SMR});
     231
     232   return $This;
     233 }
     234
     235 # Cache  appropriate molecule data...
     236 #
     237 sub _SetupMoleculeDataCache {
     238   my($This) = @_;
     239
     240   @{$This->{Atoms}} = $This->GetMolecule()->GetAtoms();
     241
     242   return $This;
     243 }
     244
     245 # Clear cached molecule data...
     246 #
     247 sub _ClearMoleculeDataCache {
     248   my($This) = @_;
     249
     250   @{$This->{Atoms}} = ();
     251
     252   return $This;
     253 }
     254
     255 # Return a string containg data for SLogPAndSMRDescriptors object...
     256 #
     257 sub StringifySLogPAndSMRDescriptors {
     258   my($This) = @_;
     259   my($SLogPAndSMRDescriptorsString);
     260
     261   $SLogPAndSMRDescriptorsString = "MolecularDescriptorType: $This->{Type}; "  . $This->_StringifyDescriptorNamesAndValues();
     262
     263   return $SLogPAndSMRDescriptorsString;
     264 }
     265
     266 # Is it a SLogPAndSMRDescriptors object?
     267 sub _IsSLogPAndSMRDescriptors {
     268   my($Object) = @_;
     269
     270   return (Scalar::Util::blessed($Object) && $Object->isa($ClassName)) ? 1 : 0;
     271 }
     272