       1 package AtomicDescriptors::AtomicDescriptors;
       2 #
       3 # $RCSfile: AtomicDescriptors.pm,v $
       4 # $Date: 2015/02/28 20:47:48 $
       5 # $Revision: 1.17 $
       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 ObjectProperty;
      34 use TextUtil ();
      35
      36 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
      37
      38 @ISA = qw(ObjectProperty Exporter);
      39 @EXPORT = qw();
      40 @EXPORT_OK = qw();
      41
      42 %EXPORT_TAGS = (all  => [@EXPORT, @EXPORT_OK]);
      43
      44 # Setup class variables...
      45 my($ClassName);
      46 _InitializeClass();
      47
      48 # Class constructor...
      49 sub new {
      50   my($Class, %PropertyNamesAndValues) = @_;
      51
      52   # Initialize object...
      53   my $This = {};
      54   bless $This, ref($Class) || $Class;
      55   $This->_InitializeAtomicDescriptors();
      56
      57   $This->_InitializeAtomicDescriptorsProperties(%PropertyNamesAndValues);
      58
      59   return $This;
      60 }
      61
      62 # Initialize object data...
      63 #
      64 sub _InitializeAtomicDescriptors {
      65   my($This) = @_;
      66
      67   # Molecule object...
      68   $This->{Molecule} = '';
      69
      70   # Type of atomic descriptors...
      71   $This->{Type} = '';
      72
      73   # By default, atomic decriptor values are also calculated for hydrogens...
      74   $This->{IgnoreHydrogens} = 0;
      75
      76   # Calculated atomic descriptor values hash. Instead of assigning the calculated values to Atom
      77   # objects, these values are stored in the current object in a hash with atom ID and atomic descriptor
      78   # values as key/value pairs.
      79   #
      80   # Unlike molecular descriptors, no descriptor names are assigned to individual atomic descriptor
      81   # values.
      82   #
      83   %{$This->{DescriptorValues}} = ();
      84 }
      85
      86 # Initialize class ...
      87 sub _InitializeClass {
      88   #Class name...
      89   $ClassName = __PACKAGE__;
      90 }
      91
      92 # Initialize object properties....
      93 sub _InitializeAtomicDescriptorsProperties {
      94   my($This, %PropertiesNamesAndValues) = @_;
      95
      96   my($Name, $Value, $MethodName);
      97   while (($Name, $Value) = each  %PropertiesNamesAndValues) {
      98     $MethodName = "Set${Name}";
      99     $This->$MethodName($Value);
     100   }
     101
     102   return $This;
     103 }
     104
     105 # Initialize descriptor values for all atoms in a molecule...
     106 #
     107 sub _InitializeDescriptorValues {
     108   my($This) = @_;
     109
     110   if (!$This->{Molecule}) {
     111     return $This;
     112   }
     113
     114   # Assign 'None' to all atomic descriptor values...
     115   #
     116   my($Atom, $AtomID);
     117
     118   ATOM: for $Atom ($This->{Molecule}->GetAtoms()) {
     119     $AtomID = $Atom->GetID();
     120     $This->{DescriptorValues}{$AtomID} = 'None';
     121   }
     122
     123   return $This;
     124 }
     125
     126 # Set molecule object and make sure it's not already set...
     127 #
     128 sub SetMolecule {
     129   my($This, $Molecule) = @_;
     130
     131   if ($This->{Molecule}) {
     132     croak "Error: ${ClassName}->SetMolecule: Can't change molecule object:  It's already set...";
     133   }
     134   $This->{Molecule} = $Molecule;
     135
     136   # Weaken the reference to disable increment of reference count...
     137   Scalar::Util::weaken($This->{Molecule});
     138
     139   return $This;
     140 }
     141
     142 # Set type and make sure it's not already set...
     143 #
     144 sub SetType {
     145   my($This, $Type) = @_;
     146
     147   if ($This->{Type}) {
     148     croak "Error: ${ClassName}->SetType: Can't change AtomicDescriptors type:  It's already set...";
     149   }
     150   $This->{Type} = $Type;
     151
     152   return $This;
     153 }
     154
     155 # Set specific atomic descriptor value...
     156 #
     157 sub SetDescriptorValue {
     158   my($This, $Atom, $AtomicDescriptor) = @_;
     159   my($AtomID);
     160
     161   $AtomID = $Atom->GetID();
     162   $This->{DescriptorValues}{$AtomID} = $AtomicDescriptor;
     163
     164   return $This;
     165 }
     166
     167 # Get specific atomic descriptor value...
     168 #
     169 sub GetDescriptorValue {
     170   my($This, $Atom) = @_;
     171   my($AtomID);
     172
     173   $AtomID = $Atom->GetID();
     174
     175   return exists $This->{DescriptorValues}{$AtomID} ? $This->{DescriptorValues}{$AtomID} : 'None';
     176 }
     177
     178 # Get calculated atomic descriptor values as a  hash with atom ID and atomic descriptor
     179 # values as key/value pairs...
     180 #
     181 sub GetDescriptorValues {
     182   my($This) = @_;
     183
     184   return %{$This->{DescriptorValues}};
     185 }
     186
     187 # Are all atomic descriptor values successfully calculated?
     188 #
     189 # Notes:
     190 #   . Dynamic checking of calculated descriptor values for atoms eliminates the need
     191 #     to check and synchronize valid descriptor values during SetDescriptorValue.
     192 #
     193 sub IsDescriptorsGenerationSuccessful {
     194   my($This) = @_;
     195   my($Atom, $DescriptorValue, @Atoms);
     196
     197   ATOM: for $Atom ($This->{Molecule}->GetAtoms()) {
     198     if ($This->{IgnoreHydrogens} && $Atom->IsHydrogen()) {
     199       next ATOM;
     200     }
     201     $DescriptorValue = $This->GetDescriptorValue($Atom);
     202     if ($DescriptorValue =~ /^None$/i) {
     203       return 0;
     204     }
     205   }
     206
     207   return 1;
     208 }
     209