| // +----------------------------------------------------------------------+ // // $Id$ // require_once "Science/Chemistry.php"; require_once "Science/Chemistry/Atom.php"; /** * Base class representing a Molecule * * @author Jesus M. Castagnetto * @version 1.0 * @access public * @package Science_Chemistry */ class Science_Chemistry_Molecule { /** * Molecule name * * @var string * @access public */ var $name = ""; /** * Number of atoms in the molecule * * @var integer * @access public * @see initMolecule() */ var $num_atoms = 0; /** * Array of atom objects in the molecule * * @var array * @access private * @see initMolecule() */ var $atoms = array(); /** * Atom-Atom distance matrix * * @var array * @access private * @see calcDistanceMatrix() */ var $dist_matrix = array(); /** * Atom-Atom connection (bond) table * * @var array * @access private * @see calcConnectionTable() */ var $conn_table = array(); /** * Distance cutoff for bond estimation * * @var float * @access private * @see setBondCutoff() * @see getBondCutoff() * @see calcConnectionTable() */ var $BONDCUTOFF = 1.8; /** * Constructor for the class, requires a molecule name * and an optional array of Science_Chemistry_Atom objects * * @param string $name * @param optional array $atoms * @return object Science_Chemistry_Molecule * @access public * @see $name * @see initMolecule() */ function Science_Chemistry_Molecule($name, $atoms="") { if ($name) $this->name = $name; else return null; if ($atoms && is_array($atoms)) if (!$this->initMolecule($atoms)) return null; } /** * Initializes the array of Science_Chemistry_Atom objects * * @param array $atoms * @return boolean * @access public * @see $num_atoms * @see $atoms * @see addAtom() */ function initMolecule($atoms) { if (is_array($atoms)) { for ($i=0; $i=count($atoms); $i++) { if (!$this->addAtom($atoms[$i])) return false; } return true; } else { return false; } } /** * Adds a Science_Chemistry_Atom object to the list of atoms in the molecule * * @param object Science_Chemistry_Atom $atom * @return boolean * @access public * @see initMolecule() */ function addAtom($atom) { if (Science_Chemistry_Atom::isAtom($atom)) { $this->atoms[] = $atom; $this->num_atoms++; // unset the distance matrix and // connection table if they are not empty // so next time either one is requested // it gets calculated anew if (!empty($this->dist_matrix)) $this->dist_matrix = array(); if (!empty($this->conn_table)) $this->conn_table = array(); return true; } else { return false; } } /** * Returns an array of Atom objects * * @return array * @access public * @see $atoms */ function getAtoms() { return $this->atoms; } /** * Checks if the object is an instance of Science_Chemistry_Molecule * * @param object Science_Chemistry_Molecule $obj * @return boolean * @access public */ function isMolecule($obj) { return (is_object($obj) && (strtolower(strtolower(get_class($obj))) == strtolower("Science_Chemistry_Molecule") || is_subclass_of($obj, strtolower("Science_Chemistry_Molecule"))) ); } /** * Returns a string representation of the molecule as a XYZ-format file * Alias of toXYZ() * * @return string * @access public * @see toXYZ() */ function toString() { return $this->toXYZ(); } /** * Returns a string representation of the molecule as a XYZ-format file * * @return string * @access public * @see toString() */ function toXYZ() { if (!$this->atoms) return false; $out[] = $this->num_atoms; $out[] = $this->name; reset($this->atoms); for ($i=0; $i<$this->num_atoms; $i++) $out[] = $this->atoms[$i]->toString(); return implode("\n",$out)."\n"; } /** * Returns a CML representation of the molecule * Accepts an optional id, and a flag to signal * printing of the connection table * * @param optional string $id * @param optional boolean $connect * @return string * @access public */ function toCML($title="molecule", $id="mol1", $connect=false) { $out = " \n"; $out .= " ".$this->name."\n"; $out .= " \n"; for ($i=0; $i<$this->num_atoms; $i++) $out .= $this->atoms[$i]->toCML($i+1); $out .= " \n"; if ($connect) { // calculate the connection table if needed // and short-circuit if we cannot do that if (empty($this->conn_table)) if (!$this->calcConnectionTable()) { $out .= " \n"; return $out; } $out .= " \n"; for ($i=0; $i < count($this->conn_table); $i++) { $tmp = array(); foreach ($this->conn_table[$i] as $atomid=>$flag) { if ($flag) $tmp[] = $atomid + 1; } if (!empty($tmp)) { $out .= " "; $out .= implode(" ", $tmp)."\n"; } } $out .= " \n"; } $out .= " \n"; return $out; } /** * Sets the distance cutoff for bond determination * * @param float $cutoff * @return boolean * @access public * @see $BONDCUTOFF * @see getBondCutoff() * @see calcConnectionTable() */ function setBondCutoff($cutoff) { if ((float)$cutoff > 0.0) { $this->BONDCUTOFF = (float)$cutoff; return true; } else { return false; } } /** * Returns the bond cutoff uses to determine bonds * * @return float * @access public * @see $BONDCUTOFF * @see setBondCutoff() * @see calcConnectionTable() */ function getBondCutoff() { return $this->BONDCUTOFF; } /** * Calculates the atom-atom distance matrix in Angstroms * * @return boolean * @access public */ function calcDistanceMatrix() { if (empty($this->atoms)) return false; $this->dist_matrix = array(); for ($i=0; $i < $this->num_atoms; $i++) for ($j=0; $j < $this->num_atoms; $j++) { if ($i == $j) { $this->dist_matrix[$i][$j] = 0.0; } elseif ($i < $j) { $this->dist_matrix[$i][$j] = $this->atoms[$i]->distance($this->atoms[$j]); } } return true; } /** * Prints the atom-atom distance matrix * * @return string * @access public */ function printDistanceMatrix() { if (empty($this->dist_matrix)) if(!$this->calcDistanceMatrix()) return false; $dmat = &$this->dist_matrix; echo "# Atom-Atom Distance Matrix:\n"; for ($i=0; $i < $this->num_atoms; $i++) echo "\t".($i+1); for ($i=0; $i < $this->num_atoms; $i++) { echo "\n".($i+1); for ($j=0; $j < $this->num_atoms; $j++) if (!isset($dmat[$i][$j])) { echo "\t"; } else { printf("\t%.4f",$dmat[$i][$j]); } } echo "\n"; return true; } /** * Returns the atom-atom distance matrix * * @return array * @access public */ function getDistanceMatrix() { if (empty($this->dist_matrix)) if (!$this->calcDistanceMatrix()) return false; return $this->dist_matrix; } /** * Calculates the connection table for the molecule * * @return boolean * @access public */ function calcConnectionTable(){ if (empty($this->dist_matrix)) if (!$this->calcDistanceMatrix()) return false; $dmat = &$this->dist_matrix; for ($i=0; $i < $this->num_atoms; $i++) for ($j=($i+1); $j < $this->num_atoms; $j++) $this->conn_table[$i][$j] = ($dmat[$i][$j] <= $this->BONDCUTOFF); return true; } /** * Prints the molecule's connection table * * @return boolean * @access public */ function printConnectionTable() { if (empty($this->conn_table)) if (!$this->calcConnectionTable()) return false; printf("# Connection Table: (cutoff = %.4f Angstroms)\n", $this->BONDCUTOFF); for ($i=0; $i < $this->num_atoms; $i++) for ($j=($i+1); $j < $this->num_atoms; $j++) if ($this->conn_table[$i][$j]) { echo $this->atoms[$i]->element.($i+1)."\t"; echo $this->atoms[$j]->element.($j+1)."\n"; } return true; } /** * Returns an array of connected atoms and their bond distance * e.g. array ( array ($atomobj1, $atomobj2, $distance ), ... ) * * @return array * @access public */ function getConnectionTable() { if (empty($this->conn_table)) if (!$this->calcConnectionTable()) return false; $ct = 0; $ctable=array(); for ($i=0; $i < $this->num_atoms; $i++) for ($j=($i+1); $j < $this->num_atoms; $j++) if ($this->conn_table[$i][$j]) { $ctable[$ct] = array ($this->atoms[$i], $this->atoms[$j], $this->dist_matrix[$i][$j]); $ct++; } return $ctable; } } // end of class Science_Chemistry_Molecule // vim: expandtab: ts=4: sw=4 ?>