Coverage for /builds/ase/ase/ase/io/sdf.py: 100.00%

17 statements  

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

1# fmt: off 

2 

3"""Reads chemical data in SDF format (wraps the molfile format). 

4 

5See https://en.wikipedia.org/wiki/Chemical_table_file#SDF 

6""" 

7from typing import TextIO 

8 

9from ase.atoms import Atoms 

10from ase.utils import reader 

11 

12 

13def get_num_atoms_sdf_v2000(first_line: str) -> int: 

14 """Parse the first line extracting the number of atoms. 

15 

16 The V2000 dialect uses a fixed field length of 3, which means there 

17 won't be space between the numbers if there are 100+ atoms, and 

18 the format doesn't support 1000+ atoms at all. 

19 

20 http://biotech.fyicenter.com/1000024_SDF_File_Format_Specification.html 

21 """ 

22 return int(first_line[0:3]) # first three characters 

23 

24 

25@reader 

26def read_sdf(file_obj: TextIO) -> Atoms: 

27 """Read the sdf data and compose the corresponding Atoms object.""" 

28 lines = file_obj.readlines() 

29 # first three lines header 

30 del lines[:3] 

31 

32 num_atoms = get_num_atoms_sdf_v2000(lines.pop(0)) 

33 positions = [] 

34 symbols = [] 

35 for line in lines[:num_atoms]: 

36 x, y, z, symbol = line.split()[:4] 

37 symbols.append(symbol) 

38 positions.append((float(x), float(y), float(z))) 

39 return Atoms(symbols=symbols, positions=positions)