11from pathlib import Path
22
33import numpy
4+ import pytest
45from helper import make_cmi_recipe
56from scipy .optimize import least_squares
67
78from diffpy .apps .app_runmacro import MacroParser
89
10+ _STRUCTURE_PATH = str (Path (__file__ ).parent / "data" / "Ni.cif" )
11+ _PROFILE_PATH = str (Path (__file__ ).parent / "data" / "Ni.gr" )
12+
913
1014def test_meta_model ():
1115 # C1: Run the same fit with pdfadapter and diffpy_cmi
1216 # Expect the refined parameters to be the same within 1e-5
1317 # diffpy_cmi fitting
14- structure_path = Path (__file__ ).parent / "data" / "Ni.cif"
15- profile_path = Path (__file__ ).parent / "data" / "Ni.gr"
1618 initial_pv_dict = {
1719 "s0" : 0.4 ,
1820 "qdamp" : 0.04 ,
@@ -30,12 +32,7 @@ def test_meta_model():
3032 "qbroad" ,
3133 ]
3234 diffpycmi_recipe = make_cmi_recipe (
33- str (structure_path ), str (profile_path ), initial_pv_dict
34- )
35- structure_path = Path (__file__ ).parent / "data" / "Ni.cif"
36- profile_path = Path (__file__ ).parent / "data" / "Ni.gr"
37- diffpycmi_recipe = make_cmi_recipe (
38- str (structure_path ), str (profile_path ), initial_pv_dict
35+ _STRUCTURE_PATH , _PROFILE_PATH , initial_pv_dict
3936 )
4037 diffpycmi_recipe .fithooks [0 ].verbose = 0
4138 diffpycmi_recipe .fix ("all" )
@@ -51,8 +48,8 @@ def test_meta_model():
5148 diffpy_pv_dict [pname ] = parameter .value
5249
5350 diffpy_dsl = f"""
54- load structure G1 from "{ str ( structure_path ) } "
55- load profile exp_ni from "{ str ( profile_path ) } "
51+ load structure G1 from "{ _STRUCTURE_PATH } "
52+ load profile exp_ni from "{ _PROFILE_PATH } "
5653
5754set G1 spacegroup as auto
5855set exp_ni q_range as 0.1 25
@@ -78,3 +75,137 @@ def test_meta_model():
7875 diffpy_value = diffpy_pv_dict [var_name ]
7976 interpreter_value = interpreter_results ["variables" ][var_name ]["value" ]
8077 assert numpy .isclose (diffpy_value , interpreter_value , atol = 1e-5 )
78+
79+
80+ @pytest .mark .parametrize (
81+ "command_string, expected_inputs, expected_variables" ,
82+ [
83+ # C1: load structure G1 from "path/to/structure.cif"
84+ # Expect inputs and variables to be set correctly
85+ (
86+ f'load structure G1 from "{ _STRUCTURE_PATH } "' ,
87+ {
88+ "initialize_structures.structure_paths" : _STRUCTURE_PATH ,
89+ "initialize_structures.names" : ["G1" ],
90+ },
91+ {"G1" : "structure" },
92+ ),
93+ # C2: load profile exp_ni from "path/to/profile.gr"
94+ # Expect inputs and variables to be set correctly
95+ (
96+ f'load profile exp_ni from "{ _PROFILE_PATH } "' ,
97+ {"initialize_profile.profile_path" : _PROFILE_PATH },
98+ {"exp_ni" : "profile" },
99+ ),
100+ # C3: create equation variables s0
101+ # Expect variable names to be stored
102+ (
103+ "create equation variables s0" ,
104+ {"add_contribution_variables.variable_names" : ["s0" ]},
105+ {},
106+ ),
107+ # C4: save to "results.json"
108+ # Expect result path to be stored
109+ (
110+ 'save to "results.json"' ,
111+ {"save_results.result_path" : "results.json" },
112+ {},
113+ ),
114+ # C5: set equation as "s0*G1"
115+ # Expect equation to be stored
116+ (
117+ 'set equation as "s0*G1"' ,
118+ {"initialize_contribution.equation" : ["s0*G1" ]},
119+ {},
120+ ),
121+ # C6: set exp_ni q_range as 0.1 25
122+ # Expect q_range to be stored
123+ (
124+ f'load profile exp_ni from "{ _PROFILE_PATH } "\n '
125+ "set exp_ni q_range as 0.1 25" ,
126+ {"initialize_profile.q_range" : [0.1 , 25 ]},
127+ {"exp_ni" : "profile" },
128+ ),
129+ # C7: set exp_ni calculation_range as 1.5 50 0.01
130+ # Expect calculation_range to be stored
131+ (
132+ f'load profile exp_ni from "{ _PROFILE_PATH } "\n '
133+ "set exp_ni calculation_range as 1.5 50 0.01" ,
134+ {"initialize_profile.calculation_range" : [1.5 , 50 , 0.01 ]},
135+ {"exp_ni" : "profile" },
136+ ),
137+ # C8: set G1 spacegroup as auto
138+ # Expect spacegroup to be stored
139+ (
140+ f'load structure G1 from "{ _STRUCTURE_PATH } "\n '
141+ "set G1 spacegroup as auto" ,
142+ {"initialize_structures.spacegroups" : ["auto" ]},
143+ {"G1" : "structure" },
144+ ),
145+ # C9: variables section with multiple variables
146+ # Expect variable names and values to be stored
147+ (
148+ """
149+ variables:
150+ ---
151+ - G1_a: 3.52
152+ - s0
153+ - G1_Uiso_0: 0.005
154+ ---
155+ """ ,
156+ {
157+ "set_initial_variable_values.variable_name_to_value" : {
158+ "G1_a" : 3.52 ,
159+ "G1_Uiso_0" : 0.005 ,
160+ },
161+ "refine_variables.variable_names" : ["G1_a" , "s0" , "G1_Uiso_0" ],
162+ },
163+ {},
164+ ),
165+ ],
166+ )
167+ def test_command_processor (
168+ command_string , expected_inputs , expected_variables
169+ ):
170+ parser = MacroParser ()
171+ parser .parse (command_string )
172+ for key , value in expected_inputs .items ():
173+ assert parser .inputs [key ] == value
174+ assert dict (parser .variables ) == expected_variables
175+
176+
177+ @pytest .mark .parametrize (
178+ "command_string, expected_exception, match" ,
179+ [
180+ (
181+ f'load unknown foo from "{ _STRUCTURE_PATH } "' ,
182+ ValueError ,
183+ "Unknown component type: unknown "
184+ "Please use 'structure' or 'profile'." ,
185+ ),
186+ (
187+ 'load structure foo from "/nonexistent/path.cif"' ,
188+ FileNotFoundError ,
189+ "structure /nonexistent/path.cif not found. "
190+ "Please ensure the path is correct and the file exists." ,
191+ ),
192+ (
193+ f'load structure G1 from "{ _STRUCTURE_PATH } "\n '
194+ f'load structure G2 from "{ _STRUCTURE_PATH } "' ,
195+ ValueError ,
196+ "Multiple structures are not supported by `runmacro` yet. "
197+ "Please use python script instead." ,
198+ ),
199+ (
200+ f'load profile p1 from "{ _PROFILE_PATH } "\n '
201+ f'load profile p2 from "{ _PROFILE_PATH } "' ,
202+ ValueError ,
203+ "Multiple profiles are not supported by `runmacro`. "
204+ "Please use python script instead." ,
205+ ),
206+ ],
207+ )
208+ def test_load_command_processor_bad (command_string , expected_exception , match ):
209+ parser = MacroParser ()
210+ with pytest .raises (expected_exception , match = match ):
211+ parser .parse (command_string )
0 commit comments