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