MayaChemTools

   1 package AtomTypes::TPSAAtomTypes;
   2 #
   3 # File: TPSAAtomTypes.pm
   4 # Author: Manish Sud <msud@san.rr.com>
   5 #
   6 # Copyright (C) 2024 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 AtomTypes::AtomTypes;
  32 use Molecule;
  33 
  34 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  35 
  36 @ISA = qw(AtomTypes::AtomTypes Exporter);
  37 @EXPORT = qw(GetTPSAAtomTypesData GetAllPossibleTPSAAtomTypes);
  38 @EXPORT_OK = qw();
  39 
  40 %EXPORT_TAGS = (all  => [@EXPORT, @EXPORT_OK]);
  41 
  42 # Setup class variables...
  43 my($ClassName, %TPSAAtomTypesDataMap);
  44 _InitializeClass();
  45 
  46 # Overload Perl functions...
  47 use overload '""' => 'StringifyTPSAAtomTypes';
  48 
  49 # Class constructor...
  50 sub new {
  51   my($Class, %NamesAndValues) = @_;
  52 
  53   # Initialize object...
  54   my $This = $Class->SUPER::new();
  55   bless $This, ref($Class) || $Class;
  56   $This->_InitializeTPSAAtomTypes();
  57 
  58   $This->_InitializeTPSAAtomTypesProperties(%NamesAndValues);
  59 
  60   return $This;
  61 }
  62 
  63 # Initialize class ...
  64 sub _InitializeClass {
  65   #Class name...
  66   $ClassName = __PACKAGE__;
  67 
  68   # Initialize the data hash. It'll be loaded on demand later...
  69   %TPSAAtomTypesDataMap = ();
  70 }
  71 
  72 # Initialize object data...
  73 #
  74 sub _InitializeTPSAAtomTypes {
  75   my($This) = @_;
  76 
  77   # Type of AtomTypes...
  78   $This->{Type} = 'TPSA';
  79 
  80   # Besides polar atoms - N, O, P, S - no TPSA atom types are assigned to any other
  81   # atoms.
  82   #
  83   # By default, TPSA atom types are not assigned to Phosphorus and Sulfur atoms.
  84   #
  85   $This->{IgnorePhosphorus} = 0;
  86   $This->{IgnoreSulfur} = 0;
  87 
  88   return $This;
  89 }
  90 
  91 # Initialize object properties...
  92 #
  93 sub _InitializeTPSAAtomTypesProperties {
  94   my($This, %NamesAndValues) = @_;
  95 
  96   my($Name, $Value, $MethodName);
  97   while (($Name, $Value) = each  %NamesAndValues) {
  98     $MethodName = "Set${Name}";
  99     $This->$MethodName($Value);
 100   }
 101 
 102   # Make sure molecule object was specified...
 103   if (!exists $NamesAndValues{Molecule}) {
 104     croak "Error: ${ClassName}->New: Object can't be instantiated without specifying molecule...";
 105   }
 106 
 107   return $This;
 108 }
 109 
 110 # Get TPSA atom types and associated data loaded from TPSA data file as
 111 # a reference to hash with the following hash data format:
 112 #
 113 # @{$TPSAAtomTypesDataMap{AtomTypes}} - Array of all possible atom types for all atoms
 114 # @{$TPSAAtomTypesDataMap->{ColLabels}} - Array of column labels
 115 # %{$TPSAAtomTypesDataMap->{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 GetTPSAAtomTypesData {
 121 
 122   # Make sure data is loaded...
 123   _CheckAndLoadTPSAAtomTypesData();
 124 
 125   return \%TPSAAtomTypesDataMap;
 126 }
 127 
 128 # Get all possible TPSA atom types atoms as an array reference...
 129 #
 130 # This functionality can be either invoked as a class function or an
 131 # object method.
 132 #
 133 sub GetAllPossibleTPSAAtomTypes {
 134   return _GetAllPossibleTPSAAtomTypes();
 135 }
 136 
 137 # Are all atoms types successfully assigned?
 138 #
 139 # Notes:
 140 #   . Dynamic checking of atom types assignment for atoms eliminates the need
 141 #     to check and synchronize valid atom types during SetAtomType.
 142 #   . Base class method is overrided to check atom assignment to nitrogen and
 143 #     oxygen atom with optional check for phosphorus and sulfur atoms.
 144 #
 145 sub IsAtomTypesAssignmentSuccessful {
 146   my($This) = @_;
 147   my($Atom, $AtomType);
 148 
 149   ATOM: for $Atom ($This->{Molecule}->GetAtoms()) {
 150     if (!($Atom->IsNitrogen() || $Atom->IsOxygen() ||
 151         ($Atom->IsPhosphorus() && !$This->{IgnorePhosphorus}) ||
 152         ($Atom->IsSulfur() && !$This->{IgnoreSulfur}))) {
 153       next ATOM;
 154     }
 155     $AtomType = $This->GetAtomType($Atom);
 156     if ($AtomType =~ /^None$/i) {
 157       return 0;
 158     }
 159   }
 160 
 161   return 1;
 162 }
 163 
 164 # Get all possible TPSA atom types as an array reference...
 165 #
 166 sub _GetAllPossibleTPSAAtomTypes {
 167   my($TPSAAtomTypesDataRef);
 168 
 169   $TPSAAtomTypesDataRef = GetTPSAAtomTypesData();
 170 
 171   return \@{$TPSAAtomTypesDataRef->{AtomTypes}};
 172 }
 173 
 174 # Assign Topological Polar Surface Area (TPSA) atom types [ Ref 90-91 ] to Nitrogen and Oxygen
 175 # atoms with optional assignment to Phosphorus and Sulfur atoms.
 176 #
 177 # Notes:
 178 #     o Number of atom type symbols for:
 179 #         o N: 27
 180 #         o O: 7
 181 #         o P: 5
 182 #         o S: 8
 183 #
 184 sub AssignAtomTypes {
 185   my($This) = @_;
 186   my($Atom, $AtomType);
 187 
 188   ATOM: for $Atom ($This->GetMolecule()->GetAtoms()) {
 189     $AtomType = $This->_GetAtomType($Atom);
 190     $This->SetAtomType($Atom, $AtomType);
 191   }
 192 
 193   return $This;
 194 }
 195 
 196 # Get TPSA atom type for atom...
 197 #
 198 sub _GetAtomType {
 199   my($This, $Atom) = @_;
 200   my($AtomType);
 201 
 202   $AtomType = 'None';
 203 
 204   ATOM: {
 205     if ($Atom->IsNitrogen()) {
 206       $AtomType = $This->_GetAtomTypeForNitrogen($Atom);
 207       last ATOM;
 208     }
 209 
 210     if ($Atom->IsOxygen()) {
 211       $AtomType = $This->_GetAtomTypeForOxygen($Atom);
 212       last ATOM;
 213     }
 214 
 215     if ($Atom->IsPhosphorus() && !$This->{IgnorePhosphorus}) {
 216       $AtomType = $This->_GetAtomTypeForPhosphorus($Atom);
 217       last ATOM;
 218     }
 219 
 220     if ($Atom->IsSulfur() && !$This->{IgnoreSulfur}) {
 221       $AtomType = $This->_GetAtomTypeForSulfur($Atom);
 222       last ATOM;
 223     }
 224     $AtomType = 'None';
 225   }
 226 
 227   return $AtomType;
 228 }
 229 
 230 
 231 # Get TPSA atom type for Nitrogen atom...
 232 #
 233 # 27 AtomTypeSymbols for element N:
 234 #
 235 # AtomTypeSymbol - SMARTS - Comments
 236 # N1 - '[N](-*)(-*)-*'
 237 # N2 - '[N](-*)=*'
 238 # N3 - '[N]#*'
 239 # N4 - '[N](-*)(=*)=*' - As in nitro group
 240 # N5 - '[N](=*)#*' - Middle nitrogen in azide group
 241 # N6 - '[N]1(-*)-*-*-1' - Atom in a 3 membered ring
 242 # N7 - '[NH](-*)-*'
 243 # N8 - '[NH]1-*-*-1' - Atom in a 3 membered ring
 244 # N9 - '[NH]=*'
 245 # N10 - '[NH2]-*'
 246 # N11 - '[N+](-*)(-*)(-*)-*'
 247 # N12 - '[N+](-*)(-*)=*'
 248 # N13 - '[N+](-*)#*' - Nitrogen in isocyano group
 249 # N14 - '[NH+](-*)(-*)-*'
 250 # N15 - '[NH+](-*)=*'
 251 # N16 - '[NH2+](-*)-*'
 252 # N17 - '[NH2+]=*'
 253 # N18 - '[NH3+]-*'
 254 # N19 - '[n](:*):*'
 255 # N20 - '[n](:*)(:*):*'
 256 # N21 - '[n](-*)(:*):*'
 257 # N22 - '[n](=*)(:*):*' - As in pyridine N-oxide
 258 # N23 - '[nH](:*):*'
 259 # N24 - '[n+](:*)(:*):*'
 260 # N25 - '[n+](-*)(:*):*'
 261 # N26 - '[nH+](:*):*'
 262 # N - '[#7]' - Any other Nitrogen; Contribution: 30.5 - X*8.2 + H*1.5 or 0.0 for negative value
 263 #
 264 sub _GetAtomTypeForNitrogen {
 265   my($This, $Atom) = @_;
 266   my($AtomType, $NumOfSigmaBonds, $NumOfPiBonds);
 267 
 268   $AtomType = 'None';
 269 
 270   ($NumOfSigmaBonds, $NumOfPiBonds) = ('0') x 2;
 271 
 272   ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms();
 273   $NumOfSigmaBonds += $Atom->GetAtomicInvariantValue('H');
 274 
 275   ATOMTYPE: {
 276 
 277     # Aromatic Nitrogens...
 278     if ($Atom->IsAromatic()) {
 279       $AtomType = $This->_GetAtomTypeForAromaticNitrogen($Atom);
 280       last ATOMTYPE;
 281     }
 282 
 283     # Only single bonds...
 284     if ($NumOfPiBonds == 0) {
 285       $AtomType = $This->_GetAtomTypeForNitrogenWithOnlySigmaBonds($Atom);
 286       last ATOMTYPE;
 287     }
 288 
 289     # One double bond...
 290     if ($NumOfPiBonds == 1) {
 291       $AtomType = $This->_GetAtomTypeForNitrogenWithOnePiBond($Atom);
 292       last ATOMTYPE;
 293     }
 294 
 295     # One triple bond or two double bonds...
 296     if ($NumOfPiBonds == 2) {
 297       $AtomType = $This->_GetAtomTypeForNitrogenWithTwoPiBonds($Atom);
 298       last ATOMTYPE;
 299     }
 300 
 301     # One triple bond and a double bond...
 302     if ($NumOfPiBonds == 3) {
 303       $AtomType = $This->_GetAtomTypeForNitrogenWithThreePiBonds($Atom);
 304       last ATOMTYPE;
 305     }
 306 
 307     $AtomType = 'N';
 308   }
 309   return $AtomType;
 310 }
 311 
 312 # Get TPSA atom type for Oxygen atom...
 313 #
 314 # AtomTypeSymbol - SMARTS - Comments
 315 # O1 - '[O](-*)-*'
 316 # O2 - '[O]1-*-*-1' - Atom in a 3 membered ring
 317 # O3 - '[O]=*'
 318 # O4 - '[OH]-*'
 319 # O5 - '[O-]-*'
 320 # O6 - '[o](:*):*'
 321 # O - '[#8]' - Any other Oxygen; Contribution: 28.5 - X*8.6 + H*1.5 or 0.0 for negative value
 322 #
 323 sub _GetAtomTypeForOxygen {
 324   my($This, $Atom) = @_;
 325   my($AtomType);
 326 
 327   $AtomType = 'None';
 328 
 329   ATOMTYPE: {
 330 
 331     # O6 - '[o](:*):*'
 332     if ($This->_IsO6Oxygen($Atom)) {
 333       $AtomType = 'O6';
 334       last ATOMTYPE;
 335     }
 336 
 337     # O3 - '[O]=*'
 338     if ($This->_IsO3Oxygen($Atom)) {
 339       $AtomType = 'O3';
 340       last ATOMTYPE;
 341     }
 342 
 343     # O4 - '[OH]-*'
 344     if ($This->_IsO4Oxygen($Atom)) {
 345       $AtomType = 'O4';
 346       last ATOMTYPE;
 347     }
 348 
 349     # O5 - '[O-]-*'
 350     if ($This->_IsO5Oxygen($Atom)) {
 351       $AtomType = 'O5';
 352       last ATOMTYPE;
 353     }
 354 
 355     # O2 - '[O]1-*-*-1' - Atom in a 3 membered ring
 356     if ($This->_IsO2Oxygen($Atom)) {
 357       $AtomType = 'O2';
 358       last ATOMTYPE;
 359     }
 360 
 361     # O1 - '[O](-*)-*'
 362     if ($This->_IsO1Oxygen($Atom)) {
 363       $AtomType = 'O1';
 364       last ATOMTYPE;
 365     }
 366 
 367     # Any other Oxygen...
 368     $AtomType = 'O';
 369   }
 370 
 371   return $AtomType;
 372 }
 373 
 374 # Get TPSA atom type for Phosphorus atom...
 375 #
 376 # 4 AtomTypeSymbols for element P:
 377 #
 378 # AtomTypeSymbol - SMARTS - Comments
 379 # P1 - '[P](-*)(-*)-*'
 380 # P2 - '[P](-*)=*'
 381 # P3 - '[P](-*)(-*)(-*)=*'
 382 # P4 - '[PH](-*)(-*)=*'
 383 # P - '[#15]' - Any other Sulfur
 384 #
 385 sub _GetAtomTypeForPhosphorus {
 386   my($This, $Atom) = @_;
 387   my($AtomType);
 388 
 389   $AtomType = 'None';
 390 
 391   ATOMTYPE: {
 392 
 393     # P1 - '[P](-*)(-*)-*'
 394     if ($This->_IsP1Phosphorus($Atom)) {
 395       $AtomType = 'P1';
 396       last ATOMTYPE;
 397     }
 398 
 399     # P2 - '[P](-*)=*'
 400     if ($This->_IsP2Phosphorus($Atom)) {
 401       $AtomType = 'P2';
 402       last ATOMTYPE;
 403     }
 404 
 405     # P3 - '[P](-*)(-*)(-*)=*'
 406     if ($This->_IsP3Phosphorus($Atom)) {
 407       $AtomType = 'P3';
 408       last ATOMTYPE;
 409     }
 410 
 411     # P4 - '[PH](-*)(-*)=*'
 412     if ($This->_IsP4Phosphorus($Atom)) {
 413       $AtomType = 'P4';
 414       last ATOMTYPE;
 415     }
 416 
 417     # Any other Phosphorus...
 418     $AtomType = 'P';
 419   }
 420 
 421   return $AtomType;
 422 }
 423 
 424 # Get TPSA atom type for Sulfur atom...
 425 #
 426 # 7 AtomTypeSymbols for element S:
 427 #
 428 # AtomTypeSymbol - SMARTS - Comments
 429 # S1 - '[S](-*)-*'
 430 # S2 - '[S]=*'
 431 # S3 - '[S](-*)(-*)=*'
 432 # S4 - '[S](-*)(-*)(=*)=*'
 433 # S5 - '[SH]-*'
 434 # S6 - '[s](:*):*'
 435 # S - '[#16]' - Any other Phosphorus
 436 #
 437 sub _GetAtomTypeForSulfur {
 438   my($This, $Atom) = @_;
 439   my($AtomType);
 440 
 441   $AtomType = 'None';
 442 
 443   ATOMTYPE: {
 444 
 445     # S6 - '[s](:*):*'
 446     if ($This->_IsS6Sulfur($Atom)) {
 447       $AtomType = 'S6';
 448       last ATOMTYPE;
 449     }
 450 
 451     # S4 - '[S](-*)(-*)(=*)=*'
 452     if ($This->_IsS4Sulfur($Atom)) {
 453       $AtomType = 'S4';
 454       last ATOMTYPE;
 455     }
 456 
 457     # S1 - '[S](-*)-*'
 458     if ($This->_IsS1Sulfur($Atom)) {
 459       $AtomType = 'S1';
 460       last ATOMTYPE;
 461     }
 462 
 463     # S2 - '[S]=*'
 464     if ($This->_IsS2Sulfur($Atom)) {
 465       $AtomType = 'S2';
 466       last ATOMTYPE;
 467     }
 468 
 469     # S3 - '[S](-*)(-*)=*'
 470     if ($This->_IsS3Sulfur($Atom)) {
 471       $AtomType = 'S3';
 472       last ATOMTYPE;
 473     }
 474 
 475     # S5 - '[SH]-*'
 476     if ($This->_IsS5Sulfur($Atom)) {
 477       $AtomType = 'S5';
 478       last ATOMTYPE;
 479     }
 480 
 481     # Any other Sulfur...
 482     $AtomType = 'S';
 483   }
 484 
 485   return $AtomType;
 486 }
 487 
 488 # Get TPSA atom type for aromatic Nitrogen...
 489 #
 490 sub _GetAtomTypeForAromaticNitrogen {
 491   my($This, $Atom) = @_;
 492   my($AtomType);
 493 
 494   $AtomType = 'None';
 495 
 496   ATOMTYPE: {
 497 
 498     # N19 - '[n](:*):*'
 499     if ($This->_IsN19Nitrogen($Atom)) {
 500       $AtomType = 'N19';
 501       last ATOMTYPE;
 502     }
 503 
 504     # N20 - '[n](:*)(:*):*'
 505     if ($This->_IsN20Nitrogen($Atom)) {
 506       $AtomType = 'N20';
 507       last ATOMTYPE;
 508     }
 509 
 510     # N21 - '[n](-*)(:*):*'
 511     if ($This->_IsN21Nitrogen($Atom)) {
 512       $AtomType = 'N21';
 513       last ATOMTYPE;
 514     }
 515 
 516     # N22 - '[n](=*)(:*):*' - As in pyridine N-oxide
 517     if ($This->_IsN22Nitrogen($Atom)) {
 518       $AtomType = 'N22';
 519       last ATOMTYPE;
 520     }
 521 
 522     # N23 - '[nH](:*):*'
 523     if ($This->_IsN23Nitrogen($Atom)) {
 524       $AtomType = 'N23';
 525       last ATOMTYPE;
 526     }
 527 
 528     # N24 - '[n+](:*)(:*):*'
 529     if ($This->_IsN24Nitrogen($Atom)) {
 530       $AtomType = 'N24';
 531       last ATOMTYPE;
 532     }
 533 
 534     # N25 - '[n+](-*)(:*):*'
 535     if ($This->_IsN25Nitrogen($Atom)) {
 536       $AtomType = 'N25';
 537       last ATOMTYPE;
 538     }
 539 
 540     # N26 - '[nH+](:*):*'
 541     if ($This->_IsN26Nitrogen($Atom)) {
 542       $AtomType = 'N26';
 543       last ATOMTYPE;
 544     }
 545 
 546     $AtomType = 'N';
 547   }
 548 
 549   return $AtomType;
 550 }
 551 
 552 # Get TPSA atom type for Nitrogen with only sigma bonds...
 553 #
 554 sub _GetAtomTypeForNitrogenWithOnlySigmaBonds {
 555   my($This, $Atom) = @_;
 556   my($AtomType);
 557 
 558   $AtomType = 'None';
 559 
 560   ATOMTYPE: {
 561 
 562    # N6 - '[N]1(-*)-*-*-1' - Atom in a 3 membered ring
 563     if ($This->_IsN6Nitrogen($Atom)) {
 564       $AtomType = 'N6';
 565       last ATOMTYPE;
 566     }
 567 
 568     # N1 - '[N](-*)(-*)-*'
 569     if ($This->_IsN1Nitrogen($Atom)) {
 570       $AtomType = 'N1';
 571       last ATOMTYPE;
 572     }
 573 
 574     # N8 - '[NH]1-*-*-1' - Atom in a 3 membered ring
 575     if ($This->_IsN8Nitrogen($Atom)) {
 576       $AtomType = 'N8';
 577       last ATOMTYPE;
 578     }
 579 
 580     # N7 - '[NH](-*)-*'
 581     if ($This->_IsN7Nitrogen($Atom)) {
 582       $AtomType = 'N7';
 583       last ATOMTYPE;
 584     }
 585 
 586     # N10 - '[NH2]-*'
 587     if ($This->_IsN10Nitrogen($Atom)) {
 588       $AtomType = 'N10';
 589       last ATOMTYPE;
 590     }
 591 
 592     # N11 - '[N+](-*)(-*)(-*)-*'
 593     if ($This->_IsN11Nitrogen($Atom)) {
 594       $AtomType = 'N11';
 595       last ATOMTYPE;
 596     }
 597 
 598     # N14 - '[NH+](-*)(-*)-*'
 599     if ($This->_IsN14Nitrogen($Atom)) {
 600       $AtomType = 'N14';
 601       last ATOMTYPE;
 602     }
 603 
 604     # N16 - '[NH2+](-*)-*'
 605     if ($This->_IsN16Nitrogen($Atom)) {
 606       $AtomType = 'N16';
 607       last ATOMTYPE;
 608     }
 609 
 610     # N18 - '[NH3+]-*'
 611     if ($This->_IsN18Nitrogen($Atom)) {
 612       $AtomType = 'N18';
 613       last ATOMTYPE;
 614     }
 615 
 616     $AtomType = 'N';
 617   }
 618 
 619   return $AtomType;
 620 }
 621 
 622 # Get TPSA atom type for Nitrogen with one pi bonds...
 623 #
 624 sub _GetAtomTypeForNitrogenWithOnePiBond {
 625   my($This, $Atom) = @_;
 626   my($AtomType);
 627 
 628   $AtomType = 'None';
 629 
 630   ATOMTYPE: {
 631 
 632     # N2 - '[N](-*)=*'
 633     if ($This->_IsN2Nitrogen($Atom)) {
 634       $AtomType = 'N2';
 635       last ATOMTYPE;
 636     }
 637 
 638     # N9 - '[NH]=*'
 639     if ($This->_IsN9Nitrogen($Atom)) {
 640       $AtomType = 'N9';
 641       last ATOMTYPE;
 642     }
 643 
 644     # N12 - '[N+](-*)(-*)=*'
 645     if ($This->_IsN12Nitrogen($Atom)) {
 646       $AtomType = 'N12';
 647       last ATOMTYPE;
 648     }
 649 
 650     # N15 - '[NH+](-*)=*'
 651     if ($This->_IsN15Nitrogen($Atom)) {
 652       $AtomType = 'N15';
 653       last ATOMTYPE;
 654     }
 655 
 656     # N17 - '[NH2+]=*'
 657     if ($This->_IsN17Nitrogen($Atom)) {
 658       $AtomType = 'N17';
 659       last ATOMTYPE;
 660     }
 661 
 662     $AtomType = 'N';
 663   }
 664 
 665   return $AtomType;
 666 }
 667 
 668 # Get TPSA atom type for Nitrogen with two pi bonds...
 669 #
 670 sub _GetAtomTypeForNitrogenWithTwoPiBonds {
 671   my($This, $Atom) = @_;
 672   my($AtomType);
 673 
 674   $AtomType = 'None';
 675 
 676   ATOMTYPE: {
 677 
 678     # N3 - '[N]#*'
 679     if ($This->_IsN3Nitrogen($Atom)) {
 680       $AtomType = 'N3';
 681       last ATOMTYPE;
 682     }
 683 
 684     # N4 - '[N](-*)(=*)=*' - As in nitro group
 685     if ($This->_IsN4Nitrogen($Atom)) {
 686       $AtomType = 'N4';
 687       last ATOMTYPE;
 688     }
 689 
 690     # N13 - '[N+](-*)#*'- Nitrogen in isocyano group
 691     if ($This->_IsN13Nitrogen($Atom)) {
 692       $AtomType = 'N13';
 693       last ATOMTYPE;
 694     }
 695 
 696     $AtomType = 'N';
 697   }
 698 
 699   return $AtomType;
 700 }
 701 
 702 # Get TPSA atom type for Nitrogen with three pi bonds...
 703 #
 704 sub _GetAtomTypeForNitrogenWithThreePiBonds {
 705   my($This, $Atom) = @_;
 706   my($AtomType);
 707 
 708   $AtomType = 'None';
 709 
 710   ATOMTYPE: {
 711 
 712     # N5 - '[N](=*)#*' - Middle nitrogen in azide group
 713     if ($This->_IsN5Nitrogen($Atom)) {
 714       $AtomType = 'N5';
 715       last ATOMTYPE;
 716     }
 717 
 718     $AtomType = 'N';
 719   }
 720 
 721   return $AtomType;
 722 }
 723 
 724 # N1 - '[N](-*)(-*)-*'
 725 #
 726 sub _IsN1Nitrogen {
 727   my($This, $Atom) = @_;
 728 
 729   return $Atom->DoesAtomNeighborhoodMatch('N.!RA3.X3.SB3.H0.FC0') ? 1 : 0;
 730 }
 731 
 732 # N2 - '[N](-*)=*'
 733 #
 734 sub _IsN2Nitrogen {
 735   my($This, $Atom) = @_;
 736 
 737   return $Atom->DoesAtomNeighborhoodMatch('N.X2.SB1.DB1.H0.FC0') ? 1 : 0;
 738 }
 739 
 740 # N3 - '[N]#*'
 741 #
 742 sub _IsN3Nitrogen {
 743   my($This, $Atom) = @_;
 744 
 745   return $Atom->DoesAtomNeighborhoodMatch('N.X1.TB1.H0.FC0') ? 1 : 0;
 746 }
 747 
 748 # N4 - '[N](-*)(=*)=*' - As in nitro group
 749 #
 750 sub _IsN4Nitrogen {
 751   my($This, $Atom) = @_;
 752 
 753   return $Atom->DoesAtomNeighborhoodMatch('N.X3.SB1.DB2.H0.FC0') ? 1 : 0;
 754 }
 755 
 756 # N5 - '[N](=*)#*' - Middle nitrogen in azide group
 757 #
 758 sub _IsN5Nitrogen {
 759   my($This, $Atom) = @_;
 760 
 761   return $Atom->DoesAtomNeighborhoodMatch('N.X2.DB1.TB1.H0.FC0') ? 1 : 0;
 762 }
 763 
 764 # N6 - '[N]1(-*)-*-*-1' - Atom in a 3 membered ring
 765 #
 766 sub _IsN6Nitrogen {
 767   my($This, $Atom) = @_;
 768 
 769   return $Atom->DoesAtomNeighborhoodMatch('N.RA3.X3.SB3.H0.FC0') ? 1 : 0;
 770 }
 771 
 772 # N7 - '[NH](-*)-*'
 773 #
 774 sub _IsN7Nitrogen {
 775   my($This, $Atom) = @_;
 776 
 777   return $Atom->DoesAtomNeighborhoodMatch('N.!RA3.X2.SB2.H1.FC0') ? 1 : 0;
 778 }
 779 
 780 # N8 - '[NH]1-*-*-1' - Atom in a 3 membered ring
 781 #
 782 sub _IsN8Nitrogen {
 783   my($This, $Atom) = @_;
 784 
 785   return $Atom->DoesAtomNeighborhoodMatch('N.RA3.X2.SB2.H1.FC0') ? 1 : 0;
 786 }
 787 
 788 # N9 - '[NH]=*'
 789 #
 790 sub _IsN9Nitrogen {
 791   my($This, $Atom) = @_;
 792 
 793   return $Atom->DoesAtomNeighborhoodMatch('N.X1.DB1.H1.FC0') ? 1 : 0;
 794 }
 795 
 796 # N10 - '[NH2]-*'
 797 #
 798 sub _IsN10Nitrogen {
 799   my($This, $Atom) = @_;
 800 
 801   return $Atom->DoesAtomNeighborhoodMatch('N.X1.SB1.H2.FC0') ? 1 : 0;
 802 }
 803 
 804 # N11 - '[N+](-*)(-*)(-*)-*'
 805 #
 806 sub _IsN11Nitrogen {
 807   my($This, $Atom) = @_;
 808 
 809   return $Atom->DoesAtomNeighborhoodMatch('N.X4.SB4.H0.FC+1') ? 1 : 0;
 810 }
 811 
 812 # N12 - '[N+](-*)(-*)=*'
 813 #
 814 sub _IsN12Nitrogen {
 815   my($This, $Atom) = @_;
 816 
 817   return $Atom->DoesAtomNeighborhoodMatch('N.X3.SB2.DB1.H0.FC+1') ? 1 : 0;
 818 }
 819 
 820 # N13 - '[N+](-*)#*'- Nitrogen in isocyano group
 821 #
 822 sub _IsN13Nitrogen {
 823   my($This, $Atom) = @_;
 824 
 825   return $Atom->DoesAtomNeighborhoodMatch('N.X2.SB1.TB1.H0.FC+1') ? 1 : 0;
 826 }
 827 
 828 # N14 - '[NH+](-*)(-*)-*'
 829 #
 830 sub _IsN14Nitrogen {
 831   my($This, $Atom) = @_;
 832 
 833   return $Atom->DoesAtomNeighborhoodMatch('N.X3.SB3.H1.FC+1') ? 1 : 0;
 834 }
 835 
 836 # N15 - '[NH+](-*)=*'
 837 #
 838 sub _IsN15Nitrogen {
 839   my($This, $Atom) = @_;
 840 
 841   return $Atom->DoesAtomNeighborhoodMatch('N.X2.SB1.DB1.H1.FC+1') ? 1 : 0;
 842 }
 843 
 844 # N16 - '[NH2+](-*)-*'
 845 #
 846 sub _IsN16Nitrogen {
 847   my($This, $Atom) = @_;
 848 
 849   return $Atom->DoesAtomNeighborhoodMatch('N.X2.SB2.H2.FC+1') ? 1 : 0;
 850 }
 851 
 852 # N17 - '[NH2+]=*'
 853 #
 854 sub _IsN17Nitrogen {
 855   my($This, $Atom) = @_;
 856 
 857   return $Atom->DoesAtomNeighborhoodMatch('N.X1.DB1.H2.FC+1') ? 1 : 0;
 858 }
 859 
 860 # N18 - '[NH3+]-*'
 861 #
 862 sub _IsN18Nitrogen {
 863   my($This, $Atom) = @_;
 864 
 865   return $Atom->DoesAtomNeighborhoodMatch('N.X1.SB1.H3.FC+1') ? 1 : 0;
 866 }
 867 
 868 # N19 - '[n](:*):*'
 869 #
 870 sub _IsN19Nitrogen {
 871   my($This, $Atom) = @_;
 872 
 873   return $Atom->DoesAtomNeighborhoodMatch('N.Ar.X2.AB2.H0.FC0') ? 1 : 0;
 874 }
 875 
 876 # N20 - '[n](:*)(:*):*'
 877 #
 878 sub _IsN20Nitrogen {
 879   my($This, $Atom) = @_;
 880 
 881   return $Atom->DoesAtomNeighborhoodMatch('N.Ar.X3.AB3.H0.FC0') ? 1 : 0;
 882 }
 883 
 884 # N21 - '[n](-*)(:*):*'
 885 #
 886 sub _IsN21Nitrogen {
 887   my($This, $Atom) = @_;
 888 
 889   return $Atom->DoesAtomNeighborhoodMatch('N.Ar.X3.AB2.H0.FC0', ['*', '*', '*'], [':', ':', '-']) ? 1 : 0;
 890 }
 891 
 892 # N22 - '[n](=*)(:*):*' - As in pyridine N-oxide
 893 #
 894 sub _IsN22Nitrogen {
 895   my($This, $Atom) = @_;
 896 
 897   return $Atom->DoesAtomNeighborhoodMatch('N.Ar.X3.AB2.H0.FC0', ['*', '*', '*'], [':', ':', '=']) ? 1 : 0;
 898 }
 899 
 900 # N23 - '[nH](:*):*'
 901 #
 902 sub _IsN23Nitrogen {
 903   my($This, $Atom) = @_;
 904 
 905   return $Atom->DoesAtomNeighborhoodMatch('N.Ar.X2.AB2.H1.FC0') ? 1 : 0;
 906 }
 907 
 908 # N24 - '[n+](:*)(:*):*'
 909 #
 910 sub _IsN24Nitrogen {
 911   my($This, $Atom) = @_;
 912 
 913   return $Atom->DoesAtomNeighborhoodMatch('N.Ar.X3.AB3.H0.FC+1') ? 1 : 0;
 914 }
 915 
 916 # N25 - '[n+](-*)(:*):*'
 917 #
 918 sub _IsN25Nitrogen {
 919   my($This, $Atom) = @_;
 920 
 921   return $Atom->DoesAtomNeighborhoodMatch('N.Ar.X3.AB2.H0.FC+1', ['*', '*', '*'], [':', ':', '-']) ? 1 : 0;
 922 }
 923 
 924 # N26 - '[nH+](:*):*'
 925 #
 926 sub _IsN26Nitrogen {
 927   my($This, $Atom) = @_;
 928 
 929   return $Atom->DoesAtomNeighborhoodMatch('N.Ar.X2.AB2.H1.FC+1') ? 1 : 0;
 930 }
 931 
 932 # O1 - '[O](-*)-*'
 933 #
 934 sub _IsO1Oxygen {
 935   my($This, $Atom) = @_;
 936 
 937   return $Atom->DoesAtomNeighborhoodMatch('O.!RA.X2.SB2.H0.FC0') ? 1 : 0;
 938 }
 939 
 940 # O2 - '[O]1-*-*-1' - Atom in a 3 membered ring
 941 #
 942 sub _IsO2Oxygen {
 943   my($This, $Atom) = @_;
 944 
 945   return $Atom->DoesAtomNeighborhoodMatch('O.RA3.X2.SB2.H0.FC0') ? 1 : 0;
 946 }
 947 
 948 # O3 - '[O]=*'
 949 #
 950 sub _IsO3Oxygen {
 951   my($This, $Atom) = @_;
 952 
 953   return $Atom->DoesAtomNeighborhoodMatch('O.X1.DB1.H0.FC0') ? 1 : 0;
 954 }
 955 
 956 # O4 - '[OH]-*'
 957 #
 958 sub _IsO4Oxygen {
 959   my($This, $Atom) = @_;
 960 
 961   return $Atom->DoesAtomNeighborhoodMatch('O.X1.SB1.H1.FC0') ? 1 : 0;
 962 }
 963 
 964 # O5 - '[O-]-*'
 965 #
 966 sub _IsO5Oxygen {
 967   my($This, $Atom) = @_;
 968 
 969   return $Atom->DoesAtomNeighborhoodMatch('O.X1.SB1.H0.FC-1') ? 1 : 0;
 970 }
 971 
 972 # O6 - '[o](:*):*'
 973 #
 974 sub _IsO6Oxygen {
 975   my($This, $Atom) = @_;
 976 
 977   return $Atom->DoesAtomNeighborhoodMatch('O.Ar.X2.AB2.H0.FC0') ? 1 : 0;
 978 }
 979 
 980 # P1 - '[P](-*)(-*)-*'
 981 #
 982 sub _IsP1Phosphorus {
 983   my($This, $Atom) = @_;
 984 
 985   return $Atom->DoesAtomNeighborhoodMatch('P.X3.SB3.H0.FC0') ? 1 : 0;
 986 }
 987 
 988 # P2 - '[P](-*)=*'
 989 #
 990 sub _IsP2Phosphorus {
 991   my($This, $Atom) = @_;
 992 
 993   return $Atom->DoesAtomNeighborhoodMatch('P.X2.SB1.DB1.H0.FC0') ? 1 : 0;
 994 }
 995 
 996 # P3 - '[P](-*)(-*)(-*)=*'
 997 #
 998 sub _IsP3Phosphorus {
 999   my($This, $Atom) = @_;
1000 
1001   return $Atom->DoesAtomNeighborhoodMatch('P.X4.SB3.DB1.H0.FC0') ? 1 : 0;
1002 }
1003 
1004 # P4 - '[PH](-*)(-*)=*'
1005 #
1006 sub _IsP4Phosphorus {
1007   my($This, $Atom) = @_;
1008 
1009   return $Atom->DoesAtomNeighborhoodMatch('P.X3.SB2.DB1.H1.FC0') ? 1 : 0;
1010 }
1011 
1012 # S1 - '[S](-*)-*'
1013 #
1014 sub _IsS1Sulfur {
1015   my($This, $Atom) = @_;
1016 
1017   return $Atom->DoesAtomNeighborhoodMatch('S.X2.SB2.H0.FC0') ? 1 : 0;
1018 }
1019 
1020 # S2 - '[S]=*'
1021 #
1022 sub _IsS2Sulfur {
1023   my($This, $Atom) = @_;
1024 
1025   return $Atom->DoesAtomNeighborhoodMatch('S.X1.DB1.H0.FC0') ? 1 : 0;
1026 }
1027 
1028 # S3 - '[S](-*)(-*)=*'
1029 #
1030 sub _IsS3Sulfur {
1031   my($This, $Atom) = @_;
1032 
1033   return $Atom->DoesAtomNeighborhoodMatch('S.X3.SB2.DB1.H0.FC0') ? 1 : 0;
1034 }
1035 
1036 # S4 - '[S](-*)(-*)(=*)=*'
1037 #
1038 sub _IsS4Sulfur {
1039   my($This, $Atom) = @_;
1040 
1041   return $Atom->DoesAtomNeighborhoodMatch('S.X4.SB2.DB2.H0.FC0') ? 1 : 0;
1042 }
1043 
1044 # S5 - '[SH]-*'
1045 #
1046 sub _IsS5Sulfur {
1047   my($This, $Atom) = @_;
1048 
1049   return $Atom->DoesAtomNeighborhoodMatch('S.X1.SB1.H1.FC0') ? 1 : 0;
1050 }
1051 
1052 # S6 - '[s](:*):*'
1053 #
1054 sub _IsS6Sulfur {
1055   my($This, $Atom) = @_;
1056 
1057   return $Atom->DoesAtomNeighborhoodMatch('S.Ar.X2.AB2.H0.FC0') ? 1 : 0;
1058 }
1059 
1060 # Return a string containg data for TPSAAtomTypes object...
1061 #
1062 sub StringifyTPSAAtomTypes {
1063   my($This) = @_;
1064   my($AtomTypesString);
1065 
1066   # Type of AtomTypes...
1067   $AtomTypesString = "AtomTypes: $This->{Type}; IgnorePhosphorus: " . ($This->{IgnorePhosphorus} ? "Yes" : "No") . "; IgnoreSulfur: " .  ($This->{IgnoreSulfur} ? "Yes" : "No");
1068 
1069   # Setup atom types information...
1070   my($AtomID, $AtomType, @AtomTypesInfo, %AssignedAtomTypes);
1071 
1072   @AtomTypesInfo = ();
1073   %AssignedAtomTypes = $This->GetAtomTypes();
1074 
1075   for $AtomID (sort { $a <=> $b } keys %AssignedAtomTypes) {
1076     $AtomType = $AssignedAtomTypes{$AtomID} ? $AssignedAtomTypes{$AtomID} : 'None';
1077     push @AtomTypesInfo, "$AtomID:$AtomType";
1078   }
1079   $AtomTypesString .= "; AtomIDs:AtomTypes: <" . TextUtil::JoinWords(\@AtomTypesInfo, ", ", 0) . ">";
1080 
1081   return $AtomTypesString;
1082 }
1083 
1084 # Is it a TPSAAtomTypes object?
1085 sub _IsTPSAAtomTypes {
1086   my($Object) = @_;
1087 
1088   return (Scalar::Util::blessed($Object) && $Object->isa($ClassName)) ? 1 : 0;
1089 }
1090 
1091 # Check and load TPSA atom types data...
1092 #
1093 sub _CheckAndLoadTPSAAtomTypesData {
1094 
1095   # Is it already loaded?
1096   if (exists $TPSAAtomTypesDataMap{AtomTypes}) {
1097     return;
1098   }
1099 
1100   _LoadTPSAAtomTypesData();
1101 }
1102 
1103 # Load TPSA atom types data from the file assuming first column to be atom type symbol..
1104 #
1105 # Format:
1106 #
1107 # "AtomType","SMARTS","TPSAContribution","Comments"
1108 # "N1","[N](-*)(-*)-*","3.24",""
1109 # "N2","[N](-*)=*","12.36",""
1110 #
1111 sub _LoadTPSAAtomTypesData {
1112   my($AtomTypesDataFile, $MayaChemToolsLibDir);
1113 
1114   $MayaChemToolsLibDir = FileUtil::GetMayaChemToolsLibDirName();
1115 
1116   $AtomTypesDataFile =  "$MayaChemToolsLibDir" . "/data/TPSAAtomTypes.csv";
1117   if (! -e "$AtomTypesDataFile") {
1118     croak "Error: MayaChemTools package file, $AtomTypesDataFile, is missing: Possible installation problems...";
1119   }
1120 
1121   %TPSAAtomTypesDataMap = ();
1122   AtomTypes::AtomTypes::LoadAtomTypesData($AtomTypesDataFile, \%TPSAAtomTypesDataMap);
1123 }
1124