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# -*- coding: utf-8 -*- 

2# 

3# Copyright (c) 2017, the cclib development team 

4# 

5# This file is part of cclib (http://cclib.github.io) and is distributed under 

6# the terms of the BSD 3-Clause License. 

7 

8"""A writer for chemical markup language (CML) files.""" 

9 

10import xml.etree.ElementTree as ET 

11 

12from cclib.io import filewriter 

13from cclib.parser.utils import find_package 

14 

15_has_openbabel = find_package("openbabel") 

16 

17 

18class CML(filewriter.Writer): 

19 """A writer for chemical markup language (CML) files.""" 

20 

21 def __init__(self, ccdata, *args, **kwargs): 

22 """Initialize the CML writer object. 

23 

24 Inputs: 

25 ccdata - An instance of ccData, parsed from a logfile. 

26 """ 

27 

28 # Call the __init__ method of the superclass 

29 super(CML, self).__init__(ccdata, *args, **kwargs) 

30 

31 def generate_repr(self): 

32 """Generate the CML representation of the logfile data.""" 

33 

34 # Create the base molecule. 

35 molecule = ET.Element('molecule') 

36 d = { 

37 # Write the namespace directly. 

38 'xmlns': 'http://www.xml-cml.org/schema', 

39 } 

40 if self.jobfilename is not None: 

41 d['id'] = self.jobfilename 

42 _set_attrs(molecule, d) 

43 

44 # Form the listing of all the atoms present. 

45 atomArray = ET.SubElement(molecule, 'atomArray') 

46 if hasattr(self.ccdata, 'atomcoords') and hasattr(self.ccdata, 'atomnos'): 

47 elements = [self.pt.element[Z] for Z in self.ccdata.atomnos] 

48 for atomid in range(self.ccdata.natom): 

49 atom = ET.SubElement(atomArray, 'atom') 

50 x, y, z = self.ccdata.atomcoords[-1][atomid].tolist() 

51 d = { 

52 'id': 'a{}'.format(atomid + 1), 

53 'elementType': elements[atomid], 

54 'x3': '{:.10f}'.format(x), 

55 'y3': '{:.10f}'.format(y), 

56 'z3': '{:.10f}'.format(z), 

57 } 

58 _set_attrs(atom, d) 

59 

60 # Form the listing of all the bonds present. 

61 bondArray = ET.SubElement(molecule, 'bondArray') 

62 if _has_openbabel: 

63 for bc in self.bond_connectivities: 

64 bond = ET.SubElement(bondArray, 'bond') 

65 d = { 

66 'atomRefs2': 'a{} a{}'.format(bc[0] + 1, bc[1] + 1), 

67 'order': str(bc[2]), 

68 } 

69 _set_attrs(bond, d) 

70 

71 _indent(molecule) 

72 

73 return _tostring(molecule) 

74 

75 

76def _set_attrs(element, d): 

77 """Set all the key-value pairs from a dictionary as element 

78 attributes. 

79 """ 

80 for (k, v) in d.items(): 

81 element.set(k, v) 

82 return 

83 

84 

85def _indent(elem, level=0): 

86 """An in-place pretty-print indenter for XML.""" 

87 i = "\n" + (level * " ") 

88 if len(elem): 

89 if not elem.text or not elem.text.strip(): 

90 elem.text = i + " " 

91 if not elem.tail or not elem.tail.strip(): 

92 elem.tail = i 

93 for elem in elem: 

94 _indent(elem, level+1) 

95 if not elem.tail or not elem.tail.strip(): 

96 elem.tail = i 

97 else: 

98 if level and (not elem.tail or not elem.tail.strip()): 

99 elem.tail = i 

100 

101 

102def _tostring(element, xml_declaration=True, encoding='utf-8', method='xml'): 

103 """A reimplementation of tostring() found in ElementTree.""" 

104 class dummy: 

105 pass 

106 data = [] 

107 file = dummy() 

108 file.write = data.append 

109 ET.ElementTree(element).write(file, 

110 xml_declaration=xml_declaration, 

111 encoding=encoding, 

112 method=method) 

113 return b''.join(data).decode(encoding) 

114 

115 

116del find_package