Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

# coding: utf-8 

# Copyright (c) Pymatgen Development Team. 

# Distributed under the terms of the MIT License. 

 

from __future__ import division, unicode_literals 

 

""" 

OpenBabel interface module, which opens up access to the hundreds of file 

formats supported by OpenBabel. Requires openbabel with python bindings to be 

installed. Please consult the 

`openbabel documentation <http://openbabel.org/wiki/Main_Page>`_. 

""" 

 

 

__author__ = "Shyue Ping Ong" 

__copyright__ = "Copyright 2012, The Materials Project" 

__version__ = "0.1" 

__maintainer__ = "Shyue Ping Ong" 

__email__ = "shyuep@gmail.com" 

__date__ = "Apr 28, 2012" 

 

from pymatgen.core.structure import Molecule 

from monty.dev import requires 

 

try: 

import openbabel as ob 

import pybel as pb 

except: 

pb = None 

ob = None 

 

 

class BabelMolAdaptor(object): 

""" 

Adaptor serves as a bridge between OpenBabel's Molecule and pymatgen's 

Molecule. 

""" 

 

@requires(pb and ob, 

"BabelMolAdaptor requires openbabel to be installed with " 

"Python bindings. Please get it at http://openbabel.org.") 

def __init__(self, mol): 

""" 

Initializes with pymatgen Molecule or OpenBabel"s OBMol. 

 

Args: 

mol: pymatgen's Molecule or OpenBabel OBMol 

""" 

if isinstance(mol, Molecule): 

if not mol.is_ordered: 

raise ValueError("OpenBabel Molecule only supports ordered " 

"molecules.") 

 

# For some reason, manually adding atoms does not seem to create 

# the correct OBMol representation to do things like force field 

# optimization. So we go through the indirect route of creating 

# an XYZ file and reading in that file. 

obmol = ob.OBMol() 

 

obmol = ob.OBMol() 

obmol.BeginModify() 

for site in mol: 

coords = [c for c in site.coords] 

atomno = site.specie.Z 

obatom = ob.OBAtom() 

obatom.thisown = 0 

obatom.SetAtomicNum(atomno) 

obatom.SetVector(*coords) 

obmol.AddAtom(obatom) 

del obatom 

obmol.ConnectTheDots() 

obmol.PerceiveBondOrders() 

obmol.SetTotalSpinMultiplicity(mol.spin_multiplicity) 

obmol.SetTotalCharge(mol.charge) 

obmol.Center() 

obmol.Kekulize() 

obmol.EndModify() 

self._obmol = obmol 

elif isinstance(mol, ob.OBMol): 

 

self._obmol = mol 

 

@property 

def pymatgen_mol(self): 

""" 

Returns pymatgen Molecule object. 

""" 

sp = [] 

coords = [] 

for atom in ob.OBMolAtomIter(self._obmol): 

sp.append(atom.GetAtomicNum()) 

coords.append([atom.GetX(), atom.GetY(), atom.GetZ()]) 

return Molecule(sp, coords) 

 

@property 

def openbabel_mol(self): 

""" 

Returns OpenBabel's OBMol. 

""" 

return self._obmol 

 

def localopt(self, forcefield='mmff94', steps=500): 

""" 

A wrapper to pybel's localopt method to optimize a Molecule. 

 

Args: 

forcefield: Default is mmff94. Options are 'gaff', 'ghemical', 

'mmff94', 'mmff94s', and 'uff'. 

steps: Default is 500. 

""" 

pbmol = pb.Molecule(self._obmol) 

pbmol.localopt(forcefield=forcefield, steps=steps) 

self._obmol = pbmol.OBMol 

 

@property 

def pybel_mol(self): 

""" 

Returns Pybel's Molecule object. 

""" 

return pb.Molecule(self._obmol) 

 

def write_file(self, filename, file_format="xyz"): 

""" 

Uses OpenBabel to output all supported formats. 

 

Args: 

filename: Filename of file to output 

file_format: String specifying any OpenBabel supported formats. 

""" 

mol = pb.Molecule(self._obmol) 

return mol.write(file_format, filename, overwrite=True) 

 

@staticmethod 

def from_file(filename, file_format="xyz"): 

""" 

Uses OpenBabel to read a molecule from a file in all supported formats. 

 

Args: 

filename: Filename of input file 

file_format: String specifying any OpenBabel supported formats. 

 

Returns: 

BabelMolAdaptor object 

""" 

mols = list(pb.readfile(str(file_format), str(filename))) 

return BabelMolAdaptor(mols[0].OBMol) 

 

@staticmethod 

def from_string(string_data, file_format="xyz"): 

""" 

Uses OpenBabel to read a molecule from a string in all supported 

formats. 

 

Args: 

string_data: String containing molecule data. 

file_format: String specifying any OpenBabel supported formats. 

 

Returns: 

BabelMolAdaptor object 

""" 

mols = pb.readstring(str(file_format), str(string_data)) 

return BabelMolAdaptor(mols.OBMol)