MayaChemTools

   1 package AtomTypes::SLogPAtomTypes;
   2 #
   3 # $RCSfile: SLogPAtomTypes.pm,v $
   4 # $Date: 2015/02/28 20:48:03 $
   5 # $Revision: 1.19 $
   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 Text::ParseWords;
  34 use FileUtil ();
  35 use AtomTypes::AtomTypes;
  36 use Molecule;
  37 
  38 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  39 
  40 @ISA = qw(AtomTypes::AtomTypes Exporter);
  41 @EXPORT = qw(GetSLogPAtomTypesData GetAllPossibleSLogPAtomTypes GetAllPossibleSLogPNonHydrogenAtomTypes);
  42 @EXPORT_OK = qw();
  43 
  44 %EXPORT_TAGS = (all  => [@EXPORT, @EXPORT_OK]);
  45 
  46 # Setup class variables...
  47 my($ClassName, %SLogPAtomTypesDataMap);
  48 _InitializeClass();
  49 
  50 # Overload Perl functions...
  51 use overload '""' => 'StringifySLogPAtomTypes';
  52 
  53 # Class constructor...
  54 sub new {
  55   my($Class, %NamesAndValues) = @_;
  56 
  57   # Initialize object...
  58   my $This = $Class->SUPER::new();
  59   bless $This, ref($Class) || $Class;
  60   $This->_InitializeSLogPAtomTypes();
  61 
  62   $This->_InitializeSLogPAtomTypesProperties(%NamesAndValues);
  63 
  64   return $This;
  65 }
  66 
  67 # Initialize class ...
  68 sub _InitializeClass {
  69   #Class name...
  70   $ClassName = __PACKAGE__;
  71 
  72   # Initialize the data hash. It'll be loaded on demand later...
  73   %SLogPAtomTypesDataMap = ();
  74 }
  75 
  76 # Initialize object data...
  77 #
  78 sub _InitializeSLogPAtomTypes {
  79   my($This) = @_;
  80 
  81   # Type of AtomTypes...
  82   $This->{Type} = 'SLogP';
  83 
  84   # By default, SLogP atom types are also assigned to hydrogens...
  85   $This->{IgnoreHydrogens} = 0;
  86 
  87   return $This;
  88 }
  89 
  90 # Initialize object properties...
  91 #
  92 sub _InitializeSLogPAtomTypesProperties {
  93   my($This, %NamesAndValues) = @_;
  94 
  95   my($Name, $Value, $MethodName);
  96   while (($Name, $Value) = each  %NamesAndValues) {
  97     $MethodName = "Set${Name}";
  98     $This->$MethodName($Value);
  99   }
 100 
 101   # Make sure molecule object was specified...
 102   if (!exists $NamesAndValues{Molecule}) {
 103     croak "Error: ${ClassName}->New: Object can't be instantiated without specifying molecule...";
 104   }
 105 
 106   return $This;
 107 }
 108 
 109 # Get SLogP atom types and associated data loaded from SLogP data file as
 110 # a reference to hash with the following hash data format:
 111 #
 112 # @{$SLogPAtomTypesDataMap{AtomTypes}} - Array of all possible atom types for all atoms
 113 # @{$SLogPAtomTypesDataMap{NonHydrogenAtomTypes}} - Array of all possible atom types for non-hydrogen atoms
 114 # @{$SLogPAtomTypesDataMap->{ColLabels}} - Array of column labels
 115 # %{$SLogPAtomTypesDataMap->{DataCol<Num>}} - Hash keys pair: <DataCol<Num>, AtomType>
 116 #
 117 # This functionality can be either invoked as a class function or an
 118 # object method.
 119 #
 120 sub GetSLogPAtomTypesData {
 121 
 122   # Make sure data is loaded...
 123   _CheckAndLoadSLogPAtomTypesData();
 124 
 125   return \%SLogPAtomTypesDataMap;
 126 }
 127 
 128 # Get all possible SLogP atom types corresponding to hydrogen and non-hydrogen
 129 # atoms as an array reference...
 130 #
 131 # This functionality can be either invoked as a class function or an
 132 # object method.
 133 #
 134 sub GetAllPossibleSLogPAtomTypes {
 135   return _GetAllPossibleSLogPAtomTypes();
 136 }
 137 
 138 # Get all possible SLogP atom types corresponding to non-hydrogen atoms
 139 # as an array reference...
 140 #
 141 # This functionality can be either invoked as a class function or an
 142 # object method.
 143 #
 144 sub GetAllPossibleSLogPNonHydrogenAtomTypes {
 145   my($NonHydrogensOnly);
 146 
 147   $NonHydrogensOnly = 1;
 148   return _GetAllPossibleSLogPAtomTypes($NonHydrogensOnly);
 149 }
 150 
 151 # Get all possible SLogP atom types as an array reference...
 152 #
 153 sub _GetAllPossibleSLogPAtomTypes {
 154   my($NonHydrogensOnly) = @_;
 155   my($SLogPAtomTypesDataRef);
 156 
 157   $NonHydrogensOnly = defined $NonHydrogensOnly ? $NonHydrogensOnly : 0;
 158 
 159   $SLogPAtomTypesDataRef = GetSLogPAtomTypesData();
 160 
 161   return $NonHydrogensOnly ? \@{$SLogPAtomTypesDataRef->{NonHydrogenAtomTypes}}: \@{$SLogPAtomTypesDataRef->{AtomTypes}};
 162 }
 163 
 164 # Assign SLogP [ Ref 89 ] atom types to all atoms...
 165 #
 166 # Notes:
 167 #     o 72 SLogP atom type symbols are listed
 168 #     o Number of atom types symbols for:
 169 #         o C: 28
 170 #         o N: 15
 171 #         o O: 13
 172 #         o P: 1
 173 #         o S: 3
 174 #         o H: 5
 175 #         o F, Cl, Br, I: 1 each
 176 #         o Ionic halogen: 1
 177 #         o p-block elements: 1
 178 #         o d-block elements: 1
 179 #
 180 sub AssignAtomTypes {
 181   my($This) = @_;
 182   my($Atom, $AtomType);
 183 
 184   ATOM: for $Atom ($This->GetMolecule()->GetAtoms()) {
 185     if ($This->{IgnoreHydrogens} && $Atom->IsHydrogen()) {
 186       next ATOM;
 187     }
 188     $AtomType = $This->_GetAtomType($Atom);
 189     $This->SetAtomType($Atom, $AtomType);
 190   }
 191 
 192   return $This;
 193 }
 194 
 195 # Get SLogP atom type for atom...
 196 #
 197 sub _GetAtomType {
 198   my($This, $Atom) = @_;
 199   my($AtomType);
 200 
 201   $AtomType = 'None';
 202 
 203   ATOM: {
 204     if ($Atom->IsCarbon()) {
 205       $AtomType = $This->_GetAtomTypeForCarbon($Atom);
 206       last ATOM;
 207     }
 208 
 209     if ($Atom->IsNitrogen()) {
 210       $AtomType = $This->_GetAtomTypeForNitrogen($Atom);
 211       last ATOM;
 212     }
 213 
 214     if ($Atom->IsOxygen()) {
 215       $AtomType = $This->_GetAtomTypeForOxygen($Atom);
 216       last ATOM;
 217     }
 218 
 219     if ($Atom->IsPhosphorus()) {
 220       $AtomType = $This->_GetAtomTypeForPhosphorus($Atom);
 221       last ATOM;
 222     }
 223 
 224     if ($Atom->IsSulfur()) {
 225       $AtomType = $This->_GetAtomTypeForSulfur($Atom);
 226       last ATOM;
 227     }
 228 
 229     if ($Atom->IsHydrogen()) {
 230       $AtomType = $This->_GetAtomTypeForHydrogen($Atom);
 231       last ATOM;
 232     }
 233 
 234     $AtomType = $This->_GetAtomTypeForOtherAtoms($Atom);
 235   }
 236 
 237   return $AtomType;
 238 }
 239 
 240 # Get SLogP atom type for Carbon atom...
 241 #
 242 # 28 AtomTypeSymbols for element C:
 243 #
 244 # AtomTypeSymbol - Description - SMARTS
 245 # C1 - primary, secondary aliphatic - '[CH4]','[CH3]C','[CH2](C)C'
 246 # C2 - tertiary, quaternary aliphatic - '[CH](C)(C)C','[C](C)(C)(C)C'
 247 # C3 - primary, secondary heteroatom - '[CH3][(N,O,P,S,F,Cl,Br,I)]','[CH2X4](N,O,P,S,F,Cl,Br,I)]'
 248 # C4 - tertiary, quaternary heteroatom - '[CH1X4][(N,O,P,S,F,Cl,Br,I)]','[CH0X4][(N,O,P,S,F,Cl,Br,I)]'
 249 # C5 - C = heteroatom - '[C]=[A#X]'
 250 # C6 - C = C aliphatic - '[CH2]=C','[CH1](=C)A','[CH0](=C)(A)A','[C](=C)=C'
 251 # C7 - acetylene, nitrile - '[CX2]#A'
 252 # C8 - primary aromatic carbon - '[CH3]c'
 253 # C9 - primary aromatic heteroatom - '[CH3][a#X]'
 254 # C10 - secondary aromatic - '[CH2X4]a'
 255 # C11 - tertiary aromatic - '[CHX4]a'
 256 # C12 - quaternary aromatic - '[CH0X4]a'
 257 # C13 - aromatic heteroatom - '[cH0]-[!(C,N,O,S,F,Cl,Br,I)]'
 258 # C14 - aromatic halide - '[c][#9]'
 259 # C15 - aromatic halide - '[c][#17]'
 260 # C16 - aromatic halide - '[c][#35]'
 261 # C17 - aromatic halide - '[c][#53]'
 262 # C18 - aromatic - '[cH]'
 263 # C19 - aromatic bridgehead - '[c](:a)(:a):a'
 264 # C20 - quaternary aromatic - '[c](:a)(:a)-a'
 265 # C21 - quaternary aromatic - '[c](:a)(:a)-C'
 266 # C22 - quaternary aromatic - '[c](:a)(:a)-N'
 267 # C23 - quaternary aromatic - '[c](:a)(:a)-O'
 268 # C24 - quaternary aromatic - '[c](:a)(:a)-S'
 269 # C25 - quaternary aromatic - '[c](:a)(:a)=C','[c](:a)(:a)=N','[c](:a)(:a)=O'
 270 # C26 - C = C aromatic - '[C](=C)(a)A','[C](=C)(c)a','[CH](=C)a','[C]=c'
 271 # C27 - aliphatic heteroatom - '[CX4][!(C,N,O,P,S,F,Cl,Br,I)]'
 272 # CS - carbon supplemental not matching any basic C type - '[#6]'
 273 #
 274 sub _GetAtomTypeForCarbon {
 275   my($This, $Atom) = @_;
 276   my($AtomType, $NumOfSigmaBonds, $NumOfPiBonds);
 277 
 278   $AtomType = 'None';
 279 
 280   ($NumOfSigmaBonds, $NumOfPiBonds) = ('0') x 2;
 281 
 282   ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms();
 283   $NumOfSigmaBonds += $Atom->GetAtomicInvariantValue('H');
 284 
 285   ATOMTYPE: {
 286 
 287     # Only single bonds...
 288     if ($NumOfPiBonds == 0) {
 289       $AtomType = $This->_GetAtomTypeForCarbonWithOnlySigmaBonds($Atom);
 290       last ATOMTYPE;
 291     }
 292 
 293     # One double bond...
 294     if ($NumOfPiBonds == 1) {
 295       $AtomType = $This->_GetAtomTypeForCarbonWithOnePiBond($Atom);
 296       last ATOMTYPE;
 297     }
 298 
 299     # One triple bond or two double bonds...
 300     if ($NumOfPiBonds == 2) {
 301       $AtomType = $This->_GetAtomTypeForCarbonWithTwoPiBonds($Atom);
 302       last ATOMTYPE;
 303     }
 304 
 305     $AtomType = 'CS';
 306   }
 307   return $AtomType;
 308 }
 309 
 310 # Get SLogP atom type for Nitrogen atom...
 311 #
 312 # 15 AtomTypeSymbols for element N:
 313 #
 314 # AtomTypeSymbol - Description - SMARTS
 315 # N1 - primary amine - '[NH2+0]A'
 316 # N2 - secondary amine - '[NH+0](A)A'
 317 # N3 - primary aromatic amine - '[NH2+0]a'
 318 # N4 - secondary aromatic amine - '[NH+0](A)a','[NH+0](a)a'
 319 # N5 - imine - '[NH+0]=A','[NH+0]=a'
 320 # N6 - substituted imine - '[N+0](=A)A','[N+0](=A)a','[N+0](=a)A','[N+0](=a)a'
 321 # N7 - tertiary amine - '[N+0](A)(A)A'
 322 # N8 - tertiary aromatic amine - '[N+0](a)(A)A','[N+0](a)(a)A','[N+0](a)(a)a'
 323 # N9 - nitrile - '[N+0]#A'
 324 # N10 - protonated amine - '[NH3+*]','[NH2+*]','[NH+*]'
 325 # N11 - unprotonated aromatic - '[n+0]'
 326 # N12 - protonated aromatic - '[n+*]'
 327 # N13 - quaternary amine - '[NH0+*](A)(A)(A)A','[NH0+*](=A)(A)A','[NH0+*](=A)(A)a','[NH0+*](=[#6])=[#7]'
 328 # N14 - other ionized nitrogen - '[N+*]#A','[N-*]','[N+*](=[N-*])=N'
 329 # NS - nitrogen supplemental not matching any basic N type - '[#7]'
 330 #
 331 sub _GetAtomTypeForNitrogen {
 332   my($This, $Atom) = @_;
 333   my($AtomType, $NumOfSigmaBonds, $NumOfPiBonds);
 334 
 335   $AtomType = 'None';
 336 
 337   ($NumOfSigmaBonds, $NumOfPiBonds) = ('0') x 2;
 338 
 339   ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms();
 340   $NumOfSigmaBonds += $Atom->GetAtomicInvariantValue('H');
 341 
 342   ATOMTYPE: {
 343 
 344     # Only single bonds...
 345     if ($NumOfPiBonds == 0) {
 346       $AtomType = $This->_GetAtomTypeForNitrogenWithOnlySigmaBonds($Atom);
 347       last ATOMTYPE;
 348     }
 349 
 350     # One double bond...
 351     if ($NumOfPiBonds == 1) {
 352       $AtomType = $This->_GetAtomTypeForNitrogenWithOnePiBond($Atom);
 353       last ATOMTYPE;
 354     }
 355 
 356     # One triple bond or two double bonds...
 357     if ($NumOfPiBonds == 2) {
 358       $AtomType = $This->_GetAtomTypeForNitrogenWithTwoPiBonds($Atom);
 359       last ATOMTYPE;
 360     }
 361 
 362     $AtomType = 'NS';
 363   }
 364   return $AtomType;
 365 }
 366 
 367 # Get SLogP atom type for Oxygen atom...
 368 #
 369 # 13 AtomTypeSymbols for element O:
 370 #
 371 # AtomTypeSymbol - Description - SMARTS
 372 # O1 - aromatic - '[o]'
 373 # O2 - alcohol - '[OH]','[OH2]'
 374 # O3 - aliphatic ether - '[O](C)C','[O](C)[A#X]','[O]([A#X])[A#X]'
 375 # O4 - aromatic ether - '[O](A)a','[O](a)a'
 376 # O5 - oxide - '[O]=[#8]','[O]=[#7]','[OX1-*][#7]'
 377 # O6 - oxide - '[OX1-*][#16]'
 378 # O7 - oxide - '[OX1-*][!(N,S)]'
 379 # O8 - aromatic carbonyl - '[O]=c'
 380 # O9 - carbonyl aliphatic - '[O]=[CH]C','[O]=C(C)C','[O]=C(C)[A#X]','[O]=[CH]N','[O]=[CH]O','[O]=[CH2]','[O]=[CX2]=O'
 381 # O10 - carbonyl aromatic - '[O]=[CH]c','[O]=C(C)c','[O]=C(c)c','[O]=C(c)[a#X]','[O]=C(c)[A#X]','[O]=C(C)[a#X]'
 382 # O11 - carbonyl heteroatom - '[O]=C([A#X])[A#X]','[O]=C([A#X])[a#X]','[O]=C([a#X])[a#X]'
 383 # O12 - acid - '[O-1]C(=O)'
 384 # OS - oxygen supplemental not matching any basic O type - '[#8]'
 385 #
 386 sub _GetAtomTypeForOxygen {
 387   my($This, $Atom) = @_;
 388   my($AtomType, $NumOfSigmaBonds, $NumOfPiBonds);
 389 
 390   $AtomType = 'None';
 391 
 392   ($NumOfSigmaBonds, $NumOfPiBonds) = ('0') x 2;
 393 
 394   ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms();
 395   $NumOfSigmaBonds += $Atom->GetAtomicInvariantValue('H');
 396 
 397   ATOMTYPE: {
 398 
 399     # Only single bonds...
 400     if ($NumOfPiBonds == 0) {
 401       $AtomType = $This->_GetAtomTypeForOxygenWithOnlySigmaBonds($Atom);
 402       last ATOMTYPE;
 403     }
 404 
 405     # One double bond...
 406     if ($NumOfPiBonds == 1) {
 407       $AtomType = $This->_GetAtomTypeForOxygenWithOnePiBond($Atom);
 408       last ATOMTYPE;
 409     }
 410 
 411     # OS - oxygen supplemental not matching any basic O type - '[#8]'
 412     $AtomType = 'OS';
 413   }
 414   return $AtomType;
 415 }
 416 
 417 # Get SLogP atom type for Phosphorus atom...
 418 #
 419 # 1 AtomTypeSymbols for element P:
 420 #
 421 # AtomTypeSymbol - Description - SMARTS
 422 # P - phosphorous - '[#15]'
 423 #
 424 sub _GetAtomTypeForPhosphorus {
 425   my($This, $Atom) = @_;
 426   my($AtomType);
 427 
 428   $AtomType = 'P';
 429 
 430   return $AtomType;
 431 }
 432 
 433 # Get SLogP atom type for Sulfur atom...
 434 #
 435 # 3 AtomTypeSymbols for element S:
 436 #
 437 # AtomTypeSymbol - Description - SMARTS
 438 # S1 - aliphatic - '[S-0]'
 439 # S2 - ionic sulfur - '[S-*]','[S+*]'
 440 # S3 - aromatic - '[s]'
 441 #
 442 sub _GetAtomTypeForSulfur {
 443   my($This, $Atom) = @_;
 444   my($AtomType);
 445 
 446   $AtomType = 'None';
 447 
 448   ATOMTYPE: {
 449 
 450     # S1 - aliphatic - '[S-0]'
 451     if ($This->_IsS1Sulfur($Atom)) {
 452       $AtomType = 'S1';
 453       last ATOMTYPE;
 454     }
 455 
 456     # S2 - ionic sulfur - '[S-*]','[S+*]'
 457     if ($This->_IsS2Sulfur($Atom)) {
 458       $AtomType = 'S2';
 459       last ATOMTYPE;
 460     }
 461 
 462     # S3 - aromatic - '[s]'
 463     if ($This->_IsS3Sulfur($Atom)) {
 464       $AtomType = 'S3';
 465       last ATOMTYPE;
 466     }
 467 
 468     # S1 - aliphatic - '[S-0]'
 469     $AtomType = 'S1';
 470   }
 471 
 472   return $AtomType;
 473 }
 474 
 475 # Get SLogP atom type for Hydrogen atom...
 476 #
 477 # 5 AtomTypeSymbols for element H:
 478 #
 479 # AtomTypeSymbol - Description - SMARTS
 480 # H1 - hydrocarbon - '[#1][#6]','[#1][#1]'
 481 # H2 - alcohol - '[#1]O[CX4]','[#1]Oc','[#1]O[!(C,N,O,S)]','[#1][!C,N,O)]'
 482 # H3 - amine - '[#1][#7]','[#1]O[#7]'
 483 # H4 - acid - '[#1]OC=[#6]','[#1]OC=[#7]','[#1]OC=O','[#1]OC=S','[#1]OO','[#1]OS'
 484 # HS - hydrogen supplemental not matching any basic H type - '[#1]'
 485 #
 486 sub _GetAtomTypeForHydrogen {
 487   my($This, $Atom) = @_;
 488   my($AtomType);
 489 
 490   $AtomType = 'None';
 491 
 492   ATOMTYPE: {
 493 
 494     # H1 - hydrocarbon - '[#1][#6]','[#1][#1]'
 495     if ($This->_IsH1Hydrogen($Atom)) {
 496       $AtomType = 'H1';
 497       last ATOMTYPE;
 498     }
 499 
 500     # H2 - alcohol - '[#1]O[CX4]','[#1]Oc','[#1]O[!(C,N,O,S)]','[#1][!C,N,O)]'
 501     if ($This->_IsH2Hydrogen($Atom)) {
 502       $AtomType = 'H2';
 503       last ATOMTYPE;
 504     }
 505 
 506     # H3 - amine - '[#1][#7]','[#1]O[#7]'
 507     if ($This->_IsH3Hydrogen($Atom)) {
 508       $AtomType = 'H3';
 509       last ATOMTYPE;
 510     }
 511 
 512     # H4 - acid - '[#1]OC=[#6]','[#1]OC=[#7]','[#1]OC=O','[#1]OC=S','[#1]OO','[#1]OS'
 513     if ($This->_IsH4Hydrogen($Atom)) {
 514       $AtomType = 'H4';
 515       last ATOMTYPE;
 516     }
 517 
 518     $AtomType = 'HS';
 519   }
 520   return $AtomType;
 521 }
 522 
 523 # Get SLogP atom type for atoms other than Carbon, Nitrogen, Oxygen, Phosporus,
 524 # Sulfur and Hydrogen...
 525 #
 526 # AtomTypeSymbol - Description - SMARTS
 527 # F - fluorine - '[#9-0]'
 528 # Cl - chlorine - '[#17-0]'
 529 # Br - bromine - '[#35-0]'
 530 # I - iodine - '[#53-0]'
 531 # Hal - ionic halogens - '[#9-*]','[#17-*]','[#35-*]',[#53-*]','[#53+*]'
 532 # Hal - all remaining s-block elements
 533 # Me1 - all remaining p-block elements
 534 # Me2 - all remaining d-block elements
 535 #
 536 sub _GetAtomTypeForOtherAtoms {
 537   my($This, $Atom) = @_;
 538   my($AtomType, $AtomSymbol);
 539 
 540   $AtomType = 'None';
 541   $AtomSymbol = $Atom->GetAtomSymbol();
 542 
 543   ATOMTYPE: {
 544 
 545     # Halogens...
 546     if ($AtomSymbol =~ /^(F|Cl|Br|I)$/i) {
 547       $AtomType = $Atom->GetFormalCharge() ? 'Hal' : $AtomSymbol;
 548       last ATOMTYPE;
 549     }
 550 
 551     # Me1 - all remaining p-block elements
 552     if ($This->_IsPBlockElement($Atom)) {
 553       $AtomType = 'Me1';
 554       last ATOMTYPE;
 555     }
 556 
 557     # Me2 - all remaining d-block elements
 558     if ($This->_IsDBlockElement($Atom)) {
 559       $AtomType = 'Me2';
 560       last ATOMTYPE;
 561     }
 562 
 563     # Hal - all remaining s-block elements
 564     if ($This->_IsSBlockElement($Atom)) {
 565       $AtomType = 'Hal';
 566       last ATOMTYPE;
 567     }
 568 
 569     $AtomType = 'None';
 570     carp "Warning: ${ClassName}->_GetAtomTypeForOtherAtoms: SLogP atom type for $AtomSymbol cann't be assigned...";
 571   }
 572   return $AtomType;
 573 }
 574 
 575 # Get SLogP atom type for Carbon with only sigma bonds...
 576 #
 577 sub _GetAtomTypeForCarbonWithOnlySigmaBonds {
 578   my($This, $Atom) = @_;
 579   my($AtomType);
 580 
 581   $AtomType = 'None';
 582 
 583   ATOMTYPE: {
 584 
 585     # C1 - primary, secondary aliphatic - '[CH4]','[CH3]C','[CH2](C)C'
 586     if ($This->_IsC1Carbon($Atom)) {
 587       $AtomType = 'C1';
 588       last ATOMTYPE;
 589     }
 590 
 591     # C2 - tertiary, quaternary aliphatic - '[CH](C)(C)C','[C](C)(C)(C)C'
 592     if ($This->_IsC2Carbon($Atom)) {
 593       $AtomType = 'C2';
 594       last ATOMTYPE;
 595     }
 596 
 597     # C3 - primary, secondary heteroatom - '[CH3][(N,O,P,S,F,Cl,Br,I)]','[CH2X4](N,O,P,S,F,Cl,Br,I)]'
 598     if ($This->_IsC3Carbon($Atom)) {
 599       $AtomType = 'C3';
 600       last ATOMTYPE;
 601     }
 602 
 603     # C4 - tertiary, quaternary heteroatom - '[CH1X4][(N,O,P,S,F,Cl,Br,I)]','[CH0X4][(N,O,P,S,F,Cl,Br,I)]'
 604     if ($This->_IsC4Carbon($Atom)) {
 605       $AtomType = 'C4';
 606       last ATOMTYPE;
 607     }
 608 
 609     # C8 - primary aromatic carbon - '[CH3]c'
 610     if ($This->_IsC8Carbon($Atom)) {
 611       $AtomType = 'C8';
 612       last ATOMTYPE;
 613     }
 614 
 615     # C9 - primary aromatic heteroatom - '[CH3][a#X]'
 616     if ($This->_IsC9Carbon($Atom)) {
 617       $AtomType = 'C9';
 618       last ATOMTYPE;
 619     }
 620 
 621     # C10 - secondary aromatic - '[CH2X4]a'
 622     if ($This->_IsC10Carbon($Atom)) {
 623       $AtomType = 'C10';
 624       last ATOMTYPE;
 625     }
 626 
 627     # C11 - tertiary aromatic - '[CHX4]a'
 628     if ($This->_IsC11Carbon($Atom)) {
 629       $AtomType = 'C11';
 630       last ATOMTYPE;
 631     }
 632 
 633     # C12 - quaternary aromatic - '[CH0X4]a'
 634     if ($This->_IsC12Carbon($Atom)) {
 635       $AtomType = 'C12';
 636       last ATOMTYPE;
 637     }
 638 
 639     # C27 - aliphatic heteroatom - '[CX4][!(C,N,O,P,S,F,Cl,Br,I)]'
 640     if ($This->_IsC27Carbon($Atom)) {
 641       $AtomType = 'C27';
 642       last ATOMTYPE;
 643     }
 644 
 645     # CS - carbon supplemental not matching any basic C type - '[#6]'
 646     $AtomType = 'CS';
 647   }
 648 
 649   return $AtomType;
 650 }
 651 
 652 # Get SLogP atom type for Carbon with one pi bond...
 653 #
 654 sub _GetAtomTypeForCarbonWithOnePiBond {
 655   my($This, $Atom) = @_;
 656   my($AtomType);
 657 
 658   $AtomType = 'None';
 659 
 660   ATOMTYPE: {
 661 
 662     # C5 - C = heteroatom - '[C]=[A#X]'
 663     if ($This->_IsC5Carbon($Atom)) {
 664       $AtomType = 'C5';
 665       last ATOMTYPE;
 666     }
 667 
 668     # C6 - C = C aliphatic - '[CH2]=C','[CH1](=C)A','[CH0](=C)(A)A','[C](=C)=C'
 669     if ($This->_IsC6Carbon($Atom)) {
 670       $AtomType = 'C6';
 671       last ATOMTYPE;
 672     }
 673 
 674     # C13 - aromatic heteroatom - '[cH0]-[!(C,N,O,S,F,Cl,Br,I)]'
 675     if ($This->_IsC13Carbon($Atom)) {
 676       $AtomType = 'C13';
 677       last ATOMTYPE;
 678     }
 679 
 680     # C14 - aromatic halide - '[c][#9]'
 681     if ($This->_IsC14Carbon($Atom)) {
 682       $AtomType = 'C14';
 683       last ATOMTYPE;
 684     }
 685 
 686     # C15 - aromatic halide - '[c][#17]'
 687     if ($This->_IsC15Carbon($Atom)) {
 688       $AtomType = 'C15';
 689       last ATOMTYPE;
 690     }
 691 
 692     # C16 - aromatic halide - '[c][#35]'
 693     if ($This->_IsC16Carbon($Atom)) {
 694       $AtomType = 'C16';
 695       last ATOMTYPE;
 696     }
 697 
 698     # C17 - aromatic halide - '[c][#53]'
 699     if ($This->_IsC17Carbon($Atom)) {
 700       $AtomType = 'C17';
 701       last ATOMTYPE;
 702     }
 703 
 704     # C18 - aromatic - '[cH]'
 705     if ($This->_IsC18Carbon($Atom)) {
 706       $AtomType = 'C18';
 707       last ATOMTYPE;
 708     }
 709 
 710     # C19 - aromatic bridgehead - '[c](:a)(:a):a'
 711     if ($This->_IsC19Carbon($Atom)) {
 712       $AtomType = 'C19';
 713       last ATOMTYPE;
 714     }
 715 
 716     # C20 - quaternary aromatic - '[c](:a)(:a)-a'
 717     if ($This->_IsC20Carbon($Atom)) {
 718       $AtomType = 'C20';
 719       last ATOMTYPE;
 720     }
 721 
 722     # C21 - quaternary aromatic - '[c](:a)(:a)-C'
 723     if ($This->_IsC21Carbon($Atom)) {
 724       $AtomType = 'C21';
 725       last ATOMTYPE;
 726     }
 727 
 728     # C22 - quaternary aromatic - '[c](:a)(:a)-N'
 729     if ($This->_IsC22Carbon($Atom)) {
 730       $AtomType = 'C22';
 731       last ATOMTYPE;
 732     }
 733 
 734     # C23 - quaternary aromatic - '[c](:a)(:a)-O'
 735     if ($This->_IsC23Carbon($Atom)) {
 736       $AtomType = 'C23';
 737       last ATOMTYPE;
 738     }
 739 
 740     # C24 - quaternary aromatic - '[c](:a)(:a)-S'
 741     if ($This->_IsC24Carbon($Atom)) {
 742       $AtomType = 'C24';
 743       last ATOMTYPE;
 744     }
 745 
 746     # C26 - C = C aromatic - '[C](=C)(a)A','[C](=C)(c)a','[CH](=C)a','[C]=c'
 747     if ($This->_IsC26Carbon($Atom)) {
 748       $AtomType = 'C26';
 749       last ATOMTYPE;
 750     }
 751 
 752     # CS - carbon supplemental not matching any basic C type - '[#6]'
 753     $AtomType = 'CS';
 754   }
 755 
 756   return $AtomType;
 757 }
 758 
 759 # Get SLogP atom type for Carbon with two pi bonds...
 760 #
 761 sub _GetAtomTypeForCarbonWithTwoPiBonds {
 762   my($This, $Atom) = @_;
 763   my($AtomType);
 764 
 765   $AtomType = 'None';
 766 
 767   ATOMTYPE: {
 768 
 769     # C6 - C = C aliphatic - '[CH2]=C','[CH1](=C)A','[CH0](=C)(A)A','[C](=C)=C'
 770     if ($This->_IsC6Carbon($Atom)) {
 771       $AtomType = 'C6';
 772       last ATOMTYPE;
 773     }
 774 
 775     # C7 - acetylene, nitrile - '[CX2]#A'
 776     if ($This->_IsC7Carbon($Atom)) {
 777       $AtomType = 'C7';
 778       last ATOMTYPE;
 779     }
 780 
 781     # CS - carbon supplemental not matching any basic C type - '[#6]'
 782     $AtomType = 'CS';
 783   }
 784 
 785   return $AtomType;
 786 }
 787 
 788 # C1 - primary, secondary aliphatic - '[CH4]','[CH3]C','[CH2](C)C'
 789 #
 790 sub _IsC1Carbon {
 791   my($This, $Atom) = @_;
 792 
 793   return $Atom->DoesAtomNeighborhoodMatch('C.T4.!Ar', ['C.!Ar,H', 'C.!Ar,H', 'H', 'H'], ['-', '-', '-', '-']) ? 1 : 0;
 794 }
 795 
 796 # C2 - tertiary, quaternary aliphatic - '[CH](C)(C)C','[C](C)(C)(C)C'
 797 #
 798 sub _IsC2Carbon {
 799   my($This, $Atom) = @_;
 800 
 801   return $Atom->DoesAtomNeighborhoodMatch('C.T4.!Ar', ['C.!Ar', 'C.!Ar', 'C.!Ar', 'C.!Ar,H'], ['-', '-', '-', '-']) ? 1 : 0;
 802 }
 803 
 804 # C3 - primary, secondary heteroatom - '[CH3][(N,O,P,S,F,Cl,Br,I)]','[CH2X4](N,O,P,S,F,Cl,Br,I)]'
 805 #
 806 sub _IsC3Carbon {
 807   my($This, $Atom) = @_;
 808 
 809   return $Atom->DoesAtomNeighborhoodMatch('C.T4.!Ar', ['N.!Ar,O.!Ar,P.!Ar,S.!Ar,F,Cl,Br,I', 'N.!Ar,O.!Ar,P.!Ar,S.!Ar,F,Cl,Br,I,H', 'H', 'H'], ['-', '-', '-', '-']) ? 1 : 0;
 810 }
 811 
 812 # C4 - tertiary, quaternary heteroatom - '[CH1X4][(N,O,P,S,F,Cl,Br,I)]','[CH0X4][(N,O,P,S,F,Cl,Br,I)]'
 813 #
 814 sub _IsC4Carbon {
 815   my($This, $Atom) = @_;
 816 
 817   return $Atom->DoesAtomNeighborhoodMatch('C.T4.!Ar', ['N.!Ar,O.!Ar,P.!Ar,.!ArS,F,Cl,Br,I', 'N.!Ar,O.!Ar,P.!Ar,S.!Ar,F,Cl,Br,I', 'N.!Ar,O.!Ar,P.!Ar,S.!Ar,F,Cl,Br,I', 'N.!Ar,O.!Ar,P.!Ar,S.!Ar,F,Cl,Br,I,H'], ['-', '-', '-', '-']) ? 1 : 0;
 818 }
 819 
 820 # C5 - C = heteroatom - '[C]=[A#X]'
 821 #
 822 sub _IsC5Carbon {
 823   my($This, $Atom) = @_;
 824 
 825   return $Atom->DoesAtomNeighborhoodMatch('C.!Ar', ['!C.!Ar'], ['=']) ? 1 : 0;
 826 }
 827 
 828 # C6 - C = C aliphatic - '[CH2]=C','[CH1](=C)A','[CH0](=C)(A)A','[C](=C)=C'
 829 #
 830 sub _IsC6Carbon {
 831   my($This, $Atom) = @_;
 832 
 833   if ($Atom->DoesAtomNeighborhoodMatch('C.DB1.!Ar', ['C.!Ar', 'H,!H.!Ar', 'H,!H.!Ar'], ['=', '-', '-']) ||
 834      $Atom->DoesAtomNeighborhoodMatch('C.H0.DB2.!Ar', ['C.!Ar', 'C.!Ar'], ['=', '='])) {
 835     return 1;
 836   }
 837   return 0;
 838 }
 839 
 840 # C7 - acetylene, nitrile - '[CX2]#A'
 841 #
 842 sub _IsC7Carbon {
 843   my($This, $Atom) = @_;
 844 
 845   return $Atom->DoesAtomNeighborhoodMatch('C.T2.TB1', ['*', '*'], ['#', '-']) ? 1 : 0;
 846 }
 847 
 848 # C8 - primary aromatic carbon - '[CH3]c'
 849 #
 850 sub _IsC8Carbon {
 851   my($This, $Atom) = @_;
 852 
 853   return $Atom->DoesAtomNeighborhoodMatch('C.T4.!Ar', ['C.Ar', 'H', 'H', 'H'], ['-', '-', '-', '-']) ? 1 : 0;
 854 }
 855 
 856 # C9 - primary aromatic heteroatom - '[CH3][a#X]'
 857 #
 858 sub _IsC9Carbon {
 859   my($This, $Atom) = @_;
 860 
 861   return $Atom->DoesAtomNeighborhoodMatch('C.T4.!Ar', ['!C.Ar', 'H', 'H', 'H'], ['-', '-', '-', '-']) ? 1 : 0;
 862 }
 863 
 864 # C10 - secondary aromatic - '[CH2X4]a'
 865 #
 866 sub _IsC10Carbon {
 867   my($This, $Atom) = @_;
 868 
 869   return $Atom->DoesAtomNeighborhoodMatch('C.T4.!Ar', ['!H.Ar', '!H', 'H', 'H'], ['-', '-', '-', '-']) ? 1 : 0;
 870 }
 871 
 872 # C11 - tertiary aromatic - '[CHX4]a'
 873 #
 874 sub _IsC11Carbon {
 875   my($This, $Atom) = @_;
 876 
 877   return $Atom->DoesAtomNeighborhoodMatch('C.T4.!Ar', ['!H.Ar', '!H', '!H', 'H'], ['-', '-', '-', '-']) ? 1 : 0;
 878 }
 879 
 880 # C12 - quaternary aromatic - '[CH0X4]a'
 881 #
 882 sub _IsC12Carbon {
 883   my($This, $Atom) = @_;
 884 
 885   return $Atom->DoesAtomNeighborhoodMatch('C.T4.!Ar', ['!H.Ar', '!H', '!H', '!H'], ['-', '-', '-', '-']) ? 1 : 0;
 886 }
 887 
 888 # C13 - aromatic heteroatom - '[cH0]-[!(C,N,O,S,F,Cl,Br,I)]' or matching [ Table 1 annotations, Ref 89 ]
 889 # '[cH0]-[B,Si,P,As,Se,Sn,Hg]'
 890 #
 891 #
 892 sub _IsC13Carbon {
 893   my($This, $Atom) = @_;
 894 
 895   return $Atom->DoesAtomNeighborhoodMatch('C.Ar.H0', ['B,Si,P,As,Se,Sn,Hg'], ['-']) ? 1 : 0;
 896 }
 897 
 898 # C14 - aromatic halide - '[c][#9]'
 899 #
 900 sub _IsC14Carbon {
 901   my($This, $Atom) = @_;
 902 
 903   return $Atom->DoesAtomNeighborhoodMatch('C.Ar', ['F'], ['-']) ? 1 : 0;
 904 }
 905 
 906 # C15 - aromatic halide - '[c][#17]'
 907 #
 908 sub _IsC15Carbon {
 909   my($This, $Atom) = @_;
 910 
 911   return $Atom->DoesAtomNeighborhoodMatch('C.Ar', ['Cl'], ['-']) ? 1 : 0;
 912 }
 913 
 914 # C16 - aromatic halide - '[c][#35]'
 915 #
 916 sub _IsC16Carbon {
 917   my($This, $Atom) = @_;
 918 
 919   return $Atom->DoesAtomNeighborhoodMatch('C.Ar', ['Br'], ['-']) ? 1 : 0;
 920 }
 921 
 922 # C17 - aromatic halide - '[c][#53]'
 923 #
 924 sub _IsC17Carbon {
 925   my($This, $Atom) = @_;
 926 
 927   return $Atom->DoesAtomNeighborhoodMatch('C.Ar', ['I'], ['-']) ? 1 : 0;
 928 }
 929 
 930 # C18 - aromatic - '[cH]'
 931 #
 932 sub _IsC18Carbon {
 933   my($This, $Atom) = @_;
 934 
 935   return $Atom->DoesAtomNeighborhoodMatch('C.Ar', ['H'], ['-']) ? 1 : 0;
 936 }
 937 
 938 # C19 - aromatic bridgehead - '[c](:a)(:a):a'
 939 #
 940 sub _IsC19Carbon {
 941   my($This, $Atom) = @_;
 942 
 943   return $Atom->DoesAtomNeighborhoodMatch('C.Ar', ['!H.Ar', '!H.Ar', '!H.Ar'], [':', ':', ':']) ? 1 : 0;
 944 }
 945 
 946 # C20 - quaternary aromatic - '[c](:a)(:a)-a'
 947 #
 948 sub _IsC20Carbon {
 949   my($This, $Atom) = @_;
 950 
 951   return $Atom->DoesAtomNeighborhoodMatch('C.Ar', ['!H.Ar', '!H.Ar', '!H.Ar'], [':', ':', '-.!:']) ? 1 : 0;
 952 }
 953 
 954 # C21 - quaternary aromatic - '[c](:a)(:a)-C'
 955 #
 956 sub _IsC21Carbon {
 957   my($This, $Atom) = @_;
 958 
 959   return $Atom->DoesAtomNeighborhoodMatch('C.Ar', ['!H.Ar', '!H.Ar', 'C.!Ar'], [':', ':', '-']) ? 1 : 0;
 960 }
 961 
 962 # C22 - quaternary aromatic - '[c](:a)(:a)-N'
 963 #
 964 sub _IsC22Carbon {
 965   my($This, $Atom) = @_;
 966 
 967   return $Atom->DoesAtomNeighborhoodMatch('C.Ar', ['!H.Ar', '!H.Ar', 'N.!Ar'], [':', ':', '-']) ? 1 : 0;
 968 }
 969 
 970 # C23 - quaternary aromatic - '[c](:a)(:a)-O'
 971 #
 972 sub _IsC23Carbon {
 973   my($This, $Atom) = @_;
 974 
 975   return $Atom->DoesAtomNeighborhoodMatch('C.Ar', ['!H.Ar', '!H.Ar', 'O.!Ar'], [':', ':', '-']) ? 1 : 0;
 976 }
 977 
 978 # C24 - quaternary aromatic - '[c](:a)(:a)-S'
 979 #
 980 sub _IsC24Carbon {
 981   my($This, $Atom) = @_;
 982 
 983   return $Atom->DoesAtomNeighborhoodMatch('C.Ar', ['!H.Ar', '!H.Ar', 'S.!Ar'], [':', ':', '-']) ? 1 : 0;
 984 }
 985 
 986 # C25 - quaternary aromatic - '[c](:a)(:a)=C','[c](:a)(:a)=N','[c](:a)(:a)=O'
 987 #
 988 sub _IsC25Carbon {
 989   my($This, $Atom) = @_;
 990 
 991   return $Atom->DoesAtomNeighborhoodMatch('C.Ar', ['!H.Ar', '!H.Ar', 'C.!Ar,N.!Ar,O.!Ar'], [':', ':', '=']) ? 1 : 0;
 992 }
 993 
 994 # C26 - C = C aromatic - '[C](=C)(a)A','[C](=C)(c)a','[CH](=C)a','[C]=c'
 995 #
 996 sub _IsC26Carbon {
 997   my($This, $Atom) = @_;
 998 
 999   if ($Atom->DoesAtomNeighborhoodMatch('C.!Ar.T3', ['C.!Ar', '!H.Ar', '!H.!Ar'], ['=', '-', '-']) ||
1000      $Atom->DoesAtomNeighborhoodMatch('C.!Ar.T3', ['C.!Ar', 'C.Ar', '!H.Ar'], ['=', '-', '-']) ||
1001      $Atom->DoesAtomNeighborhoodMatch('C.!Ar.T3.H1', ['C.!Ar', '!H.Ar', 'H'], ['=', '-', '-']) ||
1002      $Atom->DoesAtomNeighborhoodMatch('C.!Ar', ['C.Ar'], ['='])) {
1003     return 1;
1004   }
1005   return 0;
1006 }
1007 
1008 # C27 - aliphatic heteroatom - '[CX4][!(C,N,O,P,S,F,Cl,Br,I)]'
1009 #
1010 # Notes:
1011 #   . X4 implies four neighbors including Hydrogen
1012 #   . For C27 match, at least one of the neighbors must be a hetro atom other
1013 #     than C,N,O,P,S,F,Cl,Br,I. In other words, it's primary, secondary, tertiary,
1014 #     or queaternary aliphatic heteroatom not in (C,N,O,P,S,F,Cl,Br,I) group defined
1015 #     using C3 and C4.
1016 #
1017 sub _IsC27Carbon {
1018   my($This, $Atom) = @_;
1019   my($AtomNeighbor, $AtomNeighborSymbol);
1020 
1021   if (!$Atom->DoesAtomNeighborhoodMatch('C.T4.!Ar')) {
1022     return 0;
1023   }
1024 
1025   ATOMNEIGHBOR: for $AtomNeighbor ($Atom->GetNonHydrogenAtomNeighbors()) {
1026     $AtomNeighborSymbol = $AtomNeighbor->GetAtomSymbol();
1027     # Is it a heteroatom?
1028     if ($AtomNeighborSymbol =~ /^(C|N|O|P|S|F|Cl|Br|I|H)$/) {
1029       next ATOMNEIGHBOR;
1030     }
1031     # Is it aromatic?
1032     if ($AtomNeighbor->IsAromatic()) {
1033       next ATOMNEIGHBOR;
1034     }
1035     return 1;
1036   }
1037   return 0;
1038 }
1039 
1040 # CS - carbon supplemental not matching any basic C type - '[#6]'
1041 #
1042 sub _IsCSCarbon {
1043   my($This, $Atom) = @_;
1044 
1045   return $Atom->IsCarbon() ? 1 : 0;
1046 }
1047 
1048 # Get SLogP atom type for Nitrogen with only sigma bonds...
1049 #
1050 sub _GetAtomTypeForNitrogenWithOnlySigmaBonds {
1051   my($This, $Atom) = @_;
1052   my($AtomType);
1053 
1054   $AtomType = 'None';
1055 
1056   ATOMTYPE: {
1057 
1058     # N1 - primary amine - '[NH2+0]A'
1059     if ($This->_IsN1Nitrogen($Atom)) {
1060       $AtomType = 'N1';
1061       last ATOMTYPE;
1062     }
1063 
1064     # N2 - secondary amine - '[NH+0](A)A'
1065     if ($This->_IsN2Nitrogen($Atom)) {
1066       $AtomType = 'N2';
1067       last ATOMTYPE;
1068     }
1069 
1070     # N3 - primary aromatic amine - '[NH2+0]a'
1071     if ($This->_IsN3Nitrogen($Atom)) {
1072       $AtomType = 'N3';
1073       last ATOMTYPE;
1074     }
1075 
1076     # N4 - secondary aromatic amine - '[NH+0](A)a','[NH+0](a)a'
1077     if ($This->_IsN4Nitrogen($Atom)) {
1078       $AtomType = 'N4';
1079       last ATOMTYPE;
1080     }
1081 
1082     # N7 - tertiary amine - '[N+0](A)(A)A'
1083     if ($This->_IsN7Nitrogen($Atom)) {
1084       $AtomType = 'N7';
1085       last ATOMTYPE;
1086     }
1087 
1088     # N8 - tertiary aromatic amine - '[N+0](a)(A)A','[N+0](a)(a)A','[N+0](a)(a)a'
1089     if ($This->_IsN8Nitrogen($Atom)) {
1090       $AtomType = 'N8';
1091       last ATOMTYPE;
1092     }
1093 
1094     # N10 - protonated amine - '[NH3+*]','[NH2+*]','[NH+*]'
1095     if ($This->_IsN10Nitrogen($Atom)) {
1096       $AtomType = 'N10';
1097       last ATOMTYPE;
1098     }
1099 
1100     # N11 - unprotonated aromatic - '[n+0]'
1101     if ($This->_IsN11Nitrogen($Atom)) {
1102       $AtomType = 'N11';
1103       last ATOMTYPE;
1104     }
1105 
1106     # N12 - protonated aromatic - '[n+*]'
1107     if ($This->_IsN12Nitrogen($Atom)) {
1108       $AtomType = 'N12';
1109       last ATOMTYPE;
1110     }
1111 
1112     # N13 - quaternary amine - '[NH0+*](A)(A)(A)A','[NH0+*](=A)(A)A','[NH0+*](=A)(A)a','[NH0+*](=[#6])=[#7]'
1113     if ($This->_IsN13Nitrogen($Atom)) {
1114       $AtomType = 'N13';
1115       last ATOMTYPE;
1116     }
1117 
1118     # N14 - other ionized nitrogen - '[N+*]#A','[N-*]','[N+*](=[N-*])=N'
1119     if ($This->_IsN14Nitrogen($Atom)) {
1120       $AtomType = 'N14';
1121       last ATOMTYPE;
1122     }
1123 
1124     $AtomType = 'NS';
1125   }
1126 
1127   return $AtomType;
1128 }
1129 
1130 # Get SLogP atom type for Nitrogen with one pi bond...
1131 #
1132 sub _GetAtomTypeForNitrogenWithOnePiBond {
1133   my($This, $Atom) = @_;
1134   my($AtomType);
1135 
1136   $AtomType = 'None';
1137 
1138   ATOMTYPE: {
1139 
1140     # N5 - imine - '[NH+0]=A','[NH+0]=a'
1141     if ($This->_IsN5Nitrogen($Atom)) {
1142       $AtomType = 'N5';
1143       last ATOMTYPE;
1144     }
1145 
1146     # N6 - substituted imine - '[N+0](=A)A','[N+0](=A)a','[N+0](=a)A','[N+0](=a)a'
1147     if ($This->_IsN6Nitrogen($Atom)) {
1148       $AtomType = 'N6';
1149       last ATOMTYPE;
1150     }
1151 
1152     # N11 - unprotonated aromatic - '[n+0]'
1153     if ($This->_IsN11Nitrogen($Atom)) {
1154       $AtomType = 'N11';
1155       last ATOMTYPE;
1156     }
1157 
1158     # N12 - protonated aromatic - '[n+*]'
1159     if ($This->_IsN12Nitrogen($Atom)) {
1160       $AtomType = 'N12';
1161       last ATOMTYPE;
1162     }
1163 
1164     # N13 - quaternary amine - '[NH0+*](A)(A)(A)A','[NH0+*](=A)(A)A','[NH0+*](=A)(A)a','[NH0+*](=[#6])=[#7]'
1165     if ($This->_IsN13Nitrogen($Atom)) {
1166       $AtomType = 'N13';
1167       last ATOMTYPE;
1168     }
1169 
1170     # N14 - other ionized nitrogen - '[N+*]#A','[N-*]','[N+*](=[N-*])=N'
1171     if ($This->_IsN14Nitrogen($Atom)) {
1172       $AtomType = 'N14';
1173       last ATOMTYPE;
1174     }
1175 
1176     $AtomType = 'NS';
1177   }
1178 
1179   return $AtomType;
1180 }
1181 
1182 # Get SLogP atom type for Nitrogen with two pi bonds...
1183 #
1184 sub _GetAtomTypeForNitrogenWithTwoPiBonds {
1185   my($This, $Atom) = @_;
1186   my($AtomType);
1187 
1188   $AtomType = 'None';
1189 
1190   ATOMTYPE: {
1191 
1192     # N9 - nitrile - '[N+0]#A'
1193     if ($This->_IsN9Nitrogen($Atom)) {
1194       $AtomType = 'N9';
1195       last ATOMTYPE;
1196     }
1197 
1198     # N13 - quaternary amine - '[NH0+*](A)(A)(A)A','[NH0+*](=A)(A)A','[NH0+*](=A)(A)a','[NH0+*](=[#6])=[#7]'
1199     if ($This->_IsN13Nitrogen($Atom)) {
1200       $AtomType = 'N13';
1201       last ATOMTYPE;
1202     }
1203 
1204     # N14 - other ionized nitrogen - '[N+*]#A','[N-*]','[N+*](=[N-*])=N'
1205     if ($This->_IsN14Nitrogen($Atom)) {
1206       $AtomType = 'N14';
1207       last ATOMTYPE;
1208     }
1209 
1210     $AtomType = 'NS';
1211   }
1212 
1213   return $AtomType;
1214 }
1215 
1216 # N1 - primary amine - '[NH2+0]A'
1217 #
1218 sub _IsN1Nitrogen {
1219   my($This, $Atom) = @_;
1220 
1221   return $Atom->DoesAtomNeighborhoodMatch('N.!Ar.T3.FC0', ['!H.!Ar', 'H', 'H'], ['-', '-', '-']) ? 1 : 0;
1222 }
1223 
1224 # N2 - secondary amine - '[NH+0](A)A'
1225 #
1226 sub _IsN2Nitrogen {
1227   my($This, $Atom) = @_;
1228 
1229   return $Atom->DoesAtomNeighborhoodMatch('N.!Ar.T3.FC0', ['!H.!Ar', '!H.!Ar', 'H'], ['-', '-', '-']) ? 1 : 0;
1230 }
1231 
1232 # N3 - primary aromatic amine - '[NH2+0]a'
1233 #
1234 sub _IsN3Nitrogen {
1235   my($This, $Atom) = @_;
1236 
1237   return $Atom->DoesAtomNeighborhoodMatch('N.!Ar.T3.FC0', ['!H.Ar', 'H', 'H'], ['-', '-', '-']) ? 1 : 0;
1238 }
1239 
1240 # N4 - secondary aromatic amine - '[NH+0](A)a','[NH+0](a)a'
1241 #
1242 sub _IsN4Nitrogen {
1243   my($This, $Atom) = @_;
1244 
1245   return $Atom->DoesAtomNeighborhoodMatch('N.!Ar.T3.FC0', ['!H.Ar', '!H', 'H'], ['-', '-', '-']) ? 1 : 0;
1246 }
1247 
1248 # N5 - imine - '[NH+0]=A','[NH+0]=a'
1249 #
1250 sub _IsN5Nitrogen {
1251   my($This, $Atom) = @_;
1252 
1253   return $Atom->DoesAtomNeighborhoodMatch('N.!Ar.T2.FC0', ['!H', 'H'], ['=', '-']) ? 1 : 0;
1254 }
1255 
1256 # N6 - substituted imine - '[N+0](=A)A','[N+0](=A)a','[N+0](=a)A','[N+0](=a)a'
1257 #
1258 sub _IsN6Nitrogen {
1259   my($This, $Atom) = @_;
1260 
1261   return $Atom->DoesAtomNeighborhoodMatch('N.!Ar.T2.FC0', ['!H', '!H'], ['=', '-']) ? 1 : 0;
1262 }
1263 
1264 # N7 - tertiary amine - '[N+0](A)(A)A'
1265 #
1266 sub _IsN7Nitrogen {
1267   my($This, $Atom) = @_;
1268 
1269   return $Atom->DoesAtomNeighborhoodMatch('N.!Ar.T3.FC0', ['!H.!Ar', '!H.!Ar', '!H.!Ar'], ['-', '-', '-']) ? 1 : 0;
1270 }
1271 
1272 # N8 - tertiary aromatic amine - '[N+0](a)(A)A','[N+0](a)(a)A','[N+0](a)(a)a'
1273 #
1274 sub _IsN8Nitrogen {
1275   my($This, $Atom) = @_;
1276 
1277   return $Atom->DoesAtomNeighborhoodMatch('N.!Ar.T3.FC0', ['!H.Ar', '!H', '!H'], ['-', '-', '-']) ? 1 : 0;
1278 }
1279 
1280 # N9 - nitrile - '[N+0]#A'
1281 #
1282 sub _IsN9Nitrogen {
1283   my($This, $Atom) = @_;
1284 
1285   return $Atom->DoesAtomNeighborhoodMatch('N.!Ar.T1.FC0', ['!H.!Ar'], ['#']) ? 1 : 0;
1286 }
1287 
1288 # N10 - protonated amine - '[NH3+*]','[NH2+*]','[NH+*]'
1289 #
1290 sub _IsN10Nitrogen {
1291   my($This, $Atom) = @_;
1292 
1293   return $Atom->DoesAtomNeighborhoodMatch('N.!Ar.FC+*.H3,N.!Ar.FC+*.H2,N.!Ar.FC+*.H1') ? 1 : 0;
1294 }
1295 
1296 # N11 - unprotonated aromatic - '[n+0]'
1297 #
1298 sub _IsN11Nitrogen {
1299   my($This, $Atom) = @_;
1300 
1301   return $Atom->DoesAtomNeighborhoodMatch('N.Ar.FC0.H0') ? 1 : 0;
1302 }
1303 
1304 # N12 - protonated aromatic - '[n+*]'
1305 #
1306 sub _IsN12Nitrogen {
1307   my($This, $Atom) = @_;
1308 
1309   return $Atom->DoesAtomNeighborhoodMatch('N.Ar.FC+*.!H0') ? 1 : 0;
1310 }
1311 
1312 # N13 - quaternary amine - '[NH0+*](A)(A)(A)A','[NH0+*](=A)(A)A','[NH0+*](=A)(A)a','[NH0+*](=[#6])=[#7]'
1313 #
1314 sub _IsN13Nitrogen {
1315   my($This, $Atom) = @_;
1316 
1317   if ($Atom->DoesAtomNeighborhoodMatch('N.!Ar.FC+*.T4.H0', ['!H.!Ar', '!H.!Ar', '!H.!Ar', '!H.!Ar'], ['-', '-', '-', '-']) ||
1318      $Atom->DoesAtomNeighborhoodMatch('N.!Ar.FC+*.T3.H0', ['!H.!Ar', '!H.!Ar', '!H.!Ar'], ['=', '-', '-']) ||
1319      $Atom->DoesAtomNeighborhoodMatch('N.!Ar.FC+*.T3.H0', ['!H.!Ar', '!H.!Ar', '!H.Ar'], ['=', '-', '-']) ||
1320      $Atom->DoesAtomNeighborhoodMatch('N.!Ar.FC+*.T2.H0', ['C.!Ar', 'N.!Ar'], ['=', '=']) ) {
1321     return 1;
1322   }
1323   return 0;
1324 }
1325 
1326 # N14 - other ionized nitrogen - '[N+*]#A','[N-*]','[N+*](=[N-*])=N'
1327 #
1328 sub _IsN14Nitrogen {
1329   my($This, $Atom) = @_;
1330 
1331   if ($Atom->DoesAtomNeighborhoodMatch('N.!Ar.FC+*', ['!H.!Ar'], ['#']) ||
1332      $Atom->DoesAtomNeighborhoodMatch('N.!Ar.FC-*') ||
1333      $Atom->DoesAtomNeighborhoodMatch('N.!Ar.FC+*', ['N.!Ar.FC-*', 'N.!Ar'], ['=', '=']) ) {
1334     return 1;
1335   }
1336   return 0;
1337 }
1338 
1339 # NS - nitrogen supplemental not matching any basic N type - '[#7]'
1340 #
1341 sub _IsNSNitrogen {
1342   my($This, $Atom) = @_;
1343 
1344   return $Atom->IsNitrogen() ? 1 : 0;
1345 }
1346 
1347 # Get SLogP atom type for Oxygen with only sigma bonds...
1348 #
1349 sub _GetAtomTypeForOxygenWithOnlySigmaBonds {
1350   my($This, $Atom) = @_;
1351   my($AtomType);
1352 
1353   $AtomType = 'None';
1354 
1355   ATOMTYPE: {
1356 
1357     # O1 - aromatic - '[o]'
1358     if ($This->_IsO1Oxygen($Atom)) {
1359       $AtomType = 'O1';
1360       last ATOMTYPE;
1361     }
1362 
1363     # O2 - alcohol - '[OH]','[OH2]'
1364     if ($This->_IsO2Oxygen($Atom)) {
1365       $AtomType = 'O2';
1366       last ATOMTYPE;
1367     }
1368 
1369     # O3 - aliphatic ether - '[O](C)C','[O](C)[A#X]','[O]([A#X])[A#X]'
1370     if ($This->_IsO3Oxygen($Atom)) {
1371       $AtomType = 'O3';
1372       last ATOMTYPE;
1373     }
1374 
1375     # O4 - aromatic ether - '[O](A)a','[O](a)a'
1376     if ($This->_IsO4Oxygen($Atom)) {
1377       $AtomType = 'O4';
1378       last ATOMTYPE;
1379     }
1380 
1381     # O5 - oxide - '[O]=[#8]','[O]=[#7]','[OX1-*][#7]'
1382     if ($This->_IsO5Oxygen($Atom)) {
1383       $AtomType = 'O5';
1384       last ATOMTYPE;
1385     }
1386 
1387     # O6 - oxide - '[OX1-*][#16]'
1388     if ($This->_IsO6Oxygen($Atom)) {
1389       $AtomType = 'O6';
1390       last ATOMTYPE;
1391     }
1392 
1393     # O7 - oxide - '[OX1-*][!(N,S)]'
1394     if ($This->_IsO7Oxygen($Atom)) {
1395       $AtomType = 'O7';
1396       last ATOMTYPE;
1397     }
1398 
1399     # O12 - acid - '[O-1]C(=O)'
1400     if ($This->_IsO12Oxygen($Atom)) {
1401       $AtomType = 'O12';
1402       last ATOMTYPE;
1403     }
1404 
1405     $AtomType = 'OS';
1406   }
1407 
1408   return $AtomType;
1409 }
1410 
1411 # Get SLogP atom type for Oxygen with only sigma bonds...
1412 #
1413 sub _GetAtomTypeForOxygenWithOnePiBond {
1414   my($This, $Atom) = @_;
1415   my($AtomType);
1416 
1417   $AtomType = 'None';
1418 
1419   ATOMTYPE: {
1420 
1421     # O1 - aromatic - '[o]'
1422     if ($This->_IsO1Oxygen($Atom)) {
1423       $AtomType = 'O1';
1424       last ATOMTYPE;
1425     }
1426 
1427     # O5 - oxide - '[O]=[#8]','[O]=[#7]','[OX1-*][#7]'
1428     if ($This->_IsO5Oxygen($Atom)) {
1429       $AtomType = 'O5';
1430       last ATOMTYPE;
1431     }
1432 
1433     # O8 - aromatic carbonyl - '[O]=c'
1434     if ($This->_IsO8Oxygen($Atom)) {
1435       $AtomType = 'O8';
1436       last ATOMTYPE;
1437     }
1438 
1439     # O9 - carbonyl aliphatic - '[O]=[CH]C','[O]=C(C)C','[O]=C(C)[A#X]','[O]=[CH]N','[O]=[CH]O','[O]=[CH2]','[O]=[CX2]=O'
1440     if ($This->_IsO9Oxygen($Atom)) {
1441       $AtomType = 'O9';
1442       last ATOMTYPE;
1443     }
1444 
1445     # O10 - carbonyl aromatic - '[O]=[CH]c','[O]=C(C)c','[O]=C(c)c','[O]=C(c)[a#X]','[O]=C(c)[A#X]','[O]=C(C)[a#X]'
1446     if ($This->_IsO10Oxygen($Atom)) {
1447       $AtomType = 'O10';
1448       last ATOMTYPE;
1449     }
1450 
1451     # O11 - carbonyl heteroatom - '[O]=C([A#X])[A#X]','[O]=C([A#X])[a#X]','[O]=C([a#X])[a#X]'
1452     if ($This->_IsO11Oxygen($Atom)) {
1453       $AtomType = 'O11';
1454       last ATOMTYPE;
1455     }
1456 
1457     $AtomType = 'OS';
1458   }
1459 
1460   return $AtomType;
1461 }
1462 
1463 # O1 - aromatic - '[o]'
1464 #
1465 sub _IsO1Oxygen {
1466   my($This, $Atom) = @_;
1467 
1468   return $Atom->DoesAtomNeighborhoodMatch('O.Ar') ? 1 : 0;
1469 }
1470 
1471 # O2 - alcohol - '[OH]','[OH2]'
1472 #
1473 sub _IsO2Oxygen {
1474   my($This, $Atom) = @_;
1475 
1476   if ($Atom->DoesAtomNeighborhoodMatch('O.TSB2.!Ar', ['C', 'H'], ['-', '-']) ||
1477      $Atom->DoesAtomNeighborhoodMatch('O.TSB2.!Ar', ['H', 'H'])) {
1478     return 1;
1479   }
1480   return 0;
1481 }
1482 
1483 # O3 - aliphatic ether - '[O](C)C','[O](C)[A#X]','[O]([A#X])[A#X]'
1484 #
1485 sub _IsO3Oxygen {
1486   my($This, $Atom) = @_;
1487 
1488   return $Atom->DoesAtomNeighborhoodMatch('O.!Ar.X2', ['!H.!Ar', '!H.!Ar'], ['-', '-']) ? 1 : 0;
1489 }
1490 
1491 # O4 - aromatic ether - '[O](A)a','[O](a)a'
1492 #
1493 sub _IsO4Oxygen {
1494   my($This, $Atom) = @_;
1495 
1496   return $Atom->DoesAtomNeighborhoodMatch('O.X2.!Ar', ['!H', '!H.Ar'], ['-', '-']) ? 1 : 0;
1497 }
1498 
1499 # O5 - oxide - '[O]=[#8]','[O]=[#7]','[OX1-*][#7]'
1500 #
1501 sub _IsO5Oxygen {
1502   my($This, $Atom) = @_;
1503 
1504   if ($Atom->DoesAtomNeighborhoodMatch('O.DB1.FC0', ['N,O'], ['=']) ||
1505      $Atom->DoesAtomNeighborhoodMatch('O.T1.FC-*', ['N'], ['-']))  {
1506     return 1;
1507   }
1508   return 0;
1509 }
1510 
1511 # O6 - oxide - '[OX1-*][#16]'
1512 #
1513 sub _IsO6Oxygen {
1514   my($This, $Atom) = @_;
1515 
1516   return $Atom->DoesAtomNeighborhoodMatch('O.T1.FC-*', ['S'], ['-']) ? 1 : 0;
1517 }
1518 
1519 # O7 - oxide - '[OX1-*][!(N,S)]'  or matching [ Table 1 annotations, Ref 89 ]
1520 #  '[OX1-*](P,As,Tc,I)
1521 #
1522 sub _IsO7Oxygen {
1523   my($This, $Atom) = @_;
1524 
1525   return $Atom->DoesAtomNeighborhoodMatch('O.T1.FC-*', ['P,As,Tc,I'], ['-']) ? 1 : 0;
1526 }
1527 
1528 # O8 - aromatic carbonyl - '[O]=c'
1529 #
1530 sub _IsO8Oxygen {
1531   my($This, $Atom) = @_;
1532 
1533   return $Atom->DoesAtomNeighborhoodMatch('O.DB1.!Ar', ['C.Ar'], ['=']) ? 1 : 0;
1534 }
1535 
1536 # O9 - carbonyl aliphatic - '[O]=[CH]C','[O]=C(C)C','[O]=C(C)[A#X]','[O]=[CH]N','[O]=[CH]O','[O]=[CH2]','[O]=[CX2]=O'
1537 #
1538 sub _IsO9Oxygen {
1539   my($This, $Atom) = @_;
1540   my($AtomNeighbor);
1541 
1542   # Is it a doubly bonded non-aromatic Oxygen?
1543   if (!$Atom->DoesAtomNeighborhoodMatch('O.DB1.!Ar.FC0')) {
1544     return 0;
1545   }
1546 
1547   # Is it attached to appopriate Carbon?
1548   for $AtomNeighbor ($Atom->GetNeighborsUsingAtomSpecification('C')) {
1549     if ($AtomNeighbor->DoesAtomNeighborhoodMatch('C.DB1.T3', ['O.!Ar', 'C.!Ar', 'H,C.!Ar'], ['=', '-', '-'])  ||
1550        $AtomNeighbor->DoesAtomNeighborhoodMatch('C.DB1.T3.H0', ['O.!Ar', '!C.!Ar', 'C.!Ar'], ['=', '-', '-'])  ||
1551        $AtomNeighbor->DoesAtomNeighborhoodMatch('C.DB1.T3', ['O.!Ar', 'N.!Ar,O.!Ar', 'H'], ['=', '-', '-']) ||
1552        $AtomNeighbor->DoesAtomNeighborhoodMatch('C.DB1.T3', ['O.!Ar', 'H', 'H'], ['=', '-', '-']) ||
1553        $AtomNeighbor->DoesAtomNeighborhoodMatch('C.DB2.T2', ['O.!Ar', 'O.!Ar'], ['=', '='])) {
1554       return 1;
1555     }
1556   }
1557   return 0;
1558 }
1559 
1560 # O10 - carbonyl aromatic - '[O]=[CH]c','[O]=C(C)c','[O]=C(c)c','[O]=C(c)[a#X]','[O]=C(c)[A#X]','[O]=C(C)[a#X]'
1561 #
1562 sub _IsO10Oxygen {
1563   my($This, $Atom) = @_;
1564   my($AtomNeighbor);
1565 
1566   # Is it a doubly bonded non-aromatic Oxygen?
1567   if (!$Atom->DoesAtomNeighborhoodMatch('O.DB1.!Ar.FC0')) {
1568     return 0;
1569   }
1570 
1571   # Is it attached to appopriate Carbon?
1572   for $AtomNeighbor ($Atom->GetNeighborsUsingAtomSpecification('C')) {
1573     if ($AtomNeighbor->DoesAtomNeighborhoodMatch('C.DB1.T3', ['O.!Ar', 'C.Ar', 'H'], ['=', '-', '-'])  ||
1574        $AtomNeighbor->DoesAtomNeighborhoodMatch('C.DB1.T3', ['O.!Ar', 'C.Ar', 'C.!Ar'], ['=', '-', '-'])  ||
1575        $AtomNeighbor->DoesAtomNeighborhoodMatch('C.DB1.T3', ['O.!Ar', 'C.Ar', 'C.Ar'], ['=', '-', '-'])  ||
1576        $AtomNeighbor->DoesAtomNeighborhoodMatch('C.DB1.T3.H0', ['O.!Ar', '!C', 'C.Ar'], ['=', '-', '-'])  ||
1577        $AtomNeighbor->DoesAtomNeighborhoodMatch('C.DB1.T3.H0', ['O.!Ar', '!C.Ar', 'C.!Ar'], ['=', '-', '-'])) {
1578       return 1;
1579     }
1580   }
1581   return 0;
1582 }
1583 
1584 # O11 - carbonyl heteroatom - '[O]=C([A#X])[A#X]','[O]=C([A#X])[a#X]','[O]=C([a#X])[a#X]'
1585 #
1586 sub _IsO11Oxygen {
1587   my($This, $Atom) = @_;
1588   my($AtomNeighbor);
1589 
1590   # Is it a doubly bonded non-aromatic Oxygen?
1591   if (!$Atom->DoesAtomNeighborhoodMatch('O.DB1.!Ar.FC0')) {
1592     return 0;
1593   }
1594 
1595   # Is it attached to appopriate Carbon?
1596   for $AtomNeighbor ($Atom->GetNeighborsUsingAtomSpecification('C')) {
1597     if ($AtomNeighbor->DoesAtomNeighborhoodMatch('C.DB1.T3.H0', ['O.!Ar', '!C', '!C'], ['=', '-', '-'])) {
1598       return 1;
1599     }
1600   }
1601   return 0;
1602 }
1603 
1604 # O12 - acid - '[O-1]C(=O)'
1605 #
1606 sub _IsO12Oxygen {
1607   my($This, $Atom) = @_;
1608   my($AtomNeighbor);
1609 
1610   # Is it a acid Oxygen?
1611   if (!$Atom->DoesAtomNeighborhoodMatch('O.DB0.!Ar.FC-1')) {
1612     return 0;
1613   }
1614 
1615   # Is it attached to appopriate Carbon?
1616   for $AtomNeighbor ($Atom->GetNeighborsUsingAtomSpecification('C')) {
1617     if ($AtomNeighbor->DoesAtomNeighborhoodMatch('C.DB1.T3', ['O.FC0', 'O.FC-1'], ['=', '-'])) {
1618       return 1;
1619     }
1620   }
1621   return 0;
1622 }
1623 
1624 # OS - oxygen supplemental not matching any basic O type - '[#8]'
1625 #
1626 sub _IsOSOxygen {
1627   my($This, $Atom) = @_;
1628 
1629   return $Atom->IsOxygen() ? 1 : 0;
1630 }
1631 
1632 # S1 - aliphatic - '[S-0]'
1633 #
1634 sub _IsS1Sulfur {
1635   my($This, $Atom) = @_;
1636 
1637   return $Atom->DoesAtomNeighborhoodMatch('S.!Ar.FC0') ? 1 : 0;
1638 }
1639 
1640 # S2 - ionic sulfur - '[S-*]','[S+*]'
1641 #
1642 sub _IsS2Sulfur {
1643   my($This, $Atom) = @_;
1644 
1645   return $Atom->DoesAtomNeighborhoodMatch('S.!Ar.FC-*,S.!Ar.FC+*') ? 1 : 0;
1646 }
1647 
1648 # S3 - aromatic - '[s]'
1649 #
1650 sub _IsS3Sulfur {
1651   my($This, $Atom) = @_;
1652 
1653   return $Atom->DoesAtomNeighborhoodMatch('S.Ar') ? 1 : 0;
1654 }
1655 
1656 # Hal - all remaining s-block elements
1657 #
1658 sub _IsSBlockElement {
1659   my($This, $Atom) = @_;
1660   my($GroupNumber);
1661 
1662   $GroupNumber = $Atom->GetGroupNumber();
1663 
1664   return ($GroupNumber >= 1 && $GroupNumber <= 2) ? 1 : 0;
1665 }
1666 
1667 # Me1 - all remaining p-block elements
1668 #
1669 sub _IsPBlockElement {
1670   my($This, $Atom) = @_;
1671   my($GroupNumber);
1672 
1673   $GroupNumber = $Atom->GetGroupNumber();
1674 
1675   return ($GroupNumber >= 13 && $GroupNumber <= 18) ? 1 : 0;
1676 }
1677 
1678 # Me2 - all remaining d-block elements
1679 #
1680 sub _IsDBlockElement {
1681   my($This, $Atom) = @_;
1682   my($GroupNumber);
1683 
1684   $GroupNumber = $Atom->GetGroupNumber();
1685 
1686   return ($GroupNumber >= 3 && $GroupNumber <= 12) ? 1 : 0;
1687 }
1688 
1689 # H1 - hydrocarbon - '[#1][#6]','[#1][#1]'
1690 #
1691 sub _IsH1Hydrogen {
1692   my($This, $Atom) = @_;
1693 
1694   return $Atom->DoesAtomNeighborhoodMatch('H', ['C,H']) ? 1 : 0;
1695 }
1696 
1697 # H2 - alcohol - '[#1]O[CX4]','[#1]Oc','[#1]O[!(C,N,O,S)]','[#1][!C,N,O)]' or matching [ Table 1 annotations, Ref 89 ]
1698 # '[H]O[CX4]', '[H]Oc', '[H]O[H,B,Si,P,As,Sn]','[H][B,Si,P,S,Sn]'
1699 #
1700 sub _IsH2Hydrogen {
1701   my($This, $Atom) = @_;
1702   my($AtomNeighbor);
1703 
1704   # Is Hydrogen directly attached to B,Si,P,S,Sn?
1705   if ($Atom->DoesAtomNeighborhoodMatch('H', ['B,Si,P,S,Sn'], ['-'])) {
1706     return 1;
1707   }
1708 
1709   # Is Hydrogen directly attached to Oxygen?
1710   if (!$Atom->DoesAtomNeighborhoodMatch('H', ['O'])) {
1711     return 0;
1712   }
1713 
1714   # Is it attached to appropriate Oxygen?
1715   for $AtomNeighbor ($Atom->GetNeighborsUsingAtomSpecification('O')) {
1716     if ($AtomNeighbor->DoesAtomNeighborhoodMatch('O.T2', ['C.T4', 'H'], ['-', '-'])  ||
1717        $AtomNeighbor->DoesAtomNeighborhoodMatch('O.T2', ['C.Ar', 'H'], ['-', '-'])  ||
1718        $AtomNeighbor->DoesAtomNeighborhoodMatch('O.T2', ['B,Si,P,As,Sn', 'H'], ['-', '-']) ||
1719        $AtomNeighbor->DoesAtomNeighborhoodMatch('O.T2', ['H', 'H'], ['-', '-'])) {
1720       return 1;
1721     }
1722   }
1723   return 0;
1724 }
1725 
1726 # H3 - amine - '[#1][#7]','[#1]O[#7]'
1727 #
1728 sub _IsH3Hydrogen {
1729   my($This, $Atom) = @_;
1730   my($AtomNeighbor);
1731 
1732   # Is Hydrogen directly attached to Nitrogen?
1733   if ($Atom->DoesAtomNeighborhoodMatch('H', ['N'])) {
1734     return 1;
1735   }
1736 
1737   # Is Hydrogen directly attached to Oxygen?
1738   if (!$Atom->DoesAtomNeighborhoodMatch('H', ['O'])) {
1739     return 0;
1740   }
1741 
1742   # Is it attached to appropriate Oxygen?
1743   for $AtomNeighbor ($Atom->GetNeighborsUsingAtomSpecification('O')) {
1744     if ($AtomNeighbor->DoesAtomNeighborhoodMatch('O.T2', ['N', 'H'], ['-', '-'])) {
1745       return 1;
1746     }
1747   }
1748   return 0;
1749 }
1750 
1751 # H4 - acid - '[#1]OC=[#6]','[#1]OC=[#7]','[#1]OC=O','[#1]OC=S','[#1]OO','[#1]OS'
1752 #
1753 sub _IsH4Hydrogen {
1754   my($This, $Atom) = @_;
1755   my($AtomNeighbor, $AtomNbrOfNbr);
1756 
1757   # Get non-hydrogen atom neighbor...
1758   $AtomNeighbor = $Atom->GetNonHydrogenNeighborOfHydrogenAtom();
1759   if (!$AtomNeighbor) {
1760     return 0;
1761   }
1762 
1763   # Is it Oxygen neighbor?
1764   if (!$AtomNeighbor->IsOxygen()) {
1765     return 0;
1766   }
1767 
1768   # '[#1]OO','[#1]OS'
1769   if ($AtomNeighbor->DoesAtomNeighborhoodMatch('O.TSB2', ['O,S', 'H'], ['-', '-'])) {
1770     return 1;
1771   }
1772 
1773   # '[#1]OC=[#6]','[#1]OC=[#7]','[#1]OC=O','[#1]OC=S'
1774   for $AtomNbrOfNbr ($AtomNeighbor->GetNeighborsUsingAtomSpecification('C.DB1')) {
1775     if ($AtomNbrOfNbr->DoesAtomNeighborhoodMatch('C.T3.DB1', ['O.H1', 'O,C,N,S', '*'], ['-', '=', '-'])) {
1776       return 1;
1777     }
1778   }
1779   return 0;
1780 }
1781 
1782 # HS - hydrogen supplemental not matching any basic H type - '[#1]'
1783 #
1784 sub _IsHSHydrogen {
1785   my($This, $Atom) = @_;
1786 
1787   return $Atom->IsHydrogen() ? 1 : 0;
1788 }
1789 
1790 # Return a string containg data for SLogPAtomTypes object...
1791 #
1792 sub StringifySLogPAtomTypes {
1793   my($This) = @_;
1794   my($AtomTypesString);
1795 
1796   # Type of AtomTypes...
1797   $AtomTypesString = "AtomTypes: $This->{Type}; IgnoreHydrogens: " . ($This->{IgnoreHydrogens} ? "Yes" : "No");
1798 
1799   # Setup atom types information...
1800   my($AtomID, $AtomType, @AtomTypesInfo, %AssignedAtomTypes);
1801 
1802   @AtomTypesInfo = ();
1803   %AssignedAtomTypes = $This->GetAtomTypes();
1804 
1805   for $AtomID (sort { $a <=> $b } keys %AssignedAtomTypes) {
1806     $AtomType = $AssignedAtomTypes{$AtomID} ? $AssignedAtomTypes{$AtomID} : 'None';
1807     push @AtomTypesInfo, "$AtomID:$AtomType";
1808   }
1809   $AtomTypesString .= "; AtomIDs:AtomTypes: <" . TextUtil::JoinWords(\@AtomTypesInfo, ", ", 0) . ">";
1810 
1811   return $AtomTypesString;
1812 }
1813 
1814 # Is it a SLogPAtomTypes object?
1815 sub _IsSLogPAtomTypes {
1816   my($Object) = @_;
1817 
1818   return (Scalar::Util::blessed($Object) && $Object->isa($ClassName)) ? 1 : 0;
1819 }
1820 
1821 # Check and load SLogP atom types data...
1822 #
1823 sub _CheckAndLoadSLogPAtomTypesData {
1824 
1825   # Is it already loaded?
1826   if (exists $SLogPAtomTypesDataMap{AtomTypes}) {
1827     return;
1828   }
1829 
1830   _LoadSLogPAtomTypesData();
1831 }
1832 
1833 # Load SLogP atom types data from the file assuming first column to be atom type symbol..
1834 #
1835 # Format:
1836 #
1837 # "AtomTypeSymbol","Description","SMARTS","LogPContribution","MRContribution"
1838 # "C1","primary, secondary aliphatic","'[CH4]','[CH3]C','[CH2](C)C'","0.1441","2.503"
1839 # "C2","tertiary, quaternary aliphatic","'[CH](C)(C)C','[C](C)(C)(C)C'","0.0000","2.433"
1840 #
1841 sub _LoadSLogPAtomTypesData {
1842   my($AtomTypesDataFile, $MayaChemToolsLibDir);
1843 
1844   $MayaChemToolsLibDir = FileUtil::GetMayaChemToolsLibDirName();
1845 
1846   $AtomTypesDataFile =  "$MayaChemToolsLibDir" . "/data/SLogPAtomTypes.csv";
1847   if (! -e "$AtomTypesDataFile") {
1848     croak "Error: MayaChemTools package file, $AtomTypesDataFile, is missing: Possible installation problems...";
1849   }
1850 
1851   %SLogPAtomTypesDataMap = ();
1852   AtomTypes::AtomTypes::LoadAtomTypesData($AtomTypesDataFile, \%SLogPAtomTypesDataMap);
1853 }
1854