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