1<?php 2/******************************************************************** 3baphpel - PHP interface to OpenBabel 4Copyright (C) 2013 Maciej Wojcikowski <maciek@wojcikowski.pl> 5 6This file is part of of the Open Babel project. 7 8This file is part of the Open Babel project. 9For more information, see <http://openbabel.org/> 10 11This program is free software; you can redistribute it and/or modify 12it under the terms of the GNU General Public License as published by 13the Free Software Foundation version 2 of the License. 14 15This program is distributed in the hope that it will be useful, 16but WITHOUT ANY WARRANTY; without even the implied warranty of 17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18GNU General Public License for more details. 19 20********************************************************************/ 21namespace baphpel; 22 23include_once 'openbabel.php'; 24 25# define global elements 26$_builder = new \OBBuilder; 27$_obconv = new \OBConversion; 28 29function vector2array($v) { 30 $out = array(); 31 $num = $v -> size(); 32 for($i=0;$i<$num;$i++) { 33 $out[] = $v -> get($i); 34 } 35 return $out; 36} 37 38function _formatstodict($list) { 39 global $_obconv; 40 $list = vector2array($_obconv -> $list()); 41 foreach($list as $f) { 42 $fmt = explode(' -- ', preg_replace(array('/\[Read-only\]/'), '/\[Write-only\]/', $f)); 43 $out[trim($fmt[0])] = trim($fmt[1]); 44 } 45 return $out; 46} 47 48$informats = _formatstodict('GetSupportedInputFormat'); 49$outformats = _formatstodict('GetSupportedOutputFormat'); 50 51function _getplugins($findplugins, $names) { 52 $find = explode('::', $findplugins); 53 foreach($names as $x) { 54 if(in_array($find[0], array('OBDescriptor', 'OBForceField'))) { 55 $f = $find[0]::$find[1]($x); 56 } 57 else { 58 $f1 = new $find[0](null); 59 $f = $f1 -> $find[1]($x); 60 } 61 if($f) { 62 $plugins[$x] = $f; 63 } 64 } 65 return $plugins; 66} 67 68function _getpluginnames($ptype) { 69 $plugins = new \vectorString; 70 \OBPlugin::ListAsVector($ptype, null, $plugins); 71 $plugins = vector2array($plugins); 72 foreach($plugins as $p) { 73 $out[] = strtolower(explode(' ', trim($p))[0]); 74 } 75 return $out; 76} 77 78 79/* A list of supported descriptors */ 80$descs = _getpluginnames('descriptors'); 81$_descdict = _getplugins('\OBDescriptor::FindType', $descs); 82 83/* A list of supported forcefields */ 84$forcefields = _getpluginnames('forcefields'); 85$_forcefields = _getplugins('\OBForceField::FindForceField', $forcefields); 86 87/* A list of supported fingerprint types */ 88$fps = _getpluginnames('fingerprints'); 89$_fingerprinters = _getplugins('\OBFingerprint::FindType', $fps); 90 91/* A list of supported operations */ 92$operations = _getpluginnames('ops'); 93$_operations = _getplugins('\OBOp::FindType', $operations); 94 95function readfile($format, $filename, $opt=array()) { 96 # setup converter 97 $OBConversion = new \OBConversion; 98 $OBConversion -> SetInFormat($format); 99 # set options 100 if(!empty($opt)) { 101 foreach($opt as $k => $v) { 102 if(!empty($v)) { 103 $OBConversion -> AddOption($k, $OBConversion::INOPTIONS, $v); 104 } 105 else { 106 $OBConversion -> AddOption($k, $OBConversion::INOPTIONS); 107 } 108 } 109 } 110 111 class filereader implements \Iterator { 112 private $position = 0; 113 private $notatend = null; 114 private $OBMol = null; 115 116 public function __construct($OBConversion, $filename) { 117 $this -> OBConversion = $OBConversion; 118 $this -> OBMol = new \OBMol; 119 $this -> notatend = $this -> OBConversion -> ReadFile($this -> OBMol, $filename); 120 } 121 122 function rewind() { 123 $this->position = 0; 124 } 125 126 function current() { 127 return new Molecule($this -> OBMol); 128 } 129 130 function key() { 131 return $this->position; 132 } 133 134 function next() { 135 $this -> position++; 136 $this -> OBMol = new \OBMol; 137 $this -> notatend = $this -> OBConversion -> Read($this -> OBMol); 138 } 139 140 function valid() { 141 return $this -> notatend; 142 } 143 } 144 145 return new filereader($OBConversion, $filename); 146} 147 148function readstring($format, $string, $opt=array()) { 149 # setup converter 150 $OBConversion = new \OBConversion; 151 $OBConversion -> SetInFormat($format); 152 # set options 153 if(!empty($opt)) { 154 foreach($opt as $k => $v) { 155 if(!empty($v)) { 156 $OBConversion -> AddOption($k, $OBConversion::INOPTIONS, $v); 157 } 158 else { 159 $OBConversion -> AddOption($k, $OBConversion::INOPTIONS); 160 } 161 } 162 } 163 164 $OBMol = new \OBMol; 165 $OBConversion->ReadString($OBMol, $string); 166 return new Molecule($OBMol); 167} 168 169class Outputfile { 170 public function __construct($format, $filename, $overwrite=False, $opt=array()) { 171 $this -> format = $format; 172 $this -> filename = $filename; 173 if(!$overwrite && file_exists(self.filename)) { 174 throw new \Exception($this -> filename." already exists. Use 'overwrite=True' to overwrite it."); 175 } 176 $this -> OBConversion = new \OBConversion; 177 $formatok = $this -> OBConversion -> SetOutFormat($this -> format); 178 if(!$formatok) { 179 throw new \Exception($this -> format." is not a recognised Open Babel format"); 180 } 181 foreach($opt as $key => $value) { 182 if($v === null) { 183 $this -> OBConversion -> AddOption($k, $this -> OBConversion -> OUTOPTIONS); 184 } 185 else { 186 $this -> OBConversion -> AddOption($k, $this -> OBConversion -> OUTOPTIONS, $v); 187 } 188 } 189 $this -> total = 0; # The total number of molecules written to the file 190 } 191 192 public function write($molecule) { 193 if(!$this -> filename) { 194 throw new \Exception("Outputfile instance is closed."); 195 } 196 197 if($this -> total == 0) { 198 $this -> OBConversion -> WriteFile($molecule -> OBMol, $this -> filename); 199 } 200 else { 201 $this -> OBConversion -> Write($molecule -> OBMol); 202 } 203 $this -> total += 1; 204 } 205 206 public function close() { 207 $this -> OBConversion -> CloseOutFile(); 208 $this -> filename = null; 209 } 210} 211 212class Molecule implements \Iterator { 213 public $OBMol = null; 214 private $position = 0; 215 private $atoms = array(); 216 private $residues = array(); 217 218 public function __construct($OBMol) { 219 $this -> OBMol = $OBMol; 220 } 221 222 public function __get($name) { 223 switch($name) { 224 case 'atoms': 225 if(empty($this -> atoms)) { # generate atoms only once 226 $out = array(); 227 $num = $this -> OBMol -> NumAtoms(); 228 for($i=1;$i<=$num;$i++) { 229 $atom = $this -> OBMol -> GetAtom($i); 230 if(empty($atom)) { 231 echo $i.'!!!'; 232 } 233 $out[] = new Atom($this -> OBMol -> GetAtom($i)); 234 } 235 $this -> atoms = $out; 236 } 237 else { 238 $out = $this -> atoms; 239 } 240 break; 241 case 'residues': 242 if(empty($this -> residues)) { # generate residues only once 243 $out = array(); 244 $num = $this -> OBMol -> NumResidues(); 245 for($i=0;$i<$num;$i++) { 246 $out[] = new Residue($this -> OBMol -> GetResidue($i)); 247 } 248 $this -> residues = $out; 249 } 250 else { 251 $out = $this -> residues; 252 } 253 break; 254 case 'charge': 255 $out = $this -> OBMol -> GetTotalCharge(); 256 break; 257 case 'conformers': 258 $out = $this -> OBMol -> GetConformers(); 259 break; 260 case 'data': 261 $out = new MoleculeData($this -> OBMol); 262 break; 263 case 'dim': 264 $out = $this -> OBMol -> GetDimension(); 265 break; 266 case 'energy': 267 $out = $this -> OBMol -> GetEnergy(); 268 break; 269 case 'exactmass': 270 $out = $this -> OBMol -> GetExactMass(); 271 break; 272 case 'formula': 273 $out = $this -> OBMol -> GetFormula(); 274 break; 275 case 'molwt': 276 $out = $this -> OBMol -> GetMolWt(); 277 break; 278 case 'spin': 279 $out = $this -> OBMol -> GetTotalSpinMultiplicity(); 280 break; 281 case 'sssr': 282 $out = vector2array($this -> OBMol -> GetSSSR()); 283 break; 284 case 'title': 285 $out = $this -> OBMol -> GetTitle(); 286 break; 287# case 'unitcell': 288# 289# break; 290 case '_exchange': 291 if($this -> OBMol -> HasNonZeroCoords()) { 292 return $this -> write('mol'); 293 } 294 else { 295 return preg_split('/[\t\s]+/', trim($this -> write('can')))[0]; 296 } 297 break; 298 } 299 return $out; 300 } 301 302 public function __set($name, $value) { 303 switch($name) { 304 case 'title': 305 $out = $this -> OBMol -> SetTitle($value); 306 break; 307 } 308 return $out; 309 } 310 311 # iterator part 312 public function rewind() { 313 $this->position = 0; 314 # generate atoms 315 $this-> __get('atoms'); 316 } 317 318 public function current() { 319 return $this->atoms[$this->position]; 320 } 321 322 public function key() { 323 return $this->position; 324 } 325 326 public function next() { 327 $this->position++; 328 } 329 330 public function valid() { 331 return isset($this->atoms[$this->position]); 332 } 333 # end iterator 334 335 public function calcdesc($descnames = array()) { 336 global $descs, $_descdict; 337 if(empty($descnames)) { 338 $descnames = $descs; 339 } 340 foreach($descnames as $descname) { 341 if(isset($_descdict[$descname])) { 342 $out[$descname] = $_descdict[$descname] -> Predict($this -> OBMol); 343 } 344 else { 345 throw new \Exception($descname.' is not recognised Open Babel descriptor type'); 346 } 347 } 348 return $out; 349 } 350 351 public function calcfp($fptype="FP2") { 352 global $_fingerprinters; 353 $fp = new \vectorUnsignedInt; 354 $fptype = strtolower($fptype); 355 if(isset($_fingerprinters[$fptype])) { 356 $fingerprinter = $_fingerprinters[$fptype]; 357 $fingerprinter -> GetFingerprint($this -> OBMol, $fp); 358 return new Fingerprint($fp); 359 } 360 else { 361 throw new \Exception($fptype.' is not a recognised Open Babel Fingerprint type'); 362 } 363 } 364 365 public function __toString() { 366 return $this -> write(); 367 } 368 369 public function write($format = 'smi', $filename = null, $overwrite = false, $opt = array()) { 370 $OBConversion = new \OBConversion; 371 $OBConversion -> SetOutFormat($format); 372 # set options 373 if(!empty($opt)) { 374 foreach($opt as $k => $v) { 375 if($v === null) { 376 $OBConversion -> AddOption($k, $OBConversion::OUTOPTIONS, $v); 377 } 378 else { 379 $OBConversion -> AddOption($k, $OBConversion::OUTOPTIONS); 380 } 381 } 382 } 383 384 if(!empty($filename)) { 385 if(!file_exists($filename) || file_exists($filename) && $overwrite) { 386 return $OBConversion->WriteFile($this -> OBMol, $filename); 387 } 388 } 389 else { 390 return $OBConversion->WriteString($this -> OBMol); 391 } 392 } 393 394 public function localopt($forcefield = 'mmff94', $steps = 50) { 395 global $_forcefields; 396 $forcefield = strtolower($forcefield); 397 if($this -> dim != 3) { 398 $this -> make3D($forcefield); 399 } 400 $ff = $_forcefields[$forcefield]; 401 if(!$ff -> Setup($this -> OBMol)) { 402 return false; 403 } 404 $ff -> SteepestDescent($steps); 405 $ff -> GetCoordinates($this -> OBMol); 406 } 407 408 public function make3D($forcefield = 'mmff94', $steps = 50) { 409 global $_builder; 410 $forcefield = strtolower($forcefield); 411 $_builder -> Build($this -> OBMol); 412 $this -> addh(); 413 $this -> localopt($forcefield, $steps); 414 } 415 416 public function addh() { 417 $this -> OBMol -> AddHydrogens(); 418 } 419 420 public function removeh() { 421 $this -> OBMol -> DeleteHydrogens(); 422 } 423 424 public function convertdbonds() { 425 $this -> OBMol -> ConvertDativeBonds(); 426 } 427 428 public function draw() { 429 return $this -> write('svg'); 430 } 431} 432 433class Atom { 434 public function __construct($OBAtom) { 435 $this -> OBAtom = $OBAtom; 436 } 437 438 public function __get($name) { 439 switch($name) { 440 case 'coords': 441 $out = array($this -> OBAtom -> GetX(), $this -> OBAtom -> GetY(), $this -> OBAtom -> GetZ()); 442 break; 443 case 'atomicmass': 444 $out = $this -> OBAtom -> GetAtomicMass(); 445 break; 446 case 'atomicnum': 447 $out = $this -> OBAtom -> GetAtomicNum(); 448 break; 449 case 'cidx': 450 $out = $this -> OBAtom -> GetCIdx(); 451 break; 452 case 'coordidx': 453 $out = $this -> OBAtom -> GetCoordinateIdx(); 454 break; 455 case 'exactmass': 456 $out = $this -> OBAtom -> GetExactMass(); 457 break; 458 case 'formalcharge': 459 $out = $this -> OBAtom -> GetFormalCharge(); 460 break; 461 case 'heavyvalence': 462 $out = $this -> OBAtom -> GetHvyValence(); 463 break; 464 case 'heterovalence': 465 $out = $this -> OBAtom -> GetHeteroValence(); 466 break; 467 case 'hyb': 468 $out = $this -> OBAtom -> GetHyb(); 469 break; 470 case 'idx': 471 $out = $this -> OBAtom -> GetIdx(); 472 break; 473 case 'implicitvalence': 474 $out = $this -> OBAtom -> GetImplicitValence(); 475 break; 476 case 'isotope': 477 $out = $this -> OBAtom -> GetIsotope(); 478 break; 479 case 'partialcharge': 480 $out = $this -> OBAtom -> GetPartialCharge(); 481 break; 482 case 'residue': 483 $out = new Residue($this -> OBAtom -> GetResidue()); 484 break; 485 case 'spin': 486 $out = $this -> OBAtom -> GetSpinMultiplicity(); 487 break; 488 case 'type': 489 $out = $this -> OBAtom -> GetType(); 490 break; 491 case 'valence': 492 $out = $this -> OBAtom -> GetValence(); 493 break; 494 case 'vector': 495 $out = $this -> OBAtom -> GetVector(); 496 break; 497 } 498 return $out; 499 } 500 501 public function __toString() { 502 503 return 'Atom: '.$this -> atomicnum.' ('.$this -> coords[0] .', '.$this -> coords[1] .', '.$this -> coords[2] .')'; 504 } 505} 506 507class Residue { 508 private $atoms = array(); 509 510 public function __construct($OBResidue) { 511 $this -> OBResidue = $OBResidue; 512 } 513 514 public function __get($name) { 515 switch($name) { 516 case 'idx': 517 $out = $this -> OBResidue -> GetIdx(); 518 break; 519 case 'num': 520 $out = $this -> OBResidue -> GetNum(); 521 break; 522 case 'name': 523 $out = $this -> OBResidue -> GetName(); 524 break; 525 case 'atoms': 526 if(empty($this -> atoms)) { # generate atoms only once 527 $num = $this -> OBResidue -> GetNumAtoms(); 528 $iter = $this -> OBResidue -> BeginAtoms(); 529 $out[] = new Atom($this -> OBResidue -> BeginAtom($iter)); 530 for($i=0;$i<$num-1;$i++) { 531 $out[] = new Atom($this -> OBResidue -> NextAtom($iter)); 532 } 533 $this -> atoms = $out; 534 } 535 else { 536 $out = $this -> atoms; 537 } 538 break; 539 } 540 return $out; 541 } 542} 543 544function tanimoto($fp1, $fp2) { 545 return \OBFingerprint::Tanimoto($fp1 -> fp, $fp2 -> fp); 546} 547 548class Fingerprint { 549 public $fp = null; 550 551 public function __construct($fp) { 552 $this -> fp = $fp; 553 } 554 555 public function __toString() { 556 return implode(', ', vector2array($this -> fp)); 557 } 558} 559 560class Smarts { 561 private $obsmarts = null; 562 563 public function __construct($smartspattern) { 564 $this -> obsmarts = new \OBSmartsPattern; 565 if(!$this -> obsmarts -> Init($smartspattern)) { 566 throw new Exception('Invalid SMARTS pattern'); 567 } 568 } 569 570 public function findall($mol) { 571 $this -> obsmarts -> Match($mol -> OBMol); 572 foreach(vector2array($this -> obsmarts -> GetUMapList()) as $match) { 573 $out[] = vector2array($match); 574 } 575 return $out; 576 } 577} 578 579class MoleculeData { 580 private $_mol = null; 581 582 public function __construct($obmol) { 583 $this -> _mol = $obmol; 584 } 585 586 public function _data() { 587 $data = vector2array($this -> _mol -> GetData()); 588 foreach($data as $d) { 589 if(in_array($d -> GetDataType(), array(\openbabel::PairData, \openbabel::CommentData))) { 590 $out[] = \openbabel::toPairData($d); 591 592 } 593 } 594 return $out; 595 } 596 597 public function keys() { 598 foreach($this -> _data() as $d) { 599 $out[] = $d -> GetAttribute(); 600 } 601 return $out; 602 } 603 604 public function values() { 605 foreach($this -> _data() as $d) { 606 $out[] = $d -> GetValue(); 607 } 608 return $out; 609 } 610 611 public function items() { 612 foreach($this -> _data() as $d) { 613 $out[$d -> GetAttribute()] = $d -> GetValue(); 614 } 615 return $out; 616 } 617} 618?> 619