1 package AtomTypes::UFFAtomTypes; 2 # 3 # File: UFFAtomTypes.pm 4 # Author: Manish Sud <msud@san.rr.com> 5 # 6 # Copyright (C) 2024 Manish Sud. All rights reserved. 7 # 8 # This file is part of MayaChemTools. 9 # 10 # MayaChemTools is free software; you can redistribute it and/or modify it under 11 # the terms of the GNU Lesser General Public License as published by the Free 12 # Software Foundation; either version 3 of the License, or (at your option) any 13 # later version. 14 # 15 # MayaChemTools is distributed in the hope that it will be useful, but without 16 # any warranty; without even the implied warranty of merchantability of fitness 17 # for a particular purpose. See the GNU Lesser General Public License for more 18 # details. 19 # 20 # You should have received a copy of the GNU Lesser General Public License 21 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or 22 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330, 23 # Boston, MA, 02111-1307, USA. 24 # 25 26 use strict; 27 use Carp; 28 use Exporter; 29 use Scalar::Util (); 30 use AtomTypes::AtomTypes; 31 use Molecule; 32 33 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); 34 35 @ISA = qw(AtomTypes::AtomTypes Exporter); 36 @EXPORT = qw(GetUFFAtomTypesData GetAllPossibleUFFAtomTypes GetAllPossibleUFFNonHydrogenAtomTypes); 37 @EXPORT_OK = qw(); 38 39 %EXPORT_TAGS = (all => [@EXPORT, @EXPORT_OK]); 40 41 # Setup class variables... 42 my($ClassName, %UFFAtomTypesDataMap); 43 _InitializeClass(); 44 45 # Overload Perl functions... 46 use overload '""' => 'StringifyUFFAtomTypes'; 47 48 # Class constructor... 49 sub new { 50 my($Class, %NamesAndValues) = @_; 51 52 # Initialize object... 53 my $This = $Class->SUPER::new(); 54 bless $This, ref($Class) || $Class; 55 $This->_InitializeUFFAtomTypes(); 56 57 $This->_InitializeUFFAtomTypesProperties(%NamesAndValues); 58 59 return $This; 60 } 61 62 # Initialize class ... 63 sub _InitializeClass { 64 #Class name... 65 $ClassName = __PACKAGE__; 66 67 # Initialize the data hash. It'll be loaded on demand later... 68 %UFFAtomTypesDataMap = (); 69 } 70 71 # Initialize object data... 72 # 73 sub _InitializeUFFAtomTypes { 74 my($This) = @_; 75 76 # Type of AtomTypes... 77 $This->{Type} = 'UFF'; 78 79 # By default, UFF atom types are also assigned to hydrogens... 80 $This->{IgnoreHydrogens} = 0; 81 82 return $This; 83 } 84 85 # Initialize object properties... 86 # 87 sub _InitializeUFFAtomTypesProperties { 88 my($This, %NamesAndValues) = @_; 89 90 my($Name, $Value, $MethodName); 91 while (($Name, $Value) = each %NamesAndValues) { 92 $MethodName = "Set${Name}"; 93 $This->$MethodName($Value); 94 } 95 96 # Make sure molecule object was specified... 97 if (!exists $NamesAndValues{Molecule}) { 98 croak "Error: ${ClassName}->New: Object can't be instantiated without specifying molecule..."; 99 } 100 101 return $This; 102 } 103 104 # Get UFF atom types and associated data loaded from UFF data file as 105 # a reference to hash with the following hash data format: 106 # 107 # @{$UFFAtomTypesDataMap{AtomTypes}} - Array of all possible atom types for all atoms 108 # @{$UFFAtomTypesDataMap{NonHydrogenAtomTypes}} - Array of all possible atom types for non-hydrogen atoms 109 # @{$UFFAtomTypesDataMap->{ColLabels}} - Array of column labels 110 # %{$UFFAtomTypesDataMap->{DataCol<Num>}} - Hash keys pair: <DataCol<Num>, AtomType> 111 # 112 # This functionality can be either invoked as a class function or an 113 # object method. 114 # 115 sub GetUFFAtomTypesData { 116 117 # Make sure data is loaded... 118 _CheckAndLoadUFFAtomTypesData(); 119 120 return \%UFFAtomTypesDataMap; 121 } 122 123 # Get all possible UFF atom types corresponding to hydrogen and non-hydrogen 124 # atoms as an array reference... 125 # 126 # This functionality can be either invoked as a class function or an 127 # object method. 128 # 129 sub GetAllPossibleUFFAtomTypes { 130 return _GetAllPossibleUFFAtomTypes(); 131 } 132 133 # Get all possible UFF atom types corresponding to non-hydrogen atoms 134 # as an array reference... 135 # 136 # This functionality can be either invoked as a class function or an 137 # object method. 138 # 139 sub GetAllPossibleUFFNonHydrogenAtomTypes { 140 my($NonHydrogensOnly); 141 142 $NonHydrogensOnly = 1; 143 return _GetAllPossibleUFFAtomTypes($NonHydrogensOnly); 144 } 145 146 # Get all possible UFF atom types as an array reference... 147 # 148 sub _GetAllPossibleUFFAtomTypes { 149 my($NonHydrogensOnly) = @_; 150 my($UFFAtomTypesDataRef); 151 152 $NonHydrogensOnly = defined $NonHydrogensOnly ? $NonHydrogensOnly : 0; 153 154 $UFFAtomTypesDataRef = GetUFFAtomTypesData(); 155 156 return $NonHydrogensOnly ? \@{$UFFAtomTypesDataRef->{NonHydrogenAtomTypes}}: \@{$UFFAtomTypesDataRef->{AtomTypes}}; 157 } 158 # Assign UFF [ Ref 81-82 ] atom types to all atoms... 159 # 160 # Notes: 161 # . Some listed atom types - O_3_z, 162 # are not assigned to any atom 163 # o 126 UFF atom types are listed for elements with atomic number upto 103 164 # o AtomTypes::AtomTypes::UFFAtomTypes.pm module is used to assign UFF atom types 165 # o Units: 166 # o ValenceBondRadius and NonBondRadius: Angstroms 167 # o ValenceAngle: Degrees 168 # o NonBondEnergy and SP3TorsionalBarrier: kcal/mol 169 # o Five-character mnemonic label for UFF atom types 170 # o First two characters correspond to chemical symbol with an underscore as second 171 # character for elements with one character symbol 172 # o Third character describes hybridization or geometry: 1 - linear; 2 - trigonal; R - resonant; 173 # 3 = tetrahedral; 4 - square planar; 5 - trigonal bipyramidal; 6 - octahedral 174 # o Fourth and fifth characters are used as indicators of alternate parameters: formal oxidation 175 # state, bridging hydrogens and so on. 176 # 177 # 178 sub AssignAtomTypes { 179 my($This) = @_; 180 my($Atom, $AtomType); 181 182 ATOM: for $Atom ($This->GetMolecule()->GetAtoms()) { 183 if ($This->{IgnoreHydrogens} && $Atom->IsHydrogen()) { 184 next ATOM; 185 } 186 $AtomType = $This->_GetAtomType($Atom); 187 $This->SetAtomType($Atom, $AtomType); 188 } 189 return $This; 190 } 191 192 # Get UFF atom type for atom... 193 # 194 sub _GetAtomType { 195 my($This, $Atom) = @_; 196 my($AtomType); 197 198 $AtomType = ''; 199 200 ATOM: { 201 if ($Atom->IsCarbon()) { 202 $AtomType = $This->_GetAtomTypeForCarbon($Atom); 203 last ATOM; 204 } 205 if ($Atom->IsNitrogen()) { 206 $AtomType = $This->_GetAtomTypeForNitrogen($Atom); 207 last ATOM; 208 } 209 if ($Atom->IsOxygen()) { 210 $AtomType = $This->_GetAtomTypeForOxygen($Atom); 211 last ATOM; 212 } 213 if ($Atom->IsPhosphorus()) { 214 $AtomType = $This->_GetAtomTypeForPhosphorus($Atom); 215 last ATOM; 216 } 217 if ($Atom->IsSulfur()) { 218 $AtomType = $This->_GetAtomTypeForSulfur($Atom); 219 last ATOM; 220 } 221 if ($Atom->IsHydrogen()) { 222 $AtomType = $This->_GetAtomTypeForHydrogen($Atom); 223 last ATOM; 224 } 225 $AtomType = $This->_GetAtomTypeForOtherAtoms($Atom); 226 } 227 228 return $AtomType; 229 } 230 231 # Get UFF atom type for Carbon atom... 232 # 233 sub _GetAtomTypeForCarbon { 234 my($This, $Atom) = @_; 235 my($AtomType, $NumOfSigmaBonds, $NumOfPiBonds); 236 237 $AtomType = 'None'; 238 239 ($NumOfSigmaBonds, $NumOfPiBonds) = ('0') x 2; 240 241 ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms(); 242 $NumOfSigmaBonds += $Atom->GetAtomicInvariantValue('H'); 243 244 ATOMTYPE: { 245 if ($Atom->IsAromatic()) { 246 $AtomType = 'C_R'; 247 last ATOMTYPE; 248 } 249 250 # Only single bonds... 251 if ($NumOfPiBonds == 0) { 252 $AtomType = 'C_3'; 253 last ATOMTYPE; 254 } 255 256 # One double bond... 257 if ($NumOfPiBonds == 1) { 258 $AtomType = 'C_2'; 259 last ATOMTYPE; 260 } 261 262 # One triple bond or two double bonds... 263 if ($NumOfPiBonds == 2) { 264 $AtomType = 'C_1'; 265 last ATOMTYPE; 266 } 267 268 $AtomType = 'None'; 269 carp "Warning: ${ClassName}->_GetAtomTypeForCarbon: UFF atom types for Carbon cann't be assigned..."; 270 } 271 272 return $AtomType; 273 } 274 275 # Get UFF atom type for Nitrogen atom... 276 # 277 sub _GetAtomTypeForNitrogen { 278 my($This, $Atom) = @_; 279 my($AtomType, $NumOfSigmaBonds, $NumOfPiBonds); 280 281 $AtomType = 'None'; 282 283 ($NumOfSigmaBonds, $NumOfPiBonds) = ('0') x 2; 284 285 ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms(); 286 $NumOfSigmaBonds += $Atom->GetAtomicInvariantValue('H'); 287 288 ATOMTYPE: { 289 if ($Atom->IsAromatic()) { 290 $AtomType = 'N_R'; 291 last ATOMTYPE; 292 } 293 294 # Only single bonds... 295 if ($NumOfPiBonds == 0) { 296 $AtomType = 'N_3'; 297 last ATOMTYPE; 298 } 299 300 # One double bond... 301 if ($NumOfPiBonds == 1) { 302 $AtomType = 'N_2'; 303 last ATOMTYPE; 304 } 305 306 # One triple bond or two double bonds... 307 if ($NumOfPiBonds == 2) { 308 $AtomType = 'N_1'; 309 last ATOMTYPE; 310 } 311 $AtomType = 'None'; 312 carp "Warning: ${ClassName}->_GetAtomTypeForNitrogen: UFF atom types for Nitrogen cann't be assigned..."; 313 } 314 315 return $AtomType; 316 } 317 318 # Get UFF atom type for Oxygen atom... 319 # 320 sub _GetAtomTypeForOxygen { 321 my($This, $Atom) = @_; 322 my($AtomType, $NumOfSigmaBonds, $NumOfPiBonds); 323 324 $AtomType = 'None'; 325 326 ($NumOfSigmaBonds, $NumOfPiBonds) = ('0') x 2; 327 328 ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms(); 329 $NumOfSigmaBonds += $Atom->GetAtomicInvariantValue('H'); 330 331 ATOMTYPE: { 332 if ($Atom->IsAromatic()) { 333 $AtomType = 'O_R'; 334 last ATOMTYPE; 335 } 336 337 # Only single bonds... 338 if ($NumOfPiBonds == 0) { 339 $AtomType = 'O_3'; 340 last ATOMTYPE; 341 } 342 343 # One double bond... 344 if ($NumOfPiBonds == 1) { 345 $AtomType = 'O_2'; 346 last ATOMTYPE; 347 } 348 349 # One triple bond or two double bonds... 350 if ($NumOfPiBonds == 2) { 351 $AtomType = 'O_1'; 352 last ATOMTYPE; 353 } 354 355 $AtomType = 'None'; 356 carp "Warning: ${ClassName}->_GetAtomTypeForOxygen: UFF atom types for Oxygen cann't be assigned..."; 357 } 358 359 return $AtomType; 360 } 361 362 # Get UFF atom type for Phosphorus atom... 363 # 364 sub _GetAtomTypeForPhosphorus { 365 my($This, $Atom) = @_; 366 my($AtomType, $NumOfSigmaBonds, $NumOfPiBonds); 367 368 $AtomType = 'None'; 369 370 ($NumOfSigmaBonds, $NumOfPiBonds) = ('0') x 2; 371 372 ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms(); 373 $NumOfSigmaBonds += $Atom->GetAtomicInvariantValue('H'); 374 375 ATOMTYPE: { 376 # Is it a four-coordinated Phosphorus for describing organometallic coordinated phosphines? 377 if ($This->_IsFourCoordinatedOrganometallicPhosphorus($Atom)) { 378 $AtomType = 'P_3+q'; 379 last ATOMTYPE; 380 } 381 382 # -P(-)- 383 if ($NumOfSigmaBonds == 3 && $NumOfPiBonds == 0) { 384 $AtomType = 'P_3+3'; 385 last ATOMTYPE; 386 } 387 388 # =P(-)(-)- 389 if ($NumOfSigmaBonds == 4 && $NumOfPiBonds == 1) { 390 $AtomType = 'P_3+5'; 391 last ATOMTYPE; 392 } 393 394 $AtomType = 'None'; 395 carp "Warning: ${ClassName}->_GetAtomTypeForPhosphorus: UFF atom types for Phosphorus cann't be assigned..."; 396 } 397 398 return $AtomType; 399 } 400 401 # Get UFF atom type for Sulfur atom... 402 # 403 sub _GetAtomTypeForSulfur { 404 my($This, $Atom) = @_; 405 my($AtomType, $NumOfSigmaBonds, $NumOfPiBonds); 406 407 $AtomType = 'None'; 408 409 ($NumOfSigmaBonds, $NumOfPiBonds) = ('0') x 2; 410 411 ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms(); 412 $NumOfSigmaBonds += $Atom->GetAtomicInvariantValue('H'); 413 414 ATOMTYPE: { 415 if ($Atom->IsAromatic()) { 416 $AtomType = 'S_R'; 417 last ATOMTYPE; 418 } 419 420 # -S- 421 if ($NumOfSigmaBonds == 2 && $NumOfPiBonds == 0) { 422 $AtomType = 'S_3+2'; 423 last ATOMTYPE; 424 } 425 426 # -S(=)- 427 if ($NumOfSigmaBonds == 3 && $NumOfPiBonds == 1) { 428 $AtomType = 'S_3+4'; 429 last ATOMTYPE; 430 } 431 432 # -S(=)(=)- 433 if ($NumOfSigmaBonds == 4 && $NumOfPiBonds == 2) { 434 $AtomType = 'S_3+6'; 435 last ATOMTYPE; 436 } 437 438 # S= 439 if ($NumOfSigmaBonds == 1 && $NumOfPiBonds == 1) { 440 $AtomType = 'S_2'; 441 last ATOMTYPE; 442 } 443 444 $AtomType = 'None'; 445 carp "Warning: ${ClassName}->_GetAtomTypeForSulfur: UFF atom types for Sulfur cann't be assigned..."; 446 } 447 return $AtomType; 448 } 449 450 # Get UFF atom type for Hydrogen atom... 451 # 452 sub _GetAtomTypeForHydrogen { 453 my($This, $Atom) = @_; 454 my($AtomType); 455 456 if ($Atom->GetNumOfHeavyAtomNeighbors() > 1) { 457 # Bridging hydrogen as in B2H6 458 $AtomType = 'H___b'; 459 } 460 else { 461 $AtomType = 'H_'; 462 } 463 464 return $AtomType; 465 } 466 467 # Get UFF atom type for atoms other than Carbon, Nitrogen, Oxygen, Phosporus, 468 # Sulfur and Hydrogen... 469 # 470 sub _GetAtomTypeForOtherAtoms { 471 my($This, $Atom) = @_; 472 my($AtomType, $AtomicNumber, $AtomSymbol, $GroupNumber, $MethodName); 473 474 $AtomType = 'None'; 475 476 $AtomicNumber = $Atom->GetAtomicNumber(); 477 $AtomSymbol = $Atom->GetAtomSymbol(); 478 $GroupNumber = $Atom->GetGroupNumber(); 479 480 ATOMTYPE: { 481 # Get atom types for atoms in a valid periodic table group number... 482 if (defined($GroupNumber) && $GroupNumber) { 483 $MethodName = "_GetAtomTypeForOtherAtomsInGroupNumber${GroupNumber}"; 484 $AtomType = $This->$MethodName($Atom); 485 last ATOMTYPE; 486 } 487 488 # Get atom types for Lanthanidies... 489 if ($AtomicNumber >= 57 && $AtomicNumber <= 71) { 490 $AtomType = $This->_GetAtomTypeForOtherAtomsInLanthanoidGroup($Atom); 491 last ATOMTYPE; 492 } 493 494 # Get atom types for Actinides... 495 if ($AtomicNumber >= 89 && $AtomicNumber <= 103) { 496 $AtomType = $This->_GetAtomTypeForOtherAtomsInActinoidGroup($Atom); 497 last ATOMTYPE; 498 } 499 500 $AtomType = 'None'; 501 carp "Warning: ${ClassName}->_GetAtomTypeForOtherAtoms: UFF atom types for atom, $AtomSymbol, with atomic number, $AtomicNumber, cann't be assigned..."; 502 } 503 504 return $AtomType; 505 } 506 507 # Get UFF atom type for atoms in periodic table group number 1... 508 # 509 # Group number 1 contains: H, Li, Na, K, Rb, Cs, Fr 510 # 511 # And corresponding UFF atom types are: Li, Na, K_, Rb, Cs, Fr 512 # 513 # Notes: 514 # . This method doesn't assign UFF atom type for H. 515 # 516 sub _GetAtomTypeForOtherAtomsInGroupNumber1 { 517 my($This, $Atom) = @_; 518 my($AtomType, $AtomSymbol); 519 520 $AtomSymbol = $Atom->GetAtomSymbol(); 521 $AtomType = (length($AtomSymbol) == 1) ? "${AtomSymbol}_" : $AtomSymbol; 522 523 return $AtomType; 524 } 525 526 # Get UFF atom type for atoms in periodic table group number 2... 527 # 528 # Group number 2 contains: Be, Mg, Ca, Sr, Ba, Ra 529 # 530 # And corresponding UFF atom types are: Be3+2, Mg3+2, Ca6+2, Sr6+2, Ba6+2, Ra6+2 531 # 532 # Notes: 533 # . Although the number of valence electrons is two, the tetrahedral and octahedral 534 # geometry is attributed to coordination bonds from other atoms. 535 # 536 sub _GetAtomTypeForOtherAtomsInGroupNumber2 { 537 my($This, $Atom) = @_; 538 my($AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, $FormalCharge, $MethodName); 539 540 $AtomType = 'None'; 541 $MethodName = '_GetAtomTypeForOtherAtomsInGroupNumber2'; 542 543 $AtomSymbol = $Atom->GetAtomSymbol(); 544 ($NumOfNeighbors, $FormalOxidationState, $FormalCharge) = $This->_GetAtomEnvironmentInfoForUFFAtomTypes($Atom); 545 546 ATOMSYMBOL: { 547 if ($AtomSymbol =~ /^(Be|Mg)$/) { 548 $AtomType = "${AtomSymbol}3+2"; 549 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'tetrahedral', 4, 2); 550 last ATOMSYMBOL; 551 } 552 553 if ($AtomSymbol =~ /^(Ca|Sr|Ba|Ra)$/) { 554 $AtomType = "${AtomSymbol}6+2"; 555 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'octahedral', 6, 2); 556 last ATOMSYMBOL; 557 } 558 $AtomType = 'None'; 559 } 560 561 return $AtomType; 562 } 563 564 # Get UFF atom type for atoms in periodic table group number 3... 565 # 566 # Group number 3 contains: Sc, Y, Lu, Lr 567 # 568 # And corresponding UFF atom types are: Sc3+3, Y_3+3, Lu6+3, Lr6+3 569 # 570 sub _GetAtomTypeForOtherAtomsInGroupNumber3 { 571 my($This, $Atom) = @_; 572 my($AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, $FormalCharge, $MethodName); 573 574 $AtomType = 'None'; 575 $MethodName = '_GetAtomTypeForOtherAtomsInGroupNumber3'; 576 577 ($NumOfNeighbors, $FormalOxidationState, $FormalCharge) = $This->_GetAtomEnvironmentInfoForUFFAtomTypes($Atom); 578 579 $AtomSymbol = $Atom->GetAtomSymbol(); 580 581 ATOMSYMBOL: { 582 if ($AtomSymbol =~ /^(Sc|Y)$/) { 583 $AtomType = (length($AtomSymbol) == 1) ? "${AtomSymbol}_3+3" : "${AtomSymbol}3+3"; 584 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'tetrahedral', 4, 3); 585 last ATOMSYMBOL; 586 } 587 588 if ($AtomSymbol =~ /^(Lu|Lr)$/) { 589 $AtomType = "${AtomSymbol}6+3"; 590 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'octahedral', 6, 3); 591 last ATOMSYMBOL; 592 } 593 594 $AtomType = 'None'; 595 } 596 597 return $AtomType; 598 } 599 600 # Get UFF atom type for atoms in periodic table group number 4... 601 # 602 # Group number 4 contains: Ti, Zr, Hf, Rf 603 # 604 # And corresponding UFF atom types are: Ti3+4, Ti3+6, Zr3+4, Hf3+4 605 # 606 # Notes: 607 # . No UFF atom type for Rf 608 # 609 sub _GetAtomTypeForOtherAtomsInGroupNumber4 { 610 my($This, $Atom) = @_; 611 my($AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, $FormalCharge, $MethodName); 612 613 $AtomType = 'None'; 614 $MethodName = '_GetAtomTypeForOtherAtomsInGroupNumber4'; 615 616 $AtomSymbol = $Atom->GetAtomSymbol(); 617 ($NumOfNeighbors, $FormalOxidationState, $FormalCharge) = $This->_GetAtomEnvironmentInfoForUFFAtomTypes($Atom); 618 619 ATOMSYMBOL: { 620 if ($AtomSymbol =~ /^Ti$/) { 621 TI: { 622 if ($NumOfNeighbors == 4 && $FormalOxidationState == 4) { 623 $AtomType = "Ti3+4"; 624 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'tetrahedral', 4, 4); 625 last TI; 626 } 627 628 if ($NumOfNeighbors == 4 && $FormalOxidationState == 6) { 629 $AtomType = "Ti3+6"; 630 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'tetrahedral', 4, 6); 631 last TI; 632 } 633 634 # Assign default value... 635 $AtomType = "Ti3+6"; 636 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'tetrahedral', 4, 6); 637 } 638 last ATOMSYMBOL; 639 } 640 641 if ($AtomSymbol =~ /^(Zr|Hf)$/) { 642 $AtomType = "${AtomSymbol}3+4"; 643 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'tetrahedral', 4, 4); 644 last ATOMSYMBOL; 645 } 646 647 $AtomType = 'None'; 648 } 649 650 return $AtomType; 651 } 652 653 # Get UFF atom type for atoms in periodic table group number 5... 654 # 655 # Group number 5 contains: V, Nb, Ta, Db 656 # 657 # And corresponding UFF atom types are: V_3+5, Nb3+5, Ta3+5 658 # 659 # Notes: 660 # . No UFF atom type for Db 661 # 662 sub _GetAtomTypeForOtherAtomsInGroupNumber5 { 663 my($This, $Atom) = @_; 664 my($AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, $FormalCharge, $MethodName); 665 666 $AtomType = 'None'; 667 $MethodName = '_GetAtomTypeForOtherAtomsInGroupNumber5'; 668 669 $AtomSymbol = $Atom->GetAtomSymbol(); 670 ($NumOfNeighbors, $FormalOxidationState, $FormalCharge) = $This->_GetAtomEnvironmentInfoForUFFAtomTypes($Atom); 671 672 ATOMSYMBOL: { 673 if ($AtomSymbol =~ /^(V|Nb|Ta)$/) { 674 $AtomType = (length($AtomSymbol) == 1) ? "${AtomSymbol}_3+5" : "${AtomSymbol}3+5"; 675 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'tetrahedral', 4, 5); 676 last ATOMSYMBOL; 677 } 678 679 $AtomType = 'None'; 680 } 681 682 return $AtomType; 683 } 684 685 # Get UFF atom type for atoms in periodic table group number 6... 686 # 687 # Group number 6 contains: Cr, Mo, W, Sg 688 # 689 # And corresponding UFF atom types are: Cr6+3, Mo6+6, Mo3+6, W_6+6, W_3+4, W_3+6 690 # 691 # Notes: 692 # . No UFF atom type for Sg 693 # 694 sub _GetAtomTypeForOtherAtomsInGroupNumber6 { 695 my($This, $Atom) = @_; 696 my($AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, $FormalCharge, $MethodName); 697 698 $AtomType = 'None'; 699 $MethodName = '_GetAtomTypeForOtherAtomsInGroupNumber6'; 700 701 $AtomSymbol = $Atom->GetAtomSymbol(); 702 ($NumOfNeighbors, $FormalOxidationState, $FormalCharge) = $This->_GetAtomEnvironmentInfoForUFFAtomTypes($Atom); 703 704 ATOMSYMBOL: { 705 if ($AtomSymbol =~ /^Cr$/) { 706 $AtomType = "Cr6+3"; 707 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'octahedral', 6, 3); 708 last ATOMSYMBOL; 709 } 710 711 if ($AtomSymbol =~ /^Mo$/) { 712 MO: { 713 if ($NumOfNeighbors == 6 && $FormalOxidationState == 6) { 714 $AtomType = "Mo6+6"; 715 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'octahedral', 6, 6); 716 last MO; 717 } 718 719 if ($NumOfNeighbors == 4 && $FormalOxidationState == 6) { 720 $AtomType = "Mo3+6"; 721 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'tetrahedral', 4, 6); 722 last MO; 723 } 724 725 # Assign default value... 726 $AtomType = "Mo6+6"; 727 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'octahedral', 6, 6); 728 } 729 last ATOMSYMBOL; 730 } 731 732 if ($AtomSymbol =~ /^W$/) { 733 W: { 734 if ($NumOfNeighbors == 4 && $FormalOxidationState == 4) { 735 $AtomType = "W_3+4"; 736 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'tetrahedral', 4, 4); 737 last W; 738 } 739 740 if ($NumOfNeighbors == 4 && $FormalOxidationState == 6) { 741 $AtomType = "W_3+6"; 742 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'tetrahedral', 4, 6); 743 last W; 744 } 745 746 if ($NumOfNeighbors == 6 && $FormalOxidationState == 6) { 747 $AtomType = "W_6+6"; 748 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'octahedral', 6, 6); 749 last W; 750 } 751 752 # Assign default value... 753 $AtomType = "W_6+6"; 754 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'octahedral', 6, 6); 755 } 756 last ATOMSYMBOL; 757 } 758 759 $AtomType = 'None'; 760 } 761 762 return $AtomType; 763 } 764 765 # Get UFF atom type for atoms in periodic table group number 7... 766 # 767 # Group number 7 contains: Mn, Tc, Re, Bh 768 # 769 # And corresponding UFF atom types are: Mn6+2, Tc6+5, Re6+5, Re3+7 770 # 771 # Notes: 772 # . No UFF atom type for Bh 773 # 774 sub _GetAtomTypeForOtherAtomsInGroupNumber7 { 775 my($This, $Atom) = @_; 776 my($AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, $FormalCharge, $MethodName); 777 778 $AtomType = 'None'; 779 $MethodName = '_GetAtomTypeForOtherAtomsInGroupNumber7'; 780 781 $AtomSymbol = $Atom->GetAtomSymbol(); 782 ($NumOfNeighbors, $FormalOxidationState, $FormalCharge) = $This->_GetAtomEnvironmentInfoForUFFAtomTypes($Atom); 783 784 ATOMSYMBOL: { 785 if ($AtomSymbol =~ /^Mn$/) { 786 $AtomType = "Mn6+2"; 787 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'octahedral', 6, 2); 788 last ATOMSYMBOL; 789 } 790 791 if ($AtomSymbol =~ /^Tc$/) { 792 $AtomType = "Tc6+5"; 793 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'octahedral', 6, 6); 794 last ATOMSYMBOL; 795 } 796 797 if ($AtomSymbol =~ /^Re$/) { 798 RE: { 799 if ($NumOfNeighbors == 6) { 800 $AtomType = "Re6+5"; 801 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'octahedral', 6, 6); 802 last RE; 803 } 804 805 if ($NumOfNeighbors == 4 && $FormalOxidationState == 7) { 806 $AtomType = "Re3+7"; 807 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'tetrahedral', 4, 7); 808 last RE; 809 } 810 811 # Assign default value... 812 $AtomType = "Re6+5"; 813 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'octahedral', 6, 6); 814 } 815 last ATOMSYMBOL; 816 } 817 818 $AtomType = 'None'; 819 } 820 821 return $AtomType; 822 } 823 824 # Get UFF atom type for atoms in periodic table group number 8... 825 # 826 # Group number 8 contains: Fe, Ru, Os, Hs 827 # 828 # And corresponding UFF atom types are: Fe6+2, Ru6+2, Ru6+3, Os6+6 829 # 830 # Notes: 831 # . No UFF atom type for Hs 832 # 833 sub _GetAtomTypeForOtherAtomsInGroupNumber8 { 834 my($This, $Atom) = @_; 835 my($AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, $FormalCharge, $MethodName); 836 837 $AtomType = 'None'; 838 $MethodName = '_GetAtomTypeForOtherAtomsInGroupNumber8'; 839 840 $AtomSymbol = $Atom->GetAtomSymbol(); 841 ($NumOfNeighbors, $FormalOxidationState, $FormalCharge) = $This->_GetAtomEnvironmentInfoForUFFAtomTypes($Atom); 842 843 ATOMSYMBOL: { 844 if ($AtomSymbol =~ /^Fe$/) { 845 $AtomType = "Fe6+2"; 846 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'octahedral', 6, 2); 847 last ATOMSYMBOL; 848 } 849 850 if ($AtomSymbol =~ /^Ru$/) { 851 RU: { 852 if ($NumOfNeighbors == 6 && $FormalCharge == 2) { 853 $AtomType = "Ru6+2"; 854 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'octahedral', 6, 2); 855 last RU; 856 } 857 858 if ($NumOfNeighbors == 6 && $FormalCharge == 3) { 859 $AtomType = "Ru6+3"; 860 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'octahedral', 6, 3); 861 last RU; 862 } 863 864 # Assign default value... 865 $AtomType = "Ru6+3"; 866 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'octahedral', 6, 2); 867 } 868 last ATOMSYMBOL; 869 } 870 871 if ($AtomSymbol =~ /^Os$/) { 872 $AtomType = "Os6+6"; 873 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'octahedral', 6, 6); 874 last ATOMSYMBOL; 875 } 876 877 $AtomType = 'None'; 878 } 879 880 return $AtomType; 881 } 882 883 # Get UFF atom type for atoms in periodic table group number 9... 884 # 885 # Group number 9 contains: Co, Rh, Ir, Mt 886 # 887 # And corresponding UFF atom types are: Co6+3, Rh6+3, Ir6+3 888 # 889 # Notes: 890 # . No UFF atom type for Mt 891 # 892 sub _GetAtomTypeForOtherAtomsInGroupNumber9 { 893 my($This, $Atom) = @_; 894 my($AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, $FormalCharge, $MethodName); 895 896 $AtomType = 'None'; 897 $MethodName = '_GetAtomTypeForOtherAtomsInGroupNumber9'; 898 899 $AtomSymbol = $Atom->GetAtomSymbol(); 900 ($NumOfNeighbors, $FormalOxidationState, $FormalCharge) = $This->_GetAtomEnvironmentInfoForUFFAtomTypes($Atom); 901 902 ATOMSYMBOL: { 903 if ($AtomSymbol =~ /^(Co|Rh|Ir)$/) { 904 $AtomType = "${AtomSymbol}6+3"; 905 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'octahedral', 6, 3); 906 last ATOMSYMBOL; 907 } 908 909 $AtomType = 'None'; 910 } 911 912 return $AtomType; 913 } 914 915 # Get UFF atom type for atoms in periodic table group number 10... 916 # 917 # Group number 10 contains: Ni, Pd, Pt 918 # 919 # And corresponding UFF atom types are: Ni4+2, Pd4+2, Pt4+2 920 # 921 sub _GetAtomTypeForOtherAtomsInGroupNumber10 { 922 my($This, $Atom) = @_; 923 my($AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, $FormalCharge, $MethodName); 924 925 $AtomType = 'None'; 926 $MethodName = '_GetAtomTypeForOtherAtomsInGroupNumber10'; 927 928 $AtomSymbol = $Atom->GetAtomSymbol(); 929 ($NumOfNeighbors, $FormalOxidationState, $FormalCharge) = $This->_GetAtomEnvironmentInfoForUFFAtomTypes($Atom); 930 931 ATOMSYMBOL: { 932 if ($AtomSymbol =~ /^(Ni|Pd|Pt)$/) { 933 $AtomType = "${AtomSymbol}4+2"; 934 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'planar', 4, 2); 935 last ATOMSYMBOL; 936 } 937 938 $AtomType = 'None'; 939 } 940 941 return $AtomType; 942 } 943 944 # Get UFF atom type for atoms in periodic table group number 11... 945 # 946 # Group number 11 contains: Cu, Ag, Au 947 # 948 # And corresponding UFF atom types are: Cu3+1, Ag1+1, Au4+3 949 # 950 sub _GetAtomTypeForOtherAtomsInGroupNumber11 { 951 my($This, $Atom) = @_; 952 my($AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, $FormalCharge, $MethodName); 953 954 $AtomType = 'None'; 955 $MethodName = '_GetAtomTypeForOtherAtomsInGroupNumber11'; 956 957 $AtomSymbol = $Atom->GetAtomSymbol(); 958 ($NumOfNeighbors, $FormalOxidationState, $FormalCharge) = $This->_GetAtomEnvironmentInfoForUFFAtomTypes($Atom); 959 960 ATOMSYMBOL: { 961 if ($AtomSymbol =~ /^Cu$/) { 962 $AtomType = "Cu3+1"; 963 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'tetrahedral', 4, 1); 964 last ATOMSYMBOL; 965 } 966 967 if ($AtomSymbol =~ /^Ag$/) { 968 $AtomType = "Ag1+1"; 969 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'linear', 1, 1); 970 last ATOMSYMBOL; 971 } 972 973 if ($AtomSymbol =~ /^Au$/) { 974 $AtomType = "Au4+3"; 975 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'planar', 4, 3); 976 last ATOMSYMBOL; 977 } 978 979 $AtomType = 'None'; 980 } 981 982 return $AtomType; 983 } 984 985 # Get UFF atom type for atoms in periodic table group number 102.. 986 # 987 # Group number 12 contains: Zn, Cd, Hg 988 # 989 # And corresponding UFF atom types are: Zn3+2, Cd3+2, Hg1+2 990 # 991 sub _GetAtomTypeForOtherAtomsInGroupNumber12 { 992 my($This, $Atom) = @_; 993 my($AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, $FormalCharge, $MethodName); 994 995 $AtomType = 'None'; 996 $MethodName = '_GetAtomTypeForOtherAtomsInGroupNumber12'; 997 998 $AtomSymbol = $Atom->GetAtomSymbol(); 999 ($NumOfNeighbors, $FormalOxidationState, $FormalCharge) = $This->_GetAtomEnvironmentInfoForUFFAtomTypes($Atom); 1000 1001 ATOMSYMBOL: { 1002 if ($AtomSymbol =~ /^(Zn|Cd)$/) { 1003 $AtomType = "${AtomSymbol}3+2"; 1004 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'tetrahedral', 4, 2); 1005 last ATOMSYMBOL; 1006 } 1007 1008 if ($AtomSymbol =~ /^Hg$/) { 1009 $AtomType = "Hg1+2"; 1010 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'linear', 1, 2); 1011 last ATOMSYMBOL; 1012 } 1013 1014 $AtomType = 'None'; 1015 } 1016 1017 return $AtomType; 1018 } 1019 1020 # Get UFF atom type for atoms in periodic table group number 13... 1021 # 1022 # Group number 13 contains: B, Al, Ga, In, Tl 1023 # 1024 # And corresponding UFF atom types are: B_3, B_2, Al3, Ga3+3, In3+3, Tl3+3 1025 # 1026 sub _GetAtomTypeForOtherAtomsInGroupNumber13 { 1027 my($This, $Atom) = @_; 1028 my($AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, $FormalCharge, $MethodName); 1029 1030 $AtomType = 'None'; 1031 $MethodName = '_GetAtomTypeForOtherAtomsInGroupNumber13'; 1032 1033 $AtomSymbol = $Atom->GetAtomSymbol(); 1034 ($NumOfNeighbors, $FormalOxidationState, $FormalCharge) = $This->_GetAtomEnvironmentInfoForUFFAtomTypes($Atom); 1035 1036 ATOMSYMBOL: { 1037 if ($AtomSymbol =~ /^B$/) { 1038 B: { 1039 if ($NumOfNeighbors == 4) { 1040 $AtomType = "B_3"; 1041 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'tetrahedral', 4, 0); 1042 last B; 1043 } 1044 1045 if ($NumOfNeighbors == 3) { 1046 $AtomType = "B_2"; 1047 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'trigonal', 3, 0); 1048 last B; 1049 } 1050 1051 # Assign default value... 1052 $AtomType = "B_2"; 1053 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'trigonal', 3, 0); 1054 } 1055 1056 last ATOMSYMBOL; 1057 } 1058 1059 if ($AtomSymbol =~ /^Al$/) { 1060 $AtomType = "Al3"; 1061 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'tetrahedral', 4, 0); 1062 last ATOMSYMBOL; 1063 } 1064 1065 if ($AtomSymbol =~ /^(Ga|In|Tl)$/) { 1066 $AtomType = "${AtomSymbol}3+3"; 1067 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'tetrahedral', 4, 3); 1068 last ATOMSYMBOL; 1069 } 1070 1071 $AtomType = 'None'; 1072 } 1073 1074 return $AtomType; 1075 } 1076 1077 # Get UFF atom type for atoms in periodic table group number 14... 1078 # 1079 # Group number 14 contains: C, Si, Ge, Sn, Pb 1080 # 1081 # And corresponding UFF atom types are: Si3, Ge3, Sn3, Pb3 1082 # 1083 # Notes: 1084 # . This method doesn't assign UFF atom type for C. 1085 # 1086 sub _GetAtomTypeForOtherAtomsInGroupNumber14 { 1087 my($This, $Atom) = @_; 1088 my($AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, $FormalCharge, $MethodName); 1089 1090 $AtomType = 'None'; 1091 $MethodName = '_GetAtomTypeForOtherAtomsInGroupNumber14'; 1092 1093 $AtomSymbol = $Atom->GetAtomSymbol(); 1094 ($NumOfNeighbors, $FormalOxidationState, $FormalCharge) = $This->_GetAtomEnvironmentInfoForUFFAtomTypes($Atom); 1095 1096 ATOMSYMBOL: { 1097 if ($AtomSymbol =~ /^(Si|Ge|Sn|Pb)$/) { 1098 $AtomType = "${AtomSymbol}3"; 1099 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'tetrahedral', 4, 0); 1100 last ATOMSYMBOL; 1101 } 1102 1103 $AtomType = 'None'; 1104 } 1105 1106 return $AtomType; 1107 } 1108 1109 # Get UFF atom type for atoms in periodic table group number 15... 1110 # 1111 # Group number 15 contains: N, P, As, Sb, Bi 1112 # 1113 # And corresponding UFF atom types are: As3+3, Sb3+3, Bi3+3 1114 # 1115 # Notes: 1116 # . This method doesn't assign UFF atom type for N and P. 1117 # 1118 sub _GetAtomTypeForOtherAtomsInGroupNumber15 { 1119 my($This, $Atom) = @_; 1120 my($AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, $FormalCharge, $MethodName); 1121 1122 $AtomType = 'None'; 1123 $MethodName = '_GetAtomTypeForOtherAtomsInGroupNumber15'; 1124 1125 $AtomSymbol = $Atom->GetAtomSymbol(); 1126 ($NumOfNeighbors, $FormalOxidationState, $FormalCharge) = $This->_GetAtomEnvironmentInfoForUFFAtomTypes($Atom); 1127 1128 ATOMSYMBOL: { 1129 if ($AtomSymbol =~ /^(As|Sb|Bi)$/) { 1130 $AtomType = "${AtomSymbol}3+3"; 1131 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'tetrahedral', 3, 3); 1132 last ATOMSYMBOL; 1133 } 1134 1135 $AtomType = 'None'; 1136 } 1137 1138 return $AtomType; 1139 } 1140 1141 # Get UFF atom type for atoms in periodic table group number 16... 1142 # 1143 # Group number 16 contains: O, S, Se, Te, Po 1144 # 1145 # And corresponding UFF atom types are: Se3+2, Te3+2, Po3+2 1146 # 1147 # Notes: 1148 # . This method doesn't assign UFF atom type for O and S. 1149 # 1150 sub _GetAtomTypeForOtherAtomsInGroupNumber16 { 1151 my($This, $Atom) = @_; 1152 my($AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, $FormalCharge, $MethodName); 1153 1154 $AtomType = 'None'; 1155 $MethodName = '_GetAtomTypeForOtherAtomsInGroupNumber16'; 1156 1157 $AtomSymbol = $Atom->GetAtomSymbol(); 1158 ($NumOfNeighbors, $FormalOxidationState, $FormalCharge) = $This->_GetAtomEnvironmentInfoForUFFAtomTypes($Atom); 1159 1160 ATOMSYMBOL: { 1161 if ($AtomSymbol =~ /^(Se|Te|Po)$/) { 1162 $AtomType = "${AtomSymbol}3+2"; 1163 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'tetrahedral', 2, 2); 1164 last ATOMSYMBOL; 1165 } 1166 1167 $AtomType = 'None'; 1168 } 1169 1170 return $AtomType; 1171 } 1172 1173 # Get UFF atom type for atoms in periodic table group number 17... 1174 # 1175 # Group number 17 contains: F, Cl, Br, I, At 1176 # 1177 # And corresponding UFF atom types are: F_, Cl, Br, I_, At 1178 # 1179 sub _GetAtomTypeForOtherAtomsInGroupNumber17 { 1180 my($This, $Atom) = @_; 1181 my($AtomType, $AtomSymbol); 1182 1183 $AtomSymbol = $Atom->GetAtomSymbol(); 1184 $AtomType = (length($AtomSymbol) == 1) ? "${AtomSymbol}_" : $AtomSymbol; 1185 1186 return $AtomType; 1187 } 1188 1189 # Get UFF atom type for atoms in periodic table group number 18... 1190 # 1191 # Group number 18 contains: He, Ne, Ar, Kr, Xe, Rn 1192 # 1193 # And corresponding UFF atom types are: He4+4, Ne4+4, Ar4+4, Kr4+4, Xe4+4, Rn4+4 1194 # 1195 sub _GetAtomTypeForOtherAtomsInGroupNumber18 { 1196 my($This, $Atom) = @_; 1197 my($AtomSymbol, $AtomType); 1198 1199 $AtomType = 'None'; 1200 1201 $AtomSymbol = $Atom->GetAtomSymbol(); 1202 $AtomType = "${AtomSymbol}4+4"; 1203 1204 return $AtomType; 1205 } 1206 1207 # Get UFF atom type for atoms in periodic table group name Lanthanoid... 1208 # 1209 # Group name Lanthanoid contains: La, Ce, Pr, Nd, Pm, Sm, Eu, Gd, Tb, Dy, Ho, Er, Tm, Yb, Lu 1210 # 1211 # And corresponding UFF atom types are: La3+3, Ce6+3, Pr6+3, Nd6+3, Pm6+3, Sm6+3, 1212 # Eu6+3, Gd6+3, Tb6+3, Dy6+3, Ho6+3, Er6+3, Tm6+3, Yb6+3, Lu6+3 1213 # 1214 sub _GetAtomTypeForOtherAtomsInLanthanoidGroup { 1215 my($This, $Atom) = @_; 1216 my($AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, $FormalCharge, $MethodName); 1217 1218 $AtomType = 'None'; 1219 $MethodName = '_GetAtomTypeForOtherAtomsInLanthanoidGroup'; 1220 1221 $AtomSymbol = $Atom->GetAtomSymbol(); 1222 ($NumOfNeighbors, $FormalOxidationState, $FormalCharge) = $This->_GetAtomEnvironmentInfoForUFFAtomTypes($Atom); 1223 1224 ATOMSYMBOL: { 1225 if ($AtomSymbol =~ /^La$/) { 1226 $AtomType = "La3+3"; 1227 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'tetrahedral', 4, 3); 1228 last ATOMSYMBOL; 1229 } 1230 1231 $AtomType = "${AtomSymbol}6+3"; 1232 $This->_CheckGeometryAndFormalChargeMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalCharge, 'octahedral', 6, 3); 1233 } 1234 1235 return $AtomType; 1236 1237 } 1238 1239 # Get UFF atom type for atoms in periodic table group name Actinoid... 1240 # 1241 # Group name Actinoid contains: Ac, Th, Pa, U, Np, Pu, Am, Cm, Bk, Cf, Es, Fm, Md, No, Lr 1242 # 1243 # And corresponding UFF atom types are: Ac6+3, Th6+4, Pa6+4, U_6+4, Np6+4, Pu6+4, 1244 # Am6+4, Cm6+3, Bk6+3, Cf6+3, Es6+3, Fm6+3, Md6+3, No6+3, Lr6+3 1245 # 1246 sub _GetAtomTypeForOtherAtomsInActinoidGroup { 1247 my($This, $Atom) = @_; 1248 my($AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, $FormalCharge, $MethodName); 1249 1250 $AtomType = 'None'; 1251 $MethodName = '_GetAtomTypeForOtherAtomsInActinoidGroup'; 1252 1253 $AtomSymbol = $Atom->GetAtomSymbol(); 1254 ($NumOfNeighbors, $FormalOxidationState, $FormalCharge) = $This->_GetAtomEnvironmentInfoForUFFAtomTypes($Atom); 1255 1256 ATOMSYMBOL: { 1257 if ($AtomSymbol =~ /^(Ac|Cm|Bk|Cf|Es|Fm|Md|No|Lr)$/) { 1258 $AtomType = "${AtomSymbol}6+3"; 1259 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'octahedral', 6, 3); 1260 last ATOMSYMBOL; 1261 } 1262 1263 if ($AtomSymbol =~ /^(Th|Pa|U|Np|Pu|Am)$/) { 1264 $AtomType = length($AtomSymbol) == 1 ? "${AtomSymbol}_6+4" : "${AtomSymbol}6+4"; 1265 $This->_CheckGeometryAndOxidationStateMismatch($MethodName, $AtomSymbol, $AtomType, $NumOfNeighbors, $FormalOxidationState, 'octahedral', 6, 4); 1266 last ATOMSYMBOL; 1267 } 1268 1269 $AtomType = 'None'; 1270 } 1271 1272 return $AtomType; 1273 } 1274 1275 1276 # Is it a four-coordinated Phosphorus for describing organometallic coordinated phosphines? 1277 # 1278 sub _IsFourCoordinatedOrganometallicPhosphorus { 1279 my($This, $Atom) = @_; 1280 my($AtomNeighbor, $NumOfNeighbors, $MetalNeighborFound, @AtomNeighbors); 1281 1282 @AtomNeighbors = $Atom->GetHeavyAtomNeighbors(); 1283 1284 # Is it attached to a metallic atom? 1285 $MetalNeighborFound = 0; 1286 NEIGHBOR: for $AtomNeighbor (@AtomNeighbors) { 1287 if ($AtomNeighbor->IsMetallic()) { 1288 $MetalNeighborFound = 1; 1289 last NEIGHBOR; 1290 } 1291 } 1292 1293 if (!$MetalNeighborFound) { 1294 return 0; 1295 } 1296 1297 # Is it four coordinated Phosphorus? 1298 $NumOfNeighbors = scalar @AtomNeighbors; 1299 if ($NumOfNeighbors <= 4) { 1300 # As long as total number of heavy atom neighbors, including attached 1301 # metal atom is <= 4, missing hydrogens would make it a tetra coordinated 1302 # Phosphorous... 1303 return 1; 1304 } 1305 1306 return 0; 1307 } 1308 1309 # Get UFF atom environment information, number of neighbors and formal oxidatiion state, 1310 # for assigning UFF atom types... 1311 # 1312 sub _GetAtomEnvironmentInfoForUFFAtomTypes { 1313 my($This, $Atom) = @_; 1314 my($NumOfNeighbors, $NumOfHydrogens, $FormalOxidationState, $FormalCharge); 1315 1316 $NumOfHydrogens = $Atom->GetNumOfMissingHydrogens() + $Atom->GetExplicitHydrogens(); 1317 1318 # Total number of neighbor atoms... 1319 $NumOfNeighbors = $Atom->GetNumOfNonHydrogenAtomNeighbors() + $NumOfHydrogens; 1320 1321 # UFF formal oxidation state appears to just the sum of bond orders to all attched non-hyrdogen 1322 # atoms and all hydrogen atoms... 1323 # 1324 $FormalOxidationState = $Atom->GetSumOfBondOrdersToNonHydrogenAtoms() + $NumOfHydrogens; 1325 1326 # Any explicit formal charge... 1327 $FormalCharge = $Atom->GetFormalCharge(); 1328 1329 return ($NumOfNeighbors, $FormalOxidationState, $FormalCharge); 1330 } 1331 1332 # Check and warn about any geometry and/or formal charge mismatch... 1333 # 1334 sub _CheckGeometryAndFormalChargeMismatch { 1335 my($This, $CallingMethod, $AtomSymbol, $AssignedAtomType, $NumOfNeighbors, $FormalCharge, $ExpectedGeometryType, $ExpectedNumOfNeighbors, $ExpectedFormalCharge) = @_; 1336 my($MsgHeader); 1337 1338 $MsgHeader = "Warning: ${ClassName}->${CallingMethod}:_CheckGeometryAndFormalChargeMismatch"; 1339 1340 if ($NumOfNeighbors !=$ExpectedNumOfNeighbors && $FormalCharge != $ExpectedFormalCharge) { 1341 carp "\n${MsgHeader}: UFF atom type for $AtomSymbol corresponding to $ExpectedGeometryType geometry and formal charge $ExpectedFormalCharge cann't be assigned; Number of neighbors, $NumOfNeighbors, is different from $ExpectedNumOfNeighbors and formal charge, $FormalCharge, is different from $ExpectedFormalCharge. Default UFF atom type, $AssignedAtomType, has been assigned..."; 1342 } 1343 elsif ($NumOfNeighbors !=$ExpectedNumOfNeighbors) { 1344 carp "\n${MsgHeader}: UFF atom type for $AtomSymbol corresponding to $ExpectedGeometryType geometry and formal charge $ExpectedFormalCharge cann't be assigned; Number of neighbors, $NumOfNeighbors, is different from $ExpectedNumOfNeighbors. Default UFF atom type, $AssignedAtomType, has been assigned..."; 1345 } 1346 elsif ($FormalCharge != $ExpectedFormalCharge) { 1347 carp "\n${MsgHeader}: UFF atom type for $AtomSymbol corresponding to $ExpectedGeometryType geometry and formal charge $ExpectedFormalCharge cann't be assigned; Formal charge, $FormalCharge, is different from $ExpectedFormalCharge. Default UFF atom type, $AssignedAtomType, has been assigned..."; 1348 } 1349 } 1350 1351 # Check and warn about any geometry and/or formal oxidation state mismatch... 1352 # 1353 sub _CheckGeometryAndOxidationStateMismatch { 1354 my($This, $CallingMethod, $AtomSymbol, $AssignedAtomType, $NumOfNeighbors, $FormalOxidationState, $ExpectedGeometryType, $ExpectedNumOfNeighbors, $ExpectedFormalOxidationState) = @_; 1355 my($MsgHeader); 1356 1357 $MsgHeader = "Warning: ${ClassName}->${CallingMethod}:_CheckGeometryAndOxidationStateMismatch"; 1358 1359 if ($NumOfNeighbors !=$ExpectedNumOfNeighbors && $FormalOxidationState != $ExpectedFormalOxidationState) { 1360 carp "\n${MsgHeader}: UFF atom type for $AtomSymbol corresponding to $ExpectedGeometryType geometry and formal oxidation state $ExpectedFormalOxidationState cann't be assigned; Number of neighbors, $NumOfNeighbors, is different from $ExpectedNumOfNeighbors and formal oxidation state, $FormalOxidationState, is different from $ExpectedFormalOxidationState. Default UFF atom type, $AssignedAtomType, has been assigned..."; 1361 } 1362 elsif ($NumOfNeighbors !=$ExpectedNumOfNeighbors) { 1363 carp "\n${MsgHeader}: UFF atom type for $AtomSymbol corresponding to $ExpectedGeometryType geometry and formal oxidation state $ExpectedFormalOxidationState cann't be assigned; Number of neighbors, $NumOfNeighbors, is different from $ExpectedNumOfNeighbors. Default UFF atom type, $AssignedAtomType, has been assigned..."; 1364 } 1365 elsif ($FormalOxidationState != $ExpectedFormalOxidationState) { 1366 carp "\n${MsgHeader}: UFF atom type for $AtomSymbol corresponding to $ExpectedGeometryType geometry and formal oxidation state $ExpectedFormalOxidationState cann't be assigned; Formal oxidation state, $FormalOxidationState, is different from $ExpectedFormalOxidationState. Default UFF atom type, $AssignedAtomType, has been assigned..."; 1367 } 1368 } 1369 1370 1371 # Return a string containg data for UFFAtomTypes object... 1372 # 1373 sub StringifyUFFAtomTypes { 1374 my($This) = @_; 1375 my($AtomTypesString); 1376 1377 # Type of AtomTypes... 1378 $AtomTypesString = "AtomTypes: $This->{Type}; IgnoreHydrogens: " . ($This->{IgnoreHydrogens} ? "Yes" : "No"); 1379 1380 # Setup atom types information... 1381 my($AtomID, $AtomType, @AtomTypesInfo, %AssignedAtomTypes); 1382 1383 @AtomTypesInfo = (); 1384 %AssignedAtomTypes = $This->GetAtomTypes(); 1385 1386 for $AtomID (sort { $a <=> $b } keys %AssignedAtomTypes) { 1387 $AtomType = $AssignedAtomTypes{$AtomID} ? $AssignedAtomTypes{$AtomID} : 'None'; 1388 push @AtomTypesInfo, "$AtomID:$AtomType"; 1389 } 1390 $AtomTypesString .= "; AtomIDs:AtomTypes: <" . TextUtil::JoinWords(\@AtomTypesInfo, ", ", 0) . ">"; 1391 1392 return $AtomTypesString; 1393 } 1394 1395 # Is it a UFFAtomTypes object? 1396 sub _IsUFFAtomTypes { 1397 my($Object) = @_; 1398 1399 return (Scalar::Util::blessed($Object) && $Object->isa($ClassName)) ? 1 : 0; 1400 } 1401 1402 # Check and load UFF atom types data... 1403 # 1404 sub _CheckAndLoadUFFAtomTypesData { 1405 1406 # Is it already loaded? 1407 if (exists $UFFAtomTypesDataMap{AtomTypes}) { 1408 return; 1409 } 1410 1411 _LoadUFFAtomTypesData(); 1412 } 1413 1414 # Load UFF atom types data from the file assuming first column to be atom type symbol.. 1415 # 1416 # Format: 1417 # 1418 # "AtomType","Mass","ValenceBondRadius","ValenceAngle","NonBondRadius","NonBondEnergy","NonBondScale","EffectiveCharge","SP3TorsionalBarrier" 1419 # "H_","1.0080","0.354","180.000","2.886","0.044","12.000","0.733","0.000" 1420 # "C_3","12.0110","0.757","109.471","3.851","0.105","12.730","1.967","2.119" 1421 # "C_R","12.0110","0.729","120.000","3.851","0.105","12.730","1.967","0.000" 1422 # "C_2","12.0110","0.732","120.000","3.851","0.105","12.730","1.967","0.000" 1423 # "C_1","12.0110","0.711","180.000","3.851","0.105","12.730","1.967","0.000" 1424 # 1425 sub _LoadUFFAtomTypesData { 1426 my($AtomTypesDataFile, $MayaChemToolsLibDir); 1427 1428 $MayaChemToolsLibDir = FileUtil::GetMayaChemToolsLibDirName(); 1429 1430 $AtomTypesDataFile = "$MayaChemToolsLibDir" . "/data/UFFAtomTypes.csv"; 1431 if (! -e "$AtomTypesDataFile") { 1432 croak "Error: MayaChemTools package file, $AtomTypesDataFile, is missing: Possible installation problems..."; 1433 } 1434 1435 %UFFAtomTypesDataMap = (); 1436 AtomTypes::AtomTypes::LoadAtomTypesData($AtomTypesDataFile, \%UFFAtomTypesDataMap); 1437 } 1438