MayaChemTools

   1 package MolecularDescriptors::SLogPAndSMRDescriptors;
   2 #
   3 # File: SLogPAndSMRDescriptors.pm
   4 # Author: Manish Sud <msud@san.rr.com>
   5 #
   6 # Copyright (C) 2024 Manish Sud. All rights reserved.
   7 #
   8 # This file is part of MayaChemTools.
   9 #
  10 # MayaChemTools is free software; you can redistribute it and/or modify it under
  11 # the terms of the GNU Lesser General Public License as published by the Free
  12 # Software Foundation; either version 3 of the License, or (at your option) any
  13 # later version.
  14 #
  15 # MayaChemTools is distributed in the hope that it will be useful, but without
  16 # any warranty; without even the implied warranty of merchantability of fitness
  17 # for a particular purpose.  See the GNU Lesser General Public License for more
  18 # details.
  19 #
  20 # You should have received a copy of the GNU Lesser General Public License
  21 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
  22 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
  23 # Boston, MA, 02111-1307, USA.
  24 #
  25 
  26 use strict;
  27 use Carp;
  28 use Exporter;
  29 use Scalar::Util ();
  30 use TextUtil ();
  31 use MathUtil ();
  32 use Atom;
  33 use Molecule;
  34 use MolecularDescriptors::MolecularDescriptors;
  35 use AtomTypes::SLogPAtomTypes;
  36 
  37 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  38 
  39 @ISA = qw(MolecularDescriptors::MolecularDescriptors Exporter);
  40 @EXPORT = qw();
  41 @EXPORT_OK = qw(GetDescriptorNames);
  42 
  43 %EXPORT_TAGS = (all  => [@EXPORT, @EXPORT_OK]);
  44 
  45 # Setup class variables...
  46 my($ClassName, @DescriptorNames);
  47 _InitializeClass();
  48 
  49 # Overload Perl functions...
  50 use overload '""' => 'StringifySLogPAndSMRDescriptors';
  51 
  52 # Class constructor...
  53 sub new {
  54   my($Class, %NamesAndValues) = @_;
  55 
  56   # Initialize object...
  57   my $This = $Class->SUPER::new();
  58   bless $This, ref($Class) || $Class;
  59   $This->_InitializeSLogPAndSMRDescriptors();
  60 
  61   $This->_InitializeSLogPAndSMRDescriptorsProperties(%NamesAndValues);
  62 
  63   return $This;
  64 }
  65 
  66 # Initialize class ...
  67 sub _InitializeClass {
  68   #Class name...
  69   $ClassName = __PACKAGE__;
  70 
  71   # Descriptor names...
  72   @DescriptorNames = ('SLogP', 'SMR');
  73 }
  74 
  75 # Get descriptor names as an array.
  76 #
  77 # This functionality can be either invoked as a class function or an
  78 # object method.
  79 #
  80 sub GetDescriptorNames {
  81   return @DescriptorNames;
  82 }
  83 
  84 # Initialize object data...
  85 #
  86 sub _InitializeSLogPAndSMRDescriptors {
  87   my($This) = @_;
  88 
  89   # Type of MolecularDescriptor...
  90   $This->{Type} = 'SLogPAndSMR';
  91 
  92   # SLogPAndSMR atom types assigned to hydrogen and non-hydrogen atoms...
  93   %{$This->{AtomTypes}} = ();
  94 
  95   # Intialize descriptor names and values...
  96   $This->_InitializeDescriptorNamesAndValues(@DescriptorNames);
  97 
  98   return $This;
  99 }
 100 
 101 # Initialize object properties...
 102 #
 103 sub _InitializeSLogPAndSMRDescriptorsProperties {
 104   my($This, %NamesAndValues) = @_;
 105 
 106   my($Name, $Value, $MethodName);
 107   while (($Name, $Value) = each  %NamesAndValues) {
 108     $MethodName = "Set${Name}";
 109     $This->$MethodName($Value);
 110   }
 111 
 112   return $This;
 113 }
 114 
 115 
 116 # Calculate SLogPAndSMR value [ Ref 89 ] for a molecule...
 117 #
 118 # Methodology:
 119 #   . Assign SLogP atom types to all atoms.
 120 #   . Calculate SLogP and SMR value by adding contribution of each atom type.
 121 #
 122 # Caveats:
 123 #   . All hydrogens must be added to molecule before calling GenerateDescriptors.
 124 #
 125 sub GenerateDescriptors {
 126   my($This) = @_;
 127 
 128   # Initialize descriptor values...
 129   $This->_InitializeDescriptorValues();
 130 
 131   # Check availability of molecule...
 132   if (!$This->{Molecule}) {
 133     carp "Warning: ${ClassName}->GenerateDescriptors: $This->{Type} molecular descriptors generation didn't succeed: Molecule data is not available: Molecule object hasn't been set...";
 134     return undef;
 135   }
 136 
 137   # Cache appropriate molecule data...
 138   $This->_SetupMoleculeDataCache();
 139 
 140   # Assign SLogP atom types...
 141   if (!$This->_AssignAtomTypes()) {
 142     carp "Warning: ${ClassName}->GenerateDescriptors: $This->{Type} molecular descriptors generation didn't succeed: Couldn't assign valid SLogPAndSMR atom types to all atoms...";
 143     return undef;
 144   }
 145 
 146   # Calculate descriptor values...
 147   if (!$This->_CalculateDescriptorValues()) {
 148     carp "Warning: ${ClassName}->GenerateDescriptors: $This->{Type} molecular description generation didn't succeed: Couldn't calculate SLogPAndSMR values corresponding to assigned SLogP atom types...";
 149     return undef;
 150   }
 151 
 152   # Set final descriptor values...
 153   $This->_SetFinalDescriptorValues();
 154 
 155   # Clear cached molecule data...
 156   $This->_ClearMoleculeDataCache();
 157 
 158   return $This;
 159 }
 160 
 161 # Assign SLogPAndSMR atom types..
 162 #
 163 sub _AssignAtomTypes {
 164   my($This) = @_;
 165   my($SLogPAtomTypes, $Atom, $AtomID);
 166 
 167   %{$This->{AtomTypes}} = ();
 168 
 169   # Assign atom types...
 170   $SLogPAtomTypes = new AtomTypes::SLogPAtomTypes('Molecule' => $This->{Molecule}, 'IgnoreHydrogens' => 0);
 171   $SLogPAtomTypes->AssignAtomTypes();
 172 
 173   # Make sure SLogP atom types assignment is successful...
 174   if (!$SLogPAtomTypes->IsAtomTypesAssignmentSuccessful()) {
 175     return undef;
 176   }
 177 
 178   # Collect assigned atom types...
 179   for $Atom (@{$This->{Atoms}}) {
 180     $AtomID = $Atom->GetID();
 181     $This->{AtomTypes}{$AtomID} = $SLogPAtomTypes->GetAtomType($Atom);
 182   }
 183 
 184   return $This;
 185 }
 186 
 187 # Calculate SLogP and SMR values...
 188 #
 189 sub _CalculateDescriptorValues {
 190   my($This) = @_;
 191   my($SLogP, $SMR, $AtomID, $SLogPAndSMRDataRef, $AtomType);
 192 
 193   $SLogP = 0; $SMR = 0;
 194 
 195   # Get SLogP and SMR atom types data...
 196   $SLogPAndSMRDataRef = AtomTypes::SLogPAtomTypes::GetSLogPAtomTypesData();
 197 
 198   for $AtomID (keys %{$This->{AtomTypes}}) {
 199     $AtomType = $This->{AtomTypes}{$AtomID};
 200 
 201     # Makes sure data for SLogp and SMR contribution exists for atom type...
 202     if (!(exists($SLogPAndSMRDataRef->{DataCol4}{$AtomType}) && exists($SLogPAndSMRDataRef->{DataCol5}{$AtomType}))) {
 203       return undef;
 204     }
 205 
 206     # Data for SLogP contribution is in column number 4...
 207     $SLogP += $SLogPAndSMRDataRef->{DataCol4}{$AtomType};
 208 
 209     # Data for SMR contribution is in column number 5...
 210     $SMR += $SLogPAndSMRDataRef->{DataCol5}{$AtomType};
 211   }
 212 
 213   # Track the calculated values...
 214   $This->{SLogP} = MathUtil::round($SLogP, 2);
 215   $This->{SMR} = MathUtil::round($SMR, 2);
 216 
 217   return $This;
 218 }
 219 
 220 # Setup final descriptor values...
 221 #
 222 sub _SetFinalDescriptorValues {
 223   my($This) = @_;
 224 
 225   $This->{DescriptorsGenerated} = 1;
 226 
 227   $This->SetDescriptorValues($This->{SLogP}, $This->{SMR});
 228 
 229   return $This;
 230 }
 231 
 232 # Cache  appropriate molecule data...
 233 #
 234 sub _SetupMoleculeDataCache {
 235   my($This) = @_;
 236 
 237   @{$This->{Atoms}} = $This->GetMolecule()->GetAtoms();
 238 
 239   return $This;
 240 }
 241 
 242 # Clear cached molecule data...
 243 #
 244 sub _ClearMoleculeDataCache {
 245   my($This) = @_;
 246 
 247   @{$This->{Atoms}} = ();
 248 
 249   return $This;
 250 }
 251 
 252 # Return a string containg data for SLogPAndSMRDescriptors object...
 253 #
 254 sub StringifySLogPAndSMRDescriptors {
 255   my($This) = @_;
 256   my($SLogPAndSMRDescriptorsString);
 257 
 258   $SLogPAndSMRDescriptorsString = "MolecularDescriptorType: $This->{Type}; "  . $This->_StringifyDescriptorNamesAndValues();
 259 
 260   return $SLogPAndSMRDescriptorsString;
 261 }
 262 
 263 # Is it a SLogPAndSMRDescriptors object?
 264 sub _IsSLogPAndSMRDescriptors {
 265   my($Object) = @_;
 266 
 267   return (Scalar::Util::blessed($Object) && $Object->isa($ClassName)) ? 1 : 0;
 268 }
 269