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

22 statements  

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

1# fmt: off 

2 

3"""This is the implementation of the exciting I/O functions. 

4 

5The main roles these functions do is write exciting ground state 

6input files and read exciting ground state ouput files. 

7 

8Right now these functions all written without a class to wrap them. This 

9could change in the future but was done to make things simpler. 

10 

11These functions are primarily called by the exciting caculator in 

12ase/calculators/exciting/exciting.py. 

13 

14See the correpsonding test file in ase/test/io/test_exciting.py. 

15 

16Plan is to add parsing of eigenvalues in the next iteration using 

17excitingtools.exciting_dict_parsers.groundstate_parser.parse_eigval 

18 

19Note: excitingtools must be installed using `pip install excitingtools` for 

20the exciting io to work. 

21""" 

22from pathlib import Path 

23from typing import Dict, Optional, Union 

24 

25import ase 

26 

27 

28def parse_output(info_out_file_path): 

29 """Parse exciting INFO.OUT output file using excitingtools. 

30 

31 Note, excitingtools works by returning a dictionary that contains 

32 two high level keys. Initialization and results. Initialization 

33 contains data about how the calculation was setup (e.g. structure, 

34 maximum number of planewaves, etc...) and the results 

35 gives SCF cycle result information (e.g. total energy). 

36 

37 Args: 

38 info_out_file_path: path to an INFO.out exciting output file. 

39 Returns: 

40 A dictionary containing information about how the calculation was setup 

41 and results from the calculations SCF cycles. 

42 """ 

43 from excitingtools.exciting_dict_parsers.groundstate_parser import ( 

44 parse_info_out, 

45 ) 

46 

47 # Check for the file: 

48 if not Path(info_out_file_path).is_file(): 

49 raise FileNotFoundError 

50 return parse_info_out(info_out_file_path) 

51 

52 

53def write_input_xml_file( 

54 file_name, atoms: ase.Atoms, ground_state_input: Dict, 

55 species_path, title=None, 

56 properties_input: Optional[Dict] = None): 

57 """Write input xml file for exciting calculation. 

58 

59 Args: 

60 file_name: where to save the input xml file. 

61 atoms: ASE Atoms object. 

62 ground_state_input: ground state parameters for run. 

63 properties_input: optional additional parameters to run 

64 after performing the ground state calculation (e.g. bandstructure 

65 or DOS.) 

66 """ 

67 from excitingtools import ( 

68 ExcitingGroundStateInput, 

69 ExcitingInputXML, 

70 ExcitingPropertiesInput, 

71 ExcitingStructure, 

72 ) 

73 

74 # Convert ground state dictionary into expected input object. 

75 ground_state = ExcitingGroundStateInput(**ground_state_input) 

76 structure = ExcitingStructure(atoms, species_path=species_path) 

77 # If we are running futher calculations such as bandstructure/DOS. 

78 if properties_input is not None: 

79 properties_input = ExcitingPropertiesInput(**properties_input) 

80 else: 

81 properties_input = ExcitingPropertiesInput() 

82 input_xml = ExcitingInputXML(structure=structure, 

83 groundstate=ground_state, 

84 properties=properties_input, 

85 title=title) 

86 

87 input_xml.write(file_name) 

88 

89 

90def ase_atoms_from_exciting_input_xml( 

91 input_xml_path: Union[Path, str]) -> ase.Atoms: 

92 """Helper function to read structure from input.xml file. 

93 

94 Note, this function operates on the input.xml file that is the input 

95 to an exciting calculation. It parses the structure data given in the file 

96 and returns it in an ase Atoms object. Note this information can also be 

97 taken from an INFO.out file using parse_output. This script is more 

98 lightweight than parse_output since the input xml is significantly smaller 

99 than an INFO.out file and is XML structured making the parsing easier. 

100 

101 Args: 

102 input_xml_path: Path where input.xml file lives. 

103 

104 Returns: 

105 ASE atoms object with all the relevant fields filled. 

106 """ 

107 from excitingtools.exciting_obj_parsers.input_xml import parse_input_xml 

108 from excitingtools.structure.ase_utilities import exciting_structure_to_ase 

109 structure = parse_input_xml(input_xml_path).structure 

110 return exciting_structure_to_ase(structure)