#!/usr/bin/env python
##############################################################################
#
# diffpy.srfit by DANSE Diffraction group
# Simon J. L. Billinge
# (c) 2008 The Trustees of Columbia University
# in the City of New York. All rights reserved.
#
# File coded by: Chris Farrow
#
# See AUTHORS.txt for a list of people who contributed.
# See LICENSE_DANSE.txt for license information.
#
##############################################################################
"""Simple FitRecipe class that includes a FitContribution and
Profile."""
from diffpy.srfit.fitbase.fitcontribution import FitContribution
from diffpy.srfit.fitbase.fitrecipe import FitRecipe
from diffpy.srfit.fitbase.fitresults import FitResults
from diffpy.srfit.fitbase.profile import Profile
from diffpy.utils._deprecator import build_deprecation_message, deprecated
base = "diffpy.srfit.fitbase.SimpleRecipe"
removal_version = "4.0.0"
loadParsedData_dep_msg = build_deprecation_message(
base,
"loadParsedData",
"load_parsed_data",
removal_version,
)
setObservedProfile_dep_msg = build_deprecation_message(
base,
"setObservedProfile",
"set_observed_profile",
removal_version,
)
setCalculationRange_dep_msg = build_deprecation_message(
base,
"setCalculationRange",
"set_calculation_range",
removal_version,
)
setCalculationPoints_dep_msg = build_deprecation_message(
base,
"setCalculationPoints",
"set_calculation_points",
removal_version,
)
setEquation_dep_msg = build_deprecation_message(
base,
"setEquation",
"set_equation",
removal_version,
)
printResults_dep_msg = build_deprecation_message(
base,
"printResults",
"print_results",
removal_version,
)
saveResults_dep_msg = build_deprecation_message(
base,
"saveResults",
"save_results",
removal_version,
)
[docs]
class SimpleRecipe(FitRecipe):
"""FitRecipe with a built-in Profile and FitContribution.
This is a FitRecipe with a built-in Profile (the 'profile' attribute) and
FitContribution (the 'contribution' attribute). Unique methods from each of
these are exposed through this class to facilitate the creation of a simple
fit recipe.
Public FitContribution methods that SimpleRecipe does not define
itself, such as ``set_residual_equation`` or ``add_profile_generator``,
are also made available as SimpleRecipe methods.
Attributes
----------
profile : Profile
The built-in Profile object.
contribution : FitContribution
The built-in FitContribution object, named "contribution".
results : FitResults
The built-in FitResults object.
name : str
The name of this FitRecipe.
fithooks : list
The list of FitHook instances that can pass information out
of the system during a refinement. By default, this is
populated by a PrintFitHook instance with verbosity 3.
names : list of str
The variable names (read only). See ``get_names``.
values : numpy.ndarray
The variable values (read only). See ``get_values``.
See Also
--------
FitRecipe : The base class, which documents the remaining
attributes.
"""
def __init__(self, name="fit", conclass=FitContribution):
"""Initialize the recipe with a built-in Profile and
FitContribution.
Parameters
----------
name : str, optional
The name of this FitRecipe (default "fit").
conclass : type, optional
The FitContribution class used to create the built-in
contribution (default FitContribution).
"""
FitRecipe.__init__(self, name)
self.fithooks[0].verbose = 3
contribution = conclass("contribution")
self.profile = Profile()
contribution.set_profile(self.profile)
self.add_contribution(contribution)
self.results = FitResults(self, update=False)
# Adopt all the FitContribution methods
public = [
aname
for aname in dir(contribution)
if aname not in dir(self) and not aname.startswith("_")
]
for mname in public:
method = getattr(contribution, mname)
setattr(self, mname, method)
return
# Profile methods
[docs]
def load_parsed_data(self, parser):
"""Load parsed data from a ProfileParser.
This sets the xobs, yobs, dyobs arrays as well as the metadata.
Parameters
----------
parser : ProfileParser
The ProfileParser to load data from.
"""
return self.profile.load_parsed_data(parser)
@deprecated(loadParsedData_dep_msg)
def loadParsedData(self, parser):
"""This function has been deprecated and will be removed in version
4.0.0.
Please use
diffpy.srfit.fitbase.SimpleRecipe.load_parsed_data
instead.
"""
return self.load_parsed_data(parser)
[docs]
def set_observed_profile(self, xobs, yobs, dyobs=None):
"""Set the observed profile.
Parameters
----------
xobs : ndarray
The independent variable.
yobs : ndarray
The observed signal.
dyobs : ndarray, optional
The uncertainty in the observed signal. If dyobs is None
(default), dyobs stays None to indicate no uncertainty was
observed, and the calculated dy will be set to 1 at each
calculation point instead.
Raises
------
ValueError
If ``len(yobs) != len(xobs)``.
ValueError
If dyobs is not None and ``len(dyobs) != len(xobs)``.
"""
return self.profile.set_observed_profile(xobs, yobs, dyobs)
@deprecated(setObservedProfile_dep_msg)
def setObservedProfile(self, xobs, yobs, dyobs=None):
"""This function has been deprecated and will be removed in version
4.0.0.
Please use
diffpy.srfit.fitbase.SimpleRecipe.set_observed_profile
instead.
"""
return self.set_observed_profile(xobs, yobs, dyobs)
[docs]
def set_calculation_range(self, xmin=None, xmax=None, dx=None):
"""Set epsilon-inclusive calculation range.
Adhere to the observed ``xobs`` points when ``dx`` is the same
as in the data. ``xmin`` and ``xmax`` are clipped at the bounds
of the observed data. ``xmin`` is always inclusive (unless
clipped). ``xmax`` is inclusive if it is within the bounds of the
observed data.
Parameters
----------
xmin : float or "obs", optional
The minimum value of the independent variable. Keep the
current minimum when not specified. If specified as "obs"
reset to the minimum observed value.
xmax : float or "obs", optional
The maximum value of the independent variable. Keep the
current maximum when not specified. If specified as "obs"
reset to the maximum observed value.
dx : float or "obs", optional
The sample spacing in the independent variable. When different
from the data, resample the ``x`` as anchored at ``xmin``.
Raises
------
AttributeError
If there is no observed data.
ValueError
If ``xmin > xmax``, if ``dx <= 0`` or if
``dx > xmax - xmin``.
ValueError
If ``xmin``, ``xmax`` or ``dx`` is a string other than
"obs".
"""
return self.profile.set_calculation_range(xmin, xmax, dx)
@deprecated(setCalculationRange_dep_msg)
def setCalculationRange(self, xmin=None, xmax=None, dx=None):
"""This function has been deprecated and will be removed in version
4.0.0.
Please use
diffpy.srfit.fitbase.SimpleRecipe.set_calculation_range
instead.
"""
return self.set_calculation_range(xmin, xmax, dx)
[docs]
def set_calculation_points(self, x):
"""Set the calculation points.
This will create y and dy on the specified grid if xobs, yobs
and dyobs exist.
Parameters
----------
x : ndarray
The non-empty array of calculation points. If xobs exists,
the bounds of x will be limited to its bounds.
"""
return self.profile.set_calculation_points(x)
@deprecated(setCalculationPoints_dep_msg)
def setCalculationPoints(self, x):
"""This function has been deprecated and will be removed in version
4.0.0.
Please use
diffpy.srfit.fitbase.SimpleRecipe.set_calculation_points
instead.
"""
return self.set_calculation_points(x)
[docs]
def loadtxt(self, *args, **kw):
"""Load data using ``numpy.loadtxt``.
Arguments are passed to ``numpy.loadtxt``. ``unpack=True`` is
enforced. The first two arrays returned by ``numpy.loadtxt`` are
assumed to be x and y. If there is a third array, it is assumed
to be dy. Any other arrays are ignored. The loaded arrays are
passed to ``set_observed_profile``.
Parameters
----------
*args
The positional arguments passed to ``numpy.loadtxt``.
**kw
The keyword arguments passed to ``numpy.loadtxt``.
Returns
-------
x : numpy.ndarray
The array of the independent variable loaded from the
file.
y : numpy.ndarray
The array of the observed signal loaded from the file.
dy : numpy.ndarray or None
The array of the uncertainty loaded from the file, or None
if no third column is present.
Raises
------
ValueError
If the call to ``numpy.loadtxt`` returns fewer than 2 arrays.
"""
return self.profile.loadtxt(*args, **kw)
# FitContribution
[docs]
def set_equation(self, eqstr, ns={}):
"""Set the profile equation for the FitContribution.
This sets the equation that will be used when generating the residual.
The equation will be usable within set_residual_equation as "eq", and
it takes no arguments.
Parameters
----------
eqstr : str
The string representation of the equation. After the
equation is set, every top-level Parameter of the
FitContribution other than x, y and dy is added as a
variable of this recipe, unless it is one already.
Parameters without a value are given an initial value of 0.
ns : dict, optional
The dictionary of Parameters, indexed by name, that are
used in the eqstr, but not registered (default {}).
Raises
------
ValueError
If ns uses a name that is already used for a variable.
"""
self.contribution.set_equation(eqstr, ns={})
# Extract variables
for par in self.contribution:
# Skip Profile Parameters
if par.name in ("x", "y", "dy"):
continue
if par.value is None:
par.value = 0
if par.name not in self._parameters:
self.add_variable(par)
return
@deprecated(setEquation_dep_msg)
def setEquation(self, eqstr, ns={}):
"""This function has been deprecated and will be removed in version
4.0.0.
Please use
diffpy.srfit.fitbase.SimpleRecipe.set_equation
instead.
"""
self.set_equation(eqstr, ns)
return
def __call__(self):
"""Evaluate the contribution equation.
Returns
-------
numpy.ndarray
The calculated signal, which is also stored in
``profile.ycalc``.
"""
return self.contribution.evaluate()
# FitResults methods
[docs]
def print_results(self, header="", footer=""):
"""Format and print the results.
The results are updated from the current state of the recipe
before they are printed.
Parameters
----------
header : str, optional
The header to add to the output (default "").
footer : str, optional
The footer to add to the output (default "").
"""
self.results.print_results(header, footer, True)
return
@deprecated(printResults_dep_msg)
def printResults(self, header="", footer=""):
"""This function has been deprecated and will be removed in version
4.0.0.
Please use
diffpy.srfit.fitbase.SimpleRecipe.print_results
instead.
"""
self.print_results(header, footer)
return
[docs]
def save_results(self, filename, header="", footer=""):
"""Format and save the results.
The results are updated from the current state of the recipe
before they are saved.
Parameters
----------
filename : str or pathlib.Path
The name of the save file.
header : str, optional
The header to add to the output (default "").
footer : str, optional
The footer to add to the output (default "").
"""
self.results.save_results(filename, header, footer, True)
@deprecated(saveResults_dep_msg)
def saveResults(self, filename, header="", footer=""):
"""This function has been deprecated and will be removed in version
4.0.0.
Please use
diffpy.srfit.fitbase.SimpleRecipe.save_results
instead.
"""
self.save_results(filename, header, footer)
# End class SimpleRecipe
# End of file