       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