1+ import logging
12import re
23
34import networkx as nx
89from diffpy .srfit .structure import constrain_as_space_group
910from diffpy .structure import Structure
1011
12+ # NOTE: MCP server prefers logging for output
13+ logger = logging .getLogger (__name__ )
14+
1115
1216class ParametricModel :
1317 def __init__ (self , name ):
@@ -65,6 +69,11 @@ def register_submodel(self, submodel, symbol=None):
6569 if symbol in self .calc_obj ._parameters :
6670 self .calc_obj ._remove_parameter (self .calc_obj ._parameters [symbol ])
6771 if isinstance (submodel , ParametricModelPDF ):
72+ if symbol != submodel .name :
73+ logger .warning (
74+ f"ParametricModelPDF's name ({ submodel .name } ) does "
75+ f"not match with the provided symbol ({ symbol } ) " ,
76+ )
6877 self .calc_obj .add_profile_generator (submodel .calc_obj )
6978 elif isinstance (submodel , ParametricModelEquation ):
7079 self .calc_obj ._eqfactory .registerOperator (
@@ -132,17 +141,22 @@ def _rebuild_graph(self):
132141 )
133142
134143 def evaluate (self ):
135- return self .calc_obj ._eq ()
144+ raise NotImplementedError (
145+ "The evaluate method must be implemented by subclasses."
146+ )
147+
148+ def residual (self ):
149+ raise NotImplementedError (
150+ "The residual method must be implemented by subclasses."
151+ )
136152
137153
138154class ParametricModelEquation (ParametricModel ):
139155 def __init__ (self , name , equation_str = None ):
140156 super ().__init__ (name = name )
141157 self .equation_str = None
142158 if equation_str :
143- self .equation_str = equation_str
144- self .calc_obj .set_equation (equation_str )
145- self ._rebuild_graph ()
159+ self .set_equation (equation_str )
146160
147161 @property
148162 def _contribution (self ):
@@ -153,8 +167,33 @@ def set_equation(self, equation_str):
153167 self .calc_obj .set_equation (equation_str )
154168 self ._rebuild_graph ()
155169
170+ def get_equation (self ):
171+ return self .equation_str
172+
173+ def set_residual_equation (self , residual_equation_str ):
174+ self .residual_equation = residual_equation_str
175+ self .calc_obj .set_residual_equation (residual_equation_str )
176+ self ._rebuild_graph ()
177+
178+ def get_residual_equation (self ):
179+ return self .residual_equation
180+
181+ def evaluate (self ):
182+ yc = self .calc_obj ._eq ()
183+ if (
184+ hasattr (self .calc_obj , "profile" )
185+ and self .calc_obj .profile is not None
186+ ):
187+ self .calc_obj .profile .ycalc = yc
188+ return yc
189+
190+ def residual (self ):
191+ return self .calc_obj .residual ()
192+
156193
157194class ParametricModelPDF (ParametricModel ):
195+ # NOTE: qmin, qmax, stype(scattering type) are meta handled
196+ # throughout the loaded profile in the refinement session
158197 def __init__ (self , name , structure : Structure ):
159198 super ().__init__ (name = name )
160199 self .calc_obj = PDFGenerator (name )
@@ -219,11 +258,17 @@ def constrain_symmetry(self, spacegroup_symbol):
219258 "constrained_or_constant"
220259 ] = True
221260
222- def set_qmin (self , qmin : float ):
223- self .calc_obj .setQmin (qmin )
261+ def set_profile (self , profile ):
262+ self .calc_obj .set_profile (profile )
263+ self ._yname = self .calc_obj .profile .ypar .name
264+ self ._dyname = self .calc_obj .profile .dypar .name
265+ # no submodel is allowed ParametricModelPDF
224266
225- def set_qmax (self , qmax : float ):
226- self .calc_obj .setQmax ( qmax )
267+ def evaluate (self ):
268+ return self .calc_obj .operation ( )
227269
228- def set_scattering_type (self , scattering_type : str ):
229- self .calc_obj .setScatteringType (scattering_type )
270+ def residual (self ):
271+ ycalc = self .calc_obj .operation ()
272+ yobs = self .calc_obj .profile .ypar .value
273+ dyobs = self .calc_obj .profile .dypar .value
274+ return (ycalc - yobs ) / dyobs
0 commit comments