MayaChemTools

   1 package Bond;
   2 #
   3 # $RCSfile: Bond.pm,v $
   4 # $Date: 2011/12/16 00:04:11 $
   5 # $Revision: 1.31 $
   6 #
   7 # Author: Manish Sud <msud@san.rr.com>
   8 #
   9 # Copyright (C) 2004-2012 Manish Sud. All rights reserved.
  10 #
  11 # This file is part of MayaChemTools.
  12 #
  13 # MayaChemTools is free software; you can redistribute it and/or modify it under
  14 # the terms of the GNU Lesser General Public License as published by the Free
  15 # Software Foundation; either version 3 of the License, or (at your option) any
  16 # later version.
  17 #
  18 # MayaChemTools is distributed in the hope that it will be useful, but without
  19 # any warranty; without even the implied warranty of merchantability of fitness
  20 # for a particular purpose.  See the GNU Lesser General Public License for more
  21 # details.
  22 #
  23 # You should have received a copy of the GNU Lesser General Public License
  24 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
  25 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
  26 # Boston, MA, 02111-1307, USA.
  27 #
  28 
  29 use strict;
  30 use Carp;
  31 use Exporter;
  32 use Storable ();
  33 use Scalar::Util ();
  34 use ObjectProperty;
  35 
  36 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  37 
  38 @ISA = qw(ObjectProperty Exporter);
  39 @EXPORT = qw();
  40 @EXPORT_OK = qw();
  41 
  42 %EXPORT_TAGS = (all  => [@EXPORT, @EXPORT_OK]);
  43 
  44 # Setup class variables...
  45 my($ClassName, $ObjectID);
  46 _InitializeClass();
  47 
  48 # Overload Perl functions...
  49 use overload '""' => 'StringifyBond';
  50 
  51 # Class constructor...
  52 sub new {
  53   my($Class, %NamesAndValues) = @_;
  54 
  55   # Initialize object...
  56   my $This = {};
  57   bless $This, ref($Class) || $Class;
  58   $This->_InitializeBond();
  59 
  60   $This->_InitializeBondProperties(%NamesAndValues);
  61 
  62   return $This;
  63 }
  64 
  65 # Initialize object data...
  66 #
  67 sub _InitializeBond {
  68   my($This) = @_;
  69   my($ObjectID) = _GetNewObjectID();
  70 
  71   # All other property names and values along with all Set/Get<PropertyName> methods
  72   # are implemented on-demand using ObjectProperty class.
  73   $This->{ID} = $ObjectID;
  74   @{$This->{Atoms}} = ();
  75   $This->{BondOrder} = '';
  76   $This->{BondType} = '';
  77 }
  78 
  79 # Initialize class ...
  80 sub _InitializeClass {
  81   #Class name...
  82   $ClassName = __PACKAGE__;
  83 
  84   # ID to keep track of objects...
  85   $ObjectID = 0;
  86 }
  87 
  88 # Initialize bond properties...
  89 sub _InitializeBondProperties {
  90   my($This, %NamesAndValues) = @_;
  91 
  92   my($Name, $Value, $MethodName);
  93   while (($Name, $Value) = each  %NamesAndValues) {
  94     $MethodName = "Set${Name}";
  95     $This->$MethodName($Value);
  96   }
  97 
  98   if (!exists $NamesAndValues{'Atoms'}) {
  99     carp "Warning: ${ClassName}->new: Bond object instantiated without specifying atoms list...";
 100   }
 101   if (!exists $NamesAndValues{'BondOrder'}) {
 102     carp "Warning: ${ClassName}->new: Bond object instantiated without setting bond order...";
 103   }
 104   return $This;
 105 }
 106 
 107 # Setup an explicit SetID method to block setting of ID by AUTOLOAD function...
 108 sub SetID {
 109   my($This, $Value) = @_;
 110 
 111   carp "Warning: ${ClassName}->SetID: Object ID can't be changed: it's used for internal tracking...";
 112 
 113   return $This;
 114 }
 115 
 116 # Setup an explicit SetMolecule method to block setting of ID by AUTOLOAD function...
 117 sub SetMolecule {
 118   my($This, $Value) = @_;
 119 
 120   carp "Warning: ${ClassName}->SetMolecule: Molecule property can't be changed: it's used for internal tracking...";
 121 
 122   return $This;
 123 }
 124 
 125 # Assign bond to  molecule...
 126 sub _SetMolecule {
 127   my($This, $Molecule) = @_;
 128 
 129   $This->{Molecule} = $Molecule;
 130 
 131   # Weaken the reference to disable increment of reference count; otherwise,
 132   # it it becomes a circular reference and destruction of Molecule object doesn't
 133   # get initiated which in turn disables destruction of bond object.
 134   #
 135   Scalar::Util::weaken($This->{Molecule});
 136 
 137   return $This;
 138 }
 139 
 140 # Set bond atoms...
 141 sub SetAtoms {
 142   my($This, @Values) = @_;
 143 
 144   if (!@Values) {
 145     croak "Error: ${ClassName}->SetAtoms: No atoms specified...";
 146   }
 147 
 148   my($FirstValue, $TypeOfFirstValue, $Atom1, $Atom2, $AtomID1, $AtomID2);
 149   $FirstValue = $Values[0];
 150   $TypeOfFirstValue = ref $FirstValue;
 151 
 152   if ($TypeOfFirstValue =~ /^ARRAY/) {
 153     # Initialize using array refernce...
 154     if (@{$FirstValue} != 2) {
 155       croak "Warning: ${ClassName}->SetAtoms: Number of atoms specified in bond object is not equal to 2...";
 156     }
 157     ($Atom1, $Atom2) = @{$FirstValue};
 158   }
 159   else {
 160     # It's a list of values...
 161     if (@Values != 2) {
 162       croak "Warning: ${ClassName}->SetAtoms: Number of atoms specified in bond object is not equal to 2...";
 163     }
 164     ($Atom1, $Atom2) = @Values;
 165     push @{$This->{Atoms}}, @Values;
 166   }
 167 
 168   $AtomID1 = $Atom1->GetID(); $AtomID2 = $Atom2->GetID();
 169   if ($AtomID1 == $AtomID2) {
 170       croak "Warning: ${ClassName}->SetAtoms: Can't specify same atoms to create a bond...";
 171   }
 172 
 173   if ($AtomID1 < $AtomID2) {
 174     push @{$This->{Atoms}}, ($Atom1, $Atom2);
 175   }
 176   else {
 177     push @{$This->{Atoms}}, ($Atom2, $Atom1);
 178   }
 179 
 180   return $This;
 181 }
 182 
 183 # Get bond atoms as array. In scalar context, return number of atoms involved in
 184 # bond...
 185 #
 186 sub GetAtoms {
 187   my($This) = @_;
 188 
 189   return wantarray ? @{$This->{Atoms}} : scalar @{$This->{Atoms}};
 190 }
 191 
 192 # Get atom bonded to specified atom...
 193 sub GetBondedAtom {
 194   my($This, $Atom) = @_;
 195   my($Atom1, $Atom2, $AtomID1, $AtomID2, $AtomID);
 196 
 197   ($Atom1, $Atom2) = $This->GetAtoms();
 198   $AtomID1 = $Atom1->GetID(); $AtomID2 = $Atom2->GetID(); $AtomID = $Atom->GetID();
 199 
 200   return ($AtomID1 == $AtomID) ? $Atom2 : (($AtomID2 == $AtomID) ? $Atom1 : undef) ;
 201 }
 202 
 203 # Get common atom between two bonds...
 204 sub GetCommonAtom {
 205   my($This, $Other) = @_;
 206   my($Atom1, $Atom2, $AtomID1, $AtomID2, $OtherAtom1, $OtherAtom2, $OtherAtomID1, $OtherAtomID2);
 207 
 208   ($Atom1, $Atom2) = $This->GetAtoms();
 209   $AtomID1 = $Atom1->GetID(); $AtomID2 = $Atom2->GetID();
 210 
 211   ($OtherAtom1, $OtherAtom2) = $Other->GetAtoms();
 212   $OtherAtomID1 = $OtherAtom1->GetID(); $OtherAtomID2 = $OtherAtom2->GetID();
 213 
 214   return ($AtomID1 == $OtherAtomID1 || $AtomID1 == $OtherAtomID2) ? $Atom1 : (($AtomID2 == $OtherAtomID1 || $AtomID2 == $OtherAtomID2) ? $Atom2 : undef) ;
 215 }
 216 
 217 # Set bond order...
 218 #
 219 # Possible BondOrder are: 1 = Single, 1.5 = Atomatic, 2 = Double, 3 = Triple, 4 = Quadruple.
 220 #
 221 # Possible BondType for different BondOrders are:
 222 #
 223 # 1 : Single, SingleWedge (Up), SingleHash (Down), SingleWavy, Dative
 224 # 2 : Double, DoubleCross (Cis/Trans)
 225 # 3 : Triple
 226 # 4 : Quadruple
 227 # 1.5 : Aromatic (Single/Double), Tautomeric(Single/Double), Resonance (Single/Double)
 228 #
 229 # Notes:
 230 #   . BondType property is automatially assiged using default BondType values for
 231 #     specified BondOrder.
 232 #   . BondType values can also be explicit set.
 233 #   . To make bonds aromatic in a ring, explicitly set "Aromatic" property for bond/atoms and make sure
 234 #     apporpriate BondOrder values are assgined.
 235 #   . Dative bond types are treated as single bond types with explicit formal charge of + and - on first
 236 #     and second bond atoms.
 237 #
 238 sub SetBondOrder {
 239   my($This, $BondOrder) = @_;
 240 
 241   if ($BondOrder !~ /^(1|1.5|2|3|4)$/) {
 242     croak "Error: ${ClassName}->SetBondOrder: BondOrder value $BondOrder is not valid. Supported values: 1, 1.5, 2, 3, 4..";
 243   }
 244 
 245   # Set bond order and type...
 246   my($BondType);
 247 
 248   BONDORDER: {
 249       if ($BondOrder == 1) {$BondType = 'Single'; last BONDORDER; }
 250       if ($BondOrder == 1.5) {$BondType = 'Aromatic'; last BONDORDER; }
 251       if ($BondOrder == 2) {$BondType = 'Double'; last BONDORDER; }
 252       if ($BondOrder == 3) {$BondType = 'Triple'; last BONDORDER; }
 253       if ($BondOrder == 4) {$BondType = 'Quadruple'; last BONDORDER; }
 254       $BondType = '';
 255       $BondOrder = '';
 256   }
 257   $This->{BondType} = $BondType;
 258   $This->{BondOrder} = $BondOrder;
 259 
 260   return $This;
 261 
 262 }
 263 
 264 # Set bond type for a specific bond...
 265 #
 266 sub SetBondType {
 267   my($This, $BondType) = @_;
 268 
 269   if ($BondType !~ /^(Single|SingleWedge|SingleUp|SingleHash|SingleDown|SingleWavy|Dative|Double|DoubleCross|Aromatic|Tautomeric|Triple|Quadruple)$/i) {
 270     croak "Error: ${ClassName}->SetBondType: BondType value $BondType is not valid. Supported values: Single, SingleWedge, SingleUp, SingleHash, SingleDown, SingleWavy, Dative, Double, DoubleCross, Aromatic, Tautomeric, Triple, Quadruple...";
 271   }
 272 
 273   # Make sure its a valid BondType value for BondOrder...
 274   my($BondOrder, $ValidBondType);
 275 
 276   $ValidBondType = 0;
 277   $BondOrder = $This->{BondOrder};
 278   if (!$BondOrder) {
 279     croak "Error: ${ClassName}->SetBondType: BondOrder is empty: It must be set before BondOrder...";
 280   }
 281 
 282   BONDORDER: {
 283       if ($BondOrder == 1 && $BondType =~ /^(Single|SingleWedge|SingleUp|SingleHash|SingleDown|SingleWavy|Dative|Aromatic|Tautomeric)$/i) {$ValidBondType = 1; last BONDORDER; }
 284       if ($BondOrder == 1.5 && $BondType =~ /^(Aromatic|Tautomeric)$/i) {$ValidBondType = 1; last BONDORDER; }
 285       if ($BondOrder == 2 && $BondType =~ /^(Double|DoubleCross|Aromatic|Tautomeric)$/i ) {$ValidBondType = 1; last BONDORDER; }
 286       if ($BondOrder == 3 && $BondType =~ /^(Triple)$/i) {$ValidBondType = 1; last BONDORDER; }
 287       if ($BondOrder == 4 && $BondType =~ /^(Quadruple)$/i) {$ValidBondType = 1; last BONDORDER; }
 288       $ValidBondType = 0;
 289   }
 290 
 291   if (!$ValidBondType) {
 292     croak "Error: ${ClassName}->SetBondType: BondType value, $BondType, is not valid for BondOrder $BondOrder...";
 293   }
 294 
 295   $This->{BondType} = $BondType;
 296 
 297   # Set explicit formal charge for atoms involved in Dative bonds...
 298   if ($BondType =~ /^Dative$/i) {
 299     my($Atom1, $Atom2) = $This->GetAtoms();
 300     $Atom1->SetFormalCharge('1');
 301     $Atom2->SetFormalCharge('-1');
 302   }
 303 
 304   return $This;
 305 }
 306 
 307 # Set bond stereochemistry...
 308 #
 309 # Supported values are:
 310 #
 311 # Z, cis: Highest ranking group using CIP priority scheme on the same side of double bond
 312 # E, trans: Highest ranking group using CIP priority scheme on the same side of double bond
 313 #
 314 sub SetStereochemistry {
 315   my($This, $Stereochemistry) = @_;
 316 
 317   if ($Stereochemistry !~ /^(Z|cis|E|trans)$/i) {
 318     croak "Error: ${ClassName}->SetStereochemistry: Stereochemistry value $Stereochemistry is not valid. Supported values: Z, cis, E, trans..";
 319   }
 320   my($BondOrder);
 321   $BondOrder = $This->{BondOrder};
 322 
 323   if ($BondOrder != 2) {
 324     croak "Error: ${ClassName}->SetStereochemistry: Stereochemistry value, $Stereochemistry,  can't be assigned to bond with  BondOrder value of $BondOrder: It's only valid for double bonds ...";
 325   }
 326 
 327   $This->SetProperty('Stereochemistry', $Stereochemistry);
 328 
 329   return $This;
 330 }
 331 
 332 # Is it a single bond?
 333 sub IsSingle {
 334   my($This) = @_;
 335 
 336   return ($This->{BondOrder} == 1) ? 1 : 0;
 337 }
 338 
 339 # Is it a double bond?
 340 sub IsDouble {
 341   my($This) = @_;
 342 
 343   return ($This->{BondOrder} == 2) ? 1 : 0;
 344 }
 345 
 346 # Is it a triple bond?
 347 sub IsTriple {
 348   my($This) = @_;
 349 
 350   return ($This->{BondOrder} == 3) ? 1 : 0;
 351 }
 352 
 353 # Is aromatic property set for the bond?
 354 sub IsAromatic {
 355   my($This) = @_;
 356   my($Aromatic);
 357 
 358   $Aromatic = $This->GetAromatic();
 359 
 360   return (defined($Aromatic) && $Aromatic) ? 1 : 0;
 361 }
 362 
 363 # Delete bond...
 364 sub DeleteBond {
 365   my($This) = @_;
 366 
 367   # Is this atom in a molecule?
 368   if (!$This->HasProperty('Molecule')) {
 369     # Nothing to do...
 370     return $This;
 371   }
 372   my($Molecule);
 373   $Molecule = $This->GetProperty('Molecule');
 374   $Molecule->DeleteBond($This);
 375 
 376   return $This;
 377 }
 378 
 379 # Copy bond and all its associated data...
 380 sub Copy {
 381   my($This) = @_;
 382   my($Bond);
 383 
 384   $Bond = Storable::dclone($This);
 385 
 386   return $Bond;
 387 }
 388 
 389 # Is bond in a ring?
 390 #
 391 sub IsInRing {
 392   my($This) = @_;
 393 
 394   # Is this bond in a molecule?
 395   if (!$This->HasProperty('Molecule')) {
 396     return undef;
 397   }
 398   my($Molecule);
 399   $Molecule = $This->GetProperty('Molecule');
 400 
 401   return $Molecule->_IsBondInRing($This);
 402 }
 403 
 404 # Is bond not in a ring?
 405 #
 406 sub IsNotInRing {
 407   my($This) = @_;
 408 
 409   # Is this bond in a molecule?
 410   if (!$This->HasProperty('Molecule')) {
 411     return undef;
 412   }
 413   my($Molecule);
 414   $Molecule = $This->GetProperty('Molecule');
 415 
 416   return $Molecule->_IsBondNotInRing($This);
 417 }
 418 
 419 # Is bond only in one ring?
 420 #
 421 sub IsOnlyInOneRing {
 422   my($This) = @_;
 423 
 424   # Is this bond in a molecule?
 425   if (!$This->HasProperty('Molecule')) {
 426     return undef;
 427   }
 428   my($Molecule);
 429   $Molecule = $This->GetProperty('Molecule');
 430 
 431   return $Molecule->_IsBondInOnlyOneRing($This);
 432 }
 433 
 434 # Is bond in a ring of specific size?
 435 #
 436 sub IsInRingOfSize {
 437   my($This, $RingSize) = @_;
 438 
 439   # Is this bond in a molecule?
 440   if (!$This->HasProperty('Molecule')) {
 441     return undef;
 442   }
 443   my($Molecule);
 444   $Molecule = $This->GetProperty('Molecule');
 445 
 446   return $Molecule->_IsBondInRingOfSize($This, $RingSize);
 447 }
 448 
 449 # Get size of smallest ring containing the bond...
 450 #
 451 sub GetSizeOfSmallestRing {
 452   my($This) = @_;
 453 
 454   # Is this bond in a molecule?
 455   if (!$This->HasProperty('Molecule')) {
 456     return undef;
 457   }
 458   my($Molecule);
 459   $Molecule = $This->GetProperty('Molecule');
 460 
 461   return $Molecule->_GetSizeOfSmallestBondRing($This);
 462 }
 463 
 464 # Get size of largest ring containing the bond...
 465 #
 466 sub GetSizeOfLargestRing {
 467   my($This) = @_;
 468 
 469   # Is this bond in a molecule?
 470   if (!$This->HasProperty('Molecule')) {
 471     return undef;
 472   }
 473   my($Molecule);
 474   $Molecule = $This->GetProperty('Molecule');
 475 
 476   return $Molecule->_GetSizeOfLargestBondRing($This);
 477 }
 478 
 479 # Get number of  rings containing the bond...
 480 #
 481 sub GetNumOfRings {
 482   my($This) = @_;
 483 
 484   # Is this bond in a molecule?
 485   if (!$This->HasProperty('Molecule')) {
 486     return undef;
 487   }
 488   my($Molecule);
 489   $Molecule = $This->GetProperty('Molecule');
 490 
 491   return $Molecule->_GetNumOfBondRings($This);
 492 }
 493 
 494 # Get number of  rings with odd size containing the bond...
 495 #
 496 sub GetNumOfRingsWithOddSize {
 497   my($This) = @_;
 498 
 499   # Is this bond in a molecule?
 500   if (!$This->HasProperty('Molecule')) {
 501     return undef;
 502   }
 503   my($Molecule);
 504   $Molecule = $This->GetProperty('Molecule');
 505 
 506   return $Molecule->_GetNumOfBondRingsWithOddSize($This);
 507 }
 508 
 509 # Get number of  rings with even size containing the bond...
 510 #
 511 sub GetNumOfRingsWithEvenSize {
 512   my($This) = @_;
 513 
 514   # Is this bond in a molecule?
 515   if (!$This->HasProperty('Molecule')) {
 516     return undef;
 517   }
 518   my($Molecule);
 519   $Molecule = $This->GetProperty('Molecule');
 520 
 521   return $Molecule->_GetNumOfBondRingsWithEvenSize($This);
 522 }
 523 
 524 # Get number of  rings with specified size containing the bond...
 525 #
 526 sub GetNumOfRingsWithSize {
 527   my($This, $RingSize) = @_;
 528 
 529   # Is this bond in a molecule?
 530   if (!$This->HasProperty('Molecule')) {
 531     return undef;
 532   }
 533   my($Molecule);
 534   $Molecule = $This->GetProperty('Molecule');
 535 
 536   return $Molecule->_GetNumOfBondRingsWithSize($This, $RingSize);
 537 }
 538 
 539 # Get number of  rings with size less than specified containing the bond...
 540 #
 541 sub GetNumOfRingsWithSizeLessThan {
 542   my($This, $RingSize) = @_;
 543 
 544   # Is this bond in a molecule?
 545   if (!$This->HasProperty('Molecule')) {
 546     return undef;
 547   }
 548   my($Molecule);
 549   $Molecule = $This->GetProperty('Molecule');
 550 
 551   return $Molecule->_GetNumOfBondRingsWithSizeLessThan($This, $RingSize);
 552 }
 553 
 554 # Get number of  rings with size greater than specified size containing the bond...
 555 #
 556 sub GetNumOfRingsWithSizeGreaterThan {
 557   my($This, $RingSize) = @_;
 558 
 559   # Is this bond in a molecule?
 560   if (!$This->HasProperty('Molecule')) {
 561     return undef;
 562   }
 563   my($Molecule);
 564   $Molecule = $This->GetProperty('Molecule');
 565 
 566   return $Molecule->_GetNumOfBondRingsWithSizeGreaterThan($This, $RingSize);
 567 }
 568 
 569 # Get all rings as an array of references to arrays containing ring atoms...
 570 #
 571 sub GetRings {
 572   my($This) = @_;
 573 
 574   # Is this bond in a molecule?
 575   if (!$This->HasProperty('Molecule')) {
 576     return undef;
 577   }
 578   my($Molecule);
 579   $Molecule = $This->GetProperty('Molecule');
 580 
 581   return $Molecule->_GetBondRings($This);
 582 }
 583 
 584 # Get smallest ring as an array containing ring atoms...
 585 #
 586 sub GetSmallestRing {
 587   my($This) = @_;
 588 
 589   # Is this bond in a molecule?
 590   if (!$This->HasProperty('Molecule')) {
 591     return undef;
 592   }
 593   my($Molecule);
 594   $Molecule = $This->GetProperty('Molecule');
 595 
 596   return $Molecule->_GetSmallestBondRing($This);
 597 }
 598 
 599 # Get largest ring as an array containing ring atoms...
 600 #
 601 sub GetLargestRing {
 602   my($This) = @_;
 603 
 604   # Is this bond in a molecule?
 605   if (!$This->HasProperty('Molecule')) {
 606     return undef;
 607   }
 608   my($Molecule);
 609   $Molecule = $This->GetProperty('Molecule');
 610 
 611   return $Molecule->_GetLargestBondRing($This);
 612 }
 613 
 614 # Get odd size rings an array of references to arrays containing ring atoms...
 615 #
 616 sub GetRingsWithOddSize {
 617   my($This) = @_;
 618 
 619   # Is this bond in a molecule?
 620   if (!$This->HasProperty('Molecule')) {
 621     return undef;
 622   }
 623   my($Molecule);
 624   $Molecule = $This->GetProperty('Molecule');
 625 
 626   return $Molecule->_GetBondRingsWithOddSize($This);
 627 }
 628 
 629 # Get even size rings an array of references to arrays containing ring atoms...
 630 #
 631 sub GetRingsWithEvenSize {
 632   my($This) = @_;
 633 
 634   # Is this bond in a molecule?
 635   if (!$This->HasProperty('Molecule')) {
 636     return undef;
 637   }
 638   my($Molecule);
 639   $Molecule = $This->GetProperty('Molecule');
 640 
 641   return $Molecule->_GetBondRingsWithEvenSize($This);
 642 }
 643 
 644 # Get rings with specified size  an array of references to arrays containing ring atoms...
 645 #
 646 sub GetRingsWithSize {
 647   my($This, $RingSize) = @_;
 648 
 649   # Is this bond in a molecule?
 650   if (!$This->HasProperty('Molecule')) {
 651     return undef;
 652   }
 653   my($Molecule);
 654   $Molecule = $This->GetProperty('Molecule');
 655 
 656   return $Molecule->_GetBondRingsWithSize($This, $RingSize);
 657 }
 658 
 659 # Get rings with size less than specfied size as an array of references to arrays containing ring atoms...
 660 #
 661 sub GetRingsWithSizeLessThan {
 662   my($This, $RingSize) = @_;
 663 
 664   # Is this bond in a molecule?
 665   if (!$This->HasProperty('Molecule')) {
 666     return undef;
 667   }
 668   my($Molecule);
 669   $Molecule = $This->GetProperty('Molecule');
 670 
 671   return $Molecule->_GetBondRingsWithSizeLessThan($This, $RingSize);
 672 }
 673 
 674 # Get rings with size greater than specfied size as an array of references to arrays containing ring atoms...
 675 #
 676 sub GetRingsWithSizeGreaterThan {
 677   my($This, $RingSize) = @_;
 678 
 679   # Is this bond in a molecule?
 680   if (!$This->HasProperty('Molecule')) {
 681     return undef;
 682   }
 683   my($Molecule);
 684   $Molecule = $This->GetProperty('Molecule');
 685 
 686   return $Molecule->_GetBondRingsWithSizeGreaterThan($This, $RingSize);
 687 }
 688 
 689 # Get next object ID...
 690 sub _GetNewObjectID {
 691   $ObjectID++;
 692   return $ObjectID;
 693 }
 694 
 695 # Return a string containing bond and other properties...
 696 sub StringifyBond {
 697   my($This) = @_;
 698   my($BondString, $ID, $BondOrder, $BondType, $Stereochemistry, $AtomsString, $RingBond, $NumOfRings, $Atom1, $Atom2);
 699 
 700   $ID = $This->GetID();
 701   $BondOrder = $This->GetBondOrder();
 702   if (!defined $BondOrder) {
 703     $BondOrder = "undefined";
 704   }
 705   $BondType = $This->GetBondType();
 706   if (!defined $BondOrder) {
 707     $BondType = "undefined";
 708   }
 709   if (defined($BondOrder) && $BondOrder == 2) {
 710     $Stereochemistry = $This->GetStereochemistry();
 711     if (!defined $Stereochemistry) {
 712       $Stereochemistry = "undefined";
 713     }
 714   }
 715   $RingBond = $This->IsInRing();
 716   if (defined $RingBond) {
 717     $RingBond = $RingBond  ? 'Yes' : 'No';
 718     $NumOfRings = $This->GetNumOfRings();
 719   }
 720   else {
 721     $RingBond = 'undefined';
 722     $NumOfRings = 'undefined';
 723   }
 724 
 725   ($Atom1, $Atom2) = $This->GetAtoms();
 726   $AtomsString = "Atoms: undefined";
 727   if (defined($Atom1) && defined($Atom2)) {
 728     my($Atom, $AtomID, $AtomCount, $AtomName, $AtomSymbol, $AtomicNumber, @BondAtoms);
 729     @BondAtoms = ();
 730     push @BondAtoms, ($Atom1, $Atom2);
 731     $AtomCount = 0;
 732     $AtomsString = "";
 733     for $Atom (@BondAtoms) {
 734       $AtomCount++;
 735       $AtomID = $Atom->GetID();
 736       $AtomName = $Atom->GetName();
 737       $AtomSymbol = $Atom->GetAtomSymbol();
 738       $AtomicNumber = $Atom->GetAtomicNumber();
 739       if ($AtomCount == 1) {
 740         $AtomsString .= "FirstAtom:";
 741       }
 742       else {
 743         $AtomsString .= "; SecondAtom:";
 744       }
 745       $AtomsString .= " [ ID: $AtomID; Name: \"$AtomName\"; AtomSymbol: \"$AtomSymbol\"; AtomicNumber: $AtomicNumber ]";
 746     }
 747   }
 748   $BondString = "Bond: ID: $ID; BondOrder: $BondOrder; BondType: $BondType; RingBond: $RingBond; NumOfBondRings: $NumOfRings";
 749   if (defined($BondOrder) && $BondOrder == 2) {
 750   $BondString .= " Stereochemistry: $Stereochemistry;";
 751   }
 752   $BondString .= " $AtomsString";
 753 
 754   return $BondString;
 755 }
 756