MayaChemTools

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