Coverage for /builds/kinetik161/ase/ase/io/xsd.py: 69.28%

166 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-12-10 11:04 +0000

1import xml.etree.ElementTree as ET 

2from xml.dom import minidom 

3 

4import numpy as np 

5 

6from ase import Atoms 

7from ase.utils import writer 

8 

9 

10def read_xsd(fd): 

11 tree = ET.parse(fd) 

12 root = tree.getroot() 

13 

14 atomtreeroot = root.find('AtomisticTreeRoot') 

15 # if periodic system 

16 if atomtreeroot.find('SymmetrySystem') is not None: 

17 symmetrysystem = atomtreeroot.find('SymmetrySystem') 

18 mappingset = symmetrysystem.find('MappingSet') 

19 mappingfamily = mappingset.find('MappingFamily') 

20 system = mappingfamily.find('IdentityMapping') 

21 

22 coords = [] 

23 cell = [] 

24 formula = '' 

25 

26 for atom in system: 

27 if atom.tag == 'Atom3d': 

28 symbol = atom.get('Components') 

29 formula += symbol 

30 

31 xyz = atom.get('XYZ') 

32 if xyz: 

33 coord = [float(coord) for coord in xyz.split(',')] 

34 else: 

35 coord = [0.0, 0.0, 0.0] 

36 coords.append(coord) 

37 elif atom.tag == 'SpaceGroup': 

38 avec = [float(vec) for vec in atom.get('AVector').split(',')] 

39 bvec = [float(vec) for vec in atom.get('BVector').split(',')] 

40 cvec = [float(vec) for vec in atom.get('CVector').split(',')] 

41 

42 cell.append(avec) 

43 cell.append(bvec) 

44 cell.append(cvec) 

45 

46 atoms = Atoms(formula, cell=cell, pbc=True) 

47 atoms.set_scaled_positions(coords) 

48 return atoms 

49 # if non-periodic system 

50 elif atomtreeroot.find('Molecule') is not None: 

51 system = atomtreeroot.find('Molecule') 

52 

53 coords = [] 

54 formula = '' 

55 

56 for atom in system: 

57 if atom.tag == 'Atom3d': 

58 symbol = atom.get('Components') 

59 formula += symbol 

60 

61 xyz = atom.get('XYZ') 

62 coord = [float(coord) for coord in xyz.split(',')] 

63 coords.append(coord) 

64 

65 atoms = Atoms(formula, pbc=False) 

66 atoms.set_scaled_positions(coords) 

67 return atoms 

68 

69 

70def CPK_or_BnS(element): 

71 """Determine how atom is visualized""" 

72 if element in ['C', 'H', 'O', 'S', 'N']: 

73 visualization_choice = 'Ball and Stick' 

74 else: 

75 visualization_choice = 'CPK' 

76 return visualization_choice 

77 

78 

79def SetChild(parent, childname, props): 

80 Child = ET.SubElement(parent, childname) 

81 for key in props: 

82 Child.set(key, props[key]) 

83 return Child 

84 

85 

86def SetBasicChilds(): 

87 """ 

88 Basic property setup for Material Studio File 

89 """ 

90 XSD = ET.Element('XSD') 

91 XSD.set('Version', '6.0') 

92 

93 ATR = SetChild(XSD, 'AtomisticTreeRoot', dict( 

94 ID='1', 

95 NumProperties='40', 

96 NumChildren='1', 

97 )) 

98 SetChild(ATR, 'Property', dict( 

99 DefinedOn='ClassicalEnergyHolder', 

100 Name='AngleEnergy', 

101 Type='Double', 

102 )) 

103 SetChild(ATR, 'Property', dict( 

104 DefinedOn='ClassicalEnergyHolder', 

105 Name='BendBendEnergy', 

106 Type='Double', 

107 )) 

108 SetChild(ATR, 'Property', dict( 

109 DefinedOn='ClassicalEnergyHolder', 

110 Name='BendTorsionBendEnergy', 

111 Type='Double', 

112 )) 

113 SetChild(ATR, 'Property', dict( 

114 DefinedOn='ClassicalEnergyHolder', 

115 Name='BondEnergy', 

116 Type='Double', 

117 )) 

118 SetChild(ATR, 'Property', dict( 

119 DefinedOn='Atom', 

120 Name='EFGAsymmetry', 

121 Type='Double', 

122 )) 

123 SetChild(ATR, 'Property', dict( 

124 DefinedOn='Atom', 

125 Name='EFGQuadrupolarCoupling', 

126 Type='Double', 

127 )) 

128 SetChild(ATR, 'Property', dict( 

129 DefinedOn='ClassicalEnergyHolder', 

130 Name='ElectrostaticEnergy', 

131 Type='Double', 

132 )) 

133 SetChild(ATR, 'Property', dict( 

134 DefinedOn='GrowthFace', 

135 Name='FaceMillerIndex', 

136 Type='MillerIndex', 

137 )) 

138 SetChild(ATR, 'Property', dict( 

139 DefinedOn='GrowthFace', 

140 Name='FacetTransparency', 

141 Type='Float', 

142 )) 

143 SetChild(ATR, 'Property', dict( 

144 DefinedOn='Bondable', 

145 Name='Force', 

146 Type='CoDirection', 

147 )) 

148 SetChild(ATR, 'Property', dict( 

149 DefinedOn='ClassicalEnergyHolder', 

150 Name='HydrogenBondEnergy', 

151 Type='Double', 

152 )) 

153 SetChild(ATR, 'Property', dict( 

154 DefinedOn='Bondable', 

155 Name='ImportOrder', 

156 Type='UnsignedInteger', 

157 )) 

158 SetChild(ATR, 'Property', dict( 

159 DefinedOn='ClassicalEnergyHolder', 

160 Name='InversionEnergy', 

161 Type='Double', 

162 )) 

163 SetChild(ATR, 'Property', dict( 

164 DefinedOn='Atom', 

165 Name='IsBackboneAtom', 

166 Type='Boolean', 

167 )) 

168 SetChild(ATR, 'Property', dict( 

169 DefinedOn='Atom', 

170 Name='IsChiralCenter', 

171 Type='Boolean', 

172 )) 

173 SetChild(ATR, 'Property', dict( 

174 DefinedOn='Atom', 

175 Name='IsOutOfPlane', 

176 Type='Boolean', 

177 )) 

178 SetChild(ATR, 'Property', dict( 

179 DefinedOn='BestFitLineMonitor', 

180 Name='LineExtentPadding', 

181 Type='Double', 

182 )) 

183 SetChild(ATR, 'Property', dict( 

184 DefinedOn='Linkage', 

185 Name='LinkageGroupName', 

186 Type='String', 

187 )) 

188 SetChild(ATR, 'Property', dict( 

189 DefinedOn='PropertyList', 

190 Name='ListIdentifier', 

191 Type='String', 

192 )) 

193 SetChild(ATR, 'Property', dict( 

194 DefinedOn='Atom', 

195 Name='NMRShielding', 

196 Type='Double', 

197 )) 

198 SetChild(ATR, 'Property', dict( 

199 DefinedOn='ClassicalEnergyHolder', 

200 Name='NonBondEnergy', 

201 Type='Double', 

202 )) 

203 SetChild(ATR, 'Property', dict( 

204 DefinedOn='Bondable', 

205 Name='NormalMode', 

206 Type='Direction', 

207 )) 

208 SetChild(ATR, 'Property', dict( 

209 DefinedOn='Bondable', 

210 Name='NormalModeFrequency', 

211 Type='Double', 

212 )) 

213 SetChild(ATR, 'Property', dict( 

214 DefinedOn='Bondable', 

215 Name='OrbitalCutoffRadius', 

216 Type='Double', 

217 )) 

218 SetChild(ATR, 'Property', dict( 

219 DefinedOn='BestFitPlaneMonitor', 

220 Name='PlaneExtentPadding', 

221 Type='Double', 

222 )) 

223 SetChild(ATR, 'Property', dict( 

224 DefinedOn='ClassicalEnergyHolder', 

225 Name='PotentialEnergy', 

226 Type='Double', 

227 )) 

228 SetChild(ATR, 'Property', dict( 

229 DefinedOn='ScalarFieldBase', 

230 Name='QuantizationValue', 

231 Type='Double', 

232 )) 

233 SetChild(ATR, 'Property', dict( 

234 DefinedOn='ClassicalEnergyHolder', 

235 Name='RestraintEnergy', 

236 Type='Double', 

237 )) 

238 SetChild(ATR, 'Property', dict( 

239 DefinedOn='ClassicalEnergyHolder', 

240 Name='SeparatedStretchStretchEnergy', 

241 Type='Double', 

242 )) 

243 SetChild(ATR, 'Property', dict( 

244 DefinedOn='Trajectory', 

245 Name='SimulationStep', 

246 Type='Integer', 

247 )) 

248 SetChild(ATR, 'Property', dict( 

249 DefinedOn='ClassicalEnergyHolder', 

250 Name='StretchBendStretchEnergy', 

251 Type='Double', 

252 )) 

253 SetChild(ATR, 'Property', dict( 

254 DefinedOn='ClassicalEnergyHolder', 

255 Name='StretchStretchEnergy', 

256 Type='Double', 

257 )) 

258 SetChild(ATR, 'Property', dict( 

259 DefinedOn='ClassicalEnergyHolder', 

260 Name='StretchTorsionStretchEnergy', 

261 Type='Double', 

262 )) 

263 SetChild(ATR, 'Property', dict( 

264 DefinedOn='ClassicalEnergyHolder', 

265 Name='TorsionBendBendEnergy', 

266 Type='Double', 

267 )) 

268 SetChild(ATR, 'Property', dict( 

269 DefinedOn='ClassicalEnergyHolder', 

270 Name='TorsionEnergy', 

271 Type='Double', 

272 )) 

273 SetChild(ATR, 'Property', dict( 

274 DefinedOn='ClassicalEnergyHolder', 

275 Name='TorsionStretchEnergy', 

276 Type='Double', 

277 )) 

278 SetChild(ATR, 'Property', dict( 

279 DefinedOn='ClassicalEnergyHolder', 

280 Name='ValenceCrossTermEnergy', 

281 Type='Double', 

282 )) 

283 SetChild(ATR, 'Property', dict( 

284 DefinedOn='ClassicalEnergyHolder', 

285 Name='ValenceDiagonalEnergy', 

286 Type='Double', 

287 )) 

288 SetChild(ATR, 'Property', dict( 

289 DefinedOn='ClassicalEnergyHolder', 

290 Name='VanDerWaalsEnergy', 

291 Type='Double', 

292 )) 

293 SetChild(ATR, 'Property', dict( 

294 DefinedOn='SymmetrySystem', 

295 Name='_Stress', 

296 Type='Matrix', 

297 )) 

298 return ATR, XSD 

299 

300 

301def _write_xsd_html(images, connectivity=None): 

302 ATR, XSD = SetBasicChilds() 

303 natoms = len(images[0]) 

304 atom_element = images[0].get_chemical_symbols() 

305 atom_cell = images[0].get_cell() 

306 atom_positions = images[0].get_positions() 

307 # Set up bonds 

308 bonds = [] 

309 if connectivity is not None: 

310 for i in range(connectivity.shape[0]): 

311 for j in range(i + 1, connectivity.shape[0]): 

312 if connectivity[i, j]: 

313 bonds.append([i, j]) 

314 nbonds = len(bonds) 

315 

316 # non-periodic system 

317 if not images[0].pbc.all(): 

318 Molecule = SetChild(ATR, 'Molecule', dict( 

319 ID='2', 

320 NumChildren=str(natoms + nbonds), 

321 Name='Lattice=&quot1.0', 

322 )) 

323 # writing images[0] 

324 for x in range(natoms): 

325 Props = dict( 

326 ID=str(x + 3), 

327 Name=(atom_element[x] + str(x + 1)), 

328 UserID=str(x + 1), 

329 DisplayStyle=CPK_or_BnS(atom_element[x]), 

330 XYZ=','.join('%1.16f' % xi for xi in atom_positions[x]), 

331 Components=atom_element[x], 

332 ) 

333 bondstr = [] 

334 for i, bond in enumerate(bonds): 

335 if x in bond: 

336 bondstr.append(str(i + 3 + natoms)) 

337 if bondstr: 

338 Props['Connections'] = ','.join(bondstr) 

339 SetChild(Molecule, 'Atom3d', Props) 

340 for x in range(nbonds): 

341 SetChild(Molecule, 'Bond', dict( 

342 ID=str(x + 3 + natoms), 

343 Connects='%i,%i' % (bonds[x][0] + 3, bonds[x][1] + 3), 

344 )) 

345 # periodic system 

346 else: 

347 atom_positions = np.dot(atom_positions, np.linalg.inv(atom_cell)) 

348 Props = dict( 

349 ID='2', 

350 Mapping='3', 

351 Children=','.join(map(str, range(4, natoms + nbonds + 5))), 

352 Normalized='1', 

353 Name='SymmSys', 

354 UserID=str(natoms + 18), 

355 XYZ='0.00000000000000,0.00000000000000,0.000000000000000', 

356 OverspecificationTolerance='0.05', 

357 PeriodicDisplayType='Original', 

358 ) 

359 SymmSys = SetChild(ATR, 'SymmetrySystem', Props) 

360 

361 Props = dict( 

362 ID=str(natoms + nbonds + 5), 

363 SymmetryDefinition=str(natoms + 4), 

364 ActiveSystem='2', 

365 NumFamilies='1', 

366 OwnsTotalConstraintMapping='1', 

367 TotalConstraintMapping='3', 

368 ) 

369 MappngSet = SetChild(SymmSys, 'MappingSet', Props) 

370 

371 Props = dict(ID=str(natoms + nbonds + 6), NumImageMappings='0') 

372 MappngFamily = SetChild(MappngSet, 'MappingFamily', Props) 

373 

374 Props = dict( 

375 ID=str(natoms + len(bonds) + 7), 

376 Element='1,0,0,0,0,1,0,0,0,0,1,0', 

377 Constraint='1,0,0,0,0,1,0,0,0,0,1,0', 

378 MappedObjects=','.join(map(str, range(4, natoms + len(bonds) + 4))), 

379 DefectObjects='%i,%i' % (natoms + nbonds + 4, natoms + nbonds + 8), 

380 NumImages=str(natoms + len(bonds)), 

381 NumDefects='2', 

382 ) 

383 IdentMappng = SetChild(MappngFamily, 'IdentityMapping', Props) 

384 

385 SetChild(MappngFamily, 'MappingRepairs', {'NumRepairs': '0'}) 

386 

387 # writing atoms 

388 for x in range(natoms): 

389 Props = dict( 

390 ID=str(x + 4), 

391 Mapping=str(natoms + len(bonds) + 7), 

392 Parent='2', 

393 Name=(atom_element[x] + str(x + 1)), 

394 UserID=str(x + 1), 

395 DisplayStyle=CPK_or_BnS(atom_element[x]), 

396 Components=atom_element[x], 

397 XYZ=','.join(['%1.16f' % xi for xi in atom_positions[x]]), 

398 ) 

399 bondstr = [] 

400 for i, bond in enumerate(bonds): 

401 if x in bond: 

402 bondstr.append(str(i + 4 * natoms + 1)) 

403 if bondstr: 

404 Props['Connections'] = ','.join(bondstr) 

405 SetChild(IdentMappng, 'Atom3d', Props) 

406 

407 for x in range(len(bonds)): 

408 SetChild(IdentMappng, 'Bond', dict( 

409 ID=str(x + 4 + natoms + 1), 

410 Mapping=str(natoms + len(bonds) + 7), 

411 Parent='2', 

412 Connects='%i,%i' % (bonds[x][0] + 4, bonds[x][1] + 4), 

413 )) 

414 

415 Props = dict( 

416 ID=str(natoms + 4), 

417 Parent='2', 

418 Children=str(natoms + len(bonds) + 8), 

419 DisplayStyle='Solid', 

420 XYZ='0.00,0.00,0.00', 

421 Color='0,0,0,0', 

422 AVector=','.join(['%1.16f' % atom_cell[0, x] for x in range(3)]), 

423 BVector=','.join(['%1.16f' % atom_cell[1, x] for x in range(3)]), 

424 CVector=','.join(['%1.16f' % atom_cell[2, x] for x in range(3)]), 

425 OrientationBase='C along Z, B in YZ plane', 

426 Centering='3D Primitive-Centered', 

427 Lattice='3D Triclinic', 

428 GroupName='GroupName', 

429 Operators='1,0,0,0,0,1,0,0,0,0,1,0', 

430 DisplayRange='0,1,0,1,0,1', 

431 LineThickness='2', 

432 CylinderRadius='0.2', 

433 LabelAxes='1', 

434 ActiveSystem='2', 

435 ITNumber='1', 

436 LongName='P 1', 

437 Qualifier='Origin-1', 

438 SchoenfliesName='C1-1', 

439 System='Triclinic', 

440 Class='1', 

441 ) 

442 SetChild(IdentMappng, 'SpaceGroup', Props) 

443 

444 SetChild(IdentMappng, 'ReciprocalLattice3D', dict( 

445 ID=str(natoms + len(bonds) + 8), 

446 Parent=str(natoms + 4), 

447 )) 

448 

449 SetChild(MappngSet, 'InfiniteMapping', dict( 

450 ID='3', 

451 Element='1,0,0,0,0,1,0,0,0,0,1,0', 

452 MappedObjects='2', 

453 )) 

454 

455 return XSD, ATR 

456 

457 

458@writer 

459def write_xsd(fd, images, connectivity=None): 

460 """Takes Atoms object, and write materials studio file 

461 atoms: Atoms object 

462 filename: path of the output file 

463 connectivity: number of atoms by number of atoms matrix for connectivity 

464 between atoms (0 not connected, 1 connected) 

465 

466 note: material studio file cannot use a partial periodic system. If partial 

467 perodic system was inputted, full periodicity was assumed. 

468 """ 

469 if hasattr(images, 'get_positions'): 

470 images = [images] 

471 

472 XSD, ATR = _write_xsd_html(images, connectivity) 

473 

474 # Return a pretty-printed XML string for the Element. 

475 rough_string = ET.tostring(XSD, 'utf-8') 

476 reparsed = minidom.parseString(rough_string) 

477 Document = reparsed.toprettyxml(indent='\t') 

478 

479 fd.write(Document)