MayaChemTools

   1 package MolecularDescriptors::MolecularVolumeDescriptors;
   2 #
   3 # $RCSfile: MolecularVolumeDescriptors.pm,v $
   4 # $Date: 2015/02/28 20:49:20 $
   5 # $Revision: 1.16 $
   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 AtomTypes::AtomTypes;
  38 use MolecularDescriptors::MolecularDescriptors;
  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 GetVDWAtomRadiiAndVolumesData);
  45 
  46 %EXPORT_TAGS = (all  => [@EXPORT, @EXPORT_OK]);
  47 
  48 # Setup class variables...
  49 my($ClassName, @DescriptorNames, %VDWAtomRadiiAndVolumesDataMap);
  50 _InitializeClass();
  51 
  52 # Overload Perl functions...
  53 use overload '""' => 'StringifyMolecularVolumeDescriptors';
  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->_InitializeMolecularVolumeDescriptors();
  63 
  64   $This->_InitializeMolecularVolumeDescriptorsProperties(%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 = ('MolecularVolume');
  76 
  77   # Initialize the data hash. It'll be loaded on demand later...
  78   %VDWAtomRadiiAndVolumesDataMap = ();
  79 
  80 }
  81 
  82 # Get descriptor names as an array.
  83 #
  84 # This functionality can be either invoked as a class function or an
  85 # object method.
  86 #
  87 sub GetDescriptorNames {
  88   return @DescriptorNames;
  89 }
  90 
  91 # Initialize object data...
  92 #
  93 sub _InitializeMolecularVolumeDescriptors {
  94   my($This) = @_;
  95 
  96   # Type of MolecularDescriptor...
  97   $This->{Type} = 'MolecularVolume';
  98 
  99   # Intialize descriptor names and values...
 100   $This->_InitializeDescriptorNamesAndValues(@DescriptorNames);
 101 
 102   return $This;
 103 }
 104 
 105 # Initialize object properties...
 106 #
 107 sub _InitializeMolecularVolumeDescriptorsProperties {
 108   my($This, %NamesAndValues) = @_;
 109 
 110   my($Name, $Value, $MethodName);
 111   while (($Name, $Value) = each  %NamesAndValues) {
 112     $MethodName = "Set${Name}";
 113     $This->$MethodName($Value);
 114   }
 115 
 116   return $This;
 117 }
 118 
 119 # Get VDW atom data loaded from VDW atom radii and and volumes data file as
 120 # a reference to hash with the following hash data format:
 121 #
 122 # @{$VDWAtomRadiiAndVolumesDataMap{AtomTypes}} - Array of all possible atom type symbols for all atoms
 123 # @{$VDWAtomRadiiAndVolumesDataMap->{ColLabels}} - Array of column labels
 124 # %{$VDWAtomRadiiAndVolumesDataMap->{DataCol<Num>}} - Hash keys pair: <DataCol<Num>, AtomType>
 125 #
 126 # This functionality can be either invoked as a class function or an
 127 # object method.
 128 #
 129 sub GetVDWAtomRadiiAndVolumesData {
 130 
 131   # Make sure data is loaded...
 132   _CheckAndLoadVDWAtomRadiiAndVolumesData();
 133 
 134   return \%VDWAtomRadiiAndVolumesDataMap;
 135 }
 136 
 137 # Calculate van der Waals molecular volume [ Ref 93 ] of a molecule using
 138 # atomic and bonds contributions...
 139 #
 140 # van der Waals molecular volume (A**3/molecule) is defined as:
 141 #
 142 # vdwMolecularVolume = SumOfAtomicVDWVolumeContributions - 5.92 * NumOfBonds
 143 #                      - 14.7 * NumOfAromaticRings - 3.8 * NumOfNonAromaticRings
 144 #
 145 # Methodology:
 146 #   . Add up van der Waals atom volumne of all atoms
 147 #   . Calculate molecular volume by correcting sum of atom volumes for num of
 148 #     bonds and rings
 149 #
 150 # Caveats:
 151 #   . All hydrogens must be added to molecule before calling GenerateDescriptors.
 152 #
 153 sub GenerateDescriptors {
 154   my($This) = @_;
 155 
 156   # Initialize descriptor values...
 157   $This->_InitializeDescriptorValues();
 158 
 159   # Check availability of molecule...
 160   if (!$This->{Molecule}) {
 161     carp "Warning: ${ClassName}->GenerateDescriptors: $This->{Type} molecular descriptors generation didn't succeed: Molecule data is not available: Molecule object hasn't been set...";
 162     return undef;
 163   }
 164 
 165   # Calculate descriptor values...
 166   if (!$This->_CalculateDescriptorValues()) {
 167     carp "Warning: ${ClassName}->GenerateDescriptors: $This->{Type} molecular descriptors generation didn't succeed: Couldn't calculate MolecularVolume values: van der Waals atom volume data is not available for all atoms...";
 168     return undef;
 169   }
 170 
 171   # Set final descriptor values...
 172   $This->_SetFinalDescriptorValues();
 173 
 174   return $This;
 175 }
 176 
 177 # Calculate MolecularVolume value...
 178 #
 179 sub _CalculateDescriptorValues {
 180   my($This) = @_;
 181   my($Atom, $AtomID, $AtomSymbol, $SumOfVDWAtomVolumes, $Molecule, $MolecularVolume, $NumOfBonds, $NumOfAromaticRings, $NumOfNonAromaticRings, $VDWAtomRadiiAndVolumesDataMapRef);
 182 
 183   $MolecularVolume = 0;
 184 
 185   $VDWAtomRadiiAndVolumesDataMapRef = $This->GetVDWAtomRadiiAndVolumesData();
 186   $Molecule = $This->{Molecule};
 187 
 188   # Calculate atom volumes contribution to molecular volume...
 189   #
 190   $SumOfVDWAtomVolumes = 0;
 191 
 192   ATOM: for $Atom ($Molecule->GetAtoms()) {
 193     $AtomID = $Atom->GetID();
 194     $AtomSymbol = $Atom->GetAtomSymbol();
 195 
 196     # Make sure van der Waals atom volume is available...
 197     if (!exists $VDWAtomRadiiAndVolumesDataMap{DataCol3}{$AtomSymbol}) {
 198       return undef;
 199     }
 200     $SumOfVDWAtomVolumes += $VDWAtomRadiiAndVolumesDataMapRef->{DataCol3}{$AtomSymbol};
 201   }
 202 
 203   $NumOfBonds = $Molecule->GetNumOfBonds();
 204   $NumOfAromaticRings = $Molecule->GetNumOfAromaticRings();
 205   $NumOfNonAromaticRings = $Molecule->GetNumOfRings() - $NumOfAromaticRings;
 206 
 207   # Apply correction for bonds and rings...
 208   $MolecularVolume = $SumOfVDWAtomVolumes - 5.92 * $NumOfBonds - 14.7 * $NumOfAromaticRings - 3.8 * $NumOfNonAromaticRings;
 209 
 210   # Track the calculated values...
 211   $This->{MolecularVolume} = MathUtil::round($MolecularVolume, 2);
 212 
 213   return $This;
 214 }
 215 
 216 # Setup final descriptor values...
 217 #
 218 sub _SetFinalDescriptorValues {
 219   my($This) = @_;
 220 
 221   $This->{DescriptorsGenerated} = 1;
 222 
 223   $This->SetDescriptorValues($This->{MolecularVolume});
 224 
 225   return $This;
 226 }
 227 
 228 # Return a string containg data for MolecularVolumeDescriptors object...
 229 #
 230 sub StringifyMolecularVolumeDescriptors {
 231   my($This) = @_;
 232   my($MolecularVolumeDescriptorsString);
 233 
 234   $MolecularVolumeDescriptorsString = "MolecularDescriptorType: $This->{Type}; " . $This->_StringifyDescriptorNamesAndValues();
 235 
 236   return $MolecularVolumeDescriptorsString;
 237 }
 238 
 239 # Is it a MolecularVolumeDescriptors object?
 240 sub _IsMolecularVolumeDescriptors {
 241   my($Object) = @_;
 242 
 243   return (Scalar::Util::blessed($Object) && $Object->isa($ClassName)) ? 1 : 0;
 244 }
 245 
 246 # Check and load van der Waals atom radii and volumes data...
 247 #
 248 sub _CheckAndLoadVDWAtomRadiiAndVolumesData {
 249 
 250   # Is it already loaded?
 251   if (exists $VDWAtomRadiiAndVolumesDataMap{AtomTypes}) {
 252     return;
 253   }
 254 
 255   _LoadVDWAtomRadiiAndVolumesData();
 256 }
 257 
 258 # Initialize van der Waals atom radii and volumes data from the file...
 259 #
 260 # Format:
 261 #
 262 # "AtomTypeSymbol","VDWAtomRadius(A)","VDWAtomVolume(A**3)/molecule"
 263 # "H","1.20","7.24"
 264 # "He","1.40","11.49"
 265 #
 266 sub  _LoadVDWAtomRadiiAndVolumesData {
 267   my($VDWAtomDataFile, $MayaChemToolsLibDir);
 268 
 269   $MayaChemToolsLibDir = FileUtil::GetMayaChemToolsLibDirName();
 270 
 271   $VDWAtomDataFile =  "$MayaChemToolsLibDir" . "/data/VDWAtomRadiiAndVolumes.csv";
 272   if (! -e "$VDWAtomDataFile") {
 273     croak "Error: MayaChemTools package file, $VDWAtomDataFile, is missing: Possible installation problems...";
 274   }
 275 
 276   %VDWAtomRadiiAndVolumesDataMap = ();
 277   AtomTypes::AtomTypes::LoadAtomTypesData($VDWAtomDataFile, \%VDWAtomRadiiAndVolumesDataMap);
 278 };
 279