Coverage for /builds/ase/ase/ase/phasediagram.py: 68.38%

370 statements  

« prev     ^ index     » next       coverage.py v7.5.3, created at 2025-08-02 00:12 +0000

1# fmt: off 

2 

3import fractions 

4import functools 

5import re 

6from collections import OrderedDict 

7from typing import Dict, List, Tuple 

8 

9import numpy as np 

10from scipy.spatial import ConvexHull 

11 

12import ase.units as units 

13from ase.formula import Formula 

14from ase.utils import deprecated 

15 

16_solvated: List[Tuple[str, Dict[str, int], float, bool, float]] = [] 

17 

18 

19def parse_formula(formula): 

20 aq = formula.endswith('(aq)') 

21 if aq: 

22 formula = formula[:-4] 

23 charge = formula.count('+') - formula.count('-') 

24 if charge: 

25 formula = formula.rstrip('+-') 

26 count = Formula(formula).count() 

27 return count, charge, aq 

28 

29 

30def float2str(x): 

31 f = fractions.Fraction(x).limit_denominator(100) 

32 n = f.numerator 

33 d = f.denominator 

34 if abs(n / d - f) > 1e-6: 

35 return f'{f:.3f}' 

36 if d == 0: 

37 return '0' 

38 if f.denominator == 1: 

39 return str(n) 

40 return f'{f.numerator}/{f.denominator}' 

41 

42 

43def solvated(symbols): 

44 """Extract solvation energies from database. 

45 

46 symbols: str 

47 Extract only those molecules that contain the chemical elements 

48 given by the symbols string (plus water and H+). 

49 

50 Data from: 

51 

52 Johnson JW, Oelkers EH, Helgeson HC (1992) 

53 Comput Geosci 18(7):899. 

54 doi:10.1016/0098-3004(92)90029-Q 

55 

56 and: 

57 

58 Pourbaix M (1966) 

59 Atlas of electrochemical equilibria in aqueous solutions. 

60 No. v. 1 in Atlas of Electrochemical Equilibria in Aqueous Solutions. 

61 Pergamon Press, New York. 

62 

63 Returns list of (name, energy) tuples. 

64 """ 

65 

66 if isinstance(symbols, str): 

67 symbols = Formula(symbols).count().keys() 

68 if len(_solvated) == 0: 

69 for line in _aqueous.splitlines(): 

70 energy, formula = line.split(',') 

71 name = formula + '(aq)' 

72 count, charge, aq = parse_formula(name) 

73 energy = float(energy) * 0.001 * units.kcal / units.mol 

74 _solvated.append((name, count, charge, aq, energy)) 

75 references = [] 

76 for name, count, charge, aq, energy in _solvated: 

77 for symbol in count: 

78 if symbol not in 'HO' and symbol not in symbols: 

79 break 

80 else: 

81 references.append((name, energy)) 

82 return references 

83 

84 

85def bisect(A, X, Y, f): 

86 a = [] 

87 for i in [0, -1]: 

88 for j in [0, -1]: 

89 if A[i, j] == -1: 

90 A[i, j] = f(X[i], Y[j]) 

91 a.append(A[i, j]) 

92 

93 if np.ptp(a) == 0: 

94 A[:] = a[0] 

95 return 

96 if a[0] == a[1]: 

97 A[0] = a[0] 

98 if a[1] == a[3]: 

99 A[:, -1] = a[1] 

100 if a[3] == a[2]: 

101 A[-1] = a[3] 

102 if a[2] == a[0]: 

103 A[:, 0] = a[2] 

104 if not (A == -1).any(): 

105 return 

106 i = len(X) // 2 

107 j = len(Y) // 2 

108 bisect(A[:i + 1, :j + 1], X[:i + 1], Y[:j + 1], f) 

109 bisect(A[:i + 1, j:], X[:i + 1], Y[j:], f) 

110 bisect(A[i:, :j + 1], X[i:], Y[:j + 1], f) 

111 bisect(A[i:, j:], X[i:], Y[j:], f) 

112 

113 

114def print_results(results): 

115 total_energy = 0.0 

116 print('reference coefficient energy') 

117 print('------------------------------------') 

118 for name, coef, energy in results: 

119 total_energy += coef * energy 

120 if abs(coef) < 1e-7: 

121 continue 

122 print(f'{name:14}{float2str(coef):>10}{energy:12.3f}') 

123 print('------------------------------------') 

124 print(f'Total energy: {total_energy:22.3f}') 

125 print('------------------------------------') 

126 

127 

128class Pourbaix: 

129 @deprecated( 

130 'Use ase.pourbaix.Pourbaix. ' 

131 'This class will be removed in a future version of ASE.') 

132 def __init__(self, references, formula=None, T=300.0, **kwargs): 

133 """Pourbaix object. 

134 

135 references: list of (name, energy) tuples 

136 Examples of names: ZnO2, H+(aq), H2O(aq), Zn++(aq), ... 

137 formula: str 

138 Stoichiometry. Example: ``'ZnO'``. Can also be given as 

139 keyword arguments: ``Pourbaix(refs, Zn=1, O=1)``. 

140 T: float 

141 Temperature in Kelvin. 

142 

143 .. deprecated:: 3.24.0 

144 """ 

145 

146 if formula: 

147 assert not kwargs 

148 kwargs = parse_formula(formula)[0] 

149 

150 if 'O' not in kwargs: 

151 kwargs['O'] = 0 

152 if 'H' not in kwargs: 

153 kwargs['H'] = 0 

154 

155 self.kT = units.kB * T 

156 self.references = [] 

157 for name, energy in references: 

158 if name == 'O': 

159 continue 

160 count, charge, aq = parse_formula(name) 

161 if all(symbol in kwargs for symbol in count): 

162 self.references.append((count, charge, aq, energy, name)) 

163 

164 self.references.append(({}, -1, False, 0.0, 'e-')) # an electron 

165 

166 self.count = kwargs 

167 

168 self.N = {'e-': 0} 

169 for symbol in kwargs: 

170 if symbol not in self.N: 

171 self.N[symbol] = len(self.N) 

172 

173 def decompose(self, U, pH, verbose=True, concentration=1e-6): 

174 """Decompose material. 

175 

176 U: float 

177 Potential in V. 

178 pH: float 

179 pH value. 

180 verbose: bool 

181 Default is True. 

182 concentration: float 

183 Concentration of solvated references. 

184 

185 Returns optimal coefficients and energy: 

186 

187 >>> from ase.phasediagram import Pourbaix, solvated 

188 >>> refs = solvated('CoO') + [ 

189 ... ('Co', 0.0), 

190 ... ('CoO', -2.509), 

191 ... ('Co3O4', -9.402)] 

192 >>> pb = Pourbaix(refs, Co=3, O=4) 

193 >>> coefs, energy = pb.decompose(U=1.5, pH=0, 

194 ... concentration=1e-6, 

195 ... verbose=True) 

196 0 HCoO2-(aq) -3.974 

197 1 CoO2--(aq) -3.098 

198 2 H2O(aq) -2.458 

199 3 CoOH+(aq) -2.787 

200 4 CoO(aq) -2.265 

201 5 CoOH++(aq) -1.355 

202 6 Co++(aq) -0.921 

203 7 H+(aq) 0.000 

204 8 Co+++(aq) 1.030 

205 9 Co 0.000 

206 10 CoO -2.509 

207 11 Co3O4 -9.402 

208 12 e- -1.500 

209 reference coefficient energy 

210 ------------------------------------ 

211 H2O(aq) 4 -2.458 

212 Co++(aq) 3 -0.921 

213 H+(aq) -8 0.000 

214 e- -2 -1.500 

215 ------------------------------------ 

216 Total energy: -9.596 

217 ------------------------------------ 

218 """ 

219 

220 alpha = np.log(10) * self.kT 

221 entropy = -np.log(concentration) * self.kT 

222 

223 # We want to minimize np.dot(energies, x) under the constraints: 

224 # 

225 # np.dot(x, eq2) == eq1 

226 # 

227 # with bounds[i,0] <= x[i] <= bounds[i, 1]. 

228 # 

229 # First two equations are charge and number of hydrogens, and 

230 # the rest are the remaining species. 

231 

232 eq1 = [0] + list(self.count.values()) 

233 eq2 = [] 

234 energies = [] 

235 bounds = [] 

236 names = [] 

237 for count, charge, aq, energy, name in self.references: 

238 eq = np.zeros(len(self.N)) 

239 eq[0] = charge 

240 for symbol, n in count.items(): 

241 eq[self.N[symbol]] = n 

242 eq2.append(eq) 

243 if name in ['H2O(aq)', 'H+(aq)', 'e-']: 

244 bounds.append((-np.inf, np.inf)) 

245 if name == 'e-': 

246 energy = -U 

247 elif name == 'H+(aq)': 

248 energy = -pH * alpha 

249 else: 

250 bounds.append((0, np.inf)) 

251 if aq: 

252 energy -= entropy 

253 if verbose: 

254 print('{:<5}{:10}{:10.3f}'.format(len(energies), 

255 name, energy)) 

256 energies.append(energy) 

257 names.append(name) 

258 

259 from scipy.optimize import linprog 

260 

261 result = linprog(c=energies, 

262 A_eq=np.transpose(eq2), 

263 b_eq=eq1, 

264 bounds=bounds) 

265 

266 if verbose: 

267 print_results(zip(names, result.x, energies)) 

268 

269 return result.x, result.fun 

270 

271 def diagram(self, U, pH, plot=True, show=False, ax=None): 

272 """Calculate Pourbaix diagram. 

273 

274 U: list of float 

275 Potentials in V. 

276 pH: list of float 

277 pH values. 

278 plot: bool 

279 Create plot. 

280 show: bool 

281 Open graphical window and show plot. 

282 ax: matplotlib axes object 

283 When creating plot, plot onto the given axes object. 

284 If none given, plot onto the current one. 

285 """ 

286 a = np.empty((len(U), len(pH)), int) 

287 a[:] = -1 

288 colors = {} 

289 f = functools.partial(self.colorfunction, colors=colors) 

290 bisect(a, U, pH, f) 

291 compositions = [None] * len(colors) 

292 names = [ref[-1] for ref in self.references] 

293 for indices, color in colors.items(): 

294 compositions[color] = ' + '.join(names[i] for i in indices 

295 if names[i] not in 

296 ['H2O(aq)', 'H+(aq)', 'e-']) 

297 text = [] 

298 for i, name in enumerate(compositions): 

299 b = (a == i) 

300 x = np.dot(b.sum(1), U) / b.sum() 

301 y = np.dot(b.sum(0), pH) / b.sum() 

302 name = re.sub(r'(\S)([+-]+)', r'\1$^{\2}$', name) 

303 name = re.sub(r'(\d+)', r'$_{\1}$', name) 

304 text.append((x, y, name)) 

305 

306 if plot: 

307 import matplotlib.cm as cm 

308 import matplotlib.pyplot as plt 

309 if ax is None: 

310 ax = plt.gca() 

311 

312 # rasterized pcolormesh has a bug which leaves a tiny 

313 # white border. Unrasterized pcolormesh produces 

314 # unreasonably large files. Avoid this by using the more 

315 # general imshow. 

316 ax.imshow(a, cmap=cm.Accent, 

317 extent=[min(pH), max(pH), min(U), max(U)], 

318 origin='lower', 

319 aspect='auto') 

320 

321 for x, y, name in text: 

322 ax.text(y, x, name, horizontalalignment='center') 

323 ax.set_xlabel('pH') 

324 ax.set_ylabel('potential [V]') 

325 ax.set_xlim(min(pH), max(pH)) 

326 ax.set_ylim(min(U), max(U)) 

327 if show: 

328 plt.show() 

329 

330 return a, compositions, text 

331 

332 def colorfunction(self, U, pH, colors): 

333 coefs, _energy = self.decompose(U, pH, verbose=False) 

334 indices = tuple(sorted(np.where(abs(coefs) > 1e-3)[0])) 

335 color = colors.get(indices) 

336 if color is None: 

337 color = len(colors) 

338 colors[indices] = color 

339 return color 

340 

341 

342class PhaseDiagram: 

343 def __init__(self, references, filter='', verbose=True): 

344 """Phase-diagram. 

345 

346 references: list of (name, energy) tuples 

347 List of references. The energy must be the total energy and not 

348 energy per atom. The names can also be dicts like 

349 ``{'Zn': 1, 'O': 2}`` which would be equivalent to ``'ZnO2'``. 

350 filter: str or list of str 

351 Use only those references that match the given filter. 

352 Example: ``filter='ZnO'`` will select those that 

353 contain zinc or oxygen. 

354 verbose: bool 

355 Write information. 

356 """ 

357 

358 if not references: 

359 raise ValueError("You must provide a non-empty list of references" 

360 " for the phase diagram! " 

361 "You have provided '{}'".format(references)) 

362 filter = parse_formula(filter)[0] 

363 

364 self.verbose = verbose 

365 

366 self.species = OrderedDict() 

367 self.references = [] 

368 for name, energy in references: 

369 if isinstance(name, str): 

370 count = parse_formula(name)[0] 

371 else: 

372 count = name 

373 

374 if filter and any(symbol not in filter for symbol in count): 

375 continue 

376 

377 if not isinstance(name, str): 

378 name = Formula.from_dict(count).format('metal') 

379 

380 natoms = 0 

381 for symbol, n in count.items(): 

382 natoms += n 

383 if symbol not in self.species: 

384 self.species[symbol] = len(self.species) 

385 self.references.append((count, energy, name, natoms)) 

386 

387 ns = len(self.species) 

388 self.symbols = [None] * ns 

389 for symbol, id in self.species.items(): 

390 self.symbols[id] = symbol 

391 

392 if verbose: 

393 print('Species:', ', '.join(self.symbols)) 

394 print('References:', len(self.references)) 

395 for i, (count, energy, name, natoms) in enumerate(self.references): 

396 print(f'{i:<5}{name:10}{energy:10.3f}') 

397 

398 self.points = np.zeros((len(self.references), ns + 1)) 

399 for s, (count, energy, name, natoms) in enumerate(self.references): 

400 for symbol, n in count.items(): 

401 self.points[s, self.species[symbol]] = n / natoms 

402 self.points[s, -1] = energy / natoms 

403 

404 if len(self.points) == ns: 

405 # Simple case that qhull would choke on: 

406 self.simplices = np.arange(ns).reshape((1, ns)) 

407 self.hull = np.ones(ns, bool) 

408 elif ns == 1: 

409 # qhull also doesn't like ns=1: 

410 i = self.points[:, 1].argmin() 

411 self.simplices = np.array([[i]]) 

412 self.hull = np.zeros(len(self.points), bool) 

413 self.hull[i] = True 

414 else: 

415 hull = ConvexHull(self.points[:, 1:]) 

416 

417 # Find relevant simplices: 

418 ok = hull.equations[:, -2] < 0 

419 self.simplices = hull.simplices[ok] 

420 

421 # Create a mask for those points that are on the convex hull: 

422 self.hull = np.zeros(len(self.points), bool) 

423 for simplex in self.simplices: 

424 self.hull[simplex] = True 

425 

426 if verbose: 

427 print('Simplices:', len(self.simplices)) 

428 

429 def decompose(self, formula=None, **kwargs): 

430 """Find the combination of the references with the lowest energy. 

431 

432 formula: str 

433 Stoichiometry. Example: ``'ZnO'``. Can also be given as 

434 keyword arguments: ``decompose(Zn=1, O=1)``. 

435 

436 Example:: 

437 

438 pd = PhaseDiagram(...) 

439 pd.decompose(Zn=1, O=3) 

440 

441 Returns energy, indices of references and coefficients.""" 

442 

443 if formula: 

444 assert not kwargs 

445 kwargs = parse_formula(formula)[0] 

446 

447 point = np.zeros(len(self.species)) 

448 N = 0 

449 for symbol, n in kwargs.items(): 

450 point[self.species[symbol]] = n 

451 N += n 

452 

453 # Find coordinates within each simplex: 

454 X = self.points[self.simplices, 1:-1] - point[1:] / N 

455 

456 # Find the simplex with positive coordinates that sum to 

457 # less than one: 

458 eps = 1e-14 

459 candidates = [] 

460 for i, Y in enumerate(X): 

461 try: 

462 x = np.linalg.solve((Y[1:] - Y[:1]).T, -Y[0]) 

463 except np.linalg.linalg.LinAlgError: 

464 continue 

465 if (x > -eps).all() and x.sum() < 1 + eps: 

466 indices = self.simplices[i] 

467 points = self.points[indices] 

468 

469 scaledcoefs = [1 - x.sum()] 

470 scaledcoefs.extend(x) 

471 

472 energy = N * np.dot(scaledcoefs, points[:, -1]) 

473 candidates.append((energy, indices, points, scaledcoefs)) 

474 

475 # Pick the one with lowest energy: 

476 energy, indices, points, scaledcoefs = min( 

477 candidates, key=lambda x: x[0]) 

478 

479 coefs = [] 

480 results = [] 

481 for coef, s in zip(scaledcoefs, indices): 

482 _count, e, name, natoms = self.references[s] 

483 coef *= N / natoms 

484 coefs.append(coef) 

485 results.append((name, coef, e)) 

486 

487 if self.verbose: 

488 print_results(results) 

489 

490 return energy, indices, np.array(coefs) 

491 

492 def plot(self, ax=None, dims=None, show=False, **plotkwargs): 

493 """Make 2-d or 3-d plot of datapoints and convex hull. 

494 

495 Default is 2-d for 2- and 3-component diagrams and 3-d for a 

496 4-component diagram. 

497 """ 

498 import matplotlib.pyplot as plt 

499 

500 N = len(self.species) 

501 

502 if dims is None: 

503 if N <= 3: 

504 dims = 2 

505 else: 

506 dims = 3 

507 

508 if ax is None: 

509 projection = None 

510 if dims == 3: 

511 projection = '3d' 

512 from mpl_toolkits.mplot3d import Axes3D 

513 Axes3D # silence pyflakes 

514 fig = plt.figure() 

515 ax = fig.add_subplot(projection=projection) 

516 else: 

517 if dims == 3 and not hasattr(ax, 'set_zlim'): 

518 raise ValueError('Cannot make 3d plot unless axes projection ' 

519 'is 3d') 

520 

521 if dims == 2: 

522 if N == 2: 

523 self.plot2d2(ax, **plotkwargs) 

524 elif N == 3: 

525 self.plot2d3(ax) 

526 else: 

527 raise ValueError('Can only make 2-d plots for 2 and 3 ' 

528 'component systems!') 

529 else: 

530 if N == 3: 

531 self.plot3d3(ax) 

532 elif N == 4: 

533 self.plot3d4(ax) 

534 else: 

535 raise ValueError('Can only make 3-d plots for 3 and 4 ' 

536 'component systems!') 

537 if show: 

538 plt.show() 

539 return ax 

540 

541 def plot2d2(self, ax=None, 

542 only_label_simplices=False, only_plot_simplices=False): 

543 x, e = self.points[:, 1:].T 

544 names = [re.sub(r'(\d+)', r'$_{\1}$', ref[2]) 

545 for ref in self.references] 

546 hull = self.hull 

547 simplices = self.simplices 

548 xlabel = self.symbols[1] 

549 ylabel = 'energy [eV/atom]' 

550 

551 if ax: 

552 for i, j in simplices: 

553 ax.plot(x[[i, j]], e[[i, j]], '-b') 

554 ax.plot(x[hull], e[hull], 'sg') 

555 if not only_plot_simplices: 

556 ax.plot(x[~hull], e[~hull], 'or') 

557 

558 if only_plot_simplices or only_label_simplices: 

559 x = x[self.hull] 

560 e = e[self.hull] 

561 names = [name for name, h in zip(names, self.hull) if h] 

562 for a, b, name in zip(x, e, names): 

563 ax.text(a, b, name, ha='center', va='top') 

564 

565 ax.set_xlabel(xlabel) 

566 ax.set_ylabel(ylabel) 

567 

568 return (x, e, names, hull, simplices, xlabel, ylabel) 

569 

570 def plot2d3(self, ax=None): 

571 x, y = self.points[:, 1:-1].T.copy() 

572 x += y / 2 

573 y *= 3**0.5 / 2 

574 names = [re.sub(r'(\d+)', r'$_{\1}$', ref[2]) 

575 for ref in self.references] 

576 hull = self.hull 

577 simplices = self.simplices 

578 

579 if ax: 

580 for i, j, k in simplices: 

581 ax.plot(x[[i, j, k, i]], y[[i, j, k, i]], '-b') 

582 ax.plot(x[hull], y[hull], 'og') 

583 ax.plot(x[~hull], y[~hull], 'sr') 

584 for a, b, name in zip(x, y, names): 

585 ax.text(a, b, name, ha='center', va='top') 

586 

587 return (x, y, names, hull, simplices) 

588 

589 def plot3d3(self, ax): 

590 x, y, e = self.points[:, 1:].T 

591 

592 ax.scatter(x[self.hull], y[self.hull], e[self.hull], 

593 c='g', marker='o') 

594 ax.scatter(x[~self.hull], y[~self.hull], e[~self.hull], 

595 c='r', marker='s') 

596 

597 for a, b, c, ref in zip(x, y, e, self.references): 

598 name = re.sub(r'(\d+)', r'$_{\1}$', ref[2]) 

599 ax.text(a, b, c, name, ha='center', va='bottom') 

600 

601 for i, j, k in self.simplices: 

602 ax.plot(x[[i, j, k, i]], 

603 y[[i, j, k, i]], 

604 zs=e[[i, j, k, i]], c='b') 

605 

606 ax.set_xlim3d(0, 1) 

607 ax.set_ylim3d(0, 1) 

608 ax.view_init(azim=115, elev=30) 

609 ax.set_xlabel(self.symbols[1]) 

610 ax.set_ylabel(self.symbols[2]) 

611 ax.set_zlabel('energy [eV/atom]') 

612 

613 def plot3d4(self, ax): 

614 x, y, z = self.points[:, 1:-1].T 

615 a = x / 2 + y + z / 2 

616 b = 3**0.5 * (x / 2 + y / 6) 

617 c = (2 / 3)**0.5 * z 

618 

619 ax.scatter(a[self.hull], b[self.hull], c[self.hull], 

620 c='g', marker='o') 

621 ax.scatter(a[~self.hull], b[~self.hull], c[~self.hull], 

622 c='r', marker='s') 

623 

624 for x, y, z, ref in zip(a, b, c, self.references): 

625 name = re.sub(r'(\d+)', r'$_{\1}$', ref[2]) 

626 ax.text(x, y, z, name, ha='center', va='bottom') 

627 

628 for i, j, k, w in self.simplices: 

629 ax.plot(a[[i, j, k, i, w, k, j, w]], 

630 b[[i, j, k, i, w, k, j, w]], 

631 zs=c[[i, j, k, i, w, k, j, w]], c='b') 

632 

633 ax.set_xlim3d(0, 1) 

634 ax.set_ylim3d(0, 1) 

635 ax.set_zlim3d(0, 1) 

636 ax.view_init(azim=115, elev=30) 

637 

638 

639_aqueous = """\ 

640-525700,SiF6-- 

641-514100,Rh(SO4)3---- 

642-504800,Ru(SO4)3---- 

643-499900,Pd(SO4)3---- 

644-495200,Ru(SO4)3--- 

645-485700,H4P2O7 

646-483700,Rh(SO4)3--- 

647-483600,H3P2O7- 

648-480400,H2P2O7-- 

649-480380,Pt(SO4)3---- 

650-471400,HP2O7--- 

651-458700,P2O7---- 

652-447500,LaF4- 

653-437600,LaH2PO4++ 

654-377900,LaF3 

655-376299,Ca(HSiO3)+ 

656-370691,BeF4-- 

657-355400,BF4- 

658-353025,Mg(HSiO3)+ 

659-346900,LaSO4+ 

660-334100,Rh(SO4)2-- 

661-325400,Ru(SO4)2-- 

662-319640,Pd(SO4)2-- 

663-317900,Ru(SO4)2- 

664-312970,Cr2O7-- 

665-312930,CaSO4 

666-307890,NaHSiO3 

667-307800,LaF2+ 

668-307000,LaHCO3++ 

669-306100,Rh(SO4)2- 

670-302532,BeF3- 

671-300670,Pt(SO4)2-- 

672-299900,LaCO3+ 

673-289477,MgSO4 

674-288400,LaCl4- 

675-281500,HZrO3- 

676-279200,HHfO3- 

677-276720,Sr(HCO3)+ 

678-275700,Ba(HCO3)+ 

679-273830,Ca(HCO3)+ 

680-273100,H3PO4 

681-270140,H2PO4- 

682-266500,S2O8-- 

683-264860,Sr(CO3) 

684-264860,SrCO3 

685-263830,Ba(CO3) 

686-263830,BaCO3 

687-262850,Ca(CO3) 

688-262850,CaCO3 

689-260310,HPO4-- 

690-257600,LaCl3 

691-250200,Mg(HCO3)+ 

692-249200,H3VO4 

693-248700,S4O6-- 

694-246640,KSO4- 

695-243990,H2VO4- 

696-243500,PO4--- 

697-243400,KHSO4 

698-242801,HSiO3- 

699-241700,HYO2 

700-241476,NaSO4- 

701-239700,HZrO2+ 

702-239300,LaO2H 

703-238760,Mg(CO3) 

704-238760,MgCO3 

705-237800,HHfO2+ 

706-236890,Ag(CO3)2--- 

707-236800,HNbO3 

708-236600,LaF++ 

709-235640,MnSO4 

710-233400,ZrO2 

711-233000,HVO4-- 

712-231600,HScO2 

713-231540,B(OH)3 

714-231400,HfO2 

715-231386,BeF2 

716-231000,S2O6-- 

717-229000,S3O6-- 

718-229000,S5O6-- 

719-228460,HTiO3- 

720-227400,YO2- 

721-227100,NbO3- 

722-226700,LaCl2+ 

723-223400,HWO4- 

724-221700,LaO2- 

725-218500,WO4-- 

726-218100,ScO2- 

727-214900,VO4--- 

728-210000,YOH++ 

729-208900,LaOH++ 

730-207700,HAlO2 

731-206400,HMoO4- 

732-204800,H3PO3 

733-202350,H2PO3- 

734-202290,SrF+ 

735-201807,BaF+ 

736-201120,BaF+ 

737-200400,MoO4-- 

738-200390,CaF+ 

739-199190,SiO2 

740-198693,AlO2- 

741-198100,YO+ 

742-195900,LaO+ 

743-195800,LaCl++ 

744-194000,CaCl2 

745-194000,HPO3-- 

746-191300,LaNO3++ 

747-190400,ZrOH+++ 

748-189000,HfOH+++ 

749-189000,S2O5-- 

750-187600,ZrO++ 

751-186000,HfO++ 

752-183700,HCrO4- 

753-183600,ScO+ 

754-183100,H3AsO4 

755-180630,HSO4- 

756-180010,H2AsO4- 

757-177930,SO4-- 

758-177690,MgF+ 

759-174800,CrO4-- 

760-173300,SrOH+ 

761-172300,BaOH+ 

762-172200,HBeO2- 

763-171300,CaOH+ 

764-170790,HAsO4-- 

765-166000,ReO4- 

766-165800,SrCl+ 

767-165475,Al(OH)++ 

768-165475,AlOH++ 

769-164730,BaCl+ 

770-164000,La+++ 

771-163800,Y+++ 

772-163100,CaCl+ 

773-162240,BO2- 

774-158493,BeF+ 

775-158188,AlO+ 

776-155700,VOOH+ 

777-155164,CdF2 

778-154970,AsO4--- 

779-153500,Rh(SO4) 

780-152900,BeO2-- 

781-152370,HSO5- 

782-151540,RuCl6--- 

783-149255,MgOH+ 

784-147400,H2S2O4 

785-146900,HS2O4- 

786-146081,CdCl4-- 

787-145521,BeCl2 

788-145200,Ru(SO4) 

789-145056,PbF2 

790-143500,S2O4-- 

791-140330,H2AsO3- 

792-140300,VO2+ 

793-140282,HCO3- 

794-140200,Sc+++ 

795-139900,BeOH+ 

796-139700,MgCl+ 

797-139200,Ru(SO4)+ 

798-139000,Pd(SO4) 

799-138160,HF2- 

800-138100,HCrO2 

801-138000,TiO++ 

802-137300,HGaO2 

803-136450,RbF 

804-134760,Sr++ 

805-134030,Ba++ 

806-133270,Zr++++ 

807-133177,PbCl4-- 

808-132600,Hf++++ 

809-132120,Ca++ 

810-129310,ZnCl3- 

811-128700,GaO2- 

812-128600,BeO 

813-128570,NaF 

814-128000,H2S2O3 

815-127500,Rh(SO4)+ 

816-127200,HS2O3- 

817-126191,CO3-- 

818-126130,HSO3- 

819-125300,CrO2- 

820-125100,H3PO2 

821-124900,S2O3-- 

822-123641,MnF+ 

823-122400,H2PO2- 

824-121000,HMnO2- 

825-120700,RuCl5-- 

826-120400,MnO4-- 

827-120300,Pt(SO4) 

828-119800,HInO2 

829-116300,SO3-- 

830-115971,CdCl3- 

831-115609,Al+++ 

832-115316,BeCl+ 

833-112280,AgCl4--- 

834-111670,TiO2++ 

835-111500,VOH++ 

836-111430,Ag(CO3)- 

837-110720,HZnO2- 

838-108505,Mg++ 

839-108100,HSeO4- 

840-108000,LiOH 

841-107600,MnO4- 

842-106988,HgCl4-- 

843-106700,InO2- 

844-106700,VO++ 

845-106100,VO+ 

846-105500,SeO4-- 

847-105100,RbOH 

848-105000,CsOH 

849-104500,KOH 

850-104109,ZnF+ 

851-103900,PdCl4-- 

852-103579,CuCl4-- 

853-102600,MnO2-- 

854-102150,PbCl3- 

855-101850,H2SeO3 

856-101100,HFeO2 

857-100900,CsCl 

858-100500,CrOH++ 

859-99900,NaOH 

860-99800,VOH+ 

861-99250,LiCl 

862-98340,HSeO3- 

863-98300,ZnCl2 

864-97870,RbCl 

865-97400,HSbO2 

866-97300,HSnO2- 

867-97300,MnOH+ 

868-97016,InF++ 

869-96240,HAsO2 

870-95430,KCl 

871-95400,HFeO2- 

872-94610,CsBr 

873-93290,ZnO2-- 

874-93250,RhCl4-- 

875-92910,NaCl 

876-92800,CrO+ 

877-92250,CO2 

878-91210,PtCl4-- 

879-91157,FeF+ 

880-91100,GaOH++ 

881-91010,RbBr 

882-90550,Be++ 

883-90010,KBr 

884-89963,CuCl3-- 

885-89730,RuCl4- 

886-88400,SeO3-- 

887-88000,FeO2- 

888-87373,CdF+ 

889-86600,GaO+ 

890-86500,HCdO2- 

891-86290,MnCl+ 

892-85610,NaBr 

893-84851,CdCl2 

894-83900,RuCl4-- 

895-83650,AsO2- 

896-83600,Ti+++ 

897-83460,CsI 

898-83400,HCoO2- 

899-82710,AgCl3-- 

900-82400,SbO2- 

901-81980,HNiO2- 

902-81732,CoF+ 

903-81500,MnO 

904-81190,ZnOH+ 

905-81000,HPbO2- 

906-79768,NiF+ 

907-79645,FeF++ 

908-79300,HBiO2 

909-78900,RbI 

910-77740,KI 

911-77700,La++ 

912-77500,RhCl4- 

913-75860,PbF+ 

914-75338,CuCl3- 

915-75216,TlF 

916-75100,Ti++ 

917-74600,InOH++ 

918-74504,HgCl3- 

919-73480,FeCl2 

920-72900,NaI 

921-71980,SO2 

922-71662,HF 

923-71600,RuO4-- 

924-71200,PbCl2 

925-69933,Li+ 

926-69810,PdCl3- 

927-69710,Cs+ 

928-69400,InO+ 

929-67811,AuCl3-- 

930-67800,Rb+ 

931-67510,K+ 

932-67420,ZnO 

933-67340,F- 

934-67300,CdO2-- 

935-66850,ZnCl+ 

936-65850,FeOH+ 

937-65550,TlOH 

938-64200,NiO2-- 

939-63530,RhCl3- 

940-63200,CoO2-- 

941-62591,Na+ 

942-61700,BiO2- 

943-61500,CdOH+ 

944-60100,HCuO2- 

945-59226,InCl++ 

946-58600,SnOH+ 

947-58560,RuCl3 

948-58038,CuCl2- 

949-57900,V+++ 

950-57800,FeOH++ 

951-57760,PtCl3- 

952-57600,HTlO2 

953-56690,H2O 

954-56025,CoOH+ 

955-55100,Mn++ 

956-54380,RuCl3- 

957-53950,PbOH+ 

958-53739,CuF+ 

959-53600,SnO 

960-53100,FeO+ 

961-53030,FeCl+ 

962-52850,NiOH+ 

963-52627,CdCl+ 

964-52000,V++ 

965-51560,AgCl2- 

966-50720,FeO 

967-49459,AgF 

968-49300,Cr+++ 

969-47500,CdO 

970-46190,RhCl3 

971-46142,CuCl2 

972-45200,HHgO2- 

973-45157,CoCl+ 

974-44000,CoO 

975-42838,HgCl2 

976-41600,TlO2- 

977-41200,CuO2-- 

978-40920,NiCl+ 

979-39815,TlCl 

980-39400,Cr++ 

981-39350,PbO 

982-39340,NiO 

983-39050,PbCl+ 

984-38000,Ga+++ 

985-37518,FeCl++ 

986-36781,AuCl2- 

987-35332,AuCl4- 

988-35200,Zn++ 

989-35160,PdCl2 

990-33970,RhCl2 

991-32300,BiOH++ 

992-31700,HIO3 

993-31379,Cl- 

994-30600,IO3- 

995-30410,HCl 

996-30204,HgF+ 

997-30200,CuOH+ 

998-29300,BiO+ 

999-28682,CO 

1000-26507,NO3- 

1001-26440,RuCl2+ 

1002-25590,Br3- 

1003-25060,RuCl2 

1004-24870,Br- 

1005-24730,HNO3 

1006-23700,HIO 

1007-23400,In+++ 

1008-23280,OCN- 

1009-23000,CoOH++ 

1010-22608,CuCl 

1011-22290,PtCl2 

1012-21900,AgOH 

1013-21870,Fe++ 

1014-20800,CuO 

1015-20300,Mn+++ 

1016-20058,Pb(HS)2 

1017-19700,HBrO 

1018-19100,HClO 

1019-19100,ScOH++ 

1020-18990,NH4+ 

1021-18971,Pb(HS)3- 

1022-18560,Cd++ 

1023-18290,Rh(OH)+ 

1024-17450,AgCl 

1025-16250,CuCl+ 

1026-14780,RhCl2+ 

1027-14000,IO4- 

1028-13130,Pd(OH)+ 

1029-13000,Co++ 

1030-12700,HgOH+ 

1031-12410,I- 

1032-12300,I3- 

1033-12190,Ru(OH)2++ 

1034-12100,HNO2 

1035-11500,PdO 

1036-10900,Ni++ 

1037-10470,Ru(OH)+ 

1038-10450,RuO+ 

1039-9200,IO- 

1040-8900,HgO 

1041-8800,ClO- 

1042-8000,BrO- 

1043-7740,Tl+ 

1044-7738,AgNO3 

1045-7700,NO2- 

1046-7220,RhO 

1047-6673,H2S 

1048-6570,Sn++ 

1049-6383,NH3 

1050-5710,Pb++ 

1051-5500,AgO- 

1052-4500,TlOH++ 

1053-4120,Fe+++ 

1054-3380,RhCl+ 

1055-3200,TlO+ 

1056-3184,AuCl 

1057-2155,HgCl+ 

1058-2040,ClO4- 

1059-1900,ClO3- 

1060-1130,PtO 

1061-820,Rh(OH)++ 

10620,Ag(HS)2- 

10630,H+ 

1064230,RuO 

10651400,HClO2 

10661560,Pt(OH)+ 

10672429,Au(HS)2- 

10682500,PdCl+ 

10692860,HS- 

10703140,RhO+ 

10713215,Xe 

10723554,Kr 

10733890,Ar 

10744100,ClO2- 

10754347,N2 

10764450,BrO3- 

10774565,Ne 

10784658,He 

10795210,RuCl+ 

10807100,RuCl++ 

10818600,H2N2O2 

10829375,TlCl++ 

108310500,HSe- 

108411950,Cu+ 

108515675,Cu++ 

108615700,S5-- 

108716500,S4-- 

108817600,S3-- 

108918200,HN2O2- 

109018330,RhCl++ 

109118380,PtCl+ 

109218427,Ag+ 

109319000,S2-- 

109419500,SeCN- 

109519700,N2H5+ 

109621100,N2H6++ 

109722160,SCN- 

109822880,Bi+++ 

109927700,Rh++ 

110028200,BrO4- 

110128600,HCN 

110232000,Co+++ 

110333200,N2O2-- 

110435900,Ru++ 

110536710,Hg2++ 

110639360,Hg++ 

110741200,CN- 

110841440,Ru+++ 

110942200,Pd++ 

111051300,Tl+++ 

111152450,Rh+++ 

111261600,Pt++ 

111364300,Ag++ 

1114103600,Au+++"""