       1 package MolecularDescriptors::MolecularDescriptors;
       2 #
       3 # File: MolecularDescriptors.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, %NamesAndValues) = @_;
      48
      49   # Initialize object...
      50   my $This = {};
      51   bless $This, ref($Class) || $Class;
      52   $This->_InitializeMolecularDescriptors();
      53
      54   $This->_InitializeMolecularDescriptorsProperties(%NamesAndValues);
      55
      56   return $This;
      57 }
      58
      59 # Initialize object data...
      60 #
      61 sub _InitializeMolecularDescriptors {
      62   my($This) = @_;
      63
      64   # Molecule object...
      65   $This->{Molecule} = '';
      66
      67   # Type of molecular descriptors...
      68   $This->{Type} = '';
      69
      70   # Names and calculated value of molecular descriptors...
      71   #
      72   # The specific descriptor class, derived from this base class, populate descriptor names and values
      73   # arrays...
      74   #
      75   @{$This->{DescriptorNames}} = ();
      76   @{$This->{DescriptorValues}} = ();
      77
      78   # Marks successful generation of descriptors...
      79   $This->{DescriptorsGenerated} = 0;
      80
      81 }
      82
      83 # Initialize class ...
      84 sub _InitializeClass {
      85   #Class name...
      86   $ClassName = __PACKAGE__;
      87 }
      88
      89
      90 # Initialize object properties....
      91 sub _InitializeMolecularDescriptorsProperties {
      92   my($This, %NamesAndValues) = @_;
      93
      94   my($Name, $Value, $MethodName);
      95   while (($Name, $Value) = each  %NamesAndValues) {
      96     $MethodName = "Set${Name}";
      97     $This->$MethodName($Value);
      98   }
      99
     100   return $This;
     101 }
     102
     103 # Initialize descriptor names and values...
     104 #
     105 sub _InitializeDescriptorNamesAndValues {
     106   my($This, @Names) = @_;
     107
     108   @{$This->{DescriptorNames}} = @Names;
     109
     110   $This->_InitializeDescriptorValues();
     111
     112   return $This;
     113 }
     114
     115 # Initialize descriptor values...
     116 #
     117 sub _InitializeDescriptorValues {
     118   my($This) = @_;
     119
     120   $This->{DescriptorsGenerated} = 0;
     121
     122   @{$This->{DescriptorValues}} = ();
     123
     124   return $This;
     125 }
     126
     127 # Set molecule object...
     128 #
     129 sub SetMolecule {
     130   my($This, $Molecule) = @_;
     131
     132   $This->{Molecule} = $Molecule;
     133
     134   # Weaken the reference to disable increment of reference count...
     135   Scalar::Util::weaken($This->{Molecule});
     136
     137   return $This;
     138 }
     139
     140 # Set type and make sure it's not already set...
     141 #
     142 sub SetType {
     143   my($This, $Type) = @_;
     144
     145   if ($This->{Type}) {
     146     croak "Error: ${ClassName}->SetType: Can't change MolecularDescriptors type:  It's already set...";
     147   }
     148   $This->{Type} = $Type;
     149
     150   return $This;
     151 }
     152
     153 # Get molecular descriptor names as an array...
     154 #
     155 sub GetDescriptorNames {
     156   my($This) = @_;
     157
     158   return @{$This->{DescriptorNames}};
     159 }
     160
     161 # Set descriptor names...
     162 #
     163 sub SetDescriptorNames {
     164   my($This, @Names) = @_;
     165
     166   @{$This->{DescriptorNames}} = @Names;
     167
     168   return $This;
     169 }
     170
     171 # Add descriptor names...
     172 #
     173 sub AddDescriptorNames {
     174   my($This, @Names) = @_;
     175
     176   push @{$This->{DescriptorNames}}, @Names;
     177
     178   return $This;
     179 }
     180
     181 # Set descriptor values...
     182 #
     183 sub SetDescriptorValues {
     184   my($This, @Values) = @_;
     185
     186   @{$This->{DescriptorValues}} = @Values;
     187
     188   return $This;
     189 }
     190
     191 # Add descriptor values...
     192 #
     193 sub AddDescriptorValues {
     194   my($This, @Values) = @_;
     195
     196   push @{$This->{DescriptorValues}}, @Values;
     197
     198   return $This;
     199 }
     200
     201 # Is descriptors generation successful?
     202 #
     203 # Notes:
     204 #   . The specific molecular descriptor class generation class sets the value of
     205 #     DescriptorsCalculated  to 1 after the successful generation of descriptors;
     206 #     otherwise, it's set to 0.
     207 #
     208 sub IsDescriptorsGenerationSuccessful {
     209   my($This) = @_;
     210
     211   return $This->{DescriptorsGenerated} ? 1 : 0;
     212 }
     213
     214 # Get all descriptor values as an array...
     215 #
     216 sub GetDescriptorValues {
     217   my($This) = @_;
     218
     219   if ($This->{DescriptorsGenerated}) {
     220     return wantarray ? @{$This->{DescriptorValues}} : scalar @{$This->{DescriptorValues}};
     221   }
     222   else {
     223     my(@DescriptorValues);
     224
     225     @DescriptorValues = ('None') x scalar @{$This->{DescriptorNames}};
     226
     227     return wantarray ? @DescriptorValues : scalar @DescriptorValues;
     228   }
     229 }
     230
     231 # Get descriptor value for a specified descriptor name...
     232 #
     233 sub GetDescriptorValueByName {
     234   my($This, $Name) = @_;
     235   my(%NamesAndValues);
     236
     237   %NamesAndValues = $This->GetDescriptorNamesAndValues();
     238
     239   return exists $NamesAndValues{$Name} ? $NamesAndValues{$Name} : 'None';
     240
     241 }
     242
     243 # Get calculated molecular descriptor names sand values as a to a hash with names
     244 # and values as key/value pairs...
     245 #
     246 sub GetDescriptorNamesAndValues {
     247   my($This) = @_;
     248   my(%NamesAndValues);
     249
     250   %NamesAndValues = ();
     251   @NamesAndValues{ @{$This->{DescriptorNames}} } = $This->GetDescriptorValues();
     252
     253   return %NamesAndValues;
     254 }
     255
     256 # Return a string containing descriptor names and values...
     257 #
     258 sub _StringifyDescriptorNamesAndValues {
     259   my($This) = @_;
     260   my($NamesAndValuesString, $Name, $Value, @NamesAndValuesInfo, %NamesAndValues);
     261
     262   @NamesAndValuesInfo = ();
     263   %NamesAndValues = $This->GetDescriptorNamesAndValues();
     264
     265   for $Name (@{$This->{DescriptorNames}}) {
     266     $Value = $NamesAndValues{$Name};
     267     $Value = (TextUtil::IsEmpty($Value) || $Value =~ /^None$/i) ? 'None' : $Value;
     268     push @NamesAndValuesInfo, "$Name - $Value";
     269   }
     270   if (@NamesAndValuesInfo) {
     271     $NamesAndValuesString = "Names - Values: <" . TextUtil::JoinWords(\@NamesAndValuesInfo, ", ", 0) . ">";
     272   }
     273   else {
     274     $NamesAndValuesString = "Names - Values: < None>";
     275   }
     276   return $NamesAndValuesString;
     277 }
     278