1 package Bond; 2 # 3 # File: Bond.pm 4 # Author: Manish Sud <msud@san.rr.com> 5 # 6 # Copyright (C) 2024 Manish Sud. All rights reserved. 7 # 8 # This file is part of MayaChemTools. 9 # 10 # MayaChemTools is free software; you can redistribute it and/or modify it under 11 # the terms of the GNU Lesser General Public License as published by the Free 12 # Software Foundation; either version 3 of the License, or (at your option) any 13 # later version. 14 # 15 # MayaChemTools is distributed in the hope that it will be useful, but without 16 # any warranty; without even the implied warranty of merchantability of fitness 17 # for a particular purpose. See the GNU Lesser General Public License for more 18 # details. 19 # 20 # You should have received a copy of the GNU Lesser General Public License 21 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or 22 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330, 23 # Boston, MA, 02111-1307, USA. 24 # 25 26 use strict; 27 use Carp; 28 use Exporter; 29 use Storable (); 30 use Scalar::Util (); 31 use ObjectProperty; 32 33 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); 34 35 @ISA = qw(ObjectProperty Exporter); 36 @EXPORT = qw(); 37 @EXPORT_OK = qw(); 38 39 %EXPORT_TAGS = (all => [@EXPORT, @EXPORT_OK]); 40 41 # Setup class variables... 42 my($ClassName, $ObjectID); 43 _InitializeClass(); 44 45 # Overload Perl functions... 46 use overload '""' => 'StringifyBond'; 47 48 # Class constructor... 49 sub new { 50 my($Class, %NamesAndValues) = @_; 51 52 # Initialize object... 53 my $This = {}; 54 bless $This, ref($Class) || $Class; 55 $This->_InitializeBond(); 56 57 $This->_InitializeBondProperties(%NamesAndValues); 58 59 return $This; 60 } 61 62 # Initialize object data... 63 # 64 sub _InitializeBond { 65 my($This) = @_; 66 my($ObjectID) = _GetNewObjectID(); 67 68 # All other property names and values along with all Set/Get<PropertyName> methods 69 # are implemented on-demand using ObjectProperty class. 70 $This->{ID} = $ObjectID; 71 72 # Bond from and to atoms indicate begining and ending bond atoms... 73 $This->{BondFromAtom} = undef; 74 $This->{BondToAtom} = undef; 75 76 $This->{BondOrder} = ''; 77 $This->{BondType} = ''; 78 $This->{BondStereochemistry} = ''; 79 } 80 81 # Initialize class ... 82 sub _InitializeClass { 83 #Class name... 84 $ClassName = __PACKAGE__; 85 86 # ID to keep track of objects... 87 $ObjectID = 0; 88 } 89 90 # Initialize bond properties... 91 sub _InitializeBondProperties { 92 my($This, %NamesAndValues) = @_; 93 94 my($Name, $Value, $MethodName); 95 while (($Name, $Value) = each %NamesAndValues) { 96 $MethodName = "Set${Name}"; 97 $This->$MethodName($Value); 98 } 99 100 if (!exists $NamesAndValues{'Atoms'}) { 101 carp "Warning: ${ClassName}->new: Bond object instantiated without specifying atoms list..."; 102 } 103 if (!exists $NamesAndValues{'BondOrder'}) { 104 carp "Warning: ${ClassName}->new: Bond object instantiated without setting bond order..."; 105 } 106 return $This; 107 } 108 109 # Setup an explicit SetID method to block setting of ID by AUTOLOAD function... 110 sub SetID { 111 my($This, $Value) = @_; 112 113 carp "Warning: ${ClassName}->SetID: Object ID can't be changed: it's used for internal tracking..."; 114 115 return $This; 116 } 117 118 # Setup an explicit SetMolecule method to block setting of ID by AUTOLOAD function... 119 sub SetMolecule { 120 my($This, $Value) = @_; 121 122 carp "Warning: ${ClassName}->SetMolecule: Molecule property can't be changed: it's used for internal tracking..."; 123 124 return $This; 125 } 126 127 # Assign bond to molecule... 128 sub _SetMolecule { 129 my($This, $Molecule) = @_; 130 131 $This->{Molecule} = $Molecule; 132 133 # Weaken the reference to disable increment of reference count; otherwise, 134 # it it becomes a circular reference and destruction of Molecule object doesn't 135 # get initiated which in turn disables destruction of bond object. 136 # 137 Scalar::Util::weaken($This->{Molecule}); 138 139 return $This; 140 } 141 142 # Set bond atoms... 143 sub SetAtoms { 144 my($This, @Values) = @_; 145 146 if (!@Values) { 147 croak "Error: ${ClassName}->SetAtoms: No atoms specified..."; 148 } 149 150 my($FirstValue, $TypeOfFirstValue, $Atom1, $Atom2, $AtomID1, $AtomID2); 151 $FirstValue = $Values[0]; 152 $TypeOfFirstValue = ref $FirstValue; 153 154 if ($TypeOfFirstValue =~ /^ARRAY/) { 155 # Initialize using array refernce... 156 if (@{$FirstValue} != 2) { 157 croak "Warning: ${ClassName}->SetAtoms: Number of atoms specified in bond object is not equal to 2..."; 158 } 159 ($Atom1, $Atom2) = @{$FirstValue}; 160 } 161 else { 162 # It's a list of values... 163 if (@Values != 2) { 164 croak "Warning: ${ClassName}->SetAtoms: Number of atoms specified in bond object is not equal to 2..."; 165 } 166 ($Atom1, $Atom2) = @Values; 167 } 168 169 $AtomID1 = $Atom1->GetID(); $AtomID2 = $Atom2->GetID(); 170 if ($AtomID1 == $AtomID2) { 171 croak "Warning: ${ClassName}->SetAtoms: Can't specify same atoms to create a bond..."; 172 } 173 174 $This->{BondFromAtom} = $Atom1; 175 $This->{BondToAtom} = $Atom2; 176 177 return $This; 178 } 179 180 # Get bond atoms as array. In scalar context, return number of atoms involved in 181 # bond... 182 # 183 sub GetAtoms { 184 my($This) = @_; 185 186 return wantarray ? ($This->{BondFromAtom}, $This->{BondToAtom}) : 2; 187 } 188 189 # Get atom bonded to specified atom... 190 sub GetBondedAtom { 191 my($This, $Atom) = @_; 192 my($Atom1, $Atom2, $AtomID1, $AtomID2, $AtomID); 193 194 ($Atom1, $Atom2) = $This->GetAtoms(); 195 $AtomID1 = $Atom1->GetID(); $AtomID2 = $Atom2->GetID(); $AtomID = $Atom->GetID(); 196 197 return ($AtomID1 == $AtomID) ? $Atom2 : (($AtomID2 == $AtomID) ? $Atom1 : undef) ; 198 } 199 200 # Get common atom between two bonds... 201 sub GetCommonAtom { 202 my($This, $Other) = @_; 203 my($Atom1, $Atom2, $AtomID1, $AtomID2, $OtherAtom1, $OtherAtom2, $OtherAtomID1, $OtherAtomID2); 204 205 ($Atom1, $Atom2) = $This->GetAtoms(); 206 $AtomID1 = $Atom1->GetID(); $AtomID2 = $Atom2->GetID(); 207 208 ($OtherAtom1, $OtherAtom2) = $Other->GetAtoms(); 209 $OtherAtomID1 = $OtherAtom1->GetID(); $OtherAtomID2 = $OtherAtom2->GetID(); 210 211 return ($AtomID1 == $OtherAtomID1 || $AtomID1 == $OtherAtomID2) ? $Atom1 : (($AtomID2 == $OtherAtomID1 || $AtomID2 == $OtherAtomID2) ? $Atom2 : undef) ; 212 } 213 214 # Get bond from atom indicating begining atom of a bond... 215 sub GetBondFromAtom { 216 my($This) = @_; 217 218 return $This->{BondFromAtom}; 219 } 220 221 # Get begin bond atom... 222 sub GetBondBeginAtom { 223 my($This) = @_; 224 225 return $This->GetBondFromAtom(); 226 } 227 228 # Get bond to atom indicating ending atom of a bond... 229 sub GetBondToAtom { 230 my($This) = @_; 231 232 return $This->{BondToAtom}; 233 } 234 235 # Get begin bond atom... 236 sub GetBondEndAtom { 237 my($This) = @_; 238 239 return $This->GetBondToAtom(); 240 } 241 242 # Switch bond from and to atoms... 243 sub SwitchBondFromAndToAtoms { 244 my($This) = @_; 245 my($FromAtom, $ToAtom); 246 247 ($FromAtom, $ToAtom) = $This->GetAtoms(); 248 249 $This->{BondFromAtom} = $ToAtom; 250 $This->{BondToAtom} = $FromAtom; 251 252 return $This; 253 } 254 255 # Set bond order... 256 # 257 # Possible BondOrder are: 0 = None, 1 = Single, 1.5 = Aromatic, 2 = Double, 3 = Triple, 4 = Quadruple, 258 # 5 = Quintuple, 6 = Sextuple, 7 = Septuple 259 # 260 # Possible BondType for different BondOrders are: 261 # 262 # 0 : None, Ionic, Unspecified 263 # 1 : Single, Dative, Coordinate, SingleOrDouble, SingleOrAromatic, Tautomeric 264 # 1.5 : Aromatic, Resonance, SingleOrAromatic, DoubleOrAromatic 265 # 2 : Double, Tautomeric, SingleOrDouble, DoubleOrAromatic 266 # 3 : Triple 267 # 4 : Quadruple 268 # 5 : Quintuple 269 # 6 : Sextuple 270 # 7 : Septuple 271 # 272 # Note: BondType Any is valid for all BondOrders. 273 # 274 # Possible BondStereochemistry values for different BondOrders are: 275 # 276 # 0 : None, Unspecified 277 # 1 : Wedge, Up, Hash, Down, Wavy, WedgeOrHash, UpOrDown, Upward, Downward, None, Unspecified 278 # 2 : Cis, Trans, Z, E, DoubleCross, CisOrTrans, None, Unspecified 279 # 280 # Notes: 281 # . BondType property is automatically assigned using default BondType values for 282 # specified BondOrder. 283 # . BondType values can also be explicit set. 284 # . To make bonds aromatic in a ring, explicitly set "Aromatic" property for bond/atoms and make sure 285 # appropriate BondOrder values are assigned. 286 # . Dative or coordinate bond types are treated as single bond types with explicit formal charge 287 # of + and - on first and second bond atoms. 288 # 289 sub SetBondOrder { 290 my($This, $BondOrder) = @_; 291 292 if ($BondOrder !~ /^(0|1|1.5|2|3|4|5|6|7)$/) { 293 croak "Error: ${ClassName}->SetBondOrder: BondOrder value $BondOrder is not valid. Supported values: 0, 1, 1.5, 2, 3, 4, 5, 6, 7"; 294 } 295 296 # Set bond order and type... 297 my($BondType); 298 299 BONDORDER: { 300 if ($BondOrder == 1) {$BondType = 'Single'; last BONDORDER; } 301 if ($BondOrder == 1.5) {$BondType = 'Aromatic'; last BONDORDER; } 302 if ($BondOrder == 2) {$BondType = 'Double'; last BONDORDER; } 303 if ($BondOrder == 3) {$BondType = 'Triple'; last BONDORDER; } 304 if ($BondOrder == 4) {$BondType = 'Quadruple'; last BONDORDER; } 305 if ($BondOrder == 5) {$BondType = 'Quintuple'; last BONDORDER; } 306 if ($BondOrder == 6) {$BondType = 'Sextuple'; last BONDORDER; } 307 if ($BondOrder == 7) {$BondType = 'Septuple'; last BONDORDER; } 308 $BondType = ''; 309 $BondOrder = 0; 310 } 311 $This->{BondType} = $BondType; 312 $This->{BondOrder} = $BondOrder; 313 314 return $This; 315 316 } 317 318 # Set bond type for a specific bond... 319 # 320 sub SetBondType { 321 my($This, $BondType) = @_; 322 323 if ($BondType !~ /^(None|Ionic|Unspecified|Single|Dative|Coordinate|SingleOrDouble|SingleOrAromatic|Aromatic|Tautomeric|Resonance|DoubleOrAromatic|Double|Triple|Quadruple|Any)$/i) { 324 croak "Error: ${ClassName}->SetBondType: BondType value $BondType is not valid. Supported values: None, Ionic, Unspecified, Single, Dative, Coordinate, SingleOrDouble, SingleOrAromatic, Aromatic, Tautomeric, Resonance, DoubleOrAromatic, Double, Triple, Quadruple, Any..."; 325 } 326 327 # Make sure its a valid BondType value for BondOrder... 328 my($BondOrder, $ValidBondType); 329 330 $ValidBondType = 0; 331 $BondOrder = $This->{BondOrder}; 332 333 BONDORDER: { 334 if ($BondOrder == 0 && $BondType =~ /^(None|Ionic|Unspecified|Any)$/i) {$ValidBondType = 1; last BONDORDER; } 335 if ($BondOrder == 1 && $BondType =~ /^(Single|Dative|Coordinate|SingleOrDouble|SingleOrAromatic|Tautomeric|Any)$/i) {$ValidBondType = 1; last BONDORDER; } 336 if ($BondOrder == 1.5 && $BondType =~ /^(Aromatic|Resonance|SingleOrAromatic|DoubleOrAromatic|Any)$/i) {$ValidBondType = 1; last BONDORDER; } 337 if ($BondOrder == 2 && $BondType =~ /^(Double|SingleOrDouble|DoubleOrAromatic|Tautomeric|Any)$/i ) {$ValidBondType = 1; last BONDORDER; } 338 if ($BondOrder == 3 && $BondType =~ /^(Triple|Any)$/i) {$ValidBondType = 1; last BONDORDER; } 339 if ($BondOrder == 4 && $BondType =~ /^(Quadruple|Any)$/i) {$ValidBondType = 1; last BONDORDER; } 340 if ($BondOrder == 5 && $BondType =~ /^(Quintuple|Any)$/i) {$ValidBondType = 1; last BONDORDER; } 341 if ($BondOrder == 6 && $BondType =~ /^(Sextuple|Any)$/i) {$ValidBondType = 1; last BONDORDER; } 342 if ($BondOrder == 7 && $BondType =~ /^(Septuple|Any)$/i) {$ValidBondType = 1; last BONDORDER; } 343 $ValidBondType = 0; 344 } 345 346 if (!$ValidBondType) { 347 carp "Warning: ${ClassName}->SetBondType: Assigning invalid BondType value, $BondType, for BondOrder $BondOrder..."; 348 } 349 350 $This->{BondType} = $BondType; 351 352 # Set explicit formal charge for atoms involved in Dative or coordinate bonds... 353 if ($BondType =~ /^(Dative|Coordinate)$/i) { 354 my($Atom1, $Atom2) = $This->GetAtoms(); 355 $Atom1->SetFormalCharge('1'); 356 $Atom2->SetFormalCharge('-1'); 357 } 358 359 return $This; 360 } 361 362 # Set bond stereochemistry... 363 # 364 # Single bond stereochemistry: 365 # 366 # None, Unspecified: Not a stereo bond or unspecified 367 # 368 # Wedge, Up : Wedge end pointing up 369 # Hash, Down: Wedge end pointing down 370 # Wavy, WedgeOrHash, UpOrDown: Wedge end up or down 371 # 372 # Note: Wedge starts at begin atom of bond making wedge pointed end always at this 373 # atom. 374 # 375 # Upward: Single bond around cis/trans double bonds pointing upward 376 # Downward: Single bond around cis/trans double bonds pointing upward 377 # 378 # Note: Upward/downward bonds start at atoms involved in cis/trans double bond. 379 # 380 # Double bond stereochemistry: 381 # 382 # None, Unspecified: Not a stereo bond or unspecified 383 # 384 # Z, cis: Similar groups on same side of double bond 385 # E, trans: Similar groups on different side of double bond 386 # 387 # CisOrTrans, DoubleCross: cis or trans 388 # 389 sub SetBondStereochemistry { 390 my($This, $BondStereochemistry) = @_; 391 392 if ($BondStereochemistry !~ /^(None|Unspecified|Wedge|Hash|Up|Down|Wavy|WedgeOrHash|UpOrDown|Upward|Downward|Cis|Trans|Z|E|DoubleCross|CisOrTrans)$/i) { 393 croak "Error: ${ClassName}->SetBondStereochemistry: BondStereochemistry value $BondStereochemistry is not valid. Supported values: None, Unspecified, Wedge, Hash, Up, Down, Wavy, WedgeOrHash, UpOrDown, Upward, Downward, Cis, Trans, Z, E, DoubleCross, CisOrTrans..."; 394 } 395 396 # Make sure its a valid BondStereochemistry value for BondOrder... 397 my($BondOrder, $ValidBondType); 398 399 $ValidBondType = 0; 400 $BondOrder = $This->{BondOrder}; 401 402 BONDORDER: { 403 if ($BondOrder == 0 && $BondStereochemistry =~ /^(None|Unspecified)$/i) {$ValidBondType = 1; last BONDORDER; } 404 if ($BondOrder == 1 && $BondStereochemistry =~ /^(Wedge|Hash|Up|Down|Wavy|WedgeOrHash|UpOrDown|Upward|Downward|None|Unspecified)$/i) {$ValidBondType = 1; last BONDORDER; } 405 if ($BondOrder == 2 && $BondStereochemistry =~ /^(Cis|Trans|Z|E|DoubleCross|CisOrTrans|None|Unspecified)$/i ) {$ValidBondType = 1; last BONDORDER; } 406 $ValidBondType = 0; 407 } 408 409 if (!$ValidBondType) { 410 carp "Warning: ${ClassName}->SetBondStereochemistry: Assigning invalid BondStereochemistry value, $BondStereochemistry, for BondOrder $BondOrder..."; 411 } 412 413 $This->{BondStereochemistry} = $BondStereochemistry; 414 415 return $This; 416 } 417 418 # Is it a single bond? 419 sub IsSingle { 420 my($This) = @_; 421 422 return ($This->{BondOrder} == 1) ? 1 : 0; 423 } 424 425 # Is it a double bond? 426 sub IsDouble { 427 my($This) = @_; 428 429 return ($This->{BondOrder} == 2) ? 1 : 0; 430 } 431 432 # Is it a triple bond? 433 sub IsTriple { 434 my($This) = @_; 435 436 return ($This->{BondOrder} == 3) ? 1 : 0; 437 } 438 439 # Is it a quadruple bond? 440 sub IsQuadruple { 441 my($This) = @_; 442 443 return ($This->{BondOrder} == 4) ? 1 : 0; 444 } 445 446 # Is aromatic property set for the bond? 447 sub IsAromatic { 448 my($This) = @_; 449 my($Aromatic); 450 451 $Aromatic = $This->GetAromatic(); 452 453 return ((defined($Aromatic) && $Aromatic) || $This->{BondOrder} == 1.5) ? 1 : 0; 454 } 455 456 # Is it a quintuple bond? 457 sub IsQuintuple { 458 my($This) = @_; 459 460 return ($This->{BondOrder} == 5) ? 1 : 0; 461 } 462 463 # Is it a sextuple bond? 464 sub IsSextuple { 465 my($This) = @_; 466 467 return ($This->{BondOrder} == 6) ? 1 : 0; 468 } 469 470 # Is bond type specified? 471 sub IsBondTypeSpecified { 472 my($This) = @_; 473 474 return ($This->{BondType} && $This->{BondType} !~ /^(None|Unspecified)$/i) ? 1 : 0; 475 } 476 477 # Is it a dative or coordinate bond? 478 sub IsDative { 479 my($This) = @_; 480 481 return ($This->{BondType} =~ /^(Dative|Coordinate)$/i) ? 1 : 0; 482 } 483 484 # Is it a dative or coordinate bond? 485 sub IsCoordinate { 486 my($This) = @_; 487 488 return $This->IsDative(); 489 } 490 491 # Is it a ionic bond? 492 sub IsIonic { 493 my($This) = @_; 494 495 return ($This->{BondType} =~ /^Ionic$/i) ? 1 : 0; 496 } 497 498 # Is it a tautomeric bond? 499 sub IsTautomeric { 500 my($This) = @_; 501 502 return ($This->{BondType} =~ /^Tautomeric$/i) ? 1 : 0; 503 } 504 505 # Is bond stereochemistry specified? 506 sub IsBondStereochemistrySpecified { 507 my($This) = @_; 508 509 return ($This->{BondStereochemistry} && $This->{BondStereochemistry} !~ /^(None|Unspecified)$/i) ? 1 : 0; 510 } 511 512 # Is it a Wedge or Up single bond? 513 sub IsWedge { 514 my($This) = @_; 515 516 return $This->IsUp(); 517 } 518 519 # Is it a Wedge or Up single bond? 520 sub IsUp { 521 my($This) = @_; 522 523 return ($This->{BondStereochemistry} =~ /^(Wedge|Up)$/i) ? 1 : 0; 524 } 525 526 # Is it a Hash or Down single bond? 527 sub IsHash { 528 my($This) = @_; 529 530 return $This->IsDown(); 531 } 532 533 # Is it a Hash or Down single bond? 534 sub IsDown { 535 my($This) = @_; 536 537 return ($This->{BondStereochemistry} =~ /^(Hash|Down)$/i) ? 1 : 0; 538 } 539 540 # Is it a Wavy, WedgeOrHash or UpOrDown single bond? 541 sub IsWedgeOrHash { 542 my($This) = @_; 543 544 return $This->IsUpOrDown(); 545 } 546 547 # Is it a Wavy, WedgeOrHash or UpOrDown single bond? 548 sub IsUpOrDown { 549 my($This) = @_; 550 551 return ($This->{BondStereochemistry} =~ /^(Wavy|WedgeOrHash|UpOrDown)$/i) ? 1 : 0; 552 } 553 554 # Is it a upward single bond? 555 sub IsUpward { 556 my($This) = @_; 557 558 return ($This->{BondStereochemistry} =~ /^Upward$/i) ? 1 : 0; 559 } 560 561 # Is it a Downward single bond? 562 sub IsDownward { 563 my($This) = @_; 564 565 return ($This->{BondStereochemistry} =~ /^Downward$/i) ? 1 : 0; 566 } 567 # Is it a cis or Z double bond? 568 sub IsCis { 569 my($This) = @_; 570 571 return ($This->{BondStereochemistry} =~ /^(Cis|Z)$/i) ? 1 : 0; 572 } 573 574 # Is it a trans or E double bond? 575 sub IsTrans { 576 my($This) = @_; 577 578 return ($This->{BondStereochemistry} =~ /^(Trans|E)$/i) ? 1 : 0; 579 } 580 581 # Is it a cis or trans double bond? 582 sub IsCisOrTrans { 583 my($This) = @_; 584 585 return ($This->{BondStereochemistry} =~ /^(CisOrTrans|DoubleCross)$/i) ? 1 : 0; 586 } 587 588 # Delete bond... 589 sub DeleteBond { 590 my($This) = @_; 591 592 # Is this atom in a molecule? 593 if (!$This->HasProperty('Molecule')) { 594 # Nothing to do... 595 return $This; 596 } 597 my($Molecule); 598 $Molecule = $This->GetProperty('Molecule'); 599 $Molecule->DeleteBond($This); 600 601 return $This; 602 } 603 604 # Copy bond and all its associated data... 605 sub Copy { 606 my($This) = @_; 607 my($Bond); 608 609 $Bond = Storable::dclone($This); 610 611 return $Bond; 612 } 613 614 # Is bond in a ring? 615 # 616 sub IsInRing { 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->_IsBondInRing($This); 627 } 628 629 # Is bond not in a ring? 630 # 631 sub IsNotInRing { 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->_IsBondNotInRing($This); 642 } 643 644 # Is bond only in one ring? 645 # 646 sub IsOnlyInOneRing { 647 my($This) = @_; 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->_IsBondInOnlyOneRing($This); 657 } 658 659 # Is bond in a ring of specific size? 660 # 661 sub IsInRingOfSize { 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->_IsBondInRingOfSize($This, $RingSize); 672 } 673 674 # Get size of smallest ring containing the bond... 675 # 676 sub GetSizeOfSmallestRing { 677 my($This) = @_; 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->_GetSizeOfSmallestBondRing($This); 687 } 688 689 # Get size of largest ring containing the bond... 690 # 691 sub GetSizeOfLargestRing { 692 my($This) = @_; 693 694 # Is this bond in a molecule? 695 if (!$This->HasProperty('Molecule')) { 696 return undef; 697 } 698 my($Molecule); 699 $Molecule = $This->GetProperty('Molecule'); 700 701 return $Molecule->_GetSizeOfLargestBondRing($This); 702 } 703 704 # Get number of rings containing the bond... 705 # 706 sub GetNumOfRings { 707 my($This) = @_; 708 709 # Is this bond in a molecule? 710 if (!$This->HasProperty('Molecule')) { 711 return undef; 712 } 713 my($Molecule); 714 $Molecule = $This->GetProperty('Molecule'); 715 716 return $Molecule->_GetNumOfBondRings($This); 717 } 718 719 # Get number of rings with odd size containing the bond... 720 # 721 sub GetNumOfRingsWithOddSize { 722 my($This) = @_; 723 724 # Is this bond in a molecule? 725 if (!$This->HasProperty('Molecule')) { 726 return undef; 727 } 728 my($Molecule); 729 $Molecule = $This->GetProperty('Molecule'); 730 731 return $Molecule->_GetNumOfBondRingsWithOddSize($This); 732 } 733 734 # Get number of rings with even size containing the bond... 735 # 736 sub GetNumOfRingsWithEvenSize { 737 my($This) = @_; 738 739 # Is this bond in a molecule? 740 if (!$This->HasProperty('Molecule')) { 741 return undef; 742 } 743 my($Molecule); 744 $Molecule = $This->GetProperty('Molecule'); 745 746 return $Molecule->_GetNumOfBondRingsWithEvenSize($This); 747 } 748 749 # Get number of rings with specified size containing the bond... 750 # 751 sub GetNumOfRingsWithSize { 752 my($This, $RingSize) = @_; 753 754 # Is this bond in a molecule? 755 if (!$This->HasProperty('Molecule')) { 756 return undef; 757 } 758 my($Molecule); 759 $Molecule = $This->GetProperty('Molecule'); 760 761 return $Molecule->_GetNumOfBondRingsWithSize($This, $RingSize); 762 } 763 764 # Get number of rings with size less than specified containing the bond... 765 # 766 sub GetNumOfRingsWithSizeLessThan { 767 my($This, $RingSize) = @_; 768 769 # Is this bond in a molecule? 770 if (!$This->HasProperty('Molecule')) { 771 return undef; 772 } 773 my($Molecule); 774 $Molecule = $This->GetProperty('Molecule'); 775 776 return $Molecule->_GetNumOfBondRingsWithSizeLessThan($This, $RingSize); 777 } 778 779 # Get number of rings with size greater than specified size containing the bond... 780 # 781 sub GetNumOfRingsWithSizeGreaterThan { 782 my($This, $RingSize) = @_; 783 784 # Is this bond in a molecule? 785 if (!$This->HasProperty('Molecule')) { 786 return undef; 787 } 788 my($Molecule); 789 $Molecule = $This->GetProperty('Molecule'); 790 791 return $Molecule->_GetNumOfBondRingsWithSizeGreaterThan($This, $RingSize); 792 } 793 794 # Get all rings as an array of references to arrays containing ring atoms... 795 # 796 sub GetRings { 797 my($This) = @_; 798 799 # Is this bond in a molecule? 800 if (!$This->HasProperty('Molecule')) { 801 return undef; 802 } 803 my($Molecule); 804 $Molecule = $This->GetProperty('Molecule'); 805 806 return $Molecule->_GetBondRings($This); 807 } 808 809 # Get smallest ring as an array containing ring atoms... 810 # 811 sub GetSmallestRing { 812 my($This) = @_; 813 814 # Is this bond in a molecule? 815 if (!$This->HasProperty('Molecule')) { 816 return undef; 817 } 818 my($Molecule); 819 $Molecule = $This->GetProperty('Molecule'); 820 821 return $Molecule->_GetSmallestBondRing($This); 822 } 823 824 # Get largest ring as an array containing ring atoms... 825 # 826 sub GetLargestRing { 827 my($This) = @_; 828 829 # Is this bond in a molecule? 830 if (!$This->HasProperty('Molecule')) { 831 return undef; 832 } 833 my($Molecule); 834 $Molecule = $This->GetProperty('Molecule'); 835 836 return $Molecule->_GetLargestBondRing($This); 837 } 838 839 # Get odd size rings an array of references to arrays containing ring atoms... 840 # 841 sub GetRingsWithOddSize { 842 my($This) = @_; 843 844 # Is this bond in a molecule? 845 if (!$This->HasProperty('Molecule')) { 846 return undef; 847 } 848 my($Molecule); 849 $Molecule = $This->GetProperty('Molecule'); 850 851 return $Molecule->_GetBondRingsWithOddSize($This); 852 } 853 854 # Get even size rings an array of references to arrays containing ring atoms... 855 # 856 sub GetRingsWithEvenSize { 857 my($This) = @_; 858 859 # Is this bond in a molecule? 860 if (!$This->HasProperty('Molecule')) { 861 return undef; 862 } 863 my($Molecule); 864 $Molecule = $This->GetProperty('Molecule'); 865 866 return $Molecule->_GetBondRingsWithEvenSize($This); 867 } 868 869 # Get rings with specified size an array of references to arrays containing ring atoms... 870 # 871 sub GetRingsWithSize { 872 my($This, $RingSize) = @_; 873 874 # Is this bond in a molecule? 875 if (!$This->HasProperty('Molecule')) { 876 return undef; 877 } 878 my($Molecule); 879 $Molecule = $This->GetProperty('Molecule'); 880 881 return $Molecule->_GetBondRingsWithSize($This, $RingSize); 882 } 883 884 # Get rings with size less than specfied size as an array of references to arrays containing ring atoms... 885 # 886 sub GetRingsWithSizeLessThan { 887 my($This, $RingSize) = @_; 888 889 # Is this bond in a molecule? 890 if (!$This->HasProperty('Molecule')) { 891 return undef; 892 } 893 my($Molecule); 894 $Molecule = $This->GetProperty('Molecule'); 895 896 return $Molecule->_GetBondRingsWithSizeLessThan($This, $RingSize); 897 } 898 899 # Get rings with size greater than specfied size as an array of references to arrays containing ring atoms... 900 # 901 sub GetRingsWithSizeGreaterThan { 902 my($This, $RingSize) = @_; 903 904 # Is this bond in a molecule? 905 if (!$This->HasProperty('Molecule')) { 906 return undef; 907 } 908 my($Molecule); 909 $Molecule = $This->GetProperty('Molecule'); 910 911 return $Molecule->_GetBondRingsWithSizeGreaterThan($This, $RingSize); 912 } 913 914 # Get next object ID... 915 sub _GetNewObjectID { 916 $ObjectID++; 917 return $ObjectID; 918 } 919 920 # Return a string containing bond and other properties... 921 sub StringifyBond { 922 my($This) = @_; 923 my($BondString, $ID, $BondOrder, $BondType, $Stereochemistry, $AtomsString, $RingBond, $AromaticBond, $NumOfRings, $Atom1, $Atom2); 924 925 $ID = $This->GetID(); 926 $BondOrder = $This->GetBondOrder(); 927 if (!defined $BondOrder) { 928 $BondOrder = "undefined"; 929 } 930 $BondType = $This->GetBondType(); 931 if (!defined $BondOrder) { 932 $BondType = "undefined"; 933 } 934 if (defined($BondOrder) && $BondOrder == 2) { 935 $Stereochemistry = $This->GetStereochemistry(); 936 if (!defined $Stereochemistry) { 937 $Stereochemistry = "undefined"; 938 } 939 } 940 $RingBond = $This->IsInRing(); 941 if (defined $RingBond) { 942 $RingBond = $RingBond ? 'Yes' : 'No'; 943 $NumOfRings = $This->GetNumOfRings(); 944 } 945 else { 946 $RingBond = 'undefined'; 947 $NumOfRings = 'undefined'; 948 } 949 950 $AromaticBond = $This->GetAromatic(); 951 if (defined $AromaticBond) { 952 $AromaticBond = $AromaticBond ? 'Yes' : 'No'; 953 } 954 else { 955 $AromaticBond = 'undefined'; 956 } 957 958 ($Atom1, $Atom2) = $This->GetAtoms(); 959 $AtomsString = "Atoms: undefined"; 960 if (defined($Atom1) && defined($Atom2)) { 961 my($Atom, $AtomID, $AtomCount, $AtomName, $AtomSymbol, $AtomicNumber, @BondAtoms); 962 @BondAtoms = (); 963 push @BondAtoms, ($Atom1, $Atom2); 964 $AtomCount = 0; 965 $AtomsString = ""; 966 for $Atom (@BondAtoms) { 967 $AtomCount++; 968 $AtomID = $Atom->GetID(); 969 $AtomName = $Atom->GetName(); 970 $AtomSymbol = $Atom->GetAtomSymbol(); 971 $AtomicNumber = $Atom->GetAtomicNumber(); 972 if ($AtomCount == 1) { 973 $AtomsString .= "FirstAtom:"; 974 } 975 else { 976 $AtomsString .= "; SecondAtom:"; 977 } 978 $AtomsString .= " [ ID: $AtomID; Name: \"$AtomName\"; AtomSymbol: \"$AtomSymbol\"; AtomicNumber: $AtomicNumber ]"; 979 } 980 } 981 $BondString = "Bond: ID: $ID; BondOrder: $BondOrder; BondType: $BondType; RingBond: $RingBond; NumOfBondRings: $NumOfRings; AromaticBond: $AromaticBond;"; 982 if (defined($BondOrder) && $BondOrder == 2) { 983 $BondString .= " Stereochemistry: $Stereochemistry;"; 984 } 985 $BondString .= " $AtomsString"; 986 987 return $BondString; 988 } 989