       1 package AtomTypes::EStateAtomTypes;
       2 #
       3 # $RCSfile: EStateAtomTypes.pm,v $
       4 # $Date: 2015/02/28 20:48:03 $
       5 # $Revision: 1.21 $
       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 AtomTypes::AtomTypes;
      34 use Molecule;
      35
      36 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
      37
      38 @ISA = qw(AtomTypes::AtomTypes Exporter);
      39 @EXPORT = qw(GetEStateAtomTypesData GetAllPossibleEStateAtomTypes GetAllPossibleEStateNonHydrogenAtomTypes);
      40 @EXPORT_OK = qw();
      41
      42 %EXPORT_TAGS = (all  => [@EXPORT, @EXPORT_OK]);
      43
      44 # Setup class variables...
      45 my($ClassName, %EStateAtomTypesDataMap);
      46 _InitializeClass();
      47
      48 # Overload Perl functions...
      49 use overload '""' => 'StringifyEStateAtomTypes';
      50
      51 # Class constructor...
      52 sub new {
      53   my($Class, %NamesAndValues) = @_;
      54
      55   # Initialize object...
      56   my $This = $Class->SUPER::new();
      57   bless $This, ref($Class) || $Class;
      58   $This->_InitializeEStateAtomTypes();
      59
      60   $This->_InitializeEStateAtomTypesProperties(%NamesAndValues);
      61
      62   return $This;
      63 }
      64
      65 # Initialize class ...
      66 sub _InitializeClass {
      67   #Class name...
      68   $ClassName = __PACKAGE__;
      69
      70   # Initialize the data hash. It'll be loaded on demand later...
      71   %EStateAtomTypesDataMap = ();
      72 }
      73
      74 # Initialize object data...
      75 #
      76 sub _InitializeEStateAtomTypes {
      77   my($This) = @_;
      78
      79   # Type of AtomTypes...
      80   $This->{Type} = 'EState';
      81
      82   # By default, EState atom types are also assigned to hydrogens...
      83   $This->{IgnoreHydrogens} = 0;
      84
      85   return $This;
      86 }
      87
      88 # Initialize object properties...
      89 #
      90 sub _InitializeEStateAtomTypesProperties {
      91   my($This, %NamesAndValues) = @_;
      92
      93   my($Name, $Value, $MethodName);
      94   while (($Name, $Value) = each  %NamesAndValues) {
      95     $MethodName = "Set${Name}";
      96     $This->$MethodName($Value);
      97   }
      98
      99   # Make sure molecule object was specified...
     100   if (!exists $NamesAndValues{Molecule}) {
     101     croak "Error: ${ClassName}->New: Object can't be instantiated without specifying molecule...";
     102   }
     103
     104   return $This;
     105 }
     106
     107 # Get EState atom types and associated data loaded from EState data file as
     108 # a reference to hash with the following hash data format:
     109 #
     110 # @{$EStateAtomTypesDataMap{AtomTypes}} - Array of all possible atom types for all atoms
     111 # @{$EStateAtomTypesDataMap{NonHydrogenAtomTypes}} - Array of all possible atom types for non-hydrogen atoms
     112 # @{$EStateAtomTypesDataMap->{ColLabels}} - Array of column labels
     113 # %{$EStateAtomTypesDataMap->{DataCol<Num>}} - Hash keys pair: <DataCol<Num>, AtomType>
     114 #
     115 # This functionality can be either invoked as a class function or an
     116 # object method.
     117 #
     118 sub GetEStateAtomTypesData {
     119
     120   # Make sure data is loaded...
     121   _CheckAndLoadEStateAtomTypesData();
     122
     123   return \%EStateAtomTypesDataMap;
     124 }
     125
     126 # Get all possible E-state atom types corresponding to hydrogen and non-hydrogen
     127 # atoms as an array reference...
     128 #
     129 # This functionality can be either invoked as a class function or an
     130 # object method.
     131 #
     132 sub GetAllPossibleEStateAtomTypes {
     133   return _GetAllPossibleEStateAtomTypes();
     134 }
     135
     136 # Get all possible E-state atom types corresponding to non-hydrogen atoms
     137 # as an array reference...
     138 #
     139 # This functionality can be either invoked as a class function or an
     140 # object method.
     141 #
     142 sub GetAllPossibleEStateNonHydrogenAtomTypes {
     143   my($NonHydrogensOnly);
     144
     145   $NonHydrogensOnly = 1;
     146   return _GetAllPossibleEStateAtomTypes($NonHydrogensOnly);
     147 }
     148
     149 # Get all possible E-state atom types as an array reference...
     150 #
     151 sub _GetAllPossibleEStateAtomTypes {
     152   my($NonHydrogensOnly) = @_;
     153   my($EStateAtomTypesDataRef);
     154
     155   $NonHydrogensOnly = defined $NonHydrogensOnly ? $NonHydrogensOnly : 0;
     156
     157   $EStateAtomTypesDataRef = GetEStateAtomTypesData();
     158
     159   return $NonHydrogensOnly ? \@{$EStateAtomTypesDataRef->{NonHydrogenAtomTypes}}: \@{$EStateAtomTypesDataRef->{AtomTypes}};
     160 }
     161
     162 # Assign electrotopological state (E-state) [ Ref 75-78 ] atom types to all atoms...
     163 #
     164 # E-state atom types for various different atom groups [Appendix Table 1 in Ref 76, Appendix III
     165 # in Ref 77 ] are defined using central atom environments indicating its topological and valence state
     166 # along with bonded hydrogens.
     167 #
     168 # The current release of MayaChemTools implements an extended E-state atom assignment
     169 # methodology which is able to assign atom types to any valid non-hydrogen atom in any
     170 # atom group instead of a fixed set of E-state atom types [ Ref 77].
     171 #
     172 # Let:
     173 #   As = Atom symbol corresponding to element symbol
     174 #
     175 #   H<n>   = Number of implicit and explicit hydrogens for atom
     176 #
     177 #   s = Single bond to non-hydrogen atom neighbors or heavy atoms attached to atom
     178 #   s<x> = Symbol s repeated x times to indicate multiple single bonds
     179 #
     180 #   d = Double bond to non-hydrogen atom neighbors or heavy atoms attached to atom
     181 #   d<x> = Symbol d repeated x times to indicate multiple double bonds
     182 #
     183 #   t = Triple bond to non-hydrogen atom neighbors or heavy atoms attached to atom
     184 #   t<x> = Symbol t repeated x times to indicate multiple triple bonds
     185 #
     186 #   a = Aromatic to bond non-hydrogen atom neighbors or heavy atoms attached to atom
     187 #   t<x> = Symbol a repeated x times to indicate multiple aromatic bonds
     188 #
     189 #   p = Plus or positive formal charge
     190 #   m = Minus or negative formal charge
     191 #
     192 # Then:
     193 #
     194 #   AtomType specification corresponds to:
     195 #
     196 #     t<x>d<x>a<x>s<x>AsH<n>p or t<x>d<x>a<x>s<x>AsH<n>m
     197 #
     198 # Notes:
     199 #   . p and n with values of 0 are not shown.
     200 #   . s, d, t, and a bond symbol with values of zero are not shown.
     201 #   . s and d bonds which are also aromatic don't contribute to the count of single and
     202 #     double bonds; instead, aromatic bond count reflect these bonds.
     203 #   . The E-state atom type assignment scheme implemented in the current release of
     204 #     MayaChemToools package supports assignment of atom types to all the periodic tab'e
     205 #     element.
     206 #
     207 # Hydrogen E-state [ Ref 76-77 ] atom type definitions:
     208 #
     209 # HGroup    AtomType
     210 #
     211 #   -OH        HsOH
     212 #   -SH        HsSH
     213 #
     214 #   -NH2       HsNH2
     215 #   >NH        HssNH
     216 #   =NH        HdNH
     217 #   :NH:       HaaNH
     218 #   -NH3+      HsNH3p
     219 #   >NH2+     HssNH2p
     220 #   >NH-+      HsssNHp
     221 #
     222 #   #CH        HtCH
     223 #   =CH2       HdCH2 - H attached to a terminal vinyl group
     224 #   =CH-       HdsCH - H attached a non-terminal vinyl group
     225 #   :CH:       HaaCH
     226 #
     227 #   >CHF       HCHF
     228 #   -CH2F      HCH2F
     229 #   >CHCl      HCHCl
     230 #   -CH2Cl     HCH2Cl
     231 #
     232 #   CHn (saturated)      HCsats   - H attached to sp3 carbon attached to saturated carbon(s)
     233 #   CHn (unsatd.)        HCsatu   - H attached to sp3 carbon attached to unsaturated carbon(s)
     234 #
     235 #   CHn (aromatic)       Havin    - H attached to a non-terminal vinyl group, =CH-, attached to an aromatic carbon
     236 #
     237 #   CHn        Hother    - H attached to any other type of C, N, O or S
     238 #   AHn        Hmisc     - H not attached to C, N, O or  S
     239 #
     240 # Notes:
     241 #   . - : Single bond; = : Double bond; # : Triple bond
     242 #   . Hother atom type capture Hydrogen atom groups not explicitly defined.
     243 #   . HGroup doesn't explicitly corresponds to functional groups
     244 #     . -OH group could be a hydroxyl group or part of carboxylic acid group and so on
     245 #     . -NH2 group could be primary amine or part of an amide group and so on
     246 #
     247 sub AssignAtomTypes {
     248   my($This) = @_;
     249   my($Atom);
     250
     251   ATOM: for $Atom ($This->GetMolecule()->GetAtoms()) {
     252     if ($Atom->IsHydrogen()) {
     253       if (!$This->{IgnoreHydrogens}) {
     254         $This->_AssignAtomTypeToHydrogenAtom($Atom);
     255       }
     256       next ATOM;
     257     }
     258
     259     # Handle non-hydrogen atoms..
     260     $This->_AssignAtomTypeToNonHydrogenAtom($Atom);
     261   }
     262   return $This;
     263 }
     264
     265 # Assign E-State atom type to non-hydrogen atom...
     266 #
     267 sub _AssignAtomTypeToNonHydrogenAtom {
     268   my($This, $Atom) = @_;
     269   my($AtomType);
     270
     271   $AtomType = $This->_GetAtomTypeForNonHydrogenAtom($Atom);
     272   $This->SetAtomType($Atom, $AtomType);
     273
     274   return $This;
     275 }
     276
     277 # Get E-State atom type for non-hydrogen atom...
     278 #
     279 sub _GetAtomTypeForNonHydrogenAtom {
     280   my($This, $Atom) = @_;
     281   my($AtomType, $AtomSymbol, $NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds, $CountAromaticBonds, $NumOfHydrogens, $FormalCharge, @EStateAtomInvariants);
     282
     283   @EStateAtomInvariants = ();
     284
     285   $AtomSymbol = $Atom->GetAtomicInvariantValue('AS');
     286   $NumOfHydrogens = $Atom->GetAtomicInvariantValue('H');
     287   $FormalCharge = $Atom->GetAtomicInvariantValue('FC');
     288
     289   $CountAromaticBonds = 1;
     290   ($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds) = $Atom->GetNumOfBondTypesToNonHydrogenAtoms($CountAromaticBonds);
     291
     292   # Set up E-state atom invariants symbols...
     293   if ($NumOfTripleBonds > 0) {
     294     push @EStateAtomInvariants, "t" x $NumOfTripleBonds;
     295   }
     296   if ($NumOfDoubleBonds > 0) {
     297     push @EStateAtomInvariants, "d" x $NumOfDoubleBonds;
     298   }
     299   if ($NumOfAromaticBonds > 0) {
     300     push @EStateAtomInvariants, "a" x $NumOfAromaticBonds;
     301   }
     302   if ($NumOfSingleBonds > 0) {
     303     push @EStateAtomInvariants, "s" x $NumOfSingleBonds;
     304   }
     305   push @EStateAtomInvariants, $AtomSymbol;
     306   if ($NumOfHydrogens > 0) {
     307     push @EStateAtomInvariants, ($NumOfHydrogens > 1) ? "H${NumOfHydrogens}" : "H";
     308   }
     309   if ($FormalCharge > 0) {
     310     push @EStateAtomInvariants, "p";
     311   }
     312   elsif ($FormalCharge < 0) {
     313     push @EStateAtomInvariants, "m";
     314   }
     315
     316   $AtomType = TextUtil::JoinWords(\@EStateAtomInvariants, "", 0);
     317
     318   return $AtomType;
     319 }
     320
     321 # Assign E-State atom type to hydrogen atom...
     322 #
     323 sub _AssignAtomTypeToHydrogenAtom {
     324   my($This, $Atom) = @_;
     325   my($AtomType);
     326
     327   $AtomType = $This->_GetAtomTypeForHydrogenAtom($Atom);
     328   $This->SetAtomType($Atom, $AtomType);
     329
     330   return $This;
     331 }
     332
     333 # Get E-State atom type for hydrogen atom...
     334 #
     335 sub _GetAtomTypeForHydrogenAtom {
     336   my($This, $Atom) = @_;
     337   my($AtomType, $AtomNeighbor);
     338
     339   $AtomType = "Hmisc";
     340
     341   # Get non-hydrogen atom neighbor...
     342   $AtomNeighbor = $Atom->GetNonHydrogenNeighborOfHydrogenAtom();
     343   if (!$AtomNeighbor) {
     344     return $AtomType;
     345   }
     346
     347   ATOMNEIGHBOR: {
     348     if ($AtomNeighbor->IsCarbon()) {
     349       $AtomType = $This->_GetAtomTypeForHydrogenAttachedToCarbon($AtomNeighbor);
     350       last ATOMNEIGHBOR;
     351     }
     352     if ($AtomNeighbor->IsNitrogen()) {
     353       $AtomType = $This->_GetAtomTypeForHydrogenAttachedToNitrogen($AtomNeighbor);
     354       last ATOMNEIGHBOR;
     355     }
     356     if ($AtomNeighbor->IsOxygen()) {
     357       $AtomType = $This->_GetAtomTypeForHydrogenAttachedToOxygen($AtomNeighbor);
     358       last ATOMNEIGHBOR;
     359     }
     360     if ($AtomNeighbor->IsSulfur()) {
     361       $AtomType = $This->_GetAtomTypeForHydrogenAttachedToSulfur($AtomNeighbor);
     362       last ATOMNEIGHBOR;
     363     }
     364     $AtomType = "Hmisc";
     365   }
     366   return $AtomType;
     367 }
     368
     369 # Get E-state atom type for Hydrogen attached to Carbon...
     370 #
     371 # HGroup    AtomType
     372 #
     373 #   #CH        HtCH
     374 #   =CH2       HdCH2 - H attached to a terminal vinyl group
     375 #   =CH-       HdsCH - H attached a non-terminal vinyl group
     376 #   :CH:       HaaCH
     377 #
     378 #   >CHF       HCHF
     379 #   -CH2F      HCH2F
     380 #   >CHCl      HCHCl
     381 #   -CH2Cl     HCH2Cl
     382 #
     383 #   CHn (saturated)      HCsats   - H attached to sp3 carbon attached to saturated carbon(s)
     384 #   CHn (unsatd.)        HCsatu   - H attached to sp3 carbon attached to unsaturated carbon(s)
     385 #
     386 #   CHn (aromatic)       Havin    - H attached to a non-terminal vinyl group, =CH-, attached to an aromatic carbon
     387 #
     388 #
     389 sub _GetAtomTypeForHydrogenAttachedToCarbon {
     390   my($This, $CarbonAtom) = @_;
     391   my($AtomType, $AtomNeighbor, $NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds, $CountAromaticBonds, $NumOfHydrogens, $NumOfFluorines, $NumOfChlorines);
     392
     393   $AtomType = "Hother";
     394
     395   $NumOfHydrogens = $CarbonAtom->GetAtomicInvariantValue('H');
     396
     397   $CountAromaticBonds = 1;
     398   ($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds) = $CarbonAtom->GetNumOfBondTypesToNonHydrogenAtoms($CountAromaticBonds);
     399
     400   ($NumOfFluorines,  $NumOfChlorines) = $This->_GetNumOfFluorineAndChlorineNeighbors($CarbonAtom);
     401
     402   ATOMTYPE: {
     403     if ($NumOfHydrogens == 1 && $NumOfSingleBonds == 0 && $NumOfDoubleBonds == 0 && $NumOfTripleBonds == 1 && $NumOfAromaticBonds == 0) {
     404       $AtomType = "HtCH";
     405       last ATOMTYPE;
     406     }
     407     if ($NumOfHydrogens == 2 && $NumOfSingleBonds == 0 && $NumOfDoubleBonds == 1 && $NumOfTripleBonds == 0 && $NumOfAromaticBonds == 0) {
     408       $AtomType = "HdCH2";
     409       last ATOMTYPE;
     410     }
     411     if ($NumOfHydrogens == 1 && $NumOfSingleBonds == 1 && $NumOfDoubleBonds == 1 && $NumOfTripleBonds == 0 && $NumOfAromaticBonds == 0) {
     412       if ($This->_IsAttachedToAromaticCarbon($CarbonAtom)) {
     413         $AtomType = "Havin";
     414       }
     415       else {
     416         $AtomType = "HdsCH";
     417       }
     418       last ATOMTYPE;
     419     }
     420     if ($NumOfHydrogens == 1 && $NumOfSingleBonds == 0 && $NumOfDoubleBonds == 0 && $NumOfTripleBonds == 0 && $NumOfAromaticBonds == 2) {
     421       $AtomType = "HaaCH";
     422       last ATOMTYPE;
     423     }
     424
     425     if ($NumOfFluorines == 1 && $NumOfHydrogens == 1 && $NumOfSingleBonds == 3 && $NumOfDoubleBonds == 0 && $NumOfTripleBonds == 0 && $NumOfAromaticBonds == 0) {
     426       $AtomType = "HCHF";
     427       last ATOMTYPE;
     428     }
     429     if ($NumOfFluorines == 1 && $NumOfHydrogens == 2 && $NumOfSingleBonds == 2 && $NumOfDoubleBonds == 0 && $NumOfTripleBonds == 0 && $NumOfAromaticBonds == 0) {
     430       $AtomType = "HCH2F";
     431       last ATOMTYPE;
     432     }
     433     if ($NumOfChlorines == 1 && $NumOfHydrogens == 1 && $NumOfSingleBonds == 3 && $NumOfDoubleBonds == 0 && $NumOfTripleBonds == 0 && $NumOfAromaticBonds == 0) {
     434       $AtomType = "HCHCl";
     435       last ATOMTYPE;
     436     }
     437     if ($NumOfChlorines == 1 && $NumOfHydrogens == 2 && $NumOfSingleBonds == 2 && $NumOfDoubleBonds == 0 && $NumOfTripleBonds == 0 && $NumOfAromaticBonds == 0) {
     438       $AtomType = "HCH2Cl";
     439       last ATOMTYPE;
     440     }
     441     if ($NumOfDoubleBonds == 0 && $NumOfTripleBonds == 0 && $NumOfAromaticBonds == 0) {
     442       # H  attached to sp3 carbon...
     443       $AtomType = $This->_GetAtomTypeForHydrogenAttachedToSaturatedOrUnsaturatedCarbons($CarbonAtom);
     444       last ATOMTYPE;
     445     }
     446     $AtomType = "Hother";
     447   }
     448
     449   return $AtomType;
     450 }
     451
     452 # Get number of fluorines and chlorines atached to an atom...
     453 #
     454 sub _GetNumOfFluorineAndChlorineNeighbors {
     455   my($This, $Atom) = @_;
     456   my($NumOfFluorines, $NumOfChlorines, $AtomNeighbor);
     457
     458   $NumOfFluorines = 0; $NumOfChlorines = 0;
     459   ATOMNEIGHBOR: for $AtomNeighbor ($Atom->GetNonHydrogenAtomNeighbors()) {
     460     if ($AtomNeighbor->IsFluorine()) {
     461       $NumOfFluorines++;
     462       next ATOMNEIGHBOR;
     463     }
     464     if ($AtomNeighbor->IsChlorine()) {
     465       $NumOfChlorines++;
     466       next ATOMNEIGHBOR;
     467     }
     468   }
     469   return ($NumOfFluorines, $NumOfChlorines);
     470 }
     471
     472 # Get atom type of hydrogen atom attached to a sp3 carbon attached to saturated or
     473 # unsaturated carbons...
     474 #
     475 # HGroup    AtomType
     476 #
     477 #   CHn (saturated)      HCsats   - H attached to sp3 carbon attached to saturated carbon(s)
     478 #   CHn (unsatd.)        HCsatu   - H attached to sp3 carbon attached to unsaturated carbon(s)
     479 #
     480 sub _GetAtomTypeForHydrogenAttachedToSaturatedOrUnsaturatedCarbons {
     481   my($This, $CarbonAtom) = @_;
     482   my($AtomType, $AtomNeighbor, @AtomNeighbors);
     483
     484   $AtomType = "Hother";
     485   @AtomNeighbors = $CarbonAtom->GetNonHydrogenAtomNeighbors();
     486
     487   # Make sure all neighbors are carbon atoms...
     488   for $AtomNeighbor (@AtomNeighbors) {
     489     if (!$AtomNeighbor->IsCarbon()) {
     490       return $AtomType;
     491     }
     492   }
     493
     494   $AtomType = "HCsats";
     495   ATOMNEIGHBOR: for $AtomNeighbor ($CarbonAtom->GetNonHydrogenAtomNeighbors()) {
     496     if ($AtomNeighbor->IsUnsaturated()) {
     497       $AtomType = "HCsatu";
     498       last ATOMNEIGHBOR;
     499     }
     500   }
     501
     502   return $AtomType;
     503 }
     504
     505 # Is vinyl carbon attached to an aromatic carbon?
     506 #
     507 sub _IsAttachedToAromaticCarbon {
     508   my($This, $CarbonAtom) = @_;
     509   my($Status, $AtomNeighbor, @AtomNeighbors);
     510
     511   $Status = 0;
     512
     513   @AtomNeighbors = $CarbonAtom->GetNonHydrogenAtomNeighbors();
     514   ATOMNEIGHBOR: for $AtomNeighbor (@AtomNeighbors) {
     515     if ($AtomNeighbor->IsCarbon() && $AtomNeighbor->IsAromatic()) {
     516       $Status = 1;
     517       last ATOMNEIGHBOR;
     518     }
     519   }
     520   return $Status;
     521 }
     522
     523
     524 # Get E-state atom type for Hydrogen attached to Nitrogen...
     525 #
     526 # HGroup    AtomType
     527 #
     528 #   -NH2       HsNH2
     529 #   >NH        HssNH
     530 #   =NH        HdNH
     531 #   :NH:       HaaNH
     532 #   -NH3+      HsNH3p
     533 #   >NH2+     HssNH2p
     534 #   >NH-+      HsssNHp
     535 #
     536 sub _GetAtomTypeForHydrogenAttachedToNitrogen {
     537   my($This, $NitrogenAtom) = @_;
     538   my($AtomType, $NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds, $CountAromaticBonds, $NumOfHydrogens, $FormalCharge);
     539
     540   $AtomType = "Hother";
     541
     542   $NumOfHydrogens = $NitrogenAtom->GetAtomicInvariantValue('H');
     543   $FormalCharge = $NitrogenAtom->GetAtomicInvariantValue('FC');
     544
     545   $CountAromaticBonds = 1;
     546   ($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds) = $NitrogenAtom->GetNumOfBondTypesToNonHydrogenAtoms($CountAromaticBonds);
     547
     548   if (!($NumOfTripleBonds == 0)) {
     549     return $AtomType;
     550   }
     551
     552   ATOMTYPE: {
     553     if ($FormalCharge == 0) {
     554       if ($NumOfHydrogens == 2 && $NumOfSingleBonds == 1 &&  $NumOfDoubleBonds == 0 && $NumOfAromaticBonds == 0) {
     555         $AtomType = "HsNH2";
     556         last ATOMTYPE;
     557       }
     558       if ($NumOfHydrogens == 1 && $NumOfSingleBonds == 2 && $NumOfDoubleBonds == 0 && $NumOfAromaticBonds == 0) {
     559         $AtomType = "HssNH";
     560         last ATOMTYPE;
     561       }
     562       if ($NumOfHydrogens == 1 && $NumOfSingleBonds == 0 && $NumOfDoubleBonds == 1 && $NumOfAromaticBonds == 0) {
     563         $AtomType = "HdNH";
     564         last ATOMTYPE;
     565       }
     566       if ($NumOfHydrogens == 1 && $NumOfSingleBonds == 0 && $NumOfDoubleBonds == 0 && $NumOfAromaticBonds == 2) {
     567         $AtomType = "HaaNH";
     568         last ATOMTYPE;
     569       }
     570       $AtomType = "Hother";
     571       last ATOMTYPE;
     572     }
     573     if ($FormalCharge == 1) {
     574       if ($NumOfHydrogens == 3 && $NumOfSingleBonds == 1 && $NumOfDoubleBonds == 0 && $NumOfAromaticBonds == 0) {
     575         $AtomType = "HsNH3p";
     576         last ATOMTYPE;
     577       }
     578       if ( $NumOfHydrogens == 2 && $NumOfSingleBonds == 2 && $NumOfDoubleBonds == 0 && $NumOfAromaticBonds == 0) {
     579         $AtomType = "HssNH2p";
     580         last ATOMTYPE;
     581       }
     582       if ($NumOfHydrogens == 1 && $NumOfSingleBonds == 3 && $NumOfDoubleBonds == 0 && $NumOfAromaticBonds == 0) {
     583         $AtomType = "HsssNHp";
     584         last ATOMTYPE;
     585       }
     586       $AtomType = "Hother";
     587       last ATOMTYPE;
     588     }
     589     $AtomType = "Hother";
     590   }
     591
     592   return $AtomType;
     593 }
     594
     595 # Get E-state atom type for Hydrogen attached to Oxygen...
     596 #
     597 # HGroup    AtomType
     598 #
     599 #   -OH        HsOH
     600 #
     601 sub _GetAtomTypeForHydrogenAttachedToOxygen {
     602   my($This, $OxygenAtom) = @_;
     603   my($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds, $CountAromaticBonds, $NumOfHydrogens);
     604
     605   $NumOfHydrogens = $OxygenAtom->GetAtomicInvariantValue('H');
     606
     607   $CountAromaticBonds = 1;
     608   ($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds) = $OxygenAtom->GetNumOfBondTypesToNonHydrogenAtoms($CountAromaticBonds);
     609
     610   return ($NumOfSingleBonds == 1 && $NumOfHydrogens == 1 && $NumOfDoubleBonds == 0 && $NumOfTripleBonds == 0 && $NumOfAromaticBonds == 0) ? "HsOH" : "Hother";
     611 }
     612
     613 # Get E-state atom type for Hydrogen attached to Sulfur...
     614 #
     615 # HGroup    AtomType
     616 #
     617 #   -SH        HsSH
     618 #
     619 sub _GetAtomTypeForHydrogenAttachedToSulfur {
     620   my($This, $SulfurAtom) = @_;
     621   my($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds, $CountAromaticBonds, $NumOfHydrogens);
     622
     623   $NumOfHydrogens = $SulfurAtom->GetAtomicInvariantValue('H');
     624
     625   $CountAromaticBonds = 1;
     626   ($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds) = $SulfurAtom->GetNumOfBondTypesToNonHydrogenAtoms($CountAromaticBonds);
     627
     628   return ($NumOfSingleBonds == 1 && $NumOfHydrogens == 1 && $NumOfDoubleBonds == 0 && $NumOfTripleBonds == 0 && $NumOfAromaticBonds == 0) ? "HsSH" : "Hother";
     629 }
     630
     631 # Return a string containg data for EStateAtomTypes object...
     632 #
     633 sub StringifyEStateAtomTypes {
     634   my($This) = @_;
     635   my($AtomTypesString);
     636
     637   # Type of AtomTypes...
     638   $AtomTypesString = "AtomTypes: $This->{Type}; IgnoreHydrogens: " . ($This->{IgnoreHydrogens} ? "Yes" : "No");
     639
     640   # Setup atom types information...
     641   my($AtomID, $AtomType, @AtomTypesInfo, %AssignedAtomTypes);
     642
     643   @AtomTypesInfo = ();
     644   %AssignedAtomTypes = $This->GetAtomTypes();
     645
     646   for $AtomID (sort { $a <=> $b } keys %AssignedAtomTypes) {
     647     $AtomType = $AssignedAtomTypes{$AtomID} ? $AssignedAtomTypes{$AtomID} : 'None';
     648     push @AtomTypesInfo, "$AtomID:$AtomType";
     649   }
     650   $AtomTypesString .= "; AtomIDs:AtomTypes: <" . TextUtil::JoinWords(\@AtomTypesInfo, ", ", 0) . ">";
     651
     652   return $AtomTypesString;
     653 }
     654
     655 # Is it a EStateAtomTypes object?
     656 sub _IsEStateAtomTypes {
     657   my($Object) = @_;
     658
     659   return (Scalar::Util::blessed($Object) && $Object->isa($ClassName)) ? 1 : 0;
     660 }
     661
     662 # Check and load EState atom types data...
     663 #
     664 sub _CheckAndLoadEStateAtomTypesData {
     665
     666   # Is it already loaded?
     667   if (exists $EStateAtomTypesDataMap{AtomTypes}) {
     668     return;
     669   }
     670
     671   _LoadEStateAtomTypesData();
     672 }
     673
     674 # Load EState atom types data from the file assuming first column to be atom type symbol..
     675 #
     676 # Format:
     677 #
     678 # "AtomType","AtomGroup"
     679 # "sLi","-Li"
     680 # "ssBe","-Be-"
     681 # "ssssBem",">Be<-2"
     682 #
     683 sub _LoadEStateAtomTypesData {
     684   my($AtomTypesDataFile, $MayaChemToolsLibDir);
     685
     686   $MayaChemToolsLibDir = FileUtil::GetMayaChemToolsLibDirName();
     687
     688   $AtomTypesDataFile =  "$MayaChemToolsLibDir" . "/data/EStateAtomTypes.csv";
     689   if (! -e "$AtomTypesDataFile") {
     690     croak "Error: MayaChemTools package file, $AtomTypesDataFile, is missing: Possible installation problems...";
     691   }
     692
     693   %EStateAtomTypesDataMap = ();
     694   AtomTypes::AtomTypes::LoadAtomTypesData($AtomTypesDataFile, \%EStateAtomTypesDataMap);
     695 }
     696