or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

constants-utilities.mdelements.mdformulas.mdindex.mdneutron-scattering.mdxray-scattering.md

formulas.mddocs/

0

# Chemical Formulas

1

2

Parse chemical formulas, calculate molecular properties, create mixtures by weight or volume, and perform isotope substitutions with full support for composite material calculations and property estimation.

3

4

## Capabilities

5

6

### Formula Parsing

7

8

Parse chemical formula strings into Formula objects with automatic composition analysis and property calculation capabilities.

9

10

```python { .api }

11

def formula(compound: str = None, density: float = None,

12

natural_density: float = None, name: str = None,

13

table: PeriodicTable = None) -> Formula:

14

"""

15

Parse chemical formula string into Formula object.

16

17

Args:

18

compound: Chemical formula string (e.g., 'H2O', 'CaCO3', 'C6H12O6')

19

density: Known density in g/cm³

20

natural_density: Density with natural isotope abundances

21

name: Descriptive name for the compound

22

table: Custom periodic table to use for parsing

23

24

Returns:

25

Formula object with composition and properties

26

"""

27

```

28

29

Usage examples:

30

31

```python

32

import periodictable as pt

33

34

# Simple molecules

35

water = pt.formula("H2O")

36

methane = pt.formula("CH4")

37

glucose = pt.formula("C6H12O6")

38

39

# Complex formulas with parentheses

40

calcium_phosphate = pt.formula("Ca3(PO4)2")

41

hydrated_salt = pt.formula("CuSO4·5H2O", name="Copper sulfate pentahydrate")

42

43

# With known density

44

quartz = pt.formula("SiO2", density=2.65, name="Quartz")

45

46

# Isotope-specific formulas

47

heavy_water = pt.formula("D2O", name="Heavy water")

48

carbon13_methane = pt.formula("13CH4")

49

50

# Formula with charges

51

sodium_chloride = pt.formula("NaCl") # Neutral overall

52

```

53

54

### Mixture Creation by Weight

55

56

Create homogeneous mixtures by specifying weight percentages of different materials with automatic density and property calculations.

57

58

```python { .api }

59

def mix_by_weight(*args, density: float = None,

60

natural_density: float = None, name: str = None,

61

table: PeriodicTable = None) -> Formula:

62

"""

63

Create mixture apportioned by weight percentages.

64

65

Args:

66

*args: Alternating formula/weight pairs (formula1, weight1, formula2, weight2, ...)

67

density: Known density of mixture

68

natural_density: Density with natural abundances

69

name: Descriptive name for mixture

70

table: Custom periodic table

71

72

Returns:

73

Formula representing the mixture

74

"""

75

```

76

77

Usage examples:

78

79

```python

80

import periodictable as pt

81

82

# Simple mixture: 80% H2O, 20% D2O by weight

83

water_mixture = pt.mix_by_weight("H2O", 80, "D2O", 20, name="Mixed water")

84

85

# Complex mixture

86

steel_alloy = pt.mix_by_weight(

87

"Fe", 95.0, # 95% iron

88

"C", 0.8, # 0.8% carbon

89

"Mn", 2.0, # 2% manganese

90

"Si", 1.2, # 1.2% silicon

91

"Cr", 1.0, # 1% chromium

92

density=7.85,

93

name="Carbon steel"

94

)

95

96

# Using Formula objects

97

concrete_mix = pt.mix_by_weight(

98

pt.formula("Ca(OH)2"), 15, # Lime

99

pt.formula("SiO2"), 60, # Silica

100

pt.formula("Al2O3"), 25, # Alumina

101

name="Concrete mixture"

102

)

103

104

print(f"Steel composition: {steel_alloy.atoms}")

105

print(f"Steel density: {steel_alloy.density} g/cm³")

106

```

107

108

### Mixture Creation by Volume

109

110

Create homogeneous mixtures by specifying volume percentages with density calculations based on component volumes.

111

112

```python { .api }

113

def mix_by_volume(*args, density: float = None,

114

natural_density: float = None, name: str = None,

115

table: PeriodicTable = None) -> Formula:

116

"""

117

Create mixture apportioned by volume percentages.

118

119

Args:

120

*args: Alternating formula/volume pairs (formula1, vol1, formula2, vol2, ...)

121

density: Known density of mixture

122

natural_density: Density with natural abundances

123

name: Descriptive name for mixture

124

table: Custom periodic table

125

126

Returns:

127

Formula representing the mixture

128

"""

129

```

130

131

Usage examples:

132

133

```python

134

import periodictable as pt

135

136

# Air composition by volume

137

air = pt.mix_by_volume(

138

"N2", 78.08, # Nitrogen

139

"O2", 20.95, # Oxygen

140

"Ar", 0.93, # Argon

141

"CO2", 0.04, # Carbon dioxide

142

name="Air at STP"

143

)

144

145

# Liquid mixture

146

ethanol_water = pt.mix_by_volume(

147

pt.formula("C2H5OH", density=0.789), 40, # 40% ethanol by volume

148

pt.formula("H2O", density=1.0), 60, # 60% water by volume

149

name="40% ethanol solution"

150

)

151

152

print(f"Air molecular composition: {air.hill}")

153

print(f"Ethanol solution density: {ethanol_water.density:.3f} g/cm³")

154

```

155

156

### Formula Properties and Calculations

157

158

Access comprehensive molecular properties including mass, charge, composition analysis, and derived quantities.

159

160

```python { .api }

161

class Formula:

162

"""Chemical formula with composition and property calculations."""

163

164

# Core composition

165

atoms: dict # Dictionary mapping atoms to counts

166

mass: float # Molecular mass in atomic mass units (u)

167

molecular_mass: float # Molecular mass in grams

168

169

# Physical properties

170

density: float # Mass density in g/cm³

171

natural_density: float # Density with natural isotopes

172

173

# Chemical properties

174

charge: int # Net electrical charge

175

hill: str # Formula in Hill notation (C, H, others alphabetical)

176

177

# Composition analysis

178

mass_fraction: dict # Fractional mass of each component

179

180

def natural_mass_ratio(self) -> float:

181

"""Ratio of natural to isotope-substituted mass."""

182

```

183

184

Usage examples:

185

186

```python

187

import periodictable as pt

188

189

# Create and analyze glucose

190

glucose = pt.formula("C6H12O6", density=1.54)

191

192

# Basic properties

193

print(f"Molecular formula: {glucose.hill}") # C6H12O6

194

print(f"Molecular mass: {glucose.mass:.2f} u") # 180.16 u

195

print(f"Mass in grams: {glucose.molecular_mass:.2e} g") # 2.99e-22 g

196

print(f"Density: {glucose.density} g/cm³") # 1.54

197

198

# Composition analysis

199

print("Mass fractions:")

200

for atom, fraction in glucose.mass_fraction.items():

201

print(f" {atom.symbol}: {fraction:.3f}")

202

203

# Atomic composition

204

print("Atomic composition:")

205

for atom, count in glucose.atoms.items():

206

print(f" {atom.symbol}: {count}")

207

208

# For charged species

209

salt = pt.formula("Na+Cl-") # Conceptual - parser handles neutral compounds

210

print(f"Net charge: {salt.charge}") # 0 (neutral overall)

211

```

212

213

### Isotope Substitution

214

215

Replace specific elements with isotopes to study isotope effects on properties and scattering characteristics.

216

217

```python { .api }

218

def replace(self, source, target, portion: float = 1) -> 'Formula':

219

"""

220

Create new formula with isotope substitution.

221

222

Args:

223

source: Element to replace (Element, Isotope, or Ion)

224

target: Replacement isotope/element

225

portion: Fraction to replace (0-1, default 1 for complete)

226

227

Returns:

228

New Formula with substitution applied

229

"""

230

```

231

232

Usage examples:

233

234

```python

235

import periodictable as pt

236

237

# Deuteration of water

238

water = pt.formula("H2O")

239

heavy_water = water.replace(pt.H, pt.D) # Replace all H with D

240

print(f"H2O mass: {water.mass:.3f} u") # ~18.015 u

241

print(f"D2O mass: {heavy_water.mass:.3f} u") # ~20.028 u

242

243

# Partial deuteration (50%)

244

partial_d2o = water.replace(pt.H, pt.D, portion=0.5)

245

print(f"50% deuterated mass: {partial_d2o.mass:.3f} u")

246

247

# Carbon-13 labeling in glucose

248

glucose = pt.formula("C6H12O6")

249

c13_glucose = glucose.replace(pt.C, pt.C[13]) # All carbon to C-13

250

print(f"Natural glucose: {glucose.mass:.3f} u")

251

print(f"C-13 glucose: {c13_glucose.mass:.3f} u")

252

253

# Partial labeling

254

glucose_1c13 = glucose.replace(pt.C, pt.C[13], portion=1/6) # One C-13

255

print(f"One C-13 glucose: {glucose_1c13.mass:.3f} u")

256

```

257

258

### Volume and Density Estimation

259

260

Estimate molecular volumes and densities using crystallographic data and packing factors for materials without known densities.

261

262

```python { .api }

263

def volume(self, packing_factor: str = None, **kwargs) -> float:

264

"""

265

Estimate unit cell volume using atomic radii and packing factors.

266

267

Args:

268

packing_factor: Crystal structure ('cubic', 'fcc', 'bcc', 'hcp', 'diamond')

269

**kwargs: Additional crystallographic parameters

270

271

Returns:

272

Estimated volume in Ų

273

"""

274

```

275

276

Available packing factors and their values:

277

278

```python { .api }

279

PACKING_FACTORS = {

280

'cubic': π/6, # Simple cubic (52.4%)

281

'bcc': π*√3/8, # Body-centered cubic (68.0%)

282

'fcc': π/√18, # Face-centered cubic (74.0%)

283

'hcp': π/√18, # Hexagonal close-packed (74.0%)

284

'diamond': π*√3/16 # Diamond structure (34.0%)

285

}

286

```

287

288

Usage examples:

289

290

```python

291

import periodictable as pt

292

293

# Estimate volume for different crystal structures

294

silicon = pt.formula("Si")

295

296

# Different packing assumptions

297

vol_diamond = silicon.volume(packing_factor='diamond') # Diamond structure

298

vol_fcc = silicon.volume(packing_factor='fcc') # FCC assumption

299

300

print(f"Si diamond structure volume: {vol_diamond:.2f} Ų")

301

print(f"Si FCC structure volume: {vol_fcc:.2f} Ų")

302

303

# For compounds - estimates based on component radii

304

nacl = pt.formula("NaCl")

305

nacl_volume = nacl.volume(packing_factor='cubic')

306

print(f"NaCl estimated volume: {nacl_volume:.2f} Ų")

307

308

# Compare with known density

309

quartz = pt.formula("SiO2", density=2.65)

310

estimated_vol = quartz.volume()

311

actual_vol = quartz.mass / (quartz.density * 6.022e23) * 1e24 # Convert to Ų

312

print(f"SiO2 estimated volume: {estimated_vol:.2f} Ų")

313

print(f"SiO2 actual volume: {actual_vol:.2f} Ų")

314

```

315

316

### Table Management

317

318

Switch formulas between different periodic tables and access custom element data for specialized calculations.

319

320

```python { .api }

321

def change_table(self, table: PeriodicTable) -> 'Formula':

322

"""

323

Create equivalent formula using different periodic table.

324

325

Args:

326

table: Target periodic table with custom data

327

328

Returns:

329

New Formula using the specified table

330

"""

331

```

332

333

Usage examples:

334

335

```python

336

import periodictable as pt

337

from periodictable.core import PeriodicTable

338

339

# Create custom table with modified properties

340

custom_table = PeriodicTable()

341

# ... customize table properties ...

342

343

# Convert formula to use custom table

344

water = pt.formula("H2O")

345

custom_water = water.change_table(custom_table)

346

347

print(f"Original table: {water.atoms[pt.H].mass}")

348

print(f"Custom table: {custom_water.atoms[custom_table.H].mass}")

349

```

350

351

### Utility Functions

352

353

Additional functions for formula parsing, composition analysis, and formatting for different output formats.

354

355

```python { .api }

356

def count_elements(compound, by_isotope: bool = False) -> dict:

357

"""

358

Count elements in a compound without creating Formula object.

359

360

Args:

361

compound: Formula string or Formula object

362

by_isotope: Count isotopes separately if True

363

364

Returns:

365

Dictionary of element/isotope counts

366

"""

367

368

def pretty(compound, mode: str = 'unicode') -> str:

369

"""

370

Format chemical formula with subscripts and superscripts.

371

372

Args:

373

compound: Formula string or Formula object

374

mode: Output format ('unicode', 'html', 'latex')

375

376

Returns:

377

Formatted formula string

378

"""

379

380

def parse_formula(formula_str: str, table: PeriodicTable = None) -> list:

381

"""

382

Parse formula string into list of (element, count) tuples.

383

384

Args:

385

formula_str: Chemical formula string

386

table: Periodic table to use for parsing

387

388

Returns:

389

List of (atom, count) tuples

390

"""

391

```

392

393

Usage examples:

394

395

```python

396

import periodictable as pt

397

from periodictable.formulas import count_elements, pretty, parse_formula

398

399

# Count elements

400

glucose_counts = count_elements("C6H12O6")

401

print(glucose_counts) # {'C': 6, 'H': 12, 'O': 6}

402

403

# Format with subscripts

404

water_pretty = pretty("H2O")

405

print(water_pretty) # H₂O (with Unicode subscripts)

406

407

caffeine_pretty = pretty("C8H10N4O2", mode='html')

408

print(caffeine_pretty) # C<sub>8</sub>H<sub>10</sub>N<sub>4</sub>O<sub>2</sub>

409

410

# Parse formula structure

411

parsed = parse_formula("Ca(OH)2")

412

print(parsed) # [(Ca, 1), (O, 2), (H, 2)]

413

```

414

415

## Types

416

417

```python { .api }

418

class Formula:

419

"""Chemical formula with composition and property calculations."""

420

atoms: dict

421

mass: float

422

molecular_mass: float

423

density: float

424

natural_density: float

425

charge: int

426

hill: str

427

mass_fraction: dict

428

def replace(self, source, target, portion: float = 1) -> 'Formula': ...

429

def volume(self, packing_factor: str = None, **kwargs) -> float: ...

430

def change_table(self, table: PeriodicTable) -> 'Formula': ...

431

def natural_mass_ratio(self) -> float: ...

432

def neutron_sld(self, wavelength: float = None, energy: float = None) -> tuple: ...

433

def xray_sld(self, energy: float = None, wavelength: float = None) -> tuple: ...

434

435

PACKING_FACTORS: dict = {

436

'cubic': float,

437

'bcc': float,

438

'fcc': float,

439

'hcp': float,

440

'diamond': float

441

}

442

```