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