Skip to content

Commit ae57d1b

Browse files
committed
chore: finalize basic functionalities for PDF refinement
1 parent c555166 commit ae57d1b

7 files changed

Lines changed: 716 additions & 243 deletions

File tree

‎src/diffpy/apps/refinebase/parametric_model.py‎

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
import re
23

34
import networkx as nx
@@ -8,6 +9,9 @@
89
from diffpy.srfit.structure import constrain_as_space_group
910
from diffpy.structure import Structure
1011

12+
# NOTE: MCP server prefers logging for output
13+
logger = logging.getLogger(__name__)
14+
1115

1216
class 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

138154
class 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

157194
class 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

Comments
 (0)