       1 package AtomTypes::SYBYLAtomTypes;
       2 #
       3 # File: SYBYLAtomTypes.pm
       4 # Author: Manish Sud <msud@san.rr.com>
       5 #
       6 # Copyright (C) 2018 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