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