comparison mayachemtools/lib/Atom.pm @ 0:73ae111cf86f draft

Uploaded
author deepakjadmin
date Wed, 20 Jan 2016 11:55:01 -0500
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:73ae111cf86f
1 package Atom;
2 #
3 # $RCSfile: Atom.pm,v $
4 # $Date: 2015/02/28 20:47:02 $
5 # $Revision: 1.62 $
6 #
7 # Author: Manish Sud <msud@san.rr.com>
8 #
9 # Copyright (C) 2015 Manish Sud. All rights reserved.
10 #
11 # This file is part of MayaChemTools.
12 #
13 # MayaChemTools is free software; you can redistribute it and/or modify it under
14 # the terms of the GNU Lesser General Public License as published by the Free
15 # Software Foundation; either version 3 of the License, or (at your option) any
16 # later version.
17 #
18 # MayaChemTools is distributed in the hope that it will be useful, but without
19 # any warranty; without even the implied warranty of merchantability of fitness
20 # for a particular purpose. See the GNU Lesser General Public License for more
21 # details.
22 #
23 # You should have received a copy of the GNU Lesser General Public License
24 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
25 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
26 # Boston, MA, 02111-1307, USA.
27 #
28
29 use strict;
30 use Carp;
31 use Exporter;
32 use Storable ();
33 use Scalar::Util ();
34 use ObjectProperty;
35 use PeriodicTable;
36 use Vector;
37 use MathUtil;
38 use Text::ParseWords;
39 use TextUtil;
40 use FileUtil;
41
42 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
43
44 @ISA = qw(ObjectProperty Exporter);
45 @EXPORT = qw();
46 @EXPORT_OK = qw();
47
48 %EXPORT_TAGS = (all => [@EXPORT, @EXPORT_OK]);
49
50 # Setup class variables...
51 my($ClassName, $ObjectID, %MDLValenceModelDataMap, %DaylightValenceModelDataMap);
52 _InitializeClass();
53
54 # Overload Perl functions...
55 use overload '""' => 'StringifyAtom';
56
57 # Class constructor...
58 sub new {
59 my($Class, %NamesAndValues) = @_;
60
61 # Initialize object...
62 my $This = {};
63 bless $This, ref($Class) || $Class;
64 $This->_InitializeAtom();
65
66 $This->_InitializeAtomProperties(%NamesAndValues);
67
68 return $This;
69 }
70
71 # Initialize object data...
72 sub _InitializeAtom {
73 my($This) = @_;
74 my($ObjectID) = _GetNewObjectID();
75
76 # All other property names and values along with all Set/Get<PropertyName> methods
77 # are implemented on-demand using ObjectProperty class.
78 $This->{ID} = $ObjectID;
79 $This->{Name} = "Atom ${ObjectID}";
80 $This->{AtomSymbol} = '';
81 $This->{AtomicNumber} = 0;
82 $This->{XYZ} = Vector::ZeroVector;
83 }
84
85 # Initialize atom properties...
86 sub _InitializeAtomProperties {
87 my($This, %NamesAndValues) = @_;
88
89 my($Name, $Value, $MethodName);
90 while (($Name, $Value) = each %NamesAndValues) {
91 $MethodName = "Set${Name}";
92 $This->$MethodName($Value);
93 }
94 if (!exists $NamesAndValues{'AtomSymbol'}) {
95 carp "Warning: ${ClassName}->new: Atom object instantiated without setting atom symbol...";
96 }
97
98 return $This;
99 }
100
101 # Initialize class ...
102 sub _InitializeClass {
103 #Class name...
104 $ClassName = __PACKAGE__;
105
106 # ID to keep track of objects...
107 $ObjectID = 0;
108
109 # Load atom class data...
110 _LoadAtomClassData();
111 }
112
113 # Setup an explicit SetID method to block setting of ID by AUTOLOAD function...
114 sub SetID {
115 my($This, $Value) = @_;
116
117 carp "Warning: ${ClassName}->SetID: Object ID can't be changed: it's used for internal tracking...";
118
119 return $This;
120 }
121
122 # Setup an explicit SetMolecule method to block setting of ID by AUTOLOAD function...
123 sub SetMolecule {
124 my($This, $Value) = @_;
125
126 carp "Warning: ${ClassName}->SetMolecule: Molecule property can't be changed: it's used for internal tracking...";
127
128 return $This;
129 }
130
131 # Assign atom to molecule...
132 sub _SetMolecule {
133 my($This, $Molecule) = @_;
134
135 $This->{Molecule} = $Molecule;
136
137 # Weaken the reference to disable increment of reference count; otherwise,
138 # it it becomes a circular reference and destruction of Molecule object doesn't
139 # get initiated which in turn disables destruction of atom object.
140 #
141 Scalar::Util::weaken($This->{Molecule});
142
143 return $This;
144 }
145
146 # Setup atom symbol and atomic number for the element...
147 #
148 # Possible atom symbol values:
149 # . An element symbol or some other type of atom: L - Atom list; LP - Lone pair; R# - R group;
150 # A, Q, * - unknown atom; or something else?
151 #
152 # Default mass number corresponds to the most abundant natural isotope unless it's explicity
153 # set using "MassNumber" property.
154 #
155 sub SetAtomSymbol {
156 my($This, $AtomSymbol) = @_;
157 my($AtomicNumber);
158
159 $This->{AtomSymbol} = $AtomSymbol;
160
161 $AtomicNumber = PeriodicTable::GetElementAtomicNumber($AtomSymbol);
162 $This->{AtomicNumber} = (defined $AtomicNumber) ? $AtomicNumber : 0;
163
164 return $This;
165 }
166
167 # Setup atom symbol and atomic number for the element...
168 sub SetAtomicNumber {
169 my($This, $AtomicNumber) = @_;
170 my($AtomSymbol);
171
172 $AtomSymbol = PeriodicTable::GetElementAtomSymbol($AtomicNumber);
173 if (!defined $AtomSymbol) {
174 carp "Warning: ${ClassName}->SetAtomicNumber: Didn't set atomic number: Invalid atomic number, $AtomicNumber, specified...";
175 return;
176 }
177 $This->{AtomicNumber} = $AtomicNumber;
178 $This->{AtomSymbol} = $AtomSymbol;
179
180 return $This;
181 }
182
183 # Set atom as stereo center...
184 #
185 sub SetStereoCenter {
186 my($This, $StereoCenter) = @_;
187
188 $This->SetProperty('StereoCenter', $StereoCenter);
189
190 return $This;
191 }
192
193 # Is it a stereo center?
194 #
195 sub IsStereoCenter {
196 my($This) = @_;
197 my($StereoCenter);
198
199 $StereoCenter = $This->GetProperty('StereoCenter');
200
201 return (defined($StereoCenter) && $StereoCenter) ? 1 : 0;
202 }
203
204 # Set atom stereochemistry.
205 #
206 # Supported values are: R, S.
207 #
208 # Notes:
209 #
210 # . After the ligands around a central stereocenter has been ranked using CIP priority scheme and
211 # the lowest ranked ligand lies behind the center atom, then R and S values correspond to:
212 #
213 # R: Clockwise arrangement of remaining ligands around the central atom going from highest to lowest ranked ligand
214 # S: CounterClockwise arrangement of remaining ligands around the central atom going from highest to lowest ranked ligand
215 #
216 # . Assignment of any other arbitray values besides R and S is also allowed; however, a warning is printed.
217 #
218 sub SetStereochemistry {
219 my($This, $Stereochemistry) = @_;
220
221 if ($Stereochemistry !~ /^(R|S)$/i) {
222 carp "Warning: ${ClassName}->SetStereochemistry: Assigning non-supported Stereochemistry value of $Stereochemistry. Supported values: R, S...";
223 }
224
225 $This->SetProperty('StereoCenter', 1);
226 $This->SetProperty('Stereochemistry', $Stereochemistry);
227
228 return $This;
229 }
230
231 # Setup mass number for atom...
232 sub SetMassNumber {
233 my($This, $MassNumber) = @_;
234 my($AtomicNumber, $AtomSymbol);
235
236 $AtomicNumber = $This->{AtomicNumber};
237 $AtomSymbol = $This->{AtomSymbol};
238 if (!$AtomicNumber) {
239 carp "Warning: ${ClassName}->SetMassNumber: Didn't set mass number: Non standard atom with atomic number, $AtomicNumber, and atomic symbol, $AtomSymbol...";
240 return;
241 }
242 if (!PeriodicTable::IsElementNaturalIsotopeMassNumber($AtomicNumber, $MassNumber)) {
243 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...";
244 }
245 $This->SetProperty('MassNumber', $MassNumber);
246
247 return $This;
248 }
249
250 # Get mass number...
251 #
252 sub GetMassNumber {
253 my($This) = @_;
254
255 # Is mass number explicity set?
256 if ($This->HasProperty('MassNumber')) {
257 return $This->GetProperty('MassNumber');
258 }
259
260 # Is it an element symbol?
261 my($AtomicNumber) = $This->{AtomicNumber};
262 if (!$AtomicNumber) {
263 return 0;
264 }
265
266 # Return most abundant mass number...
267 return PeriodicTable::GetElementMostAbundantNaturalIsotopeMassNumber($AtomicNumber);
268 }
269
270 # Get atomic weight:
271 # . Explicitly set by the caller
272 # . Using atomic number
273 #
274 sub GetAtomicWeight {
275 my($This) = @_;
276
277 # Is atomic weight explicity set?
278 if ($This->HasProperty('AtomicWeight')) {
279 return $This->GetProperty('AtomicWeight');
280 }
281
282 # Is it an element symbol?
283 my($AtomicNumber) = $This->{AtomicNumber};
284 if (!$AtomicNumber) {
285 return 0;
286 }
287
288 # Return its atomic weight...
289 return PeriodicTable::GetElementAtomicWeight($AtomicNumber);
290 }
291
292 # Get exact mass weight:
293 # . Explicitly set by the caller
294 # . Using atomic number and mass number explicity set by the caller
295 # . Using atomic number and most abundant isotope
296 #
297 sub GetExactMass {
298 my($This) = @_;
299
300 # Is exact mass explicity set?
301 if ($This->HasProperty('ExactMass')) {
302 return $This->GetProperty('ExactMass');
303 }
304
305 # Is it an element symbol?
306 my($AtomicNumber) = $This->{AtomicNumber};
307 if (!$AtomicNumber) {
308 return 0;
309 }
310
311 # Is mass number explicitly set?
312 if ($This->HasProperty('MassNumber')) {
313 my($MassNumber) = $This->GetProperty('MassNumber');
314 if (PeriodicTable::IsElementNaturalIsotopeMassNumber($AtomicNumber, $MassNumber)) {
315 return PeriodicTable::GetElementNaturalIsotopeMass($AtomicNumber, $MassNumber);
316 }
317 }
318
319 # Return most abundant isotope mass...
320 return PeriodicTable::GetElementMostAbundantNaturalIsotopeMass($AtomicNumber);
321 }
322
323 # Get formal charge:
324 # . Explicitly set by the caller
325 # . Or return zero insetad of undef
326 #
327 sub GetFormalCharge {
328 my($This) = @_;
329 my($FormalCharge);
330
331 $FormalCharge = 0;
332 if ($This->HasProperty('FormalCharge')) {
333 $FormalCharge = $This->GetProperty('FormalCharge');
334 }
335
336 return defined($FormalCharge) ? $FormalCharge : 0;
337 }
338
339 # Get spin multiplicity:
340 # . Explicitly set by the caller
341 # . From FreeRadicalElectrons value explicitly set by the caller
342 # . Or return zero insetad of undef
343 #
344 sub GetSpinMultiplicity {
345 my($This) = @_;
346 my($SpinMultiplicity);
347
348 $SpinMultiplicity = 0;
349 if ($This->HasProperty('SpinMultiplicity')) {
350 $SpinMultiplicity = $This->GetProperty('SpinMultiplicity');
351 return defined($SpinMultiplicity) ? $SpinMultiplicity : 0;
352 }
353
354 if ($This->HasProperty('FreeRadicalElectrons')) {
355 my($FreeRadicalElectrons);
356 $FreeRadicalElectrons = $This->GetProperty('FreeRadicalElectrons');
357
358 SPINMULTIPLICITY: {
359 if ($FreeRadicalElectrons == 1) { $SpinMultiplicity = 2; last SPINMULTIPLICITY;}
360 if ($FreeRadicalElectrons == 2) { $SpinMultiplicity = 1; last SPINMULTIPLICITY;}
361 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...";
362 $SpinMultiplicity = 0;
363 }
364 }
365
366 return $SpinMultiplicity;
367 }
368
369 # Get number of free radical electrons:
370 # . Explicitly set by the caller
371 # . From SpinMultiplicity value explicitly set by the caller
372 # . Or return zero insetad of undef
373 #
374 # Notes:
375 # . For atoms with explicit assignment of SpinMultiplicity property values corresponding to
376 # Singlet (two unpaired electrons corresponding to one spin state), Doublet (free radical; an unpaired
377 # electron corresponding to two spin states), and Triplet (two unparied electrons corresponding to
378 # three spin states; divalent carbon atoms (carbenes)), FreeRadicalElectrons are calculated as follows:
379 #
380 # SpinMultiplicity: Doublet(2); FreeRadicalElectrons: 1
381 # SpinMultiplicity: Singlet(1)/Triplet(3); FreeRadicalElectrons: 2
382 #
383 sub GetFreeRadicalElectrons {
384 my($This) = @_;
385 my($FreeRadicalElectrons);
386
387 $FreeRadicalElectrons = 0;
388
389 if ($This->HasProperty('FreeRadicalElectrons')) {
390 $FreeRadicalElectrons = $This->GetProperty('FreeRadicalElectrons');
391 return defined($FreeRadicalElectrons) ? $FreeRadicalElectrons : 0;
392 }
393
394 if ($This->HasProperty('SpinMultiplicity')) {
395 my($SpinMultiplicity);
396 $SpinMultiplicity = $This->GetProperty('SpinMultiplicity');
397
398 SPINMULTIPLICITY: {
399 if ($SpinMultiplicity == 1) { $FreeRadicalElectrons = 2; last SPINMULTIPLICITY;}
400 if ($SpinMultiplicity == 2) { $FreeRadicalElectrons = 1; last SPINMULTIPLICITY;}
401 if ($SpinMultiplicity == 3) { $FreeRadicalElectrons = 2; last SPINMULTIPLICITY;}
402 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...";
403 $FreeRadicalElectrons = 0;
404 }
405 }
406
407 return $FreeRadicalElectrons;
408 }
409
410 # Set atom coordinates using:
411 # . An array reference with three values
412 # . An array containg three values
413 # . A 3D vector
414 #
415 sub SetXYZ {
416 my($This, @Values) = @_;
417
418 if (!@Values) {
419 carp "Warning: ${ClassName}->SetXYZ: No values specified...";
420 return;
421 }
422
423 $This->{XYZ}->SetXYZ(@Values);
424 return $This;
425 }
426
427 # Set X value...
428 sub SetX {
429 my($This, $Value) = @_;
430
431 if (!defined $Value) {
432 carp "Warning: ${ClassName}->SetX: Undefined X value...";
433 return;
434 }
435 $This->{XYZ}->SetX($Value);
436 return $This;
437 }
438
439 # Set Y value...
440 sub SetY {
441 my($This, $Value) = @_;
442
443 if (!defined $Value) {
444 carp "Warning: ${ClassName}->SetY: Undefined Y value...";
445 return;
446 }
447 $This->{XYZ}->SetY($Value);
448 return $This;
449 }
450
451 # Set Z value...
452 sub SetZ {
453 my($This, $Value) = @_;
454
455 if (!defined $Value) {
456 carp "Warning: ${ClassName}->SetZ: Undefined Z value...";
457 return;
458 }
459 $This->{XYZ}->SetZ($Value);
460 return $This;
461 }
462
463 # Return XYZ as:
464 # . Reference to an array
465 # . An array
466 #
467 sub GetXYZ {
468 my($This) = @_;
469
470 return $This->{XYZ}->GetXYZ();
471 }
472
473 # Return XYZ as a vector object...
474 #
475 sub GetXYZVector {
476 my($This) = @_;
477
478 return $This->{XYZ};
479 }
480
481 # Get X value...
482 sub GetX {
483 my($This) = @_;
484
485 return $This->{XYZ}->GetX();
486 }
487
488 # Get Y value...
489 sub GetY {
490 my($This) = @_;
491
492 return $This->{XYZ}->GetY();
493 }
494
495 # Get Z value...
496 sub GetZ {
497 my($This) = @_;
498
499 return $This->{XYZ}->GetZ();
500 }
501
502 # Delete atom...
503 sub DeleteAtom {
504 my($This) = @_;
505
506 # Is this atom in a molecule?
507 if (!$This->HasProperty('Molecule')) {
508 # Nothing to do...
509 return $This;
510 }
511 my($Molecule) = $This->GetProperty('Molecule');
512
513 return $Molecule->_DeleteAtom($This);
514 }
515
516 # Get atom neighbor objects as array. In scalar conetxt, return number of neighbors...
517 sub GetNeighbors {
518 my($This, @ExcludeNeighbors) = @_;
519
520 # Is this atom in a molecule?
521 if (!$This->HasProperty('Molecule')) {
522 return undef;
523 }
524 my($Molecule) = $This->GetProperty('Molecule');
525
526 if (@ExcludeNeighbors) {
527 return $This->_GetAtomNeighbors(@ExcludeNeighbors);
528 }
529 else {
530 return $This->_GetAtomNeighbors();
531 }
532 }
533
534 # Get atom neighbor objects as array. In scalar conetxt, return number of neighbors...
535 sub _GetAtomNeighbors {
536 my($This, @ExcludeNeighbors) = @_;
537 my($Molecule) = $This->GetProperty('Molecule');
538
539 if (!@ExcludeNeighbors) {
540 return $Molecule->_GetAtomNeighbors($This);
541 }
542
543 # Setup a map for neigbhors to exclude...
544 my($ExcludeNeighbor, $ExcludeNeighborID, %ExcludeNeighborsIDsMap);
545
546 %ExcludeNeighborsIDsMap = ();
547 for $ExcludeNeighbor (@ExcludeNeighbors) {
548 $ExcludeNeighborID = $ExcludeNeighbor->GetID();
549 $ExcludeNeighborsIDsMap{$ExcludeNeighborID} = $ExcludeNeighborID;
550 }
551
552 # Generate a filtered neighbors list...
553 my($Neighbor, $NeighborID, @FilteredAtomNeighbors);
554 @FilteredAtomNeighbors = ();
555 NEIGHBOR: for $Neighbor ($Molecule->_GetAtomNeighbors($This)) {
556 $NeighborID = $Neighbor->GetID();
557 if (exists $ExcludeNeighborsIDsMap{$NeighborID}) {
558 next NEIGHBOR;
559 }
560 push @FilteredAtomNeighbors, $Neighbor;
561 }
562
563 return wantarray ? @FilteredAtomNeighbors : scalar @FilteredAtomNeighbors;
564 }
565
566 # Get specific atom neighbor objects as array. In scalar conetxt, return number of neighbors.
567 #
568 # Notes:
569 # . AtomSpecification correspond to any valid AtomicInvariant based atomic specifications
570 # as implemented in DoesAtomNeighborhoodMatch method.
571 # . Multiple atom specifications can be used in a string delimited by comma.
572 #
573 sub GetNeighborsUsingAtomSpecification {
574 my($This, $AtomSpecification, @ExcludeNeighbors) = @_;
575 my(@AtomNeighbors);
576
577 @AtomNeighbors = ();
578 @AtomNeighbors = $This->GetNeighbors(@ExcludeNeighbors);
579
580 # Does atom has any neighbors and do they need to be filtered?
581 if (!(@AtomNeighbors && defined($AtomSpecification) && $AtomSpecification)) {
582 return wantarray ? @AtomNeighbors : scalar @AtomNeighbors;
583 }
584
585 # Filter neighbors using atom specification...
586 my($AtomNeighbor, @FilteredAtomNeighbors);
587
588 @FilteredAtomNeighbors = ();
589 NEIGHBOR: for $AtomNeighbor (@AtomNeighbors) {
590 if (!$AtomNeighbor->_DoesAtomSpecificationMatch($AtomSpecification)) {
591 next NEIGHBOR;
592 }
593 push @FilteredAtomNeighbors, $AtomNeighbor;
594 }
595
596 return wantarray ? @FilteredAtomNeighbors : scalar @FilteredAtomNeighbors;
597 }
598
599
600 # Get non-hydrogen atom neighbor objects as array. In scalar context, return number of neighbors...
601 sub GetHeavyAtomNeighbors {
602 my($This) = @_;
603
604 return $This->GetNonHydrogenAtomNeighbors();
605 }
606
607 # Get non-hydrogen atom neighbor objects as array. In scalar context, return number of neighbors...
608 sub GetNonHydrogenAtomNeighbors {
609 my($This) = @_;
610
611 # Is this atom in a molecule?
612 if (!$This->HasProperty('Molecule')) {
613 return undef;
614 }
615 my($NonHydrogenAtomsOnly, $HydrogenAtomsOnly) = (1, 0);
616
617 return $This->_GetFilteredAtomNeighbors($NonHydrogenAtomsOnly, $HydrogenAtomsOnly);
618 }
619
620 # Get hydrogen atom neighbor objects as array. In scalar context, return numbe of neighbors...
621 sub GetHydrogenAtomNeighbors {
622 my($This) = @_;
623
624 # Is this atom in a molecule?
625 if (!$This->HasProperty('Molecule')) {
626 return undef;
627 }
628 my($NonHydrogenAtomsOnly, $HydrogenAtomsOnly) = (0, 1);
629
630 return $This->_GetFilteredAtomNeighbors($NonHydrogenAtomsOnly, $HydrogenAtomsOnly);
631 }
632
633 # Get non-hydrogen neighbor of hydrogen atom...
634 #
635 sub GetNonHydrogenNeighborOfHydrogenAtom {
636 my($This) = @_;
637
638 # Is it Hydrogen?
639 if (!$This->IsHydrogen()) {
640 return undef;
641 }
642 my(@Neighbors);
643
644 @Neighbors = $This->GetNonHydrogenAtomNeighbors();
645
646 return (@Neighbors == 1) ? $Neighbors[0] : undef;
647 }
648
649 # Get filtered atom atom neighbors
650 sub _GetFilteredAtomNeighbors {
651 my($This, $NonHydrogenAtomsOnly, $HydrogenAtomsOnly) = @_;
652
653 # Check flags...
654 if (!defined $NonHydrogenAtomsOnly) {
655 $NonHydrogenAtomsOnly = 0;
656 }
657 if (!defined $HydrogenAtomsOnly) {
658 $HydrogenAtomsOnly = 0;
659 }
660 my($Neighbor, @FilteredAtomNeighbors);
661
662 @FilteredAtomNeighbors = ();
663 NEIGHBOR: for $Neighbor ($This->GetNeighbors()) {
664 if ($NonHydrogenAtomsOnly && $Neighbor->IsHydrogen()) {
665 next NEIGHBOR;
666 }
667 if ($HydrogenAtomsOnly && (!$Neighbor->IsHydrogen())) {
668 next NEIGHBOR;
669 }
670 push @FilteredAtomNeighbors, $Neighbor;
671 }
672
673 return wantarray ? @FilteredAtomNeighbors : scalar @FilteredAtomNeighbors;
674 }
675
676 # Get number of neighbors...
677 #
678 sub GetNumOfNeighbors {
679 my($This) = @_;
680 my($NumOfNeighbors);
681
682 $NumOfNeighbors = $This->GetNeighbors();
683
684 return (defined $NumOfNeighbors) ? $NumOfNeighbors : undef;
685 }
686
687 # Get number of neighbors which are non-hydrogen atoms...
688 sub GetNumOfHeavyAtomNeighbors {
689 my($This) = @_;
690
691 return $This->GetNumOfNonHydrogenAtomNeighbors();
692 }
693
694 # Get number of neighbors which are non-hydrogen atoms...
695 sub GetNumOfNonHydrogenAtomNeighbors {
696 my($This) = @_;
697 my($NumOfNeighbors);
698
699 $NumOfNeighbors = $This->GetNonHydrogenAtomNeighbors();
700
701 return (defined $NumOfNeighbors) ? $NumOfNeighbors : undef;
702 }
703
704 # Get number of neighbors which are hydrogen atoms...
705 sub GetNumOfHydrogenAtomNeighbors {
706 my($This) = @_;
707 my($NumOfNeighbors);
708
709 $NumOfNeighbors = $This->GetHydrogenAtomNeighbors();
710
711 return (defined $NumOfNeighbors) ? $NumOfNeighbors : undef;
712 }
713
714 # Get bond objects as array. In scalar context, return number of bonds...
715 sub GetBonds {
716 my($This) = @_;
717
718 # Is this atom in a molecule?
719 if (!$This->HasProperty('Molecule')) {
720 return undef;
721 }
722 my($Molecule) = $This->GetProperty('Molecule');
723
724 return $Molecule->_GetAtomBonds($This);
725 }
726
727 # Get bond to specified atom...
728 sub GetBondToAtom {
729 my($This, $Other) = @_;
730
731 # Is this atom in a molecule?
732 if (!$This->HasProperty('Molecule')) {
733 return undef;
734 }
735 my($Molecule) = $This->GetProperty('Molecule');
736
737 return $Molecule->_GetBondToAtom($This, $Other);
738 }
739
740 # It it bonded to a specified atom?
741 sub IsBondedToAtom {
742 my($This, $Other) = @_;
743
744 # Is this atom in a molecule?
745 if (!$This->HasProperty('Molecule')) {
746 return undef;
747 }
748 my($Molecule) = $This->GetProperty('Molecule');
749
750 return $Molecule->_IsBondedToAtom($This, $Other);
751 }
752
753 # Get bond objects to non-hydrogen atoms as array. In scalar context, return number of bonds...
754 sub GetBondsToHeavyAtoms {
755 my($This) = @_;
756
757 return $This->GetBondsToNonHydrogenAtoms();
758 }
759
760 # Get bond objects to non-hydrogen atoms as array. In scalar context, return number of bonds...
761 sub GetBondsToNonHydrogenAtoms {
762 my($This) = @_;
763
764 # Is this atom in a molecule?
765 if (!$This->HasProperty('Molecule')) {
766 return undef;
767 }
768 my($BondsToNonHydrogenAtomsOnly, $BondsToHydrogenAtomsOnly) = (1, 0);
769
770 return $This->_GetFilteredBonds($BondsToNonHydrogenAtomsOnly, $BondsToHydrogenAtomsOnly);
771 }
772
773 # Get bond objects to hydrogen atoms as array. In scalar context, return number of bonds...
774 sub GetBondsToHydrogenAtoms {
775 my($This) = @_;
776
777 # Is this atom in a molecule?
778 if (!$This->HasProperty('Molecule')) {
779 return undef;
780 }
781 my($BondsToNonHydrogenAtomsOnly, $BondsToHydrogenAtomsOnly) = (0, 1);
782
783 return $This->_GetFilteredBonds($BondsToNonHydrogenAtomsOnly, $BondsToHydrogenAtomsOnly);
784 }
785
786 # Get filtered bonds...
787 sub _GetFilteredBonds {
788 my($This, $BondsToNonHydrogenAtomsOnly, $BondsToHydrogenAtomsOnly) = @_;
789
790 # Check flags...
791 if (!defined $BondsToNonHydrogenAtomsOnly) {
792 $BondsToNonHydrogenAtomsOnly = 0;
793 }
794 if (!defined $BondsToHydrogenAtomsOnly) {
795 $BondsToHydrogenAtomsOnly = 0;
796 }
797
798 my($Bond, $BondedAtom, @FilteredBonds);
799
800 @FilteredBonds = ();
801 BOND: for $Bond ($This->GetBonds()) {
802 $BondedAtom = $Bond->GetBondedAtom($This);
803 if ($BondsToNonHydrogenAtomsOnly && $BondedAtom->IsHydrogen()) {
804 next BOND;
805 }
806 if ($BondsToHydrogenAtomsOnly && (!$BondedAtom->IsHydrogen())) {
807 next BOND;
808 }
809 push @FilteredBonds, $Bond;
810 }
811
812 return wantarray ? @FilteredBonds : (scalar @FilteredBonds);
813 }
814
815 # Get number of bonds...
816 #
817 sub GetNumOfBonds {
818 my($This) = @_;
819 my($NumOfBonds);
820
821 $NumOfBonds = $This->GetBonds();
822
823 return (defined $NumOfBonds) ? ($NumOfBonds) : undef;
824 }
825
826 # Get number of bonds to non-hydrogen atoms...
827 sub GetNumOfBondsToHeavyAtoms {
828 my($This) = @_;
829
830 return $This->GetNumOfBondsToNonHydrogenAtoms();
831 }
832
833 # Get number of bonds to non-hydrogen atoms...
834 sub GetNumOfBondsToNonHydrogenAtoms {
835 my($This) = @_;
836 my($NumOfBonds);
837
838 $NumOfBonds = $This->GetBondsToNonHydrogenAtoms();
839
840 return (defined $NumOfBonds) ? ($NumOfBonds) : undef;
841 }
842
843 # Get number of single bonds to heavy atoms...
844 sub GetNumOfSingleBondsToHeavyAtoms {
845 my($This) = @_;
846
847 return $This->GetNumOfSingleBondsToNonHydrogenAtoms();
848 }
849
850 # Get number of single bonds to non-hydrogen atoms...
851 sub GetNumOfSingleBondsToNonHydrogenAtoms {
852 my($This) = @_;
853
854 # Is this atom in a molecule?
855 if (!$This->HasProperty('Molecule')) {
856 return undef;
857 }
858 return $This->_GetNumOfBondsWithSpecifiedBondOrderToNonHydrogenAtoms(1);
859 }
860
861 # Get number of double bonds to heavy atoms...
862 sub GetNumOfDoubleBondsToHeavyAtoms {
863 my($This) = @_;
864
865 return $This->GetNumOfDoubleBondsToNonHydrogenAtoms();
866 }
867
868 # Get number of double bonds to non-hydrogen atoms...
869 sub GetNumOfDoubleBondsToNonHydrogenAtoms {
870 my($This) = @_;
871
872 # Is this atom in a molecule?
873 if (!$This->HasProperty('Molecule')) {
874 return undef;
875 }
876 return $This->_GetNumOfBondsWithSpecifiedBondOrderToNonHydrogenAtoms(2);
877 }
878
879 # Get number of triple bonds to heavy atoms...
880 sub GetNumOfTripleBondsToHeavyAtoms {
881 my($This) = @_;
882
883 return $This->GetNumOfTripleBondsToNonHydrogenAtoms();
884 }
885
886 # Get number of triple bonds to non-hydrogen atoms...
887 sub GetNumOfTripleBondsToNonHydrogenAtoms {
888 my($This) = @_;
889
890 # Is this atom in a molecule?
891 if (!$This->HasProperty('Molecule')) {
892 return undef;
893 }
894 return $This->_GetNumOfBondsWithSpecifiedBondOrderToNonHydrogenAtoms(3);
895 }
896
897 # Get number of bonds of specified bond order to non-hydrogen atoms...
898 sub _GetNumOfBondsWithSpecifiedBondOrderToNonHydrogenAtoms {
899 my($This, $SpecifiedBondOrder) = @_;
900 my($NumOfBonds, $Bond, $BondOrder, @Bonds);
901
902 $NumOfBonds = 0;
903 @Bonds = $This->GetBondsToNonHydrogenAtoms();
904 for $Bond (@Bonds) {
905 $BondOrder = $Bond->GetBondOrder();
906 if ($SpecifiedBondOrder == $BondOrder) {
907 $NumOfBonds++;
908 }
909 }
910 return $NumOfBonds;
911 }
912
913 # Get number of aromatic bonds to heavy atoms...
914 sub GetNumOfAromaticBondsToHeavyAtoms {
915 my($This) = @_;
916
917 return $This->GetNumOfAromaticBondsToNonHydrogenAtoms();
918 }
919
920 # Get number of aromatic bonds to non-hydrogen atoms...
921 sub GetNumOfAromaticBondsToNonHydrogenAtoms {
922 my($This) = @_;
923 my($NumOfBonds, $Bond, @Bonds);
924
925 # Is this atom in a molecule?
926 if (!$This->HasProperty('Molecule')) {
927 return undef;
928 }
929
930 $NumOfBonds = 0;
931 @Bonds = $This->GetBondsToNonHydrogenAtoms();
932 for $Bond (@Bonds) {
933 if ($Bond->IsAromatic()) { $NumOfBonds++; }
934 }
935 return $NumOfBonds;
936 }
937
938 # Get number of different bond types to non-hydrogen atoms...
939 #
940 sub GetNumOfBondTypesToHeavyAtoms {
941 my($This, $CountAromaticBonds) = @_;
942
943 return $This->GetNumOfBondTypesToNonHydrogenAtoms($CountAromaticBonds);
944 }
945
946 # Get number of single, double, triple, and aromatic bonds from an atom to all other
947 # non-hydrogen atoms. Value of CountAtomaticBonds parameter controls whether
948 # number of aromatic bonds is returned; default is not to count aromatic bonds. During
949 # counting of aromatic bonds, the bond marked aromatic is not included in the count
950 # of other bond types.
951 #
952 sub GetNumOfBondTypesToNonHydrogenAtoms {
953 my($This, $CountAromaticBonds) = @_;
954 my($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds, $None, $Bond, @Bonds);
955
956 $CountAromaticBonds = defined($CountAromaticBonds) ? $CountAromaticBonds : 0;
957
958 ($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds) = ('0') x 3;
959 $NumOfAromaticBonds = $CountAromaticBonds ? 0 : undef;
960
961 # Is this atom in a molecule?
962 if (!$This->HasProperty('Molecule')) {
963 return ($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds);
964 }
965
966 @Bonds = $This->GetBondsToNonHydrogenAtoms();
967
968 for $Bond (@Bonds) {
969 BONDTYPE: {
970 if ($CountAromaticBonds) {
971 if ($Bond->IsAromatic()) { $NumOfAromaticBonds++; last BONDTYPE; }
972 }
973 if ($Bond->IsSingle()) { $NumOfSingleBonds++; last BONDTYPE; }
974 if ($Bond->IsDouble()) { $NumOfDoubleBonds++; last BONDTYPE; }
975 if ($Bond->IsTriple()) { $NumOfTripleBonds++; last BONDTYPE; }
976 $None = 1;
977 }
978 }
979 return ($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds);
980 }
981
982 # Get number of sigma and pi bonds to heavy atoms...
983 #
984 sub GetNumOfSigmaAndPiBondsToHeavyAtoms {
985 my($This) = @_;
986
987 return $This->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms();
988 }
989
990 # Get number of sigma and pi bonds from an atom to all other non-hydrogen atoms.
991 # Sigma and pi bonds are counted using the following methodology: a single bond
992 # correspond to one sigma bond; a double bond contributes one to sigma bond count
993 # and one to pi bond count; a triple bond contributes one to sigma bond count and
994 # two to pi bond count.
995 #
996 sub GetNumOfSigmaAndPiBondsToNonHydrogenAtoms {
997 my($This) = @_;
998 my($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfSigmaBonds, $NumOfPiBonds);
999
1000 ($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds) = $This->GetNumOfBondTypesToNonHydrogenAtoms();
1001
1002 $NumOfSigmaBonds = $NumOfSingleBonds + $NumOfDoubleBonds + $NumOfTripleBonds;
1003 $NumOfPiBonds = $NumOfDoubleBonds + 2*$NumOfTripleBonds;
1004
1005 return ($NumOfSigmaBonds, $NumOfPiBonds);
1006 }
1007
1008 # Get information related to atoms for all heavy atoms attached to an atom..
1009 #
1010 sub GetHeavyAtomNeighborsAtomInformation {
1011 my($This) = @_;
1012
1013 return $This->GetNonHydrogenAtomNeighborsAtomInformation();
1014 }
1015
1016 # Get information related to atoms for all non-hydrogen atoms attached to an atom..
1017 #
1018 # The following values are returned:
1019 # . Number of non-hydrogen atom neighbors
1020 # . A reference to an array containing atom objects correpsonding to non-hydrogen
1021 # atom neighbors
1022 # . Number of different types of non-hydrogen atom neighbors
1023 # . A reference to a hash containing atom symbol as key with value corresponding
1024 # to its count for non-hydrogen atom neighbors
1025 #
1026 sub GetNonHydrogenAtomNeighborsAtomInformation {
1027 my($This) = @_;
1028
1029 # Is this atom in a molecule?
1030 if (!$This->HasProperty('Molecule')) {
1031 return (undef, undef, undef, undef);
1032 }
1033 my($AtomSymbol, $AtomNeighbor, $NumOfAtomNeighbors, $NumOfAtomNeighborsType, @AtomNeighbors, %AtomNeighborsTypeMap);
1034
1035 $NumOfAtomNeighbors = 0; @AtomNeighbors = ();
1036 $NumOfAtomNeighborsType = 0; %AtomNeighborsTypeMap = ();
1037
1038 @AtomNeighbors = $This->GetNonHydrogenAtomNeighbors();
1039 $NumOfAtomNeighbors = scalar @AtomNeighbors;
1040
1041 for $AtomNeighbor (@AtomNeighbors) {
1042 $AtomSymbol = $AtomNeighbor->{AtomSymbol};
1043 if (exists $AtomNeighborsTypeMap{$AtomSymbol}) {
1044 $AtomNeighborsTypeMap{$AtomSymbol} += 1;
1045 }
1046 else {
1047 $AtomNeighborsTypeMap{$AtomSymbol} = 1;
1048 $NumOfAtomNeighborsType++;
1049 }
1050 }
1051
1052 return ($NumOfAtomNeighbors, \@AtomNeighbors, $NumOfAtomNeighborsType, \%AtomNeighborsTypeMap);
1053 }
1054
1055 # Get information related to bonds for all heavy atoms attached to an atom..
1056 #
1057 sub GetHeavyAtomNeighborsBondformation {
1058 my($This) = @_;
1059
1060 return $This->GetNonHydrogenAtomNeighborsBondInformation();
1061 }
1062
1063 # Get information related to bonds for all non-hydrogen atoms attached to an atom..
1064 #
1065 # The following values are returned:
1066 # . Number of bonds to non-hydrogen atom neighbors
1067 # . A reference to an array containing bond objects correpsonding to non-hydrogen
1068 # atom neighbors
1069 # . A reference to a hash containing bond type as key with value corresponding
1070 # to its count for non-hydrogen atom neighbors. Bond types are: Single, Double or Triple
1071 # . A reference to a hash containing atom symbol as key pointing to bond type as second
1072 # key with values correponding to count of bond types for atom symbol for non-hydrogen
1073 # atom neighbors
1074 # . A reference to a hash containing atom symbol as key pointing to bond type as second
1075 # key with values correponding to atom objects array involved in corresponding bond type for
1076 # atom symbol for non-hydrogen atom neighbors
1077 #
1078 sub GetNonHydrogenAtomNeighborsBondInformation {
1079 my($This) = @_;
1080
1081 # Is this atom in a molecule?
1082 if (!$This->HasProperty('Molecule')) {
1083 return (undef, undef, undef, undef, undef);
1084 }
1085 my($BondedAtom, $BondedAtomSymbol, $BondType, $None, $Bond, $NumOfBonds, @Bonds, %BondTypeCountMap, %AtomsBondTypesCountMap, %AtomsBondTypeAtomsMap);
1086
1087 $NumOfBonds = 0; @Bonds = ();
1088 %BondTypeCountMap = ();
1089 %AtomsBondTypesCountMap = (); %AtomsBondTypeAtomsMap = ();
1090
1091 $BondTypeCountMap{Single} = 0;
1092 $BondTypeCountMap{Double} = 0;
1093 $BondTypeCountMap{Triple} = 0;
1094
1095 @Bonds = $This->GetBondsToNonHydrogenAtoms();
1096 $NumOfBonds = scalar @Bonds;
1097
1098 BOND: for $Bond (@Bonds) {
1099 $BondType = $Bond->IsSingle() ? "Single" : ($Bond->IsDouble() ? "Double" : ($Bond->IsTriple() ? "Triple" : ""));
1100 if (!$BondType) {
1101 next BOND;
1102 }
1103
1104 # Track bond types...
1105 if (exists $BondTypeCountMap{$BondType}) {
1106 $BondTypeCountMap{$BondType} += 1;
1107 }
1108 else {
1109 $BondTypeCountMap{$BondType} = 1;
1110 }
1111
1112 $BondedAtom = $Bond->GetBondedAtom($This);
1113 $BondedAtomSymbol = $BondedAtom->{AtomSymbol};
1114
1115 # Track bond types count for atom types involved in specific bond types...
1116 if (!exists $AtomsBondTypesCountMap{$BondedAtomSymbol}) {
1117 %{$AtomsBondTypesCountMap{$BondedAtomSymbol}} = ();
1118 }
1119 if (exists $AtomsBondTypesCountMap{$BondedAtomSymbol}{$BondType}) {
1120 $AtomsBondTypesCountMap{$BondedAtomSymbol}{$BondType} += 1;
1121 }
1122 else {
1123 $AtomsBondTypesCountMap{$BondedAtomSymbol}{$BondType} = 1;
1124 }
1125
1126 # Track atoms involved in specific bond types for specific atom types...
1127 if (!exists $AtomsBondTypeAtomsMap{$BondedAtomSymbol}) {
1128 %{$AtomsBondTypeAtomsMap{$BondedAtomSymbol}} = ();
1129 }
1130 if (!exists $AtomsBondTypeAtomsMap{$BondedAtomSymbol}{$BondType}) {
1131 @{$AtomsBondTypeAtomsMap{$BondedAtomSymbol}{$BondType}} = ();
1132 }
1133 push @{$AtomsBondTypeAtomsMap{$BondedAtomSymbol}{$BondType}}, $BondedAtom;
1134 }
1135
1136 return ($NumOfBonds, \@Bonds, \%BondTypeCountMap, \%AtomsBondTypesCountMap, \%AtomsBondTypeAtomsMap);
1137 }
1138
1139 # Get number of bonds to hydrogen atoms...
1140 sub GetNumOfBondsToHydrogenAtoms {
1141 my($This) = @_;
1142 my($NumOfBonds);
1143
1144 $NumOfBonds = $This->GetBondsToHydrogenAtoms();
1145
1146 return (defined $NumOfBonds) ? ($NumOfBonds) : undef;
1147 }
1148
1149 # Get sum of bond orders to all bonded atoms...
1150 #
1151 sub GetSumOfBondOrders {
1152 my($This) = @_;
1153
1154 # Is this atom in a molecule?
1155 if (!$This->HasProperty('Molecule')) {
1156 return undef;
1157 }
1158
1159 return $This->_GetSumOfBondOrders();
1160 }
1161
1162 # Get sum of bond orders to non-hydrogen atoms only...
1163 #
1164 sub GetSumOfBondOrdersToHeavyAtoms {
1165 my($This) = @_;
1166
1167 return $This->GetSumOfBondOrdersToNonHydrogenAtoms();
1168 }
1169
1170 # Get sum of bond orders to non-hydrogen atoms only...
1171 #
1172 sub GetSumOfBondOrdersToNonHydrogenAtoms {
1173 my($This) = @_;
1174
1175 # Is this atom in a molecule?
1176 if (!$This->HasProperty('Molecule')) {
1177 return undef;
1178 }
1179 my($ToNonHydrogenAtomsOnly, $ToHydrogenAtomsOnly) = (1, 0);
1180
1181 return $This->_GetSumOfBondOrders($ToNonHydrogenAtomsOnly, $ToHydrogenAtomsOnly);
1182 }
1183
1184 # Get sum of bond orders to hydrogen atoms only...
1185 #
1186 sub GetSumOfBondOrdersToHydrogenAtoms {
1187 my($This) = @_;
1188
1189 # Is this atom in a molecule?
1190 if (!$This->HasProperty('Molecule')) {
1191 return undef;
1192 }
1193 my($ToNonHydrogenAtomsOnly, $ToHydrogenAtomsOnly) = (0, 1);
1194
1195 return $This->_GetSumOfBondOrders($ToNonHydrogenAtomsOnly, $ToHydrogenAtomsOnly);
1196 }
1197
1198 # Get sum of bond orders to all bonded atoms, non-hydrogen or hydrogen bonded atoms...
1199 #
1200 sub _GetSumOfBondOrders {
1201 my($This, $ToNonHydrogenAtomsOnly, $ToHydrogenAtomsOnly) = @_;
1202
1203 # Check flags...
1204 if (!defined $ToNonHydrogenAtomsOnly) {
1205 $ToNonHydrogenAtomsOnly = 0;
1206 }
1207 if (!defined $ToHydrogenAtomsOnly) {
1208 $ToHydrogenAtomsOnly = 0;
1209 }
1210 my($Bond, $SumOfBondOrders, @Bonds);
1211 @Bonds = ();
1212
1213 if ($ToNonHydrogenAtomsOnly) {
1214 @Bonds = $This->GetBondsToNonHydrogenAtoms();
1215 }
1216 elsif ($ToHydrogenAtomsOnly) {
1217 @Bonds = $This->GetBondsToHydrogenAtoms();
1218 }
1219 else {
1220 # All bonds...
1221 @Bonds = $This->GetBonds();
1222 }
1223
1224 $SumOfBondOrders = 0;
1225 for $Bond (@Bonds) {
1226 $SumOfBondOrders += $Bond->GetBondOrder();
1227 }
1228
1229 if ($SumOfBondOrders =~ /\./) {
1230 #
1231 # Change any fractional bond order to next largest integer...
1232 #
1233 # As long as aromatic bond orders in a ring are correctly using using 4n + 2 Huckel rule
1234 # (BondOrder: 1.5) or explicity set as Kekule bonds (alternate single/double),
1235 # SumOfBondOrders should add up to an integer.
1236 #
1237 $SumOfBondOrders = ceil($SumOfBondOrders);
1238 }
1239
1240 return $SumOfBondOrders;
1241 }
1242
1243 # Get largest bond order to any bonded atoms...
1244 #
1245 sub GetLargestBondOrder {
1246 my($This) = @_;
1247
1248 # Is this atom in a molecule?
1249 if (!$This->HasProperty('Molecule')) {
1250 return undef;
1251 }
1252
1253 return $This->_GetLargestBondOrder();
1254 }
1255
1256 # Get largest bond order to bonded non-hydrogen atoms...
1257 #
1258 sub GetLargestBondOrderToHeavyAtoms {
1259 my($This) = @_;
1260
1261 return $This->GetLargestBondOrderToNonHydrogenAtoms();
1262 }
1263
1264 # Get largest bond order to bonded non-hydrogen atoms...
1265 #
1266 sub GetLargestBondOrderToNonHydrogenAtoms {
1267 my($This) = @_;
1268
1269 # Is this atom in a molecule?
1270 if (!$This->HasProperty('Molecule')) {
1271 return undef;
1272 }
1273
1274 my($ToNonHydrogenAtomsOnly) = (1);
1275
1276 return $This->_GetLargestBondOrder($ToNonHydrogenAtomsOnly);
1277 }
1278
1279 # Get largest bond order to all bonded atoms, non-hydrogen or hydrogen bonded atoms...
1280 #
1281 sub _GetLargestBondOrder {
1282 my($This, $ToNonHydrogenAtomsOnly, $ToHydrogenAtomsOnly) = @_;
1283
1284 # Check flags...
1285 if (!defined $ToNonHydrogenAtomsOnly) {
1286 $ToNonHydrogenAtomsOnly = 0;
1287 }
1288 if (!defined $ToHydrogenAtomsOnly) {
1289 $ToHydrogenAtomsOnly = 0;
1290 }
1291 my($Bond, $LargestBondOrder, $BondOrder, @Bonds);
1292 @Bonds = ();
1293
1294 if ($ToNonHydrogenAtomsOnly) {
1295 @Bonds = $This->GetBondsToNonHydrogenAtoms();
1296 }
1297 elsif ($ToHydrogenAtomsOnly) {
1298 @Bonds = $This->GetBondsToHydrogenAtoms();
1299 }
1300 else {
1301 # All bonds...
1302 @Bonds = $This->GetBonds();
1303 }
1304
1305 $LargestBondOrder = 0;
1306 for $Bond (@Bonds) {
1307 $BondOrder = $Bond->GetBondOrder();
1308 if ($BondOrder > $LargestBondOrder) {
1309 $LargestBondOrder = $BondOrder;
1310 }
1311 }
1312
1313 return $LargestBondOrder;
1314 }
1315
1316 # Get number of implicit hydrogen for atom...
1317 #
1318 sub GetImplicitHydrogens {
1319 my($This) = @_;
1320
1321 return $This->GetNumOfImplicitHydrogens();
1322 }
1323
1324 # Get number of implicit hydrogen for atom...
1325 #
1326 sub GetNumOfImplicitHydrogens {
1327 my($This) = @_;
1328
1329 # Is this atom in a molecule?
1330 if (!$This->HasProperty('Molecule')) {
1331 return undef;
1332 }
1333
1334 # Is ImplicitHydrogens property explicitly set?
1335 if ($This->HasProperty('ImplicitHydrogens')) {
1336 return $This->GetProperty('ImplicitHydrogens');
1337 }
1338
1339 # Is it an element symbol?
1340 if (!$This->{AtomicNumber}) {
1341 return 0;
1342 }
1343
1344 my($ImplicitHydrogens, $PotentialTotalValence, $SumOfBondOrders);
1345
1346 $ImplicitHydrogens = 0;
1347 $SumOfBondOrders = $This->GetSumOfBondOrders();
1348 $PotentialTotalValence = $This->GetPotentialTotalCommonValence();
1349
1350 if (defined($PotentialTotalValence) && defined($SumOfBondOrders)) {
1351 # Subtract sum of bond orders to non-hydrogen and hydrogen atom neighbors...
1352 $ImplicitHydrogens = $PotentialTotalValence - $SumOfBondOrders;
1353 }
1354
1355 return $ImplicitHydrogens > 0 ? $ImplicitHydrogens : 0;
1356 }
1357
1358 # Get number of bonds available to form additional bonds with heavy atoms, excluding
1359 # any implicit bonds to hydrogens set using ImplicitHydrogens property.
1360 #
1361 # It's different from number of implicit or missing hydrogens, both of which are equivalent.
1362 #
1363 # For example, in a SMILES string, [nH] ring atom corresponds to an aromatic nitrogen.
1364 # Although the hydrogen specified for n is treated internally as implicit hydrogen and shows
1365 # up in missing hydrogen count, it's not available to participate in double bonds to additional
1366 # heavy atoms.
1367 #
1368 sub GetNumOfBondsAvailableForHeavyAtoms {
1369 my($This) = @_;
1370
1371 return $This->GetNumOfBondsAvailableForNonHydrogenAtoms();
1372 }
1373
1374 # It's another name for GetNumOfBondsAvailableForHeavyAtoms
1375 #
1376 sub GetNumOfBondsAvailableForNonHydrogenAtoms {
1377 my($This) = @_;
1378 my($NumOfAvailableBonds, $PotentialTotalValence, $SumOfBondOrders);
1379
1380 $NumOfAvailableBonds = 0;
1381
1382 $SumOfBondOrders = $This->GetSumOfBondOrders();
1383 $PotentialTotalValence = $This->GetPotentialTotalCommonValence();
1384
1385 if (defined($PotentialTotalValence) && defined($SumOfBondOrders)) {
1386 # Subtract sum of bond orders to non-hydrogen and hydrogen atom neighbors...
1387 $NumOfAvailableBonds = $PotentialTotalValence - $SumOfBondOrders;
1388 }
1389
1390 if ($This->HasProperty('ImplicitHydrogens')) {
1391 $NumOfAvailableBonds -= $This->GetProperty('ImplicitHydrogens');
1392 }
1393
1394 return $NumOfAvailableBonds > 0 ? $NumOfAvailableBonds : 0;
1395 }
1396
1397 # Disable setting of explicit hydrogens property...
1398 sub SetExplicitHydrogens {
1399 my($This, $Value) = @_;
1400
1401 carp "Warning: ${ClassName}->SetExplicitHydrogens: Setting of explicit hydrogens is not supported...";
1402
1403 return $This;
1404 }
1405
1406 # Get number of explicit hydrogens for atom...
1407 #
1408 sub GetExplicitHydrogens {
1409 my($This) = @_;
1410
1411 return $This->GetNumOfExplicitHydrogens();
1412 }
1413
1414 # Get number of explicit hydrogens for atom...
1415 #
1416 sub GetNumOfExplicitHydrogens {
1417 my($This) = @_;
1418 my($HydrogenAtomNbrs);
1419
1420 # Is this atom in a molecule?
1421 if (!$This->HasProperty('Molecule')) {
1422 return undef;
1423 }
1424
1425 $HydrogenAtomNbrs = $This->GetNumOfHydrogenAtomNeighbors();
1426
1427 return defined $HydrogenAtomNbrs ? $HydrogenAtomNbrs : 0;
1428 }
1429
1430 # Get num of missing hydrogens...
1431 #
1432 sub GetMissingHydrogens {
1433 my($This) = @_;
1434
1435 return $This->GetNumOfMissingHydrogens();
1436 }
1437
1438 # Get num of missing hydrogens...
1439 #
1440 sub GetNumOfMissingHydrogens {
1441 my($This) = @_;
1442
1443 # Is this atom in a molecule?
1444 if (!$This->HasProperty('Molecule')) {
1445 return undef;
1446 }
1447
1448 return $This->GetNumOfImplicitHydrogens();
1449 }
1450
1451 # Get total number of hydrogens...
1452 #
1453 sub GetHydrogens {
1454 my($This) = @_;
1455
1456 return $This->GetNumOfHydrogens();
1457 }
1458
1459 # Get total number of hydrogens...
1460 #
1461 sub GetNumOfHydrogens {
1462 my($This) = @_;
1463
1464 # Is this atom in a molecule?
1465 if (!$This->HasProperty('Molecule')) {
1466 return undef;
1467 }
1468
1469 return $This->GetNumOfImplicitHydrogens() + $This->GetNumOfExplicitHydrogens();
1470 }
1471
1472 # Valence corresponds to the number of electrons used by an atom in bonding:
1473 #
1474 # Valence = ValenceElectrons - ValenceFreeElectrons = BondingElectrons
1475 #
1476 # Single, double, triple bonds with bond orders of 1, 2 and 3 correspond to contribution of
1477 # 1, 2, and 3 bonding electrons. So Valence can be computed using:
1478 #
1479 # Valence = SumOfBondOrders + NumOfMissingHydrogens + FormalCharge
1480 #
1481 # where positive and negative values of FormalCharge increase and decrease the number
1482 # of bonding electrons respectively.
1483 #
1484 # The current release of MayaChemTools supports the following three valence models, which
1485 # are used during calculation of implicit hydrogens: MDLValenceModel, DaylightValenceModel,
1486 # InternalValenceModel or MayaChemToolsValenceModel.
1487 #
1488 # Notes:
1489 # . This doesn't always corresponds to explicit valence.
1490 # . Missing hydrogens are included in the valence.
1491 # . For neutral molecules, valence and sum of bond order are equal.
1492 # . For molecules containing only single bonds, SumOfBondOrders and NumOfBonds are equal.
1493 # . Free radical electrons lead to the decrease in valence. For atoms with explicit assignment
1494 # of SpinMultiplicity property values corresponding to Singlet (two unparied electrons
1495 # corresponding to one spin state), Doublet (free radical; an unpaired electron corresponding
1496 # to two spin states), and Triplet (two unparied electrons corresponding to three spin states;
1497 # divalent carbon atoms (carbenes)), FreeRadicalElectrons are calculated as follows:
1498 #
1499 # SpinMultiplicity: Doublet(2); FreeRadicalElectrons: 1 (one valence electron not available for bonding)
1500 # SpinMultiplicity: Singlet(1)/Triplet(3); FreeRadicalElectrons: 2 (two valence electrons not available for bonding)
1501 #
1502 sub GetValence {
1503 my($This) = @_;
1504
1505 # Is this atom in a molecule?
1506 if (!$This->HasProperty('Molecule')) {
1507 return undef;
1508 }
1509
1510 # Is Valence property explicitly set?
1511 if ($This->HasProperty('Valence')) {
1512 return $This->GetProperty('Valence');
1513 }
1514 my($Valence);
1515
1516 $Valence = $This->GetSumOfBondOrders() + $This->GetNumOfMissingHydrogens() + $This->GetFormalCharge();
1517
1518 return $Valence > 0 ? $Valence : 0;
1519 }
1520
1521 # Get free non-bodning valence electrons left on atom after taking into account
1522 # sum of bond orders, missing hydrogens and formal charged on the atom. Free
1523 # radical electrons are included in the valence free electrons count by default.
1524 #
1525 # Valence corresponds to number of electrons used by atom in bonding:
1526 #
1527 # Valence = ValenceElectrons - ValenceFreeElectrons
1528 #
1529 # Additionally, valence can also be calculated by:
1530 #
1531 # Valence = SumOfBondOrders + NumOfMissingHydrogens + FormalCharge
1532 #
1533 # Valence and SumOfBondOrders are equal for neutral molecules.
1534 #
1535 # From two formulas for Valence described above, non-bonding free electrons
1536 # left can be computed by:
1537 #
1538 # ValenceFreeElectrons = ValenceElectrons - Valence
1539 # = ValenceElectrons - SumOfBondOrders -
1540 # NumOfMissingHydrogens - FormalCharge
1541 #
1542 # . Notes:
1543 # . Missing hydrogens are excluded from the valence free electrons.
1544 # . Any free radical electrons are considered part of the valence free electrons
1545 # by default.
1546 #
1547 # Examples:
1548 #
1549 # o NH3: ValenceFreeElectrons = 5 - 3 = 5 - 3 - 0 - 0 = 2
1550 # o NH2: ValenceFreeElectrons = 5 - 3 = 5 - 2 - 1 - 0 = 2
1551 # o NH4+; ValenceFreeElectrons = 5 - 5 = 5 - 4 - 0 - 1 = 0
1552 # o NH3+; ValenceFreeElectrons = 5 - 5 = 5 - 3 - 1 - 1 = 0
1553 # o C(=O)O- : ValenceFreeElectrons on O- = 6 - 0 = 6 - 1 - 0 - (-1) = 6
1554 # o C(=O)O- : ValenceFreeElectrons on =O = 6 - 2 = 6 - 2 - 0 - 0 = 4
1555 #
1556 #
1557 sub GetValenceFreeElectrons {
1558 my($This, $ExcludeFreeRadicalElectrons) = @_;
1559
1560 # Is this atom in a molecule?
1561 if (!$This->HasProperty('Molecule')) {
1562 return undef;
1563 }
1564
1565 # Is ValenceFreeElectrons property explicitly set?
1566 if ($This->HasProperty('ValenceFreeElectrons')) {
1567 return $This->GetProperty('ValenceFreeElectrons');
1568 }
1569
1570 if (!$This->{AtomicNumber}) {
1571 return 0;
1572 }
1573
1574 my($ValenceFreeElectrons);
1575
1576 $ValenceFreeElectrons = $This->GetValenceElectrons() - $This->GetValence();
1577 if ($ExcludeFreeRadicalElectrons) {
1578 $ValenceFreeElectrons -= $This->GetFreeRadicalElectrons();
1579 }
1580
1581 return $ValenceFreeElectrons > 0 ? $ValenceFreeElectrons : 0;
1582 }
1583
1584 # Get potential total common valence for calculating the number of implicit hydrogens
1585 # using the specified common valence model or default internal model for a molecule...
1586 #
1587 sub GetPotentialTotalCommonValence {
1588 my($This) = @_;
1589
1590 # Is this atom in a molecule?
1591 if (!$This->HasProperty('Molecule')) {
1592 return undef;
1593 }
1594 my($PotentialTotalValence, $ValenceModel);
1595
1596 $PotentialTotalValence = 0;
1597 $ValenceModel = $This->GetProperty('Molecule')->GetValenceModel();
1598
1599 VALENCEMODEL: {
1600 if ($ValenceModel =~ /^MDLValenceModel$/i) {
1601 $PotentialTotalValence = $This->_GetPotentialTotalCommonValenceUsingMDLValenceModel();
1602 last VALENCEMODEL;
1603 }
1604 if ($ValenceModel =~ /^DaylightValenceModel$/i) {
1605 $PotentialTotalValence = $This->_GetPotentialTotalCommonValenceUsingDaylightValenceModel();
1606 last VALENCEMODEL;
1607 }
1608 if ($ValenceModel !~ /^(InternalValenceModel|MayaChemToolsValenceModel)$/i) {
1609 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...";
1610 }
1611 # Use internal valence model as the default valence model...
1612 $PotentialTotalValence = $This->_GetPotentialTotalCommonValenceUsingInternalValenceModel();
1613 }
1614
1615 return $PotentialTotalValence;
1616 }
1617
1618 # Get potential total common valence using data for MDL valence model available in file,
1619 # lib/data/MDLValenceModelData.csv, distributed with the package...
1620 #
1621 sub _GetPotentialTotalCommonValenceUsingMDLValenceModel {
1622 my($This) = @_;
1623
1624 return $This->_GetPotentialTotalCommonValenceUsingValenceModelData(\%MDLValenceModelDataMap);
1625
1626 }
1627
1628 # Get potential total common valence using data for Daylight valence model available in file,
1629 # lib/data/DaylightValenceModelData.csv, distributed with the release...
1630 #
1631 sub _GetPotentialTotalCommonValenceUsingDaylightValenceModel {
1632 my($This) = @_;
1633
1634 return $This->_GetPotentialTotalCommonValenceUsingValenceModelData(\%DaylightValenceModelDataMap);
1635 }
1636
1637 # Get potential total common valence using data for a specific valence model...
1638 #
1639 sub _GetPotentialTotalCommonValenceUsingValenceModelData {
1640 my($This, $ValenceModelDataRef) = @_;
1641 my($AtomicNumber, $FormalCharge);
1642
1643 $AtomicNumber = $This->{AtomicNumber};
1644 if (!$AtomicNumber) {
1645 return 0;
1646 }
1647
1648 $FormalCharge = $This->GetFormalCharge();
1649
1650 # Is any valence model data available for atomic number and formal charge?
1651 if (!exists $ValenceModelDataRef->{$AtomicNumber}) {
1652 return 0;
1653 }
1654 if (!exists $ValenceModelDataRef->{$AtomicNumber}{$FormalCharge}) {
1655 return 0;
1656 }
1657
1658 my($PotentialTotalValence, $SumOfBondOrders, $CurrentEffectiveValence, $AvailableCommonValence);
1659
1660 $SumOfBondOrders = $This->GetSumOfBondOrders();
1661 if (!defined $SumOfBondOrders) {
1662 $SumOfBondOrders = 0;
1663 }
1664 $CurrentEffectiveValence = $SumOfBondOrders + $This->GetFreeRadicalElectrons();
1665
1666 $PotentialTotalValence = 0;
1667 VALENCE: for $AvailableCommonValence (@{$ValenceModelDataRef->{$AtomicNumber}{$FormalCharge}{CommonValences}}) {
1668 if ($CurrentEffectiveValence <= $AvailableCommonValence) {
1669 $PotentialTotalValence = $AvailableCommonValence;
1670 last VALENCE;
1671 }
1672 }
1673
1674 return $PotentialTotalValence;
1675 }
1676
1677 #
1678 # For elements with one one common valence, potential total common valence used
1679 # during the calculation for number of implicit hydrogens during InternalValenceMode
1680 # corresponds to:
1681 #
1682 # CommonValence + FormalCharge - FreeRadicalElectrons
1683 #
1684 # For elements with multiple common valences, each common valence is used to
1685 # calculate total potential common valence as shown above, and the first total potential
1686 # common valence gerater than the sum of bond orderes is selected as the final total
1687 # common valence.
1688 #
1689 # Group numbers > 14 - Group numbers 15 (N), 16 (O), 17 (F), 18 (He)
1690 #
1691 # Formal charge sign is not adjusted. Positive and negative values result in the
1692 # increase and decrease of valence.
1693 #
1694 # Group 14 containing C, Si, Ge, Sn, Pb...
1695 #
1696 # Formal charge sign is reversed for positive values. Both positive and negative
1697 # values result in the decrease of valence.
1698 #
1699 # Group 13 containing B, Al, Ga, In, Tl...
1700 #
1701 # Formal charge sign is always reversed. Positive and negative values result in the
1702 # decrease and increase of valence.
1703 #
1704 # Groups 1 (H) through 12 (Zn)...
1705 #
1706 # Formal charge sign is reversed for positive values. Both positive and negative
1707 # values result in the decrease of valence.
1708 #
1709 # Lanthanides and actinides...
1710 #
1711 # Formal charge sign is reversed for positive values. Both positive and negative
1712 # values result in the decrease of valence.
1713 #
1714 # Notes:
1715 # . CommonValence and HighestCommonValence available from PeriodicTable module
1716 # are equivalent to most common and highest sum of bond orders for an element. For
1717 # neutral atoms involved only in single bonds, it corresponds to highest number of
1718 # allowed bonds for the atom.
1719 # . FormalCharge sign is reversed for electropositive elements with positive formal charge
1720 # during common valence calculations. Electropositive elements, metals and transition elements,
1721 # have usually plus formal charge and it leads to decrease in common valence; the negative
1722 # formal charge should result in the decrease of common valence.
1723 # . For carbon, both plus/minus formal charge cause decrease in common valence
1724 # . For elements on the right of carbon in periodic table, electronegative elements, plus formal
1725 # charge causes common valence to increase and minus formal charge cause it to decrease.
1726 #
1727 sub _GetPotentialTotalCommonValenceUsingInternalValenceModel {
1728 my($This) = @_;
1729 my($AtomicNumber, $CommonValences);
1730
1731 $AtomicNumber = $This->{AtomicNumber};
1732 if (!$AtomicNumber) {
1733 return 0;
1734 }
1735
1736 $CommonValences = PeriodicTable::GetElementCommonValences($AtomicNumber);
1737 if (!$CommonValences) {
1738 return 0;
1739 }
1740
1741 my($PotentialTotalValence, $AdjustedFormalCharge, $FreeRadicalElectrons, $SumOfBondOrders, $AvailableCommonValence, @AvailableCommonValences);
1742
1743 $AdjustedFormalCharge = $This->_GetFormalChargeAdjustedForInternalValenceModel();
1744 $FreeRadicalElectrons = $This->GetFreeRadicalElectrons();
1745
1746 $SumOfBondOrders = $This->GetSumOfBondOrders();
1747 if (!defined $SumOfBondOrders) {
1748 $SumOfBondOrders = 0;
1749 }
1750
1751 @AvailableCommonValences = split /\,/, $CommonValences;
1752
1753 if (@AvailableCommonValences == 1) {
1754 # Calculate potential total valence using the only available common valence...
1755 $PotentialTotalValence = $AvailableCommonValences[0] + $AdjustedFormalCharge - $FreeRadicalElectrons;
1756 }
1757 else {
1758 # Calculate potential total valence using common valence from a list of available valences
1759 # that makes it higher than sum of bond orders or using the highest common valence...
1760 VALENCE: for $AvailableCommonValence (@AvailableCommonValences) {
1761 $PotentialTotalValence = $AvailableCommonValence + $AdjustedFormalCharge - $FreeRadicalElectrons;
1762
1763 if ($PotentialTotalValence < 0 || $PotentialTotalValence >= $SumOfBondOrders) {
1764 last VALENCE;
1765 }
1766 }
1767 }
1768
1769 return $PotentialTotalValence > 0 ? $PotentialTotalValence : 0;
1770 }
1771
1772 # Adjust sign of the formal charge for potential total common valence calculation
1773 # used during internal valence model to figure out number of implicit hydrogens.
1774 #
1775 sub _GetFormalChargeAdjustedForInternalValenceModel {
1776 my($This) = @_;
1777 my($FormalCharge, $GroupNumber, $SwitchSign);
1778
1779 $FormalCharge = $This->GetFormalCharge();
1780 if ($FormalCharge == 0) {
1781 return 0;
1782 }
1783
1784 $GroupNumber = $This->GetGroupNumber();
1785 if (!defined $GroupNumber) {
1786 return $FormalCharge;
1787 }
1788
1789 # Group numbers > 14 - Group numbers 15 (N), 16 (O), 17 (F), 18 (He)
1790 #
1791 # Formal charge sign is not adjusted. Positive and negative values result in the
1792 # increase and decrease of valence.
1793 #
1794 # Group 14 containing C, Si, Ge, Sn, Pb...
1795 #
1796 # Formal charge sign is reversed for positive values. Both positive and negative
1797 # values result in the decrease of valence.
1798 #
1799 # Group 13 containing B, Al, Ga, In, Tl...
1800 #
1801 # Formal charge sign is always reversed. Positive and negative values result in the
1802 # decrease and increase of valence.
1803 #
1804 # Groups 1 (H) through 12 (Zn)...
1805 #
1806 # Formal charge sign is reversed for positive values. Both positive and negative
1807 # values result in the decrease of valence.
1808 #
1809 # Lanthanides and actinides...
1810 #
1811 # Formal charge sign is reversed for positive values. Both positive and negative
1812 # values result in the decrease of valence.
1813 #
1814
1815 $SwitchSign = 0;
1816 if (length $GroupNumber) {
1817 GROUPNUMBER: {
1818 if ($GroupNumber > 14) {
1819 # Groups on the right side of C group in the periodic table...
1820 $SwitchSign = 0;
1821 last GROUPNUMBER;
1822 }
1823 if ($GroupNumber == 14) {
1824 # Group containing C, Si, Ge, Sn, Pb...
1825 $SwitchSign = ($FormalCharge > 0) ? 1 : 0;
1826 last GROUPNUMBER;
1827 }
1828 if ($GroupNumber == 13) {
1829 # Group containing B, Al, Ga, In, Tl...
1830 $SwitchSign = 1;
1831 last GROUPNUMBER;
1832 }
1833 # Groups 1 (H) through 12 (Zn)...
1834 if ($GroupNumber >=1 && $GroupNumber <= 12) {
1835 # Groups 1 (H) through 12 (Zn)...
1836 $SwitchSign = ($FormalCharge > 0) ? 1 : 0;
1837 last GROUPNUMBER;
1838 }
1839 }
1840 }
1841 else {
1842 # Lanthanides and actinides...
1843 $SwitchSign = ($FormalCharge > 0) ? 1 : 0;
1844 }
1845
1846 if ($SwitchSign) {
1847 $FormalCharge *= -1.0;
1848 }
1849
1850 return $FormalCharge;
1851 }
1852
1853 # Get lowest common valence...
1854 sub GetLowestCommonValence {
1855 my($This) = @_;
1856
1857 # Is LowestCommonValence property explicitly set?
1858 if ($This->HasProperty('LowestCommonValence')) {
1859 return $This->GetProperty('LowestCommonValence');
1860 }
1861 my($AtomicNumber, $LowestCommonValence);
1862
1863 $AtomicNumber = $This->{AtomicNumber};
1864 if (!$AtomicNumber) {
1865 return 0;
1866 }
1867 # Any need to differentiate between internal and other valence models...
1868
1869 # LowestCommonValence is not set for all elements...
1870 $LowestCommonValence = PeriodicTable::GetElementLowestCommonValence($AtomicNumber);
1871 if (!$LowestCommonValence) {
1872 $LowestCommonValence = undef;
1873 }
1874
1875 return $LowestCommonValence;
1876 }
1877
1878 # Get highest common valence...
1879 sub GetHighestCommonValence {
1880 my($This) = @_;
1881
1882 # Is HighestCommonValence property explicitly set?
1883 if ($This->HasProperty('HighestCommonValence')) {
1884 return $This->GetProperty('HighestCommonValence');
1885 }
1886 my($AtomicNumber, $HighestCommonValence);
1887
1888 $AtomicNumber = $This->{AtomicNumber};
1889 if (!$AtomicNumber) {
1890 return 0;
1891 }
1892
1893 # Any need to differentiate between internal and other valence models...
1894
1895 # HighestCommonValence is not set for all elements...
1896 $HighestCommonValence = PeriodicTable::GetElementHighestCommonValence($AtomicNumber);
1897 if (!$HighestCommonValence) {
1898 $HighestCommonValence = undef;
1899 }
1900
1901 return $HighestCommonValence;
1902 }
1903
1904 # Get valence electrons...
1905 sub GetValenceElectrons {
1906 my($This) = @_;
1907
1908 # Is ValenceElectrons property explicitly set?
1909 if ($This->HasProperty('ValenceElectrons')) {
1910 return $This->GetProperty('ValenceElectrons');
1911 }
1912 my($AtomicNumber, $ValenceElectrons);
1913
1914 $AtomicNumber = $This->{AtomicNumber};
1915 if (!$AtomicNumber) {
1916 return 0;
1917 }
1918
1919 $ValenceElectrons = PeriodicTable::GetElementValenceElectrons($AtomicNumber);
1920
1921 return $ValenceElectrons;
1922 }
1923
1924 # Add hydrogens to specified atom in molecule and return number of hydrogens added:
1925 #
1926 # o HydrogensToAdd = ImplicitHydrogenCount - ExplicitHydrogenCount
1927 #
1928 # o XYZ are set to ZeroVector
1929 #
1930 sub AddHydrogens {
1931 my($This, $HydrogenPositionsWarning) = @_;
1932
1933 # Is this atom in a molecule?
1934 if (!$This->HasProperty('Molecule')) {
1935 return undef;
1936 }
1937 if (!defined $HydrogenPositionsWarning) {
1938 $HydrogenPositionsWarning = 1;
1939 }
1940 if ($HydrogenPositionsWarning) {
1941 carp "Warning: ${ClassName}->AddHydrogens: The current release of MayaChemTools doesn't assign any hydrogen positions...";
1942 }
1943
1944 # Is it an element symbol?
1945 if (!$This->{AtomicNumber}) {
1946 return 0;
1947 }
1948
1949 my($Molecule, $HydrogensAdded, $HydrogensToAdd);
1950
1951 $Molecule = $This->GetProperty('Molecule');
1952 $HydrogensAdded = 0;
1953 $HydrogensToAdd = $This->GetNumOfMissingHydrogens();
1954 if ($HydrogensToAdd <= 0) {
1955 return $HydrogensAdded;
1956 }
1957
1958 my($Count, $Hydrogen);
1959
1960 for $Count (1 .. $HydrogensToAdd) {
1961 $HydrogensAdded++;
1962
1963 $Hydrogen = $Molecule->NewAtom('AtomSymbol' => 'H', 'XYZ' => [0, 0, 0]);
1964 $Molecule->NewBond('Atoms' => [$This, $Hydrogen], 'BondOrder' => 1);
1965 }
1966
1967 return $HydrogensAdded;
1968 }
1969
1970 # Delete hydrogens attached to atom in molecule and return total number of hydrogens deleted...
1971 sub DeleteHydrogens {
1972 my($This) = @_;
1973
1974 # Is this atom in a molecule?
1975 if (!$This->HasProperty('Molecule')) {
1976 return undef;
1977 }
1978
1979 # Is it an element symbol?
1980 if (!$This->{AtomicNumber}) {
1981 return 0;
1982 }
1983
1984 my($Molecule, $Neighbor, $HydrogensDeleted, @Neighbors);
1985
1986 $Molecule = $This->GetProperty('Molecule');
1987 $HydrogensDeleted = 0;
1988 @Neighbors = $This->GetNeighbors();
1989
1990 NEIGHBOR: for $Neighbor (@Neighbors) {
1991 if (!$Neighbor->IsHydrogen()) {
1992 next NEIGHBOR;
1993 }
1994 $Molecule->_DeleteAtom($Neighbor);
1995 $HydrogensDeleted++;
1996 }
1997
1998 return $HydrogensDeleted;
1999 }
2000
2001 # Copy atom and all its associated data...
2002 sub Copy {
2003 my($This) = @_;
2004 my($Atom);
2005
2006 $Atom = Storable::dclone($This);
2007
2008 return $Atom;
2009 }
2010
2011 # Get atomic invariant value...
2012 #
2013 sub GetAtomicInvariantValue {
2014 my($This, $AtomicInvariant) = @_;
2015 my($Value);
2016
2017 $Value = "";
2018
2019 ATOMICVARIANT: {
2020 if ($AtomicInvariant =~ /^(AS|AtomSymbol|ElementSymbol)$/i) {
2021 $Value = $This->GetAtomSymbol();
2022 last ATOMICVARIANT;
2023 }
2024 if ($AtomicInvariant =~ /^(X|NumOfNonHydrogenAtomNeighbors|NumOfHeavyAtomNeighbors)$/i) {
2025 $Value = $This->GetNumOfNonHydrogenAtomNeighbors();
2026 last ATOMICVARIANT;
2027 }
2028 if ($AtomicInvariant =~ /^(BO|SumOfBondOrdersToNonHydrogenAtoms|SumOfBondOrdersToHeavyAtoms)$/i) {
2029 $Value = $This->GetSumOfBondOrdersToNonHydrogenAtoms();
2030 last ATOMICVARIANT;
2031 }
2032 if ($AtomicInvariant =~ /^(LBO|LargestBondOrderToNonHydrogenAtoms|LargestBondOrderToHeavyAtoms)$/i) {
2033 $Value = $This->GetLargestBondOrderToNonHydrogenAtoms();
2034 last ATOMICVARIANT;
2035 }
2036 if ($AtomicInvariant =~ /^(H|NumOfImplicitAndExplicitHydrogens)$/i) {
2037 $Value = $This->GetNumOfHydrogens();
2038 last ATOMICVARIANT;
2039 }
2040 if ($AtomicInvariant =~ /^(SB|NumOfSingleBondsToNonHydrogenAtoms|NumOfSingleBondsToHeavyAtoms)$/i) {
2041 $Value = $This->GetNumOfSingleBondsToNonHydrogenAtoms();
2042 last ATOMICVARIANT;
2043 }
2044 if ($AtomicInvariant =~ /^(DB|NumOfDoubleBondsToNonHydrogenAtoms|NumOfDoubleBondsToHeavyAtoms)$/i) {
2045 $Value = $This->GetNumOfDoubleBondsToNonHydrogenAtoms();
2046 last ATOMICVARIANT;
2047 }
2048 if ($AtomicInvariant =~ /^(TB|NumOfTripleBondsToNonHydrogenAtoms|NumOfTripleBondsToHeavyAtoms)$/i) {
2049 $Value = $This->GetNumOfTripleBondsToNonHydrogenAtoms();
2050 last ATOMICVARIANT;
2051 }
2052 if ($AtomicInvariant =~ /^(AB|NumOfAromaticBondsToNonHydrogenAtoms|NumOfAromaticBondsToHeavyAtoms)$/i) {
2053 $Value = $This->GetNumOfAromaticBondsToNonHydrogenAtoms();
2054 last ATOMICVARIANT;
2055 }
2056 if ($AtomicInvariant =~ /^(FC|FormalCharge)$/i) {
2057 $Value = $This->GetFormalCharge();
2058 $Value = defined $Value ? $Value : 0;
2059 last ATOMICVARIANT;
2060 }
2061 if ($AtomicInvariant =~ /^(T|TotalNumOfAtomNeighbors)$/i) {
2062 $Value = $This->GetNumOfNonHydrogenAtomNeighbors() + $This->GetNumOfHydrogens();
2063 last ATOMICVARIANT;
2064 }
2065 if ($AtomicInvariant =~ /^(TSB|TotalNumOfSingleBonds)$/i) {
2066 $Value = $This->GetNumOfSingleBondsToNonHydrogenAtoms() + $This->GetNumOfHydrogens();
2067 last ATOMICVARIANT;
2068 }
2069 if ($AtomicInvariant =~ /^(Ar|Aromatic)$/i) {
2070 $Value = $This->IsAromatic() ? 1 : 0;
2071 last ATOMICVARIANT;
2072 }
2073 if ($AtomicInvariant =~ /^(RA|RingAtom)$/i) {
2074 $Value = $This->IsInRing() ? 1 : 0;
2075 last ATOMICVARIANT;
2076 }
2077 if ($AtomicInvariant =~ /^(Str|Stereochemistry)$/i) {
2078 $Value = $This->GetStereochemistry();
2079 $Value= (defined($Value) && ($Value =~ /^(R|S)$/i)) ? $Value : '';
2080 last ATOMICVARIANT;
2081 }
2082 if ($AtomicInvariant =~ /^(AN|AtomicNumber)$/i) {
2083 $Value = $This->GetAtomicNumber();
2084 last ATOMICVARIANT;
2085 }
2086 if ($AtomicInvariant =~ /^(AM|AtomicMass)$/i) {
2087 $Value = round($This->GetExactMass(), 4) + 0;
2088 last ATOMICVARIANT;
2089 }
2090 if ($AtomicInvariant =~ /^(MN|MassNumber)$/i) {
2091 $Value = $This->GetMassNumber();
2092 last ATOMICVARIANT;
2093 }
2094 if ($AtomicInvariant =~ /^(SM|SpinMultiplicity)$/i) {
2095 $Value = $This->GetSpinMultiplicity();
2096 $Value = defined $Value ? $Value : '';
2097 last ATOMICVARIANT;
2098 }
2099 $Value = "";
2100 carp "Warning: ${ClassName}->GetAtomicInvariantValue: Unknown atomic invariant $AtomicInvariant...";
2101 }
2102
2103 return $Value;
2104 }
2105
2106 # Get period number of the atom..
2107 #
2108 sub GetPeriodNumber {
2109 my($This) = @_;
2110
2111 # Is PeriodNumber property explicitly set?
2112 if ($This->HasProperty('PeriodNumber')) {
2113 return $This->GetProperty('PeriodNumber');
2114 }
2115 my($AtomicNumber, $PeriodNumber);
2116
2117 $AtomicNumber = $This->{AtomicNumber};
2118 if (!$AtomicNumber) {
2119 return 0;
2120 }
2121
2122 $PeriodNumber = PeriodicTable::GetElementPeriodNumber($AtomicNumber);
2123
2124 return $PeriodNumber;
2125 }
2126
2127 # Get group number of the atom..
2128 #
2129 sub GetGroupNumber {
2130 my($This) = @_;
2131
2132 # Is GroupNumber property explicitly set?
2133 if ($This->HasProperty('GroupNumber')) {
2134 return $This->GetProperty('GroupNumber');
2135 }
2136 my($AtomicNumber, $GroupNumber);
2137
2138 $AtomicNumber = $This->{AtomicNumber};
2139 if (!$AtomicNumber) {
2140 return 0;
2141 }
2142
2143 $GroupNumber = PeriodicTable::GetElementGroupNumber($AtomicNumber);
2144
2145 return $GroupNumber;
2146 }
2147
2148 # Is it a specified topological pharmacophore atom type?
2149 #
2150 sub IsTopologicalPharmacophoreType {
2151 my($This, $Type) = @_;
2152
2153 return $This->_IsFunctionalClassType($Type);
2154 }
2155
2156 # Is it a specified functional class atom type?
2157 #
2158 sub IsFunctionalClassType {
2159 my($This, $Type) = @_;
2160
2161 return $This->_IsFunctionalClassType($Type);
2162 }
2163
2164 # Is it a specified functional/topological pharmacophore atom type?
2165 #
2166 sub _IsFunctionalClassType {
2167 my($This, $Type) = @_;
2168 my($Value);
2169
2170 $Value = 0;
2171
2172 TYPE: {
2173 if ($Type =~ /^(HBD|HydrogenBondDonor)$/i) {
2174 $Value = $This->IsHydrogenBondDonor();
2175 last TYPE;
2176 }
2177 if ($Type =~ /^(HBA|HydrogenBondAcceptor)$/i) {
2178 $Value = $This->IsHydrogenBondAcceptor();
2179 last TYPE;
2180 }
2181 if ($Type =~ /^(PI|PositivelyIonizable)$/i) {
2182 $Value = $This->IsPositivelyIonizable();
2183 last TYPE;
2184 }
2185 if ($Type =~ /^(NI|NegativelyIonizable)$/i) {
2186 $Value = $This->IsNegativelyIonizable();
2187 last TYPE;
2188 }
2189 if ($Type =~ /^(H|Hydrophobic)$/i) {
2190 $Value = $This->IsHydrophobic();
2191 last TYPE;
2192 }
2193 if ($Type =~ /^(Ar|Aromatic)$/i) {
2194 $Value = $This->IsAromatic();
2195 last TYPE;
2196 }
2197 if ($Type =~ /^(Hal|Halogen)$/i) {
2198 $Value = $This->IsHalogen();
2199 last TYPE;
2200 }
2201 if ($Type =~ /^(RA|RingAtom)$/i) {
2202 $Value = $This->IsInRing();
2203 last TYPE;
2204 }
2205 if ($Type =~ /^(CA|ChainAtom)$/i) {
2206 $Value = $This->IsNotInRing();
2207 last TYPE;
2208 }
2209 $Value = 0;
2210 carp "Warning: ${ClassName}->_IsType: Unknown functional/pharmacohore type $Type...";
2211 }
2212 return $Value;
2213 }
2214
2215 # Is it a Hydrogen atom?
2216 sub IsHydrogen {
2217 my($This) = @_;
2218
2219 return ($This->{AtomicNumber} == 1) ? 1 : 0;
2220 }
2221
2222 # Is it a Carbon atom?
2223 sub IsCarbon {
2224 my($This) = @_;
2225
2226 return ($This->{AtomicNumber} == 6) ? 1 : 0;
2227 }
2228
2229 # Is it a Nitrogen atom?
2230 sub IsNitrogen {
2231 my($This) = @_;
2232
2233 return ($This->{AtomicNumber} == 7) ? 1 : 0;
2234 }
2235
2236 # Is it a Oxygen atom?
2237 sub IsOxygen {
2238 my($This) = @_;
2239
2240 return ($This->{AtomicNumber} == 8) ? 1 : 0;
2241 }
2242
2243 # Is it a Fluorine atom?
2244 sub IsFluorine {
2245 my($This) = @_;
2246
2247 return ($This->{AtomicNumber} == 9) ? 1 : 0;
2248 }
2249
2250 # Is it a Silicon atom?
2251 sub IsSilicon {
2252 my($This) = @_;
2253
2254 return ($This->{AtomicNumber} == 14) ? 1 : 0;
2255 }
2256
2257 # Is it a Phosphorus atom?
2258 sub IsPhosphorus {
2259 my($This) = @_;
2260
2261 return ($This->{AtomicNumber} == 15) ? 1 : 0;
2262 }
2263
2264 # Is it a Sulphur atom?
2265 sub IsSulphur {
2266 my($This) = @_;
2267
2268 return $This->IsSulfur();
2269 }
2270
2271 # Is it a Sulfur atom?
2272 sub IsSulfur {
2273 my($This) = @_;
2274
2275 return ($This->{AtomicNumber} == 16) ? 1 : 0;
2276 }
2277
2278 # Is it a Chlorine atom?
2279 sub IsChlorine {
2280 my($This) = @_;
2281
2282 return ($This->{AtomicNumber} == 17) ? 1 : 0;
2283 }
2284
2285 # Is it a Arsenic atom?
2286 sub IsArsenic {
2287 my($This) = @_;
2288
2289 return ($This->{AtomicNumber} == 33) ? 1 : 0;
2290 }
2291
2292 # Is it a Selenium atom?
2293 sub IsSelenium {
2294 my($This) = @_;
2295
2296 return ($This->{AtomicNumber} == 34) ? 1 : 0;
2297 }
2298
2299 # Is it a Bromine atom?
2300 sub IsBromine {
2301 my($This) = @_;
2302
2303 return ($This->{AtomicNumber} == 35) ? 1 : 0;
2304 }
2305
2306 # Is it a Tellurium atom?
2307 sub IsTellurium {
2308 my($This) = @_;
2309
2310 return ($This->{AtomicNumber} == 52) ? 1 : 0;
2311 }
2312
2313 # Is it a Iodine atom?
2314 sub IsIodine {
2315 my($This) = @_;
2316
2317 return ($This->{AtomicNumber} == 53) ? 1 : 0;
2318 }
2319
2320 # Is it a hetro atom? (N, O, F, P, S, Cl, Br, I)
2321 sub IsHeteroAtom {
2322 my($This) = @_;
2323
2324 return ($This->{AtomicNumber} =~ /^(7|8|9|15|16|17|35|53)$/) ? 1 : 0;
2325 }
2326
2327 # Is it a halogen atom? (F, Cl, Br, I)
2328 sub IsHalogen {
2329 my($This) = @_;
2330
2331 return ($This->{AtomicNumber} =~ /^(9|17|35|53)$/) ? 1 : 0;
2332 }
2333
2334 # Is it classified as metallic?
2335 sub IsMetallic {
2336 my($This) = @_;
2337 my($Classification);
2338
2339 $Classification = PeriodicTable::GetElementClassification($This->{AtomicNumber});
2340
2341 return ($Classification =~ /^Metallic$/i) ? 1 : 0;
2342 }
2343
2344 # Is it a non carbon or hydrogen atom? (C, H)
2345 sub IsNonCarbonOrHydrogen {
2346 my($This) = @_;
2347
2348 return ($This->{AtomicNumber} =~ /^(1|6)$/) ? 0 : 1;
2349 }
2350
2351 # Is it a polar atom? ( N, O, P, S)
2352 sub IsPolarAtom {
2353 my($This) = @_;
2354
2355 return ($This->{AtomicNumber} =~ /^(7|8|15|16)$/) ? 1 : 0;
2356 }
2357
2358 # Is it an isotope?
2359 sub IsIsotope {
2360 my($This) = @_;
2361
2362 my($AtomicNumber) = $This->{AtomicNumber};
2363 if (!$AtomicNumber) {
2364 return 0;
2365 }
2366
2367 if (!$This->HasProperty('MassNumber')) {
2368 return 0;
2369 }
2370 my($MassNumber, $MostAbundantMassNumber);
2371
2372 $MassNumber = $This->GetProperty('MassNumber');
2373 $MostAbundantMassNumber = PeriodicTable::GetElementMostAbundantNaturalIsotopeMassNumber($AtomicNumber);
2374
2375 return ($MassNumber == $MostAbundantMassNumber) ? 0 : 1;
2376 }
2377
2378 # Is it a terminal atom?
2379 sub IsTerminal {
2380 my($This) = @_;
2381
2382 # Is this atom in a molecule?
2383 if (!$This->HasProperty('Molecule')) {
2384 return undef;
2385 }
2386
2387 return ($This->GetNumOfNonHydrogenAtomNeighbors() <= 1) ? 1 : 0
2388
2389 }
2390
2391 # Is aromatic property set for the atom?
2392 sub IsAromatic {
2393 my($This) = @_;
2394 my($Aromatic);
2395
2396 $Aromatic = $This->GetAromatic();
2397
2398 return (defined($Aromatic) && $Aromatic) ? 1 : 0;
2399 }
2400
2401 # Is this a hydrogen atom and attached to one of these atoms: N, O, P, S
2402 sub IsPolarHydrogen {
2403 my($This) = @_;
2404
2405 if (!$This->IsHydrogen()) {
2406 return 0;
2407 }
2408
2409 my(@Bonds);
2410 @Bonds = $This->GetBonds();
2411 if (@Bonds > 1) {
2412 return 0;
2413 }
2414
2415 my($Bond, $BondedAtom);
2416 ($Bond) = @Bonds;
2417 $BondedAtom = $Bond->GetBondedAtom($This);
2418
2419 return $BondedAtom->IsPolarAtom() ? 1 : 0;
2420 }
2421
2422 # Is it a hydrogen bond donor atom?
2423 #
2424 sub IsHBondDonor {
2425 my($This, $HydrogenBondsType) = @_;
2426
2427 return $This->IsHydrogenBondDonor($HydrogenBondsType);
2428 }
2429
2430 # The currrent release of MayaChemTools supports identification of two types of
2431 # hydrogen bond donor and acceptor atoms with these names:
2432 #
2433 # HBondsType1 or HydrogenBondsType1
2434 # HBondsType2 or HydrogenBondsType2
2435 #
2436 # The names of these hydrogen bond types are rather arbitrary. However, their
2437 # definitions have specific meaning and are as follows:
2438 #
2439 # HydrogenBondsType1 [ Ref 60-61, Ref 65-66 ]:
2440 # . Donor: NH, NH2, NH3, OH - Any N and O with available H
2441 # . Acceptor: N[!H], O - Any N without available H and any O
2442 #
2443 # HydrogenBondsType2 [ Ref 91 ]:
2444 # . Donor: NH, NH2, NH3, OH - Any N and O with availabe H
2445 # . Acceptor: N, O - Any N and O
2446 #
2447 # Note:
2448 # . HydrogenBondsType2 definition corresponds to Rule of 5.
2449 #
2450
2451 # Is it a hydrogen bond donor atom?
2452 #
2453 # The currrent release of MayaChemTools supports identification of two types of
2454 sub IsHydrogenBondDonor {
2455 my($This, $HydrogenBondsType) = @_;
2456 my($Status);
2457
2458 $HydrogenBondsType = defined $HydrogenBondsType ? $HydrogenBondsType : 'HBondsType1';
2459 $Status = 0;
2460
2461 HYDROGENBONDSTYPE: {
2462
2463 if ($HydrogenBondsType =~ /^(HBondsType1|HydrogenBondsType1)$/i) {
2464 $Status = $This->_IsHydrogenBondDonorOfType1();
2465 last HYDROGENBONDSTYPE;
2466 }
2467
2468 if ($HydrogenBondsType =~ /^(HBondsType2|HydrogenBondsType2)$/i) {
2469 $Status = $This->_IsHydrogenBondDonorOfType2();
2470 last HYDROGENBONDSTYPE;
2471 }
2472
2473 $Status = 0;
2474 carp "Warning: ${ClassName}->IsHydrogenBondDonor: The current release of MayaChemTools doesn't support specified value, $HydrogenBondsType, for HydrogenBondsType. Valid values: HBondsType1, HydrogenBondsType1, HBondsType2 HydrogenBondsType2 ...";
2475 }
2476
2477 return $Status;
2478 }
2479
2480 # Is it a MayaChemTools HBondType1 hydrogen bond donor atom?
2481 #
2482 sub _IsHydrogenBondDonorOfType1 {
2483 my($This) = @_;
2484
2485 return $This->_IsHydrogenBondDonorOfType1OrType2();
2486 }
2487
2488 # Is it a MayaChemTools HBondType2 hydrogen bond donor atom?
2489 #
2490 sub _IsHydrogenBondDonorOfType2 {
2491 my($This) = @_;
2492
2493 return $This->_IsHydrogenBondDonorOfType1OrType2();
2494 }
2495
2496 # Is it a hydrogen bond donor atom of MayaChemTools Type1 or Type2?
2497 #
2498 # HydrogenBondDonor definition [ Ref 60-61, Ref 65-66, Ref 91 ]: NH, NH2, OH
2499 #
2500 # In other words:
2501 # . NH, NH2 - Nitrogen atom with available hydrogen
2502 # . OH - Oxygen atom with avilable hydrogen
2503 #
2504 sub _IsHydrogenBondDonorOfType1OrType2 {
2505 my($This) = @_;
2506
2507 # Is this atom in a molecule?
2508 if (!$This->HasProperty('Molecule')) {
2509 return 0;
2510 }
2511
2512 # Is it N or O?
2513 if ($This->{AtomicNumber} !~ /^(7|8)$/) {
2514 return 0;
2515 }
2516
2517 # Any explicitly attached hydrogens?
2518 if ($This->GetExplicitHydrogens()) {
2519 return 1;
2520 }
2521
2522 # Any missing hydrogens?
2523 return $This->GetNumOfMissingHydrogens() ? 1 : 0;
2524 }
2525
2526 # Is it a hydrogen bond acceptor atom?
2527 #
2528 sub IsHBondAcceptor {
2529 my($This, $HydrogenBondsType) = @_;
2530
2531 return $This->IsHydrogenBondAcceptor($HydrogenBondsType);
2532 }
2533
2534 # Is it a hydrogen bond acceptor atom?
2535 #
2536 sub IsHydrogenBondAcceptor {
2537 my($This, $HydrogenBondsType) = @_;
2538 my($Status);
2539
2540 $HydrogenBondsType = defined $HydrogenBondsType ? $HydrogenBondsType : 'HBondsType1';
2541 $Status = 0;
2542
2543 HYDROGENBONDSTYPE: {
2544
2545 if ($HydrogenBondsType =~ /^(HBondsType1|HydrogenBondsType1)$/i) {
2546 $Status = $This->_IsHydrogenBondAcceptorOfType1();
2547 last HYDROGENBONDSTYPE;
2548 }
2549
2550 if ($HydrogenBondsType =~ /^(HBondsType2|HydrogenBondsType2)$/i) {
2551 $Status = $This->_IsHydrogenBondAcceptorOfType2();
2552 last HYDROGENBONDSTYPE;
2553 }
2554
2555 $Status = 0;
2556 carp "Warning: ${ClassName}->IsHydrogenBondAcceptor: The current release of MayaChemTools doesn't support specified value, $HydrogenBondsType, for HydrogenBondsType. Valid values: HBondsType1, HydrogenBondsType1, HBondsType2 HydrogenBondsType2 ...";
2557 }
2558
2559 return $Status;
2560 }
2561
2562 # Is it a MayaChemTools HBondType1 hydrogen bond acceptor atom?
2563 #
2564 # HydrogenBondAcceptor definition [ Ref 60-61, Ref 65-66 ]: N[!H], O
2565 #
2566 # In other words:
2567 # . N[!H] - Nitrogen atom with no hydrogen
2568 # . O - Oxygen atom
2569 #
2570 sub _IsHydrogenBondAcceptorOfType1 {
2571 my($This) = @_;
2572
2573 # Is this atom in a molecule?
2574 if (!$This->HasProperty('Molecule')) {
2575 return 0;
2576 }
2577
2578 # Is it N or O?
2579 if ($This->{AtomicNumber} !~ /^(7|8)$/) {
2580 return 0;
2581 }
2582
2583 # Is it O?
2584 if ($This->{AtomicNumber} == 8 ) {
2585 return 1;
2586 }
2587
2588 # Any explicitly attached hydrogens?
2589 if ($This->GetExplicitHydrogens()) {
2590 return 0;
2591 }
2592
2593 # Any missing hydrogens?
2594 return $This->GetNumOfMissingHydrogens() ? 0 : 1;
2595 }
2596
2597 # Is it a MayaChemTools HBondType2 hydrogen bond acceptor atom?
2598 #
2599 # HydrogenBondAcceptor definition [ Ref 91 ]: N, O
2600 #
2601 # In other words:
2602 # . Any Nitrogen or Oxygen atom
2603 #
2604 # Note:
2605 # . HydrogenBondsType2 definition corresponds to Rule of 5.
2606 #
2607 sub _IsHydrogenBondAcceptorOfType2 {
2608 my($This) = @_;
2609
2610 # Is this atom in a molecule?
2611 if (!$This->HasProperty('Molecule')) {
2612 return 0;
2613 }
2614
2615 return ($This->{AtomicNumber} =~ /^(7|8)$/) ? 1 : 0;
2616 }
2617
2618 # Is it a positively ionizable atom?
2619 #
2620 # PositivelyIonizable defintion [ Ref 60-61, Ref 65-66 ]: +, NH2
2621 #
2622 # In other words:
2623 # . Any atom with positve formal charge
2624 # . NH2 - Nitogen atom in amino group
2625 #
2626 sub IsPositivelyIonizable {
2627 my($This) = @_;
2628 my($FormalCharge);
2629
2630 # Is this atom in a molecule?
2631 if (!$This->HasProperty('Molecule')) {
2632 return 0;
2633 }
2634
2635 # Any explicit positive formal charge?
2636 $FormalCharge = $This->GetFormalCharge();
2637 if (defined($FormalCharge) && $FormalCharge > 0) {
2638 return 1;
2639 }
2640
2641 # Is it N?
2642 if ($This->{AtomicNumber} != 7 ) {
2643 return 0;
2644 }
2645
2646 return ($This->GetNumOfHydrogens() == 2) ? 1 : 0;
2647 }
2648
2649 # Is it a negatively ionizable atom?
2650 #
2651 # NegativelyIonizable definition [ Ref 60-61, Ref 65-66 ]: -, C(=O)OH, S(=O)OH, P(=O)OH
2652 #
2653 # In other words:
2654 # . Any atom with negative formal charge
2655 # . Carbon atom in C(=O)OH group
2656 # . Phosphorous in P(=O)OH group
2657 # . Sulfur atom in S(=O)OH group
2658 #
2659 sub IsNegativelyIonizable {
2660 my($This) = @_;
2661 my($FormalCharge);
2662
2663 # Is this atom in a molecule?
2664 if (!$This->HasProperty('Molecule')) {
2665 return 0;
2666 }
2667
2668 # Any explicit negative formal charge?
2669 $FormalCharge = $This->GetFormalCharge();
2670 if (defined($FormalCharge) && $FormalCharge < 0) {
2671 return 1;
2672 }
2673
2674 # Is it C, P or S?
2675 if ($This->{AtomicNumber} !~ /^(6|15|16)$/ ) {
2676 return 0;
2677 }
2678
2679 # Collect oxygens connected to C, P or S with single or double bonds and not connected to
2680 # any other heavy atom...
2681 my($Neighbor, $NeighborOxygenBondOrder, $NumOfNeighborOxygensWithSingleBonds, $NumOfNeighborOxygensWithDoubleBonds);
2682
2683 $NumOfNeighborOxygensWithSingleBonds = 0; $NumOfNeighborOxygensWithDoubleBonds = 0;
2684
2685 NEIGHBOR: for $Neighbor ($This->GetNeighbors()) {
2686 # Is it an oxygen?
2687 if ($Neighbor->{AtomicNumber} != 8) {
2688 next NEIGHBOR;
2689 }
2690 # Is oxygent connected to only heavy atom?
2691 if ($Neighbor->GetNumOfHeavyAtomNeighbors() != 1) {
2692 next NEIGHBOR;
2693 }
2694 $NeighborOxygenBondOrder = $This->GetBondToAtom($Neighbor)->GetBondOrder();
2695
2696 if ($NeighborOxygenBondOrder == 2) {
2697 $NumOfNeighborOxygensWithDoubleBonds++;
2698 }
2699 elsif ($NeighborOxygenBondOrder == 1) {
2700 $NumOfNeighborOxygensWithSingleBonds++;
2701 }
2702 }
2703 return ($NumOfNeighborOxygensWithDoubleBonds >= 1 && $NumOfNeighborOxygensWithSingleBonds >= 1) ? 1 : 0;
2704 }
2705
2706 # Is it a liphophilic atom?
2707 #
2708 # Lipophilic definition [ Ref 60-61, Ref 65-66 ]: C(C)(C)(C)(C), Cl, Br, I, S(C)(C)
2709 #
2710 # In other words:
2711 # . C(C)(C)(C)(C) - Carbon atom connected to only other carbons
2712 # . Chlorine, Bromine or Iodine atom
2713 # . S(C)(C) - Sulfur connected to two carbons
2714 #
2715 sub IsLipophilic {
2716 my($This) = @_;
2717
2718 # Is this atom in a molecule?
2719 if (!$This->HasProperty('Molecule')) {
2720 return 0;
2721 }
2722
2723 # Is it Cl, Br, I?
2724 if ($This->{AtomicNumber} =~ /^(17|35|53)$/) {
2725 return 1;
2726 }
2727
2728 # Is it C, S?
2729 if ($This->{AtomicNumber} !~ /^(6|16)$/) {
2730 return 0;
2731 }
2732
2733 # Are all heavy atom neighbors Carbons?
2734 my($HeavyAtomNeighbor, @HeavyAtomNeighbors);
2735 @HeavyAtomNeighbors = ();
2736 @HeavyAtomNeighbors = $This->GetHeavyAtomNeighbors();
2737
2738 for $HeavyAtomNeighbor (@HeavyAtomNeighbors) {
2739 if ($HeavyAtomNeighbor->{AtomicNumber} != 6) {
2740 return 0;
2741 }
2742 }
2743
2744 # Does sulfur has two carbon neighbors?
2745 if ($This->{AtomicNumber} == 16) {
2746 if (@HeavyAtomNeighbors != 2) {
2747 return 0;
2748 }
2749 }
2750 return 1;
2751 }
2752
2753 # Is it hydrophobic?
2754 #
2755 sub IsHydrophobic {
2756 my($This) = @_;
2757
2758 return $This->IsLipophilic();
2759 }
2760
2761 # Is it a Nitrogen atom in Guadinium group?
2762 #
2763 sub IsGuadiniumNitrogen {
2764 my($This) = @_;
2765
2766 # Is it Nitrogen?
2767 if (!$This->IsNitrogen()) {
2768 return 0;
2769 }
2770
2771 # Is it connected to a Guadinium Carbon?
2772 my($AtomNeighbor);
2773
2774 for $AtomNeighbor ($This->GetNonHydrogenAtomNeighbors()) {
2775 if ($AtomNeighbor->IsGuadiniumCarbon()) {
2776 return 1;
2777 }
2778 }
2779
2780 return 0;
2781 }
2782
2783 # Is it a Carbon atom in Guadinium group?
2784 #
2785 # Guadinium group definition:
2786 #
2787 # R2N-C(=NR)-(NR2) or R2N-C(=NR2+)-(NR2)
2788 #
2789 # where:
2790 # . R = Hydrogens or group of atoms attached through Carbon
2791 # . Only one of the three Nitrogens has a double bond to Carbon and has optional
2792 # formal charge allowing it to be neutral or charged state
2793 #
2794 sub IsGuadiniumCarbon {
2795 my($This) = @_;
2796
2797 # Is it Carbon?
2798 if (!$This->IsCarbon()) {
2799 return 0;
2800 }
2801
2802 # Match atom neighborhood...
2803 my($CentralAtomSpec, @NbrAtomSpecsRef, @NbrBondSpecsRef, @NbrOfNbrAtomSpecsRef);
2804
2805 $CentralAtomSpec = 'C.X3.BO4';
2806 @NbrAtomSpecsRef = ('N.FC0', 'N.FC0', 'N.FC0,N.FC+1');
2807 @NbrBondSpecsRef = ('-', '-', '=');
2808 @NbrOfNbrAtomSpecsRef = ('C,H', 'C,H', 'C,H');
2809
2810 if ($This->DoesAtomNeighborhoodMatch($CentralAtomSpec, \@NbrAtomSpecsRef, \@NbrBondSpecsRef, \@NbrOfNbrAtomSpecsRef)) {
2811 return 1;
2812 }
2813
2814 return 0;
2815 }
2816
2817 # Is it a Nitrogen atom in Amide group?
2818 #
2819 sub IsAmideNitrogen {
2820 my($This) = @_;
2821
2822 # Is it Nitrogen?
2823 if (!$This->IsNitrogen()) {
2824 return 0;
2825 }
2826
2827 # Is it connected to a Amide Carbon?
2828 my($AtomNeighbor);
2829
2830 for $AtomNeighbor ($This->GetNonHydrogenAtomNeighbors()) {
2831 if ($AtomNeighbor->IsAmideCarbon()) {
2832 return 1;
2833 }
2834 }
2835
2836 return 0;
2837 }
2838
2839 # Is it a Carbon atom in Amide group?
2840 #
2841 # Amide group definition: R-C(=O)-N(-R')-R''
2842 #
2843 # where:
2844 # . R = Hydrogen or groups of atoms attached through Carbon
2845 # . R' = Hydrogens or groups of atoms attached through Carbon or hetro atoms
2846 # . R'' = Hydrogens or groups of atoms attached through Carbon or hetro atoms
2847 #
2848 sub IsAmideCarbon {
2849 my($This) = @_;
2850
2851 # Is this atom in a molecule?
2852 if (!$This->HasProperty('Molecule')) {
2853 return 0;
2854 }
2855
2856 # Is it Carbon?
2857 if (!$This->IsCarbon()) {
2858 return 0;
2859 }
2860
2861 # Match atom neighborhood...
2862 my($CentralAtomSpec, @NbrAtomSpecsRef, @NbrBondSpecsRef, @NbrOfNbrAtomSpecsRef);
2863
2864 $CentralAtomSpec = 'C.X3.BO4,C.X2.BO3';
2865 @NbrAtomSpecsRef = ('C,H', 'O', 'N');
2866 @NbrBondSpecsRef = ('-', '=', '-');
2867 @NbrOfNbrAtomSpecsRef = ('C,H', 'C', 'C,H,N,O,S,P,F,Cl,Br,I');
2868
2869 if ($This->DoesAtomNeighborhoodMatch($CentralAtomSpec, \@NbrAtomSpecsRef, \@NbrBondSpecsRef, \@NbrOfNbrAtomSpecsRef)) {
2870 return 1;
2871 }
2872
2873 return 0;
2874 }
2875
2876 # Is it a Oxygen atom in Carboxylate group?
2877 #
2878 sub IsCarboxylateOxygen {
2879 my($This) = @_;
2880
2881 return $This->_MatchCarboxylateAndOrCarboxylOxygen('Carboxylate');
2882 }
2883
2884 # Is it a Carbon atom in Carboxylate group?
2885 #
2886 # Carboxyl group definition: R-C(=O)-O-
2887 #
2888 sub IsCarboxylateCarbon {
2889 my($This) = @_;
2890
2891 return $This->_MatchCarboxylateAndOrCarboxylCarbon('Carboxylate');
2892 }
2893
2894 # Is it a Oxygen atom in Carboxyl group?
2895 #
2896 sub IsCarboxylOxygen {
2897 my($This) = @_;
2898
2899 return $This->_MatchCarboxylateAndOrCarboxylOxygen('Carboxyl');
2900 }
2901
2902 # Is it a Carbon atom in Carboxyl group?
2903 #
2904 # Carboxyl group definition: R-C(=O)-OH
2905 #
2906 sub IsCarboxylCarbon {
2907 my($This) = @_;
2908
2909 return $This->_MatchCarboxylateAndOrCarboxylCarbon('Carboxyl');
2910 }
2911
2912 # Match Carboxylate and/or Carboxyl oxygen...
2913 #
2914 sub _MatchCarboxylateAndOrCarboxylOxygen {
2915 my($This, $Mode) = @_;
2916
2917 # Is it Oxygen?
2918 if (!$This->IsOxygen()) {
2919 return 0;
2920 }
2921
2922 # Is it connected to a Carboxylate Carbon?
2923 my($AtomNeighbor);
2924
2925 for $AtomNeighbor ($This->GetNonHydrogenAtomNeighbors()) {
2926 if ($AtomNeighbor->_MatchCarboxylateAndOrCarboxylCarbon($Mode)) {
2927 return 1;
2928 }
2929 }
2930
2931 return 0;
2932 }
2933
2934 # Match Carboxylate and Carboxyl Carbon
2935 #
2936 # Carboxylate group definition: R-C(=O)-O-
2937 # Carboxyl group definition: R-C(=O)-OH
2938 #
2939 # where:
2940 # . R = Hydrogens or groups of atoms attached through Carbon
2941 #
2942 sub _MatchCarboxylateAndOrCarboxylCarbon {
2943 my($This, $Mode) = @_;
2944
2945 # Is this atom in a molecule?
2946 if (!$This->HasProperty('Molecule')) {
2947 return 0;
2948 }
2949
2950 # Is it Carbon?
2951 if (!$This->IsCarbon()) {
2952 return 0;
2953 }
2954
2955 # Match atom neighborhood...
2956 my($CentralAtomSpec, @NbrAtomSpecsRef, @NbrBondSpecsRef, @NbrOfNbrAtomSpecsRef);
2957
2958 $CentralAtomSpec = 'C.X3.BO4,C.X2.BO3';
2959 MODE: {
2960 if ($Mode =~ /^Carboxylate$/i) {
2961 @NbrAtomSpecsRef = ('C,H', 'O', 'O.X1.FC-1');
2962 last MODE;
2963 }
2964 if ($Mode =~ /^Carboxyl$/i) {
2965 @NbrAtomSpecsRef = ('C,H', 'O', 'O.X1.FC0');
2966 last MODE;
2967 }
2968 if ($Mode =~ /^CarboxylateOrCarboxyl$/i) {
2969 @NbrAtomSpecsRef = ('C,H', 'O', 'O.X1.FC-1,O.X1.FC0');
2970 last MODE;
2971 }
2972 carp "Warning: ${ClassName}->_MatchCarboxylateAndCarboxylCarbon.: Unknown mode $Mode...";
2973 return 0;
2974 }
2975 @NbrBondSpecsRef = ('-', '=', '-');
2976 @NbrOfNbrAtomSpecsRef = ('C,H', 'C', 'C');
2977
2978 if ($This->DoesAtomNeighborhoodMatch($CentralAtomSpec, \@NbrAtomSpecsRef, \@NbrBondSpecsRef, \@NbrOfNbrAtomSpecsRef)) {
2979 return 1;
2980 }
2981
2982 return 0;
2983 }
2984
2985 # Is it a Oxygen atom in Phosphate group?
2986 #
2987 sub IsPhosphateOxygen {
2988 my($This) = @_;
2989
2990 # Is it Oxygen?
2991 if (!$This->IsOxygen()) {
2992 return 0;
2993 }
2994
2995 # Is it connected to a Phosphate Phosphorus?
2996 my($AtomNeighbor);
2997
2998 for $AtomNeighbor ($This->GetNonHydrogenAtomNeighbors()) {
2999 if ($AtomNeighbor->IsPhosphatePhosphorus()) {
3000 return 1;
3001 }
3002 }
3003
3004 return 0;
3005 }
3006
3007 # Is it a Phosphorus atom in Phosphate group?
3008 #
3009 # Phosphate group definition: AO-(O=)P(-OA)-OA
3010 #
3011 # where:
3012 # . A = Any Groups of atoms including hydrogens
3013 #
3014 sub IsPhosphatePhosphorus {
3015 my($This) = @_;
3016
3017 # Is this atom in a molecule?
3018 if (!$This->HasProperty('Molecule')) {
3019 return 0;
3020 }
3021
3022 # Is it Phosphorus?
3023 if (!$This->IsPhosphorus()) {
3024 return 0;
3025 }
3026
3027 # Match atom neighborhood...
3028 my($CentralAtomSpec, @NbrAtomSpecsRef, @NbrBondSpecsRef, @NbrOfNbrAtomSpecsRef);
3029
3030 $CentralAtomSpec = 'P.X4.BO5';
3031 @NbrAtomSpecsRef = ('O', 'O', 'O', 'O');
3032 @NbrBondSpecsRef = ('-', '=', '-', '-');
3033 @NbrOfNbrAtomSpecsRef = (undef, undef, undef, undef);
3034
3035 if ($This->DoesAtomNeighborhoodMatch($CentralAtomSpec, \@NbrAtomSpecsRef, \@NbrBondSpecsRef, \@NbrOfNbrAtomSpecsRef)) {
3036 return 1;
3037 }
3038
3039 return 0;
3040 }
3041
3042
3043 # Match central atom and its neighborhood using specified atom and bonds specifications...
3044 #
3045 # Let:
3046 # AS = Atom symbol corresponding to element symbol, atomic number (#n) or any
3047 # atom (A)
3048 #
3049 # X<n> = Number of non-hydrogen atom neighbors or heavy atoms attached to atom
3050 # T<n> = Total number of atom neighbors including implcit and explicit hydrogens
3051 # BO<n> = Sum of bond orders to non-hydrogen atom neighbors or heavy atoms attached to atom
3052 # LBO<n> = Largest bond order of non-hydrogen atom neighbors or heavy atoms attached to atom
3053 # SB<n> = Number of single bonds to non-hydrogen atom neighbors or heavy atoms attached to atom
3054 # TSB<n> = Total number of single bonds to atom neighbors including implcit and explicit hydrogens
3055 # DB<n> = Number of double bonds to non-hydrogen atom neighbors or heavy atoms attached to atom
3056 # TB<n> = Number of triple bonds to non-hydrogen atom neighbors or heavy atoms attached to atom
3057 # H<n> = Number of implicit and explicit hydrogens for atom
3058 # Ar = Aromatic annotation indicating whether atom is aromatic
3059 # RA or RA<n> = Ring atom annotation indicating whether atom is a ring
3060 # TR<n> = Total number of rings containing atom
3061 # FC<+n/-n> = Formal charge assigned to atom
3062 # MN<n> = Mass number indicating isotope other than most abundant isotope
3063 # SM<n> = Spin multiplicity of atom. Possible values: 1 (singlet), 2 (doublet) or 3 (triplet)
3064 #
3065 # Then:
3066 #
3067 # Atom specification corresponds to:
3068 #
3069 # 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>
3070 #
3071 # Except for AS which is a required atomic invariant in atom specification, all other atomic invariants are
3072 # optional. For an atom specification to match an atom, the values of all specified atomic invariants must
3073 # match. Exclamation in from of atomic invariant can be used to negate its effect during the match.
3074 #
3075 # A comma delimited atom specification string is used to match any one of the specifed atom specification.
3076 #
3077 # Notes:
3078 # . During atom specification match to an atom, the first atomic invariant is always assumed to
3079 # atom symbol.
3080 # . Atom match specfication is based on AtomicInvariantAtomTypes implemented in
3081 # AotmTypes::AtomicInvariantAtomType.pm module
3082 #
3083 # Examples:
3084 # . ('N', 'N', 'N')
3085 # . ('N.FC0', 'N.FC0', 'N,N.FC+1.H1')
3086 # . ('N.H2', 'N.H2', 'N.H1')
3087 # . ('C,N', '!N', '!H')
3088 # . ('C,N', 'N.Ar', 'N.R5')
3089 #
3090 # Let:
3091 # -|1|s|Single = Single bond
3092 # =|2|d|Double = Double bond
3093 # #|3|t|Triple = Triple bond
3094 # :|1.5|a|Ar|Aromatic = Aromatic bond
3095 #
3096 # @|RB|Ring = Ring bond
3097 # ~|*|Any = Any bond
3098 #
3099 # Then:
3100 #
3101 # Bond specification corresponds to:
3102 #
3103 # -.:
3104 # =.@
3105 # Double.Aromatic
3106 #
3107 # For a bond specification to match bond between two atoms, the values of all specified bond symbols must
3108 # match. Exclamation in from of bond symbol can be used to negate its effect during the match.
3109 #
3110 # A comma delimited bond specification string is used to match any one of the specifed atom specification.
3111 #
3112 sub DoesAtomNeighborhoodMatch {
3113 my($CentralAtom, $CentralAtomSpec, $NbrAtomSpecsRef, $NbrBondSpecsRef, $NbrOfNbrAtomSpecsRef) = @_;
3114 my($NumOfNbrAtomSpecs, $NumOfNbrBondSpecs, $NumOfNbrOfNbrAtomSpecs);
3115
3116 # Is this atom in a molecule?
3117 if (!$CentralAtom->HasProperty('Molecule')) {
3118 return 0;
3119 }
3120
3121 $NumOfNbrAtomSpecs = defined $NbrAtomSpecsRef ? scalar @{$NbrAtomSpecsRef} : 0;
3122 $NumOfNbrBondSpecs = defined $NbrBondSpecsRef ? scalar @{$NbrBondSpecsRef} : 0;
3123 $NumOfNbrOfNbrAtomSpecs = defined $NbrOfNbrAtomSpecsRef ? scalar @{$NbrOfNbrAtomSpecsRef} : 0;
3124
3125 # Validate number of specifications...
3126 if ($NumOfNbrBondSpecs && ($NumOfNbrAtomSpecs != $NumOfNbrBondSpecs)) {
3127 carp "Warning: ${ClassName}->DoesAtomNeighborhoodMatch: Number of specified central atom, $NumOfNbrAtomSpecs, and bond, $NumOfNbrBondSpecs, specifications must be same; No neighborhood match performed ...";
3128 return 0;
3129 }
3130
3131 if ($NumOfNbrOfNbrAtomSpecs && ($NumOfNbrOfNbrAtomSpecs != $NumOfNbrAtomSpecs)) {
3132 carp "Warning: ${ClassName}->DoesAtomNeighborhoodMatch: Number of specified central atom, $NumOfNbrAtomSpecs, and neighbor of neighbor atoms specifications, $NumOfNbrOfNbrAtomSpecs, must be same; No neighborhood match performed ...";
3133 return 0;
3134 }
3135
3136 # Sort atom and bond specifications in terms of being most specific to least specific..
3137 ($NbrAtomSpecsRef, $NbrBondSpecsRef, $NbrOfNbrAtomSpecsRef) = $CentralAtom->_SortSpecificationsForAtomNeighborhoodMatch($NbrAtomSpecsRef, $NbrBondSpecsRef, $NbrOfNbrAtomSpecsRef);
3138
3139 # Does central atom specification match?
3140 if (!$CentralAtom->_DoesAtomSpecificationMatch($CentralAtomSpec)) {
3141 return 0;
3142 }
3143
3144 # No neighbors to match...
3145 if (!$NumOfNbrAtomSpecs) {
3146 return 1;
3147 }
3148
3149 # Match neighbors...
3150 my($NbrSpecsMatched, $NbrSpecCount, $NbrSpecMatchCount, %NbrSpecAlreadyMatchedMap);
3151
3152 $NbrSpecCount = $NumOfNbrAtomSpecs;
3153 $NbrSpecMatchCount = 0;
3154
3155 %NbrSpecAlreadyMatchedMap = ();
3156 ($NbrSpecsMatched, $NbrSpecMatchCount) = $CentralAtom->_MatchAtomNeighborhoodUsingAtomBondSpecs($NbrSpecCount, $NbrSpecMatchCount, \%NbrSpecAlreadyMatchedMap, $NbrAtomSpecsRef, $NbrBondSpecsRef, $NbrOfNbrAtomSpecsRef);
3157
3158 if ($NbrSpecsMatched) {
3159 # It's match...
3160 return 1;
3161 }
3162
3163 # Match central atom's missing hydrogens with any unmatched atom
3164 # and bond specifications...
3165 #
3166 ($NbrSpecsMatched, $NbrSpecMatchCount) = $CentralAtom->_MatchAtomNeighborhoodUsingMissingHydrogens($NbrSpecCount, $NbrSpecMatchCount, \%NbrSpecAlreadyMatchedMap, $NbrAtomSpecsRef, $NbrBondSpecsRef, $NbrOfNbrAtomSpecsRef);
3167
3168 if ($NbrSpecsMatched) {
3169 # It's match...
3170 return 1;
3171 }
3172
3173 # No match...
3174 return 0;
3175 }
3176
3177 # Match central atom neighborhood atom and bond specifications...
3178 #
3179 sub _MatchAtomNeighborhoodUsingAtomBondSpecs {
3180 my($CentralAtom, $NbrSpecCount, $NbrSpecMatchCount, $NbrSpecAlreadyMatchedRef, $NbrAtomSpecsRef, $NbrBondSpecsRef, $NbrOfNbrAtomSpecsRef) = @_;
3181 my($Index, $NbrAtom, $NbrAtomSpec, $NbrBondSpec, $NbrOfNbrAtom, $NbrOfNbrAtomSpec, $MatchNbrOfNbrAtomSpecs, $NbrSpecsMatched);
3182
3183 $MatchNbrOfNbrAtomSpecs = (defined $NbrOfNbrAtomSpecsRef && scalar @{$NbrOfNbrAtomSpecsRef}) ? 1 : 0;
3184
3185 $NbrSpecsMatched = 0;
3186
3187 # Match central atom's immediate neighbors atom and bond specifications...
3188 NBRATOM: for $NbrAtom ($CentralAtom->GetNeighbors()) {
3189 NBRATOMSPEC: for $Index (0 .. ($NbrSpecCount - 1)) {
3190 if (exists $NbrSpecAlreadyMatchedRef->{$Index}) {
3191 next NBRATOMSPEC;
3192 }
3193 $NbrAtomSpec = $NbrAtomSpecsRef->[$Index];
3194 $NbrBondSpec = $NbrBondSpecsRef->[$Index];
3195
3196 $NbrOfNbrAtomSpec = $MatchNbrOfNbrAtomSpecs ? $NbrOfNbrAtomSpecsRef->[$Index] : undef;
3197
3198 # Match neighbor atom specification...
3199 if (!$NbrAtom->_DoesAtomSpecificationMatch($NbrAtomSpec)) {
3200 next NBRATOMSPEC;
3201 }
3202
3203 # Match central atom to neighbor atom bond specification...
3204 if (!$CentralAtom->_DoesBondSpecificationMatch($NbrAtom, $NbrBondSpec)) {
3205 next NBRATOMSPEC;
3206 }
3207
3208 # Match any neighbor of neighbor atom specifications...
3209 if (defined $NbrOfNbrAtomSpec) {
3210 # Go over the neighbors of central atom skipping the central atom...
3211 for $NbrOfNbrAtom ($NbrAtom->GetNeighbors($CentralAtom)) {
3212 if (!$NbrOfNbrAtom->_DoesAtomSpecificationMatch($NbrOfNbrAtomSpec)) {
3213 next NBRATOMSPEC;
3214 }
3215 }
3216 }
3217
3218 # It's a match for a neighbor atom specification...
3219 $NbrSpecAlreadyMatchedRef->{$Index} = $Index;
3220 $NbrSpecMatchCount++;
3221
3222 if ($NbrSpecMatchCount == $NbrSpecCount) {
3223 # It's match...
3224 $NbrSpecsMatched = 1;
3225 last NBRATOM;
3226 }
3227 # Match next neighbor atom...
3228 next NBRATOM;
3229 }
3230 }
3231 return ($NbrSpecsMatched, $NbrSpecMatchCount);
3232 }
3233
3234 # Match central atom's missing hydrogens with any unmatched atom and bond
3235 # specifications...
3236 #
3237 sub _MatchAtomNeighborhoodUsingMissingHydrogens {
3238 my($CentralAtom, $NbrSpecCount, $NbrSpecMatchCount, $NbrSpecAlreadyMatchedRef, $NbrAtomSpecsRef, $NbrBondSpecsRef, $NbrOfNbrAtomSpecsRef) = @_;
3239 my($Index, $NbrAtom, $NbrAtomSpec, $NbrBondSpec, $NumOfMissingHydrogens, $MissingHydrogensIndex, $NbrSpecsMatched, $AtomSpecMatched, $AtomSpec, $AtomSymbol);
3240
3241 $NbrSpecsMatched = 0;
3242
3243 $NumOfMissingHydrogens = $CentralAtom->GetNumOfMissingHydrogens();
3244 if (($NbrSpecCount - $NbrSpecMatchCount) > $NumOfMissingHydrogens) {
3245 # It won't match...
3246 return ($NbrSpecsMatched, $NbrSpecMatchCount);
3247 }
3248
3249 MISSINGHYDROGENNBR: for $MissingHydrogensIndex (0 .. ($NumOfMissingHydrogens - 1)) {
3250 NBRATOMSPEC: for $Index (0 .. ($NbrSpecCount - 1)) {
3251 if (exists $NbrSpecAlreadyMatchedRef->{$Index}) {
3252 next NBRATOMSPEC;
3253 }
3254 $NbrAtomSpec = $NbrAtomSpecsRef->[$Index];
3255 $NbrBondSpec = $NbrBondSpecsRef->[$Index];
3256
3257 $NbrAtomSpec =~ s/ //g;
3258
3259 # Match neighbor atom specification hydrogen atom symbol...
3260 $AtomSpecMatched = 0;
3261 ATOMSPEC: for $AtomSpec (split /\,/, $NbrAtomSpec) {
3262 ($AtomSymbol) = split /\./, $AtomSpec;
3263 if ($AtomSymbol =~ /^(H|A|\*)$/i) {
3264 $AtomSpecMatched = 1;
3265 last ATOMSPEC;
3266 }
3267 }
3268 if (!$AtomSpecMatched) {
3269 next NBRATOMSPEC;
3270 }
3271
3272 # Match neighbor atom bond specification to singal bond...
3273 if (defined $NbrBondSpec) {
3274 $NbrBondSpec =~ s/ //g;
3275 if ($NbrBondSpec !~ /^(-|1|s|Single|\~|\*|Any)/i) {
3276 next NBRATOMSPEC;
3277 }
3278 }
3279
3280 # It's a match for a neighbor atom specification...
3281 $NbrSpecAlreadyMatchedRef->{$Index} = $Index;
3282 $NbrSpecMatchCount++;
3283
3284 if ($NbrSpecMatchCount == $NbrSpecCount) {
3285 # It's match...
3286 $NbrSpecsMatched = 1;
3287 last MISSINGHYDROGENNBR;
3288 }
3289 # Match next missing hydrogen neighbor...
3290 next MISSINGHYDROGENNBR;
3291 }
3292 }
3293
3294 return ($NbrSpecsMatched, $NbrSpecMatchCount);
3295 }
3296
3297 # Sort atom and bond specifications base on neighbor atom specifications going
3298 # from most to least specific atom specifications.
3299 #
3300 # Atom specifications are sorted at the following two levels:
3301 #
3302 # o By atom specification count with in each specification going from most specific
3303 # to least specific, where count is determined by the number of "," in each
3304 # specification. Wild card containing specifications are considered least specific
3305 # and end up at the end of the sorted list.
3306 # o By atomic invariant count with in each sorted list going from most specific to
3307 # least specific, where count is determined by the number of "." in each atom
3308 # specification.
3309 #
3310 #A single atom specification,
3311 # without any commas in atom specification, is is considered most specific...
3312 #
3313 sub _SortSpecificationsForAtomNeighborhoodMatch {
3314 my($This, $NbrAtomSpecsRef, $NbrBondSpecsRef, $NbrOfNbrAtomSpecsRef) = @_;
3315 my($Index, $NeedToSort, $NumOfNbrAtomSpecs, $NbrAtomSpecCount, $NbrAtomSpecAtomicInvarintCount, $NbrAtomSpecToMatch, $NbrAtomSpec, $FirstAtomicInvariant, $WildCardInNbrAtomSpec, @NbrAtomSpecs, @NbrAtomSpecAtomicInvariants, @SortedNbrAtomSpecs, @SortedNbrBondSpecs, @SortedNbrOfNbrAtomSpecs, %NbrAtomSpecDataMap);
3316
3317 $NumOfNbrAtomSpecs = defined $NbrAtomSpecsRef ? scalar @{$NbrAtomSpecsRef} : 0;
3318
3319 # Figure out whether sorting is necessary...
3320 $NeedToSort = 0;
3321 if ($NumOfNbrAtomSpecs > 1) {
3322 ATOMSPEC: for $NbrAtomSpecToMatch (@{$NbrAtomSpecsRef}) {
3323 if ($NbrAtomSpecToMatch =~ /(,|\.|A|\*)/i) {
3324 $NeedToSort = 1;
3325 last ATOMSPEC;
3326 }
3327 }
3328 }
3329 if (!$NeedToSort) {
3330 # Nothing to do...
3331 return ($NbrAtomSpecsRef, $NbrBondSpecsRef, $NbrOfNbrAtomSpecsRef);
3332 }
3333
3334 %NbrAtomSpecDataMap = ();
3335
3336 for $Index (0 .. ($NumOfNbrAtomSpecs - 1)) {
3337 $NbrAtomSpecToMatch = $NbrAtomSpecsRef->[$Index];
3338 $NbrAtomSpecToMatch =~ s/ //g;
3339
3340 @NbrAtomSpecs = split /\,/, $NbrAtomSpecToMatch;
3341 $NbrAtomSpecCount = scalar @NbrAtomSpecs;
3342
3343 # Does neighbor specification contains a wild card in atom symbol specification?
3344 #
3345 if ($NbrAtomSpecToMatch =~ /(A|\*)/i) {
3346 $WildCardInNbrAtomSpec = 0;
3347 NBRATOMSPEC: for $NbrAtomSpec (@NbrAtomSpecs) {
3348 ($FirstAtomicInvariant) = split /\./, $NbrAtomSpec;
3349 if ($FirstAtomicInvariant =~ /^!/) {
3350 $FirstAtomicInvariant =~ s/^!//;
3351 }
3352 $WildCardInNbrAtomSpec = $This->_IsWildCardAtomSymbolAtomicInvariant($FirstAtomicInvariant);
3353 if ($WildCardInNbrAtomSpec) {
3354 last NBRATOMSPEC;
3355 }
3356 }
3357 if ($WildCardInNbrAtomSpec) {
3358 # Set NbrAtomSpecCount arbitrarily high to make the spec containing wild
3359 # card last on the sorted list while maintaining its original order in the list...
3360 $NbrAtomSpecCount = 999;
3361 }
3362 }
3363
3364 if (!exists $NbrAtomSpecDataMap{$NbrAtomSpecCount}) {
3365 %{$NbrAtomSpecDataMap{$NbrAtomSpecCount}} = ();
3366 }
3367
3368 # Use first NbrAtomSpec available in @NbrAtomSpecs to determine atomic invariant count
3369 # with in each NbrAtomSpecToMatch, as @NbrAtomSpecs derived from $NbrAtomSpecToMatch
3370 # simply corresponds to a list of possible matches...
3371 #
3372 ($NbrAtomSpec) = @NbrAtomSpecs;
3373 @NbrAtomSpecAtomicInvariants = split /\./, $NbrAtomSpec;
3374 $NbrAtomSpecAtomicInvarintCount = scalar @NbrAtomSpecAtomicInvariants;
3375
3376 if (!exists $NbrAtomSpecDataMap{$NbrAtomSpecCount}{$NbrAtomSpecAtomicInvarintCount}) {
3377 @{$NbrAtomSpecDataMap{$NbrAtomSpecCount}{$NbrAtomSpecAtomicInvarintCount}} = ();
3378 }
3379 push @{$NbrAtomSpecDataMap{$NbrAtomSpecCount}{$NbrAtomSpecAtomicInvarintCount}}, $Index;
3380
3381 }
3382
3383 @SortedNbrAtomSpecs = (); @SortedNbrBondSpecs = ();
3384 @SortedNbrOfNbrAtomSpecs = ();
3385
3386 for $NbrAtomSpecCount ( sort { $a <=> $b } keys %NbrAtomSpecDataMap) {
3387 for $NbrAtomSpecAtomicInvarintCount ( sort { $b <=> $a } keys %{$NbrAtomSpecDataMap{$NbrAtomSpecCount}}) {
3388 for $Index (@{$NbrAtomSpecDataMap{$NbrAtomSpecCount}{$NbrAtomSpecAtomicInvarintCount}}) {
3389 push @SortedNbrAtomSpecs, $NbrAtomSpecsRef->[$Index];
3390 if (defined $NbrBondSpecsRef) {
3391 push @SortedNbrBondSpecs, $NbrBondSpecsRef->[$Index];
3392 }
3393 if (defined $NbrOfNbrAtomSpecsRef) {
3394 push @SortedNbrOfNbrAtomSpecs, $NbrOfNbrAtomSpecsRef->[$Index];
3395 }
3396 }
3397 }
3398 }
3399
3400 return (\@SortedNbrAtomSpecs, defined $NbrBondSpecsRef ? \@SortedNbrBondSpecs : undef, defined $NbrOfNbrAtomSpecsRef ? \@SortedNbrOfNbrAtomSpecs : undef);
3401 }
3402
3403 # Check whether atom matches supported atom specification...
3404 #
3405 sub _DoesAtomSpecificationMatch {
3406 my($This, $AtomSpecificationToMatch) = @_;
3407 my($AtomSpecification, $AtomicInvariant, $AtomSpecificationMatched, $AtomicInvariantMatched, $FirstMatch);
3408
3409 # Anything to match...
3410 if (!(defined($AtomSpecificationToMatch) && $AtomSpecificationToMatch)) {
3411 return 1;
3412 }
3413
3414 # Take out any spaces...
3415 $AtomSpecificationToMatch =~ s/ //g;
3416
3417 # Match specified atom specifications. For multiple atom specifications in a comma delimited string,
3418 # only one atom specification needs to match for a successful match. It's up to the caller to make
3419 # sure that the specificaton list is ordered from least to most specific atom specification...
3420 #
3421 for $AtomSpecification (split /\,/, $AtomSpecificationToMatch) {
3422 $AtomSpecificationMatched = 1;
3423 $FirstMatch = 1;
3424
3425 # Match all atom symbol atomic invariants...
3426 ATOMICINVARIANT: for $AtomicInvariant (split /\./, $AtomSpecification) {
3427 if ($FirstMatch) {
3428 # Match atom symbol atomic invariant...
3429 $FirstMatch = 0;
3430 $AtomicInvariantMatched = $This->_MatchAtomSymbolAtomicInvariant($AtomicInvariant);
3431 }
3432 else {
3433 # Match non atom symbol atomic invariant...
3434 $AtomicInvariantMatched = $This->_MatchNonAtomSymbolAtomicInvariant($AtomicInvariant);
3435 }
3436
3437 if (!$AtomicInvariantMatched) {
3438 # No need to match other atomic invariants...
3439 $AtomSpecificationMatched = 0;
3440 last ATOMICINVARIANT;
3441 }
3442 }
3443
3444 if ($AtomSpecificationMatched) {
3445 # No need to match other atom specifications...
3446 return 1;
3447 }
3448 }
3449
3450 # Nothing matched...
3451 return 0;
3452 }
3453
3454 # Check whether atom matches atom symbol atomic invariant...
3455 #
3456 sub _MatchAtomSymbolAtomicInvariant {
3457 my($This, $AtomicInvariant) = @_;
3458 my($NegateMatch, $Status, $AtomicNumber);
3459
3460 $Status = 0;
3461 $NegateMatch = 0;
3462
3463 # Does match needs to be negated?
3464 if ($AtomicInvariant =~ /^!/) {
3465 $NegateMatch = 1;
3466 $AtomicInvariant =~ s/^!//;
3467 }
3468
3469 ATOMICINVARIANT: {
3470 # Any atom match...
3471 if ($This->_IsWildCardAtomSymbolAtomicInvariant($AtomicInvariant)) {
3472 $Status = 1;
3473 last ATOMICINVARIANT;
3474 }
3475
3476 # Atomic number match...
3477 if ($AtomicInvariant =~ /^#/) {
3478 $AtomicNumber = $AtomicInvariant; $AtomicNumber =~ s/^#//;
3479 $Status = ($This->{AtomicNumber} == $AtomicNumber) ? 1 : 0;
3480 last ATOMICINVARIANT;
3481 }
3482
3483 # Atom symbol match...
3484 $Status = ($This->{AtomSymbol} =~ /^$AtomicInvariant$/i) ? 1 : 0;
3485 }
3486
3487 if ($NegateMatch) {
3488 $Status = $Status ? 0 : 1;
3489 }
3490
3491 return $Status;
3492 }
3493
3494 # Is it a wild card atom symbol atomic invariant?
3495 #
3496 sub _IsWildCardAtomSymbolAtomicInvariant {
3497 my($This, $AtomicInvariant) = @_;
3498
3499 return ($AtomicInvariant =~ /^(A|\*)$/i) ? 1 : 0;
3500 }
3501
3502 # Check whether atom matches non atom symbol atomic invariants...
3503 #
3504 sub _MatchNonAtomSymbolAtomicInvariant {
3505 my($This, $AtomicInvariant) = @_;
3506 my($NegateMatch, $Status, $Name, $Value, $UnknownName);
3507
3508 ($Status, $NegateMatch, $UnknownName) = ('0') x 3;
3509
3510 # Does match needs to be negated?
3511 if ($AtomicInvariant =~ /^!/) {
3512 $NegateMatch = 1;
3513 $AtomicInvariant =~ s/^!//;
3514 }
3515
3516 # Extract atomic invariant name and any value...
3517 if ($AtomicInvariant =~ /[0-9\*]+/) {
3518 ($Name, $Value) = $AtomicInvariant =~ /^([a-zA-Z]+)([0-9\-\+\*\>\<\=]+)$/;
3519 }
3520 else {
3521 ($Name, $Value) = ($AtomicInvariant, undef);
3522 }
3523
3524 NAME: {
3525 # Match number of non-hydrogen atom neighbors
3526 if ($Name =~ /^X$/i) {
3527 $Status = (defined($Value) && $This->GetNumOfNonHydrogenAtomNeighbors() == $Value) ? 1 : 0;
3528 last NAME;
3529 }
3530
3531 # Match total number of atom neighbors including missing hydrogens...
3532 if ($Name =~ /^T$/i) {
3533 $Status = (defined($Value) && ($This->GetNumOfNonHydrogenAtomNeighbors() + $This->GetNumOfHydrogens()) == $Value) ? 1 : 0;
3534 last NAME;
3535 }
3536
3537 # Match formal charge...
3538 if ($Name =~ /^FC$/i) {
3539 my $FormalCharge = $This->GetFormalCharge();
3540 $Status = $This->_MatchNonAtomSymbolAtomicInvariantValue($FormalCharge, $Value);
3541 last NAME;
3542 }
3543
3544 # Match aromatic annotation indicating whether atom is aromatic...
3545 if ($Name =~ /^Ar$/i) {
3546 $Status = $This->IsAromatic() ? 1 : 0;
3547 last NAME;
3548 }
3549
3550 # Match number of implicit and explicit hydrogens...
3551 if ($Name =~ /^H$/i) {
3552 $Status = (defined($Value) && ($This->GetNumOfHydrogens() == $Value)) ? 1 : 0;
3553 last NAME;
3554 }
3555
3556 # Match ring atom annotation indicating whether atom is in ring...
3557 if ($Name =~ /^RA$/i) {
3558 $Status = defined($Value) ? $This->IsInRingOfSize($Value) : ($This->IsInRing() ? 1 : 0);
3559 last NAME;
3560 }
3561
3562 # Match number of rings for atom..
3563 if ($Name =~ /^TR$/i) {
3564 $Status = (defined($Value) && ($Value == $This->GetNumOfRings())) ? 1 : 0;
3565 last NAME;
3566 }
3567
3568 # Match sum of bond orders to non-hydrogen atom neighbors...
3569 if ($Name =~ /^BO$/i) {
3570 $Status = (defined($Value) && $This->GetSumOfBondOrdersToNonHydrogenAtoms() == $Value) ? 1 : 0;
3571 last NAME;
3572 }
3573
3574 # Match largest bond order of non-hydrogen atom neighbors...
3575 if ($Name =~ /^LBO$/i) {
3576 $Status = (defined($Value) && $This->GetLargestBondOrderToNonHydrogenAtoms() == $Value) ? 1 : 0;
3577 last NAME;
3578 }
3579
3580 # Match number of single bonds to non-hydrogen atom neighbors...
3581 if ($Name =~ /^SB$/i) {
3582 $Status = (defined($Value) && $This->GetNumOfSingleBondsToNonHydrogenAtoms() == $Value) ? 1 : 0;
3583 last NAME;
3584 }
3585
3586 # Match total number of single bonds to atom neighbors including missing and explicit hydrogens...
3587 if ($Name =~ /^TSB$/i) {
3588 $Status = (defined($Value) && ($This->GetNumOfSingleBondsToNonHydrogenAtoms() + $This->GetNumOfHydrogens()) == $Value) ? 1 : 0;
3589 last NAME;
3590 }
3591
3592 # Match number of double bonds to non-hydrogen atom neighbors...
3593 if ($Name =~ /^DB$/i) {
3594 $Status = (defined($Value) && $This->GetNumOfDoubleBondsToNonHydrogenAtoms() == $Value) ? 1 : 0;
3595 last NAME;
3596 }
3597
3598 # Match number of triple bonds to non-hydrogen atom neighbors...
3599 if ($Name =~ /^TB$/i) {
3600 $Status = (defined($Value) && $This->GetNumOfTripleBondsToNonHydrogenAtoms() == $Value) ? 1 : 0;
3601 last NAME;
3602 }
3603
3604 # Match number of aromatic bonds to non-hydrogen atom neighbors...
3605 if ($Name =~ /^AB$/i) {
3606 $Status = (defined($Value) && $This->GetNumOfAromaticBondsToNonHydrogenAtoms() == $Value) ? 1 : 0;
3607 last NAME;
3608 }
3609
3610
3611 # Match mass number indicating isotope other than most abundant isotope...
3612 if ($Name =~ /^MN$/i) {
3613 $Status = (defined($Value) && $This->GetMassNumber() == $Value) ? 1 : 0;
3614 last NAME;
3615 }
3616
3617 # Match spin multiplicity...
3618 if ($Name =~ /^SM$/i) {
3619 my $SpinMultiplicity = $This->GetSpinMultiplicity();
3620 if (!defined $SpinMultiplicity) { $SpinMultiplicity = 0; }
3621 $Status = (defined($Value) && defined($SpinMultiplicity) && $Value == $SpinMultiplicity) ? 1 : 0;
3622 last NAME;
3623 }
3624
3625 $UnknownName = 1;
3626 carp "Warning: ${ClassName}->_MatchNonAtomSymbolAtomicInvariant: Unknown atomic invariant $AtomicInvariant...";
3627 }
3628
3629 if (!$UnknownName) {
3630 if ($NegateMatch) {
3631 $Status = $Status ? 0 : 1;
3632 }
3633 }
3634
3635 return $Status;
3636 }
3637
3638 # Match atomic invariant value...
3639 #
3640 # Specified value format:
3641 # . +* : Any positive value
3642 # . -* : Any negative value
3643 # . >ValidNumber or >=ValidNumber
3644 # . <ValidNumber or <=ValidNumber
3645 # . Any valid number
3646 #
3647 sub _MatchNonAtomSymbolAtomicInvariantValue {
3648 my($This, $TargetValue, $SpecifiedValue) = @_;
3649 my($Status);
3650
3651 $Status = 0;
3652
3653 if (!(defined($TargetValue) && defined($SpecifiedValue))) {
3654 return $Status;
3655 }
3656
3657 VALUE: {
3658 if ($SpecifiedValue =~ /^\+\*/) {
3659 $Status = ($TargetValue > 0) ? 1 : 0;
3660 last VALUE;
3661 }
3662 if ($SpecifiedValue =~ /^\-\*/) {
3663 $Status = ($TargetValue < 0) ? 1 : 0;
3664 last VALUE;
3665 }
3666 if ($SpecifiedValue =~ /^>/) {
3667 if ($SpecifiedValue =~ /^>=/) {
3668 $SpecifiedValue =~ s/^>=//;
3669 $Status = ($SpecifiedValue >= $TargetValue) ? 1 : 0;
3670 }
3671 else {
3672 $SpecifiedValue =~ s/^>//;
3673 $Status = ($SpecifiedValue > $TargetValue) ? 1 : 0;
3674 }
3675 last VALUE;
3676 }
3677 if ($SpecifiedValue =~ /^</) {
3678 if ($SpecifiedValue =~ /^<=/) {
3679 $SpecifiedValue =~ s/^<=//;
3680 $Status = ($SpecifiedValue <= $TargetValue) ? 1 : 0;
3681 }
3682 else {
3683 $SpecifiedValue =~ s/^<//;
3684 $Status = ($SpecifiedValue < $TargetValue) ? 1 : 0;
3685 }
3686 last VALUE;
3687 }
3688 # Default is do perform an equality match...
3689 $Status = ($SpecifiedValue == $TargetValue) ? 1 : 0;
3690 }
3691
3692 return $Status;
3693 }
3694
3695 # Check whether atoms match bond specifications...
3696 #
3697 sub _DoesBondSpecificationMatch {
3698 my($This, $BondedAtom, $BondSpecificationToMatch) = @_;
3699 my($BondSpecification, $BondSymbolSpecification, $BondSpecificationMatched);
3700
3701 # Anything to match...
3702 if (!(defined($BondSpecificationToMatch) && $BondSpecificationToMatch)) {
3703 return 1;
3704 }
3705
3706 # Take out any spaces...
3707 $BondSpecificationToMatch =~ s/ //g;
3708
3709 # Match specified bond specifications. For multiple bond specifications in a comma delimited string,
3710 # only one bond specification needs to match for a successful match...
3711 #
3712 for $BondSpecification (split /\,/, $BondSpecificationToMatch) {
3713 $BondSpecificationMatched = 1;
3714
3715 # Match all specified bond symbol specifications...
3716 BONDSYMBOL: for $BondSymbolSpecification (split /\./, $BondSpecification) {
3717 if (!$This->_MatchBondSymbolSpecification($BondedAtom, $BondSymbolSpecification)) {
3718 # No need to match other bond symbol specifications...
3719 $BondSpecificationMatched = 0;
3720 last BONDSYMBOL;
3721 }
3722 }
3723 if ($BondSpecificationMatched) {
3724 # No need to try matching other bond specifications...
3725 return 1;
3726 }
3727 }
3728
3729 # Nothing matched...
3730 return 0;
3731 }
3732
3733 # Check whether atoms match bond symbol specification...
3734 #
3735 sub _MatchBondSymbolSpecification {
3736 my($This, $BondedAtom, $BondSymbolSpecification) = @_;
3737 my($NegateMatch, $Status, $Bond, $BondSymbol, $UnknownBondSymbol);
3738
3739 ($Status, $NegateMatch, $UnknownBondSymbol) = ('0') x 3;
3740
3741 # Does match needs to be negated?
3742 if ($BondSymbolSpecification =~ /^!/) {
3743 $NegateMatch = 1;
3744 $BondSymbolSpecification =~ s/^!//;
3745 }
3746 $BondSymbol = $BondSymbolSpecification;
3747 $Bond = $This->GetBondToAtom($BondedAtom);
3748
3749 BONDSYMBOL: {
3750 if ($BondSymbol =~ /^(-|1|s|Single)$/i) { $Status = $Bond->IsSingle() ? 1 : 0; last BONDSYMBOL; }
3751 if ($BondSymbol =~ /^(=|2|d|Double)$/i) { $Status = $Bond->IsDouble() ? 1 : 0; last BONDSYMBOL; }
3752 if ($BondSymbol =~ /^(#|3|t|Triple)$/i) { $Status = $Bond->IsTriple() ? 1 : 0; last BONDSYMBOL; }
3753 if ($BondSymbol =~ /^(:|a|Ar|Aromatic)$/i) { $Status = $Bond->IsAromatic() ? 1 : 0; last BONDSYMBOL; }
3754
3755 if ($BondSymbol =~ /^(\@|RB|Ring)$/i) { $Status = $Bond->IsInRing() ? 1 : 0; last BONDSYMBOL; }
3756
3757 if ($BondSymbol =~ /^(\~|\*|Any)$/i) { $Status = 1; last BONDSYMBOL; }
3758
3759 $UnknownBondSymbol = 1;
3760 carp "Warning: ${ClassName}->_MatchBondSpecification: Unknown bond specification $BondSymbolSpecification...";
3761 }
3762
3763 if (!$UnknownBondSymbol) {
3764 if ($NegateMatch) {
3765 $Status = $Status ? 0 : 1;
3766 }
3767 }
3768
3769 return $Status;
3770 }
3771
3772 # Is it a saturated atom?
3773 #
3774 sub IsSaturated {
3775 my($This) = @_;
3776
3777 return !$This->IsUnsaturated();
3778 }
3779
3780 # Is it an unsaturated atom containing at least one non-single bond?
3781 #
3782 sub IsUnsaturated {
3783 my($This) = @_;
3784 my($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds);
3785
3786 ($NumOfSingleBonds, $NumOfDoubleBonds, $NumOfTripleBonds, $NumOfAromaticBonds) = $This->GetNumOfBondTypesToNonHydrogenAtoms();
3787
3788 return ($NumOfDoubleBonds || $NumOfTripleBonds || $NumOfAromaticBonds) ? 1 : 0;
3789 }
3790
3791 # Is atom in a ring?
3792 #
3793 sub IsInRing {
3794 my($This) = @_;
3795
3796 # Is this atom in a molecule?
3797 if (!$This->HasProperty('Molecule')) {
3798 return undef;
3799 }
3800 my($Molecule);
3801 $Molecule = $This->GetProperty('Molecule');
3802
3803 return $Molecule->_IsAtomInRing($This);
3804 }
3805
3806 # Is atom not in a ring?
3807 #
3808 sub IsNotInRing {
3809 my($This) = @_;
3810
3811 # Is this atom in a molecule?
3812 if (!$This->HasProperty('Molecule')) {
3813 return undef;
3814 }
3815 my($Molecule);
3816 $Molecule = $This->GetProperty('Molecule');
3817
3818 return $Molecule->_IsAtomNotInRing($This);
3819 }
3820
3821 # Is atom only in one ring?
3822 #
3823 sub IsOnlyInOneRing {
3824 my($This) = @_;
3825
3826 # Is this atom in a molecule?
3827 if (!$This->HasProperty('Molecule')) {
3828 return undef;
3829 }
3830 my($Molecule);
3831 $Molecule = $This->GetProperty('Molecule');
3832
3833 return $Molecule->_IsAtomInOnlyOneRing($This);
3834 }
3835
3836 # Is atom in a ring of specific size?
3837 #
3838 sub IsInRingOfSize {
3839 my($This, $RingSize) = @_;
3840
3841 # Is this atom in a molecule?
3842 if (!$This->HasProperty('Molecule')) {
3843 return undef;
3844 }
3845 my($Molecule);
3846 $Molecule = $This->GetProperty('Molecule');
3847
3848 return $Molecule->_IsAtomInRingOfSize($This, $RingSize);
3849 }
3850
3851 # Get size of smallest ring containing the atom...
3852 #
3853 sub GetSizeOfSmallestRing {
3854 my($This) = @_;
3855
3856 # Is this atom in a molecule?
3857 if (!$This->HasProperty('Molecule')) {
3858 return undef;
3859 }
3860 my($Molecule);
3861 $Molecule = $This->GetProperty('Molecule');
3862
3863 return $Molecule->_GetSizeOfSmallestAtomRing($This);
3864 }
3865
3866 # Get size of largest ring containing the atom...
3867 #
3868 sub GetSizeOfLargestRing {
3869 my($This) = @_;
3870
3871 # Is this atom in a molecule?
3872 if (!$This->HasProperty('Molecule')) {
3873 return undef;
3874 }
3875 my($Molecule);
3876 $Molecule = $This->GetProperty('Molecule');
3877
3878 return $Molecule->_GetSizeOfLargestAtomRing($This);
3879 }
3880
3881 # Get number of rings containing the atom...
3882 #
3883 sub GetNumOfRings {
3884 my($This) = @_;
3885
3886 # Is this atom in a molecule?
3887 if (!$This->HasProperty('Molecule')) {
3888 return undef;
3889 }
3890 my($Molecule);
3891 $Molecule = $This->GetProperty('Molecule');
3892
3893 return $Molecule->_GetNumOfAtomRings($This);
3894 }
3895
3896 # Get number of rings with odd size containing the atom...
3897 #
3898 sub GetNumOfRingsWithOddSize {
3899 my($This) = @_;
3900
3901 # Is this atom in a molecule?
3902 if (!$This->HasProperty('Molecule')) {
3903 return undef;
3904 }
3905 my($Molecule);
3906 $Molecule = $This->GetProperty('Molecule');
3907
3908 return $Molecule->_GetNumOfAtomRingsWithOddSize($This);
3909 }
3910
3911 # Get number of rings with even size containing the atom...
3912 #
3913 sub GetNumOfRingsWithEvenSize {
3914 my($This) = @_;
3915
3916 # Is this atom in a molecule?
3917 if (!$This->HasProperty('Molecule')) {
3918 return undef;
3919 }
3920 my($Molecule);
3921 $Molecule = $This->GetProperty('Molecule');
3922
3923 return $Molecule->_GetNumOfAtomRingsWithEvenSize($This);
3924 }
3925
3926 # Get number of rings with specified size containing the atom...
3927 #
3928 sub GetNumOfRingsWithSize {
3929 my($This, $RingSize) = @_;
3930
3931 # Is this atom in a molecule?
3932 if (!$This->HasProperty('Molecule')) {
3933 return undef;
3934 }
3935 my($Molecule);
3936 $Molecule = $This->GetProperty('Molecule');
3937
3938 return $Molecule->_GetNumOfAtomRingsWithSize($This, $RingSize);
3939
3940 }
3941
3942 # Get number of rings with size less than specified containing the atom...
3943 #
3944 sub GetNumOfRingsWithSizeLessThan {
3945 my($This, $RingSize) = @_;
3946
3947 # Is this atom in a molecule?
3948 if (!$This->HasProperty('Molecule')) {
3949 return undef;
3950 }
3951 my($Molecule);
3952 $Molecule = $This->GetProperty('Molecule');
3953
3954 return $Molecule->_GetNumOfAtomRingsWithSizeLessThan($This, $RingSize);
3955 }
3956
3957 # Get number of rings with size greater than specified size containing the atom...
3958 #
3959 sub GetNumOfRingsWithSizeGreaterThan {
3960 my($This, $RingSize) = @_;
3961
3962 # Is this atom in a molecule?
3963 if (!$This->HasProperty('Molecule')) {
3964 return undef;
3965 }
3966 my($Molecule);
3967 $Molecule = $This->GetProperty('Molecule');
3968
3969 return $Molecule->_GetNumOfAtomRingsWithSizeGreaterThan($This, $RingSize);
3970 }
3971
3972 # Get all rings an array of references to arrays containing ring atoms...
3973 #
3974 sub GetRings {
3975 my($This) = @_;
3976
3977 # Is this atom in a molecule?
3978 if (!$This->HasProperty('Molecule')) {
3979 return undef;
3980 }
3981 my($Molecule);
3982 $Molecule = $This->GetProperty('Molecule');
3983
3984 return $Molecule->_GetAtomRings($This);
3985 }
3986
3987 # Get smallest ring as an array containing ring atoms...
3988 #
3989 sub GetSmallestRing {
3990 my($This) = @_;
3991
3992 # Is this atom in a molecule?
3993 if (!$This->HasProperty('Molecule')) {
3994 return undef;
3995 }
3996 my($Molecule);
3997 $Molecule = $This->GetProperty('Molecule');
3998
3999 return $Molecule->_GetSmallestAtomRing($This);
4000 }
4001
4002 # Get largest ring as an array containing ring atoms...
4003 #
4004 sub GetLargestRing {
4005 my($This) = @_;
4006
4007 # Is this atom in a molecule?
4008 if (!$This->HasProperty('Molecule')) {
4009 return undef;
4010 }
4011 my($Molecule);
4012 $Molecule = $This->GetProperty('Molecule');
4013
4014 return $Molecule->_GetLargestAtomRing($This);
4015 }
4016
4017 # Get odd size rings an array of references to arrays containing ring atoms...
4018 #
4019 sub GetRingsWithOddSize {
4020 my($This) = @_;
4021
4022 # Is this atom in a molecule?
4023 if (!$This->HasProperty('Molecule')) {
4024 return undef;
4025 }
4026 my($Molecule);
4027 $Molecule = $This->GetProperty('Molecule');
4028
4029 return $Molecule->_GetAtomRingsWithOddSize($This);
4030 }
4031
4032 # Get even size rings an array of references to arrays containing ring atoms...
4033 #
4034 sub GetRingsWithEvenSize {
4035 my($This) = @_;
4036
4037 # Is this atom in a molecule?
4038 if (!$This->HasProperty('Molecule')) {
4039 return undef;
4040 }
4041 my($Molecule);
4042 $Molecule = $This->GetProperty('Molecule');
4043
4044 return $Molecule->_GetAtomRingsWithEvenSize($This);
4045 }
4046
4047 # Get rings with specified size as an array of references to arrays containing ring atoms...
4048 #
4049 sub GetRingsWithSize {
4050 my($This, $RingSize) = @_;
4051
4052 # Is this atom in a molecule?
4053 if (!$This->HasProperty('Molecule')) {
4054 return undef;
4055 }
4056 my($Molecule);
4057 $Molecule = $This->GetProperty('Molecule');
4058
4059 return $Molecule->_GetAtomRingsWithSize($This, $RingSize);
4060 }
4061
4062 # Get rings with size less than specfied size as an array of references to arrays containing ring atoms...
4063 #
4064 sub GetRingsWithSizeLessThan {
4065 my($This, $RingSize) = @_;
4066
4067 # Is this atom in a molecule?
4068 if (!$This->HasProperty('Molecule')) {
4069 return undef;
4070 }
4071 my($Molecule);
4072 $Molecule = $This->GetProperty('Molecule');
4073
4074 return $Molecule->_GetAtomRingsWithSizeLessThan($This, $RingSize);
4075 }
4076
4077 # Get rings with size greater than specfied size as an array of references to arrays containing ring atoms...
4078 #
4079 sub GetRingsWithSizeGreaterThan {
4080 my($This, $RingSize) = @_;
4081
4082 # Is this atom in a molecule?
4083 if (!$This->HasProperty('Molecule')) {
4084 return undef;
4085 }
4086 my($Molecule);
4087 $Molecule = $This->GetProperty('Molecule');
4088
4089 return $Molecule->_GetAtomRingsWithSizeGreaterThan($This, $RingSize);
4090 }
4091
4092 # Get next object ID...
4093 sub _GetNewObjectID {
4094 $ObjectID++;
4095 return $ObjectID;
4096 }
4097
4098 # Return a string containing vertices, edges and other properties...
4099 sub StringifyAtom {
4100 my($This) = @_;
4101 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);
4102
4103 $ID = $This->GetID();
4104 $Name = $This->GetName();
4105 $AtomSymbol = $This->GetAtomSymbol();
4106 $AtomicNumber = $This->GetAtomicNumber();
4107 $XYZVector = $This->GetXYZVector();
4108
4109 $AtomicWeight = $This->GetAtomicWeight();
4110 if (!defined $AtomicWeight) {
4111 $AtomicWeight = 'undefined';
4112 }
4113 $ExactMass = $This->GetExactMass();
4114 if (!defined $ExactMass) {
4115 $ExactMass = 'undefined';
4116 }
4117 $NumOfNeighbors = $This->GetNumOfNeighbors();
4118 if (!defined $NumOfNeighbors) {
4119 $NumOfNeighbors = 'undefined';
4120 }
4121 $NumOfBonds = $This->GetNumOfBonds();
4122 if (!defined $NumOfBonds) {
4123 $NumOfBonds = 'undefined';
4124 }
4125 $Valence = $This->GetValence();
4126 if (!defined $Valence) {
4127 $Valence = 'undefined';
4128 }
4129
4130 $MissingHydrogens = $This->GetNumOfMissingHydrogens();
4131 if (!defined $MissingHydrogens) {
4132 $MissingHydrogens = 'undefined';
4133 }
4134 $TotalHydrogens = $This->GetNumOfHydrogens();
4135 if (!defined $TotalHydrogens) {
4136 $TotalHydrogens = 'undefined';
4137 }
4138 $ImplicitHydrogens = $This->GetNumOfImplicitHydrogens();
4139 if (!defined $ImplicitHydrogens) {
4140 $ImplicitHydrogens = 'undefined';
4141 }
4142 $ExplicitHydrogens = $This->GetNumOfExplicitHydrogens();
4143 if (!defined $ExplicitHydrogens) {
4144 $ExplicitHydrogens = 'undefined';
4145 }
4146
4147 $FormalCharge = $This->GetFormalCharge();
4148 if (!defined $FormalCharge) {
4149 $FormalCharge = 'undefined';
4150 }
4151 $Charge = $This->GetCharge();
4152 if (!defined $Charge) {
4153 $Charge = 'undefined';
4154 }
4155
4156 $SpinMultiplicity = $This->GetSpinMultiplicity();
4157 if (!defined $SpinMultiplicity) {
4158 $SpinMultiplicity = 'undefined';
4159 }
4160 $FreeRadicalElectrons = $This->GetFreeRadicalElectrons();
4161 if (!defined $FreeRadicalElectrons) {
4162 $FreeRadicalElectrons = 'undefined';
4163 }
4164
4165 $RingAtom = $This->IsInRing();
4166 if (defined $RingAtom) {
4167 $RingAtom = $RingAtom ? 'Yes' : 'No';
4168 $NumOfRings = $This->GetNumOfRings();
4169 }
4170 else {
4171 $RingAtom = 'undefined';
4172 $NumOfRings = 'undefined';
4173 }
4174
4175 $AromaticAtom = $This->GetAromatic();
4176 if (defined $AromaticAtom) {
4177 $AromaticAtom = $AromaticAtom ? 'Yes' : 'No';
4178 }
4179 else {
4180 $AromaticAtom = 'undefined';
4181 }
4182
4183 $StereochemistryString = '';
4184 $StereoCenter = $This->GetStereoCenter();
4185 if (defined $StereoCenter) {
4186 $StereoCenterStatus = $This->IsStereoCenter() ? 'Yes' : 'No';
4187 $StereoChemistry = $This->GetStereochemistry();
4188 if (!defined $StereoChemistry) {
4189 $StereoChemistry = 'undefined';
4190 }
4191 $StereochemistryString = "StereoCenter: $StereoCenterStatus; Stereochemistry: $StereoChemistry";
4192 }
4193
4194 $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";
4195
4196 if ($StereochemistryString) {
4197 $AtomString .= "; $StereochemistryString";
4198 }
4199
4200 return $AtomString;
4201 }
4202
4203 # Load appropriate atom data files from <MayaChemTools>/lib directory used by various
4204 # object methods in the current class...
4205 #
4206 sub _LoadAtomClassData {
4207 my($MayaChemToolsLibDir);
4208
4209 $MayaChemToolsLibDir = GetMayaChemToolsLibDirName();
4210
4211 _LoadAtomValenceModelData($MayaChemToolsLibDir);
4212
4213 }
4214
4215 #
4216 # Load data for supported valence models...
4217 #
4218 sub _LoadAtomValenceModelData {
4219 my($MayaChemToolsLibDir) = @_;
4220 my($MDLValenceModelDataFile, $DaylightValenceModelDataFile);
4221
4222 %MDLValenceModelDataMap = ();
4223 %DaylightValenceModelDataMap = ();
4224
4225 $MDLValenceModelDataFile = $MayaChemToolsLibDir . "/data/MDLValenceModelData.csv";
4226 $DaylightValenceModelDataFile = $MayaChemToolsLibDir . "/data/DaylightValenceModelData.csv";
4227
4228 if (! -e "$MDLValenceModelDataFile") {
4229 croak "Error: ${ClassName}::_LoadAtomValenceModelData: MayaChemTools package file, $MDLValenceModelDataFile, is missing: Possible installation problems...";
4230 }
4231
4232 if (! -e "$DaylightValenceModelDataFile") {
4233 croak "Error: ${ClassName}::_LoadAtomValenceModelData: MayaChemTools package file, $DaylightValenceModelDataFile, is missing: Possible installation problems...";
4234 }
4235
4236 _LoadValenceModelDataFile($MDLValenceModelDataFile, \%MDLValenceModelDataMap);
4237 _LoadValenceModelDataFile($DaylightValenceModelDataFile, \%DaylightValenceModelDataMap);
4238
4239 }
4240
4241 #
4242 # Load valence model data file...
4243 #
4244 sub _LoadValenceModelDataFile {
4245 my($DataFile, $DataMapRef) = @_;
4246
4247 # File format:
4248 #
4249 # "AtomicNumber","ElementSymbol","FormalCharge","CommomValences"
4250 #
4251 my($InDelim, $Line, $NumOfCols, @ColLabels, @LineWords);
4252
4253 $InDelim = "\,";
4254 open DATAFILE, "$DataFile" or croak "Couldn't open $DataFile: $! ...";
4255
4256 # Skip lines up to column labels...
4257 LINE: while ($Line = GetTextLine(\*DATAFILE)) {
4258 if ($Line !~ /^#/) {
4259 last LINE;
4260 }
4261 }
4262 @ColLabels= quotewords($InDelim, 0, $Line);
4263 $NumOfCols = @ColLabels;
4264
4265 my($AtomicNumber, $ElementSymbol, $FormalCharge, $CommonValences);
4266
4267 # Process element data...
4268 LINE: while ($Line = GetTextLine(\*DATAFILE)) {
4269 if ($Line =~ /^#/) {
4270 next LINE;
4271 }
4272 @LineWords = ();
4273 @LineWords = quotewords($InDelim, 0, $Line);
4274 if (@LineWords != $NumOfCols) {
4275 croak "Error: ${ClassName}::_LoadValenceModelDataFile: The number of data fields, @LineWords, in $DataFile must be $NumOfCols.\nLine: $Line...";
4276 }
4277
4278 ($AtomicNumber, $ElementSymbol, $FormalCharge, $CommonValences) = @LineWords;
4279
4280 if (exists $DataMapRef->{$AtomicNumber}) {
4281 # Additional data for an element...
4282 if (exists $DataMapRef->{$AtomicNumber}{$FormalCharge}) {
4283 # Duplicate data entries for an element...
4284 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...";
4285 next LINE;
4286 }
4287 }
4288 else {
4289 # Data for a new element...
4290 %{$DataMapRef->{$AtomicNumber}} = ();
4291 }
4292
4293 %{$DataMapRef->{$AtomicNumber}{$FormalCharge}} = ();
4294 $DataMapRef->{$AtomicNumber}{$FormalCharge}{ElementSymbol} = $ElementSymbol;
4295
4296 @{$DataMapRef->{$AtomicNumber}{$FormalCharge}{CommonValences}} = ();
4297 @{$DataMapRef->{$AtomicNumber}{$FormalCharge}{CommonValences}} = sort { $a <=> $b } split /\,/, $CommonValences;
4298 }
4299 close DATAFILE;
4300 }
4301
4302 1;
4303
4304 __END__
4305
4306 =head1 NAME
4307
4308 Atom
4309
4310 =head1 SYNOPSIS
4311
4312 use Atom;
4313
4314 =head1 DESCRIPTION
4315
4316 B<Atom> class provides the following methods:
4317
4318 new, AddHydrogens, Copy, DeleteAtom, DeleteHydrogens, DoesAtomNeighborhoodMatch,
4319 GetAtomicInvariantValue, GetAtomicWeight, GetBondToAtom, GetBonds,
4320 GetBondsToHeavyAtoms, GetBondsToHydrogenAtoms, GetBondsToNonHydrogenAtoms,
4321 GetExactMass, GetExplicitHydrogens, GetFormalCharge, GetFreeRadicalElectrons,
4322 GetGroupNumber, GetHeavyAtomNeighbors, GetHeavyAtomNeighborsAtomInformation,
4323 GetHeavyAtomNeighborsBondformation, GetHighestCommonValence,
4324 GetHydrogenAtomNeighbors, GetHydrogens, GetImplicitHydrogens, GetLargestBondOrder,
4325 GetLargestBondOrderToHeavyAtoms, GetLargestBondOrderToNonHydrogenAtoms,
4326 GetLargestRing, GetLowestCommonValence, GetMassNumber, GetMissingHydrogens,
4327 GetNeighbors, GetNeighborsUsingAtomSpecification, GetNonHydrogenAtomNeighbors,
4328 GetNonHydrogenAtomNeighborsAtomInformation,
4329 GetNonHydrogenAtomNeighborsBondInformation, GetNonHydrogenNeighborOfHydrogenAtom,
4330 GetNumOfAromaticBondsToHeavyAtoms, GetNumOfAromaticBondsToNonHydrogenAtoms,
4331 GetNumOfBondTypesToHeavyAtoms, GetNumOfBondTypesToNonHydrogenAtoms, GetNumOfBonds,
4332 GetNumOfBondsToHeavyAtoms, GetNumOfBondsToHydrogenAtoms,
4333 GetNumOfBondsToNonHydrogenAtoms, GetNumOfDoubleBondsToHeavyAtoms,
4334 GetNumOfBondsAvailableForHeavyAtoms, GetNumOfBondsAvailableForNonHydrogenAtoms,
4335 GetNumOfDoubleBondsToNonHydrogenAtoms, GetNumOfExplicitHydrogens,
4336 GetNumOfHeavyAtomNeighbors, GetNumOfHydrogenAtomNeighbors, GetNumOfHydrogens,
4337 GetNumOfImplicitHydrogens, GetNumOfMissingHydrogens, GetNumOfNeighbors,
4338 GetNumOfNonHydrogenAtomNeighbors, GetNumOfRings, GetNumOfRingsWithEvenSize,
4339 GetNumOfRingsWithOddSize, GetNumOfRingsWithSize, GetNumOfRingsWithSizeGreaterThan,
4340 GetNumOfRingsWithSizeLessThan, GetNumOfSigmaAndPiBondsToHeavyAtoms,
4341 GetNumOfSigmaAndPiBondsToNonHydrogenAtoms, GetNumOfSingleBondsToHeavyAtoms,
4342 GetNumOfSingleBondsToNonHydrogenAtoms, GetNumOfTripleBondsToHeavyAtoms,
4343 GetNumOfTripleBondsToNonHydrogenAtoms, GetPeriodNumber,
4344 GetPotentialTotalCommonValence, GetRings, GetRingsWithEvenSize,
4345 GetRingsWithOddSize, GetRingsWithSize, GetRingsWithSizeGreaterThan,
4346 GetRingsWithSizeLessThan, GetSizeOfLargestRing, GetSizeOfSmallestRing,
4347 GetSmallestRing, GetSpinMultiplicity, GetSumOfBondOrders,
4348 GetSumOfBondOrdersToHeavyAtoms, GetSumOfBondOrdersToHydrogenAtoms,
4349 GetSumOfBondOrdersToNonHydrogenAtoms, GetValence, GetValenceElectrons,
4350 GetValenceFreeElectrons, GetX, GetXYZ, GetXYZVector, GetY, GetZ, IsAmideCarbon,
4351 IsAmideNitrogen, IsAromatic, IsArsenic, IsBondedToAtom, IsBromine, IsCarbon, IsCarboxylCarbon,
4352 IsCarboxylOxygen, IsCarboxylateCarbon, IsCarboxylateOxygen, IsChlorine,
4353 IsFluorine, IsFunctionalClassType, IsGuadiniumCarbon, IsGuadiniumNitrogen,
4354 IsHBondAcceptor, IsHBondDonor, IsHalogen, IsHeteroAtom, IsHydrogen,
4355 IsHydrogenBondAcceptor, IsHydrogenBondDonor, IsHydrophobic, IsInRing,
4356 IsInRingOfSize, IsIodine, IsIsotope, IsLipophilic, IsMetallic,
4357 IsNegativelyIonizable, IsNitrogen, IsNonCarbonOrHydrogen, IsNotInRing,
4358 IsOnlyInOneRing, IsOxygen, IsPhosphateOxygen, IsPhosphatePhosphorus, IsPhosphorus,
4359 IsPolarAtom, IsPolarHydrogen, IsPositivelyIonizable, IsSaturated, IsSelenium,
4360 IsSilicon, IsStereoCenter, IsSulfur, IsSulphur, IsTellurium, IsTerminal,
4361 IsTopologicalPharmacophoreType, IsUnsaturated, SetAtomSymbol, SetAtomicNumber,
4362 SetExplicitHydrogens, SetMassNumber, SetStereoCenter, SetStereochemistry,
4363 SetX, SetXYZ, SetY, SetZ, StringifyAtom
4364
4365 B<Atom> class is derived from B<ObjectProperty> base class which provides methods not explicitly
4366 defined in B<Atom> or B<ObjectProperty> class using Perl's AUTOLOAD functionality. These methods
4367 are generated on-the-fly for a specified object property:
4368
4369 Set<PropertyName>(<PropertyValue>);
4370 $PropertyValue = Get<PropertyName>();
4371 Delete<PropertyName>();
4372
4373 =head2 METHODS
4374
4375 =over 4
4376
4377 =item B<new>
4378
4379 $NewAtom = new Atom([%PropertyNameAndValues]);
4380
4381 Using specified I<Atom> property names and values hash, B<new> method creates a new object
4382 and returns a reference to newly created B<Atom> object. By default, following properties are
4383 initialized:
4384
4385 ID = SequentialObjectID
4386 Name = "Atom <SequentialObjectID>"
4387 AtomSymbol = ""
4388 AtomicNumber = 0
4389 XYZ = ZeroVector
4390
4391 Except for I<ID> property, all other default properties and other additional properties can
4392 be set during invocation of this method.
4393
4394 Examples:
4395
4396 $Atom = new Atom();
4397 $CarbonAtom = new Atom('AtomSymbol' => 'C', 'XYZ' => (0.0, 1.0,
4398 0.0));
4399 $OxygenAtom = new Atom('AtomName' => 'Oxygen', AtomSymbol' => 'O',
4400 'XYZ' => (1.0, 1.0, 1.0));
4401
4402 =item B<AddHydrogens>
4403
4404 $NumOfHydrogensAdded = $Atom->AddHydrogens();
4405
4406 Adds hydrogens to an B<Atom> present in a B<Molecule> object and returns
4407 the number of added hydrogens. The current release of MayaChemTools doesn't
4408 assign hydrogen positions.
4409
4410 =item B<Copy>
4411
4412 $AtomCopy = $Atom->Copy();
4413
4414 Copy I<Atom> and its associated data using B<Storable::dclone> and return a new
4415 B<Atom> object.
4416
4417 =item B<DeleteAtom>
4418
4419 $Atom->DeleteAtom();
4420
4421 Delete I<Atom> from a molecule.
4422
4423 =item B<DoesAtomNeighborhoodMatch>
4424
4425 $Status = $Atom->DoesAtomNeighborhoodMatch($CentralAtomSpec);
4426 $Status = $Atom->DoesAtomNeighborhoodMatch($CentralAtomSpec,
4427 $NbrAtomSpecsRef);
4428 $Status = $Atom->DoesAtomNeighborhoodMatch($CentralAtomSpec,
4429 $NbrAtomSpecsRef, $AllowedNbrBondSpecsRef);
4430 $Status = $Atom->DoesAtomNeighborhoodMatch($CentralAtomSpec,
4431 $NbrAtomSpecsRef, $NbrBondSpecsRef,
4432 $AllowedNbrOfNbrAtomSpecsRef);
4433
4434 Returns 1 or 0 based on whether atom matches central atom and its neighborhood
4435 using specified atom and bonds specifications. Neighborhood atom and bond specifications
4436 are specified as array references containing neighbor atom and bond specifications.
4437
4438 Let:
4439
4440 AS = Atom symbol corresponding to element symbol, atomic number (#n)
4441 or any atom (A)
4442
4443 X<n> = Number of non-hydrogen atom neighbors or heavy atoms
4444 attached to atom
4445 T<n> = Total number of atom neighbors including implicit and explicit
4446 hydrogens
4447 BO<n> = Sum of bond orders to non-hydrogen atom neighbors or heavy
4448 atoms attached to atom
4449 LBO<n> = Largest bond order of non-hydrogen atom neighbors or heavy
4450 atoms attached to atom
4451 SB<n> = Number of single bonds to non-hydrogen atom neighbors or
4452 heavy atoms attached to atom
4453 TSB<n> = Total number of single bonds to atom neighbors including implicit
4454 and explicit hydrogens
4455 DB<n> = Number of double bonds to non-hydrogen atom neighbors or
4456 heavy atoms attached to atom
4457 TB<n> = Number of triple bonds to non-hydrogen atom neighbors or
4458 heavy atoms attached to atom
4459 AB<n> = Number of aromatic bonds to non-hydrogen atom neighbors or
4460 heavy atoms attached to atom
4461 H<n> = Number of implicit and explicit hydrogens for atom
4462 Ar = Aromatic annotation indicating whether atom is aromatic
4463 RA or RA<n> = Ring atom annotation indicating whether atom
4464 is a ring
4465 TR<n> = Total number of rings containing atom
4466 FC<+n/-n> = Formal charge assigned to atom
4467 MN<n> = Mass number indicating isotope other than most abundant isotope
4468 SM<n> = Spin multiplicity of atom. Possible values: 1 (singlet),
4469 2 (doublet) or 3 (triplet)
4470
4471 Then, atom specification corresponds to:
4472
4473 AS.X<n>.T<n>.BO<n>.LBO<n>.<SB><n>.TSB<n>.<DB><n>.<TB><n>.AB<n>.H<n>.Ar.
4474 RA<n>.TR<n>FC<+n/-n>.MN<n>.SM<n>
4475
4476 Except for AS which is a required atomic invariant in atom specification, all other atomic invariants are
4477 optional. For an atom specification to match an atom, the values of all specified atomic invariants must
4478 match. Exclamation in from of atomic invariant can be used to negate its effect during the match.
4479
4480 For I<FC> value matching, the following value operators are also supported:
4481
4482 o +* : Any positive value
4483 o -* : Any negative value
4484 o > ValidNumber or >= ValidNumber
4485 o < ValidNumber or <= ValidNumber
4486
4487 A comma delimited atom specification string is used to match any one of the specified atom specification.
4488
4489 Notes:
4490
4491 o During atom specification match to an atom, the first atomic invariant is always assumed to
4492 atom symbol.
4493
4494 Examples:
4495
4496 o ('N', 'N', 'N')
4497 o ('N.FC0', 'N.FC0', 'N,N.FC+1.H1')
4498 o ('N.H2', 'N.H2', 'N.H1')
4499 o ('C,N', '!N', '!H')
4500 o ('C,N', 'N.Ar', 'N.R5')
4501
4502 Let:
4503
4504 -|1|s|Single = Single bond
4505 =|2|d|Double = Double bond
4506 #|3|t|Triple = Triple bond
4507 :|1.5|a|Ar|Aromatic = Aromatic bond
4508
4509 @|RB|Ring = Ring bond
4510 ~|*|Any = Any bond
4511
4512 Then, bond specification corresponds to:
4513
4514 -.:
4515 =.@
4516 Double.Aromatic
4517
4518 For a bond specification to match bond between two atoms, the values of all specified bond symbols must
4519 match. Exclamation in from of bond symbol can be used to negate its effect during the match.
4520
4521 A comma delimited bond specification string is used to match any one of the specified atom specification.
4522
4523 Notes:
4524
4525 o During atom neighborhood match for central atom neighborhood atom and bond specifications,
4526 implicit or missing hydrogens are automatically checked for any matches to unmatched
4527 specifications.
4528
4529 Examples:
4530
4531
4532 Aromatic carbon in a 5 membered ring:
4533 $Atom->DoesAtomNeighborhoodMatch('C.Ar.RA5');
4534
4535 AcetylenicCarbon: $Atom->DoesAtomNeighborhoodMatch('C.T2.TB1'); or
4536 $Atom->DoesAtomNeighborhoodMatch('C.T2.TB1',
4537 ['*', '*'], ['#', '-']);
4538
4539 GuadiniumCarbon: $Atom->DoesAtomNeighborhoodMatch('C.X3.BO4',
4540 ['N.FC0', 'N.FC0', 'N.FC0,N.FC+1'],
4541 ['-', '-', '='],
4542 ['C,H', 'C,H', 'C,H']);
4543
4544 AmideCarbon: $Atom->DoesAtomNeighborhoodMatch('C.X3.BO4,C.X2.BO3',
4545 ['C,H', 'O', 'N'],
4546 ['-', '=', '-'],
4547 ['C,H', 'C', 'C,H,N,O,S,P,F,Cl,Br,I']);
4548
4549 CarboxylCarbon: $Atom->DoesAtomNeighborhoodMatch('C.X3.BO4,C.X2.BO3',
4550 ['C,H', 'O', 'O.X1.FC0'],
4551 ['-', '=', '-'],
4552 ['C,H', 'C', 'C']);
4553
4554 CarboxylateCarbon: $Atom->DoesAtomNeighborhoodMatch('C.X3.BO4,C.X2.BO3',
4555 ['C,H', 'O', 'O.X1.FC-1'],
4556 ['-', '=', '-'],
4557 ['C,H', 'C', 'C']);
4558
4559
4560 =item B<DeleteHydrogens>
4561
4562 $NumOfHydrogensDeleted = $Atom->AddHydrogens();
4563
4564 Delete hydrogens from an B<Atom> present in a B<Molecule> object and returns
4565 the number of deleted hydrogens.
4566
4567 =item B<GetAtomicInvariantValue>
4568
4569 $Value = $Atom->GetAtomicInvariantValue($AtomicInvariant);
4570
4571 Returns atomic invariant value for a specified I<AtomicInvariant>. The current release
4572 of MayaChemTools supports following abbreviations and descriptive names for
4573 I<AtomicInvarints>:
4574
4575 AS : Atom or element symbol
4576 X : NumOfNonHydrogenAtomNeighbors or NumOfHeavyAtomNeighbors
4577 T : TotalNumOfAtomNeighbors
4578 BO : SumOfBondOrdersToNonHydrogenAtoms or SumOfBondOrdersToHeavyAtoms
4579 LBO : LargestBondOrderToNonHydrogenAtoms or LargestBondOrderToHeavyAtoms
4580 SB : NumOfSingleBondsToNonHydrogenAtoms or NumOfSingleBondsToHeavyAtoms
4581 TSB : TotalNumOfSingleBonds
4582 DB : NumOfDoubleBondsToNonHydrogenAtoms or NumOfDoubleBondsToHeavyAtoms
4583 TB : NumOfTripleBondsToNonHydrogenAtoms or NumOfTripleBondsToHeavyAtoms
4584 AB : NumOfAromaticBondsToNonHydrogenAtoms or NumOfAromaticBondsToHeavyAtoms
4585 H : NumOfImplicitAndExplicitHydrogens
4586 Ar : Aromatic
4587 Str : Stereochemistry
4588 RA : RingAtom
4589 FC : FormalCharge
4590 AN : AtomicNumber
4591 AM : AtomicMass
4592 MN : MassNumber
4593 SM : SpinMultiplicity
4594
4595 =item B<GetAtomicWeight>
4596
4597 $Value = $Aom->GetAtomicWeight();
4598
4599 Returns atomic weight of an B<Atom> which corresponds to either explicity set I<AtomicWeight>
4600 atom property or atomic weight of the corresponding element in the periodic table available by
4601 B<PeriodicTable> module.
4602
4603 =item B<GetBondToAtom>
4604
4605 $Bond = $Atom->GetBondToAtom($OtherAtom);
4606
4607 Returns a B<Bond> object corresponding to bond between I<Atom> and I<OtherAtom> in
4608 a molecule.
4609
4610 =item B<GetBonds>
4611
4612 @Bonds = $Aoto->GetBonds();
4613
4614 Returns an array of B<Bond> objects corresponding to all bonds from I<Atom> to other
4615 bonded atoms in a molecule.
4616
4617 =item B<GetBondsToHeavyAtoms>
4618
4619 @Bonds = $Atom->GetBondsToHeavyAtoms();
4620
4621 Returns an array of B<Bond> objects corresponding to bonds from I<Atom> to other bonded
4622 non-hydrogen atoms in a molecule.
4623
4624 =item B<GetBondsToHydrogenAtoms>
4625
4626 @Bonds = $Atom->GetBondsToHydrogenAtoms();
4627
4628 Returns an array of B<Bond> objects corresponding to bonds from I<Atom> to any other
4629 hydrogen atom in a molecule.
4630
4631 =item B<GetBondsToNonHydrogenAtoms>
4632
4633 @Bonds = $Atom->GetBondsToNonHydrogenAtoms();
4634
4635 Returns an array of B<Bond> objects corresponding to bonds from I<Atom> to other bonded
4636 non-hydrogen atoms in a molecule.
4637
4638 =item B<GetExactMass>
4639
4640 $ExactMass = $Atom->GetExactMass();
4641
4642 Returns exact mass of an I<Atom> which correspond to one of these three values: explicity set
4643 I<ExactMass> property; mass of natural isotope for an explicty set value of I<MassNumber>; most
4644 abundant natural isotope mass for I<Atom> with valid atomic number value available by
4645 B<PerodicTable> module.
4646
4647 =item B<GetExplicitHydrogens>
4648
4649 $NumOfExplicitHydrogens = $Atom->GetExplicitHydrogens();
4650
4651 Returns number of hydrogens explicity bonded to an I<Atom> in a molecule.
4652
4653 =item B<GetFormalCharge>
4654
4655 $FormalCharge = $Atom->GetFormalCharge();
4656
4657 Returns formal charge of an I<Atom> in a molecule.
4658
4659 =item B<GetFreeRadicalElectrons>
4660
4661 $FreeRadicalElectrons = $Atom->GetFreeRadicalElectrons();
4662
4663 Returns number of free radical electrons corresponding to to one of these
4664 three values: I<FreeRadicalElectrons> property; I<SpinMultiplicity> property; value
4665 of 0.
4666
4667 For atoms with explicit assignment of I<SpinMultiplicity> atom property values,
4668
4669 Singlet - two unparied electrons corresponding to one spin state
4670 Doublet - free radical; an unpaired electron corresponding to two
4671 spin states
4672 Triplet - two unparied electrons corresponding to three spin states
4673 (divalent carbon atoms: carbenes)
4674
4675 B<FreeRadicalElectrons> are calculated as follows:
4676
4677 Doublet: 1 (one valence electron not available for bonding)
4678 Singlet: 2 (two valence electrons not available for bonding)
4679 Triplet: 2 (two valence electrons not available for bonding)
4680
4681 =item B<GetGroupNumber>
4682
4683 $GroupNumber = $Atom->GetGroupNumber();
4684
4685 Returns group number of an I<Atom> in a molecule with a valid atomic number.
4686
4687 =item B<GetHeavyAtomNeighbors>
4688
4689 $NumOfHeavyAtoms = $Atom->GetHeavyAtomNeighbors();
4690 @HeavyAtoms = $Atom->GetHeavyAtomNeighbors();
4691
4692 Return number of heavy atoms or an array of B<Atom> objects corresponding to heavy atoms
4693 bonded to an I<Atom> in a molecule.
4694
4695 =item B<GetHeavyAtomNeighborsAtomInformation>
4696
4697 ($NumOfAtomNeighbors, $AtomNeighborsRef,
4698 $NumOfAtomNeighborsType, $AtomNeighborsTypeMapRef) = $Atom->
4699 GetHeavyAtomNeighborsAtomInformation();
4700
4701 Returns atoms information for all non-hydrogen atoms attached to an I<Atom>
4702 in a molecule.
4703
4704 The following values are returned:
4705
4706 o Number of non-hydrogen atom neighbors
4707 o A reference to an array containing atom objects corresponding to
4708 non-hydrogen atom neighbors
4709 o Number of different types of non-hydrogen atom neighbors
4710 o A reference to a hash containing atom symbol as key with value
4711 corresponding to its count for non-hydrogen atom neighbors
4712
4713 =item B<GetHeavyAtomNeighborsBondformation>
4714
4715 ($NumOfBonds, $BondTypeCountMapRef,
4716 $AtomsBondTypesCountMapRef,
4717 $AtomsBondTypeAtomsMap) = $Atom->
4718 GetHeavyAtomNeighborsBondformation();
4719
4720 Returns bonds information for all non-hydrogen atoms attached to an I<Atom>
4721 in a molecule.
4722
4723 The following values are returned:
4724
4725 o Number of bonds to non-hydrogen atom neighbors
4726 o A reference to an array containing bond objects corresponding to
4727 non-hydrogen atom neighbors
4728 o A reference to a hash containing bond type as key with value
4729 corresponding to its count for non-hydrogen atom neighbors. Bond
4730 types are: Single, Double or Triple
4731 o A reference to a hash containing atom symbol as key pointing to bond
4732 type as second key with values corresponding to count of bond types for atom
4733 symbol for non-hydrogen atom neighbors
4734 o A reference to a hash containing atom symbol as key pointing to bond
4735 type as second key with values corresponding to atom objects array involved
4736 in corresponding bond type for atom symbol for non-hydrogen atom neighbors
4737
4738 =item B<GetHighestCommonValence>
4739
4740 $HighestCommonValence = $Atom->GetHighestCommonValence();
4741
4742 Returns highest common valence of an I<Atom> which corresponds to either explicity set
4743 I<HighestCommonValence> atom property or highest common valence of the corresponding
4744 element in the periodic table available by B<PerodicTable> module.
4745
4746 =item B<GetHydrogens>
4747
4748 $NumOfHydrogens = $Atom->GetHydrogens();
4749
4750 Returns total number of hydrogens for an I<Atom> in a molecule including both hydrogen atom
4751 neighbors and implicit hydrogens.
4752
4753 =item B<GetHydrogenAtomNeighbors>
4754
4755 $NumOfHydrogenAtomNeighbors = $Atom->GetHydrogenAtomNeighbors();
4756 @HydrogenAtomNeighbors = $Atom->GetHydrogenAtomNeighbors();
4757
4758 Return number of hydrogen atoms or an array of I<Atom> objects corresponding to hydrogen
4759 atoms bonded to an I<Atom> in a molecule.
4760
4761 =item B<GetImplicitHydrogens>
4762
4763 $NumOfImplicitHydrogens = $Atom->GetImplicitHydrogens();
4764
4765 Returns number of implicit hydrogens for an I<Atom> in a molecule. This value either
4766 corresponds to explicitly set I<ImplicitHydrogens> atom property or calculated as the
4767 difference between the value of potential total valence and sum of bond orders to
4768 both hydrogen and non-hydrogen atom neighbors.
4769
4770 =item B<GetPotentialTotalCommonValence>
4771
4772 $PotentialTotalValence = $Atom->GetPotentialTotalCommonValence();
4773
4774 Returns potential total common valence of an I<Atom> in a molecule corresponding
4775 to a specific valence model set for the molecule using its B<SetValenceModel> method
4776 or default internal valence model. It is used during the calculation of missing or
4777 implicit hydrogens.
4778
4779 The current release of MayaChemTools supports three valence models: I<MDLValenceModel,
4780 DaylightValenceModel, InternalValenceModel or MayaChemToolsValenceModel>.
4781
4782 For I<MDLValenceModel> and I<DaylightValenceModel>, the following data files, distributed
4783 with the package, are used to calculate potential total valence:
4784
4785 lib/data/MDLValenceModelData.csv
4786 lib/data/DaylightValenceModelData.csv
4787
4788 The calculation of potential total common valence for these two models is performed as
4789 follows: Calculate current effective total valence of the I<Atom> by adding up the bond
4790 order of its neighbors and number of free radical electrons; Find available common valence
4791 for the I<Atom>, corresponding to any specified formal charge, higher than the effective
4792 total valence, and return it as I<PotentialTotalValence>.
4793
4794 The calculation of potential total common valence For I<InternalValenceModel> or
4795 I<MayaChenToolsValenceModel> doesn't uses B<PeriodicTable> module to retrieve values
4796 for common valence, which in turn reads in PeriodicTableElements.csv file distributed with
4797 the package.
4798
4799 For elements with one one common valence, potential total common valence corresponds
4800 to:
4801
4802 CommonValence + FormalCharge - FreeRadicalElectrons
4803
4804 For elements with multiple common valences, each common valence is used to
4805 calculate total potential common valence as shown above, and the first total potential
4806 common valence greater than the sum of bond orders to all neighbors is selected as
4807 the final total common valence.
4808
4809 FormalCharge sign is reversed for electropositive elements with positive formal charge
4810 during common valence calculations. Electropositive elements, metals and transition elements,
4811 have usually plus formal charge and it leads to decrease in common valence; the negative
4812 formal charge should result in the decrease of common valence.
4813
4814 The sign of formal charge is adjusted as follows.
4815
4816 Group numbers > 14 - Group numbers 15 (N), 16 (O), 17 (F), 18 (He):
4817
4818 Formal charge sign is not adjusted. Positive and negative values result in the
4819 increase and decrease of valence.
4820
4821 Group 14 containing C, Si, Ge, Sn, Pb...:
4822
4823 Formal charge sign is reversed for positive values. Both positive and negative
4824 values result in the decrease of valence.
4825
4826 Group 13 containing B, Al, Ga, In, Tl...:
4827
4828 Formal charge sign is always reversed. Positive and negative values result in the
4829 decrease and increase of valence.
4830
4831 Groups 1 (H) through 12 (Zn)...:
4832
4833 Formal charge sign is reversed for positive values. Both positive and negative
4834 values result in the decrease of valence.
4835
4836 Lanthanides and actinides:
4837
4838 Formal charge sign is reversed for positive values. Both positive and negative
4839 values result in the decrease of valence.
4840
4841 =item B<GetLargestBondOrder>
4842
4843 $LargestBO =$Atom->GetLargestBondOrder();
4844
4845 Returns largest bond order for an I<Atom> among the bonds to other atoms in a molecule.
4846
4847 =item B<GetLargestBondOrderToHeavyAtoms>
4848
4849 $LargestBO =$Atom->GetLargestBondOrderToHeavyAtoms();
4850
4851 Returns largest bond order for an I<Atom> among the bonds to other heavy atoms in a molecule.
4852
4853 =item B<GetLargestBondOrderToNonHydrogenAtoms>
4854
4855 $LargestBO =$Atom->GetLargestBondOrderToNonHydrogenAtoms();
4856
4857 Returns largest bond order for an I<Atom> among the bonds to other non-hydrogen atoms
4858 in a molecule.
4859
4860 =item B<GetLargestRing>
4861
4862 @RingAtoms = $Atom->GetLargestRing();
4863
4864 Returns an array of ring I<Atom> objects corresponding to the largest ring containing I<Atom>
4865 in a molecule.
4866
4867 =item B<GetLowestCommonValence>
4868
4869 $LowestCommonValence = $Atom->GetLowestCommonValence();
4870
4871 Returns lowest common valence of an I<Atom> which corresponds to either explicity set
4872 I<LowestCommonValence> atom property or highest common valence of the corresponding
4873 element in the periodic table available by B<PerodicTable> module.
4874
4875 =item B<GetMassNumber>
4876
4877 $MassNumber = $Aom->GetMassNumber();
4878
4879 Returns atomic weight of an B<Atom> which corresponds to either explicity set I<MassNumber>
4880 atom property or mass number of the most abundant natural isotope of the corresponding element
4881 in the periodic table available by B<PeriodicTable> module.
4882
4883 =item B<GetMissingHydrogens>
4884
4885 $NumOfMissingHydrogens = $Atom->GetMissingHydrogens();
4886
4887 Returns number of missing hydrogens for an I<Atom> in a molecule. This value either
4888 corresponds to explicitly set I<ImplicitHydrogens> atom property or calculated as the
4889 difference between the value of potential total valence and sum of bond orders to
4890 both hydrogen and non-hydrogen atom neighbors.
4891
4892 =item B<GetNeighbors>
4893
4894 $NumOfNeighbors = $Atom->GetNeighbors();
4895 @Neighbors = $Atom->GetNeighbors();
4896
4897 Returns number of neighbor atoms or an array of I<Atom> objects corresponding to all
4898 atoms bonded to an I<Atom> in a molecule.
4899
4900 =item B<GetNeighborsUsingAtomSpecification>
4901
4902 @AtomNeighbors = $Atom->GetNeighborsUsingAtomSpecification($AtomSpec);
4903 $NumOfNeighbors = $Atom->GetNeighborsUsingAtomSpecification($AtomSpec);
4904
4905 @AtomNeighbors = $Atom->GetNeighborsUsingAtomSpecification($AtomSpec,
4906 @ExcludeNeighbors);
4907
4908 Returns number of neighbor atoms or an array of I<Atom> objects matching atom
4909 specification corresponding to atom neighbors of an I<Atom> in a molecule. Optionally,
4910 I<Atom> neighbors can be excluded from the neighbors list using I<ExcludeNeighbors>.
4911
4912 Notes:
4913
4914 o AtomSpecification correspond to any valid AtomicInvariant based atomic specifications
4915 as supported by DoesAtomNeighborhoodMatch method
4916 o Multiple atom specifications can be used in a string delimited by comma
4917
4918 =item B<GetNonHydrogenAtomNeighbors>
4919
4920 $NumOfNeighbors = $Atom->GetNonHydrogenAtomNeighbors();
4921 @Neighbors = $Atom->GetNonHydrogenAtomNeighbors();
4922
4923 Returns number of non-hydrogen atoms or an array of B<Atom> objects corresponding to non-hydrogen
4924 atoms bonded to an I<Atom> in a molecule.
4925
4926 =item B<GetNonHydrogenAtomNeighborsAtomInformation>
4927
4928 ($NumOfAtomNeighbors, $AtomNeighborsRef,
4929 $NumOfAtomNeighborsType, $AtomNeighborsTypeMapRef) = $Atom->
4930 GetNonHydrogenAtomNeighborsAtomInformation();
4931
4932 Returns atoms information for all non-hydrogen atoms attached to an I<Atom>
4933 in a molecule.
4934
4935 The following values are returned:
4936
4937 o Number of non-hydrogen atom neighbors
4938 o A reference to an array containing atom objects corresponding to
4939 non-hydrogen atom neighbors
4940 o Number of different types of non-hydrogen atom neighbors
4941 o A reference to a hash containing atom symbol as key with value
4942 corresponding to its count for non-hydrogen atom neighbors
4943
4944
4945 =item B<GetNonHydrogenAtomNeighborsBondInformation>
4946
4947 ($NumOfBonds, $BondTypeCountMapRef,
4948 $AtomsBondTypesCountMapRef,
4949 $AtomsBondTypeAtomsMap) = $Atom->
4950 GetNonHydrogenAtomNeighborsBondInformation();
4951
4952 Returns bonds information for all non-hydrogen atoms attached to an I<Atom>
4953 in a molecule.
4954
4955 The following values are returned:
4956
4957 o Number of bonds to non-hydrogen atom neighbors
4958 o A reference to an array containing bond objects corresponding to
4959 non-hydrogen atom neighbors
4960 o A reference to a hash containing bond type as key with value
4961 corresponding to its count for non-hydrogen atom neighbors. Bond
4962 types are: Single, Double or Triple
4963 o A reference to a hash containing atom symbol as key pointing to bond
4964 type as second key with values corresponding to count of bond types for atom
4965 symbol for non-hydrogen atom neighbors
4966 o A reference to a hash containing atom symbol as key pointing to bond
4967 type as second key with values corresponding to atom objects array involved
4968 in corresponding bond type for atom symbol for non-hydrogen atom neighbors
4969
4970 =item B<GetNonHydrogenNeighborOfHydrogenAtom>
4971
4972 $Atom = $Atom->GetNonHydrogenNeighborOfHydrogenAtom();
4973
4974 Returns non-hydrogen or heavy atom neighbor of a hydrogen atom in a molecule..
4975
4976 =item B<GetNumOfAromaticBondsToHeavyAtoms>
4977
4978 $NumOfBonds = $Atom->GetNumOfAromaticBondsToHeavyAtoms();
4979
4980 Returns number of aromatic bonds from an I<Atom> to other non-hydrogen or heavy atoms in
4981 a molecule.
4982
4983 =item B<GetNumOfAromaticBondsToNonHydrogenAtoms>
4984
4985 $NumOfBonds = $Atom->GetNumOfAromaticBondsToNonHydrogenAtoms();
4986
4987 Returns number of aromatic bonds from an I<Atom> to other non-hydrogen or heavy atoms in
4988 a molecule.
4989
4990 =item B<GetNumOfBonds>
4991
4992 $NumOfBonds = $Atom->GetNumOfBonds();
4993
4994 Returns number of bonds from an I<Atom> to other atoms in a molecule.
4995
4996 =item B<GetNumOfBondsAvailableForHeavyAtoms>
4997
4998 $NumOfBonds = $Atom->GetNumOfBondsAvailableForHeavyAtoms();
4999
5000 Get number of bonds available to form additional bonds with heavy atoms, excluding
5001 any implicit bonds to hydrogens set using I<ImplicitHydrogens> property.
5002
5003 It's different from number of implicit or missing hydrogens, both of which are equivalent.
5004
5005 For example, in a SMILES string, [nH] ring atom corresponds to an aromatic nitrogen.
5006 Although the hydrogen specified for n is treated internally as implicit hydrogen and shows
5007 up in missing hydrogen count, it's not available to participate in double bonds to additional
5008 heavy atoms.
5009
5010 =item B<GetNumOfBondsAvailableForNonHydrogenAtoms>
5011
5012 $NumOfBonds = $Atom->GetNumOfBondsAvailableForNonHydrogenAtoms();
5013
5014 Get number of bonds available to form additional bonds with heavy atoms, excluding
5015 any implicit bonds to hydrogens set using ImplicitHydrogens property.
5016
5017 =item B<GetNumOfBondsToHeavyAtoms>
5018
5019 $NumOfBondsToHeavyAtoms = $Atom->GetNumOfBondsToHeavyAtoms();
5020
5021 Returns number of bonds from an I<Atom> to other heavy atoms in a molecule.
5022
5023 =item B<GetNumOfBondsToHydrogenAtoms>
5024
5025 $NumOfBonds = $Atom->GetNumOfBondsToHydrogenAtoms();
5026
5027 Returns number of bonds from an I<Atom> to other hydrogen atoms in a molecule.
5028
5029 =item B<GetNumOfBondsToNonHydrogenAtoms>
5030
5031 $NumOfBonds = $Atom->GetNumOfBondsToNonHydrogenAtoms();
5032
5033 Returns number of bonds from an I<Atom> to other non-hydrogen atoms in a molecule.
5034
5035 =item B<GetNumOfBondTypesToHeavyAtoms>
5036
5037 ($NumOfSingleBonds, $NumOfDoubleBonds,
5038 $NumOfTripleBonds, $NumOfAromaticBonds) = $Atom->
5039 GetNumOfBondTypesToHeavyAtoms($CountAromaticBonds);
5040
5041 Get number of single, double, triple, and aromatic bonds from an I<Atom> to all other
5042 non-hydrogen atoms in a molecule.
5043
5044 Value of I<CountAtomaticBonds> parameter controls whether number of aromatic
5045 bonds is returned; default is not to count aromatic bonds. During counting of
5046 aromatic bonds, the bond marked aromatic is not included in the count
5047 of other bond types.
5048
5049 =item B<GetNumOfBondTypesToNonHydrogenAtoms>
5050
5051 ($NumOfSingleBonds, $NumOfDoubleBonds,
5052 $NumOfTripleBonds, $NumOfAromaticBonds) = $Atom->
5053 GetNumOfBondTypesToNonHydrogenAtoms($CountAromaticBonds);
5054
5055 Get number of single, double, triple, and aromatic bonds from an I<Atom> to all other
5056 non-hydrogen atoms in a molecule.
5057
5058 Value of I<CountAtomaticBonds> parameter controls whether number of aromatic
5059 bonds is returned; default is not to count aromatic bonds. During counting of
5060 aromatic bonds, the bond marked aromatic is not included in the count
5061 of other bond types.
5062
5063 =item B<GetNumOfDoubleBondsToHeavyAtoms>
5064
5065 $NumOfDoubleBonds = $Atom->GetNumOfDoubleBondsToHeavyAtoms();
5066
5067 Returns number of double bonds from an I<Atom> to other heavy atoms or non-hydrogen
5068 atoms in a molecule.
5069
5070 =item B<GetNumOfDoubleBondsToNonHydrogenAtoms>
5071
5072 $NumOfDoubleBonds =$Atom->GetNumOfDoubleBondsToNonHydrogenAtoms();
5073
5074 Returns number of double bonds from an I<Atom> to other heavy atoms or non-hydrogen
5075 atoms in a molecule.
5076
5077 =item B<GetNumOfHeavyAtomNeighbors>
5078
5079 $NumOfNeighbors = $Atom->GetNumOfHeavyAtomNeighbors();
5080
5081 Returns number heavy atom neighbors for an I<Atom> in a molecule.
5082
5083 =item B<GetNumOfHydrogenAtomNeighbors>
5084
5085 $NumOfNeighbors = $Atom->GetNumOfHydrogenAtomNeighbors();
5086
5087 Returns number hydrogens atom neighbors for an I<Atom> in a molecule.
5088
5089 =item B<GetNumOfMissingHydrogens>
5090
5091 $NumOfMissingHydrogens = $Atom->GetNumOfMissingHydrogens();
5092
5093 Returns number of implicit hydrogens for an I<Atom> in a molecule. This value either
5094 corresponds to explicitly set I<ImplicitHydrogens> atom property or calculated as the
5095 difference between the value of potential total valence and sum of bond orders to
5096 both hydrogen and non-hydrogen atom neighbors.
5097
5098 =item B<GetNumOfExplicitHydrogens>
5099
5100 $NumOfExplicitHydrogens = $Atom->GetNumOfExplicitHydrogens();
5101
5102 Returns number hydrogens atom neighbors for an I<Atom> in a molecule.
5103
5104 =item B<GetNumOfHydrogens>
5105
5106 $NumOfHydrogens = $Atom->GetNumOfHydrogens();
5107
5108 Returns total number of hydrogens for an I<Atom> in a molecule including both hydrogen atom
5109 neighbors and implicit hydrogens.
5110
5111 =item B<GetNumOfImplicitHydrogens>
5112
5113 $NumOfImplicitHydrogens = $Atom->GetNumOfImplicitHydrogens();
5114
5115 Returns number of implicit hydrogens for an I<Atom> in a molecule. This value either
5116 corresponds to explicitly set I<ImplicitHydrogens> atom property or calculated as the
5117 difference between the value of potential total valence and sum of bond orders to
5118 both hydrogen and non-hydrogen atom neighbors.
5119
5120 =item B<GetNumOfNeighbors>
5121
5122 $NumOfNeighbors = $Atom->GetNumOfNeighbors();
5123
5124 Returns number atom neighbors for an I<Atom> in a molecule.
5125
5126 =item B<GetNumOfNonHydrogenAtomNeighbors>
5127
5128 $NumNeighbors = $This->GetNumOfNonHydrogenAtomNeighbors();
5129
5130 Returns number non-hydrogens atom neighbors for an I<Atom> in a molecule.
5131
5132 =item B<GetNumOfRings>
5133
5134 $NumOfRings = $Atom->GetNumOfRings();
5135
5136 Returns number of rings containing I<Atom> in a molecule.
5137
5138 =item B<GetNumOfRingsWithEvenSize>
5139
5140 $NumOfRings = $Atom->GetNumOfRingsWithEvenSize();
5141
5142 Returns number of rings with even size containing I<Atom> in a molecule.
5143
5144 =item B<GetNumOfRingsWithOddSize>
5145
5146 $NumOfRings = $Atom->GetNumOfRingsWithOddSize();
5147
5148 Returns number of rings with odd size containing I<Atom> in a molecule.
5149
5150 =item B<GetNumOfRingsWithSize>
5151
5152 $NumOfRings = $Atom->GetNumOfRingsWithSize($RingSize);
5153
5154 Returns number of rings with specific I<RingSize> containing I<Atom> in a molecule.
5155
5156 =item B<GetNumOfRingsWithSizeGreaterThan>
5157
5158 $NumOfRings = $Atom->GetNumOfRingsWithSizeGreaterThan($RingSize);
5159
5160 Returns number of rings with size greater than specific I<RingSize> containing I<Atom>
5161 in a molecule.
5162
5163 =item B<GetNumOfRingsWithSizeLessThan>
5164
5165 $NumOfRings = $Atom->GetNumOfRingsWithSizeLessThan($RingSize);
5166
5167 Returns number of rings with size less than specific I<RingSize> containing I<Atom> in a molecule.
5168
5169 =item B<GetNumOfSigmaAndPiBondsToHeavyAtoms>
5170
5171 ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->
5172 GetNumOfSigmaAndPiBondsToHeavyAtoms();
5173
5174 Get number of sigma and pi bonds from an I<Atom> to all other non-hydrogen
5175 atoms in a molecule.
5176
5177 Sigma and pi bonds are counted using the following methodology: a single bond
5178 correspond to one sigma bond; a double bond contributes one to sigma bond count
5179 and one to pi bond count; a triple bond contributes one to sigma bond count and
5180 two to pi bond count.
5181
5182
5183 =item B<GetNumOfSigmaAndPiBondsToNonHydrogenAtoms>
5184
5185 ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->
5186 GetNumOfSigmaAndPiBondsToNonHydrogenAtoms();
5187
5188 Get number of sigma and pi bonds from an I<Atom> to all other non-hydrogen
5189 atoms in a molecule.
5190
5191 Sigma and pi bonds are counted using the following methodology: a single bond
5192 correspond to one sigma bond; a double bond contributes one to sigma bond count
5193 and one to pi bond count; a triple bond contributes one to sigma bond count and
5194 two to pi bond count.
5195
5196 =item B<GetNumOfSingleBondsToNonHydrogenAtoms>
5197
5198 $NumOfSingleBonds =$Atom->GetNumOfSingleBondsToNonHydrogenAtoms();
5199
5200 Returns number of single bonds from an I<Atom> to other heavy atoms or non-hydrogen
5201 atoms in a molecule.
5202
5203 =item B<GetNumOfSingleBondsToHeavyAtoms>
5204
5205 $NumOfSingleBonds = $Atom->GetNumOfSingleBondsToHeavyAtoms();
5206
5207 Returns number of single bonds from an I<Atom> to other heavy atoms or non-hydrogen
5208 atoms in a molecule.
5209
5210 =item B<GetNumOfTripleBondsToNonHydrogenAtoms>
5211
5212 $NumOfTripleBonds =$Atom->GetNumOfTripleBondsToNonHydrogenAtoms();
5213
5214 Returns number of triple bonds from an I<Atom> to other heavy atoms or non-hydrogen
5215 atoms in a molecule.
5216
5217 =item B<GetNumOfTripleBondsToHeavyAtoms>
5218
5219 $NumOfTripleBonds = $Atom->GetNumOfTripleBondsToHeavyAtoms();
5220
5221 Returns number of triple bonds from an I<Atom> to other heavy atoms or non-hydrogen
5222 atoms in a molecule.
5223
5224 =item B<GetPeriodNumber>
5225
5226 $PeriodNumber = $Atom->GetPeriodNumber();
5227
5228 Returns periodic table period number for an I<Atom> in a molecule with a valid atomic number .
5229
5230 =item B<GetRings>
5231
5232 @Rings = $Aotm->GetRings();
5233
5234 Returns an array of references to arrays containing ring atoms corressponding to all rings containing
5235 I<Atom> in a molecule.
5236
5237 =item B<GetRingsWithEvenSize>
5238
5239 @Rings = $Aotm->GetRingsWithEvenSize();
5240
5241 Returns an array of references to arrays containing ring atoms corressponding to all rings with even size
5242 containing I<Atom> in a molecule.
5243
5244 =item B<GetRingsWithOddSize>
5245
5246 @Rings = $Aotm->GetRingsWithOddSize();
5247
5248 Returns an array of references to arrays containing ring atoms corressponding to all rings with odd size
5249 containing I<Atom> in a molecule.
5250
5251 =item B<GetRingsWithSize>
5252
5253 @Rings = $Aotm->GetRingsWithSize($RingSize);
5254
5255 Returns an array of references to arrays containing ring atoms corressponding to all rings with specific
5256 I<RingSize >containing I<Atom> in a molecule.
5257
5258 =item B<GetRingsWithSizeGreaterThan>
5259
5260 @Rings = $Aotm->GetRingsWithSizeGreaterThan($RingSize);
5261
5262 Returns an array of references to arrays containing ring atoms corressponding to all rings with size
5263 greater than specific I<RingSize >containing I<Atom> in a molecule.
5264
5265 =item B<GetRingsWithSizeLessThan>
5266
5267 @Rings = $Aotm->GetRingsWithSizeLessThan($RingSize);
5268
5269 Returns an array of references to arrays containing ring atoms corressponding to all rings with size
5270 less than specific I<RingSize >containing I<Atom> in a molecule.
5271
5272 =item B<GetSizeOfLargestRing>
5273
5274 $Size = $Atom->GetSizeOfLargestRing();
5275
5276 Returns size of the largest ring containing I<Atom> in a molecule.
5277
5278 =item B<GetSizeOfSmallestRing>
5279
5280 $Size = $Atom->GetSizeOfSmallestRing();
5281
5282 Returns size of the smallest ring containing I<Atom> in a molecule.
5283
5284 =item B<GetSmallestRing>
5285
5286 @RingAtoms = $Atom->GetSmallestRing();
5287
5288 Returns an array of ring I<Atom> objects corresponding to the largest ring containing I<Atom>
5289 in a molecule.
5290
5291 =item B<GetSpinMultiplicity>
5292
5293 $SpinMultiplicity = $Atom->GetSpinMultiplicity();
5294
5295 Returns spin multiplicity of an I<Atom> corresponding to one of these three
5296 values: explicitly set B<SpinMultiplicity> property value; calculated from
5297 B<FreeRadicalElectrons> property; value of 0.
5298
5299 The B<SpinMultiplicity> is calculate from I<FreeRadicalElectrons> property as
5300 follows:
5301
5302 FreeRadicalElectrons: 1; SpinMultiplicity: 2
5303 FreeRadicalElectrons: 2; SpinMultiplicity: 1
5304 FreeRadicalElectrons: other; SpinMultiplicity: 0
5305
5306 =item B<GetSumOfBondOrders>
5307
5308 $SumBondOrders = $Atom->GetSumOfBondOrders();
5309
5310 Returns sum of bond orders corresponding to all atoms bonded to an I<Atom> in a molecule.
5311
5312 =item B<GetSumOfBondOrdersToHeavyAtoms>
5313
5314 $SumBondOrders = $Atom->GetSumOfBondOrdersToHeavyAtoms();
5315
5316 Returns sum of bond orders corresponding to all heavy atoms bonded to an I<Atom> in a molecule.
5317
5318 =item B<GetSumOfBondOrdersToHydrogenAtoms>
5319
5320 $SumBondOrders = $Atom->GetSumOfBondOrdersToHydrogenAtoms();
5321
5322 Returns sum of bond orders corresponding to all hydrogen atoms bonded to an I<Atom> in a molecule.
5323
5324 =item B<GetSumOfBondOrdersToNonHydrogenAtoms>
5325
5326 $SumBondOrders = $Atom->GetSumOfBondOrdersToNonHydrogenAtoms();
5327
5328 Returns sum of bond orders corresponding to all non-hydrogen atoms bonded to an I<Atom>
5329 in a molecule.
5330
5331 =item B<GetValence>
5332
5333 $Valence = $Atom->GetValence();
5334
5335 Returns valence of an I<Atom> in a molecule. Valence corresponds to number of electrons used
5336 by an atom in bonding:
5337
5338 Valence = ValenceElectrons - ValenceFreeElectrons = BondingElectrons
5339
5340 Single, double and triple bonds with bond orders of 1, 2, and 3 correspond to
5341 contribution of 1, 2, and 3 bonding electrons. So:
5342
5343 Valence = SumOfBondOrders + NumOfMissingHydrogens + FormalCharge
5344
5345 where positive and negative values of FormalCharge increase and decrease the number of bonding
5346 electrons, respectively.
5347
5348 The current release of MayaChemTools supports the following three valence models, which
5349 are used during calculation of implicit hydrogens: MDLValenceModel, DaylightValenceModel,
5350 InternalValenceModel or MayaChemToolsValenceModel.
5351
5352 Notes:
5353
5354 . Missing hydrogens are included in the valence.
5355 . For neutral molecules, valence and sum of bond orders are equal.
5356 . For molecules containing only single bonds, SumOfBondOrders and
5357 NumOfBonds are equal.
5358 . Free radical electrons lead to the decrease in valence. For atoms with
5359 explicit assignment of SpinMultiplicity property values corresponding to
5360 Singlet (two unparied electrons corresponding to one spin state), Doublet
5361 (free radical; an unpaired electron corresponding to two spin states),
5362 and Triplet (two unparied electrons corresponding to three spin states;
5363 divalent carbon atoms (carbenes)), FreeRadicalElectrons are calculated as follows:
5364
5365 SpinMultiplicity: Doublet(2); FreeRadicalElectrons: 1 (one valence
5366 electron not available for bonding)
5367 SpinMultiplicity: Singlet(1)/Triplet(3); FreeRadicalElectrons: 2 (two
5368 valence electrons not available for bonding)
5369
5370 =item B<GetValenceElectrons>
5371
5372 $ValenceElectrons = $Atom->GetValenceElectrons();
5373
5374 Returns valence electrons for an B<Atom> which corresponds to either explicity set I<ValenceElectrons>
5375 atom property or valence electrons for the corresponding element in the periodic table available by
5376 B<PeriodicTable> module.
5377
5378 =item B<GetValenceFreeElectrons>
5379
5380 $ValenceFreeElectrons = $Atom->GetValenceFreeElectrons();
5381 $ValenceFreeElectrons = $Atom->GetValenceFreeElectrons(
5382 $ExcludeFreeRadicalElectrons);
5383
5384 Returns valence frees electrons for an B<Atom> in a molecule. It corresponds to:
5385
5386 ValenceElectrons - Valence
5387 or
5388 ValenceElectrons - NumOfMissingHydrogens - SumOfBondOrders - FormalCharge
5389
5390 Free radical electrons are included in the valence free electrons count by default.
5391
5392 Examples:
5393
5394 NH3: ValenceFreeElectrons = 5 - 3 = 5 - 3 - 0 - 0 = 2
5395 NH2: ValenceFreeElectrons = 5 - 3 = 5 - 2 - 1 - 0 = 2
5396 NH4+; ValenceFreeElectrons = 5 - 5 = 5 - 4 - 0 - 1 = 0
5397 NH3+; ValenceFreeElectrons = 5 - 5 = 5 - 3 - 1 - 1 = 0
5398 C(=O)O- : ValenceFreeElectrons on O- = 6 - 0 = 6 - 1 - 0 - (-1) = 6
5399 C(=O)O- : ValenceFreeElectrons on =O = 6 - 2 = 6 - 2 - 0 - 0 = 4
5400
5401 =item B<GetX>
5402
5403 $X = $Atom->GetX();
5404
5405 Returns value of X-coordinate for an I<Atom>.
5406
5407 =item B<GetXYZ>
5408
5409 @XYZ = $Atom->GetXYZ();
5410 $XYZRef = $Atom->GetXYZ();
5411
5412 Returns an array or a reference to an array containing values for I<Atom> coordinates.
5413
5414 =item B<GetXYZVector>
5415
5416 $XYZVector = $Atom->GetXYZVector();
5417
5418 Returns a I<Vector> object containing values for I<Atom> coordinates
5419
5420 =item B<GetY>
5421
5422 $Y = $Atom->GetY();
5423
5424 Returns value of Y-coordinate for an I<Atom>.
5425
5426 =item B<GetZ>
5427
5428 $Z = $Atom->GetZ();
5429
5430 Returns value of Z-coordinate for an I<Atom>.
5431
5432 =item B<IsAmideCarbon>
5433
5434 $Status = $Atom->IsAmideCarbon();
5435
5436 Returns 1 or 0 based on whether it's amide carbon I<Atom>.
5437
5438 An amide group is defineds as:
5439
5440 R-C(=O)-N(-R')-R''
5441
5442 where:
5443
5444 o R = Hydrogen or groups of atoms attached through carbon
5445 o R' = Hydrogens or groups of atoms attached through carbon or
5446 hetro atoms
5447 o R'' = Hydrogens or groups of atoms attached through carbon or
5448 hetro atoms
5449
5450 =item B<IsAmideNitrogen>
5451
5452 $Status = $Atom->IsAmideNitrogen();
5453
5454 Returns 1 or 0 based on whether it's amide nitrogen I<Atom>.
5455
5456 =item B<IsAromatic>
5457
5458 $Status = $Atom->IsAromatic();
5459
5460 Returns 1 or 0 based on whether it's an aromatic I<Atom>.
5461
5462 =item B<IsArsenic>
5463
5464 $Status = $Atom->IsArsenic();
5465
5466 Returns 1 or 0 based on whether it's an arsenic I<Atom>.
5467
5468 =item B<IsBondedToAtom>
5469
5470 $Status = $Atom->IsBondedToAtom($OtherAtom);
5471
5472 Returns 1 or 0 based on whether I<Atom> is bonded to I<OtherAtom>.
5473
5474 =item B<IsBromine>
5475
5476 $Status = $Atom->IsBromine();
5477
5478 Returns 1 or 0 based on whether it's a bromine I<Atom>.
5479
5480 =item B<IsCarbon>
5481
5482 $Status = $Atom->IsCarbon();
5483
5484 Returns 1 or 0 based on whether it's a carbon I<Atom>.
5485
5486 =item B<IsCarboxylCarbon>
5487
5488 $Status = $Atom->IsCarboxylCarbon();
5489
5490 Returns 1 or 0 based on whether it's a carboxyl carbon atom in carboxyl group:
5491 R-C(=O)-OH.
5492
5493 =item B<IsCarboxylOxygen>
5494
5495 $Status = $Atom->IsCarboxylOxygen();
5496
5497 Returns 1 or 0 based on whether it's a carboxyl oxygen atom in carboxyl group:
5498 R-C(=O)-OH.
5499
5500 =item B<IsCarboxylateCarbon>
5501
5502 $Status = $Atom->IsCarboxylateCarbon();
5503
5504 Returns 1 or 0 based on whether it's a carboxylate carbon atom in carboxyl group:
5505 R-C(=O)-O-.
5506
5507 =item B<IsCarboxylateOxygen>
5508
5509 $Status = $Atom->IsCarboxylateOxygen();
5510
5511 Returns 1 or 0 based on whether it's a carboxylate oxygen atom in carboxyl group:
5512 R-C(=O)-O-.
5513
5514 =item B<IsChlorine>
5515
5516 $Status = $Atom->IsChlorine();
5517
5518 Returns 1 or 0 based on whether it's a chlorine I<Atom>.
5519
5520 =item B<IsFluorine>
5521
5522 $Status = $Atom->IsFluorine();
5523
5524 Returns 1 or 0 based on whether it's a fluorine I<Atom>.
5525
5526 =item B<IsFunctionalClassType>
5527
5528 $Status =$Atom->IsFunctionalClassType($Type);
5529
5530 Returns 1 or 0 based on whether it's a specified functional class I<Type>.
5531
5532 The current release of MayaChemTools supports following abbreviations and descriptive
5533 names for I<FunctionalClassType>:
5534
5535 HBD: HydrogenBondDonor
5536 HBA: HydrogenBondAcceptor
5537 PI : PositivelyIonizable
5538 NI : NegativelyIonizable
5539 Ar : Aromatic
5540 Hal : Halogen
5541 H : Hydrophobic
5542 RA : RingAtom
5543 CA : ChainAtom
5544
5545 The following definitions are used to determine functional class types: [ Ref 60-61, Ref 65-66 ]:
5546
5547 HydrogenBondDonor: NH, NH2, OH
5548 HydrogenBondAcceptor: N[!H], O
5549 PositivelyIonizable: +, NH2
5550 NegativelyIonizable: -, C(=O)OH, S(=O)OH, P(=O)OH
5551
5552 =item B<IsGuadiniumCarbon>
5553
5554 $Status = $Atom->IsGuadiniumCarbon();
5555
5556 Returns 1 or 0 based on whether it's a guadinium carbon in guadinium group by
5557 checking its neighbors for a nitrogen in guadinium group.
5558
5559 =item B<IsGuadiniumNitrogen>
5560
5561 $Status = $Atom->IsGuadiniumNitrogen();
5562
5563 Returns 1 or 0 based on whether it's a guadinium nitrogen in guadinium group.
5564
5565 A guadinium group is defined as:
5566
5567 R2N-C(=NR)-(NR2) or R2N-C(=NR2+)-(NR2)
5568
5569 where:
5570
5571 o R = Hydrogens or group of atoms attached through carbon
5572 o Only one of the three nitrogens has a double bond to carbon
5573 and has optional formal charge allowing it to be neutral or charged state
5574
5575 =item B<IsHBondAcceptor>
5576
5577 $Status =$Atom->IsHBondAcceptor();
5578 $Status =$Atom->IsHBondAcceptor($HydrogenBondsType);
5579
5580 Returns 1 or 0 based on whether it's a hydrogen bond acceptor I<Atom>.
5581
5582 =item B<IsHBondDonor>
5583
5584 $Status =$Atom->IsHBondDonor();
5585 $Status =$Atom->IsHBondDonor($HydrogenBondsType);
5586
5587 Returns 1 or 0 based on whether it's a hydrogen bond donor I<Atom>.
5588
5589 =item B<IsHydrogenBondAcceptor>
5590
5591 $Status =$Atom->IsHydrogenBondAcceptor();
5592 $Status =$Atom->IsHydrogenBondAcceptor($HydrogenBondsType);
5593
5594 Returns 1 or 0 based on whether it's a hydrogen bond acceptor I<Atom>.
5595
5596 =item B<IsHydrogenBondDonor>
5597
5598 $Status =$Atom->IsHydrogenBondDonor();
5599 $Status =$Atom->IsHydrogenBondDonor($HydrogenBondsType);
5600
5601 Returns 1 or 0 based on whether it's a hydrogen bond donor I<Atom>.
5602
5603 The current release of MayaChemTools supports identification of two types of hydrogen bond
5604 donor and acceptor atoms with these names:
5605
5606 HBondsType1 or HydrogenBondsType1
5607 HBondsType2 or HydrogenBondsType2
5608
5609 The names of these hydrogen bond types are rather arbitrary. However, their definitions have
5610 specific meaning and are as follows:
5611
5612 HydrogenBondsType1 [ Ref 60-61, Ref 65-66 ]:
5613
5614 Donor: NH, NH2, OH - Any N and O with available H
5615 Acceptor: N[!H], O - Any N without available H and any O
5616
5617 HydrogenBondsType2 [ Ref 91 ]:
5618
5619 Donor: NH, NH2, OH - N and O with available H
5620 Acceptor: N, O - And N and O
5621
5622 By default, I<HydrogenBondsType1> is used to calculate number hydrogen bond donor
5623 and acceptor atoms. I<HydrogenBondsType2> corresponds to B<RuleOf5> definition
5624 of hydrogen bond donors and acceptors.
5625
5626 =item B<IsHalogen>
5627
5628 $Status =$Atom->IsHalogen();
5629
5630 Returns 1 or 0 based on whether it's a halogen I<Atom>.
5631
5632 =item B<IsHeteroAtom>
5633
5634 $Status = $Atom->IsHeteroAtom();
5635
5636 Returns 0 or 1 based on whether it's a hetro I<Atom>. Following atoms are considered hetro atoms:
5637 B<N, O, F, P, S, Cl, Br, I>.
5638
5639 =item B<IsHydrogen>
5640
5641 $Status = $Atom->IsHydrogen();
5642
5643 Returns 1 or 0 based on whether it's a hydrogen I<Atom>.
5644
5645 =item B<IsHydrophobic>
5646
5647 $Status =$Atom->IsHydrophobic();
5648
5649 Returns 1 or 0 based on whether it's a hydrophobic I<Atom>.
5650
5651 =item B<IsInRing>
5652
5653 $Status = $Atom->IsInRing();
5654
5655 Returns 1 or 0 based on whether I<Atom> is present in a ring.
5656
5657 =item B<IsInRingOfSize>
5658
5659 $Status = $Atom->IsInRingOfSize($Size);
5660
5661 Returns 1 or 0 based on whether I<Atom> is present in a ring of specific I<Size>.
5662
5663 =item B<IsIodine>
5664
5665 $Status = $Atom->IsIodine();
5666
5667 Returns 1 or 0 based on whether it's an iodine I<Atom>.
5668
5669 =item B<IsIsotope>
5670
5671 $Status =$Atom->IsIsotope();
5672
5673 Returns 1 or 0 based on whether it's an isotope I<Atom>.
5674
5675 =item B<IsLipophilic>
5676
5677 $Status =$Atom->IsLipophilic();
5678
5679 Returns 1 or 0 based on whether it's a lipophilic I<Atom>.
5680
5681 =item B<IsMetallic>
5682
5683 $Status = $Atom->IsMetallic();
5684
5685 Returns 1 or 0 based on whether it's a metallic I<Atom>.
5686
5687 =item B<IsNegativelyIonizable>
5688
5689 $Status =$Atom->IsNegativelyIonizable();
5690
5691 Returns 1 or 0 based on whether it's a negatively ionizable atom I<Atom>.
5692
5693 =item B<IsNitrogen>
5694
5695 $Status = $Atom->IsNitrogen();
5696
5697 Returns 1 or 0 based on whether it's a nitrogen I<Atom>.
5698
5699 =item B<IsNonCarbonOrHydrogen>
5700
5701 $Status =$Atom->IsNonCarbonOrHydrogen();
5702
5703 Returns 1 or 0 based on whether it's not a carbon or hydrogen I<Atom>.
5704
5705 =item B<IsNotInRing>
5706
5707 $Status = $Atom->IsNotInRing();
5708
5709 Returns 1 or 0 based on whether I<Atom> is not present in a ring.
5710
5711 =item B<IsOnlyInOneRing>
5712
5713 $Status = $Atom->IsOnlyInOneRing();
5714
5715 Returns 1 or 0 based on whether I<Atom> is only present in one ring.
5716
5717 =item B<IsOxygen>
5718
5719 $Status = $Atom->IsOxygen();
5720
5721 Returns 0 or 1 based on whether it's an oxygen I<Atom>.
5722
5723 =item B<IsPhosphorus>
5724
5725 $Status = $Atom->IsPhosphorus();
5726
5727 Returns 0 or 1 based on whether it's a phosphorus I<Atom>.
5728
5729 =item B<IsPhosphateOxygen>
5730
5731 $Status = $Atom->IsPhosphateOxygen();
5732
5733 Returns 1 or 0 based on whether it's a phosphate oxygen in phosphate group.
5734
5735 A phosphate group is defined as:
5736
5737 AO-(O=)P(-OA)-OA
5738
5739 Where:
5740
5741 A - Any group of atoms including hydrogens
5742
5743 =item B<IsPhosphatePhosphorus>
5744
5745 $Status = $Atom->IsPhosphatePhosphorus();
5746
5747 Returns 1 or 0 based on whether it's a phosphate phosphorus in phosphate group.
5748
5749 =item B<IsPolarAtom>
5750
5751 $Status = $Atom->IsPolarAtom();
5752
5753 Returns 0 or 1 based on whether it's a polar I<Atom>. Following atoms are considered polar atoms:
5754 B<N, O, P, S>.
5755
5756 =item B<IsPolarHydrogen>
5757
5758 $Status = $Atom->IsPolarHydrogen();
5759
5760 Returns 0 or 1 based on whether it's a hydrogen I<Atom> bonded to a polar atom.
5761
5762 =item B<IsPositivelyIonizable>
5763
5764 $Status =$Atom->IsPositivelyIonizable();
5765
5766 Returns 1 or 0 based on whether it's a positively ionizable I<Atom>.
5767
5768 =item B<IsSaturated>
5769
5770 $Status = $Atom->IsSaturated();
5771
5772 Returns 1 or 0 based on whether it's a saturated I<Atom>. An atom attached
5773 to other atoms with only single bonds is considered a saturated atom.
5774
5775 =item B<IsSelenium>
5776
5777 $Status = $Atom->IsSelenium();
5778
5779 Returns 0 or 1 based on whether it's a selenium I<Atom>.
5780
5781 =item B<IsStereoCenter>
5782
5783 $Status = $Atom->IsStereoCenter();
5784
5785 Returns 0 or 1 based on whether it's marked as a stero center I<Atom> by explicit setting
5786 of I<StereoCenter> atom propert to value of I<1>.
5787
5788 =item B<IsSilicon>
5789
5790 $Status = $Atom->IsSilicon();
5791
5792 Returns 0 or 1 based on whether it's a silicon I<Atom>.
5793
5794 =item B<IsSulfur>
5795
5796 $Status = $Atom->IsSulfur();
5797
5798 Returns 0 or 1 based on whether it's a sulfur I<Atom>.
5799
5800 =item B<IsSulphur>
5801
5802 $Status = $Atom->IsSulphur();
5803
5804 Returns 0 or 1 based on whether it's a sulfur I<Atom>.
5805
5806 =item B<IsTellurium>
5807
5808 $Status = $Atom->IsTellurium();
5809
5810 Returns 0 or 1 based on whether it's a tellurium I<Atom>.
5811
5812 =item B<IsTerminal>
5813
5814 $Status = $Atom->IsTerminal();
5815
5816 Returns 0 or 1 based on whether it's a terminal I<Atom> attached to no
5817 more than one non-hydrogen atom.
5818
5819 =item B<IsUnsaturated>
5820
5821 $Status = $Atom->IsUnsaturated();
5822
5823 Returns 1 or 0 based on whether it's as unsaturated I<Atom>. An atom attached
5824 to other atoms with at least one non-single bond is considered an unsaturated atom.
5825
5826 =item B<IsTopologicalPharmacophoreType>
5827
5828 $Status =$Atom->IsTopologicalPharmacophoreType();
5829
5830 Returns 1 or 0 based on whether it's any of the supportyed topological pharmacophore
5831 I<Atom> type. See I<IsFunctionalClassType> for a list of supported types.
5832
5833 =item B<SetAtomSymbol>
5834
5835 $Atom->SetAtomSymbol($AtomicSymbol);
5836
5837 Sets atom symbol for I<Atom> and returns I<Atom> object. The appropriate atomic number is also
5838 set automatically.
5839
5840 =item B<SetAtomicNumber>
5841
5842 $Atom->SetAtomicNumber($AtomicNumber);
5843
5844 Sets atomic number for I<Atom> and returns I<Atom> object. The appropriate atom symbol is also
5845 set automatically.
5846
5847 =item B<SetMassNumber>
5848
5849 $Atom->SetMassNumber($MassNumber);
5850
5851 Sets mass number for I<Atom> and returns I<Atom> object.
5852
5853 =item B<SetStereoCenter>
5854
5855 $Atom->SetStereoCenter($StereoCenter);
5856
5857 Sets stereo center for I<Atom> and returns I<Atom> object.
5858
5859 =item B<SetStereochemistry>
5860
5861 $Atom->SetStereochemistry($Stereochemistry);
5862
5863 Sets stereo chemistry for I<Atom> and returns I<Atom> object.
5864
5865 =item B<SetX>
5866
5867 $Atom->SetX($Value);
5868
5869 Sets X-coordinate value for I<Atom> and returns I<Atom> object.
5870
5871 =item B<SetXYZ>
5872
5873 $Atom->SetXYZ(@XYZValues);
5874 $Atom->SetXYZ($XYZValuesRef);
5875 $Atom->SetXYZ($XYZVector);
5876
5877 Sets I<Atom> coordinates using an array, reference to an array or a I<Vector> object and
5878 returns I<Atom> object.
5879
5880 =item B<SetY>
5881
5882 $Atom->SetY($Value);
5883
5884 Sets Y-coordinate value for I<Atom> and returns I<Atom> object.
5885
5886 =item B<SetZ>
5887
5888 $Atom->SetZ($Value);
5889
5890 Sets Z-coordinate value for I<Atom> and returns I<Atom> object.
5891
5892 =item B<StringifyAtom>
5893
5894 $AtomString = $Atom->StringifyAtom();
5895
5896 Returns a string containing information about I<Atom> object.
5897
5898 =back
5899
5900 =head1 AUTHOR
5901
5902 Manish Sud <msud@san.rr.com>
5903
5904 =head1 SEE ALSO
5905
5906 Bond.pm, Molecule.pm, MoleculeFileIO.pm
5907
5908 =head1 COPYRIGHT
5909
5910 Copyright (C) 2015 Manish Sud. All rights reserved.
5911
5912 This file is part of MayaChemTools.
5913
5914 MayaChemTools is free software; you can redistribute it and/or modify it under
5915 the terms of the GNU Lesser General Public License as published by the Free
5916 Software Foundation; either version 3 of the License, or (at your option)
5917 any later version.
5918
5919 =cut