1 package AtomTypes::DREIDINGAtomTypes; 2 # 3 # $RCSfile: DREIDINGAtomTypes.pm,v $ 4 # $Date: 2015/02/28 20:48:03 $ 5 # $Revision: 1.17 $ 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 Scalar::Util (); 33 use AtomTypes::AtomTypes; 34 use Molecule; 35 36 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); 37 38 @ISA = qw(AtomTypes::AtomTypes Exporter); 39 @EXPORT = qw(GetDREIDINGAtomTypesData GetAllPossibleDREIDINGAtomTypes GetAllPossibleDREIDINGNonHydrogenAtomTypes); 40 @EXPORT_OK = qw(); 41 42 %EXPORT_TAGS = (all => [@EXPORT, @EXPORT_OK]); 43 44 # Setup class variables... 45 my($ClassName, %DREIDINGAtomTypesDataMap); 46 _InitializeClass(); 47 48 # Overload Perl functions... 49 use overload '""' => 'StringifyDREIDINGAtomTypes'; 50 51 # Class constructor... 52 sub new { 53 my($Class, %NamesAndValues) = @_; 54 55 # Initialize object... 56 my $This = $Class->SUPER::new(); 57 bless $This, ref($Class) || $Class; 58 $This->_InitializeDREIDINGAtomTypes(); 59 60 $This->_InitializeDREIDINGAtomTypesProperties(%NamesAndValues); 61 62 return $This; 63 } 64 65 # Initialize class ... 66 sub _InitializeClass { 67 #Class name... 68 $ClassName = __PACKAGE__; 69 70 # Initialize the data hash. It'll be loaded on demand later... 71 %DREIDINGAtomTypesDataMap = (); 72 } 73 74 75 # Initialize object data... 76 # 77 sub _InitializeDREIDINGAtomTypes { 78 my($This) = @_; 79 80 # Type of AtomTypes... 81 $This->{Type} = 'DREIDING'; 82 83 # By default, DREIDING atom types are also assigned to hydrogens... 84 $This->{IgnoreHydrogens} = 0; 85 86 return $This; 87 } 88 89 # Initialize object properties... 90 # 91 sub _InitializeDREIDINGAtomTypesProperties { 92 my($This, %NamesAndValues) = @_; 93 94 my($Name, $Value, $MethodName); 95 while (($Name, $Value) = each %NamesAndValues) { 96 $MethodName = "Set${Name}"; 97 $This->$MethodName($Value); 98 } 99 100 # Make sure molecule object was specified... 101 if (!exists $NamesAndValues{Molecule}) { 102 croak "Error: ${ClassName}->New: Object can't be instantiated without specifying molecule..."; 103 } 104 105 return $This; 106 } 107 108 # Get DREIDING atom types and associated data loaded from DREIDING data file as 109 # a reference to hash with the following hash data format: 110 # 111 # @{$DREIDINGAtomTypesDataMap{AtomTypes}} - Array of all possible atom types for all atoms 112 # @{$DREIDINGAtomTypesDataMap{NonHydrogenAtomTypes}} - Array of all possible atom types for non-hydrogen atoms 113 # @{$DREIDINGAtomTypesDataMap->{ColLabels}} - Array of column labels 114 # %{$DREIDINGAtomTypesDataMap->{DataCol<Num>}} - Hash keys pair: <DataCol<Num>, AtomType> 115 # 116 # This functionality can be either invoked as a class function or an 117 # object method. 118 # 119 sub GetDREIDINGAtomTypesData { 120 121 # Make sure data is loaded... 122 _CheckAndLoadDREIDINGAtomTypesData(); 123 124 return \%DREIDINGAtomTypesDataMap; 125 } 126 127 # Get all possible DREIDING atom types corresponding to hydrogen and non-hydrogen 128 # atoms as an array reference... 129 # 130 # This functionality can be either invoked as a class function or an 131 # object method. 132 # 133 sub GetAllPossibleDREIDINGAtomTypes { 134 return _GetAllPossibleDREIDINGAtomTypes(); 135 } 136 137 # Get all possible DREIDING atom types corresponding to non-hydrogen atoms 138 # as an array reference... 139 # 140 # This functionality can be either invoked as a class function or an 141 # object method. 142 # 143 sub GetAllPossibleDREIDINGNonHydrogenAtomTypes { 144 my($NonHydrogensOnly); 145 146 $NonHydrogensOnly = 1; 147 return _GetAllPossibleDREIDINGAtomTypes($NonHydrogensOnly); 148 } 149 150 # Get all possible DREIDING atom types as an array reference... 151 # 152 sub _GetAllPossibleDREIDINGAtomTypes { 153 my($NonHydrogensOnly) = @_; 154 my($DREIDINGAtomTypesDataRef); 155 156 $NonHydrogensOnly = defined $NonHydrogensOnly ? $NonHydrogensOnly : 0; 157 158 $DREIDINGAtomTypesDataRef = GetDREIDINGAtomTypesData(); 159 160 return $NonHydrogensOnly ? \@{$DREIDINGAtomTypesDataRef->{NonHydrogenAtomTypes}}: \@{$DREIDINGAtomTypesDataRef->{AtomTypes}}; 161 } 162 163 # Assign DREIDING [ Ref 88 ] atom types to all atoms... 164 # 165 # Notes: 166 # o 37 DREIDING atom types are listed 167 # o AtomTypes::DREIDINGAtomTypes.pm module is used to assign DREIDING atom types 168 # o Units: 169 # o ValenceBondRadius and NonBondRadius: Angstroms 170 # o ValenceAngle: Degrees 171 # o Five-character mnemonic label for DREIDING atom types 172 # o First two characters correspond to chemical symbol with an underscore as second 173 # character for elements with one character symbol 174 # o Third character describes hybridization: 1 - linear (sp); 2 - trigonal (sp2); 175 # 3 = tetrahedral (sp3); R - sp2 involved in resonance situation 176 # o Fourth character used to indicate number of implicit hydrogens 177 # o Fourth and fifth chracters are used as indicators of alternate parameters: formal oxidation 178 # state, bridging hydrogens and so on. The _HB type denotes a hydrogen atom capable 179 # of forming hdyrogen bonds attached to (N, O, F). The H_b is the bridging hydrogen 180 # of diborane. 181 # 182 # 183 sub AssignAtomTypes { 184 my($This) = @_; 185 my($Atom, $AtomType); 186 187 ATOM: for $Atom ($This->GetMolecule()->GetAtoms()) { 188 if ($This->{IgnoreHydrogens} && $Atom->IsHydrogen()) { 189 next ATOM; 190 } 191 $AtomType = $This->_GetAtomType($Atom); 192 $This->SetAtomType($Atom, $AtomType); 193 } 194 return $This; 195 } 196 197 # Get DREIDING atom type for atom... 198 # 199 sub _GetAtomType { 200 my($This, $Atom) = @_; 201 my($AtomType); 202 203 $AtomType = ''; 204 205 ATOM: { 206 if ($Atom->IsCarbon()) { 207 $AtomType = $This->_GetAtomTypeForCarbon($Atom); 208 last ATOM; 209 } 210 if ($Atom->IsNitrogen()) { 211 $AtomType = $This->_GetAtomTypeForNitrogen($Atom); 212 last ATOM; 213 } 214 if ($Atom->IsOxygen()) { 215 $AtomType = $This->_GetAtomTypeForOxygen($Atom); 216 last ATOM; 217 } 218 if ($Atom->IsPhosphorus()) { 219 $AtomType = $This->_GetAtomTypeForPhosphorus($Atom); 220 last ATOM; 221 } 222 if ($Atom->IsSulfur()) { 223 $AtomType = $This->_GetAtomTypeForSulfur($Atom); 224 last ATOM; 225 } 226 if ($Atom->IsHydrogen()) { 227 $AtomType = $This->_GetAtomTypeForHydrogen($Atom); 228 last ATOM; 229 } 230 $AtomType = $This->_GetAtomTypeForOtherAtoms($Atom); 231 } 232 233 return $AtomType; 234 } 235 236 # Get DREIDING atom type for Carbon atom... 237 # 238 sub _GetAtomTypeForCarbon { 239 my($This, $Atom) = @_; 240 my($AtomType, $NumOfSigmaBonds, $NumOfPiBonds); 241 242 $AtomType = 'None'; 243 244 ($NumOfSigmaBonds, $NumOfPiBonds) = ('0') x 2; 245 246 ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms(); 247 $NumOfSigmaBonds += $Atom->GetAtomicInvariantValue('H'); 248 249 ATOMTYPE: { 250 if ($Atom->IsAromatic()) { 251 $AtomType = 'C_R'; 252 last ATOMTYPE; 253 } 254 255 # Only single bonds... 256 if ($NumOfPiBonds == 0) { 257 $AtomType = 'C_3'; 258 last ATOMTYPE; 259 } 260 261 # One double bond... 262 if ($NumOfPiBonds == 1) { 263 $AtomType = 'C_2'; 264 last ATOMTYPE; 265 } 266 267 # One triple bond or two double bonds... 268 if ($NumOfPiBonds == 2) { 269 $AtomType = 'C_1'; 270 last ATOMTYPE; 271 } 272 273 $AtomType = 'None'; 274 carp "Warning: ${ClassName}->_GetAtomTypeForCarbon: DREIDING atom types for Carbon cann't be assigned..."; 275 } 276 277 return $AtomType; 278 } 279 280 # Get DREIDING atom type for Nitrogen atom... 281 # 282 sub _GetAtomTypeForNitrogen { 283 my($This, $Atom) = @_; 284 my($AtomType, $NumOfSigmaBonds, $NumOfPiBonds); 285 286 $AtomType = 'None'; 287 288 ($NumOfSigmaBonds, $NumOfPiBonds) = ('0') x 2; 289 290 ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms(); 291 $NumOfSigmaBonds += $Atom->GetAtomicInvariantValue('H'); 292 293 ATOMTYPE: { 294 if ($Atom->IsAromatic()) { 295 $AtomType = 'N_R'; 296 last ATOMTYPE; 297 } 298 299 # Only single bonds... 300 if ($NumOfPiBonds == 0) { 301 $AtomType = 'N_3'; 302 last ATOMTYPE; 303 } 304 305 # One double bond... 306 if ($NumOfPiBonds == 1) { 307 $AtomType = 'N_2'; 308 last ATOMTYPE; 309 } 310 311 # One triple bond or two double bonds... 312 if ($NumOfPiBonds == 2) { 313 $AtomType = 'N_1'; 314 last ATOMTYPE; 315 } 316 317 $AtomType = 'None'; 318 carp "Warning: ${ClassName}->_GetAtomTypeForNitrogen: DREIDING atom types for Nitrogen cann't be assigned..."; 319 } 320 321 return $AtomType; 322 } 323 324 # Get DREIDING atom type for Oxygen atom... 325 # 326 sub _GetAtomTypeForOxygen { 327 my($This, $Atom) = @_; 328 my($AtomType, $NumOfSigmaBonds, $NumOfPiBonds); 329 330 $AtomType = 'None'; 331 332 ($NumOfSigmaBonds, $NumOfPiBonds) = ('0') x 2; 333 334 ($NumOfSigmaBonds, $NumOfPiBonds) = $Atom->GetNumOfSigmaAndPiBondsToNonHydrogenAtoms(); 335 $NumOfSigmaBonds += $Atom->GetAtomicInvariantValue('H'); 336 337 ATOMTYPE: { 338 if ($Atom->IsAromatic()) { 339 $AtomType = 'O_R'; 340 last ATOMTYPE; 341 } 342 343 # Only single bonds... 344 if ($NumOfPiBonds == 0) { 345 $AtomType = 'O_3'; 346 last ATOMTYPE; 347 } 348 349 # One double bond... 350 if ($NumOfPiBonds == 1) { 351 $AtomType = 'O_2'; 352 last ATOMTYPE; 353 } 354 355 # One triple bond or two double bonds... 356 if ($NumOfPiBonds == 2) { 357 $AtomType = 'O_1'; 358 last ATOMTYPE; 359 } 360 361 $AtomType = 'None'; 362 carp "Warning: ${ClassName}->_GetAtomTypeForOxygen: DREIDING atom types for Oxygen cann't be assigned..."; 363 } 364 365 return $AtomType; 366 } 367 368 # Get DREIDING atom type for Phosphorus atom... 369 # 370 sub _GetAtomTypeForPhosphorus { 371 my($This, $Atom) = @_; 372 my($AtomType); 373 374 $AtomType = 'P_3'; 375 376 return $AtomType; 377 } 378 379 # Get DREIDING atom type for Sulfur atom... 380 # 381 sub _GetAtomTypeForSulfur { 382 my($This, $Atom) = @_; 383 my($AtomType); 384 385 $AtomType = 'S_3'; 386 387 return $AtomType; 388 } 389 390 # Get DREIDING atom type for Hydrogen atom... 391 # 392 sub _GetAtomTypeForHydrogen { 393 my($This, $Atom) = @_; 394 my($AtomType, $NumOfNeighbors, $NeighborAtom, @NonHydrogenAtomNeighbors); 395 396 @NonHydrogenAtomNeighbors = $Atom->GetNonHydrogenAtomNeighbors(); 397 398 $NumOfNeighbors = scalar @NonHydrogenAtomNeighbors; 399 $NeighborAtom = $NonHydrogenAtomNeighbors[0]; 400 401 ATOMTYPE: { 402 if ($NumOfNeighbors > 1) { 403 # Bridging hydrogen as in B2H6 404 $AtomType = 'H___b'; 405 last ATOMTYPE; 406 } 407 408 if ($NeighborAtom->GetAtomicNumber() =~ /^(7|8|9)$/) { 409 # Involved in hydrogen bonding due to its attachment to N, O, or F 410 $AtomType = 'H__HB'; 411 last ATOMTYPE; 412 } 413 $AtomType = 'H_'; 414 } 415 416 return $AtomType; 417 } 418 419 # Get DREIDING atom type for atoms other than Carbon, Nitrogen, Oxygen, Phosporus, 420 # Sulfur and Hydrogen... 421 # 422 sub _GetAtomTypeForOtherAtoms { 423 my($This, $Atom) = @_; 424 my($AtomType, $AtomicNumber, $AtomSymbol); 425 426 $AtomType = 'None'; 427 428 $AtomicNumber = $Atom->GetAtomicNumber(); 429 $AtomSymbol = $Atom->GetAtomSymbol(); 430 431 ATOMICNUMBER: { 432 if ($AtomicNumber =~ /^(9|17|35|53)$/i) { 433 # F, Cl, Br, I 434 $AtomType = length($AtomSymbol) == 1 ? "${AtomSymbol}_" : $AtomSymbol; 435 last ATOMICNUMBER; 436 } 437 438 if ($AtomicNumber =~ /^5$/i) { 439 # B: B_2 and B_3 440 $AtomType = (($Atom->GetNumOfNonHydrogenAtomNeighbors() + $Atom->GetAtomicInvariantValue('H')) == 4) ? "B_3" : "B_2"; 441 last ATOMICNUMBER; 442 } 443 444 if ($AtomicNumber =~ /^(13|14|31|32|33|34|49|50|51|52)$/i) { 445 # Al, Si, Ga, Ge, As, Se, In, Sn, Sb, Te 446 $AtomType = "${AtomSymbol}3"; 447 last ATOMICNUMBER; 448 } 449 450 if ($AtomicNumber =~ /^(11|20|26|30)$/i) { 451 # Na, Ca, Fe, Zn 452 $AtomType = $AtomSymbol; 453 last ATOMICNUMBER; 454 } 455 456 $AtomType = 'None'; 457 carp "Warning: ${ClassName}->_GetAtomTypeForOtherAtoms: DREIDING atom types for atom, $AtomSymbol, with atomic number, $AtomicNumber, cann't be assigned..."; 458 } 459 460 return $AtomType; 461 } 462 463 # Return a string containg data for DREIDINGAtomTypes object... 464 # 465 sub StringifyDREIDINGAtomTypes { 466 my($This) = @_; 467 my($AtomTypesString); 468 469 # Type of AtomTypes... 470 $AtomTypesString = "AtomTypes: $This->{Type}; IgnoreHydrogens: " . ($This->{IgnoreHydrogens} ? "Yes" : "No"); 471 472 # Setup atom types information... 473 my($AtomID, $AtomType, @AtomTypesInfo, %AssignedAtomTypes); 474 475 @AtomTypesInfo = (); 476 %AssignedAtomTypes = $This->GetAtomTypes(); 477 478 for $AtomID (sort { $a <=> $b } keys %AssignedAtomTypes) { 479 $AtomType = $AssignedAtomTypes{$AtomID} ? $AssignedAtomTypes{$AtomID} : 'None'; 480 push @AtomTypesInfo, "$AtomID:$AtomType"; 481 } 482 $AtomTypesString .= "; AtomIDs:AtomTypes: <" . TextUtil::JoinWords(\@AtomTypesInfo, ", ", 0) . ">"; 483 484 return $AtomTypesString; 485 } 486 487 # Is it a DREIDINGAtomTypes object? 488 sub _IsDREIDINGAtomTypes { 489 my($Object) = @_; 490 491 return (Scalar::Util::blessed($Object) && $Object->isa($ClassName)) ? 1 : 0; 492 } 493 494 # Check and load DREIDING atom types data... 495 # 496 sub _CheckAndLoadDREIDINGAtomTypesData { 497 498 # Is it already loaded? 499 if (exists $DREIDINGAtomTypesDataMap{AtomTypes}) { 500 return; 501 } 502 503 _LoadDREIDINGAtomTypesData(); 504 } 505 506 # Load DREIDING atom types data from the file assuming first column to be atom type symbol.. 507 # 508 # Format: 509 # 510 # "AtomType","ValenceBondRadius","ValenceAngle" 511 # "H_","0.330","180.0" 512 # "C_3","0.770","109.471" 513 # "C_R","0.700","120.0" 514 # "C_2","0.670","120.0" 515 # "C_1","0.602","180.0" 516 # "N_3","0.702","106.7" 517 # 518 sub _LoadDREIDINGAtomTypesData { 519 my($AtomTypesDataFile, $MayaChemToolsLibDir); 520 521 $MayaChemToolsLibDir = FileUtil::GetMayaChemToolsLibDirName(); 522 523 $AtomTypesDataFile = "$MayaChemToolsLibDir" . "/data/DREIDINGAtomTypes.csv"; 524 if (! -e "$AtomTypesDataFile") { 525 croak "Error: MayaChemTools package file, $AtomTypesDataFile, is missing: Possible installation problems..."; 526 } 527 528 %DREIDINGAtomTypesDataMap = (); 529 AtomTypes::AtomTypes::LoadAtomTypesData($AtomTypesDataFile, \%DREIDINGAtomTypesDataMap); 530 } 531