Mercurial > repos > deepakjadmin > mayatool3_test3
diff mayachemtools/lib/Atom.pm @ 0:73ae111cf86f draft
Uploaded
author | deepakjadmin |
---|---|
date | Wed, 20 Jan 2016 11:55:01 -0500 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mayachemtools/lib/Atom.pm Wed Jan 20 11:55:01 2016 -0500 @@ -0,0 +1,5919 @@ +package Atom; +# +# $RCSfile: Atom.pm,v $ +# $Date: 2015/02/28 20:47:02 $ +# $Revision: 1.62 $ +# +# Author: Manish Sud <msud@san.rr.com> +# +# Copyright (C) 2015 Manish Sud. All rights reserved. +# +# This file is part of MayaChemTools. +# +# MayaChemTools is free software; you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) any +# later version. +# +# MayaChemTools is distributed in the hope that it will be useful, but without +# any warranty; without even the implied warranty of merchantability of fitness +# for a particular purpose. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or +# write to the Free Software Foundation Inc., 59 Temple Place, Suite 330, +# Boston, MA, 02111-1307, USA. +# + +use strict; +use Carp; +use Exporter; +use Storable (); +use Scalar::Util (); +use ObjectProperty; +use PeriodicTable; +use Vector; +use MathUtil; +use Text::ParseWords; +use TextUtil; +use FileUtil; + +use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); + +@ISA = qw(ObjectProperty Exporter); +@EXPORT = qw(); +@EXPORT_OK = qw(); + +%EXPORT_TAGS = (all => [@EXPORT, @EXPORT_OK]); + +# Setup class variables... +my($ClassName, $ObjectID, %MDLValenceModelDataMap, %DaylightValenceModelDataMap); +_InitializeClass(); + +# Overload Perl functions... +use overload '""' => 'StringifyAtom'; + +# Class constructor... +sub new { + my($Class, %NamesAndValues) = @_; + + # Initialize object... + my $This = {}; + bless $This, ref($Class) || $Class; + $This->_InitializeAtom(); + + $This->_InitializeAtomProperties(%NamesAndValues); + + return $This; +} + +# Initialize object data... +sub _InitializeAtom { + my($This) = @_; + my($ObjectID) = _GetNewObjectID(); + + # All other property names and values along with all Set/Get<PropertyName> methods + # are implemented on-demand using ObjectProperty class. + $This->{ID} = $ObjectID; + $This->{Name} = "Atom ${ObjectID}"; + $This->{AtomSymbol} = ''; + $This->{AtomicNumber} = 0; + $This->{XYZ} = Vector::ZeroVector; +} + +# Initialize atom properties... +sub _InitializeAtomProperties { + my($This, %NamesAndValues) = @_; + + my($Name, $Value, $MethodName); + while (($Name, $Value) = each %NamesAndValues) { + $MethodName = "Set${Name}"; + $This->$MethodName($Value); + } + if (!exists $NamesAndValues{'AtomSymbol'}) { + carp "Warning: ${ClassName}->new: Atom object instantiated without setting atom symbol..."; + } + + return $This; +} + +# Initialize class ... +sub _InitializeClass { + #Class name... + $ClassName = __PACKAGE__; + + # ID to keep track of objects... + $ObjectID = 0; + + # Load atom class data... + _LoadAtomClassData(); +} + +# Setup an explicit SetID method to block setting of ID by AUTOLOAD function... +sub SetID { + my($This, $Value) = @_; + + carp "Warning: ${ClassName}->SetID: Object ID can't be changed: it's used for internal tracking..."; + + return $This; +} + +# Setup an explicit SetMolecule method to block setting of ID by AUTOLOAD function... +sub SetMolecule { + my($This, $Value) = @_; + + carp "Warning: ${ClassName}->SetMolecule: Molecule property can't be changed: it's used for internal tracking..."; + + return $This; +} + +# Assign atom to molecule... +sub _SetMolecule { + my($This, $Molecule) = @_; + + $This->{Molecule} = $Molecule; + + # Weaken the reference to disable increment of reference count; otherwise, + # it it becomes a circular reference and destruction of Molecule object doesn't + # get initiated which in turn disables destruction of atom object. + # + Scalar::Util::weaken($This->{Molecule}); + + return $This; +} + +# Setup atom symbol and atomic number for the element... +# +# Possible atom symbol values: +# . An element symbol or some other type of atom: L - Atom list; LP - Lone pair; R# - R group; +# A, Q, * - unknown atom; or something else? +# +# Default mass number corresponds to the most abundant natural isotope unless it's explicity +# set using "MassNumber" property. +# +sub SetAtomSymbol { + my($This, $AtomSymbol) = @_; + my($AtomicNumber); + + $This->{AtomSymbol} = $AtomSymbol; + + $AtomicNumber = PeriodicTable::GetElementAtomicNumber($AtomSymbol); + $This->{AtomicNumber} = (defined $AtomicNumber) ? $AtomicNumber : 0; + + return $This; +} + +# Setup atom symbol and atomic number for the element... +sub SetAtomicNumber { + my($This, $AtomicNumber) = @_; + my($AtomSymbol); + + $AtomSymbol = PeriodicTable::GetElementAtomSymbol($AtomicNumber); + if (!defined $AtomSymbol) { + carp "Warning: ${ClassName}->SetAtomicNumber: Didn't set atomic number: Invalid atomic number, $AtomicNumber, specified..."; + return; + } + $This->{AtomicNumber} = $AtomicNumber; + $This->{AtomSymbol} = $AtomSymbol; + + return $This; +} + +# Set atom as stereo center... +# +sub SetStereoCenter { + my($This, $StereoCenter) = @_; + + $This->SetProperty('StereoCenter', $StereoCenter); + + return $This; +} + +# Is it a stereo center? +# +sub IsStereoCenter { + my($This) = @_; + my($StereoCenter); + + $StereoCenter = $This->GetProperty('StereoCenter'); + + return (defined($StereoCenter) && $StereoCenter) ? 1 : 0; +} + +# Set atom stereochemistry. +# +# Supported values are: R, S. +# +# Notes: +# +# . After the ligands around a central stereocenter has been ranked using CIP priority scheme and +# the lowest ranked ligand lies behind the center atom, then R and S values correspond to: +# +# R: Clockwise arrangement of remaining ligands around the central atom going from highest to lowest ranked ligand +# S: CounterClockwise arrangement of remaining ligands around the central atom going from highest to lowest ranked ligand +# +# . Assignment of any other arbitray values besides R and S is also allowed; however, a warning is printed. +# +sub SetStereochemistry { + my($This, $Stereochemistry) = @_; + + if ($Stereochemistry !~ /^(R|S)$/i) { + carp "Warning: ${ClassName}->SetStereochemistry: Assigning non-supported Stereochemistry value of $Stereochemistry. Supported values: R, S..."; + } + + $This->SetProperty('StereoCenter', 1); + $This->SetProperty('Stereochemistry', $Stereochemistry); + + return $This; +} + +# Setup mass number for atom... +sub SetMassNumber { + my($This, $MassNumber) = @_; + my($AtomicNumber, $AtomSymbol); + + $AtomicNumber = $This->{AtomicNumber}; + $AtomSymbol = $This->{AtomSymbol}; + if (!$AtomicNumber) { + carp "Warning: ${ClassName}->SetMassNumber: Didn't set mass number: Non standard atom with atomic number, $AtomicNumber, and atomic symbol, $AtomSymbol..."; + return; + } + if (!PeriodicTable::IsElementNaturalIsotopeMassNumber($AtomicNumber, $MassNumber)) { + carp "Warning: ${ClassName}->SetMassNumber: Unknown mass number, $MassNumber, specified for atom with atomic number, $AtomicNumber, and atomic symbol, $AtomSymbol. Don't forget to Set ExactMass property explicitly; otherwise, GetExactMass method would return mass of most abundant isotope..."; + } + $This->SetProperty('MassNumber', $MassNumber); + + return $This; +} + +# Get mass number... +# +sub GetMassNumber { + my($This) = @_; + + # Is mass number explicity set? + if ($This->HasProperty('MassNumber')) { + return $This->GetProperty('MassNumber'); + } + + # Is it an element symbol? + my($AtomicNumber) = $This->{AtomicNumber}; + if (!$AtomicNumber) { + return 0; + } + + # Return most abundant mass number... + return PeriodicTable::GetElementMostAbundantNaturalIsotopeMassNumber($AtomicNumber); +} + +# Get atomic weight: +# . Explicitly set by the caller +# . Using atomic number +# +sub GetAtomicWeight { + my($This) = @_; + + # Is atomic weight explicity set? + if ($This->HasProperty('AtomicWeight')) { + return $This->GetProperty('AtomicWeight'); + } + + # Is it an element symbol? + my($AtomicNumber) = $This->{AtomicNumber}; + if (!$AtomicNumber) { + return 0; + } + + # Return its atomic weight... + return PeriodicTable::GetElementAtomicWeight($AtomicNumber); +} + +# Get exact mass weight: +# . Explicitly set by the caller +# . Using atomic number and mass number explicity set by the caller +# . Using atomic number and most abundant isotope +# +sub GetExactMass { + my($This) = @_; + + # Is exact mass explicity set? + if ($This->HasProperty('ExactMass')) { + return $This->GetProperty('ExactMass'); + } + + # Is it an element symbol? + my($AtomicNumber) = $This->{AtomicNumber}; + if (!$AtomicNumber) { + return 0; + } + + # Is mass number explicitly set? + if ($This->HasProperty('MassNumber')) { + my($MassNumber) = $This->GetProperty('MassNumber'); + if (PeriodicTable::IsElementNaturalIsotopeMassNumber($AtomicNumber, $MassNumber)) { + return PeriodicTable::GetElementNaturalIsotopeMass($AtomicNumber, $MassNumber); + } + } + + # Return most abundant isotope mass... + return PeriodicTable::GetElementMostAbundantNaturalIsotopeMass($AtomicNumber); +} + +# Get formal charge: +# . Explicitly set by the caller +# . Or return zero insetad of undef +# +sub GetFormalCharge { + my($This) = @_; + my($FormalCharge); + + $FormalCharge = 0; + if ($This->HasProperty('FormalCharge')) { + $FormalCharge = $This->GetProperty('FormalCharge'); + } + + return defined($FormalCharge) ? $FormalCharge : 0; +} + +# Get spin multiplicity: +# . Explicitly set by the caller +# . From FreeRadicalElectrons value explicitly set by the caller +# . Or return zero insetad of undef +# +sub GetSpinMultiplicity { + my($This) = @_; + my($SpinMultiplicity); + + $SpinMultiplicity = 0; + if ($This->HasProperty('SpinMultiplicity')) { + $SpinMultiplicity = $This->GetProperty('SpinMultiplicity'); + return defined($SpinMultiplicity) ? $SpinMultiplicity : 0; + } + + if ($This->HasProperty('FreeRadicalElectrons')) { + my($FreeRadicalElectrons); + $FreeRadicalElectrons = $This->GetProperty('FreeRadicalElectrons'); + + SPINMULTIPLICITY: { + if ($FreeRadicalElectrons == 1) { $SpinMultiplicity = 2; last SPINMULTIPLICITY;} + if ($FreeRadicalElectrons == 2) { $SpinMultiplicity = 1; last SPINMULTIPLICITY;} + carp "Warning: ${ClassName}->GetSpinMultiplicity: It's not possible to determine spin multiplicity from the specified free radical electrons value, $FreeRadicalElectrons. It has been set to 0..."; + $SpinMultiplicity = 0; + } + } + + return $SpinMultiplicity; +} + +# Get number of free radical electrons: +# . Explicitly set by the caller +# . From SpinMultiplicity value explicitly set by the caller +# . Or return zero insetad of undef +# +# Notes: +# . For atoms with explicit assignment of SpinMultiplicity property values corresponding to +# Singlet (two unpaired electrons corresponding to one spin state), Doublet (free radical; an unpaired +# electron corresponding to two spin states), and Triplet (two unparied electrons corresponding to +# three spin states; divalent carbon atoms (carbenes)), FreeRadicalElectrons are calculated as follows: +# +# SpinMultiplicity: Doublet(2); FreeRadicalElectrons: 1 +# SpinMultiplicity: Singlet(1)/Triplet(3); FreeRadicalElectrons: 2 +# +sub GetFreeRadicalElectrons { + my($This) = @_; + my($FreeRadicalElectrons); + + $FreeRadicalElectrons = 0; + + if ($This->HasProperty('FreeRadicalElectrons')) { + $FreeRadicalElectrons = $This->GetProperty('FreeRadicalElectrons'); + return defined($FreeRadicalElectrons) ? $FreeRadicalElectrons : 0; + } + + if ($This->HasProperty('SpinMultiplicity')) { + my($SpinMultiplicity); + $SpinMultiplicity = $This->GetProperty('SpinMultiplicity'); + + SPINMULTIPLICITY: { + if ($SpinMultiplicity == 1) { $FreeRadicalElectrons = 2; last SPINMULTIPLICITY;} + if ($SpinMultiplicity == 2) { $FreeRadicalElectrons = 1; last SPINMULTIPLICITY;} + if ($SpinMultiplicity == 3) { $FreeRadicalElectrons = 2; last SPINMULTIPLICITY;} + carp "Warning: ${ClassName}->GetFreeRadicalElectrons: It's not possible to determine free radical electrons from the specified spin multiplicity value, $FreeRadicalElectrons. It has been set to 0..."; + $FreeRadicalElectrons = 0; + } + } + + return $FreeRadicalElectrons; +} + +# Set atom coordinates using: +# . An array reference with three values +# . An array containg three values +# . A 3D vector +# +sub SetXYZ { + my($This, @Values) = @_; + + if (!@Values) { + carp "Warning: ${ClassName}->SetXYZ: No values specified..."; + return; + } + + $This->{XYZ}->SetXYZ(@Values); + return $This; +} + +# Set X value... +sub SetX { + my($This, $Value) = @_; + + if (!defined $Value) { + carp "Warning: ${ClassName}->SetX: Undefined X value..."; + return; + } + $This->{XYZ}->SetX($Value); + return $This; +} + +# Set Y value... +sub SetY { + my($This, $Value) = @_; + + if (!defined $Value) { + carp "Warning: ${ClassName}->SetY: Undefined Y value..."; + return; + } + $This->{XYZ}->SetY($Value); + return $This; +} + +# Set Z value... +sub SetZ { + my($This, $Value) = @_; + + if (!defined $Value) { + carp "Warning: ${ClassName}->SetZ: Undefined Z value..."; + return; + } + $This->{XYZ}->SetZ($Value); + return $This; +} + +# Return XYZ as: +# . Reference to an array +# . An array +# +sub GetXYZ { + my($This) = @_; + + return $This->{XYZ}->GetXYZ(); +} + +# Return XYZ as a vector object... +# +sub GetXYZVector { + my($This) = @_; + + return $This->{XYZ}; +} + +# Get X value... +sub GetX { + my($This) = @_; + + return $This->{XYZ}->GetX(); +} + +# Get Y value... +sub GetY { + my($This) = @_; + + return $This->{XYZ}->GetY(); +} + +# Get Z value... +sub GetZ { + my($This) = @_; + + return $This->{XYZ}->GetZ(); +} + +# Delete atom... +sub DeleteAtom { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + # Nothing to do... + return $This; + } + my($Molecule) = $This->GetProperty('Molecule'); + + return $Molecule->_DeleteAtom($This); +} + +# Get atom neighbor objects as array. In scalar conetxt, return number of neighbors... +sub GetNeighbors { + my($This, @ExcludeNeighbors) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule) = $This->GetProperty('Molecule'); + + if (@ExcludeNeighbors) { + return $This->_GetAtomNeighbors(@ExcludeNeighbors); + } + else { + return $This->_GetAtomNeighbors(); + } +} + +# Get atom neighbor objects as array. In scalar conetxt, return number of neighbors... +sub _GetAtomNeighbors { + my($This, @ExcludeNeighbors) = @_; + my($Molecule) = $This->GetProperty('Molecule'); + + if (!@ExcludeNeighbors) { + return $Molecule->_GetAtomNeighbors($This); + } + + # Setup a map for neigbhors to exclude... + my($ExcludeNeighbor, $ExcludeNeighborID, %ExcludeNeighborsIDsMap); + + %ExcludeNeighborsIDsMap = (); + for $ExcludeNeighbor (@ExcludeNeighbors) { + $ExcludeNeighborID = $ExcludeNeighbor->GetID(); + $ExcludeNeighborsIDsMap{$ExcludeNeighborID} = $ExcludeNeighborID; + } + + # Generate a filtered neighbors list... + my($Neighbor, $NeighborID, @FilteredAtomNeighbors); + @FilteredAtomNeighbors = (); + NEIGHBOR: for $Neighbor ($Molecule->_GetAtomNeighbors($This)) { + $NeighborID = $Neighbor->GetID(); + if (exists $ExcludeNeighborsIDsMap{$NeighborID}) { + next NEIGHBOR; + } + push @FilteredAtomNeighbors, $Neighbor; + } + + return wantarray ? @FilteredAtomNeighbors : scalar @FilteredAtomNeighbors; +} + +# Get specific atom neighbor objects as array. In scalar conetxt, return number of neighbors. +# +# Notes: +# . AtomSpecification correspond to any valid AtomicInvariant based atomic specifications +# as implemented in DoesAtomNeighborhoodMatch method. +# . Multiple atom specifications can be used in a string delimited by comma. +# +sub GetNeighborsUsingAtomSpecification { + my($This, $AtomSpecification, @ExcludeNeighbors) = @_; + my(@AtomNeighbors); + + @AtomNeighbors = (); + @AtomNeighbors = $This->GetNeighbors(@ExcludeNeighbors); + + # Does atom has any neighbors and do they need to be filtered? + if (!(@AtomNeighbors && defined($AtomSpecification) && $AtomSpecification)) { + return wantarray ? @AtomNeighbors : scalar @AtomNeighbors; + } + + # Filter neighbors using atom specification... + my($AtomNeighbor, @FilteredAtomNeighbors); + + @FilteredAtomNeighbors = (); + NEIGHBOR: for $AtomNeighbor (@AtomNeighbors) { + if (!$AtomNeighbor->_DoesAtomSpecificationMatch($AtomSpecification)) { + next NEIGHBOR; + } + push @FilteredAtomNeighbors, $AtomNeighbor; + } + + return wantarray ? @FilteredAtomNeighbors : scalar @FilteredAtomNeighbors; +} + + +# Get non-hydrogen atom neighbor objects as array. In scalar context, return number of neighbors... +sub GetHeavyAtomNeighbors { + my($This) = @_; + + return $This->GetNonHydrogenAtomNeighbors(); +} + +# Get non-hydrogen atom neighbor objects as array. In scalar context, return number of neighbors... +sub GetNonHydrogenAtomNeighbors { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($NonHydrogenAtomsOnly, $HydrogenAtomsOnly) = (1, 0); + + return $This->_GetFilteredAtomNeighbors($NonHydrogenAtomsOnly, $HydrogenAtomsOnly); +} + +# Get hydrogen atom neighbor objects as array. In scalar context, return numbe of neighbors... +sub GetHydrogenAtomNeighbors { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($NonHydrogenAtomsOnly, $HydrogenAtomsOnly) = (0, 1); + + return $This->_GetFilteredAtomNeighbors($NonHydrogenAtomsOnly, $HydrogenAtomsOnly); +} + +# Get non-hydrogen neighbor of hydrogen atom... +# +sub GetNonHydrogenNeighborOfHydrogenAtom { + my($This) = @_; + + # Is it Hydrogen? + if (!$This->IsHydrogen()) { + return undef; + } + my(@Neighbors); + + @Neighbors = $This->GetNonHydrogenAtomNeighbors(); + + return (@Neighbors == 1) ? $Neighbors[0] : undef; +} + +# Get filtered atom atom neighbors +sub _GetFilteredAtomNeighbors { + my($This, $NonHydrogenAtomsOnly, $HydrogenAtomsOnly) = @_; + + # Check flags... + if (!defined $NonHydrogenAtomsOnly) { + $NonHydrogenAtomsOnly = 0; + } + if (!defined $HydrogenAtomsOnly) { + $HydrogenAtomsOnly = 0; + } + my($Neighbor, @FilteredAtomNeighbors); + + @FilteredAtomNeighbors = (); + NEIGHBOR: for $Neighbor ($This->GetNeighbors()) { + if ($NonHydrogenAtomsOnly && $Neighbor->IsHydrogen()) { + next NEIGHBOR; + } + if ($HydrogenAtomsOnly && (!$Neighbor->IsHydrogen())) { + next NEIGHBOR; + } + push @FilteredAtomNeighbors, $Neighbor; + } + + return wantarray ? @FilteredAtomNeighbors : scalar @FilteredAtomNeighbors; +} + +# Get number of neighbors... +# +sub GetNumOfNeighbors { + my($This) = @_; + my($NumOfNeighbors); + + $NumOfNeighbors = $This->GetNeighbors(); + + return (defined $NumOfNeighbors) ? $NumOfNeighbors : undef; +} + +# Get number of neighbors which are non-hydrogen atoms... +sub GetNumOfHeavyAtomNeighbors { + my($This) = @_; + + return $This->GetNumOfNonHydrogenAtomNeighbors(); +} + +# Get number of neighbors which are non-hydrogen atoms... +sub GetNumOfNonHydrogenAtomNeighbors { + my($This) = @_; + my($NumOfNeighbors); + + $NumOfNeighbors = $This->GetNonHydrogenAtomNeighbors(); + + return (defined $NumOfNeighbors) ? $NumOfNeighbors : undef; +} + +# Get number of neighbors which are hydrogen atoms... +sub GetNumOfHydrogenAtomNeighbors { + my($This) = @_; + my($NumOfNeighbors); + + $NumOfNeighbors = $This->GetHydrogenAtomNeighbors(); + + return (defined $NumOfNeighbors) ? $NumOfNeighbors : undef; +} + +# Get bond objects as array. In scalar context, return number of bonds... +sub GetBonds { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule) = $This->GetProperty('Molecule'); + + return $Molecule->_GetAtomBonds($This); +} + +# Get bond to specified atom... +sub GetBondToAtom { + my($This, $Other) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule) = $This->GetProperty('Molecule'); + + return $Molecule->_GetBondToAtom($This, $Other); +} + +# It it bonded to a specified atom? +sub IsBondedToAtom { + my($This, $Other) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule) = $This->GetProperty('Molecule'); + + return $Molecule->_IsBondedToAtom($This, $Other); +} + +# Get bond objects to non-hydrogen atoms as array. In scalar context, return number of bonds... +sub GetBondsToHeavyAtoms { + my($This) = @_; + + return $This->GetBondsToNonHydrogenAtoms(); +} + +# Get bond objects to non-hydrogen atoms as array. In scalar context, return number of bonds... +sub GetBondsToNonHydrogenAtoms { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($BondsToNonHydrogenAtomsOnly, $BondsToHydrogenAtomsOnly) = (1, 0); + + return $This->_GetFilteredBonds($BondsToNonHydrogenAtomsOnly, $BondsToHydrogenAtomsOnly); +} + +# Get bond objects to hydrogen atoms as array. In scalar context, return number of bonds... +sub GetBondsToHydrogenAtoms { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($BondsToNonHydrogenAtomsOnly, $BondsToHydrogenAtomsOnly) = (0, 1); + + return $This->_GetFilteredBonds($BondsToNonHydrogenAtomsOnly, $BondsToHydrogenAtomsOnly); +} + +# Get filtered bonds... +sub _GetFilteredBonds { + my($This, $BondsToNonHydrogenAtomsOnly, $BondsToHydrogenAtomsOnly) = @_; + + # Check flags... + if (!defined $BondsToNonHydrogenAtomsOnly) { + $BondsToNonHydrogenAtomsOnly = 0; + } + if (!defined $BondsToHydrogenAtomsOnly) { + $BondsToHydrogenAtomsOnly = 0; + } + + my($Bond, $BondedAtom, @FilteredBonds); + + @FilteredBonds = (); + BOND: for $Bond ($This->GetBonds()) { + $BondedAtom = $Bond->GetBondedAtom($This); + if ($BondsToNonHydrogenAtomsOnly && $BondedAtom->IsHydrogen()) { + next BOND; + } + if ($BondsToHydrogenAtomsOnly && (!$BondedAtom->IsHydrogen())) { + next BOND; + } + push @FilteredBonds, $Bond; + } + + return wantarray ? @FilteredBonds : (scalar @FilteredBonds); +} + +# Get number of bonds... +# +sub GetNumOfBonds { + my($This) = @_; + my($NumOfBonds); + + $NumOfBonds = $This->GetBonds(); + + return (defined $NumOfBonds) ? ($NumOfBonds) : undef; +} + +# Get number of bonds to non-hydrogen atoms... +sub GetNumOfBondsToHeavyAtoms { + my($This) = @_; + + return $This->GetNumOfBondsToNonHydrogenAtoms(); +} + +# Get number of bonds to non-hydrogen atoms... +sub GetNumOfBondsToNonHydrogenAtoms { + my($This) = @_; + my($NumOfBonds); + + $NumOfBonds = $This->GetBondsToNonHydrogenAtoms(); + + return (defined $NumOfBonds) ? ($NumOfBonds) : undef; +} + +# Get number of single bonds to heavy atoms... +sub GetNumOfSingleBondsToHeavyAtoms { + my($This) = @_; + + return $This->GetNumOfSingleBondsToNonHydrogenAtoms(); +} + +# Get number of single bonds to non-hydrogen atoms... +sub GetNumOfSingleBondsToNonHydrogenAtoms { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + return $This->_GetNumOfBondsWithSpecifiedBondOrderToNonHydrogenAtoms(1); +} + +# Get number of double bonds to heavy atoms... +sub GetNumOfDoubleBondsToHeavyAtoms { + my($This) = @_; + + return $This->GetNumOfDoubleBondsToNonHydrogenAtoms(); +} + +# Get number of double bonds to non-hydrogen atoms... +sub GetNumOfDoubleBondsToNonHydrogenAtoms { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + return $This->_GetNumOfBondsWithSpecifiedBondOrderToNonHydrogenAtoms(2); +} + +# Get number of triple bonds to heavy atoms... +sub GetNumOfTripleBondsToHeavyAtoms { + my($This) = @_; + + return $This->GetNumOfTripleBondsToNonHydrogenAtoms(); +} + +# Get number of triple bonds to non-hydrogen atoms... +sub GetNumOfTripleBondsToNonHydrogenAtoms { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + return $This->_GetNumOfBondsWithSpecifiedBondOrderToNonHydrogenAtoms(3); +} + +# Get number of bonds of specified bond order to non-hydrogen atoms... +sub _GetNumOfBondsWithSpecifiedBondOrderToNonHydrogenAtoms { + my($This, $SpecifiedBondOrder) = @_; + my($NumOfBonds, $Bond, $BondOrder, @Bonds); + + $NumOfBonds = 0; + @Bonds = $This->GetBondsToNonHydrogenAtoms(); + for $Bond (@Bonds) { + $BondOrder = $Bond->GetBondOrder(); + if ($SpecifiedBondOrder == $BondOrder) { + $NumOfBonds++; + } + } + return $NumOfBonds; +} + +# Get number of aromatic bonds to heavy atoms... +sub GetNumOfAromaticBondsToHeavyAtoms { + my($This) = @_; + + return $This->GetNumOfAromaticBondsToNonHydrogenAtoms(); +} + +# Get number of aromatic bonds to non-hydrogen atoms... +sub GetNumOfAromaticBondsToNonHydrogenAtoms { + my($This) = @_; + my($NumOfBonds, $Bond, @Bonds); + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + + $NumOfBonds = 0; + @Bonds = $This->GetBondsToNonHydrogenAtoms(); + for $Bond (@Bonds) { + if ($Bond->IsAromatic()) { $NumOfBonds++; } + } + return $NumOfBonds; +} + +# Get number of different bond types to non-hydrogen atoms... +# +sub GetNumOfBondTypesToHeavyAtoms { + my($This, $CountAromaticBonds) = @_; + + return $This->GetNumOfBondTypesToNonHydrogenAtoms($CountAromaticBonds); +} + +# Get number of single, double, triple, and aromatic bonds from an atom to all other +# non-hydrogen atoms. Value of CountAtomaticBonds parameter controls whether +# number of aromatic bonds is returned; default is not to count aromatic bonds. During +# counting of aromatic bonds, the bond marked aromatic is not included in the count +# of other bond types. +# +sub GetNumOfBondTypesToNonHydrogenAtoms { + my($This, $CountAromaticBonds) = @_; + my($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds, $None, $Bond, @Bonds); + + $CountAromaticBonds = defined($CountAromaticBonds) ? $CountAromaticBonds : 0; + + ($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds) = ('0') x 3; + $NumOfAromaticBonds = $CountAromaticBonds ? 0 : undef; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return ($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds); + } + + @Bonds = $This->GetBondsToNonHydrogenAtoms(); + + for $Bond (@Bonds) { + BONDTYPE: { + if ($CountAromaticBonds) { + if ($Bond->IsAromatic()) { $NumOfAromaticBonds++; last BONDTYPE; } + } + if ($Bond->IsSingle()) { $NumOfSingleBonds++; last BONDTYPE; } + if ($Bond->IsDouble()) { $NumOfDoubleBonds++; last BONDTYPE; } + if ($Bond->IsTriple()) { $NumOfTripleBonds++; last BONDTYPE; } + $None = 1; + } + } + return ($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds); +} + +# Get number of sigma and pi bonds to heavy atoms... +# +sub GetNumOfSigmaAndPiBondsToHeavyAtoms { + my($This) = @_; + + return $This->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms(); +} + +# Get number of sigma and pi bonds from an atom to all other non-hydrogen atoms. +# Sigma and pi bonds are counted using the following methodology: a single bond +# correspond to one sigma bond; a double bond contributes one to sigma bond count +# and one to pi bond count; a triple bond contributes one to sigma bond count and +# two to pi bond count. +# +sub GetNumOfSigmaAndPiBondsToNonHydrogenAtoms { + my($This) = @_; + my($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfSigmaBonds, $NumOfPiBonds); + + ($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds) = $This->GetNumOfBondTypesToNonHydrogenAtoms(); + + $NumOfSigmaBonds = $NumOfSingleBonds + $NumOfDoubleBonds + $NumOfTripleBonds; + $NumOfPiBonds = $NumOfDoubleBonds + 2*$NumOfTripleBonds; + + return ($NumOfSigmaBonds, $NumOfPiBonds); +} + +# Get information related to atoms for all heavy atoms attached to an atom.. +# +sub GetHeavyAtomNeighborsAtomInformation { + my($This) = @_; + + return $This->GetNonHydrogenAtomNeighborsAtomInformation(); +} + +# Get information related to atoms for all non-hydrogen atoms attached to an atom.. +# +# The following values are returned: +# . Number of non-hydrogen atom neighbors +# . A reference to an array containing atom objects correpsonding to non-hydrogen +# atom neighbors +# . Number of different types of non-hydrogen atom neighbors +# . A reference to a hash containing atom symbol as key with value corresponding +# to its count for non-hydrogen atom neighbors +# +sub GetNonHydrogenAtomNeighborsAtomInformation { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return (undef, undef, undef, undef); + } + my($AtomSymbol, $AtomNeighbor, $NumOfAtomNeighbors, $NumOfAtomNeighborsType, @AtomNeighbors, %AtomNeighborsTypeMap); + + $NumOfAtomNeighbors = 0; @AtomNeighbors = (); + $NumOfAtomNeighborsType = 0; %AtomNeighborsTypeMap = (); + + @AtomNeighbors = $This->GetNonHydrogenAtomNeighbors(); + $NumOfAtomNeighbors = scalar @AtomNeighbors; + + for $AtomNeighbor (@AtomNeighbors) { + $AtomSymbol = $AtomNeighbor->{AtomSymbol}; + if (exists $AtomNeighborsTypeMap{$AtomSymbol}) { + $AtomNeighborsTypeMap{$AtomSymbol} += 1; + } + else { + $AtomNeighborsTypeMap{$AtomSymbol} = 1; + $NumOfAtomNeighborsType++; + } + } + + return ($NumOfAtomNeighbors, \@AtomNeighbors, $NumOfAtomNeighborsType, \%AtomNeighborsTypeMap); +} + +# Get information related to bonds for all heavy atoms attached to an atom.. +# +sub GetHeavyAtomNeighborsBondformation { + my($This) = @_; + + return $This->GetNonHydrogenAtomNeighborsBondInformation(); +} + +# Get information related to bonds for all non-hydrogen atoms attached to an atom.. +# +# The following values are returned: +# . Number of bonds to non-hydrogen atom neighbors +# . A reference to an array containing bond objects correpsonding to non-hydrogen +# atom neighbors +# . A reference to a hash containing bond type as key with value corresponding +# to its count for non-hydrogen atom neighbors. Bond types are: Single, Double or Triple +# . A reference to a hash containing atom symbol as key pointing to bond type as second +# key with values correponding to count of bond types for atom symbol for non-hydrogen +# atom neighbors +# . A reference to a hash containing atom symbol as key pointing to bond type as second +# key with values correponding to atom objects array involved in corresponding bond type for +# atom symbol for non-hydrogen atom neighbors +# +sub GetNonHydrogenAtomNeighborsBondInformation { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return (undef, undef, undef, undef, undef); + } + my($BondedAtom, $BondedAtomSymbol, $BondType, $None, $Bond, $NumOfBonds, @Bonds, %BondTypeCountMap, %AtomsBondTypesCountMap, %AtomsBondTypeAtomsMap); + + $NumOfBonds = 0; @Bonds = (); + %BondTypeCountMap = (); + %AtomsBondTypesCountMap = (); %AtomsBondTypeAtomsMap = (); + + $BondTypeCountMap{Single} = 0; + $BondTypeCountMap{Double} = 0; + $BondTypeCountMap{Triple} = 0; + + @Bonds = $This->GetBondsToNonHydrogenAtoms(); + $NumOfBonds = scalar @Bonds; + + BOND: for $Bond (@Bonds) { + $BondType = $Bond->IsSingle() ? "Single" : ($Bond->IsDouble() ? "Double" : ($Bond->IsTriple() ? "Triple" : "")); + if (!$BondType) { + next BOND; + } + + # Track bond types... + if (exists $BondTypeCountMap{$BondType}) { + $BondTypeCountMap{$BondType} += 1; + } + else { + $BondTypeCountMap{$BondType} = 1; + } + + $BondedAtom = $Bond->GetBondedAtom($This); + $BondedAtomSymbol = $BondedAtom->{AtomSymbol}; + + # Track bond types count for atom types involved in specific bond types... + if (!exists $AtomsBondTypesCountMap{$BondedAtomSymbol}) { + %{$AtomsBondTypesCountMap{$BondedAtomSymbol}} = (); + } + if (exists $AtomsBondTypesCountMap{$BondedAtomSymbol}{$BondType}) { + $AtomsBondTypesCountMap{$BondedAtomSymbol}{$BondType} += 1; + } + else { + $AtomsBondTypesCountMap{$BondedAtomSymbol}{$BondType} = 1; + } + + # Track atoms involved in specific bond types for specific atom types... + if (!exists $AtomsBondTypeAtomsMap{$BondedAtomSymbol}) { + %{$AtomsBondTypeAtomsMap{$BondedAtomSymbol}} = (); + } + if (!exists $AtomsBondTypeAtomsMap{$BondedAtomSymbol}{$BondType}) { + @{$AtomsBondTypeAtomsMap{$BondedAtomSymbol}{$BondType}} = (); + } + push @{$AtomsBondTypeAtomsMap{$BondedAtomSymbol}{$BondType}}, $BondedAtom; + } + + return ($NumOfBonds, \@Bonds, \%BondTypeCountMap, \%AtomsBondTypesCountMap, \%AtomsBondTypeAtomsMap); +} + +# Get number of bonds to hydrogen atoms... +sub GetNumOfBondsToHydrogenAtoms { + my($This) = @_; + my($NumOfBonds); + + $NumOfBonds = $This->GetBondsToHydrogenAtoms(); + + return (defined $NumOfBonds) ? ($NumOfBonds) : undef; +} + +# Get sum of bond orders to all bonded atoms... +# +sub GetSumOfBondOrders { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + + return $This->_GetSumOfBondOrders(); +} + +# Get sum of bond orders to non-hydrogen atoms only... +# +sub GetSumOfBondOrdersToHeavyAtoms { + my($This) = @_; + + return $This->GetSumOfBondOrdersToNonHydrogenAtoms(); +} + +# Get sum of bond orders to non-hydrogen atoms only... +# +sub GetSumOfBondOrdersToNonHydrogenAtoms { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($ToNonHydrogenAtomsOnly, $ToHydrogenAtomsOnly) = (1, 0); + + return $This->_GetSumOfBondOrders($ToNonHydrogenAtomsOnly, $ToHydrogenAtomsOnly); +} + +# Get sum of bond orders to hydrogen atoms only... +# +sub GetSumOfBondOrdersToHydrogenAtoms { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($ToNonHydrogenAtomsOnly, $ToHydrogenAtomsOnly) = (0, 1); + + return $This->_GetSumOfBondOrders($ToNonHydrogenAtomsOnly, $ToHydrogenAtomsOnly); +} + +# Get sum of bond orders to all bonded atoms, non-hydrogen or hydrogen bonded atoms... +# +sub _GetSumOfBondOrders { + my($This, $ToNonHydrogenAtomsOnly, $ToHydrogenAtomsOnly) = @_; + + # Check flags... + if (!defined $ToNonHydrogenAtomsOnly) { + $ToNonHydrogenAtomsOnly = 0; + } + if (!defined $ToHydrogenAtomsOnly) { + $ToHydrogenAtomsOnly = 0; + } + my($Bond, $SumOfBondOrders, @Bonds); + @Bonds = (); + + if ($ToNonHydrogenAtomsOnly) { + @Bonds = $This->GetBondsToNonHydrogenAtoms(); + } + elsif ($ToHydrogenAtomsOnly) { + @Bonds = $This->GetBondsToHydrogenAtoms(); + } + else { + # All bonds... + @Bonds = $This->GetBonds(); + } + + $SumOfBondOrders = 0; + for $Bond (@Bonds) { + $SumOfBondOrders += $Bond->GetBondOrder(); + } + + if ($SumOfBondOrders =~ /\./) { + # + # Change any fractional bond order to next largest integer... + # + # As long as aromatic bond orders in a ring are correctly using using 4n + 2 Huckel rule + # (BondOrder: 1.5) or explicity set as Kekule bonds (alternate single/double), + # SumOfBondOrders should add up to an integer. + # + $SumOfBondOrders = ceil($SumOfBondOrders); + } + + return $SumOfBondOrders; +} + +# Get largest bond order to any bonded atoms... +# +sub GetLargestBondOrder { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + + return $This->_GetLargestBondOrder(); +} + +# Get largest bond order to bonded non-hydrogen atoms... +# +sub GetLargestBondOrderToHeavyAtoms { + my($This) = @_; + + return $This->GetLargestBondOrderToNonHydrogenAtoms(); +} + +# Get largest bond order to bonded non-hydrogen atoms... +# +sub GetLargestBondOrderToNonHydrogenAtoms { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + + my($ToNonHydrogenAtomsOnly) = (1); + + return $This->_GetLargestBondOrder($ToNonHydrogenAtomsOnly); +} + +# Get largest bond order to all bonded atoms, non-hydrogen or hydrogen bonded atoms... +# +sub _GetLargestBondOrder { + my($This, $ToNonHydrogenAtomsOnly, $ToHydrogenAtomsOnly) = @_; + + # Check flags... + if (!defined $ToNonHydrogenAtomsOnly) { + $ToNonHydrogenAtomsOnly = 0; + } + if (!defined $ToHydrogenAtomsOnly) { + $ToHydrogenAtomsOnly = 0; + } + my($Bond, $LargestBondOrder, $BondOrder, @Bonds); + @Bonds = (); + + if ($ToNonHydrogenAtomsOnly) { + @Bonds = $This->GetBondsToNonHydrogenAtoms(); + } + elsif ($ToHydrogenAtomsOnly) { + @Bonds = $This->GetBondsToHydrogenAtoms(); + } + else { + # All bonds... + @Bonds = $This->GetBonds(); + } + + $LargestBondOrder = 0; + for $Bond (@Bonds) { + $BondOrder = $Bond->GetBondOrder(); + if ($BondOrder > $LargestBondOrder) { + $LargestBondOrder = $BondOrder; + } + } + + return $LargestBondOrder; +} + +# Get number of implicit hydrogen for atom... +# +sub GetImplicitHydrogens { + my($This) = @_; + + return $This->GetNumOfImplicitHydrogens(); +} + +# Get number of implicit hydrogen for atom... +# +sub GetNumOfImplicitHydrogens { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + + # Is ImplicitHydrogens property explicitly set? + if ($This->HasProperty('ImplicitHydrogens')) { + return $This->GetProperty('ImplicitHydrogens'); + } + + # Is it an element symbol? + if (!$This->{AtomicNumber}) { + return 0; + } + + my($ImplicitHydrogens, $PotentialTotalValence, $SumOfBondOrders); + + $ImplicitHydrogens = 0; + $SumOfBondOrders = $This->GetSumOfBondOrders(); + $PotentialTotalValence = $This->GetPotentialTotalCommonValence(); + + if (defined($PotentialTotalValence) && defined($SumOfBondOrders)) { + # Subtract sum of bond orders to non-hydrogen and hydrogen atom neighbors... + $ImplicitHydrogens = $PotentialTotalValence - $SumOfBondOrders; + } + + return $ImplicitHydrogens > 0 ? $ImplicitHydrogens : 0; +} + +# Get number of bonds available to form additional bonds with heavy atoms, excluding +# any implicit bonds to hydrogens set using ImplicitHydrogens property. +# +# It's different from number of implicit or missing hydrogens, both of which are equivalent. +# +# For example, in a SMILES string, [nH] ring atom corresponds to an aromatic nitrogen. +# Although the hydrogen specified for n is treated internally as implicit hydrogen and shows +# up in missing hydrogen count, it's not available to participate in double bonds to additional +# heavy atoms. +# +sub GetNumOfBondsAvailableForHeavyAtoms { + my($This) = @_; + + return $This->GetNumOfBondsAvailableForNonHydrogenAtoms(); +} + +# It's another name for GetNumOfBondsAvailableForHeavyAtoms +# +sub GetNumOfBondsAvailableForNonHydrogenAtoms { + my($This) = @_; + my($NumOfAvailableBonds, $PotentialTotalValence, $SumOfBondOrders); + + $NumOfAvailableBonds = 0; + + $SumOfBondOrders = $This->GetSumOfBondOrders(); + $PotentialTotalValence = $This->GetPotentialTotalCommonValence(); + + if (defined($PotentialTotalValence) && defined($SumOfBondOrders)) { + # Subtract sum of bond orders to non-hydrogen and hydrogen atom neighbors... + $NumOfAvailableBonds = $PotentialTotalValence - $SumOfBondOrders; + } + + if ($This->HasProperty('ImplicitHydrogens')) { + $NumOfAvailableBonds -= $This->GetProperty('ImplicitHydrogens'); + } + + return $NumOfAvailableBonds > 0 ? $NumOfAvailableBonds : 0; +} + +# Disable setting of explicit hydrogens property... +sub SetExplicitHydrogens { + my($This, $Value) = @_; + + carp "Warning: ${ClassName}->SetExplicitHydrogens: Setting of explicit hydrogens is not supported..."; + + return $This; +} + +# Get number of explicit hydrogens for atom... +# +sub GetExplicitHydrogens { + my($This) = @_; + + return $This->GetNumOfExplicitHydrogens(); +} + +# Get number of explicit hydrogens for atom... +# +sub GetNumOfExplicitHydrogens { + my($This) = @_; + my($HydrogenAtomNbrs); + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + + $HydrogenAtomNbrs = $This->GetNumOfHydrogenAtomNeighbors(); + + return defined $HydrogenAtomNbrs ? $HydrogenAtomNbrs : 0; +} + +# Get num of missing hydrogens... +# +sub GetMissingHydrogens { + my($This) = @_; + + return $This->GetNumOfMissingHydrogens(); +} + +# Get num of missing hydrogens... +# +sub GetNumOfMissingHydrogens { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + + return $This->GetNumOfImplicitHydrogens(); +} + +# Get total number of hydrogens... +# +sub GetHydrogens { + my($This) = @_; + + return $This->GetNumOfHydrogens(); +} + +# Get total number of hydrogens... +# +sub GetNumOfHydrogens { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + + return $This->GetNumOfImplicitHydrogens() + $This->GetNumOfExplicitHydrogens(); +} + +# Valence corresponds to the number of electrons used by an atom in bonding: +# +# Valence = ValenceElectrons - ValenceFreeElectrons = BondingElectrons +# +# Single, double, triple bonds with bond orders of 1, 2 and 3 correspond to contribution of +# 1, 2, and 3 bonding electrons. So Valence can be computed using: +# +# Valence = SumOfBondOrders + NumOfMissingHydrogens + FormalCharge +# +# where positive and negative values of FormalCharge increase and decrease the number +# of bonding electrons respectively. +# +# The current release of MayaChemTools supports the following three valence models, which +# are used during calculation of implicit hydrogens: MDLValenceModel, DaylightValenceModel, +# InternalValenceModel or MayaChemToolsValenceModel. +# +# Notes: +# . This doesn't always corresponds to explicit valence. +# . Missing hydrogens are included in the valence. +# . For neutral molecules, valence and sum of bond order are equal. +# . For molecules containing only single bonds, SumOfBondOrders and NumOfBonds are equal. +# . Free radical electrons lead to the decrease in valence. For atoms with explicit assignment +# of SpinMultiplicity property values corresponding to Singlet (two unparied electrons +# corresponding to one spin state), Doublet (free radical; an unpaired electron corresponding +# to two spin states), and Triplet (two unparied electrons corresponding to three spin states; +# divalent carbon atoms (carbenes)), FreeRadicalElectrons are calculated as follows: +# +# SpinMultiplicity: Doublet(2); FreeRadicalElectrons: 1 (one valence electron not available for bonding) +# SpinMultiplicity: Singlet(1)/Triplet(3); FreeRadicalElectrons: 2 (two valence electrons not available for bonding) +# +sub GetValence { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + + # Is Valence property explicitly set? + if ($This->HasProperty('Valence')) { + return $This->GetProperty('Valence'); + } + my($Valence); + + $Valence = $This->GetSumOfBondOrders() + $This->GetNumOfMissingHydrogens() + $This->GetFormalCharge(); + + return $Valence > 0 ? $Valence : 0; +} + +# Get free non-bodning valence electrons left on atom after taking into account +# sum of bond orders, missing hydrogens and formal charged on the atom. Free +# radical electrons are included in the valence free electrons count by default. +# +# Valence corresponds to number of electrons used by atom in bonding: +# +# Valence = ValenceElectrons - ValenceFreeElectrons +# +# Additionally, valence can also be calculated by: +# +# Valence = SumOfBondOrders + NumOfMissingHydrogens + FormalCharge +# +# Valence and SumOfBondOrders are equal for neutral molecules. +# +# From two formulas for Valence described above, non-bonding free electrons +# left can be computed by: +# +# ValenceFreeElectrons = ValenceElectrons - Valence +# = ValenceElectrons - SumOfBondOrders - +# NumOfMissingHydrogens - FormalCharge +# +# . Notes: +# . Missing hydrogens are excluded from the valence free electrons. +# . Any free radical electrons are considered part of the valence free electrons +# by default. +# +# Examples: +# +# o NH3: ValenceFreeElectrons = 5 - 3 = 5 - 3 - 0 - 0 = 2 +# o NH2: ValenceFreeElectrons = 5 - 3 = 5 - 2 - 1 - 0 = 2 +# o NH4+; ValenceFreeElectrons = 5 - 5 = 5 - 4 - 0 - 1 = 0 +# o NH3+; ValenceFreeElectrons = 5 - 5 = 5 - 3 - 1 - 1 = 0 +# o C(=O)O- : ValenceFreeElectrons on O- = 6 - 0 = 6 - 1 - 0 - (-1) = 6 +# o C(=O)O- : ValenceFreeElectrons on =O = 6 - 2 = 6 - 2 - 0 - 0 = 4 +# +# +sub GetValenceFreeElectrons { + my($This, $ExcludeFreeRadicalElectrons) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + + # Is ValenceFreeElectrons property explicitly set? + if ($This->HasProperty('ValenceFreeElectrons')) { + return $This->GetProperty('ValenceFreeElectrons'); + } + + if (!$This->{AtomicNumber}) { + return 0; + } + + my($ValenceFreeElectrons); + + $ValenceFreeElectrons = $This->GetValenceElectrons() - $This->GetValence(); + if ($ExcludeFreeRadicalElectrons) { + $ValenceFreeElectrons -= $This->GetFreeRadicalElectrons(); + } + + return $ValenceFreeElectrons > 0 ? $ValenceFreeElectrons : 0; +} + +# Get potential total common valence for calculating the number of implicit hydrogens +# using the specified common valence model or default internal model for a molecule... +# +sub GetPotentialTotalCommonValence { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($PotentialTotalValence, $ValenceModel); + + $PotentialTotalValence = 0; + $ValenceModel = $This->GetProperty('Molecule')->GetValenceModel(); + + VALENCEMODEL: { + if ($ValenceModel =~ /^MDLValenceModel$/i) { + $PotentialTotalValence = $This->_GetPotentialTotalCommonValenceUsingMDLValenceModel(); + last VALENCEMODEL; + } + if ($ValenceModel =~ /^DaylightValenceModel$/i) { + $PotentialTotalValence = $This->_GetPotentialTotalCommonValenceUsingDaylightValenceModel(); + last VALENCEMODEL; + } + if ($ValenceModel !~ /^(InternalValenceModel|MayaChemToolsValenceModel)$/i) { + carp "Warning: ${ClassName}->GetPotentialTotalCommonValence: The current release of MayaChemTools doesn't support the specified valence model $ValenceModel. Supported valence models: MDLValenceModel, DaylightValenceModel, InternalValenceModel. Using internal valence model..."; + } + # Use internal valence model as the default valence model... + $PotentialTotalValence = $This->_GetPotentialTotalCommonValenceUsingInternalValenceModel(); + } + + return $PotentialTotalValence; +} + +# Get potential total common valence using data for MDL valence model available in file, +# lib/data/MDLValenceModelData.csv, distributed with the package... +# +sub _GetPotentialTotalCommonValenceUsingMDLValenceModel { + my($This) = @_; + + return $This->_GetPotentialTotalCommonValenceUsingValenceModelData(\%MDLValenceModelDataMap); + +} + +# Get potential total common valence using data for Daylight valence model available in file, +# lib/data/DaylightValenceModelData.csv, distributed with the release... +# +sub _GetPotentialTotalCommonValenceUsingDaylightValenceModel { + my($This) = @_; + + return $This->_GetPotentialTotalCommonValenceUsingValenceModelData(\%DaylightValenceModelDataMap); +} + +# Get potential total common valence using data for a specific valence model... +# +sub _GetPotentialTotalCommonValenceUsingValenceModelData { + my($This, $ValenceModelDataRef) = @_; + my($AtomicNumber, $FormalCharge); + + $AtomicNumber = $This->{AtomicNumber}; + if (!$AtomicNumber) { + return 0; + } + + $FormalCharge = $This->GetFormalCharge(); + + # Is any valence model data available for atomic number and formal charge? + if (!exists $ValenceModelDataRef->{$AtomicNumber}) { + return 0; + } + if (!exists $ValenceModelDataRef->{$AtomicNumber}{$FormalCharge}) { + return 0; + } + + my($PotentialTotalValence, $SumOfBondOrders, $CurrentEffectiveValence, $AvailableCommonValence); + + $SumOfBondOrders = $This->GetSumOfBondOrders(); + if (!defined $SumOfBondOrders) { + $SumOfBondOrders = 0; + } + $CurrentEffectiveValence = $SumOfBondOrders + $This->GetFreeRadicalElectrons(); + + $PotentialTotalValence = 0; + VALENCE: for $AvailableCommonValence (@{$ValenceModelDataRef->{$AtomicNumber}{$FormalCharge}{CommonValences}}) { + if ($CurrentEffectiveValence <= $AvailableCommonValence) { + $PotentialTotalValence = $AvailableCommonValence; + last VALENCE; + } + } + + return $PotentialTotalValence; +} + +# +# For elements with one one common valence, potential total common valence used +# during the calculation for number of implicit hydrogens during InternalValenceMode +# corresponds to: +# +# CommonValence + FormalCharge - FreeRadicalElectrons +# +# For elements with multiple common valences, each common valence is used to +# calculate total potential common valence as shown above, and the first total potential +# common valence gerater than the sum of bond orderes is selected as the final total +# common valence. +# +# Group numbers > 14 - Group numbers 15 (N), 16 (O), 17 (F), 18 (He) +# +# Formal charge sign is not adjusted. Positive and negative values result in the +# increase and decrease of valence. +# +# Group 14 containing C, Si, Ge, Sn, Pb... +# +# Formal charge sign is reversed for positive values. Both positive and negative +# values result in the decrease of valence. +# +# Group 13 containing B, Al, Ga, In, Tl... +# +# Formal charge sign is always reversed. Positive and negative values result in the +# decrease and increase of valence. +# +# Groups 1 (H) through 12 (Zn)... +# +# Formal charge sign is reversed for positive values. Both positive and negative +# values result in the decrease of valence. +# +# Lanthanides and actinides... +# +# Formal charge sign is reversed for positive values. Both positive and negative +# values result in the decrease of valence. +# +# Notes: +# . CommonValence and HighestCommonValence available from PeriodicTable module +# are equivalent to most common and highest sum of bond orders for an element. For +# neutral atoms involved only in single bonds, it corresponds to highest number of +# allowed bonds for the atom. +# . FormalCharge sign is reversed for electropositive elements with positive formal charge +# during common valence calculations. Electropositive elements, metals and transition elements, +# have usually plus formal charge and it leads to decrease in common valence; the negative +# formal charge should result in the decrease of common valence. +# . For carbon, both plus/minus formal charge cause decrease in common valence +# . For elements on the right of carbon in periodic table, electronegative elements, plus formal +# charge causes common valence to increase and minus formal charge cause it to decrease. +# +sub _GetPotentialTotalCommonValenceUsingInternalValenceModel { + my($This) = @_; + my($AtomicNumber, $CommonValences); + + $AtomicNumber = $This->{AtomicNumber}; + if (!$AtomicNumber) { + return 0; + } + + $CommonValences = PeriodicTable::GetElementCommonValences($AtomicNumber); + if (!$CommonValences) { + return 0; + } + + my($PotentialTotalValence, $AdjustedFormalCharge, $FreeRadicalElectrons, $SumOfBondOrders, $AvailableCommonValence, @AvailableCommonValences); + + $AdjustedFormalCharge = $This->_GetFormalChargeAdjustedForInternalValenceModel(); + $FreeRadicalElectrons = $This->GetFreeRadicalElectrons(); + + $SumOfBondOrders = $This->GetSumOfBondOrders(); + if (!defined $SumOfBondOrders) { + $SumOfBondOrders = 0; + } + + @AvailableCommonValences = split /\,/, $CommonValences; + + if (@AvailableCommonValences == 1) { + # Calculate potential total valence using the only available common valence... + $PotentialTotalValence = $AvailableCommonValences[0] + $AdjustedFormalCharge - $FreeRadicalElectrons; + } + else { + # Calculate potential total valence using common valence from a list of available valences + # that makes it higher than sum of bond orders or using the highest common valence... + VALENCE: for $AvailableCommonValence (@AvailableCommonValences) { + $PotentialTotalValence = $AvailableCommonValence + $AdjustedFormalCharge - $FreeRadicalElectrons; + + if ($PotentialTotalValence < 0 || $PotentialTotalValence >= $SumOfBondOrders) { + last VALENCE; + } + } + } + + return $PotentialTotalValence > 0 ? $PotentialTotalValence : 0; +} + +# Adjust sign of the formal charge for potential total common valence calculation +# used during internal valence model to figure out number of implicit hydrogens. +# +sub _GetFormalChargeAdjustedForInternalValenceModel { + my($This) = @_; + my($FormalCharge, $GroupNumber, $SwitchSign); + + $FormalCharge = $This->GetFormalCharge(); + if ($FormalCharge == 0) { + return 0; + } + + $GroupNumber = $This->GetGroupNumber(); + if (!defined $GroupNumber) { + return $FormalCharge; + } + + # Group numbers > 14 - Group numbers 15 (N), 16 (O), 17 (F), 18 (He) + # + # Formal charge sign is not adjusted. Positive and negative values result in the + # increase and decrease of valence. + # + # Group 14 containing C, Si, Ge, Sn, Pb... + # + # Formal charge sign is reversed for positive values. Both positive and negative + # values result in the decrease of valence. + # + # Group 13 containing B, Al, Ga, In, Tl... + # + # Formal charge sign is always reversed. Positive and negative values result in the + # decrease and increase of valence. + # + # Groups 1 (H) through 12 (Zn)... + # + # Formal charge sign is reversed for positive values. Both positive and negative + # values result in the decrease of valence. + # + # Lanthanides and actinides... + # + # Formal charge sign is reversed for positive values. Both positive and negative + # values result in the decrease of valence. + # + + $SwitchSign = 0; + if (length $GroupNumber) { + GROUPNUMBER: { + if ($GroupNumber > 14) { + # Groups on the right side of C group in the periodic table... + $SwitchSign = 0; + last GROUPNUMBER; + } + if ($GroupNumber == 14) { + # Group containing C, Si, Ge, Sn, Pb... + $SwitchSign = ($FormalCharge > 0) ? 1 : 0; + last GROUPNUMBER; + } + if ($GroupNumber == 13) { + # Group containing B, Al, Ga, In, Tl... + $SwitchSign = 1; + last GROUPNUMBER; + } + # Groups 1 (H) through 12 (Zn)... + if ($GroupNumber >=1 && $GroupNumber <= 12) { + # Groups 1 (H) through 12 (Zn)... + $SwitchSign = ($FormalCharge > 0) ? 1 : 0; + last GROUPNUMBER; + } + } + } + else { + # Lanthanides and actinides... + $SwitchSign = ($FormalCharge > 0) ? 1 : 0; + } + + if ($SwitchSign) { + $FormalCharge *= -1.0; + } + + return $FormalCharge; +} + +# Get lowest common valence... +sub GetLowestCommonValence { + my($This) = @_; + + # Is LowestCommonValence property explicitly set? + if ($This->HasProperty('LowestCommonValence')) { + return $This->GetProperty('LowestCommonValence'); + } + my($AtomicNumber, $LowestCommonValence); + + $AtomicNumber = $This->{AtomicNumber}; + if (!$AtomicNumber) { + return 0; + } + # Any need to differentiate between internal and other valence models... + + # LowestCommonValence is not set for all elements... + $LowestCommonValence = PeriodicTable::GetElementLowestCommonValence($AtomicNumber); + if (!$LowestCommonValence) { + $LowestCommonValence = undef; + } + + return $LowestCommonValence; +} + +# Get highest common valence... +sub GetHighestCommonValence { + my($This) = @_; + + # Is HighestCommonValence property explicitly set? + if ($This->HasProperty('HighestCommonValence')) { + return $This->GetProperty('HighestCommonValence'); + } + my($AtomicNumber, $HighestCommonValence); + + $AtomicNumber = $This->{AtomicNumber}; + if (!$AtomicNumber) { + return 0; + } + + # Any need to differentiate between internal and other valence models... + + # HighestCommonValence is not set for all elements... + $HighestCommonValence = PeriodicTable::GetElementHighestCommonValence($AtomicNumber); + if (!$HighestCommonValence) { + $HighestCommonValence = undef; + } + + return $HighestCommonValence; +} + +# Get valence electrons... +sub GetValenceElectrons { + my($This) = @_; + + # Is ValenceElectrons property explicitly set? + if ($This->HasProperty('ValenceElectrons')) { + return $This->GetProperty('ValenceElectrons'); + } + my($AtomicNumber, $ValenceElectrons); + + $AtomicNumber = $This->{AtomicNumber}; + if (!$AtomicNumber) { + return 0; + } + + $ValenceElectrons = PeriodicTable::GetElementValenceElectrons($AtomicNumber); + + return $ValenceElectrons; +} + +# Add hydrogens to specified atom in molecule and return number of hydrogens added: +# +# o HydrogensToAdd = ImplicitHydrogenCount - ExplicitHydrogenCount +# +# o XYZ are set to ZeroVector +# +sub AddHydrogens { + my($This, $HydrogenPositionsWarning) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + if (!defined $HydrogenPositionsWarning) { + $HydrogenPositionsWarning = 1; + } + if ($HydrogenPositionsWarning) { + carp "Warning: ${ClassName}->AddHydrogens: The current release of MayaChemTools doesn't assign any hydrogen positions..."; + } + + # Is it an element symbol? + if (!$This->{AtomicNumber}) { + return 0; + } + + my($Molecule, $HydrogensAdded, $HydrogensToAdd); + + $Molecule = $This->GetProperty('Molecule'); + $HydrogensAdded = 0; + $HydrogensToAdd = $This->GetNumOfMissingHydrogens(); + if ($HydrogensToAdd <= 0) { + return $HydrogensAdded; + } + + my($Count, $Hydrogen); + + for $Count (1 .. $HydrogensToAdd) { + $HydrogensAdded++; + + $Hydrogen = $Molecule->NewAtom('AtomSymbol' => 'H', 'XYZ' => [0, 0, 0]); + $Molecule->NewBond('Atoms' => [$This, $Hydrogen], 'BondOrder' => 1); + } + + return $HydrogensAdded; +} + +# Delete hydrogens attached to atom in molecule and return total number of hydrogens deleted... +sub DeleteHydrogens { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + + # Is it an element symbol? + if (!$This->{AtomicNumber}) { + return 0; + } + + my($Molecule, $Neighbor, $HydrogensDeleted, @Neighbors); + + $Molecule = $This->GetProperty('Molecule'); + $HydrogensDeleted = 0; + @Neighbors = $This->GetNeighbors(); + + NEIGHBOR: for $Neighbor (@Neighbors) { + if (!$Neighbor->IsHydrogen()) { + next NEIGHBOR; + } + $Molecule->_DeleteAtom($Neighbor); + $HydrogensDeleted++; + } + + return $HydrogensDeleted; +} + +# Copy atom and all its associated data... +sub Copy { + my($This) = @_; + my($Atom); + + $Atom = Storable::dclone($This); + + return $Atom; +} + +# Get atomic invariant value... +# +sub GetAtomicInvariantValue { + my($This, $AtomicInvariant) = @_; + my($Value); + + $Value = ""; + + ATOMICVARIANT: { + if ($AtomicInvariant =~ /^(AS|AtomSymbol|ElementSymbol)$/i) { + $Value = $This->GetAtomSymbol(); + last ATOMICVARIANT; + } + if ($AtomicInvariant =~ /^(X|NumOfNonHydrogenAtomNeighbors|NumOfHeavyAtomNeighbors)$/i) { + $Value = $This->GetNumOfNonHydrogenAtomNeighbors(); + last ATOMICVARIANT; + } + if ($AtomicInvariant =~ /^(BO|SumOfBondOrdersToNonHydrogenAtoms|SumOfBondOrdersToHeavyAtoms)$/i) { + $Value = $This->GetSumOfBondOrdersToNonHydrogenAtoms(); + last ATOMICVARIANT; + } + if ($AtomicInvariant =~ /^(LBO|LargestBondOrderToNonHydrogenAtoms|LargestBondOrderToHeavyAtoms)$/i) { + $Value = $This->GetLargestBondOrderToNonHydrogenAtoms(); + last ATOMICVARIANT; + } + if ($AtomicInvariant =~ /^(H|NumOfImplicitAndExplicitHydrogens)$/i) { + $Value = $This->GetNumOfHydrogens(); + last ATOMICVARIANT; + } + if ($AtomicInvariant =~ /^(SB|NumOfSingleBondsToNonHydrogenAtoms|NumOfSingleBondsToHeavyAtoms)$/i) { + $Value = $This->GetNumOfSingleBondsToNonHydrogenAtoms(); + last ATOMICVARIANT; + } + if ($AtomicInvariant =~ /^(DB|NumOfDoubleBondsToNonHydrogenAtoms|NumOfDoubleBondsToHeavyAtoms)$/i) { + $Value = $This->GetNumOfDoubleBondsToNonHydrogenAtoms(); + last ATOMICVARIANT; + } + if ($AtomicInvariant =~ /^(TB|NumOfTripleBondsToNonHydrogenAtoms|NumOfTripleBondsToHeavyAtoms)$/i) { + $Value = $This->GetNumOfTripleBondsToNonHydrogenAtoms(); + last ATOMICVARIANT; + } + if ($AtomicInvariant =~ /^(AB|NumOfAromaticBondsToNonHydrogenAtoms|NumOfAromaticBondsToHeavyAtoms)$/i) { + $Value = $This->GetNumOfAromaticBondsToNonHydrogenAtoms(); + last ATOMICVARIANT; + } + if ($AtomicInvariant =~ /^(FC|FormalCharge)$/i) { + $Value = $This->GetFormalCharge(); + $Value = defined $Value ? $Value : 0; + last ATOMICVARIANT; + } + if ($AtomicInvariant =~ /^(T|TotalNumOfAtomNeighbors)$/i) { + $Value = $This->GetNumOfNonHydrogenAtomNeighbors() + $This->GetNumOfHydrogens(); + last ATOMICVARIANT; + } + if ($AtomicInvariant =~ /^(TSB|TotalNumOfSingleBonds)$/i) { + $Value = $This->GetNumOfSingleBondsToNonHydrogenAtoms() + $This->GetNumOfHydrogens(); + last ATOMICVARIANT; + } + if ($AtomicInvariant =~ /^(Ar|Aromatic)$/i) { + $Value = $This->IsAromatic() ? 1 : 0; + last ATOMICVARIANT; + } + if ($AtomicInvariant =~ /^(RA|RingAtom)$/i) { + $Value = $This->IsInRing() ? 1 : 0; + last ATOMICVARIANT; + } + if ($AtomicInvariant =~ /^(Str|Stereochemistry)$/i) { + $Value = $This->GetStereochemistry(); + $Value= (defined($Value) && ($Value =~ /^(R|S)$/i)) ? $Value : ''; + last ATOMICVARIANT; + } + if ($AtomicInvariant =~ /^(AN|AtomicNumber)$/i) { + $Value = $This->GetAtomicNumber(); + last ATOMICVARIANT; + } + if ($AtomicInvariant =~ /^(AM|AtomicMass)$/i) { + $Value = round($This->GetExactMass(), 4) + 0; + last ATOMICVARIANT; + } + if ($AtomicInvariant =~ /^(MN|MassNumber)$/i) { + $Value = $This->GetMassNumber(); + last ATOMICVARIANT; + } + if ($AtomicInvariant =~ /^(SM|SpinMultiplicity)$/i) { + $Value = $This->GetSpinMultiplicity(); + $Value = defined $Value ? $Value : ''; + last ATOMICVARIANT; + } + $Value = ""; + carp "Warning: ${ClassName}->GetAtomicInvariantValue: Unknown atomic invariant $AtomicInvariant..."; + } + + return $Value; +} + +# Get period number of the atom.. +# +sub GetPeriodNumber { + my($This) = @_; + + # Is PeriodNumber property explicitly set? + if ($This->HasProperty('PeriodNumber')) { + return $This->GetProperty('PeriodNumber'); + } + my($AtomicNumber, $PeriodNumber); + + $AtomicNumber = $This->{AtomicNumber}; + if (!$AtomicNumber) { + return 0; + } + + $PeriodNumber = PeriodicTable::GetElementPeriodNumber($AtomicNumber); + + return $PeriodNumber; +} + +# Get group number of the atom.. +# +sub GetGroupNumber { + my($This) = @_; + + # Is GroupNumber property explicitly set? + if ($This->HasProperty('GroupNumber')) { + return $This->GetProperty('GroupNumber'); + } + my($AtomicNumber, $GroupNumber); + + $AtomicNumber = $This->{AtomicNumber}; + if (!$AtomicNumber) { + return 0; + } + + $GroupNumber = PeriodicTable::GetElementGroupNumber($AtomicNumber); + + return $GroupNumber; +} + +# Is it a specified topological pharmacophore atom type? +# +sub IsTopologicalPharmacophoreType { + my($This, $Type) = @_; + + return $This->_IsFunctionalClassType($Type); +} + +# Is it a specified functional class atom type? +# +sub IsFunctionalClassType { + my($This, $Type) = @_; + + return $This->_IsFunctionalClassType($Type); +} + +# Is it a specified functional/topological pharmacophore atom type? +# +sub _IsFunctionalClassType { + my($This, $Type) = @_; + my($Value); + + $Value = 0; + + TYPE: { + if ($Type =~ /^(HBD|HydrogenBondDonor)$/i) { + $Value = $This->IsHydrogenBondDonor(); + last TYPE; + } + if ($Type =~ /^(HBA|HydrogenBondAcceptor)$/i) { + $Value = $This->IsHydrogenBondAcceptor(); + last TYPE; + } + if ($Type =~ /^(PI|PositivelyIonizable)$/i) { + $Value = $This->IsPositivelyIonizable(); + last TYPE; + } + if ($Type =~ /^(NI|NegativelyIonizable)$/i) { + $Value = $This->IsNegativelyIonizable(); + last TYPE; + } + if ($Type =~ /^(H|Hydrophobic)$/i) { + $Value = $This->IsHydrophobic(); + last TYPE; + } + if ($Type =~ /^(Ar|Aromatic)$/i) { + $Value = $This->IsAromatic(); + last TYPE; + } + if ($Type =~ /^(Hal|Halogen)$/i) { + $Value = $This->IsHalogen(); + last TYPE; + } + if ($Type =~ /^(RA|RingAtom)$/i) { + $Value = $This->IsInRing(); + last TYPE; + } + if ($Type =~ /^(CA|ChainAtom)$/i) { + $Value = $This->IsNotInRing(); + last TYPE; + } + $Value = 0; + carp "Warning: ${ClassName}->_IsType: Unknown functional/pharmacohore type $Type..."; + } + return $Value; +} + +# Is it a Hydrogen atom? +sub IsHydrogen { + my($This) = @_; + + return ($This->{AtomicNumber} == 1) ? 1 : 0; +} + +# Is it a Carbon atom? +sub IsCarbon { + my($This) = @_; + + return ($This->{AtomicNumber} == 6) ? 1 : 0; +} + +# Is it a Nitrogen atom? +sub IsNitrogen { + my($This) = @_; + + return ($This->{AtomicNumber} == 7) ? 1 : 0; +} + +# Is it a Oxygen atom? +sub IsOxygen { + my($This) = @_; + + return ($This->{AtomicNumber} == 8) ? 1 : 0; +} + +# Is it a Fluorine atom? +sub IsFluorine { + my($This) = @_; + + return ($This->{AtomicNumber} == 9) ? 1 : 0; +} + +# Is it a Silicon atom? +sub IsSilicon { + my($This) = @_; + + return ($This->{AtomicNumber} == 14) ? 1 : 0; +} + +# Is it a Phosphorus atom? +sub IsPhosphorus { + my($This) = @_; + + return ($This->{AtomicNumber} == 15) ? 1 : 0; +} + +# Is it a Sulphur atom? +sub IsSulphur { + my($This) = @_; + + return $This->IsSulfur(); +} + +# Is it a Sulfur atom? +sub IsSulfur { + my($This) = @_; + + return ($This->{AtomicNumber} == 16) ? 1 : 0; +} + +# Is it a Chlorine atom? +sub IsChlorine { + my($This) = @_; + + return ($This->{AtomicNumber} == 17) ? 1 : 0; +} + +# Is it a Arsenic atom? +sub IsArsenic { + my($This) = @_; + + return ($This->{AtomicNumber} == 33) ? 1 : 0; +} + +# Is it a Selenium atom? +sub IsSelenium { + my($This) = @_; + + return ($This->{AtomicNumber} == 34) ? 1 : 0; +} + +# Is it a Bromine atom? +sub IsBromine { + my($This) = @_; + + return ($This->{AtomicNumber} == 35) ? 1 : 0; +} + +# Is it a Tellurium atom? +sub IsTellurium { + my($This) = @_; + + return ($This->{AtomicNumber} == 52) ? 1 : 0; +} + +# Is it a Iodine atom? +sub IsIodine { + my($This) = @_; + + return ($This->{AtomicNumber} == 53) ? 1 : 0; +} + +# Is it a hetro atom? (N, O, F, P, S, Cl, Br, I) +sub IsHeteroAtom { + my($This) = @_; + + return ($This->{AtomicNumber} =~ /^(7|8|9|15|16|17|35|53)$/) ? 1 : 0; +} + +# Is it a halogen atom? (F, Cl, Br, I) +sub IsHalogen { + my($This) = @_; + + return ($This->{AtomicNumber} =~ /^(9|17|35|53)$/) ? 1 : 0; +} + +# Is it classified as metallic? +sub IsMetallic { + my($This) = @_; + my($Classification); + + $Classification = PeriodicTable::GetElementClassification($This->{AtomicNumber}); + + return ($Classification =~ /^Metallic$/i) ? 1 : 0; +} + +# Is it a non carbon or hydrogen atom? (C, H) +sub IsNonCarbonOrHydrogen { + my($This) = @_; + + return ($This->{AtomicNumber} =~ /^(1|6)$/) ? 0 : 1; +} + +# Is it a polar atom? ( N, O, P, S) +sub IsPolarAtom { + my($This) = @_; + + return ($This->{AtomicNumber} =~ /^(7|8|15|16)$/) ? 1 : 0; +} + +# Is it an isotope? +sub IsIsotope { + my($This) = @_; + + my($AtomicNumber) = $This->{AtomicNumber}; + if (!$AtomicNumber) { + return 0; + } + + if (!$This->HasProperty('MassNumber')) { + return 0; + } + my($MassNumber, $MostAbundantMassNumber); + + $MassNumber = $This->GetProperty('MassNumber'); + $MostAbundantMassNumber = PeriodicTable::GetElementMostAbundantNaturalIsotopeMassNumber($AtomicNumber); + + return ($MassNumber == $MostAbundantMassNumber) ? 0 : 1; +} + +# Is it a terminal atom? +sub IsTerminal { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + + return ($This->GetNumOfNonHydrogenAtomNeighbors() <= 1) ? 1 : 0 + +} + +# Is aromatic property set for the atom? +sub IsAromatic { + my($This) = @_; + my($Aromatic); + + $Aromatic = $This->GetAromatic(); + + return (defined($Aromatic) && $Aromatic) ? 1 : 0; +} + +# Is this a hydrogen atom and attached to one of these atoms: N, O, P, S +sub IsPolarHydrogen { + my($This) = @_; + + if (!$This->IsHydrogen()) { + return 0; + } + + my(@Bonds); + @Bonds = $This->GetBonds(); + if (@Bonds > 1) { + return 0; + } + + my($Bond, $BondedAtom); + ($Bond) = @Bonds; + $BondedAtom = $Bond->GetBondedAtom($This); + + return $BondedAtom->IsPolarAtom() ? 1 : 0; +} + +# Is it a hydrogen bond donor atom? +# +sub IsHBondDonor { + my($This, $HydrogenBondsType) = @_; + + return $This->IsHydrogenBondDonor($HydrogenBondsType); +} + +# The currrent release of MayaChemTools supports identification of two types of +# hydrogen bond donor and acceptor atoms with these names: +# +# HBondsType1 or HydrogenBondsType1 +# HBondsType2 or HydrogenBondsType2 +# +# The names of these hydrogen bond types are rather arbitrary. However, their +# definitions have specific meaning and are as follows: +# +# HydrogenBondsType1 [ Ref 60-61, Ref 65-66 ]: +# . Donor: NH, NH2, NH3, OH - Any N and O with available H +# . Acceptor: N[!H], O - Any N without available H and any O +# +# HydrogenBondsType2 [ Ref 91 ]: +# . Donor: NH, NH2, NH3, OH - Any N and O with availabe H +# . Acceptor: N, O - Any N and O +# +# Note: +# . HydrogenBondsType2 definition corresponds to Rule of 5. +# + +# Is it a hydrogen bond donor atom? +# +# The currrent release of MayaChemTools supports identification of two types of +sub IsHydrogenBondDonor { + my($This, $HydrogenBondsType) = @_; + my($Status); + + $HydrogenBondsType = defined $HydrogenBondsType ? $HydrogenBondsType : 'HBondsType1'; + $Status = 0; + + HYDROGENBONDSTYPE: { + + if ($HydrogenBondsType =~ /^(HBondsType1|HydrogenBondsType1)$/i) { + $Status = $This->_IsHydrogenBondDonorOfType1(); + last HYDROGENBONDSTYPE; + } + + if ($HydrogenBondsType =~ /^(HBondsType2|HydrogenBondsType2)$/i) { + $Status = $This->_IsHydrogenBondDonorOfType2(); + last HYDROGENBONDSTYPE; + } + + $Status = 0; + carp "Warning: ${ClassName}->IsHydrogenBondDonor: The current release of MayaChemTools doesn't support specified value, $HydrogenBondsType, for HydrogenBondsType. Valid values: HBondsType1, HydrogenBondsType1, HBondsType2 HydrogenBondsType2 ..."; + } + + return $Status; +} + +# Is it a MayaChemTools HBondType1 hydrogen bond donor atom? +# +sub _IsHydrogenBondDonorOfType1 { + my($This) = @_; + + return $This->_IsHydrogenBondDonorOfType1OrType2(); +} + +# Is it a MayaChemTools HBondType2 hydrogen bond donor atom? +# +sub _IsHydrogenBondDonorOfType2 { + my($This) = @_; + + return $This->_IsHydrogenBondDonorOfType1OrType2(); +} + +# Is it a hydrogen bond donor atom of MayaChemTools Type1 or Type2? +# +# HydrogenBondDonor definition [ Ref 60-61, Ref 65-66, Ref 91 ]: NH, NH2, OH +# +# In other words: +# . NH, NH2 - Nitrogen atom with available hydrogen +# . OH - Oxygen atom with avilable hydrogen +# +sub _IsHydrogenBondDonorOfType1OrType2 { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return 0; + } + + # Is it N or O? + if ($This->{AtomicNumber} !~ /^(7|8)$/) { + return 0; + } + + # Any explicitly attached hydrogens? + if ($This->GetExplicitHydrogens()) { + return 1; + } + + # Any missing hydrogens? + return $This->GetNumOfMissingHydrogens() ? 1 : 0; +} + +# Is it a hydrogen bond acceptor atom? +# +sub IsHBondAcceptor { + my($This, $HydrogenBondsType) = @_; + + return $This->IsHydrogenBondAcceptor($HydrogenBondsType); +} + +# Is it a hydrogen bond acceptor atom? +# +sub IsHydrogenBondAcceptor { + my($This, $HydrogenBondsType) = @_; + my($Status); + + $HydrogenBondsType = defined $HydrogenBondsType ? $HydrogenBondsType : 'HBondsType1'; + $Status = 0; + + HYDROGENBONDSTYPE: { + + if ($HydrogenBondsType =~ /^(HBondsType1|HydrogenBondsType1)$/i) { + $Status = $This->_IsHydrogenBondAcceptorOfType1(); + last HYDROGENBONDSTYPE; + } + + if ($HydrogenBondsType =~ /^(HBondsType2|HydrogenBondsType2)$/i) { + $Status = $This->_IsHydrogenBondAcceptorOfType2(); + last HYDROGENBONDSTYPE; + } + + $Status = 0; + carp "Warning: ${ClassName}->IsHydrogenBondAcceptor: The current release of MayaChemTools doesn't support specified value, $HydrogenBondsType, for HydrogenBondsType. Valid values: HBondsType1, HydrogenBondsType1, HBondsType2 HydrogenBondsType2 ..."; + } + + return $Status; +} + +# Is it a MayaChemTools HBondType1 hydrogen bond acceptor atom? +# +# HydrogenBondAcceptor definition [ Ref 60-61, Ref 65-66 ]: N[!H], O +# +# In other words: +# . N[!H] - Nitrogen atom with no hydrogen +# . O - Oxygen atom +# +sub _IsHydrogenBondAcceptorOfType1 { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return 0; + } + + # Is it N or O? + if ($This->{AtomicNumber} !~ /^(7|8)$/) { + return 0; + } + + # Is it O? + if ($This->{AtomicNumber} == 8 ) { + return 1; + } + + # Any explicitly attached hydrogens? + if ($This->GetExplicitHydrogens()) { + return 0; + } + + # Any missing hydrogens? + return $This->GetNumOfMissingHydrogens() ? 0 : 1; +} + +# Is it a MayaChemTools HBondType2 hydrogen bond acceptor atom? +# +# HydrogenBondAcceptor definition [ Ref 91 ]: N, O +# +# In other words: +# . Any Nitrogen or Oxygen atom +# +# Note: +# . HydrogenBondsType2 definition corresponds to Rule of 5. +# +sub _IsHydrogenBondAcceptorOfType2 { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return 0; + } + + return ($This->{AtomicNumber} =~ /^(7|8)$/) ? 1 : 0; +} + +# Is it a positively ionizable atom? +# +# PositivelyIonizable defintion [ Ref 60-61, Ref 65-66 ]: +, NH2 +# +# In other words: +# . Any atom with positve formal charge +# . NH2 - Nitogen atom in amino group +# +sub IsPositivelyIonizable { + my($This) = @_; + my($FormalCharge); + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return 0; + } + + # Any explicit positive formal charge? + $FormalCharge = $This->GetFormalCharge(); + if (defined($FormalCharge) && $FormalCharge > 0) { + return 1; + } + + # Is it N? + if ($This->{AtomicNumber} != 7 ) { + return 0; + } + + return ($This->GetNumOfHydrogens() == 2) ? 1 : 0; +} + +# Is it a negatively ionizable atom? +# +# NegativelyIonizable definition [ Ref 60-61, Ref 65-66 ]: -, C(=O)OH, S(=O)OH, P(=O)OH +# +# In other words: +# . Any atom with negative formal charge +# . Carbon atom in C(=O)OH group +# . Phosphorous in P(=O)OH group +# . Sulfur atom in S(=O)OH group +# +sub IsNegativelyIonizable { + my($This) = @_; + my($FormalCharge); + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return 0; + } + + # Any explicit negative formal charge? + $FormalCharge = $This->GetFormalCharge(); + if (defined($FormalCharge) && $FormalCharge < 0) { + return 1; + } + + # Is it C, P or S? + if ($This->{AtomicNumber} !~ /^(6|15|16)$/ ) { + return 0; + } + + # Collect oxygens connected to C, P or S with single or double bonds and not connected to + # any other heavy atom... + my($Neighbor, $NeighborOxygenBondOrder, $NumOfNeighborOxygensWithSingleBonds, $NumOfNeighborOxygensWithDoubleBonds); + + $NumOfNeighborOxygensWithSingleBonds = 0; $NumOfNeighborOxygensWithDoubleBonds = 0; + + NEIGHBOR: for $Neighbor ($This->GetNeighbors()) { + # Is it an oxygen? + if ($Neighbor->{AtomicNumber} != 8) { + next NEIGHBOR; + } + # Is oxygent connected to only heavy atom? + if ($Neighbor->GetNumOfHeavyAtomNeighbors() != 1) { + next NEIGHBOR; + } + $NeighborOxygenBondOrder = $This->GetBondToAtom($Neighbor)->GetBondOrder(); + + if ($NeighborOxygenBondOrder == 2) { + $NumOfNeighborOxygensWithDoubleBonds++; + } + elsif ($NeighborOxygenBondOrder == 1) { + $NumOfNeighborOxygensWithSingleBonds++; + } + } + return ($NumOfNeighborOxygensWithDoubleBonds >= 1 && $NumOfNeighborOxygensWithSingleBonds >= 1) ? 1 : 0; +} + +# Is it a liphophilic atom? +# +# Lipophilic definition [ Ref 60-61, Ref 65-66 ]: C(C)(C)(C)(C), Cl, Br, I, S(C)(C) +# +# In other words: +# . C(C)(C)(C)(C) - Carbon atom connected to only other carbons +# . Chlorine, Bromine or Iodine atom +# . S(C)(C) - Sulfur connected to two carbons +# +sub IsLipophilic { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return 0; + } + + # Is it Cl, Br, I? + if ($This->{AtomicNumber} =~ /^(17|35|53)$/) { + return 1; + } + + # Is it C, S? + if ($This->{AtomicNumber} !~ /^(6|16)$/) { + return 0; + } + + # Are all heavy atom neighbors Carbons? + my($HeavyAtomNeighbor, @HeavyAtomNeighbors); + @HeavyAtomNeighbors = (); + @HeavyAtomNeighbors = $This->GetHeavyAtomNeighbors(); + + for $HeavyAtomNeighbor (@HeavyAtomNeighbors) { + if ($HeavyAtomNeighbor->{AtomicNumber} != 6) { + return 0; + } + } + + # Does sulfur has two carbon neighbors? + if ($This->{AtomicNumber} == 16) { + if (@HeavyAtomNeighbors != 2) { + return 0; + } + } + return 1; +} + +# Is it hydrophobic? +# +sub IsHydrophobic { + my($This) = @_; + + return $This->IsLipophilic(); +} + +# Is it a Nitrogen atom in Guadinium group? +# +sub IsGuadiniumNitrogen { + my($This) = @_; + + # Is it Nitrogen? + if (!$This->IsNitrogen()) { + return 0; + } + + # Is it connected to a Guadinium Carbon? + my($AtomNeighbor); + + for $AtomNeighbor ($This->GetNonHydrogenAtomNeighbors()) { + if ($AtomNeighbor->IsGuadiniumCarbon()) { + return 1; + } + } + + return 0; +} + +# Is it a Carbon atom in Guadinium group? +# +# Guadinium group definition: +# +# R2N-C(=NR)-(NR2) or R2N-C(=NR2+)-(NR2) +# +# where: +# . R = Hydrogens or group of atoms attached through Carbon +# . Only one of the three Nitrogens has a double bond to Carbon and has optional +# formal charge allowing it to be neutral or charged state +# +sub IsGuadiniumCarbon { + my($This) = @_; + + # Is it Carbon? + if (!$This->IsCarbon()) { + return 0; + } + + # Match atom neighborhood... + my($CentralAtomSpec, @NbrAtomSpecsRef, @NbrBondSpecsRef, @NbrOfNbrAtomSpecsRef); + + $CentralAtomSpec = 'C.X3.BO4'; + @NbrAtomSpecsRef = ('N.FC0', 'N.FC0', 'N.FC0,N.FC+1'); + @NbrBondSpecsRef = ('-', '-', '='); + @NbrOfNbrAtomSpecsRef = ('C,H', 'C,H', 'C,H'); + + if ($This->DoesAtomNeighborhoodMatch($CentralAtomSpec, \@NbrAtomSpecsRef, \@NbrBondSpecsRef, \@NbrOfNbrAtomSpecsRef)) { + return 1; + } + + return 0; +} + +# Is it a Nitrogen atom in Amide group? +# +sub IsAmideNitrogen { + my($This) = @_; + + # Is it Nitrogen? + if (!$This->IsNitrogen()) { + return 0; + } + + # Is it connected to a Amide Carbon? + my($AtomNeighbor); + + for $AtomNeighbor ($This->GetNonHydrogenAtomNeighbors()) { + if ($AtomNeighbor->IsAmideCarbon()) { + return 1; + } + } + + return 0; +} + +# Is it a Carbon atom in Amide group? +# +# Amide group definition: R-C(=O)-N(-R')-R'' +# +# where: +# . R = Hydrogen or groups of atoms attached through Carbon +# . R' = Hydrogens or groups of atoms attached through Carbon or hetro atoms +# . R'' = Hydrogens or groups of atoms attached through Carbon or hetro atoms +# +sub IsAmideCarbon { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return 0; + } + + # Is it Carbon? + if (!$This->IsCarbon()) { + return 0; + } + + # Match atom neighborhood... + my($CentralAtomSpec, @NbrAtomSpecsRef, @NbrBondSpecsRef, @NbrOfNbrAtomSpecsRef); + + $CentralAtomSpec = 'C.X3.BO4,C.X2.BO3'; + @NbrAtomSpecsRef = ('C,H', 'O', 'N'); + @NbrBondSpecsRef = ('-', '=', '-'); + @NbrOfNbrAtomSpecsRef = ('C,H', 'C', 'C,H,N,O,S,P,F,Cl,Br,I'); + + if ($This->DoesAtomNeighborhoodMatch($CentralAtomSpec, \@NbrAtomSpecsRef, \@NbrBondSpecsRef, \@NbrOfNbrAtomSpecsRef)) { + return 1; + } + + return 0; +} + +# Is it a Oxygen atom in Carboxylate group? +# +sub IsCarboxylateOxygen { + my($This) = @_; + + return $This->_MatchCarboxylateAndOrCarboxylOxygen('Carboxylate'); +} + +# Is it a Carbon atom in Carboxylate group? +# +# Carboxyl group definition: R-C(=O)-O- +# +sub IsCarboxylateCarbon { + my($This) = @_; + + return $This->_MatchCarboxylateAndOrCarboxylCarbon('Carboxylate'); +} + +# Is it a Oxygen atom in Carboxyl group? +# +sub IsCarboxylOxygen { + my($This) = @_; + + return $This->_MatchCarboxylateAndOrCarboxylOxygen('Carboxyl'); +} + +# Is it a Carbon atom in Carboxyl group? +# +# Carboxyl group definition: R-C(=O)-OH +# +sub IsCarboxylCarbon { + my($This) = @_; + + return $This->_MatchCarboxylateAndOrCarboxylCarbon('Carboxyl'); +} + +# Match Carboxylate and/or Carboxyl oxygen... +# +sub _MatchCarboxylateAndOrCarboxylOxygen { + my($This, $Mode) = @_; + + # Is it Oxygen? + if (!$This->IsOxygen()) { + return 0; + } + + # Is it connected to a Carboxylate Carbon? + my($AtomNeighbor); + + for $AtomNeighbor ($This->GetNonHydrogenAtomNeighbors()) { + if ($AtomNeighbor->_MatchCarboxylateAndOrCarboxylCarbon($Mode)) { + return 1; + } + } + + return 0; +} + +# Match Carboxylate and Carboxyl Carbon +# +# Carboxylate group definition: R-C(=O)-O- +# Carboxyl group definition: R-C(=O)-OH +# +# where: +# . R = Hydrogens or groups of atoms attached through Carbon +# +sub _MatchCarboxylateAndOrCarboxylCarbon { + my($This, $Mode) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return 0; + } + + # Is it Carbon? + if (!$This->IsCarbon()) { + return 0; + } + + # Match atom neighborhood... + my($CentralAtomSpec, @NbrAtomSpecsRef, @NbrBondSpecsRef, @NbrOfNbrAtomSpecsRef); + + $CentralAtomSpec = 'C.X3.BO4,C.X2.BO3'; + MODE: { + if ($Mode =~ /^Carboxylate$/i) { + @NbrAtomSpecsRef = ('C,H', 'O', 'O.X1.FC-1'); + last MODE; + } + if ($Mode =~ /^Carboxyl$/i) { + @NbrAtomSpecsRef = ('C,H', 'O', 'O.X1.FC0'); + last MODE; + } + if ($Mode =~ /^CarboxylateOrCarboxyl$/i) { + @NbrAtomSpecsRef = ('C,H', 'O', 'O.X1.FC-1,O.X1.FC0'); + last MODE; + } + carp "Warning: ${ClassName}->_MatchCarboxylateAndCarboxylCarbon.: Unknown mode $Mode..."; + return 0; + } + @NbrBondSpecsRef = ('-', '=', '-'); + @NbrOfNbrAtomSpecsRef = ('C,H', 'C', 'C'); + + if ($This->DoesAtomNeighborhoodMatch($CentralAtomSpec, \@NbrAtomSpecsRef, \@NbrBondSpecsRef, \@NbrOfNbrAtomSpecsRef)) { + return 1; + } + + return 0; +} + +# Is it a Oxygen atom in Phosphate group? +# +sub IsPhosphateOxygen { + my($This) = @_; + + # Is it Oxygen? + if (!$This->IsOxygen()) { + return 0; + } + + # Is it connected to a Phosphate Phosphorus? + my($AtomNeighbor); + + for $AtomNeighbor ($This->GetNonHydrogenAtomNeighbors()) { + if ($AtomNeighbor->IsPhosphatePhosphorus()) { + return 1; + } + } + + return 0; +} + +# Is it a Phosphorus atom in Phosphate group? +# +# Phosphate group definition: AO-(O=)P(-OA)-OA +# +# where: +# . A = Any Groups of atoms including hydrogens +# +sub IsPhosphatePhosphorus { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return 0; + } + + # Is it Phosphorus? + if (!$This->IsPhosphorus()) { + return 0; + } + + # Match atom neighborhood... + my($CentralAtomSpec, @NbrAtomSpecsRef, @NbrBondSpecsRef, @NbrOfNbrAtomSpecsRef); + + $CentralAtomSpec = 'P.X4.BO5'; + @NbrAtomSpecsRef = ('O', 'O', 'O', 'O'); + @NbrBondSpecsRef = ('-', '=', '-', '-'); + @NbrOfNbrAtomSpecsRef = (undef, undef, undef, undef); + + if ($This->DoesAtomNeighborhoodMatch($CentralAtomSpec, \@NbrAtomSpecsRef, \@NbrBondSpecsRef, \@NbrOfNbrAtomSpecsRef)) { + return 1; + } + + return 0; +} + + +# Match central atom and its neighborhood using specified atom and bonds specifications... +# +# Let: +# AS = Atom symbol corresponding to element symbol, atomic number (#n) or any +# atom (A) +# +# X<n> = Number of non-hydrogen atom neighbors or heavy atoms attached to atom +# T<n> = Total number of atom neighbors including implcit and explicit hydrogens +# BO<n> = Sum of bond orders to non-hydrogen atom neighbors or heavy atoms attached to atom +# LBO<n> = Largest bond order of non-hydrogen atom neighbors or heavy atoms attached to atom +# SB<n> = Number of single bonds to non-hydrogen atom neighbors or heavy atoms attached to atom +# TSB<n> = Total number of single bonds to atom neighbors including implcit and explicit hydrogens +# DB<n> = Number of double bonds to non-hydrogen atom neighbors or heavy atoms attached to atom +# TB<n> = Number of triple bonds to non-hydrogen atom neighbors or heavy atoms attached to atom +# H<n> = Number of implicit and explicit hydrogens for atom +# Ar = Aromatic annotation indicating whether atom is aromatic +# RA or RA<n> = Ring atom annotation indicating whether atom is a ring +# TR<n> = Total number of rings containing atom +# FC<+n/-n> = Formal charge assigned to atom +# MN<n> = Mass number indicating isotope other than most abundant isotope +# SM<n> = Spin multiplicity of atom. Possible values: 1 (singlet), 2 (doublet) or 3 (triplet) +# +# Then: +# +# Atom specification corresponds to: +# +# AS.X<n>.T<n>.BO<n>.LBO<n>.<SB><n>.TSB<n>.<DB><n>.<TB><n>.H<n>.Ar.RA<n>.TR<n>FC<+n/-n>.MN<n>.SM<n> +# +# Except for AS which is a required atomic invariant in atom specification, all other atomic invariants are +# optional. For an atom specification to match an atom, the values of all specified atomic invariants must +# match. Exclamation in from of atomic invariant can be used to negate its effect during the match. +# +# A comma delimited atom specification string is used to match any one of the specifed atom specification. +# +# Notes: +# . During atom specification match to an atom, the first atomic invariant is always assumed to +# atom symbol. +# . Atom match specfication is based on AtomicInvariantAtomTypes implemented in +# AotmTypes::AtomicInvariantAtomType.pm module +# +# Examples: +# . ('N', 'N', 'N') +# . ('N.FC0', 'N.FC0', 'N,N.FC+1.H1') +# . ('N.H2', 'N.H2', 'N.H1') +# . ('C,N', '!N', '!H') +# . ('C,N', 'N.Ar', 'N.R5') +# +# Let: +# -|1|s|Single = Single bond +# =|2|d|Double = Double bond +# #|3|t|Triple = Triple bond +# :|1.5|a|Ar|Aromatic = Aromatic bond +# +# @|RB|Ring = Ring bond +# ~|*|Any = Any bond +# +# Then: +# +# Bond specification corresponds to: +# +# -.: +# =.@ +# Double.Aromatic +# +# For a bond specification to match bond between two atoms, the values of all specified bond symbols must +# match. Exclamation in from of bond symbol can be used to negate its effect during the match. +# +# A comma delimited bond specification string is used to match any one of the specifed atom specification. +# +sub DoesAtomNeighborhoodMatch { + my($CentralAtom, $CentralAtomSpec, $NbrAtomSpecsRef, $NbrBondSpecsRef, $NbrOfNbrAtomSpecsRef) = @_; + my($NumOfNbrAtomSpecs, $NumOfNbrBondSpecs, $NumOfNbrOfNbrAtomSpecs); + + # Is this atom in a molecule? + if (!$CentralAtom->HasProperty('Molecule')) { + return 0; + } + + $NumOfNbrAtomSpecs = defined $NbrAtomSpecsRef ? scalar @{$NbrAtomSpecsRef} : 0; + $NumOfNbrBondSpecs = defined $NbrBondSpecsRef ? scalar @{$NbrBondSpecsRef} : 0; + $NumOfNbrOfNbrAtomSpecs = defined $NbrOfNbrAtomSpecsRef ? scalar @{$NbrOfNbrAtomSpecsRef} : 0; + + # Validate number of specifications... + if ($NumOfNbrBondSpecs && ($NumOfNbrAtomSpecs != $NumOfNbrBondSpecs)) { + carp "Warning: ${ClassName}->DoesAtomNeighborhoodMatch: Number of specified central atom, $NumOfNbrAtomSpecs, and bond, $NumOfNbrBondSpecs, specifications must be same; No neighborhood match performed ..."; + return 0; + } + + if ($NumOfNbrOfNbrAtomSpecs && ($NumOfNbrOfNbrAtomSpecs != $NumOfNbrAtomSpecs)) { + carp "Warning: ${ClassName}->DoesAtomNeighborhoodMatch: Number of specified central atom, $NumOfNbrAtomSpecs, and neighbor of neighbor atoms specifications, $NumOfNbrOfNbrAtomSpecs, must be same; No neighborhood match performed ..."; + return 0; + } + + # Sort atom and bond specifications in terms of being most specific to least specific.. + ($NbrAtomSpecsRef, $NbrBondSpecsRef, $NbrOfNbrAtomSpecsRef) = $CentralAtom->_SortSpecificationsForAtomNeighborhoodMatch($NbrAtomSpecsRef, $NbrBondSpecsRef, $NbrOfNbrAtomSpecsRef); + + # Does central atom specification match? + if (!$CentralAtom->_DoesAtomSpecificationMatch($CentralAtomSpec)) { + return 0; + } + + # No neighbors to match... + if (!$NumOfNbrAtomSpecs) { + return 1; + } + + # Match neighbors... + my($NbrSpecsMatched, $NbrSpecCount, $NbrSpecMatchCount, %NbrSpecAlreadyMatchedMap); + + $NbrSpecCount = $NumOfNbrAtomSpecs; + $NbrSpecMatchCount = 0; + + %NbrSpecAlreadyMatchedMap = (); + ($NbrSpecsMatched, $NbrSpecMatchCount) = $CentralAtom->_MatchAtomNeighborhoodUsingAtomBondSpecs($NbrSpecCount, $NbrSpecMatchCount, \%NbrSpecAlreadyMatchedMap, $NbrAtomSpecsRef, $NbrBondSpecsRef, $NbrOfNbrAtomSpecsRef); + + if ($NbrSpecsMatched) { + # It's match... + return 1; + } + + # Match central atom's missing hydrogens with any unmatched atom + # and bond specifications... + # + ($NbrSpecsMatched, $NbrSpecMatchCount) = $CentralAtom->_MatchAtomNeighborhoodUsingMissingHydrogens($NbrSpecCount, $NbrSpecMatchCount, \%NbrSpecAlreadyMatchedMap, $NbrAtomSpecsRef, $NbrBondSpecsRef, $NbrOfNbrAtomSpecsRef); + + if ($NbrSpecsMatched) { + # It's match... + return 1; + } + + # No match... + return 0; +} + +# Match central atom neighborhood atom and bond specifications... +# +sub _MatchAtomNeighborhoodUsingAtomBondSpecs { + my($CentralAtom, $NbrSpecCount, $NbrSpecMatchCount, $NbrSpecAlreadyMatchedRef, $NbrAtomSpecsRef, $NbrBondSpecsRef, $NbrOfNbrAtomSpecsRef) = @_; + my($Index, $NbrAtom, $NbrAtomSpec, $NbrBondSpec, $NbrOfNbrAtom, $NbrOfNbrAtomSpec, $MatchNbrOfNbrAtomSpecs, $NbrSpecsMatched); + + $MatchNbrOfNbrAtomSpecs = (defined $NbrOfNbrAtomSpecsRef && scalar @{$NbrOfNbrAtomSpecsRef}) ? 1 : 0; + + $NbrSpecsMatched = 0; + + # Match central atom's immediate neighbors atom and bond specifications... + NBRATOM: for $NbrAtom ($CentralAtom->GetNeighbors()) { + NBRATOMSPEC: for $Index (0 .. ($NbrSpecCount - 1)) { + if (exists $NbrSpecAlreadyMatchedRef->{$Index}) { + next NBRATOMSPEC; + } + $NbrAtomSpec = $NbrAtomSpecsRef->[$Index]; + $NbrBondSpec = $NbrBondSpecsRef->[$Index]; + + $NbrOfNbrAtomSpec = $MatchNbrOfNbrAtomSpecs ? $NbrOfNbrAtomSpecsRef->[$Index] : undef; + + # Match neighbor atom specification... + if (!$NbrAtom->_DoesAtomSpecificationMatch($NbrAtomSpec)) { + next NBRATOMSPEC; + } + + # Match central atom to neighbor atom bond specification... + if (!$CentralAtom->_DoesBondSpecificationMatch($NbrAtom, $NbrBondSpec)) { + next NBRATOMSPEC; + } + + # Match any neighbor of neighbor atom specifications... + if (defined $NbrOfNbrAtomSpec) { + # Go over the neighbors of central atom skipping the central atom... + for $NbrOfNbrAtom ($NbrAtom->GetNeighbors($CentralAtom)) { + if (!$NbrOfNbrAtom->_DoesAtomSpecificationMatch($NbrOfNbrAtomSpec)) { + next NBRATOMSPEC; + } + } + } + + # It's a match for a neighbor atom specification... + $NbrSpecAlreadyMatchedRef->{$Index} = $Index; + $NbrSpecMatchCount++; + + if ($NbrSpecMatchCount == $NbrSpecCount) { + # It's match... + $NbrSpecsMatched = 1; + last NBRATOM; + } + # Match next neighbor atom... + next NBRATOM; + } + } + return ($NbrSpecsMatched, $NbrSpecMatchCount); +} + +# Match central atom's missing hydrogens with any unmatched atom and bond +# specifications... +# +sub _MatchAtomNeighborhoodUsingMissingHydrogens { + my($CentralAtom, $NbrSpecCount, $NbrSpecMatchCount, $NbrSpecAlreadyMatchedRef, $NbrAtomSpecsRef, $NbrBondSpecsRef, $NbrOfNbrAtomSpecsRef) = @_; + my($Index, $NbrAtom, $NbrAtomSpec, $NbrBondSpec, $NumOfMissingHydrogens, $MissingHydrogensIndex, $NbrSpecsMatched, $AtomSpecMatched, $AtomSpec, $AtomSymbol); + + $NbrSpecsMatched = 0; + + $NumOfMissingHydrogens = $CentralAtom->GetNumOfMissingHydrogens(); + if (($NbrSpecCount - $NbrSpecMatchCount) > $NumOfMissingHydrogens) { + # It won't match... + return ($NbrSpecsMatched, $NbrSpecMatchCount); + } + + MISSINGHYDROGENNBR: for $MissingHydrogensIndex (0 .. ($NumOfMissingHydrogens - 1)) { + NBRATOMSPEC: for $Index (0 .. ($NbrSpecCount - 1)) { + if (exists $NbrSpecAlreadyMatchedRef->{$Index}) { + next NBRATOMSPEC; + } + $NbrAtomSpec = $NbrAtomSpecsRef->[$Index]; + $NbrBondSpec = $NbrBondSpecsRef->[$Index]; + + $NbrAtomSpec =~ s/ //g; + + # Match neighbor atom specification hydrogen atom symbol... + $AtomSpecMatched = 0; + ATOMSPEC: for $AtomSpec (split /\,/, $NbrAtomSpec) { + ($AtomSymbol) = split /\./, $AtomSpec; + if ($AtomSymbol =~ /^(H|A|\*)$/i) { + $AtomSpecMatched = 1; + last ATOMSPEC; + } + } + if (!$AtomSpecMatched) { + next NBRATOMSPEC; + } + + # Match neighbor atom bond specification to singal bond... + if (defined $NbrBondSpec) { + $NbrBondSpec =~ s/ //g; + if ($NbrBondSpec !~ /^(-|1|s|Single|\~|\*|Any)/i) { + next NBRATOMSPEC; + } + } + + # It's a match for a neighbor atom specification... + $NbrSpecAlreadyMatchedRef->{$Index} = $Index; + $NbrSpecMatchCount++; + + if ($NbrSpecMatchCount == $NbrSpecCount) { + # It's match... + $NbrSpecsMatched = 1; + last MISSINGHYDROGENNBR; + } + # Match next missing hydrogen neighbor... + next MISSINGHYDROGENNBR; + } + } + + return ($NbrSpecsMatched, $NbrSpecMatchCount); +} + +# Sort atom and bond specifications base on neighbor atom specifications going +# from most to least specific atom specifications. +# +# Atom specifications are sorted at the following two levels: +# +# o By atom specification count with in each specification going from most specific +# to least specific, where count is determined by the number of "," in each +# specification. Wild card containing specifications are considered least specific +# and end up at the end of the sorted list. +# o By atomic invariant count with in each sorted list going from most specific to +# least specific, where count is determined by the number of "." in each atom +# specification. +# +#A single atom specification, +# without any commas in atom specification, is is considered most specific... +# +sub _SortSpecificationsForAtomNeighborhoodMatch { + my($This, $NbrAtomSpecsRef, $NbrBondSpecsRef, $NbrOfNbrAtomSpecsRef) = @_; + my($Index, $NeedToSort, $NumOfNbrAtomSpecs, $NbrAtomSpecCount, $NbrAtomSpecAtomicInvarintCount, $NbrAtomSpecToMatch, $NbrAtomSpec, $FirstAtomicInvariant, $WildCardInNbrAtomSpec, @NbrAtomSpecs, @NbrAtomSpecAtomicInvariants, @SortedNbrAtomSpecs, @SortedNbrBondSpecs, @SortedNbrOfNbrAtomSpecs, %NbrAtomSpecDataMap); + + $NumOfNbrAtomSpecs = defined $NbrAtomSpecsRef ? scalar @{$NbrAtomSpecsRef} : 0; + + # Figure out whether sorting is necessary... + $NeedToSort = 0; + if ($NumOfNbrAtomSpecs > 1) { + ATOMSPEC: for $NbrAtomSpecToMatch (@{$NbrAtomSpecsRef}) { + if ($NbrAtomSpecToMatch =~ /(,|\.|A|\*)/i) { + $NeedToSort = 1; + last ATOMSPEC; + } + } + } + if (!$NeedToSort) { + # Nothing to do... + return ($NbrAtomSpecsRef, $NbrBondSpecsRef, $NbrOfNbrAtomSpecsRef); + } + + %NbrAtomSpecDataMap = (); + + for $Index (0 .. ($NumOfNbrAtomSpecs - 1)) { + $NbrAtomSpecToMatch = $NbrAtomSpecsRef->[$Index]; + $NbrAtomSpecToMatch =~ s/ //g; + + @NbrAtomSpecs = split /\,/, $NbrAtomSpecToMatch; + $NbrAtomSpecCount = scalar @NbrAtomSpecs; + + # Does neighbor specification contains a wild card in atom symbol specification? + # + if ($NbrAtomSpecToMatch =~ /(A|\*)/i) { + $WildCardInNbrAtomSpec = 0; + NBRATOMSPEC: for $NbrAtomSpec (@NbrAtomSpecs) { + ($FirstAtomicInvariant) = split /\./, $NbrAtomSpec; + if ($FirstAtomicInvariant =~ /^!/) { + $FirstAtomicInvariant =~ s/^!//; + } + $WildCardInNbrAtomSpec = $This->_IsWildCardAtomSymbolAtomicInvariant($FirstAtomicInvariant); + if ($WildCardInNbrAtomSpec) { + last NBRATOMSPEC; + } + } + if ($WildCardInNbrAtomSpec) { + # Set NbrAtomSpecCount arbitrarily high to make the spec containing wild + # card last on the sorted list while maintaining its original order in the list... + $NbrAtomSpecCount = 999; + } + } + + if (!exists $NbrAtomSpecDataMap{$NbrAtomSpecCount}) { + %{$NbrAtomSpecDataMap{$NbrAtomSpecCount}} = (); + } + + # Use first NbrAtomSpec available in @NbrAtomSpecs to determine atomic invariant count + # with in each NbrAtomSpecToMatch, as @NbrAtomSpecs derived from $NbrAtomSpecToMatch + # simply corresponds to a list of possible matches... + # + ($NbrAtomSpec) = @NbrAtomSpecs; + @NbrAtomSpecAtomicInvariants = split /\./, $NbrAtomSpec; + $NbrAtomSpecAtomicInvarintCount = scalar @NbrAtomSpecAtomicInvariants; + + if (!exists $NbrAtomSpecDataMap{$NbrAtomSpecCount}{$NbrAtomSpecAtomicInvarintCount}) { + @{$NbrAtomSpecDataMap{$NbrAtomSpecCount}{$NbrAtomSpecAtomicInvarintCount}} = (); + } + push @{$NbrAtomSpecDataMap{$NbrAtomSpecCount}{$NbrAtomSpecAtomicInvarintCount}}, $Index; + + } + + @SortedNbrAtomSpecs = (); @SortedNbrBondSpecs = (); + @SortedNbrOfNbrAtomSpecs = (); + + for $NbrAtomSpecCount ( sort { $a <=> $b } keys %NbrAtomSpecDataMap) { + for $NbrAtomSpecAtomicInvarintCount ( sort { $b <=> $a } keys %{$NbrAtomSpecDataMap{$NbrAtomSpecCount}}) { + for $Index (@{$NbrAtomSpecDataMap{$NbrAtomSpecCount}{$NbrAtomSpecAtomicInvarintCount}}) { + push @SortedNbrAtomSpecs, $NbrAtomSpecsRef->[$Index]; + if (defined $NbrBondSpecsRef) { + push @SortedNbrBondSpecs, $NbrBondSpecsRef->[$Index]; + } + if (defined $NbrOfNbrAtomSpecsRef) { + push @SortedNbrOfNbrAtomSpecs, $NbrOfNbrAtomSpecsRef->[$Index]; + } + } + } + } + + return (\@SortedNbrAtomSpecs, defined $NbrBondSpecsRef ? \@SortedNbrBondSpecs : undef, defined $NbrOfNbrAtomSpecsRef ? \@SortedNbrOfNbrAtomSpecs : undef); +} + +# Check whether atom matches supported atom specification... +# +sub _DoesAtomSpecificationMatch { + my($This, $AtomSpecificationToMatch) = @_; + my($AtomSpecification, $AtomicInvariant, $AtomSpecificationMatched, $AtomicInvariantMatched, $FirstMatch); + + # Anything to match... + if (!(defined($AtomSpecificationToMatch) && $AtomSpecificationToMatch)) { + return 1; + } + + # Take out any spaces... + $AtomSpecificationToMatch =~ s/ //g; + + # Match specified atom specifications. For multiple atom specifications in a comma delimited string, + # only one atom specification needs to match for a successful match. It's up to the caller to make + # sure that the specificaton list is ordered from least to most specific atom specification... + # + for $AtomSpecification (split /\,/, $AtomSpecificationToMatch) { + $AtomSpecificationMatched = 1; + $FirstMatch = 1; + + # Match all atom symbol atomic invariants... + ATOMICINVARIANT: for $AtomicInvariant (split /\./, $AtomSpecification) { + if ($FirstMatch) { + # Match atom symbol atomic invariant... + $FirstMatch = 0; + $AtomicInvariantMatched = $This->_MatchAtomSymbolAtomicInvariant($AtomicInvariant); + } + else { + # Match non atom symbol atomic invariant... + $AtomicInvariantMatched = $This->_MatchNonAtomSymbolAtomicInvariant($AtomicInvariant); + } + + if (!$AtomicInvariantMatched) { + # No need to match other atomic invariants... + $AtomSpecificationMatched = 0; + last ATOMICINVARIANT; + } + } + + if ($AtomSpecificationMatched) { + # No need to match other atom specifications... + return 1; + } + } + + # Nothing matched... + return 0; +} + +# Check whether atom matches atom symbol atomic invariant... +# +sub _MatchAtomSymbolAtomicInvariant { + my($This, $AtomicInvariant) = @_; + my($NegateMatch, $Status, $AtomicNumber); + + $Status = 0; + $NegateMatch = 0; + + # Does match needs to be negated? + if ($AtomicInvariant =~ /^!/) { + $NegateMatch = 1; + $AtomicInvariant =~ s/^!//; + } + + ATOMICINVARIANT: { + # Any atom match... + if ($This->_IsWildCardAtomSymbolAtomicInvariant($AtomicInvariant)) { + $Status = 1; + last ATOMICINVARIANT; + } + + # Atomic number match... + if ($AtomicInvariant =~ /^#/) { + $AtomicNumber = $AtomicInvariant; $AtomicNumber =~ s/^#//; + $Status = ($This->{AtomicNumber} == $AtomicNumber) ? 1 : 0; + last ATOMICINVARIANT; + } + + # Atom symbol match... + $Status = ($This->{AtomSymbol} =~ /^$AtomicInvariant$/i) ? 1 : 0; + } + + if ($NegateMatch) { + $Status = $Status ? 0 : 1; + } + + return $Status; +} + +# Is it a wild card atom symbol atomic invariant? +# +sub _IsWildCardAtomSymbolAtomicInvariant { + my($This, $AtomicInvariant) = @_; + + return ($AtomicInvariant =~ /^(A|\*)$/i) ? 1 : 0; +} + +# Check whether atom matches non atom symbol atomic invariants... +# +sub _MatchNonAtomSymbolAtomicInvariant { + my($This, $AtomicInvariant) = @_; + my($NegateMatch, $Status, $Name, $Value, $UnknownName); + + ($Status, $NegateMatch, $UnknownName) = ('0') x 3; + + # Does match needs to be negated? + if ($AtomicInvariant =~ /^!/) { + $NegateMatch = 1; + $AtomicInvariant =~ s/^!//; + } + + # Extract atomic invariant name and any value... + if ($AtomicInvariant =~ /[0-9\*]+/) { + ($Name, $Value) = $AtomicInvariant =~ /^([a-zA-Z]+)([0-9\-\+\*\>\<\=]+)$/; + } + else { + ($Name, $Value) = ($AtomicInvariant, undef); + } + + NAME: { + # Match number of non-hydrogen atom neighbors + if ($Name =~ /^X$/i) { + $Status = (defined($Value) && $This->GetNumOfNonHydrogenAtomNeighbors() == $Value) ? 1 : 0; + last NAME; + } + + # Match total number of atom neighbors including missing hydrogens... + if ($Name =~ /^T$/i) { + $Status = (defined($Value) && ($This->GetNumOfNonHydrogenAtomNeighbors() + $This->GetNumOfHydrogens()) == $Value) ? 1 : 0; + last NAME; + } + + # Match formal charge... + if ($Name =~ /^FC$/i) { + my $FormalCharge = $This->GetFormalCharge(); + $Status = $This->_MatchNonAtomSymbolAtomicInvariantValue($FormalCharge, $Value); + last NAME; + } + + # Match aromatic annotation indicating whether atom is aromatic... + if ($Name =~ /^Ar$/i) { + $Status = $This->IsAromatic() ? 1 : 0; + last NAME; + } + + # Match number of implicit and explicit hydrogens... + if ($Name =~ /^H$/i) { + $Status = (defined($Value) && ($This->GetNumOfHydrogens() == $Value)) ? 1 : 0; + last NAME; + } + + # Match ring atom annotation indicating whether atom is in ring... + if ($Name =~ /^RA$/i) { + $Status = defined($Value) ? $This->IsInRingOfSize($Value) : ($This->IsInRing() ? 1 : 0); + last NAME; + } + + # Match number of rings for atom.. + if ($Name =~ /^TR$/i) { + $Status = (defined($Value) && ($Value == $This->GetNumOfRings())) ? 1 : 0; + last NAME; + } + + # Match sum of bond orders to non-hydrogen atom neighbors... + if ($Name =~ /^BO$/i) { + $Status = (defined($Value) && $This->GetSumOfBondOrdersToNonHydrogenAtoms() == $Value) ? 1 : 0; + last NAME; + } + + # Match largest bond order of non-hydrogen atom neighbors... + if ($Name =~ /^LBO$/i) { + $Status = (defined($Value) && $This->GetLargestBondOrderToNonHydrogenAtoms() == $Value) ? 1 : 0; + last NAME; + } + + # Match number of single bonds to non-hydrogen atom neighbors... + if ($Name =~ /^SB$/i) { + $Status = (defined($Value) && $This->GetNumOfSingleBondsToNonHydrogenAtoms() == $Value) ? 1 : 0; + last NAME; + } + + # Match total number of single bonds to atom neighbors including missing and explicit hydrogens... + if ($Name =~ /^TSB$/i) { + $Status = (defined($Value) && ($This->GetNumOfSingleBondsToNonHydrogenAtoms() + $This->GetNumOfHydrogens()) == $Value) ? 1 : 0; + last NAME; + } + + # Match number of double bonds to non-hydrogen atom neighbors... + if ($Name =~ /^DB$/i) { + $Status = (defined($Value) && $This->GetNumOfDoubleBondsToNonHydrogenAtoms() == $Value) ? 1 : 0; + last NAME; + } + + # Match number of triple bonds to non-hydrogen atom neighbors... + if ($Name =~ /^TB$/i) { + $Status = (defined($Value) && $This->GetNumOfTripleBondsToNonHydrogenAtoms() == $Value) ? 1 : 0; + last NAME; + } + + # Match number of aromatic bonds to non-hydrogen atom neighbors... + if ($Name =~ /^AB$/i) { + $Status = (defined($Value) && $This->GetNumOfAromaticBondsToNonHydrogenAtoms() == $Value) ? 1 : 0; + last NAME; + } + + + # Match mass number indicating isotope other than most abundant isotope... + if ($Name =~ /^MN$/i) { + $Status = (defined($Value) && $This->GetMassNumber() == $Value) ? 1 : 0; + last NAME; + } + + # Match spin multiplicity... + if ($Name =~ /^SM$/i) { + my $SpinMultiplicity = $This->GetSpinMultiplicity(); + if (!defined $SpinMultiplicity) { $SpinMultiplicity = 0; } + $Status = (defined($Value) && defined($SpinMultiplicity) && $Value == $SpinMultiplicity) ? 1 : 0; + last NAME; + } + + $UnknownName = 1; + carp "Warning: ${ClassName}->_MatchNonAtomSymbolAtomicInvariant: Unknown atomic invariant $AtomicInvariant..."; + } + + if (!$UnknownName) { + if ($NegateMatch) { + $Status = $Status ? 0 : 1; + } + } + + return $Status; +} + +# Match atomic invariant value... +# +# Specified value format: +# . +* : Any positive value +# . -* : Any negative value +# . >ValidNumber or >=ValidNumber +# . <ValidNumber or <=ValidNumber +# . Any valid number +# +sub _MatchNonAtomSymbolAtomicInvariantValue { + my($This, $TargetValue, $SpecifiedValue) = @_; + my($Status); + + $Status = 0; + + if (!(defined($TargetValue) && defined($SpecifiedValue))) { + return $Status; + } + + VALUE: { + if ($SpecifiedValue =~ /^\+\*/) { + $Status = ($TargetValue > 0) ? 1 : 0; + last VALUE; + } + if ($SpecifiedValue =~ /^\-\*/) { + $Status = ($TargetValue < 0) ? 1 : 0; + last VALUE; + } + if ($SpecifiedValue =~ /^>/) { + if ($SpecifiedValue =~ /^>=/) { + $SpecifiedValue =~ s/^>=//; + $Status = ($SpecifiedValue >= $TargetValue) ? 1 : 0; + } + else { + $SpecifiedValue =~ s/^>//; + $Status = ($SpecifiedValue > $TargetValue) ? 1 : 0; + } + last VALUE; + } + if ($SpecifiedValue =~ /^</) { + if ($SpecifiedValue =~ /^<=/) { + $SpecifiedValue =~ s/^<=//; + $Status = ($SpecifiedValue <= $TargetValue) ? 1 : 0; + } + else { + $SpecifiedValue =~ s/^<//; + $Status = ($SpecifiedValue < $TargetValue) ? 1 : 0; + } + last VALUE; + } + # Default is do perform an equality match... + $Status = ($SpecifiedValue == $TargetValue) ? 1 : 0; + } + + return $Status; +} + +# Check whether atoms match bond specifications... +# +sub _DoesBondSpecificationMatch { + my($This, $BondedAtom, $BondSpecificationToMatch) = @_; + my($BondSpecification, $BondSymbolSpecification, $BondSpecificationMatched); + + # Anything to match... + if (!(defined($BondSpecificationToMatch) && $BondSpecificationToMatch)) { + return 1; + } + + # Take out any spaces... + $BondSpecificationToMatch =~ s/ //g; + + # Match specified bond specifications. For multiple bond specifications in a comma delimited string, + # only one bond specification needs to match for a successful match... + # + for $BondSpecification (split /\,/, $BondSpecificationToMatch) { + $BondSpecificationMatched = 1; + + # Match all specified bond symbol specifications... + BONDSYMBOL: for $BondSymbolSpecification (split /\./, $BondSpecification) { + if (!$This->_MatchBondSymbolSpecification($BondedAtom, $BondSymbolSpecification)) { + # No need to match other bond symbol specifications... + $BondSpecificationMatched = 0; + last BONDSYMBOL; + } + } + if ($BondSpecificationMatched) { + # No need to try matching other bond specifications... + return 1; + } + } + + # Nothing matched... + return 0; +} + +# Check whether atoms match bond symbol specification... +# +sub _MatchBondSymbolSpecification { + my($This, $BondedAtom, $BondSymbolSpecification) = @_; + my($NegateMatch, $Status, $Bond, $BondSymbol, $UnknownBondSymbol); + + ($Status, $NegateMatch, $UnknownBondSymbol) = ('0') x 3; + + # Does match needs to be negated? + if ($BondSymbolSpecification =~ /^!/) { + $NegateMatch = 1; + $BondSymbolSpecification =~ s/^!//; + } + $BondSymbol = $BondSymbolSpecification; + $Bond = $This->GetBondToAtom($BondedAtom); + + BONDSYMBOL: { + if ($BondSymbol =~ /^(-|1|s|Single)$/i) { $Status = $Bond->IsSingle() ? 1 : 0; last BONDSYMBOL; } + if ($BondSymbol =~ /^(=|2|d|Double)$/i) { $Status = $Bond->IsDouble() ? 1 : 0; last BONDSYMBOL; } + if ($BondSymbol =~ /^(#|3|t|Triple)$/i) { $Status = $Bond->IsTriple() ? 1 : 0; last BONDSYMBOL; } + if ($BondSymbol =~ /^(:|a|Ar|Aromatic)$/i) { $Status = $Bond->IsAromatic() ? 1 : 0; last BONDSYMBOL; } + + if ($BondSymbol =~ /^(\@|RB|Ring)$/i) { $Status = $Bond->IsInRing() ? 1 : 0; last BONDSYMBOL; } + + if ($BondSymbol =~ /^(\~|\*|Any)$/i) { $Status = 1; last BONDSYMBOL; } + + $UnknownBondSymbol = 1; + carp "Warning: ${ClassName}->_MatchBondSpecification: Unknown bond specification $BondSymbolSpecification..."; + } + + if (!$UnknownBondSymbol) { + if ($NegateMatch) { + $Status = $Status ? 0 : 1; + } + } + + return $Status; +} + +# Is it a saturated atom? +# +sub IsSaturated { + my($This) = @_; + + return !$This->IsUnsaturated(); +} + +# Is it an unsaturated atom containing at least one non-single bond? +# +sub IsUnsaturated { + my($This) = @_; + my($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds); + + ($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds) = $This->GetNumOfBondTypesToNonHydrogenAtoms(); + + return ($NumOfDoubleBonds || $NumOfTripleBonds || $NumOfAromaticBonds) ? 1 : 0; +} + +# Is atom in a ring? +# +sub IsInRing { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_IsAtomInRing($This); +} + +# Is atom not in a ring? +# +sub IsNotInRing { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_IsAtomNotInRing($This); +} + +# Is atom only in one ring? +# +sub IsOnlyInOneRing { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_IsAtomInOnlyOneRing($This); +} + +# Is atom in a ring of specific size? +# +sub IsInRingOfSize { + my($This, $RingSize) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_IsAtomInRingOfSize($This, $RingSize); +} + +# Get size of smallest ring containing the atom... +# +sub GetSizeOfSmallestRing { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_GetSizeOfSmallestAtomRing($This); +} + +# Get size of largest ring containing the atom... +# +sub GetSizeOfLargestRing { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_GetSizeOfLargestAtomRing($This); +} + +# Get number of rings containing the atom... +# +sub GetNumOfRings { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_GetNumOfAtomRings($This); +} + +# Get number of rings with odd size containing the atom... +# +sub GetNumOfRingsWithOddSize { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_GetNumOfAtomRingsWithOddSize($This); +} + +# Get number of rings with even size containing the atom... +# +sub GetNumOfRingsWithEvenSize { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_GetNumOfAtomRingsWithEvenSize($This); +} + +# Get number of rings with specified size containing the atom... +# +sub GetNumOfRingsWithSize { + my($This, $RingSize) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_GetNumOfAtomRingsWithSize($This, $RingSize); + +} + +# Get number of rings with size less than specified containing the atom... +# +sub GetNumOfRingsWithSizeLessThan { + my($This, $RingSize) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_GetNumOfAtomRingsWithSizeLessThan($This, $RingSize); +} + +# Get number of rings with size greater than specified size containing the atom... +# +sub GetNumOfRingsWithSizeGreaterThan { + my($This, $RingSize) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_GetNumOfAtomRingsWithSizeGreaterThan($This, $RingSize); +} + +# Get all rings an array of references to arrays containing ring atoms... +# +sub GetRings { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_GetAtomRings($This); +} + +# Get smallest ring as an array containing ring atoms... +# +sub GetSmallestRing { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_GetSmallestAtomRing($This); +} + +# Get largest ring as an array containing ring atoms... +# +sub GetLargestRing { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_GetLargestAtomRing($This); +} + +# Get odd size rings an array of references to arrays containing ring atoms... +# +sub GetRingsWithOddSize { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_GetAtomRingsWithOddSize($This); +} + +# Get even size rings an array of references to arrays containing ring atoms... +# +sub GetRingsWithEvenSize { + my($This) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_GetAtomRingsWithEvenSize($This); +} + +# Get rings with specified size as an array of references to arrays containing ring atoms... +# +sub GetRingsWithSize { + my($This, $RingSize) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_GetAtomRingsWithSize($This, $RingSize); +} + +# Get rings with size less than specfied size as an array of references to arrays containing ring atoms... +# +sub GetRingsWithSizeLessThan { + my($This, $RingSize) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_GetAtomRingsWithSizeLessThan($This, $RingSize); +} + +# Get rings with size greater than specfied size as an array of references to arrays containing ring atoms... +# +sub GetRingsWithSizeGreaterThan { + my($This, $RingSize) = @_; + + # Is this atom in a molecule? + if (!$This->HasProperty('Molecule')) { + return undef; + } + my($Molecule); + $Molecule = $This->GetProperty('Molecule'); + + return $Molecule->_GetAtomRingsWithSizeGreaterThan($This, $RingSize); +} + +# Get next object ID... +sub _GetNewObjectID { + $ObjectID++; + return $ObjectID; +} + +# Return a string containing vertices, edges and other properties... +sub StringifyAtom { + my($This) = @_; + my($AtomString, $ID, $Name, $AtomSymbol, $AtomicNumber, $XYZVector, $AtomicWeight, $ExactMass, $NumOfNeighbors, $NumOfBonds, $Valence, $MissingHydrogens, $TotalHydrogens, $ImplicitHydrogens, $ExplicitHydrogens, $FormalCharge, $Charge, $SpinMultiplicity, $FreeRadicalElectrons, $StereoCenter, $StereoCenterStatus, $StereoChemistry, $StereochemistryString, $RingAtom, $NumOfRings, $AromaticAtom); + + $ID = $This->GetID(); + $Name = $This->GetName(); + $AtomSymbol = $This->GetAtomSymbol(); + $AtomicNumber = $This->GetAtomicNumber(); + $XYZVector = $This->GetXYZVector(); + + $AtomicWeight = $This->GetAtomicWeight(); + if (!defined $AtomicWeight) { + $AtomicWeight = 'undefined'; + } + $ExactMass = $This->GetExactMass(); + if (!defined $ExactMass) { + $ExactMass = 'undefined'; + } + $NumOfNeighbors = $This->GetNumOfNeighbors(); + if (!defined $NumOfNeighbors) { + $NumOfNeighbors = 'undefined'; + } + $NumOfBonds = $This->GetNumOfBonds(); + if (!defined $NumOfBonds) { + $NumOfBonds = 'undefined'; + } + $Valence = $This->GetValence(); + if (!defined $Valence) { + $Valence = 'undefined'; + } + + $MissingHydrogens = $This->GetNumOfMissingHydrogens(); + if (!defined $MissingHydrogens) { + $MissingHydrogens = 'undefined'; + } + $TotalHydrogens = $This->GetNumOfHydrogens(); + if (!defined $TotalHydrogens) { + $TotalHydrogens = 'undefined'; + } + $ImplicitHydrogens = $This->GetNumOfImplicitHydrogens(); + if (!defined $ImplicitHydrogens) { + $ImplicitHydrogens = 'undefined'; + } + $ExplicitHydrogens = $This->GetNumOfExplicitHydrogens(); + if (!defined $ExplicitHydrogens) { + $ExplicitHydrogens = 'undefined'; + } + + $FormalCharge = $This->GetFormalCharge(); + if (!defined $FormalCharge) { + $FormalCharge = 'undefined'; + } + $Charge = $This->GetCharge(); + if (!defined $Charge) { + $Charge = 'undefined'; + } + + $SpinMultiplicity = $This->GetSpinMultiplicity(); + if (!defined $SpinMultiplicity) { + $SpinMultiplicity = 'undefined'; + } + $FreeRadicalElectrons = $This->GetFreeRadicalElectrons(); + if (!defined $FreeRadicalElectrons) { + $FreeRadicalElectrons = 'undefined'; + } + + $RingAtom = $This->IsInRing(); + if (defined $RingAtom) { + $RingAtom = $RingAtom ? 'Yes' : 'No'; + $NumOfRings = $This->GetNumOfRings(); + } + else { + $RingAtom = 'undefined'; + $NumOfRings = 'undefined'; + } + + $AromaticAtom = $This->GetAromatic(); + if (defined $AromaticAtom) { + $AromaticAtom = $AromaticAtom ? 'Yes' : 'No'; + } + else { + $AromaticAtom = 'undefined'; + } + + $StereochemistryString = ''; + $StereoCenter = $This->GetStereoCenter(); + if (defined $StereoCenter) { + $StereoCenterStatus = $This->IsStereoCenter() ? 'Yes' : 'No'; + $StereoChemistry = $This->GetStereochemistry(); + if (!defined $StereoChemistry) { + $StereoChemistry = 'undefined'; + } + $StereochemistryString = "StereoCenter: $StereoCenterStatus; Stereochemistry: $StereoChemistry"; + } + + $AtomString = "Atom: ID: $ID; Name: \"$Name\"; AtomSymbol: \"$AtomSymbol\"; AtomicNumber: $AtomicNumber; XYZ: $XYZVector; AtomicWeight: $AtomicWeight; ExactMass: $ExactMass; NumOfNeighbors: $NumOfNeighbors; NumOfBonds: $NumOfBonds; Valence: $Valence; MissingHydrogens: $MissingHydrogens; TotalHydrogens: $TotalHydrogens; ImplicitHydrogens: $ImplicitHydrogens; ExplicitHydrogens: $ExplicitHydrogens; FormalCharge: $FormalCharge; Charge: $Charge; SpinMultiplicity: $SpinMultiplicity; FreeRadicalElectrons: $FreeRadicalElectrons; RingAtom: $RingAtom; NumOfAtomRings: $NumOfRings; AromaticAtom: $AromaticAtom"; + + if ($StereochemistryString) { + $AtomString .= "; $StereochemistryString"; + } + + return $AtomString; +} + +# Load appropriate atom data files from <MayaChemTools>/lib directory used by various +# object methods in the current class... +# +sub _LoadAtomClassData { + my($MayaChemToolsLibDir); + + $MayaChemToolsLibDir = GetMayaChemToolsLibDirName(); + + _LoadAtomValenceModelData($MayaChemToolsLibDir); + +} + +# +# Load data for supported valence models... +# +sub _LoadAtomValenceModelData { + my($MayaChemToolsLibDir) = @_; + my($MDLValenceModelDataFile, $DaylightValenceModelDataFile); + + %MDLValenceModelDataMap = (); + %DaylightValenceModelDataMap = (); + + $MDLValenceModelDataFile = $MayaChemToolsLibDir . "/data/MDLValenceModelData.csv"; + $DaylightValenceModelDataFile = $MayaChemToolsLibDir . "/data/DaylightValenceModelData.csv"; + + if (! -e "$MDLValenceModelDataFile") { + croak "Error: ${ClassName}::_LoadAtomValenceModelData: MayaChemTools package file, $MDLValenceModelDataFile, is missing: Possible installation problems..."; + } + + if (! -e "$DaylightValenceModelDataFile") { + croak "Error: ${ClassName}::_LoadAtomValenceModelData: MayaChemTools package file, $DaylightValenceModelDataFile, is missing: Possible installation problems..."; + } + + _LoadValenceModelDataFile($MDLValenceModelDataFile, \%MDLValenceModelDataMap); + _LoadValenceModelDataFile($DaylightValenceModelDataFile, \%DaylightValenceModelDataMap); + +} + +# +# Load valence model data file... +# +sub _LoadValenceModelDataFile { + my($DataFile, $DataMapRef) = @_; + + # File format: + # + # "AtomicNumber","ElementSymbol","FormalCharge","CommomValences" + # + my($InDelim, $Line, $NumOfCols, @ColLabels, @LineWords); + + $InDelim = "\,"; + open DATAFILE, "$DataFile" or croak "Couldn't open $DataFile: $! ..."; + + # Skip lines up to column labels... + LINE: while ($Line = GetTextLine(\*DATAFILE)) { + if ($Line !~ /^#/) { + last LINE; + } + } + @ColLabels= quotewords($InDelim, 0, $Line); + $NumOfCols = @ColLabels; + + my($AtomicNumber, $ElementSymbol, $FormalCharge, $CommonValences); + + # Process element data... + LINE: while ($Line = GetTextLine(\*DATAFILE)) { + if ($Line =~ /^#/) { + next LINE; + } + @LineWords = (); + @LineWords = quotewords($InDelim, 0, $Line); + if (@LineWords != $NumOfCols) { + croak "Error: ${ClassName}::_LoadValenceModelDataFile: The number of data fields, @LineWords, in $DataFile must be $NumOfCols.\nLine: $Line..."; + } + + ($AtomicNumber, $ElementSymbol, $FormalCharge, $CommonValences) = @LineWords; + + if (exists $DataMapRef->{$AtomicNumber}) { + # Additional data for an element... + if (exists $DataMapRef->{$AtomicNumber}{$FormalCharge}) { + # Duplicate data entries for an element... + carp "Warning: ${ClassName}::_LoadValenceModelDataFile: Ignoring valence data for element with atomic number $AtomicNumber and formal charge $FormalCharge in data file $DataFile: It has already been loaded.\nLine: $Line..."; + next LINE; + } + } + else { + # Data for a new element... + %{$DataMapRef->{$AtomicNumber}} = (); + } + + %{$DataMapRef->{$AtomicNumber}{$FormalCharge}} = (); + $DataMapRef->{$AtomicNumber}{$FormalCharge}{ElementSymbol} = $ElementSymbol; + + @{$DataMapRef->{$AtomicNumber}{$FormalCharge}{CommonValences}} = (); + @{$DataMapRef->{$AtomicNumber}{$FormalCharge}{CommonValences}} = sort { $a <=> $b } split /\,/, $CommonValences; + } + close DATAFILE; +} + +1; + +__END__ + +=head1 NAME + +Atom + +=head1 SYNOPSIS + +use Atom; + +=head1 DESCRIPTION + +B<Atom> class provides the following methods: + +new, AddHydrogens, Copy, DeleteAtom, DeleteHydrogens, DoesAtomNeighborhoodMatch, +GetAtomicInvariantValue, GetAtomicWeight, GetBondToAtom, GetBonds, +GetBondsToHeavyAtoms, GetBondsToHydrogenAtoms, GetBondsToNonHydrogenAtoms, +GetExactMass, GetExplicitHydrogens, GetFormalCharge, GetFreeRadicalElectrons, +GetGroupNumber, GetHeavyAtomNeighbors, GetHeavyAtomNeighborsAtomInformation, +GetHeavyAtomNeighborsBondformation, GetHighestCommonValence, +GetHydrogenAtomNeighbors, GetHydrogens, GetImplicitHydrogens, GetLargestBondOrder, +GetLargestBondOrderToHeavyAtoms, GetLargestBondOrderToNonHydrogenAtoms, +GetLargestRing, GetLowestCommonValence, GetMassNumber, GetMissingHydrogens, +GetNeighbors, GetNeighborsUsingAtomSpecification, GetNonHydrogenAtomNeighbors, +GetNonHydrogenAtomNeighborsAtomInformation, +GetNonHydrogenAtomNeighborsBondInformation, GetNonHydrogenNeighborOfHydrogenAtom, +GetNumOfAromaticBondsToHeavyAtoms, GetNumOfAromaticBondsToNonHydrogenAtoms, +GetNumOfBondTypesToHeavyAtoms, GetNumOfBondTypesToNonHydrogenAtoms, GetNumOfBonds, +GetNumOfBondsToHeavyAtoms, GetNumOfBondsToHydrogenAtoms, +GetNumOfBondsToNonHydrogenAtoms, GetNumOfDoubleBondsToHeavyAtoms, +GetNumOfBondsAvailableForHeavyAtoms, GetNumOfBondsAvailableForNonHydrogenAtoms, +GetNumOfDoubleBondsToNonHydrogenAtoms, GetNumOfExplicitHydrogens, +GetNumOfHeavyAtomNeighbors, GetNumOfHydrogenAtomNeighbors, GetNumOfHydrogens, +GetNumOfImplicitHydrogens, GetNumOfMissingHydrogens, GetNumOfNeighbors, +GetNumOfNonHydrogenAtomNeighbors, GetNumOfRings, GetNumOfRingsWithEvenSize, +GetNumOfRingsWithOddSize, GetNumOfRingsWithSize, GetNumOfRingsWithSizeGreaterThan, +GetNumOfRingsWithSizeLessThan, GetNumOfSigmaAndPiBondsToHeavyAtoms, +GetNumOfSigmaAndPiBondsToNonHydrogenAtoms, GetNumOfSingleBondsToHeavyAtoms, +GetNumOfSingleBondsToNonHydrogenAtoms, GetNumOfTripleBondsToHeavyAtoms, +GetNumOfTripleBondsToNonHydrogenAtoms, GetPeriodNumber, +GetPotentialTotalCommonValence, GetRings, GetRingsWithEvenSize, +GetRingsWithOddSize, GetRingsWithSize, GetRingsWithSizeGreaterThan, +GetRingsWithSizeLessThan, GetSizeOfLargestRing, GetSizeOfSmallestRing, +GetSmallestRing, GetSpinMultiplicity, GetSumOfBondOrders, +GetSumOfBondOrdersToHeavyAtoms, GetSumOfBondOrdersToHydrogenAtoms, +GetSumOfBondOrdersToNonHydrogenAtoms, GetValence, GetValenceElectrons, +GetValenceFreeElectrons, GetX, GetXYZ, GetXYZVector, GetY, GetZ, IsAmideCarbon, +IsAmideNitrogen, IsAromatic, IsArsenic, IsBondedToAtom, IsBromine, IsCarbon, IsCarboxylCarbon, +IsCarboxylOxygen, IsCarboxylateCarbon, IsCarboxylateOxygen, IsChlorine, +IsFluorine, IsFunctionalClassType, IsGuadiniumCarbon, IsGuadiniumNitrogen, +IsHBondAcceptor, IsHBondDonor, IsHalogen, IsHeteroAtom, IsHydrogen, +IsHydrogenBondAcceptor, IsHydrogenBondDonor, IsHydrophobic, IsInRing, +IsInRingOfSize, IsIodine, IsIsotope, IsLipophilic, IsMetallic, +IsNegativelyIonizable, IsNitrogen, IsNonCarbonOrHydrogen, IsNotInRing, +IsOnlyInOneRing, IsOxygen, IsPhosphateOxygen, IsPhosphatePhosphorus, IsPhosphorus, +IsPolarAtom, IsPolarHydrogen, IsPositivelyIonizable, IsSaturated, IsSelenium, +IsSilicon, IsStereoCenter, IsSulfur, IsSulphur, IsTellurium, IsTerminal, +IsTopologicalPharmacophoreType, IsUnsaturated, SetAtomSymbol, SetAtomicNumber, +SetExplicitHydrogens, SetMassNumber, SetStereoCenter, SetStereochemistry, +SetX, SetXYZ, SetY, SetZ, StringifyAtom + +B<Atom> class is derived from B<ObjectProperty> base class which provides methods not explicitly +defined in B<Atom> or B<ObjectProperty> class using Perl's AUTOLOAD functionality. These methods +are generated on-the-fly for a specified object property: + + Set<PropertyName>(<PropertyValue>); + $PropertyValue = Get<PropertyName>(); + Delete<PropertyName>(); + +=head2 METHODS + +=over 4 + +=item B<new> + + $NewAtom = new Atom([%PropertyNameAndValues]); + +Using specified I<Atom> property names and values hash, B<new> method creates a new object +and returns a reference to newly created B<Atom> object. By default, following properties are +initialized: + + ID = SequentialObjectID + Name = "Atom <SequentialObjectID>" + AtomSymbol = "" + AtomicNumber = 0 + XYZ = ZeroVector + +Except for I<ID> property, all other default properties and other additional properties can +be set during invocation of this method. + +Examples: + + $Atom = new Atom(); + $CarbonAtom = new Atom('AtomSymbol' => 'C', 'XYZ' => (0.0, 1.0, + 0.0)); + $OxygenAtom = new Atom('AtomName' => 'Oxygen', AtomSymbol' => 'O', + 'XYZ' => (1.0, 1.0, 1.0)); + +=item B<AddHydrogens> + + $NumOfHydrogensAdded = $Atom->AddHydrogens(); + +Adds hydrogens to an B<Atom> present in a B<Molecule> object and returns +the number of added hydrogens. The current release of MayaChemTools doesn't +assign hydrogen positions. + +=item B<Copy> + + $AtomCopy = $Atom->Copy(); + +Copy I<Atom> and its associated data using B<Storable::dclone> and return a new +B<Atom> object. + +=item B<DeleteAtom> + + $Atom->DeleteAtom(); + +Delete I<Atom> from a molecule. + +=item B<DoesAtomNeighborhoodMatch> + + $Status = $Atom->DoesAtomNeighborhoodMatch($CentralAtomSpec); + $Status = $Atom->DoesAtomNeighborhoodMatch($CentralAtomSpec, + $NbrAtomSpecsRef); + $Status = $Atom->DoesAtomNeighborhoodMatch($CentralAtomSpec, + $NbrAtomSpecsRef, $AllowedNbrBondSpecsRef); + $Status = $Atom->DoesAtomNeighborhoodMatch($CentralAtomSpec, + $NbrAtomSpecsRef, $NbrBondSpecsRef, + $AllowedNbrOfNbrAtomSpecsRef); + +Returns 1 or 0 based on whether atom matches central atom and its neighborhood +using specified atom and bonds specifications. Neighborhood atom and bond specifications +are specified as array references containing neighbor atom and bond specifications. + +Let: + + AS = Atom symbol corresponding to element symbol, atomic number (#n) + or any atom (A) + + X<n> = Number of non-hydrogen atom neighbors or heavy atoms + attached to atom + T<n> = Total number of atom neighbors including implicit and explicit + hydrogens + BO<n> = Sum of bond orders to non-hydrogen atom neighbors or heavy + atoms attached to atom + LBO<n> = Largest bond order of non-hydrogen atom neighbors or heavy + atoms attached to atom + SB<n> = Number of single bonds to non-hydrogen atom neighbors or + heavy atoms attached to atom + TSB<n> = Total number of single bonds to atom neighbors including implicit + and explicit hydrogens + DB<n> = Number of double bonds to non-hydrogen atom neighbors or + heavy atoms attached to atom + TB<n> = Number of triple bonds to non-hydrogen atom neighbors or + heavy atoms attached to atom + AB<n> = Number of aromatic bonds to non-hydrogen atom neighbors or + heavy atoms attached to atom + H<n> = Number of implicit and explicit hydrogens for atom + Ar = Aromatic annotation indicating whether atom is aromatic + RA or RA<n> = Ring atom annotation indicating whether atom + is a ring + TR<n> = Total number of rings containing atom + FC<+n/-n> = Formal charge assigned to atom + MN<n> = Mass number indicating isotope other than most abundant isotope + SM<n> = Spin multiplicity of atom. Possible values: 1 (singlet), + 2 (doublet) or 3 (triplet) + +Then, atom specification corresponds to: + + AS.X<n>.T<n>.BO<n>.LBO<n>.<SB><n>.TSB<n>.<DB><n>.<TB><n>.AB<n>.H<n>.Ar. + RA<n>.TR<n>FC<+n/-n>.MN<n>.SM<n> + +Except for AS which is a required atomic invariant in atom specification, all other atomic invariants are +optional. For an atom specification to match an atom, the values of all specified atomic invariants must +match. Exclamation in from of atomic invariant can be used to negate its effect during the match. + +For I<FC> value matching, the following value operators are also supported: + + o +* : Any positive value + o -* : Any negative value + o > ValidNumber or >= ValidNumber + o < ValidNumber or <= ValidNumber + +A comma delimited atom specification string is used to match any one of the specified atom specification. + +Notes: + + o During atom specification match to an atom, the first atomic invariant is always assumed to + atom symbol. + +Examples: + + o ('N', 'N', 'N') + o ('N.FC0', 'N.FC0', 'N,N.FC+1.H1') + o ('N.H2', 'N.H2', 'N.H1') + o ('C,N', '!N', '!H') + o ('C,N', 'N.Ar', 'N.R5') + +Let: + + -|1|s|Single = Single bond + =|2|d|Double = Double bond + #|3|t|Triple = Triple bond + :|1.5|a|Ar|Aromatic = Aromatic bond + + @|RB|Ring = Ring bond + ~|*|Any = Any bond + +Then, bond specification corresponds to: + + -.: + =.@ + Double.Aromatic + +For a bond specification to match bond between two atoms, the values of all specified bond symbols must +match. Exclamation in from of bond symbol can be used to negate its effect during the match. + +A comma delimited bond specification string is used to match any one of the specified atom specification. + +Notes: + + o During atom neighborhood match for central atom neighborhood atom and bond specifications, + implicit or missing hydrogens are automatically checked for any matches to unmatched + specifications. + +Examples: + + + Aromatic carbon in a 5 membered ring: + $Atom->DoesAtomNeighborhoodMatch('C.Ar.RA5'); + + AcetylenicCarbon: $Atom->DoesAtomNeighborhoodMatch('C.T2.TB1'); or + $Atom->DoesAtomNeighborhoodMatch('C.T2.TB1', + ['*', '*'], ['#', '-']); + + GuadiniumCarbon: $Atom->DoesAtomNeighborhoodMatch('C.X3.BO4', + ['N.FC0', 'N.FC0', 'N.FC0,N.FC+1'], + ['-', '-', '='], + ['C,H', 'C,H', 'C,H']); + + AmideCarbon: $Atom->DoesAtomNeighborhoodMatch('C.X3.BO4,C.X2.BO3', + ['C,H', 'O', 'N'], + ['-', '=', '-'], + ['C,H', 'C', 'C,H,N,O,S,P,F,Cl,Br,I']); + + CarboxylCarbon: $Atom->DoesAtomNeighborhoodMatch('C.X3.BO4,C.X2.BO3', + ['C,H', 'O', 'O.X1.FC0'], + ['-', '=', '-'], + ['C,H', 'C', 'C']); + + CarboxylateCarbon: $Atom->DoesAtomNeighborhoodMatch('C.X3.BO4,C.X2.BO3', + ['C,H', 'O', 'O.X1.FC-1'], + ['-', '=', '-'], + ['C,H', 'C', 'C']); + + +=item B<DeleteHydrogens> + + $NumOfHydrogensDeleted = $Atom->AddHydrogens(); + +Delete hydrogens from an B<Atom> present in a B<Molecule> object and returns +the number of deleted hydrogens. + +=item B<GetAtomicInvariantValue> + + $Value = $Atom->GetAtomicInvariantValue($AtomicInvariant); + +Returns atomic invariant value for a specified I<AtomicInvariant>. The current release +of MayaChemTools supports following abbreviations and descriptive names for +I<AtomicInvarints>: + + AS : Atom or element symbol + X : NumOfNonHydrogenAtomNeighbors or NumOfHeavyAtomNeighbors + T : TotalNumOfAtomNeighbors + BO : SumOfBondOrdersToNonHydrogenAtoms or SumOfBondOrdersToHeavyAtoms + LBO : LargestBondOrderToNonHydrogenAtoms or LargestBondOrderToHeavyAtoms + SB : NumOfSingleBondsToNonHydrogenAtoms or NumOfSingleBondsToHeavyAtoms + TSB : TotalNumOfSingleBonds + DB : NumOfDoubleBondsToNonHydrogenAtoms or NumOfDoubleBondsToHeavyAtoms + TB : NumOfTripleBondsToNonHydrogenAtoms or NumOfTripleBondsToHeavyAtoms + AB : NumOfAromaticBondsToNonHydrogenAtoms or NumOfAromaticBondsToHeavyAtoms + H : NumOfImplicitAndExplicitHydrogens + Ar : Aromatic + Str : Stereochemistry + RA : RingAtom + FC : FormalCharge + AN : AtomicNumber + AM : AtomicMass + MN : MassNumber + SM : SpinMultiplicity + +=item B<GetAtomicWeight> + + $Value = $Aom->GetAtomicWeight(); + +Returns atomic weight of an B<Atom> which corresponds to either explicity set I<AtomicWeight> +atom property or atomic weight of the corresponding element in the periodic table available by +B<PeriodicTable> module. + +=item B<GetBondToAtom> + + $Bond = $Atom->GetBondToAtom($OtherAtom); + +Returns a B<Bond> object corresponding to bond between I<Atom> and I<OtherAtom> in +a molecule. + +=item B<GetBonds> + + @Bonds = $Aoto->GetBonds(); + +Returns an array of B<Bond> objects corresponding to all bonds from I<Atom> to other +bonded atoms in a molecule. + +=item B<GetBondsToHeavyAtoms> + + @Bonds = $Atom->GetBondsToHeavyAtoms(); + +Returns an array of B<Bond> objects corresponding to bonds from I<Atom> to other bonded +non-hydrogen atoms in a molecule. + +=item B<GetBondsToHydrogenAtoms> + + @Bonds = $Atom->GetBondsToHydrogenAtoms(); + +Returns an array of B<Bond> objects corresponding to bonds from I<Atom> to any other +hydrogen atom in a molecule. + +=item B<GetBondsToNonHydrogenAtoms> + + @Bonds = $Atom->GetBondsToNonHydrogenAtoms(); + +Returns an array of B<Bond> objects corresponding to bonds from I<Atom> to other bonded +non-hydrogen atoms in a molecule. + +=item B<GetExactMass> + + $ExactMass = $Atom->GetExactMass(); + +Returns exact mass of an I<Atom> which correspond to one of these three values: explicity set +I<ExactMass> property; mass of natural isotope for an explicty set value of I<MassNumber>; most +abundant natural isotope mass for I<Atom> with valid atomic number value available by +B<PerodicTable> module. + +=item B<GetExplicitHydrogens> + + $NumOfExplicitHydrogens = $Atom->GetExplicitHydrogens(); + +Returns number of hydrogens explicity bonded to an I<Atom> in a molecule. + +=item B<GetFormalCharge> + + $FormalCharge = $Atom->GetFormalCharge(); + +Returns formal charge of an I<Atom> in a molecule. + +=item B<GetFreeRadicalElectrons> + + $FreeRadicalElectrons = $Atom->GetFreeRadicalElectrons(); + +Returns number of free radical electrons corresponding to to one of these +three values: I<FreeRadicalElectrons> property; I<SpinMultiplicity> property; value +of 0. + +For atoms with explicit assignment of I<SpinMultiplicity> atom property values, + + Singlet - two unparied electrons corresponding to one spin state + Doublet - free radical; an unpaired electron corresponding to two + spin states + Triplet - two unparied electrons corresponding to three spin states + (divalent carbon atoms: carbenes) + +B<FreeRadicalElectrons> are calculated as follows: + + Doublet: 1 (one valence electron not available for bonding) + Singlet: 2 (two valence electrons not available for bonding) + Triplet: 2 (two valence electrons not available for bonding) + +=item B<GetGroupNumber> + + $GroupNumber = $Atom->GetGroupNumber(); + +Returns group number of an I<Atom> in a molecule with a valid atomic number. + +=item B<GetHeavyAtomNeighbors> + + $NumOfHeavyAtoms = $Atom->GetHeavyAtomNeighbors(); + @HeavyAtoms = $Atom->GetHeavyAtomNeighbors(); + +Return number of heavy atoms or an array of B<Atom> objects corresponding to heavy atoms +bonded to an I<Atom> in a molecule. + +=item B<GetHeavyAtomNeighborsAtomInformation> + + ($NumOfAtomNeighbors, $AtomNeighborsRef, + $NumOfAtomNeighborsType, $AtomNeighborsTypeMapRef) = $Atom-> + GetHeavyAtomNeighborsAtomInformation(); + +Returns atoms information for all non-hydrogen atoms attached to an I<Atom> +in a molecule. + +The following values are returned: + + o Number of non-hydrogen atom neighbors + o A reference to an array containing atom objects corresponding to + non-hydrogen atom neighbors + o Number of different types of non-hydrogen atom neighbors + o A reference to a hash containing atom symbol as key with value + corresponding to its count for non-hydrogen atom neighbors + +=item B<GetHeavyAtomNeighborsBondformation> + + ($NumOfBonds, $BondTypeCountMapRef, + $AtomsBondTypesCountMapRef, + $AtomsBondTypeAtomsMap) = $Atom-> + GetHeavyAtomNeighborsBondformation(); + +Returns bonds information for all non-hydrogen atoms attached to an I<Atom> +in a molecule. + +The following values are returned: + + o Number of bonds to non-hydrogen atom neighbors + o A reference to an array containing bond objects corresponding to + non-hydrogen atom neighbors + o A reference to a hash containing bond type as key with value + corresponding to its count for non-hydrogen atom neighbors. Bond + types are: Single, Double or Triple + o A reference to a hash containing atom symbol as key pointing to bond + type as second key with values corresponding to count of bond types for atom + symbol for non-hydrogen atom neighbors + o A reference to a hash containing atom symbol as key pointing to bond + type as second key with values corresponding to atom objects array involved + in corresponding bond type for atom symbol for non-hydrogen atom neighbors + +=item B<GetHighestCommonValence> + + $HighestCommonValence = $Atom->GetHighestCommonValence(); + +Returns highest common valence of an I<Atom> which corresponds to either explicity set +I<HighestCommonValence> atom property or highest common valence of the corresponding +element in the periodic table available by B<PerodicTable> module. + +=item B<GetHydrogens> + + $NumOfHydrogens = $Atom->GetHydrogens(); + +Returns total number of hydrogens for an I<Atom> in a molecule including both hydrogen atom +neighbors and implicit hydrogens. + +=item B<GetHydrogenAtomNeighbors> + + $NumOfHydrogenAtomNeighbors = $Atom->GetHydrogenAtomNeighbors(); + @HydrogenAtomNeighbors = $Atom->GetHydrogenAtomNeighbors(); + +Return number of hydrogen atoms or an array of I<Atom> objects corresponding to hydrogen +atoms bonded to an I<Atom> in a molecule. + +=item B<GetImplicitHydrogens> + + $NumOfImplicitHydrogens = $Atom->GetImplicitHydrogens(); + +Returns number of implicit hydrogens for an I<Atom> in a molecule. This value either +corresponds to explicitly set I<ImplicitHydrogens> atom property or calculated as the +difference between the value of potential total valence and sum of bond orders to +both hydrogen and non-hydrogen atom neighbors. + +=item B<GetPotentialTotalCommonValence> + + $PotentialTotalValence = $Atom->GetPotentialTotalCommonValence(); + +Returns potential total common valence of an I<Atom> in a molecule corresponding +to a specific valence model set for the molecule using its B<SetValenceModel> method +or default internal valence model. It is used during the calculation of missing or +implicit hydrogens. + +The current release of MayaChemTools supports three valence models: I<MDLValenceModel, +DaylightValenceModel, InternalValenceModel or MayaChemToolsValenceModel>. + +For I<MDLValenceModel> and I<DaylightValenceModel>, the following data files, distributed +with the package, are used to calculate potential total valence: + + lib/data/MDLValenceModelData.csv + lib/data/DaylightValenceModelData.csv + +The calculation of potential total common valence for these two models is performed as +follows: Calculate current effective total valence of the I<Atom> by adding up the bond +order of its neighbors and number of free radical electrons; Find available common valence +for the I<Atom>, corresponding to any specified formal charge, higher than the effective +total valence, and return it as I<PotentialTotalValence>. + +The calculation of potential total common valence For I<InternalValenceModel> or +I<MayaChenToolsValenceModel> doesn't uses B<PeriodicTable> module to retrieve values +for common valence, which in turn reads in PeriodicTableElements.csv file distributed with +the package. + +For elements with one one common valence, potential total common valence corresponds +to: + + CommonValence + FormalCharge - FreeRadicalElectrons + +For elements with multiple common valences, each common valence is used to +calculate total potential common valence as shown above, and the first total potential +common valence greater than the sum of bond orders to all neighbors is selected as +the final total common valence. + +FormalCharge sign is reversed for electropositive elements with positive formal charge +during common valence calculations. Electropositive elements, metals and transition elements, +have usually plus formal charge and it leads to decrease in common valence; the negative +formal charge should result in the decrease of common valence. + +The sign of formal charge is adjusted as follows. + +Group numbers > 14 - Group numbers 15 (N), 16 (O), 17 (F), 18 (He): + +Formal charge sign is not adjusted. Positive and negative values result in the +increase and decrease of valence. + +Group 14 containing C, Si, Ge, Sn, Pb...: + +Formal charge sign is reversed for positive values. Both positive and negative +values result in the decrease of valence. + +Group 13 containing B, Al, Ga, In, Tl...: + +Formal charge sign is always reversed. Positive and negative values result in the +decrease and increase of valence. + +Groups 1 (H) through 12 (Zn)...: + +Formal charge sign is reversed for positive values. Both positive and negative +values result in the decrease of valence. + +Lanthanides and actinides: + +Formal charge sign is reversed for positive values. Both positive and negative +values result in the decrease of valence. + +=item B<GetLargestBondOrder> + + $LargestBO =$Atom->GetLargestBondOrder(); + +Returns largest bond order for an I<Atom> among the bonds to other atoms in a molecule. + +=item B<GetLargestBondOrderToHeavyAtoms> + + $LargestBO =$Atom->GetLargestBondOrderToHeavyAtoms(); + +Returns largest bond order for an I<Atom> among the bonds to other heavy atoms in a molecule. + +=item B<GetLargestBondOrderToNonHydrogenAtoms> + + $LargestBO =$Atom->GetLargestBondOrderToNonHydrogenAtoms(); + +Returns largest bond order for an I<Atom> among the bonds to other non-hydrogen atoms +in a molecule. + +=item B<GetLargestRing> + + @RingAtoms = $Atom->GetLargestRing(); + +Returns an array of ring I<Atom> objects corresponding to the largest ring containing I<Atom> +in a molecule. + +=item B<GetLowestCommonValence> + + $LowestCommonValence = $Atom->GetLowestCommonValence(); + +Returns lowest common valence of an I<Atom> which corresponds to either explicity set +I<LowestCommonValence> atom property or highest common valence of the corresponding +element in the periodic table available by B<PerodicTable> module. + +=item B<GetMassNumber> + + $MassNumber = $Aom->GetMassNumber(); + +Returns atomic weight of an B<Atom> which corresponds to either explicity set I<MassNumber> +atom property or mass number of the most abundant natural isotope of the corresponding element +in the periodic table available by B<PeriodicTable> module. + +=item B<GetMissingHydrogens> + + $NumOfMissingHydrogens = $Atom->GetMissingHydrogens(); + +Returns number of missing hydrogens for an I<Atom> in a molecule. This value either +corresponds to explicitly set I<ImplicitHydrogens> atom property or calculated as the +difference between the value of potential total valence and sum of bond orders to +both hydrogen and non-hydrogen atom neighbors. + +=item B<GetNeighbors> + + $NumOfNeighbors = $Atom->GetNeighbors(); + @Neighbors = $Atom->GetNeighbors(); + +Returns number of neighbor atoms or an array of I<Atom> objects corresponding to all +atoms bonded to an I<Atom> in a molecule. + +=item B<GetNeighborsUsingAtomSpecification> + + @AtomNeighbors = $Atom->GetNeighborsUsingAtomSpecification($AtomSpec); + $NumOfNeighbors = $Atom->GetNeighborsUsingAtomSpecification($AtomSpec); + + @AtomNeighbors = $Atom->GetNeighborsUsingAtomSpecification($AtomSpec, + @ExcludeNeighbors); + +Returns number of neighbor atoms or an array of I<Atom> objects matching atom +specification corresponding to atom neighbors of an I<Atom> in a molecule. Optionally, +I<Atom> neighbors can be excluded from the neighbors list using I<ExcludeNeighbors>. + +Notes: + + o AtomSpecification correspond to any valid AtomicInvariant based atomic specifications + as supported by DoesAtomNeighborhoodMatch method + o Multiple atom specifications can be used in a string delimited by comma + +=item B<GetNonHydrogenAtomNeighbors> + + $NumOfNeighbors = $Atom->GetNonHydrogenAtomNeighbors(); + @Neighbors = $Atom->GetNonHydrogenAtomNeighbors(); + +Returns number of non-hydrogen atoms or an array of B<Atom> objects corresponding to non-hydrogen +atoms bonded to an I<Atom> in a molecule. + +=item B<GetNonHydrogenAtomNeighborsAtomInformation> + + ($NumOfAtomNeighbors, $AtomNeighborsRef, + $NumOfAtomNeighborsType, $AtomNeighborsTypeMapRef) = $Atom-> + GetNonHydrogenAtomNeighborsAtomInformation(); + +Returns atoms information for all non-hydrogen atoms attached to an I<Atom> +in a molecule. + +The following values are returned: + + o Number of non-hydrogen atom neighbors + o A reference to an array containing atom objects corresponding to + non-hydrogen atom neighbors + o Number of different types of non-hydrogen atom neighbors + o A reference to a hash containing atom symbol as key with value + corresponding to its count for non-hydrogen atom neighbors + + +=item B<GetNonHydrogenAtomNeighborsBondInformation> + + ($NumOfBonds, $BondTypeCountMapRef, + $AtomsBondTypesCountMapRef, + $AtomsBondTypeAtomsMap) = $Atom-> + GetNonHydrogenAtomNeighborsBondInformation(); + +Returns bonds information for all non-hydrogen atoms attached to an I<Atom> +in a molecule. + +The following values are returned: + + o Number of bonds to non-hydrogen atom neighbors + o A reference to an array containing bond objects corresponding to + non-hydrogen atom neighbors + o A reference to a hash containing bond type as key with value + corresponding to its count for non-hydrogen atom neighbors. Bond + types are: Single, Double or Triple + o A reference to a hash containing atom symbol as key pointing to bond + type as second key with values corresponding to count of bond types for atom + symbol for non-hydrogen atom neighbors + o A reference to a hash containing atom symbol as key pointing to bond + type as second key with values corresponding to atom objects array involved + in corresponding bond type for atom symbol for non-hydrogen atom neighbors + +=item B<GetNonHydrogenNeighborOfHydrogenAtom> + + $Atom = $Atom->GetNonHydrogenNeighborOfHydrogenAtom(); + +Returns non-hydrogen or heavy atom neighbor of a hydrogen atom in a molecule.. + +=item B<GetNumOfAromaticBondsToHeavyAtoms> + + $NumOfBonds = $Atom->GetNumOfAromaticBondsToHeavyAtoms(); + +Returns number of aromatic bonds from an I<Atom> to other non-hydrogen or heavy atoms in +a molecule. + +=item B<GetNumOfAromaticBondsToNonHydrogenAtoms> + + $NumOfBonds = $Atom->GetNumOfAromaticBondsToNonHydrogenAtoms(); + +Returns number of aromatic bonds from an I<Atom> to other non-hydrogen or heavy atoms in +a molecule. + +=item B<GetNumOfBonds> + + $NumOfBonds = $Atom->GetNumOfBonds(); + +Returns number of bonds from an I<Atom> to other atoms in a molecule. + +=item B<GetNumOfBondsAvailableForHeavyAtoms> + + $NumOfBonds = $Atom->GetNumOfBondsAvailableForHeavyAtoms(); + +Get number of bonds available to form additional bonds with heavy atoms, excluding +any implicit bonds to hydrogens set using I<ImplicitHydrogens> property. + +It's different from number of implicit or missing hydrogens, both of which are equivalent. + +For example, in a SMILES string, [nH] ring atom corresponds to an aromatic nitrogen. +Although the hydrogen specified for n is treated internally as implicit hydrogen and shows +up in missing hydrogen count, it's not available to participate in double bonds to additional +heavy atoms. + +=item B<GetNumOfBondsAvailableForNonHydrogenAtoms> + + $NumOfBonds = $Atom->GetNumOfBondsAvailableForNonHydrogenAtoms(); + +Get number of bonds available to form additional bonds with heavy atoms, excluding +any implicit bonds to hydrogens set using ImplicitHydrogens property. + +=item B<GetNumOfBondsToHeavyAtoms> + + $NumOfBondsToHeavyAtoms = $Atom->GetNumOfBondsToHeavyAtoms(); + +Returns number of bonds from an I<Atom> to other heavy atoms in a molecule. + +=item B<GetNumOfBondsToHydrogenAtoms> + + $NumOfBonds = $Atom->GetNumOfBondsToHydrogenAtoms(); + +Returns number of bonds from an I<Atom> to other hydrogen atoms in a molecule. + +=item B<GetNumOfBondsToNonHydrogenAtoms> + + $NumOfBonds = $Atom->GetNumOfBondsToNonHydrogenAtoms(); + +Returns number of bonds from an I<Atom> to other non-hydrogen atoms in a molecule. + +=item B<GetNumOfBondTypesToHeavyAtoms> + + ($NumOfSingleBonds, $NumOfDoubleBonds, + $NumOfTripleBonds, $NumOfAromaticBonds) = $Atom-> + GetNumOfBondTypesToHeavyAtoms($CountAromaticBonds); + +Get number of single, double, triple, and aromatic bonds from an I<Atom> to all other +non-hydrogen atoms in a molecule. + +Value of I<CountAtomaticBonds> parameter controls whether number of aromatic +bonds is returned; default is not to count aromatic bonds. During counting of +aromatic bonds, the bond marked aromatic is not included in the count +of other bond types. + +=item B<GetNumOfBondTypesToNonHydrogenAtoms> + + ($NumOfSingleBonds, $NumOfDoubleBonds, + $NumOfTripleBonds, $NumOfAromaticBonds) = $Atom-> + GetNumOfBondTypesToNonHydrogenAtoms($CountAromaticBonds); + +Get number of single, double, triple, and aromatic bonds from an I<Atom> to all other +non-hydrogen atoms in a molecule. + +Value of I<CountAtomaticBonds> parameter controls whether number of aromatic +bonds is returned; default is not to count aromatic bonds. During counting of +aromatic bonds, the bond marked aromatic is not included in the count +of other bond types. + +=item B<GetNumOfDoubleBondsToHeavyAtoms> + + $NumOfDoubleBonds = $Atom->GetNumOfDoubleBondsToHeavyAtoms(); + +Returns number of double bonds from an I<Atom> to other heavy atoms or non-hydrogen +atoms in a molecule. + +=item B<GetNumOfDoubleBondsToNonHydrogenAtoms> + + $NumOfDoubleBonds =$Atom->GetNumOfDoubleBondsToNonHydrogenAtoms(); + +Returns number of double bonds from an I<Atom> to other heavy atoms or non-hydrogen +atoms in a molecule. + +=item B<GetNumOfHeavyAtomNeighbors> + + $NumOfNeighbors = $Atom->GetNumOfHeavyAtomNeighbors(); + +Returns number heavy atom neighbors for an I<Atom> in a molecule. + +=item B<GetNumOfHydrogenAtomNeighbors> + + $NumOfNeighbors = $Atom->GetNumOfHydrogenAtomNeighbors(); + +Returns number hydrogens atom neighbors for an I<Atom> in a molecule. + +=item B<GetNumOfMissingHydrogens> + + $NumOfMissingHydrogens = $Atom->GetNumOfMissingHydrogens(); + +Returns number of implicit hydrogens for an I<Atom> in a molecule. This value either +corresponds to explicitly set I<ImplicitHydrogens> atom property or calculated as the +difference between the value of potential total valence and sum of bond orders to +both hydrogen and non-hydrogen atom neighbors. + +=item B<GetNumOfExplicitHydrogens> + + $NumOfExplicitHydrogens = $Atom->GetNumOfExplicitHydrogens(); + +Returns number hydrogens atom neighbors for an I<Atom> in a molecule. + +=item B<GetNumOfHydrogens> + + $NumOfHydrogens = $Atom->GetNumOfHydrogens(); + +Returns total number of hydrogens for an I<Atom> in a molecule including both hydrogen atom +neighbors and implicit hydrogens. + +=item B<GetNumOfImplicitHydrogens> + + $NumOfImplicitHydrogens = $Atom->GetNumOfImplicitHydrogens(); + +Returns number of implicit hydrogens for an I<Atom> in a molecule. This value either +corresponds to explicitly set I<ImplicitHydrogens> atom property or calculated as the +difference between the value of potential total valence and sum of bond orders to +both hydrogen and non-hydrogen atom neighbors. + +=item B<GetNumOfNeighbors> + + $NumOfNeighbors = $Atom->GetNumOfNeighbors(); + +Returns number atom neighbors for an I<Atom> in a molecule. + +=item B<GetNumOfNonHydrogenAtomNeighbors> + + $NumNeighbors = $This->GetNumOfNonHydrogenAtomNeighbors(); + +Returns number non-hydrogens atom neighbors for an I<Atom> in a molecule. + +=item B<GetNumOfRings> + + $NumOfRings = $Atom->GetNumOfRings(); + +Returns number of rings containing I<Atom> in a molecule. + +=item B<GetNumOfRingsWithEvenSize> + + $NumOfRings = $Atom->GetNumOfRingsWithEvenSize(); + +Returns number of rings with even size containing I<Atom> in a molecule. + +=item B<GetNumOfRingsWithOddSize> + + $NumOfRings = $Atom->GetNumOfRingsWithOddSize(); + +Returns number of rings with odd size containing I<Atom> in a molecule. + +=item B<GetNumOfRingsWithSize> + + $NumOfRings = $Atom->GetNumOfRingsWithSize($RingSize); + +Returns number of rings with specific I<RingSize> containing I<Atom> in a molecule. + +=item B<GetNumOfRingsWithSizeGreaterThan> + + $NumOfRings = $Atom->GetNumOfRingsWithSizeGreaterThan($RingSize); + +Returns number of rings with size greater than specific I<RingSize> containing I<Atom> +in a molecule. + +=item B<GetNumOfRingsWithSizeLessThan> + + $NumOfRings = $Atom->GetNumOfRingsWithSizeLessThan($RingSize); + +Returns number of rings with size less than specific I<RingSize> containing I<Atom> in a molecule. + +=item B<GetNumOfSigmaAndPiBondsToHeavyAtoms> + + ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom-> + GetNumOfSigmaAndPiBondsToHeavyAtoms(); + +Get number of sigma and pi bonds from an I<Atom> to all other non-hydrogen +atoms in a molecule. + +Sigma and pi bonds are counted using the following methodology: a single bond +correspond to one sigma bond; a double bond contributes one to sigma bond count +and one to pi bond count; a triple bond contributes one to sigma bond count and +two to pi bond count. + + +=item B<GetNumOfSigmaAndPiBondsToNonHydrogenAtoms> + + ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom-> + GetNumOfSigmaAndPiBondsToNonHydrogenAtoms(); + +Get number of sigma and pi bonds from an I<Atom> to all other non-hydrogen +atoms in a molecule. + +Sigma and pi bonds are counted using the following methodology: a single bond +correspond to one sigma bond; a double bond contributes one to sigma bond count +and one to pi bond count; a triple bond contributes one to sigma bond count and +two to pi bond count. + +=item B<GetNumOfSingleBondsToNonHydrogenAtoms> + + $NumOfSingleBonds =$Atom->GetNumOfSingleBondsToNonHydrogenAtoms(); + +Returns number of single bonds from an I<Atom> to other heavy atoms or non-hydrogen +atoms in a molecule. + +=item B<GetNumOfSingleBondsToHeavyAtoms> + + $NumOfSingleBonds = $Atom->GetNumOfSingleBondsToHeavyAtoms(); + +Returns number of single bonds from an I<Atom> to other heavy atoms or non-hydrogen +atoms in a molecule. + +=item B<GetNumOfTripleBondsToNonHydrogenAtoms> + + $NumOfTripleBonds =$Atom->GetNumOfTripleBondsToNonHydrogenAtoms(); + +Returns number of triple bonds from an I<Atom> to other heavy atoms or non-hydrogen +atoms in a molecule. + +=item B<GetNumOfTripleBondsToHeavyAtoms> + + $NumOfTripleBonds = $Atom->GetNumOfTripleBondsToHeavyAtoms(); + +Returns number of triple bonds from an I<Atom> to other heavy atoms or non-hydrogen +atoms in a molecule. + +=item B<GetPeriodNumber> + + $PeriodNumber = $Atom->GetPeriodNumber(); + +Returns periodic table period number for an I<Atom> in a molecule with a valid atomic number . + +=item B<GetRings> + + @Rings = $Aotm->GetRings(); + +Returns an array of references to arrays containing ring atoms corressponding to all rings containing +I<Atom> in a molecule. + +=item B<GetRingsWithEvenSize> + + @Rings = $Aotm->GetRingsWithEvenSize(); + +Returns an array of references to arrays containing ring atoms corressponding to all rings with even size +containing I<Atom> in a molecule. + +=item B<GetRingsWithOddSize> + + @Rings = $Aotm->GetRingsWithOddSize(); + +Returns an array of references to arrays containing ring atoms corressponding to all rings with odd size +containing I<Atom> in a molecule. + +=item B<GetRingsWithSize> + + @Rings = $Aotm->GetRingsWithSize($RingSize); + +Returns an array of references to arrays containing ring atoms corressponding to all rings with specific +I<RingSize >containing I<Atom> in a molecule. + +=item B<GetRingsWithSizeGreaterThan> + + @Rings = $Aotm->GetRingsWithSizeGreaterThan($RingSize); + +Returns an array of references to arrays containing ring atoms corressponding to all rings with size +greater than specific I<RingSize >containing I<Atom> in a molecule. + +=item B<GetRingsWithSizeLessThan> + + @Rings = $Aotm->GetRingsWithSizeLessThan($RingSize); + +Returns an array of references to arrays containing ring atoms corressponding to all rings with size +less than specific I<RingSize >containing I<Atom> in a molecule. + +=item B<GetSizeOfLargestRing> + + $Size = $Atom->GetSizeOfLargestRing(); + +Returns size of the largest ring containing I<Atom> in a molecule. + +=item B<GetSizeOfSmallestRing> + + $Size = $Atom->GetSizeOfSmallestRing(); + +Returns size of the smallest ring containing I<Atom> in a molecule. + +=item B<GetSmallestRing> + + @RingAtoms = $Atom->GetSmallestRing(); + +Returns an array of ring I<Atom> objects corresponding to the largest ring containing I<Atom> +in a molecule. + +=item B<GetSpinMultiplicity> + + $SpinMultiplicity = $Atom->GetSpinMultiplicity(); + +Returns spin multiplicity of an I<Atom> corresponding to one of these three +values: explicitly set B<SpinMultiplicity> property value; calculated from +B<FreeRadicalElectrons> property; value of 0. + +The B<SpinMultiplicity> is calculate from I<FreeRadicalElectrons> property as +follows: + + FreeRadicalElectrons: 1; SpinMultiplicity: 2 + FreeRadicalElectrons: 2; SpinMultiplicity: 1 + FreeRadicalElectrons: other; SpinMultiplicity: 0 + +=item B<GetSumOfBondOrders> + + $SumBondOrders = $Atom->GetSumOfBondOrders(); + +Returns sum of bond orders corresponding to all atoms bonded to an I<Atom> in a molecule. + +=item B<GetSumOfBondOrdersToHeavyAtoms> + + $SumBondOrders = $Atom->GetSumOfBondOrdersToHeavyAtoms(); + +Returns sum of bond orders corresponding to all heavy atoms bonded to an I<Atom> in a molecule. + +=item B<GetSumOfBondOrdersToHydrogenAtoms> + + $SumBondOrders = $Atom->GetSumOfBondOrdersToHydrogenAtoms(); + +Returns sum of bond orders corresponding to all hydrogen atoms bonded to an I<Atom> in a molecule. + +=item B<GetSumOfBondOrdersToNonHydrogenAtoms> + + $SumBondOrders = $Atom->GetSumOfBondOrdersToNonHydrogenAtoms(); + +Returns sum of bond orders corresponding to all non-hydrogen atoms bonded to an I<Atom> +in a molecule. + +=item B<GetValence> + + $Valence = $Atom->GetValence(); + +Returns valence of an I<Atom> in a molecule. Valence corresponds to number of electrons used +by an atom in bonding: + + Valence = ValenceElectrons - ValenceFreeElectrons = BondingElectrons + +Single, double and triple bonds with bond orders of 1, 2, and 3 correspond to +contribution of 1, 2, and 3 bonding electrons. So: + + Valence = SumOfBondOrders + NumOfMissingHydrogens + FormalCharge + +where positive and negative values of FormalCharge increase and decrease the number of bonding +electrons, respectively. + +The current release of MayaChemTools supports the following three valence models, which +are used during calculation of implicit hydrogens: MDLValenceModel, DaylightValenceModel, +InternalValenceModel or MayaChemToolsValenceModel. + +Notes: + + . Missing hydrogens are included in the valence. + . For neutral molecules, valence and sum of bond orders are equal. + . For molecules containing only single bonds, SumOfBondOrders and + NumOfBonds are equal. + . Free radical electrons lead to the decrease in valence. For atoms with + explicit assignment of SpinMultiplicity property values corresponding to + Singlet (two unparied electrons corresponding to one spin state), Doublet + (free radical; an unpaired electron corresponding to two spin states), + and Triplet (two unparied electrons corresponding to three spin states; + divalent carbon atoms (carbenes)), FreeRadicalElectrons are calculated as follows: + + SpinMultiplicity: Doublet(2); FreeRadicalElectrons: 1 (one valence + electron not available for bonding) + SpinMultiplicity: Singlet(1)/Triplet(3); FreeRadicalElectrons: 2 (two + valence electrons not available for bonding) + +=item B<GetValenceElectrons> + + $ValenceElectrons = $Atom->GetValenceElectrons(); + +Returns valence electrons for an B<Atom> which corresponds to either explicity set I<ValenceElectrons> +atom property or valence electrons for the corresponding element in the periodic table available by +B<PeriodicTable> module. + +=item B<GetValenceFreeElectrons> + + $ValenceFreeElectrons = $Atom->GetValenceFreeElectrons(); + $ValenceFreeElectrons = $Atom->GetValenceFreeElectrons( + $ExcludeFreeRadicalElectrons); + +Returns valence frees electrons for an B<Atom> in a molecule. It corresponds to: + + ValenceElectrons - Valence + or + ValenceElectrons - NumOfMissingHydrogens - SumOfBondOrders - FormalCharge + +Free radical electrons are included in the valence free electrons count by default. + +Examples: + + NH3: ValenceFreeElectrons = 5 - 3 = 5 - 3 - 0 - 0 = 2 + NH2: ValenceFreeElectrons = 5 - 3 = 5 - 2 - 1 - 0 = 2 + NH4+; ValenceFreeElectrons = 5 - 5 = 5 - 4 - 0 - 1 = 0 + NH3+; ValenceFreeElectrons = 5 - 5 = 5 - 3 - 1 - 1 = 0 + C(=O)O- : ValenceFreeElectrons on O- = 6 - 0 = 6 - 1 - 0 - (-1) = 6 + C(=O)O- : ValenceFreeElectrons on =O = 6 - 2 = 6 - 2 - 0 - 0 = 4 + +=item B<GetX> + + $X = $Atom->GetX(); + +Returns value of X-coordinate for an I<Atom>. + +=item B<GetXYZ> + + @XYZ = $Atom->GetXYZ(); + $XYZRef = $Atom->GetXYZ(); + +Returns an array or a reference to an array containing values for I<Atom> coordinates. + +=item B<GetXYZVector> + + $XYZVector = $Atom->GetXYZVector(); + +Returns a I<Vector> object containing values for I<Atom> coordinates + +=item B<GetY> + + $Y = $Atom->GetY(); + +Returns value of Y-coordinate for an I<Atom>. + +=item B<GetZ> + + $Z = $Atom->GetZ(); + +Returns value of Z-coordinate for an I<Atom>. + +=item B<IsAmideCarbon> + + $Status = $Atom->IsAmideCarbon(); + +Returns 1 or 0 based on whether it's amide carbon I<Atom>. + +An amide group is defineds as: + + R-C(=O)-N(-R')-R'' + +where: + + o R = Hydrogen or groups of atoms attached through carbon + o R' = Hydrogens or groups of atoms attached through carbon or + hetro atoms + o R'' = Hydrogens or groups of atoms attached through carbon or + hetro atoms + +=item B<IsAmideNitrogen> + + $Status = $Atom->IsAmideNitrogen(); + +Returns 1 or 0 based on whether it's amide nitrogen I<Atom>. + +=item B<IsAromatic> + + $Status = $Atom->IsAromatic(); + +Returns 1 or 0 based on whether it's an aromatic I<Atom>. + +=item B<IsArsenic> + + $Status = $Atom->IsArsenic(); + +Returns 1 or 0 based on whether it's an arsenic I<Atom>. + +=item B<IsBondedToAtom> + + $Status = $Atom->IsBondedToAtom($OtherAtom); + +Returns 1 or 0 based on whether I<Atom> is bonded to I<OtherAtom>. + +=item B<IsBromine> + + $Status = $Atom->IsBromine(); + +Returns 1 or 0 based on whether it's a bromine I<Atom>. + +=item B<IsCarbon> + + $Status = $Atom->IsCarbon(); + +Returns 1 or 0 based on whether it's a carbon I<Atom>. + +=item B<IsCarboxylCarbon> + + $Status = $Atom->IsCarboxylCarbon(); + +Returns 1 or 0 based on whether it's a carboxyl carbon atom in carboxyl group: +R-C(=O)-OH. + +=item B<IsCarboxylOxygen> + + $Status = $Atom->IsCarboxylOxygen(); + +Returns 1 or 0 based on whether it's a carboxyl oxygen atom in carboxyl group: +R-C(=O)-OH. + +=item B<IsCarboxylateCarbon> + + $Status = $Atom->IsCarboxylateCarbon(); + +Returns 1 or 0 based on whether it's a carboxylate carbon atom in carboxyl group: +R-C(=O)-O-. + +=item B<IsCarboxylateOxygen> + + $Status = $Atom->IsCarboxylateOxygen(); + +Returns 1 or 0 based on whether it's a carboxylate oxygen atom in carboxyl group: +R-C(=O)-O-. + +=item B<IsChlorine> + + $Status = $Atom->IsChlorine(); + +Returns 1 or 0 based on whether it's a chlorine I<Atom>. + +=item B<IsFluorine> + + $Status = $Atom->IsFluorine(); + +Returns 1 or 0 based on whether it's a fluorine I<Atom>. + +=item B<IsFunctionalClassType> + + $Status =$Atom->IsFunctionalClassType($Type); + +Returns 1 or 0 based on whether it's a specified functional class I<Type>. + +The current release of MayaChemTools supports following abbreviations and descriptive +names for I<FunctionalClassType>: + + HBD: HydrogenBondDonor + HBA: HydrogenBondAcceptor + PI : PositivelyIonizable + NI : NegativelyIonizable + Ar : Aromatic + Hal : Halogen + H : Hydrophobic + RA : RingAtom + CA : ChainAtom + +The following definitions are used to determine functional class types: [ Ref 60-61, Ref 65-66 ]: + + HydrogenBondDonor: NH, NH2, OH + HydrogenBondAcceptor: N[!H], O + PositivelyIonizable: +, NH2 + NegativelyIonizable: -, C(=O)OH, S(=O)OH, P(=O)OH + +=item B<IsGuadiniumCarbon> + + $Status = $Atom->IsGuadiniumCarbon(); + +Returns 1 or 0 based on whether it's a guadinium carbon in guadinium group by +checking its neighbors for a nitrogen in guadinium group. + +=item B<IsGuadiniumNitrogen> + + $Status = $Atom->IsGuadiniumNitrogen(); + +Returns 1 or 0 based on whether it's a guadinium nitrogen in guadinium group. + +A guadinium group is defined as: + + R2N-C(=NR)-(NR2) or R2N-C(=NR2+)-(NR2) + +where: + + o R = Hydrogens or group of atoms attached through carbon + o Only one of the three nitrogens has a double bond to carbon + and has optional formal charge allowing it to be neutral or charged state + +=item B<IsHBondAcceptor> + + $Status =$Atom->IsHBondAcceptor(); + $Status =$Atom->IsHBondAcceptor($HydrogenBondsType); + +Returns 1 or 0 based on whether it's a hydrogen bond acceptor I<Atom>. + +=item B<IsHBondDonor> + + $Status =$Atom->IsHBondDonor(); + $Status =$Atom->IsHBondDonor($HydrogenBondsType); + +Returns 1 or 0 based on whether it's a hydrogen bond donor I<Atom>. + +=item B<IsHydrogenBondAcceptor> + + $Status =$Atom->IsHydrogenBondAcceptor(); + $Status =$Atom->IsHydrogenBondAcceptor($HydrogenBondsType); + +Returns 1 or 0 based on whether it's a hydrogen bond acceptor I<Atom>. + +=item B<IsHydrogenBondDonor> + + $Status =$Atom->IsHydrogenBondDonor(); + $Status =$Atom->IsHydrogenBondDonor($HydrogenBondsType); + +Returns 1 or 0 based on whether it's a hydrogen bond donor I<Atom>. + +The current release of MayaChemTools supports identification of two types of hydrogen bond +donor and acceptor atoms with these names: + + HBondsType1 or HydrogenBondsType1 + HBondsType2 or HydrogenBondsType2 + +The names of these hydrogen bond types are rather arbitrary. However, their definitions have +specific meaning and are as follows: + + HydrogenBondsType1 [ Ref 60-61, Ref 65-66 ]: + + Donor: NH, NH2, OH - Any N and O with available H + Acceptor: N[!H], O - Any N without available H and any O + + HydrogenBondsType2 [ Ref 91 ]: + + Donor: NH, NH2, OH - N and O with available H + Acceptor: N, O - And N and O + +By default, I<HydrogenBondsType1> is used to calculate number hydrogen bond donor +and acceptor atoms. I<HydrogenBondsType2> corresponds to B<RuleOf5> definition +of hydrogen bond donors and acceptors. + +=item B<IsHalogen> + + $Status =$Atom->IsHalogen(); + +Returns 1 or 0 based on whether it's a halogen I<Atom>. + +=item B<IsHeteroAtom> + + $Status = $Atom->IsHeteroAtom(); + +Returns 0 or 1 based on whether it's a hetro I<Atom>. Following atoms are considered hetro atoms: +B<N, O, F, P, S, Cl, Br, I>. + +=item B<IsHydrogen> + + $Status = $Atom->IsHydrogen(); + +Returns 1 or 0 based on whether it's a hydrogen I<Atom>. + +=item B<IsHydrophobic> + + $Status =$Atom->IsHydrophobic(); + +Returns 1 or 0 based on whether it's a hydrophobic I<Atom>. + +=item B<IsInRing> + + $Status = $Atom->IsInRing(); + +Returns 1 or 0 based on whether I<Atom> is present in a ring. + +=item B<IsInRingOfSize> + + $Status = $Atom->IsInRingOfSize($Size); + +Returns 1 or 0 based on whether I<Atom> is present in a ring of specific I<Size>. + +=item B<IsIodine> + + $Status = $Atom->IsIodine(); + +Returns 1 or 0 based on whether it's an iodine I<Atom>. + +=item B<IsIsotope> + + $Status =$Atom->IsIsotope(); + +Returns 1 or 0 based on whether it's an isotope I<Atom>. + +=item B<IsLipophilic> + + $Status =$Atom->IsLipophilic(); + +Returns 1 or 0 based on whether it's a lipophilic I<Atom>. + +=item B<IsMetallic> + + $Status = $Atom->IsMetallic(); + +Returns 1 or 0 based on whether it's a metallic I<Atom>. + +=item B<IsNegativelyIonizable> + + $Status =$Atom->IsNegativelyIonizable(); + +Returns 1 or 0 based on whether it's a negatively ionizable atom I<Atom>. + +=item B<IsNitrogen> + + $Status = $Atom->IsNitrogen(); + +Returns 1 or 0 based on whether it's a nitrogen I<Atom>. + +=item B<IsNonCarbonOrHydrogen> + + $Status =$Atom->IsNonCarbonOrHydrogen(); + +Returns 1 or 0 based on whether it's not a carbon or hydrogen I<Atom>. + +=item B<IsNotInRing> + + $Status = $Atom->IsNotInRing(); + +Returns 1 or 0 based on whether I<Atom> is not present in a ring. + +=item B<IsOnlyInOneRing> + + $Status = $Atom->IsOnlyInOneRing(); + +Returns 1 or 0 based on whether I<Atom> is only present in one ring. + +=item B<IsOxygen> + + $Status = $Atom->IsOxygen(); + +Returns 0 or 1 based on whether it's an oxygen I<Atom>. + +=item B<IsPhosphorus> + + $Status = $Atom->IsPhosphorus(); + +Returns 0 or 1 based on whether it's a phosphorus I<Atom>. + +=item B<IsPhosphateOxygen> + + $Status = $Atom->IsPhosphateOxygen(); + +Returns 1 or 0 based on whether it's a phosphate oxygen in phosphate group. + +A phosphate group is defined as: + + AO-(O=)P(-OA)-OA + +Where: + + A - Any group of atoms including hydrogens + +=item B<IsPhosphatePhosphorus> + + $Status = $Atom->IsPhosphatePhosphorus(); + +Returns 1 or 0 based on whether it's a phosphate phosphorus in phosphate group. + +=item B<IsPolarAtom> + + $Status = $Atom->IsPolarAtom(); + +Returns 0 or 1 based on whether it's a polar I<Atom>. Following atoms are considered polar atoms: +B<N, O, P, S>. + +=item B<IsPolarHydrogen> + + $Status = $Atom->IsPolarHydrogen(); + +Returns 0 or 1 based on whether it's a hydrogen I<Atom> bonded to a polar atom. + +=item B<IsPositivelyIonizable> + + $Status =$Atom->IsPositivelyIonizable(); + +Returns 1 or 0 based on whether it's a positively ionizable I<Atom>. + +=item B<IsSaturated> + + $Status = $Atom->IsSaturated(); + +Returns 1 or 0 based on whether it's a saturated I<Atom>. An atom attached +to other atoms with only single bonds is considered a saturated atom. + +=item B<IsSelenium> + + $Status = $Atom->IsSelenium(); + +Returns 0 or 1 based on whether it's a selenium I<Atom>. + +=item B<IsStereoCenter> + + $Status = $Atom->IsStereoCenter(); + +Returns 0 or 1 based on whether it's marked as a stero center I<Atom> by explicit setting +of I<StereoCenter> atom propert to value of I<1>. + +=item B<IsSilicon> + + $Status = $Atom->IsSilicon(); + +Returns 0 or 1 based on whether it's a silicon I<Atom>. + +=item B<IsSulfur> + + $Status = $Atom->IsSulfur(); + +Returns 0 or 1 based on whether it's a sulfur I<Atom>. + +=item B<IsSulphur> + + $Status = $Atom->IsSulphur(); + +Returns 0 or 1 based on whether it's a sulfur I<Atom>. + +=item B<IsTellurium> + + $Status = $Atom->IsTellurium(); + +Returns 0 or 1 based on whether it's a tellurium I<Atom>. + +=item B<IsTerminal> + + $Status = $Atom->IsTerminal(); + +Returns 0 or 1 based on whether it's a terminal I<Atom> attached to no +more than one non-hydrogen atom. + +=item B<IsUnsaturated> + + $Status = $Atom->IsUnsaturated(); + +Returns 1 or 0 based on whether it's as unsaturated I<Atom>. An atom attached +to other atoms with at least one non-single bond is considered an unsaturated atom. + +=item B<IsTopologicalPharmacophoreType> + + $Status =$Atom->IsTopologicalPharmacophoreType(); + +Returns 1 or 0 based on whether it's any of the supportyed topological pharmacophore +I<Atom> type. See I<IsFunctionalClassType> for a list of supported types. + +=item B<SetAtomSymbol> + + $Atom->SetAtomSymbol($AtomicSymbol); + +Sets atom symbol for I<Atom> and returns I<Atom> object. The appropriate atomic number is also +set automatically. + +=item B<SetAtomicNumber> + + $Atom->SetAtomicNumber($AtomicNumber); + +Sets atomic number for I<Atom> and returns I<Atom> object. The appropriate atom symbol is also +set automatically. + +=item B<SetMassNumber> + + $Atom->SetMassNumber($MassNumber); + +Sets mass number for I<Atom> and returns I<Atom> object. + +=item B<SetStereoCenter> + + $Atom->SetStereoCenter($StereoCenter); + +Sets stereo center for I<Atom> and returns I<Atom> object. + +=item B<SetStereochemistry> + + $Atom->SetStereochemistry($Stereochemistry); + +Sets stereo chemistry for I<Atom> and returns I<Atom> object. + +=item B<SetX> + + $Atom->SetX($Value); + +Sets X-coordinate value for I<Atom> and returns I<Atom> object. + +=item B<SetXYZ> + + $Atom->SetXYZ(@XYZValues); + $Atom->SetXYZ($XYZValuesRef); + $Atom->SetXYZ($XYZVector); + +Sets I<Atom> coordinates using an array, reference to an array or a I<Vector> object and +returns I<Atom> object. + +=item B<SetY> + + $Atom->SetY($Value); + +Sets Y-coordinate value for I<Atom> and returns I<Atom> object. + +=item B<SetZ> + + $Atom->SetZ($Value); + +Sets Z-coordinate value for I<Atom> and returns I<Atom> object. + +=item B<StringifyAtom> + + $AtomString = $Atom->StringifyAtom(); + +Returns a string containing information about I<Atom> object. + +=back + +=head1 AUTHOR + +Manish Sud <msud@san.rr.com> + +=head1 SEE ALSO + +Bond.pm, Molecule.pm, MoleculeFileIO.pm + +=head1 COPYRIGHT + +Copyright (C) 2015 Manish Sud. All rights reserved. + +This file is part of MayaChemTools. + +MayaChemTools is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the Free +Software Foundation; either version 3 of the License, or (at your option) +any later version. + +=cut