MayaChemTools

   1 package AtomTypes::SYBYLAtomTypes;
   2 #
   3 # File: SYBYLAtomTypes.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 AtomTypes::AtomTypes;
  31 use Molecule;
  32 
  33 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  34 
  35 @ISA = qw(AtomTypes::AtomTypes Exporter);
  36 @EXPORT = qw(GetSYBYLAtomTypesData GetAllPossibleSYBYLAtomTypes GetAllPossibleSYBYLNonHydrogenAtomTypes);
  37 @EXPORT_OK = qw();
  38 
  39 %EXPORT_TAGS = (all  => [@EXPORT, @EXPORT_OK]);
  40 
  41 # Setup class variables...
  42 my($ClassName, %SYBYLAtomTypesDataMap);
  43 _InitializeClass();
  44 
  45 # Overload Perl functions...
  46 use overload '""' => 'StringifySYBYLAtomTypes';
  47 
  48 # Class constructor...
  49 sub new {
  50   my($Class, %NamesAndValues) = @_;
  51 
  52   # Initialize object...
  53   my $This = $Class->SUPER::new();
  54   bless $This, ref($Class) || $Class;
  55   $This->_InitializeSYBYLAtomTypes();
  56 
  57   $This->_InitializeSYBYLAtomTypesProperties(%NamesAndValues);
  58 
  59   return $This;
  60 }
  61 
  62 # Initialize class ...
  63 sub _InitializeClass {
  64   #Class name...
  65   $ClassName = __PACKAGE__;
  66 
  67   # Initialize the data hash. It'll be loaded on demand later...
  68   %SYBYLAtomTypesDataMap = ();
  69 }
  70 
  71 
  72 # Initialize object data...
  73 #
  74 sub _InitializeSYBYLAtomTypes {
  75   my($This) = @_;
  76 
  77   # Type of AtomTypes...
  78   $This->{Type} = 'SYBYL';
  79 
  80   # By default, SYBYL atom types are also assigned to hydrogens...
  81   $This->{IgnoreHydrogens} = 0;
  82 
  83   return $This;
  84 }
  85 
  86 # Initialize object properties...
  87 #
  88 sub _InitializeSYBYLAtomTypesProperties {
  89   my($This, %NamesAndValues) = @_;
  90 
  91   my($Name, $Value, $MethodName);
  92   while (($Name, $Value) = each  %NamesAndValues) {
  93     $MethodName = "Set${Name}";
  94     $This->$MethodName($Value);
  95   }
  96 
  97   # Make sure molecule object was specified...
  98   if (!exists $NamesAndValues{Molecule}) {
  99     croak "Error: ${ClassName}->New: Object can't be instantiated without specifying molecule...";
 100   }
 101 
 102   return $This;
 103 }
 104 
 105 # Get SYBYL atom types and associated data loaded from SYBYL data file as
 106 # a reference to hash with the following hash data format:
 107 #
 108 # @{$SYBYLAtomTypesDataMap{AtomTypes}} - Array of all possible atom types for all atoms
 109 # @{$SYBYLAtomTypesDataMap{NonHydrogenAtomTypes}} - Array of all possible atom types for non-hydrogen atoms
 110 # @{$SYBYLAtomTypesDataMap->{ColLabels}} - Array of column labels
 111 # %{$SYBYLAtomTypesDataMap->{DataCol<Num>}} - Hash keys pair: <DataCol<Num>, AtomType>
 112 #
 113 # This functionality can be either invoked as a class function or an
 114 # object method.
 115 #
 116 sub GetSYBYLAtomTypesData {
 117 
 118   # Make sure data is loaded...
 119   _CheckAndLoadSYBYLAtomTypesData();
 120 
 121   return \%SYBYLAtomTypesDataMap;
 122 }
 123 
 124 # Get all possible SYBYL atom types corresponding to hydrogen and non-hydrogen
 125 # atoms as an array reference...
 126 #
 127 # This functionality can be either invoked as a class function or an
 128 # object method.
 129 #
 130 sub GetAllPossibleSYBYLAtomTypes {
 131   return _GetAllPossibleSYBYLAtomTypes();
 132 }
 133 
 134 # Get all possible SYBYL atom types corresponding to non-hydrogen atoms
 135 # as an array reference...
 136 #
 137 # This functionality can be either invoked as a class function or an
 138 # object method.
 139 #
 140 sub GetAllPossibleSYBYLNonHydrogenAtomTypes {
 141   my($NonHydrogensOnly);
 142 
 143   $NonHydrogensOnly = 1;
 144   return _GetAllPossibleSYBYLAtomTypes($NonHydrogensOnly);
 145 }
 146 
 147 # Get all possible SYBYL atom types as an array reference...
 148 #
 149 sub _GetAllPossibleSYBYLAtomTypes {
 150   my($NonHydrogensOnly) = @_;
 151   my($SYBYLAtomTypesDataRef);
 152 
 153   $NonHydrogensOnly = defined $NonHydrogensOnly ? $NonHydrogensOnly : 0;
 154 
 155   $SYBYLAtomTypesDataRef = GetSYBYLAtomTypesData();
 156 
 157   return $NonHydrogensOnly ? \@{$SYBYLAtomTypesDataRef->{NonHydrogenAtomTypes}}: \@{$SYBYLAtomTypesDataRef->{AtomTypes}};
 158 }
 159 # Assign Tripos SYBYL [ Ref 79-80 ] atom types to all atoms...
 160 #
 161 # Notes:
 162 #   . 8 SYBYL listed atom types - O.spc, O.t3p, H.spc, H.t3p, Du, Du.C, HEV, LP -
 163 #     are not assigned to any atom
 164 #   . N.pl3 atom type is assigned to Nitrogens in a guadinium group attached
 165 #     to Carbon C.cat
 166 #
 167 #
 168 sub AssignAtomTypes {
 169   my($This) = @_;
 170   my($Atom, $AtomType);
 171 
 172   ATOM: for $Atom ($This->GetMolecule()->GetAtoms()) {
 173     if ($This->{IgnoreHydrogens} && $Atom->IsHydrogen()) {
 174       next ATOM;
 175     }
 176     $AtomType = $This->_GetAtomType($Atom);
 177     $This->SetAtomType($Atom, $AtomType);
 178   }
 179   return $This;
 180 }
 181 
 182 # Get SYBYL atom type for atom...
 183 #
 184 sub _GetAtomType {
 185   my($This, $Atom) = @_;
 186   my($AtomType);
 187 
 188   $AtomType = 'Any';
 189 
 190   ATOM: {
 191     if ($Atom->IsCarbon()) {
 192       $AtomType = $This->_GetAtomTypeForCarbon($Atom);
 193       last ATOM;
 194     }
 195     if ($Atom->IsNitrogen()) {
 196       $AtomType = $This->_GetAtomTypeForNitrogen($Atom);
 197       last ATOM;
 198     }
 199     if ($Atom->IsOxygen()) {
 200       $AtomType = $This->_GetAtomTypeForOxygen($Atom);
 201       last ATOM;
 202     }
 203     if ($Atom->IsPhosphorus()) {
 204       $AtomType = $This->_GetAtomTypeForPhosphorus($Atom);
 205       last ATOM;
 206     }
 207     if ($Atom->IsSulfur()) {
 208       $AtomType = $This->_GetAtomTypeForSulfur($Atom);
 209       last ATOM;
 210     }
 211     if ($Atom->IsHydrogen()) {
 212       $AtomType = $This->_GetAtomTypeForHydrogen($Atom);
 213       last ATOM;
 214     }
 215     $AtomType = $This->_GetAtomTypeForOtherAtoms($Atom);
 216   }
 217 
 218   return $AtomType;
 219 }
 220 
 221 # Get SYBYL atom type for Carbon atom...
 222 #
 223 sub _GetAtomTypeForCarbon {
 224   my($This, $Atom) = @_;
 225   my($AtomType, $NumOfSigmaBonds, $NumOfPiBonds);
 226 
 227   $AtomType = 'Any';
 228 
 229   ($NumOfSigmaBonds, $NumOfPiBonds) = ('0') x 2;
 230 
 231   ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms();
 232   $NumOfSigmaBonds += $Atom->GetAtomicInvariantValue('H');
 233 
 234   ATOMTYPE: {
 235     if ($Atom->IsAromatic()) {
 236       $AtomType = 'C.ar';
 237       last ATOMTYPE;
 238     }
 239 
 240     if ($Atom->IsGuadiniumCarbon()) {
 241       $AtomType = 'C.cat';
 242       last ATOMTYPE;
 243     }
 244 
 245     # Only single bonds...
 246     if ($NumOfPiBonds == 0) {
 247       $AtomType = 'C.3';
 248       last ATOMTYPE;
 249     }
 250 
 251     # One double bond...
 252     if ($NumOfPiBonds == 1) {
 253       $AtomType = 'C.2';
 254       last ATOMTYPE;
 255     }
 256 
 257     # One triple bond or two double bonds...
 258     if ($NumOfPiBonds == 2) {
 259       $AtomType = 'C.1';
 260       last ATOMTYPE;
 261     }
 262 
 263     $AtomType = 'Any';
 264   }
 265 
 266   return $AtomType;
 267 }
 268 
 269 # Get SYBYL atom type for Nitrogen atom...
 270 #
 271 sub _GetAtomTypeForNitrogen {
 272   my($This, $Atom) = @_;
 273   my($AtomType, $NumOfSigmaBonds, $NumOfPiBonds);
 274 
 275   $AtomType = 'Het';
 276 
 277   ($NumOfSigmaBonds, $NumOfPiBonds) = ('0') x 2;
 278 
 279   ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms();
 280   $NumOfSigmaBonds += $Atom->GetAtomicInvariantValue('H');
 281 
 282   ATOMTYPE: {
 283     if ($Atom->IsAromatic()) {
 284       $AtomType = 'N.ar';
 285       last ATOMTYPE;
 286     }
 287 
 288     if ($Atom->IsGuadiniumNitrogen()) {
 289       $AtomType = 'N.pl3';
 290       last ATOMTYPE;
 291     }
 292 
 293     if ($Atom->IsAmideNitrogen()) {
 294       $AtomType = 'N.am';
 295       last ATOMTYPE;
 296     }
 297 
 298     # Only single bonds...
 299     if ($NumOfSigmaBonds == 4 && $NumOfPiBonds == 0) {
 300       $AtomType = 'N.4';
 301       last ATOMTYPE;
 302     }
 303 
 304     # Only single bonds...
 305     if ($NumOfSigmaBonds == 3 && $NumOfPiBonds == 0) {
 306       $AtomType = $This->_IsN3NitrogenPlanar($Atom) ? 'N.pl3' : 'N.3';
 307       last ATOMTYPE;
 308     }
 309 
 310     # One double bond...
 311     if ($NumOfPiBonds == 1) {
 312       $AtomType = 'N.2';
 313       last ATOMTYPE;
 314     }
 315 
 316     # One triple bond or two double bonds...
 317     if ($NumOfPiBonds == 2) {
 318       $AtomType = 'N.1';
 319       last ATOMTYPE;
 320     }
 321 
 322     $AtomType = 'Het';
 323   }
 324 
 325   return $AtomType;
 326 }
 327 
 328 # Get SYBYL atom type for Oxygen atom...
 329 #
 330 sub _GetAtomTypeForOxygen {
 331   my($This, $Atom) = @_;
 332   my($AtomType, $NumOfSigmaBonds, $NumOfPiBonds);
 333 
 334   $AtomType = 'Het';
 335 
 336   ($NumOfSigmaBonds, $NumOfPiBonds) = ('0') x 2;
 337 
 338   ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms();
 339   $NumOfSigmaBonds += $Atom->GetAtomicInvariantValue('H');
 340 
 341   ATOMTYPE: {
 342     if ($Atom->IsCarboxylateOxygen() || $Atom->IsCarboxylOxygen() || $Atom->IsPhosphateOxygen()) {
 343       $AtomType = 'O.co2';
 344       last ATOMTYPE;
 345     }
 346 
 347     # Only single bonds...
 348     if ($NumOfPiBonds == 0) {
 349       $AtomType = 'O.3';
 350       last ATOMTYPE;
 351     }
 352 
 353     # One double bond...
 354     if ($NumOfPiBonds == 1) {
 355       $AtomType = 'O.2';
 356       last ATOMTYPE;
 357     }
 358 
 359     $AtomType = 'Het';
 360   }
 361 
 362   return $AtomType;
 363 }
 364 
 365 # Get SYBYL atom type for Phosphorus atom...
 366 #
 367 sub _GetAtomTypeForPhosphorus {
 368   my($This, $Atom) = @_;
 369   my($AtomType, $NumOfSigmaBonds, $NumOfPiBonds);
 370 
 371   $AtomType = 'Het';
 372 
 373   ($NumOfSigmaBonds, $NumOfPiBonds) = ('0') x 2;
 374 
 375   ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms();
 376   $NumOfSigmaBonds += $Atom->GetAtomicInvariantValue('H');
 377 
 378   ATOMTYPE: {
 379     # -P(-)-, =P(-)(-)-
 380     if (($NumOfSigmaBonds == 3 && $NumOfPiBonds == 0) || ($NumOfSigmaBonds == 4 && $NumOfPiBonds == 1)) {
 381       $AtomType = 'P.3';
 382       last ATOMTYPE;
 383     }
 384 
 385     $AtomType = 'Het';
 386   }
 387 
 388   return $AtomType;
 389 }
 390 
 391 # Get SYBYL atom type for Sulfur atom...
 392 #
 393 sub _GetAtomTypeForSulfur {
 394   my($This, $Atom) = @_;
 395   my($AtomType, $NumOfSigmaBonds, $NumOfPiBonds);
 396 
 397   $AtomType = 'Het';
 398 
 399   ($NumOfSigmaBonds, $NumOfPiBonds) = ('0') x 2;
 400 
 401   ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms();
 402   $NumOfSigmaBonds += $Atom->GetAtomicInvariantValue('H');
 403 
 404   ATOMTYPE: {
 405     if ($This->_IsSulfoneSulfur($Atom)) {
 406       $AtomType = 'S.O2';
 407       last ATOMTYPE;
 408     }
 409 
 410     if ($This->_IsSulfoxideSulfur($Atom)) {
 411       $AtomType = 'S.O';
 412       last ATOMTYPE;
 413     }
 414 
 415     # -S-
 416     if ($NumOfSigmaBonds == 2 && $NumOfPiBonds == 0) {
 417       $AtomType = 'S.3';
 418       last ATOMTYPE;
 419     }
 420 
 421     # S=
 422     if ($NumOfSigmaBonds == 1 && $NumOfPiBonds == 1) {
 423       $AtomType = 'S.2';
 424       last ATOMTYPE;
 425     }
 426 
 427     $AtomType = 'Het';
 428   }
 429 
 430   return $AtomType;
 431 }
 432 
 433 # Get SYBYL atom type for Hydrogen atom...
 434 #
 435 sub _GetAtomTypeForHydrogen {
 436   my($This, $Atom) = @_;
 437   my($AtomType);
 438 
 439   $AtomType = 'H';
 440 
 441   return $AtomType;
 442 }
 443 
 444 # Get SYBYL atom type for atoms other than Carbon, Nitrogen, Oxygen, Phosporus
 445 # and Sulfur...
 446 #
 447 sub _GetAtomTypeForOtherAtoms {
 448   my($This, $Atom) = @_;
 449   my($AtomType, $AtomicNumber, $AtomSymbol);
 450 
 451   $AtomType = 'Any';
 452 
 453   $AtomicNumber = $Atom->GetAtomicNumber();
 454   $AtomSymbol = $Atom->GetAtomSymbol();
 455 
 456   ATOMICNUMBER: {
 457     if ($AtomicNumber =~ /^(9|17|35|53)$/i) {
 458       # F, Cl, Br, I
 459       $AtomType = $AtomSymbol;
 460       last ATOMICNUMBER;
 461     }
 462 
 463     if ($AtomicNumber =~ /^(3|11|12|13|14)$/i) {
 464       # Li, Na, Mg, Al, Si
 465       $AtomType = $AtomSymbol;
 466       last ATOMICNUMBER;
 467     }
 468 
 469     if ($AtomicNumber =~ /^(19|20|25|26|29|30|34)$/i) {
 470       # K, Ca, Mn, Fe, Cu, Zn, Se
 471       $AtomType = $AtomSymbol;
 472       last ATOMICNUMBER;
 473     }
 474 
 475     if ($AtomicNumber =~ /^24$/i) {
 476       $AtomType = $This->_GetAtomTypeForChromium($Atom);
 477       last ATOMICNUMBER;
 478     }
 479 
 480     if ($AtomicNumber =~ /^27$/i) {
 481       $AtomType = $This->_GetAtomTypeForCobalt($Atom);
 482       last ATOMICNUMBER;
 483     }
 484 
 485     if ($AtomicNumber =~ /^(42|50)$/i) {
 486       # Mo, Sn
 487       $AtomType = $AtomSymbol;
 488       last ATOMICNUMBER;
 489     }
 490 
 491     $AtomType = 'Any';
 492   }
 493 
 494   return $AtomType;
 495 }
 496 
 497 # Get SYBYL atom type for Chromium atom...
 498 #
 499 sub _GetAtomTypeForChromium {
 500   my($This, $Atom) = @_;
 501   my($AtomType, $NumOfNeighbors);
 502 
 503   $AtomType = 'Any';
 504   $NumOfNeighbors = $Atom->GetNumOfNeighbors();
 505 
 506   NUMOFNEIGHBORS: {
 507     if ($NumOfNeighbors == 4) {
 508       $AtomType = 'Cr.th';
 509       last NUMOFNEIGHBORS;
 510     }
 511 
 512     if ($NumOfNeighbors == 6) {
 513       $AtomType = 'Cr.oh';
 514       last NUMOFNEIGHBORS;
 515     }
 516 
 517     $AtomType = 'Cr.oh';
 518     carp "Warning: ${ClassName}->_GetAtomTypeForChromium: SYBYL atom types for Cromimum, Co.th or Cr.oh, corresponding to tetrahedral or octahedral geometry cann't be assigned; Number of neighbors, $NumOfNeighbors, is different from 4 or 6. Default SYBYL atom type, Cr.oh, has been assigned...";
 519   }
 520 
 521   return $AtomType;
 522 }
 523 
 524 # Get SYBYL atom type for Cobalt atom...
 525 #
 526 sub _GetAtomTypeForCobalt {
 527   my($This, $Atom) = @_;
 528   my($AtomType, $NumOfNeighbors);
 529 
 530   $AtomType = 'Any';
 531 
 532   $NumOfNeighbors = $Atom->GetNumOfNeighbors();
 533 
 534   if ($NumOfNeighbors == 6) {
 535     $AtomType = 'Co.oh';
 536   }
 537   else {
 538     $AtomType = 'Co.oh';
 539     carp "Warning: ${ClassName}->_GetAtomTypeForCobalt: SYBYL atom type for Cobalt, Co.oh, corresponding to octahedral geometry cann't be assigned; Number of neighbors, $NumOfNeighbors, is different from 6. Default SYBYL atom type, Co.oh, has been assigned...";
 540   }
 541 
 542   return $AtomType;
 543 }
 544 
 545 # Is it N.3 Nitrogen a planar Nitrogen?
 546 #
 547 # A N.3 Nitrogen is a planar Nitrogen when it meets any of the following constraints:
 548 #
 549 #   . Nitrogen atom is in a ring
 550 #   . Attached to only one heavy atom which is an aromatic atom or in a ring
 551 #   . Attached to two or more heavy atom which are aromatic atoms or in a ring
 552 #
 553 sub _IsN3NitrogenPlanar {
 554   my($This, $Atom) = @_;
 555 
 556   # Is it a ring Nitrogen atom?
 557   if ($Atom->IsInRing()) {
 558     return 1;
 559   }
 560 
 561   # Count number of ring and aromatic heavy atoms attached to Nitrogen...
 562   my($AtomNeighbor, $NumOfAromaticAtomNeighbors, $NumOfRingAotmNeighbors, $NumOfNeighbors, @AtomNeighbors);
 563 
 564   @AtomNeighbors = $Atom->GetHeavyAtomNeighbors();
 565   $NumOfNeighbors = scalar @AtomNeighbors;
 566 
 567   $NumOfAromaticAtomNeighbors = 0;  $NumOfRingAotmNeighbors = 0;
 568 
 569   for $AtomNeighbor (@AtomNeighbors) {
 570     if ($AtomNeighbor->IsAromatic()) {
 571       $NumOfAromaticAtomNeighbors++;
 572     }
 573     if ($AtomNeighbor->IsInRing()) {
 574       $NumOfRingAotmNeighbors++;
 575     }
 576   }
 577 
 578   # Is attached to only one heavy atom which is in a ring or aromatic?
 579   if ($NumOfNeighbors == 1) {
 580     if ($NumOfAromaticAtomNeighbors || $NumOfRingAotmNeighbors) {
 581       return 1;
 582     }
 583   }
 584 
 585   # Is attached to more than heavy atoms which are in a ring or aromatic?
 586   if ($NumOfAromaticAtomNeighbors >= 2 || $NumOfRingAotmNeighbors >= 2) {
 587     return 1;
 588   }
 589 
 590   return 0;
 591 }
 592 
 593 # Is it a Sulfur atom in Sulfoxide group?
 594 #
 595 # SYBYL Sulfoxide group definition: A-S(=O)-A
 596 #
 597 #   where:
 598 #      . A = Any atom
 599 #
 600 sub _IsSulfoxideSulfur {
 601   my($This, $Atom) = @_;
 602 
 603   # Is it Sulfur?
 604   if (!$Atom->IsSulfur()) {
 605     return 0;
 606   }
 607   # Match atom neighborhood...
 608   my($CentralAtomSpec, @NbrAtomSpecsRef, @NbrBondSpecsRef);
 609 
 610   $CentralAtomSpec = 'S.X3.BO4';
 611   @NbrAtomSpecsRef = ('O', '*', '*');
 612   @NbrBondSpecsRef = ('=', '-', '-');
 613 
 614   if ($Atom->DoesAtomNeighborhoodMatch($CentralAtomSpec, \@NbrAtomSpecsRef, \@NbrBondSpecsRef)) {
 615     return 1;
 616   }
 617 
 618   return 0;
 619 }
 620 
 621 # Is it a Sulfur atom in Sulfone group?
 622 #
 623 # Sulfoxide group definition: A-(O=)S(=O)-A
 624 #
 625 #   where:
 626 #      . A = Any atom
 627 #
 628 sub _IsSulfoneSulfur {
 629   my($This, $Atom) = @_;
 630 
 631   # Is it Sulfur?
 632   if (!$Atom->IsSulfur()) {
 633     return 0;
 634   }
 635 
 636   # Match atom neighborhood...
 637   my($CentralAtomSpec, @NbrAtomSpecsRef, @NbrBondSpecsRef);
 638 
 639   $CentralAtomSpec = 'S.X4.BO6';
 640   @NbrAtomSpecsRef = ('O', 'O', '*', '*');
 641   @NbrBondSpecsRef = ('=', '=', '-', '-');
 642 
 643   if ($Atom->DoesAtomNeighborhoodMatch($CentralAtomSpec, \@NbrAtomSpecsRef, \@NbrBondSpecsRef)) {
 644     return 1;
 645   }
 646 
 647   return 0;
 648 }
 649 
 650 # Return a string containg data for SYBYLAtomTypes object...
 651 #
 652 sub StringifySYBYLAtomTypes {
 653   my($This) = @_;
 654   my($AtomTypesString);
 655 
 656   # Type of AtomTypes...
 657   $AtomTypesString = "AtomTypes: $This->{Type}; IgnoreHydrogens: " . ($This->{IgnoreHydrogens} ? "Yes" : "No");
 658 
 659   # Setup atom types information...
 660   my($AtomID, $AtomType, @AtomTypesInfo, %AssignedAtomTypes);
 661 
 662   @AtomTypesInfo = ();
 663   %AssignedAtomTypes = $This->GetAtomTypes();
 664 
 665   for $AtomID (sort { $a <=> $b } keys %AssignedAtomTypes) {
 666     $AtomType = $AssignedAtomTypes{$AtomID} ? $AssignedAtomTypes{$AtomID} : 'None';
 667     push @AtomTypesInfo, "$AtomID:$AtomType";
 668   }
 669   $AtomTypesString .= "; AtomIDs:AtomTypes: <" . TextUtil::JoinWords(\@AtomTypesInfo, ", ", 0) . ">";
 670 
 671   return $AtomTypesString;
 672 }
 673 
 674 # Is it a SYBYLAtomTypes object?
 675 sub _IsSYBYLAtomTypes {
 676   my($Object) = @_;
 677 
 678   return (Scalar::Util::blessed($Object) && $Object->isa($ClassName)) ? 1 : 0;
 679 }
 680 
 681 # Check and load SYBYL atom types data...
 682 #
 683 sub _CheckAndLoadSYBYLAtomTypesData {
 684 
 685   # Is it already loaded?
 686   if (exists $SYBYLAtomTypesDataMap{AtomTypes}) {
 687     return;
 688   }
 689 
 690   _LoadSYBYLAtomTypesData();
 691 }
 692 
 693 # Load SYBYL atom types data from the file assuming first column to be atom type symbol..
 694 #
 695 # Format:
 696 #
 697 # "AtomType","Description"
 698 # "C.3","sp3 carbon"
 699 # "C.2","sp2 carbon"
 700 #
 701 sub _LoadSYBYLAtomTypesData {
 702   my($AtomTypesDataFile, $MayaChemToolsLibDir);
 703 
 704   $MayaChemToolsLibDir = FileUtil::GetMayaChemToolsLibDirName();
 705 
 706   $AtomTypesDataFile =  "$MayaChemToolsLibDir" . "/data/SYBYLAtomTypes.csv";
 707   if (! -e "$AtomTypesDataFile") {
 708     croak "Error: MayaChemTools package file, $AtomTypesDataFile, is missing: Possible installation problems...";
 709   }
 710 
 711   %SYBYLAtomTypesDataMap = ();
 712   AtomTypes::AtomTypes::LoadAtomTypesData($AtomTypesDataFile, \%SYBYLAtomTypesDataMap);
 713 }
 714 
 715