diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 0e4a84d..7a1f00b 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -11,7 +11,7 @@ ci:
submodules: false
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.6.0
+ rev: v6.0.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
@@ -21,45 +21,45 @@ repos:
- id: check-toml
- id: check-added-large-files
- repo: https://github.com/psf/black
- rev: 24.4.2
+ rev: 26.5.1
hooks:
- id: black
- repo: https://github.com/pycqa/flake8
- rev: 7.0.0
+ rev: 7.3.0
hooks:
- id: flake8
- repo: https://github.com/pycqa/isort
- rev: 5.13.2
+ rev: 9.0.0b2
hooks:
- id: isort
args: ["--profile", "black"]
- repo: https://github.com/kynan/nbstripout
- rev: 0.7.1
+ rev: 0.9.1
hooks:
- id: nbstripout
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.4.0
+ rev: v6.0.0
hooks:
- id: no-commit-to-branch
name: Prevent Commit to Main Branch
args: ["--branch", "main"]
stages: [pre-commit]
- repo: https://github.com/codespell-project/codespell
- rev: v2.3.0
+ rev: v2.4.3
hooks:
- id: codespell
additional_dependencies:
- tomli
# prettier - multi formatter for .json, .yml, and .md files
- repo: https://github.com/pre-commit/mirrors-prettier
- rev: f12edd9c7be1c20cfa42420fd0e6df71e42b51ea # frozen: v4.0.0-alpha.8
+ rev: v4.0.0-alpha.8
hooks:
- id: prettier
additional_dependencies:
- "prettier@^3.2.4"
# docformatter - PEP 257 compliant docstring formatter
- - repo: https://github.com/s-weigand/docformatter
- rev: 5757c5190d95e5449f102ace83df92e7d3b06c6c
+ - repo: https://github.com/PyCQA/docformatter
+ rev: v1.7.8
hooks:
- id: docformatter
additional_dependencies: [tomli]
diff --git a/docs/examples/core/debye-waller/debyemodel.py b/docs/examples/core/debye-waller/debyemodel.py
index 3ca50a9..c01b5f2 100644
--- a/docs/examples/core/debye-waller/debyemodel.py
+++ b/docs/examples/core/debye-waller/debyemodel.py
@@ -35,7 +35,7 @@
import numpy
-from diffpy.cmi.fit_tools import optimize_recipe, plot_results
+from diffpy.cmi.fit_tools import optimize_recipe
from diffpy.srfit.fitbase import (
FitContribution,
FitRecipe,
@@ -85,7 +85,6 @@ def make_recipe():
optimize for the data/equation pair. This can be modified, but we
won't do that here.
"""
-
# The Profile
# Create a Profile to hold the experimental and calculated signal.
profile = Profile()
@@ -94,7 +93,7 @@ def make_recipe():
# data into the profile.
xydy = numpy.array(data.split(), dtype=float).reshape(-1, 3)
x, y, dy = xydy.T
- profile.setObservedProfile(x, y, dy)
+ profile.set_observed_profile(x, y, dy)
# The FitContribution
# The FitContribution associates the profile with the Debye function.
@@ -103,17 +102,17 @@ def make_recipe():
# independent variable (the temperature) from the data to calculate the
# theoretical signal, so give it an informative name ('T') that we can use
# later.
- contribution.setProfile(profile, xname="T")
+ contribution.set_profile(profile, xname="T")
# We now need to create the fitting equation. We tell the FitContribution
- # to use the 'debye' function defined below. The 'registerFunction' method
+ # to use the 'debye' function defined below. The 'register_function' method
# will let us do this. Since we haven't told it otherwise,
- # 'registerFunction' will extract the name of the function ('debye') and
+ # 'register_function' will extract the name of the function ('debye') and
# the names of the arguments ('T', 'm', 'thetaD'). These arguments will
# become Parameters of the FitContribution. Since we named the x-variable
# 'T' above, the 'T' in the 'debye' equation will refer to this x-variable
# whenever it is used.
- contribution.registerFunction(debye)
+ contribution.register_function(debye)
# Now we can create the fitting equation. We want to extend the 'debye'
# equation by adding a vertical offset. We could wrap 'debye' in a new
@@ -127,7 +126,7 @@ def make_recipe():
# the debye equation to be positive, so we specify the input as abs(thetaD)
# in the equation below. Furthermore, we know 'm', the mass of lead, so we
# can specify that as well.
- contribution.setEquation("debye(T, 207.2, abs(thetaD)) + offset")
+ contribution.set_equation("debye(T, 207.2, abs(thetaD)) + offset")
# The FitRecipe
# The FitRecipe lets us define what we want to fit. It is where we can
@@ -135,14 +134,14 @@ def make_recipe():
# to fit simultaneously, the contribution from each could be added to the
# recipe.
recipe = FitRecipe()
- recipe.addContribution(contribution)
+ recipe.add_contribution(contribution)
# Specify which Parameters we want to refine.
# Vary the offset
- recipe.addVar(contribution.offset, 0)
+ recipe.add_variable(contribution.offset, 0)
# We also vary the Debye temperature.
- recipe.addVar(contribution.thetaD, 100)
+ recipe.add_variable(contribution.thetaD, 100)
# We would like to 'suggest' that the offset should remain positive. This
# is somethine that we know about the system that might help the refinement
@@ -152,7 +151,7 @@ def make_recipe():
# breaking the restraint by the point-average chi^2 value so that the
# restraint is roughly as significant as any other data point throughout
# the fit.
- recipe.restrain(recipe.offset, lb=0, scaled=True)
+ recipe.add_soft_bounds(recipe.offset, lower_bound=0, scaled=True)
# We're done setting up the recipe. We can now do other things with it.
return recipe
@@ -160,7 +159,6 @@ def make_recipe():
def main():
"""The workflow of creating, running and inspecting a fit."""
-
# Create the recipe
recipe = make_recipe()
@@ -171,14 +169,17 @@ def main():
res = FitResults(recipe)
# Print the results
- res.printResults()
+ res.print_results()
# Plot the results
- x = recipe.pb.profile.x
- yobs = recipe.pb.profile.y
- ycalc = recipe.pb.profile.ycalc
-
- plot_results(x, yobs, ycalc)
+ recipe.plot_recipe(
+ show_diff=False,
+ data_label=r"Pb $U_{iso}$ Data",
+ fit_label="Calculated",
+ xlabel="T (K)",
+ ylabel=r"$U_{iso} (\AA^2)$",
+ legend_loc=(0.0, 0.8),
+ )
return
diff --git a/docs/examples/core/debye-waller/debyemodelII.py b/docs/examples/core/debye-waller/debyemodelII.py
index 875d8f7..107add0 100644
--- a/docs/examples/core/debye-waller/debyemodelII.py
+++ b/docs/examples/core/debye-waller/debyemodelII.py
@@ -56,7 +56,6 @@ def make_recipeII():
constrain the Debye temperature in each FitContribution to be the
same.
"""
-
# We'll throw these away. We just want the FitContributions that are
# configured within the recipes.
m1 = make_recipe()
@@ -73,66 +72,58 @@ def make_recipeII():
# Now create a fresh FitRecipe to work with and add to it the two
# FitContributions.
recipe = FitRecipe()
- recipe.addContribution(lowT)
- recipe.addContribution(highT)
+ recipe.add_contribution(lowT)
+ recipe.add_contribution(highT)
# Change the fit ranges of the Profiles embedded within the
# FitContributions. We want to fit one of the contributions at low
# temperature, and one at high.
- lowT.profile.setCalculationRange(0, 150)
- highT.profile.setCalculationRange(400, 500)
+ lowT.profile.set_calculation_range(0, 150)
+ highT.profile.set_calculation_range(400, 500)
# Vary the offset from each FitContribution separately, while keeping the
# Debye temperatures the same. We give each offset variable a different
# name in the recipe so it retains its identity.
- recipe.addVar(recipe.lowT.offset, name="lowToffset")
- recipe.addVar(recipe.highT.offset, name="highToffset")
+ recipe.add_variable(recipe.lowT.offset, name="lowToffset")
+ recipe.add_variable(recipe.highT.offset, name="highToffset")
# We create a new Variable and use the recipe's "constrain" method to
# associate the Debye temperature parameters with that variable.
- recipe.newVar("thetaD", 100)
- recipe.constrain(recipe.lowT.thetaD, "thetaD")
- recipe.constrain(recipe.highT.thetaD, "thetaD")
+ recipe.create_new_variable("thetaD", 100)
+ recipe.add_constraint(recipe.lowT.thetaD, "thetaD")
+ recipe.add_constraint(recipe.highT.thetaD, "thetaD")
return recipe
def plot_results(recipe):
"""Display the results contained within a refined FitRecipe."""
-
# The variable values are returned in the order in which the variables were
# added to the FitRecipe.
- lowToffset, highToffset, thetaD = recipe.getValues()
+ lowToffset, highToffset, thetaD = recipe.get_values()
+ print(
+ r"lowT: $T_d$=%3.1f K, offset=%1.5f $\AA^2$"
+ % (abs(thetaD), lowToffset)
+ )
+ print(
+ r"highT: $T_d$=%3.1f K, offset=%1.5f $\AA^2$"
+ % (abs(thetaD), highToffset)
+ )
# We want to extend the fitting range to its full extent so we can get a
- # nice full plot.
- recipe.lowT.profile.setCalculationRange(xmin="obs", xmax="obs")
- recipe.highT.profile.setCalculationRange(xmin="obs", xmax="obs")
- T = recipe.lowT.profile.x
- U = recipe.lowT.profile.y
- # We can use a FitContribution's 'evaluateEquation' method to evaluate
- # expressions involving the Parameters and other aspects of the
- # FitContribution. Here we evaluate the fitting equation, which is always
- # accessed using the name "eq". We access it this way (rather than through
- # the Profile's ycalc attribute) because we changed the calculation range
- # above, and we therefore need to recalculate the profile.
- lowU = recipe.lowT.evaluateEquation("eq")
- highU = recipe.highT.evaluateEquation("eq")
-
- # Now we can plot this.
- import pylab
-
- pylab.plot(T, U, "o", label="Pb $U_{iso}$ Data")
- lbl1 = r"$T_d$=%3.1f K, lowToff=%1.5f $\AA^2$" % (abs(thetaD), lowToffset)
- lbl2 = r"$T_d$=%3.1f K, highToff=%1.5f $\AA^2$" % (
- abs(thetaD),
- highToffset,
+ # nice full plot. Since the calculated profile is only valid for the
+ # calculation range that was used during the fit, we need to trigger a
+ # recalculation over the widened range before plotting.
+ recipe.lowT.profile.set_calculation_range(xmin="obs", xmax="obs")
+ recipe.highT.profile.set_calculation_range(xmin="obs", xmax="obs")
+ recipe.residual()
+
+ recipe.plot_recipe(
+ show_diff=False,
+ data_label=r"Pb $U_{iso}$ Data",
+ fit_label="Calculated",
+ xlabel="T (K)",
+ ylabel=r"$U_{iso} (\AA^2)$",
+ legend_loc=(0.0, 0.8),
)
- pylab.plot(T, lowU, label=lbl1)
- pylab.plot(T, highU, label=lbl2)
- pylab.xlabel("T (K)")
- pylab.ylabel(r"$U_{iso} (\AA^2)$")
- pylab.legend()
-
- pylab.show()
return
@@ -148,7 +139,7 @@ def main():
res = FitResults(recipe)
# Print the results
- res.printResults()
+ res.print_results()
# Plot the results
plot_results(recipe)
diff --git a/docs/examples/core/gaussianfit/gaussiangenerator.py b/docs/examples/core/gaussianfit/gaussiangenerator.py
index 5c98f6d..32eaf18 100644
--- a/docs/examples/core/gaussianfit/gaussiangenerator.py
+++ b/docs/examples/core/gaussianfit/gaussiangenerator.py
@@ -33,8 +33,8 @@
Extensions
-- Remove the amplitude from GaussianGenerator and instead use the 'setEquation'
- method of the FitContribution to account for it. Note that the
+- Remove the amplitude from GaussianGenerator and instead use the
+ 'set_equation' method of the FitContribution to account for it. Note that the
GaussianGenerator will be accessible by its name, "g".
"""
@@ -126,7 +126,6 @@ def make_recipe():
This will create a FitContribution that uses the GaussianGenerator,
associate this with a Profile, and use this to define a FitRecipe.
"""
-
# The Profile
# Create a Profile to hold the experimental and calculated signal.
profile = Profile()
@@ -147,13 +146,13 @@ def make_recipe():
# attribute of the FitContribution by its name ("g"). Note that this will
# set the fitting equation to "g", which calls the GaussianGenerator.
contribution = FitContribution("g1")
- contribution.addProfileGenerator(generator)
- contribution.setProfile(profile)
+ contribution.add_profile_generator(generator)
+ contribution.set_profile(profile)
# The FitRecipe
# Now we create the FitRecipe and add the FitContribution.
recipe = FitRecipe()
- recipe.addContribution(contribution)
+ recipe.add_contribution(contribution)
# Specify which Parameters we want to vary in the fit. This will add
# Variables to the FitRecipe that directly modify the Parameters of the
diff --git a/docs/examples/core/gaussianfit/gaussianrecipe.py b/docs/examples/core/gaussianfit/gaussianrecipe.py
index 9634a92..3881f17 100644
--- a/docs/examples/core/gaussianfit/gaussianrecipe.py
+++ b/docs/examples/core/gaussianfit/gaussianrecipe.py
@@ -26,8 +26,6 @@
to get an understanding of how a fit recipe can be used once created. After
that, read the 'make_recipe' code to see what goes into a fit recipe. After
that, read the 'optimize_recipe' code to see how the refinement is executed.
-Finally, read the 'plot_results' code to see how to extracts the refined
-profile and plot it.
Extensions
@@ -43,7 +41,6 @@
file.
"""
-
from pathlib import Path
from diffpy.srfit.fitbase import (
@@ -59,7 +56,6 @@
def main():
"""The workflow of creating, running and inspecting a fit."""
-
# Start by creating the recipe. The recipe describes the data to be fit,
# the profile generator used to simulate the data and the variables that
# will be tuned by the optimizer.
@@ -74,10 +70,10 @@ def main():
res = FitResults(recipe)
# Print the results.
- res.printResults()
+ res.print_results()
# Plot the results.
- plot_results(recipe)
+ recipe.plot_recipe()
return
@@ -96,7 +92,6 @@ def make_recipe():
Once we define the FitRecipe, we can send it an optimizer to be
optimized. See the 'optimize_recipe' function.
"""
-
# The Profile
# Create a Profile to hold the experimental and calculated signal.
profile = Profile()
@@ -116,7 +111,7 @@ def make_recipe():
# us access to the data held within the Profile. Here, we can tell it what
# name we want to use for the independent variable. We tell it to use the
# name "x".
- contribution.setProfile(profile, xname="x")
+ contribution.set_profile(profile, xname="x")
# Now we need to create a fitting equation. We do that by writing out the
# equation as a string. The FitContribution will turn this into a callable
@@ -126,7 +121,7 @@ def make_recipe():
# contribution by name. Since we told the contribution that our
# independent variable is named "x", this value will be substituted into
# the fitting equation whenever it is called.
- contribution.setEquation("A * exp(-0.5*(x-x0)**2/sigma**2)")
+ contribution.set_equation("A * exp(-0.5*(x-x0)**2/sigma**2)")
# To demonstrate how these parameters are used, we will give "A" an initial
# value. Note that Parameters are not numbers, but are containers for
@@ -142,7 +137,7 @@ def make_recipe():
# Here we tell the FitRecipe to use our FitContribution. When the FitRecipe
# calculates its residual function, it will call on the FitContribution to
# do part of the work.
- recipe.addContribution(contribution)
+ recipe.add_contribution(contribution)
# Specify which Parameters we want to vary in the fit. This will add
# Variables to the FitRecipe that directly modify the Parameters of the
@@ -151,13 +146,13 @@ def make_recipe():
# Here we create a Variable for the 'A' Parameter from our fit equation.
# The resulting Variable will be named 'A' as well, but it will be accessed
# via the FitRecipe.
- recipe.addVar(contribution.A)
+ recipe.add_variable(contribution.A)
# Here we create the Variable for 'x0' and give it an initial value of 5.
- recipe.addVar(contribution.x0, 5)
+ recipe.add_variable(contribution.x0, 5)
# Here we create a Variable named 'sig', which is tied to the 'sigma'
# Parameter of our FitContribution. We give it an initial value through the
# FitRecipe instance.
- recipe.addVar(contribution.sigma, name="sig")
+ recipe.add_variable(contribution.sigma, name="sig")
recipe.sig.value = 1
return recipe
@@ -170,45 +165,18 @@ def optimize_recipe(recipe):
we can be minimized using a scipy optimizer. The details are
described in the source.
"""
-
# We're going to use the least-squares (Levenberg-Marquardt) optimizer from
# scipy. We simply have to give it the function to minimize
# (recipe.residual) and the starting values of the Variables
- # (recipe.getValues()).
+ # (recipe.get_values()).
from scipy.optimize.minpack import leastsq
print("Fit using scipy's LM optimizer")
- leastsq(recipe.residual, recipe.getValues())
+ leastsq(recipe.residual, recipe.get_values())
return
-def plot_results(recipe):
- """Plot the results contained within a refined FitRecipe."""
-
- # We can access the data and fit profile through the Profile we created
- # above. We get to it through our FitContribution, which we named "g1".
- #
- # The independent variable. This is always under the "x" attribute.
- x = recipe.g1.profile.x
- # The observed profile that we loaded earlier, the "y" attribute.
- y = recipe.g1.profile.y
- # The calculated profile, the "ycalc" attribute.
- ycalc = recipe.g1.profile.ycalc
-
- # This stuff is specific to pylab from the matplotlib distribution.
- import pylab
-
- pylab.plot(x, y, "b.", label="observed Gaussian")
- pylab.plot(x, ycalc, "g-", label="calculated Gaussian")
- pylab.legend()
- pylab.xlabel("x")
- pylab.ylabel("y")
-
- pylab.show()
- return
-
-
if __name__ == "__main__":
main()
diff --git a/docs/examples/core/gaussianfit/interface.py b/docs/examples/core/gaussianfit/interface.py
index d00fcef..8ffae34 100644
--- a/docs/examples/core/gaussianfit/interface.py
+++ b/docs/examples/core/gaussianfit/interface.py
@@ -17,6 +17,7 @@
This is like gaussianrecipe.py, but it uses a shorthand interface
defined in the diffpy.srfit.interface.interface.py module.
"""
+
from pathlib import Path
from diffpy.srfit.fitbase import (
@@ -39,8 +40,8 @@ def main():
# FitContribution operations
# "<<" - Inject a parameter value
c = FitContribution("g1")
- c.setProfile(p)
- c.setEquation("A * exp(-0.5*(x-x0)**2/sigma**2)")
+ c.set_profile(p)
+ c.set_equation("A * exp(-0.5*(x-x0)**2/sigma**2)")
c.A << 0.5
c.x0 << 5
c.sigma << 1
@@ -48,7 +49,7 @@ def main():
# FitRecipe operations
# "|=" - Union of necessary components.
# "+=" - Add Parameter or create a new one. Each tuple is a set of
- # arguments for either setVar or addVar.
+ # arguments for either setVar or add_variable.
# "*=" - Constrain a parameter. Think of "*" as a push-pin holding one
# parameter's value to that of another.
# "%=" - Restrain a parameter or equation. Think of "%" as a rope
@@ -65,15 +66,9 @@ def main():
res = FitResults(r)
# Print the results.
- res.printResults()
+ res.print_results()
# Plot the results.
- from diffpy.cmi.fit_tools import plot_results
-
- x = r.g1.profile.x
- y = r.g1.profile.y
- ycalc = r.g1.profile.ycalc
-
- plot_results(x, y, ycalc)
+ r.plot_recipe(xlabel="x", ylabel="y")
return
diff --git a/docs/examples/core/gaussianfit/simplerecipe.py b/docs/examples/core/gaussianfit/simplerecipe.py
index 311ae8c..fc36c0d 100644
--- a/docs/examples/core/gaussianfit/simplerecipe.py
+++ b/docs/examples/core/gaussianfit/simplerecipe.py
@@ -29,7 +29,6 @@
def main():
"""Set up a simple recipe in a few lines."""
-
# The SimpleRecipe class is a type of FitRecipe. It provides attribute-like
# access to variables and a residual function that can be minimized.
recipe = SimpleRecipe()
@@ -41,7 +40,7 @@ def main():
# Set the equation. The variable "x" is taken from the data that was just
# loaded. The other variables, "A", "x0" and "sigma" are turned into
# attributes with an initial value of 0.
- recipe.setEquation("A * exp(-0.5*(x-x0)**2/sigma**2)")
+ recipe.set_equation("A * exp(-0.5*(x-x0)**2/sigma**2)")
# We can give them other values here.
recipe.A = 1
@@ -54,7 +53,7 @@ def main():
leastsq(recipe.residual, recipe.values)
# Print the results
- recipe.printResults()
+ recipe.print_results()
return
diff --git a/docs/examples/core/gaussianfit/threedoublepeaks.py b/docs/examples/core/gaussianfit/threedoublepeaks.py
index c5a4fd3..a62fc36 100644
--- a/docs/examples/core/gaussianfit/threedoublepeaks.py
+++ b/docs/examples/core/gaussianfit/threedoublepeaks.py
@@ -13,7 +13,7 @@
import numpy as np
-from diffpy.cmi.fit_tools import optimize_recipe, plot_results
+from diffpy.cmi.fit_tools import optimize_recipe
from diffpy.srfit.fitbase import (
FitContribution,
FitRecipe,
@@ -29,7 +29,6 @@ def make_recipe():
Robust version with safe defaults for dy, safe peak location
constraint, and stable delta/gaussian handling.
"""
-
# Profile - load data and ensure y/dy are set
profile = Profile()
data = str(Path(__file__).parent / "threedoublepeaks.dat")
@@ -44,7 +43,7 @@ def make_recipe():
# FitContribution
contribution = FitContribution("peaks")
- contribution.setProfile(profile, xname="t")
+ contribution.set_profile(profile, xname="t")
pi = np.pi
exp = np.exp
@@ -58,7 +57,7 @@ def gaussian(t, mu, sig):
* exp(-0.5 * ((t - mu) / sig) ** 2)
)
- contribution.registerFunction(gaussian, name="peakshape")
+ contribution.register_function(gaussian, name="peakshape")
# define a delta function (small width gaussian) for peak position
def delta(t, mu):
@@ -67,14 +66,14 @@ def delta(t, mu):
eps = max(1e-6, spacing * 0.1)
return gaussian(t, mu, eps)
- contribution.registerFunction(delta)
+ contribution.register_function(delta)
# background string function: 6th degree polynomial
bkgdstr = "b0 + b1*t + b2*t**2 + b3*t**3 + b4*t**4 + b5*t**5 + b6*t**6"
- contribution.registerStringFunction(bkgdstr, "bkgd")
+ contribution.register_string_function(bkgdstr, "bkgd")
# Define equation: three double-peaks with fixed amplitude ratio 0.23
- contribution.setEquation(
+ contribution.set_equation(
"A1 * ( convolve( delta(t, mu11), peakshape(t, c, sig11) ) "
" + 0.23*convolve( delta(t, mu12), peakshape(t, c, sig12) ) ) + "
"A2 * ( convolve( delta(t, mu21), peakshape(t, c, sig21) ) "
@@ -89,17 +88,17 @@ def delta(t, mu):
# Build recipe
recipe = FitRecipe()
- recipe.addContribution(contribution)
+ recipe.add_contribution(contribution)
# amplitudes
- recipe.addVar(contribution.A1, 100)
- recipe.addVar(contribution.A2, 100)
- recipe.addVar(contribution.A3, 100)
+ recipe.add_variable(contribution.A1, 100)
+ recipe.add_variable(contribution.A2, 100)
+ recipe.add_variable(contribution.A3, 100)
# primary peak positions
- recipe.addVar(contribution.mu11, 13.0)
- recipe.addVar(contribution.mu21, 24.0)
- recipe.addVar(contribution.mu31, 33.0)
+ recipe.add_variable(contribution.mu11, 13.0)
+ recipe.add_variable(contribution.mu21, 24.0)
+ recipe.add_variable(contribution.mu31, 33.0)
# Safe peak location constraint using arcsin with clipping
l1 = 1.012
@@ -115,14 +114,16 @@ def peakloc(mu):
out_rad = np.arcsin(arg)
return np.rad2deg(out_rad)
- recipe.registerFunction(peakloc)
- recipe.constrain(contribution.mu12, "peakloc(mu11)")
- recipe.constrain(contribution.mu22, "peakloc(mu21)")
- recipe.constrain(contribution.mu32, "peakloc(mu31)")
+ recipe.register_function(peakloc)
+ recipe.add_constraint(contribution.mu12, "peakloc(mu11)")
+ recipe.add_constraint(contribution.mu22, "peakloc(mu21)")
+ recipe.add_constraint(contribution.mu32, "peakloc(mu31)")
# Peak widths: use sig0 and dsig with a safer functional form (positive)
- recipe.newVar("sig0", 0.1) # base width in same units as t
- recipe.newVar("dsig", 0.001) # small quadratic broadening coefficient
+ recipe.create_new_variable("sig0", 0.1) # base width in same units as t
+ recipe.create_new_variable(
+ "dsig", 0.001
+ ) # small quadratic broadening coefficient
def sig(sig0, dsig, mu):
"""Compute sigma from base sig0, broadening dsig, and peak
@@ -132,22 +133,22 @@ def sig(sig0, dsig, mu):
# enforce a minimum width
return np.maximum(out, 1e-6)
- recipe.registerFunction(sig)
+ recipe.register_function(sig)
# Constrain the component sigmas
- recipe.constrain(contribution.sig11, "sig(sig0, dsig, mu11)")
- recipe.constrain(
+ recipe.add_constraint(contribution.sig11, "sig(sig0, dsig, mu11)")
+ recipe.add_constraint(
contribution.sig12,
"sig(sig0, dsig, mu12)",
ns={"mu12": contribution.mu12},
)
- recipe.constrain(contribution.sig21, "sig(sig0, dsig, mu21)")
- recipe.constrain(
+ recipe.add_constraint(contribution.sig21, "sig(sig0, dsig, mu21)")
+ recipe.add_constraint(
contribution.sig22,
"sig(sig0, dsig, mu22)",
ns={"mu22": contribution.mu22},
)
- recipe.constrain(contribution.sig31, "sig(sig0, dsig, mu31)")
- recipe.constrain(
+ recipe.add_constraint(contribution.sig31, "sig(sig0, dsig, mu31)")
+ recipe.add_constraint(
contribution.sig32,
"sig(sig0, dsig, mu32)",
ns={"mu32": contribution.mu32},
@@ -155,9 +156,10 @@ def sig(sig0, dsig, mu):
# background variables
for i in range(7):
- # addVar(param, startvalue, tag='bkgd') keeps them grouped for steering
+ # add_variable(param, startvalue, tag='bkgd') keeps them grouped for
+ # steering
p = getattr(contribution, f"b{i}")
- recipe.addVar(p, 0.0, tag="bkgd")
+ recipe.add_variable(p, 0.0, tag="bkgd")
# Initialize sig0/dsig sensible values
recipe.sig0.value = 0.1
@@ -166,7 +168,7 @@ def sig(sig0, dsig, mu):
return recipe
-def steerFit(recipe):
+def steer_fit(recipe):
"""Simple steering sequence (similar to your original)."""
# Start by fitting only background
recipe.fix("all")
@@ -186,10 +188,7 @@ def steerFit(recipe):
if __name__ == "__main__":
recipe = make_recipe()
- steerFit(recipe)
+ steer_fit(recipe)
res = FitResults(recipe)
- res.printResults()
- x = recipe.peaks.profile.x
- yobs = recipe.peaks.profile.y
- ycalc = recipe.peaks.profile.ycalc
- plot_results(x, yobs, ycalc, difference_offset=-700)
+ res.print_results()
+ recipe.plot_recipe()
diff --git a/docs/examples/core/intensityfit/npintensity.py b/docs/examples/core/intensityfit/npintensity.py
index 464f56f..9e4c8fd 100644
--- a/docs/examples/core/intensityfit/npintensity.py
+++ b/docs/examples/core/intensityfit/npintensity.py
@@ -32,18 +32,18 @@
Extensions
-- The IntensityGenerator class uses the 'addParameterSet' method to associate
+- The IntensityGenerator class uses the 'add_parameter_set' method to associate
the structure adapter (DiffpyStructureParSet) with the generator. Most SrFit
- classes have an 'addParameterSet' class and can store ParameterSet objects.
+ classes have an 'add_parameter_set' class and can store ParameterSet objects.
Grab the phase object from the IntensityGenerator and try to add it to other
objects used in the fit recipe. Create variables from the moved Parameters
rather than from the 'phase' that lives in the IntensityGenerator and see if
everything still refines.
"""
-
from pathlib import Path
+import matplotlib.pyplot as plt
import numpy
from diffpy.cmi.fit_tools import optimize_recipe
@@ -94,7 +94,7 @@ def __init__(self, name):
self.count = 0
return
- def setStructure(self, strufile):
+ def set_structure(self, strufile):
"""Set the structure used in the calculation.
strufile -- The name of a structure file. A
@@ -154,7 +154,7 @@ def setStructure(self, strufile):
parset = DiffpyStructureParSet("phase", stru)
# Put this ParameterSet in the ProfileGenerator.
- self.addParameterSet(parset)
+ self.add_parameter_set(parset)
return
@@ -165,8 +165,8 @@ def __call__(self, q):
will be optimized to fit some data. By the time this function
is evaluated, the diffpy.structure.Structure instance has been
updated by the optimizer via the DiffpyStructureParSet defined
- in setStructure. Thus, we need only call iofq with the internal
- structure object.
+ in set_structure. Thus, we need only call iofq with the
+ internal structure object.
"""
self.count += 1
print("iofq called", self.count)
@@ -182,7 +182,6 @@ def make_recipe(strufile, datname):
This will create a FitContribution that uses the IntensityGenerator,
associate this with a Profile, and use this to define a FitRecipe.
"""
-
# The Profile
# Create a Profile. This will hold the experimental and calculated signal.
profile = Profile()
@@ -195,7 +194,7 @@ def make_recipe(strufile, datname):
# refer to the generator from within the FitContribution equation. We also
# need to load the model structure we're using.
generator = IntensityGenerator("I")
- generator.setStructure(strufile)
+ generator.set_structure(strufile)
# The FitContribution
# Create a FitContribution, that will associate the Profile with the
@@ -204,8 +203,8 @@ def make_recipe(strufile, datname):
# the FitContribution to name the x-variable of the profile "q", so we can
# use it in equations with this name.
contribution = FitContribution("bucky")
- contribution.addProfileGenerator(generator)
- contribution.setProfile(profile, xname="q")
+ contribution.add_profile_generator(generator)
+ contribution.set_profile(profile, xname="q")
# Now we're ready to define the fitting equation for the FitContribution.
# We need to modify the intensity calculation, and we'll do that from
@@ -232,7 +231,7 @@ def make_recipe(strufile, datname):
# This creates a callable equation named "bkgd" within the FitContribution,
# and turns the polynomial coefficients into Parameters.
- contribution.registerStringFunction(bkgdstr, "bkgd")
+ contribution.register_string_function(bkgdstr, "bkgd")
# We will create the broadening function that we need by creating a python
# function and registering it with the FitContribution.
@@ -248,7 +247,7 @@ def gaussian(q, q0, width):
# This registers the python function and extracts the name and creates
# Parameters from the arguments.
- contribution.registerFunction(gaussian)
+ contribution.register_function(gaussian)
# Center the Gaussian so it is not truncated.
contribution.q0.value = x[len(x) // 2]
@@ -257,27 +256,27 @@ def gaussian(q, q0, width):
# convolve the signal with the Gaussian to broaden it. Recall that we don't
# need to supply arguments to the registered functions unless we want to
# make changes to their input values.
- contribution.setEquation("scale * convolve(I, gaussian) + bkgd")
+ contribution.set_equation("scale * convolve(I, gaussian) + bkgd")
# Make the FitRecipe and add the FitContribution.
recipe = FitRecipe()
- recipe.addContribution(contribution)
+ recipe.add_contribution(contribution)
# Specify which parameters we want to refine.
- recipe.addVar(contribution.b0, 0)
- recipe.addVar(contribution.b1, 0)
- recipe.addVar(contribution.b2, 0)
- recipe.addVar(contribution.b3, 0)
- recipe.addVar(contribution.b4, 0)
- recipe.addVar(contribution.b5, 0)
- recipe.addVar(contribution.b6, 0)
- recipe.addVar(contribution.b7, 0)
- recipe.addVar(contribution.b8, 0)
- recipe.addVar(contribution.b9, 0)
+ recipe.add_variable(contribution.b0, 0)
+ recipe.add_variable(contribution.b1, 0)
+ recipe.add_variable(contribution.b2, 0)
+ recipe.add_variable(contribution.b3, 0)
+ recipe.add_variable(contribution.b4, 0)
+ recipe.add_variable(contribution.b5, 0)
+ recipe.add_variable(contribution.b6, 0)
+ recipe.add_variable(contribution.b7, 0)
+ recipe.add_variable(contribution.b8, 0)
+ recipe.add_variable(contribution.b9, 0)
# We also want to adjust the scale and the convolution width
- recipe.addVar(contribution.scale, 1)
- recipe.addVar(contribution.width, 0.1)
+ recipe.add_variable(contribution.scale, 1)
+ recipe.add_variable(contribution.width, 0.1)
# We can also refine structural parameters. Here we extract the
# DiffpyStructureParSet from the intensity generator and use the parameters
@@ -290,16 +289,16 @@ def gaussian(q, q0, width):
# constrained to a Variable by name. This has the same effect.
lattice = phase.getLattice()
a = lattice.a
- recipe.addVar(a)
- recipe.constrain(lattice.b, a)
- recipe.constrain(lattice.c, a)
+ recipe.add_variable(a)
+ recipe.add_constraint(lattice.b, a)
+ recipe.add_constraint(lattice.c, a)
# We want to refine the thermal parameters as well. We will add a new
# Variable that we call "Uiso" and constrain the atomic Uiso values to
# this. Note that we don't give Uiso an initial value. The initial value
# will be inferred from the following constraints.
- Uiso = recipe.newVar("Uiso")
+ Uiso = recipe.create_new_variable("Uiso")
for atom in phase.getScatterers():
- recipe.constrain(atom.Uiso, Uiso)
+ recipe.add_constraint(atom.Uiso, Uiso)
# Give the recipe away so it can be used!
return recipe
@@ -311,7 +310,7 @@ def main():
strufile = str((Path(__file__).parent / "C60.stru").resolve())
q = numpy.arange(1, 20, 0.05)
iq_path = str((Path(__file__).parent / "C60.iq").resolve())
- makeData(strufile, q, iq_path, 1.0, 100.68, 0.005, 0.13, 2)
+ make_data(strufile, q, iq_path, 1.0, 100.68, 0.005, 0.13, 2)
# Make the recipe
recipe = make_recipe(strufile, iq_path)
@@ -328,7 +327,7 @@ def main():
rescount = recipe.fithooks[0].count
calcount = recipe.bucky.I.count
footer = "iofq called %i%% of the time" % int(100.0 * calcount / rescount)
- res.printResults(footer=footer)
+ res.print_results(footer=footer)
# Plot!
plot_results(recipe)
@@ -338,26 +337,27 @@ def main():
def plot_results(recipe):
"""Plot the results contained within a refined FitRecipe."""
-
- # All this should be pretty familiar by now.
+ # The background is not part of the standard observed/fit/diff plot
+ # that plot_recipe produces, so we overlay it afterwards.
q = recipe.bucky.profile.x
-
- Imeas = recipe.bucky.profile.y
- Icalc = recipe.bucky.profile.ycalc
- bkgd = recipe.bucky.evaluateEquation("bkgd")
- diff = Imeas - Icalc
-
- import pylab
-
- pylab.plot(q, Imeas, "ob", label="I(Q) Data")
- pylab.plot(q, Icalc, "r-", label="I(Q) Fit")
- pylab.plot(q, diff, "g-", label="I(Q) diff")
- pylab.plot(q, bkgd, "c-", label="Bkgd. Fit")
- pylab.xlabel(r"$Q (\AA^{-1})$")
- pylab.ylabel("Intensity (arb. units)")
- pylab.legend(loc=1)
-
- pylab.show()
+ bkgd = recipe.bucky.evaluate_equation("bkgd")
+
+ fig, ax = recipe.plot_recipe(
+ show=False,
+ return_fig=True,
+ data_color="b",
+ fit_color="r",
+ diff_color="g",
+ data_label="I(Q) Data",
+ fit_label="I(Q) Fit",
+ diff_label="I(Q) diff",
+ xlabel=r"$Q (\AA^{-1})$",
+ ylabel="Intensity (arb. units)",
+ )
+ ax.plot(q, bkgd, "c-", label="Bkgd. Fit")
+ ax.legend(loc=1)
+
+ plt.show()
return
@@ -425,7 +425,7 @@ def iofq(S, q):
# First we must cache the scattering factors
fdict = {}
for el in elcount:
- fdict[el] = getXScatteringFactor(el, q)
+ fdict[el] = get_x_scattering_factor(el, q)
# Now we can compute I(Q) for the i != j pairs
y = 0
@@ -453,7 +453,7 @@ def iofq(S, q):
return y
-def getXScatteringFactor(el, q):
+def get_x_scattering_factor(el, q):
"""Get the x-ray scattering factor for an element over the q range.
If cctbx is not available, f(q) = 1 is used.
@@ -470,7 +470,7 @@ def getXScatteringFactor(el, q):
return 1
-def makeData(strufile, q, datname, scale, a, Uiso, sig, bkgc, nl=1):
+def make_data(strufile, q, datname, scale, a, Uiso, sig, bkgc, nl=1):
"""Make some fake data and save it to file.
Make some data to fit. This uses iofq to calculate an intensity curve, and
@@ -486,14 +486,13 @@ def makeData(strufile, q, datname, scale, a, Uiso, sig, bkgc, nl=1):
bkgc -- A parameter that gives minor control of the background.
nl -- Noise level (0, inf), default 1, larger -> less noise.
"""
-
from diffpy.structure import Structure
S = Structure()
S.read(strufile)
# Set the lattice parameters
- S.lattice.setLatPar(a, a, a)
+ S.lattice.set_latt_parms(a, a, a)
# Set a DW factor
for a in S:
diff --git a/docs/examples/core/intensityfit/npintensityII.py b/docs/examples/core/intensityfit/npintensityII.py
index 32508c2..6400fea 100644
--- a/docs/examples/core/intensityfit/npintensityII.py
+++ b/docs/examples/core/intensityfit/npintensityII.py
@@ -33,10 +33,12 @@
mistakes in the code. This encapsulation of configuration workflow is the
first step towards writing a user interface.
"""
+
from pathlib import Path
+import matplotlib.pyplot as plt
import numpy
-from npintensity import IntensityGenerator, makeData
+from npintensity import IntensityGenerator, make_data
from diffpy.cmi.fit_tools import optimize_recipe
from diffpy.srfit.fitbase import (
@@ -64,7 +66,6 @@ def make_recipe(strufile, datname1, datname2):
(which is generated by the IntensityGenerator when we load the
structure) in both generators.
"""
-
# The Profiles
# Create two Profiles for the two FitContributions.
profile1 = Profile()
@@ -83,30 +84,31 @@ def make_recipe(strufile, datname1, datname2):
# using the exact same Parameters, and underlying Structure object in the
# calculation of the profile.
generator1 = IntensityGenerator("I")
- generator1.setStructure(strufile)
+ generator1.set_structure(strufile)
generator2 = IntensityGenerator("I")
- generator2.addParameterSet(generator1.phase)
+ generator2.add_parameter_set(generator1.phase)
# The FitContributions
# Create the FitContributions.
contribution1 = FitContribution("bucky1")
- contribution1.addProfileGenerator(generator1)
- contribution1.setProfile(profile1, xname="q")
+ contribution1.add_profile_generator(generator1)
+ contribution1.set_profile(profile1, xname="q")
contribution2 = FitContribution("bucky2")
- contribution2.addProfileGenerator(generator2)
- contribution2.setProfile(profile2, xname="q")
+ contribution2.add_profile_generator(generator2)
+ contribution2.set_profile(profile2, xname="q")
# Now we're ready to define the fitting equation for each FitContribution.
# The functions registered below will be independent, even though they take
# the same form and use the same Parameter names. By default, Parameters
# in different contributions are different Parameters even if they have the
# same names. FitContributions are isolated namespaces than only share
- # information if you tell them to by using addParameter or addParameterSet.
+ # information if you tell them to by using addParameter or
+ # add_parameter_set.
bkgdstr = "b0 + b1*q + b2*q**2 + b3*q**3 + b4*q**4 + b5*q**5 + b6*q**6 +\
b7*q**7 +b8*q**8 + b9*q**9"
- contribution1.registerStringFunction(bkgdstr, "bkgd")
- contribution2.registerStringFunction(bkgdstr, "bkgd")
+ contribution1.register_string_function(bkgdstr, "bkgd")
+ contribution2.register_string_function(bkgdstr, "bkgd")
# We will create the broadening function by registering a python function.
pi = numpy.pi
@@ -119,114 +121,102 @@ def gaussian(q, q0, width):
* exp(-0.5 * ((q - q0) / width) ** 2)
)
- contribution1.registerFunction(gaussian)
- contribution2.registerFunction(gaussian)
+ contribution1.register_function(gaussian)
+ contribution2.register_function(gaussian)
# Center the gaussian
contribution1.q0.value = x[len(x) // 2]
contribution2.q0.value = x[len(x) // 2]
# Now we can incorporate the scale and bkgd into our calculation. We also
# convolve the signal with the gaussian to broaden it.
- contribution1.setEquation("scale * convolve(I, gaussian) + bkgd")
- contribution2.setEquation("scale * convolve(I, gaussian) + bkgd")
+ contribution1.set_equation("scale * convolve(I, gaussian) + bkgd")
+ contribution2.set_equation("scale * convolve(I, gaussian) + bkgd")
# Make a FitRecipe and associate the FitContributions.
recipe = FitRecipe()
- recipe.addContribution(contribution1)
- recipe.addContribution(contribution2)
+ recipe.add_contribution(contribution1)
+ recipe.add_contribution(contribution2)
# Specify which Parameters we want to refine. We want to refine the
# background that we just defined in the FitContributions. We have to do
# this separately for each FitContribution. We tag the variables so it is
# easy to retrieve the background variables.
- recipe.addVar(contribution1.b0, 0, name="b1_0", tag="bcoeffs1")
- recipe.addVar(contribution1.b1, 0, name="b1_1", tag="bcoeffs1")
- recipe.addVar(contribution1.b2, 0, name="b1_2", tag="bcoeffs1")
- recipe.addVar(contribution1.b3, 0, name="b1_3", tag="bcoeffs1")
- recipe.addVar(contribution1.b4, 0, name="b1_4", tag="bcoeffs1")
- recipe.addVar(contribution1.b5, 0, name="b1_5", tag="bcoeffs1")
- recipe.addVar(contribution1.b6, 0, name="b1_6", tag="bcoeffs1")
- recipe.addVar(contribution1.b7, 0, name="b1_7", tag="bcoeffs1")
- recipe.addVar(contribution1.b8, 0, name="b1_8", tag="bcoeffs1")
- recipe.addVar(contribution1.b9, 0, name="b1_9", tag="bcoeffs1")
- recipe.addVar(contribution2.b0, 0, name="b2_0", tag="bcoeffs2")
- recipe.addVar(contribution2.b1, 0, name="b2_1", tag="bcoeffs2")
- recipe.addVar(contribution2.b2, 0, name="b2_2", tag="bcoeffs2")
- recipe.addVar(contribution2.b3, 0, name="b2_3", tag="bcoeffs2")
- recipe.addVar(contribution2.b4, 0, name="b2_4", tag="bcoeffs2")
- recipe.addVar(contribution2.b5, 0, name="b2_5", tag="bcoeffs2")
- recipe.addVar(contribution2.b6, 0, name="b2_6", tag="bcoeffs2")
- recipe.addVar(contribution2.b7, 0, name="b2_7", tag="bcoeffs2")
- recipe.addVar(contribution2.b8, 0, name="b2_8", tag="bcoeffs2")
- recipe.addVar(contribution2.b9, 0, name="b2_9", tag="bcoeffs2")
+ recipe.add_variable(contribution1.b0, 0, name="b1_0", tag="bcoeffs1")
+ recipe.add_variable(contribution1.b1, 0, name="b1_1", tag="bcoeffs1")
+ recipe.add_variable(contribution1.b2, 0, name="b1_2", tag="bcoeffs1")
+ recipe.add_variable(contribution1.b3, 0, name="b1_3", tag="bcoeffs1")
+ recipe.add_variable(contribution1.b4, 0, name="b1_4", tag="bcoeffs1")
+ recipe.add_variable(contribution1.b5, 0, name="b1_5", tag="bcoeffs1")
+ recipe.add_variable(contribution1.b6, 0, name="b1_6", tag="bcoeffs1")
+ recipe.add_variable(contribution1.b7, 0, name="b1_7", tag="bcoeffs1")
+ recipe.add_variable(contribution1.b8, 0, name="b1_8", tag="bcoeffs1")
+ recipe.add_variable(contribution1.b9, 0, name="b1_9", tag="bcoeffs1")
+ recipe.add_variable(contribution2.b0, 0, name="b2_0", tag="bcoeffs2")
+ recipe.add_variable(contribution2.b1, 0, name="b2_1", tag="bcoeffs2")
+ recipe.add_variable(contribution2.b2, 0, name="b2_2", tag="bcoeffs2")
+ recipe.add_variable(contribution2.b3, 0, name="b2_3", tag="bcoeffs2")
+ recipe.add_variable(contribution2.b4, 0, name="b2_4", tag="bcoeffs2")
+ recipe.add_variable(contribution2.b5, 0, name="b2_5", tag="bcoeffs2")
+ recipe.add_variable(contribution2.b6, 0, name="b2_6", tag="bcoeffs2")
+ recipe.add_variable(contribution2.b7, 0, name="b2_7", tag="bcoeffs2")
+ recipe.add_variable(contribution2.b8, 0, name="b2_8", tag="bcoeffs2")
+ recipe.add_variable(contribution2.b9, 0, name="b2_9", tag="bcoeffs2")
# We also want to adjust the scale and the convolution width
- recipe.addVar(contribution1.scale, 1, name="scale1")
- recipe.addVar(contribution1.width, 0.1, name="width1")
- recipe.addVar(contribution2.scale, 1, name="scale2")
- recipe.addVar(contribution2.width, 0.1, name="width2")
+ recipe.add_variable(contribution1.scale, 1, name="scale1")
+ recipe.add_variable(contribution1.width, 0.1, name="width1")
+ recipe.add_variable(contribution2.scale, 1, name="scale2")
+ recipe.add_variable(contribution2.width, 0.1, name="width2")
# We can also refine structural parameters. We only have to do this once,
# since each generator holds the same DiffpyStructureParSet.
phase = generator1.phase
lattice = phase.getLattice()
- a = recipe.addVar(lattice.a)
+ a = recipe.add_variable(lattice.a)
# We want to allow for isotropic expansion, so we'll make constraints for
# that.
- recipe.constrain(lattice.b, a)
- recipe.constrain(lattice.c, a)
+ recipe.add_constraint(lattice.b, a)
+ recipe.add_constraint(lattice.c, a)
# We want to refine the thermal parameters as well. We will add a new
# variable that we call "Uiso" and constrain the atomic Uiso values to
# this. Note that we don't give Uiso an initial value. The initial value
# will be inferred from the subsequent constraints.
- Uiso = recipe.newVar("Uiso")
+ Uiso = recipe.create_new_variable("Uiso")
for atom in phase.getScatterers():
- recipe.constrain(atom.Uiso, Uiso)
+ recipe.add_constraint(atom.Uiso, Uiso)
# Give the recipe away so it can be used!
return recipe
def plot_results(recipe):
- """Plot the results contained within a refined FitRecipe."""
+ """Plot the results contained within a refined FitRecipe.
- # plotting song and dance
+ The recipe has two contributions ("bucky1" and "bucky2"), so
+ plot_recipe produces one figure per contribution. The backgrounds
+ are not part of the standard observed/fit/diff plot, so they are
+ overlaid on each figure afterwards.
+ """
q = recipe.bucky1.profile.x
-
- # Plot this for fun.
- I1 = recipe.bucky1.profile.y
- Icalc1 = recipe.bucky1.profile.ycalc
- bkgd1 = recipe.bucky1.evaluateEquation("bkgd")
- diff1 = I1 - Icalc1
- I2 = recipe.bucky2.profile.y
- Icalc2 = recipe.bucky2.profile.ycalc
- bkgd2 = recipe.bucky2.evaluateEquation("bkgd")
- diff2 = I2 - Icalc2
- offset = 1.2 * max(I2) * numpy.ones_like(I2)
- I1 += offset
- Icalc1 += offset
- bkgd1 += offset
- diff1 += offset
-
- import pylab
-
- pylab.subplot(2, 1, 1)
- pylab.plot(q, I1, "bo", label="I1(Q) Data")
- pylab.plot(q, Icalc1, "r-", label="I1(Q) Fit")
- pylab.plot(q, diff1, "g-", label="I1(Q) diff")
- pylab.plot(q, bkgd1, "c-", label="Bkgd1 Fit")
- pylab.legend(loc=1)
-
- pylab.subplot(2, 1, 2)
- pylab.plot(q, I2, "bo", label="I2(Q) Data")
- pylab.plot(q, Icalc2, "r-", label="I2(Q) Fit")
- pylab.plot(q, diff2, "g-", label="I2(Q) diff")
- pylab.plot(q, bkgd2, "c-", label="Bkgd2 Fit")
- pylab.xlabel(r"$Q (\AA^{-1})$")
- pylab.ylabel("Intensity (arb. units)")
- pylab.legend(loc=1)
-
- pylab.show()
+ bkgd1 = recipe.bucky1.evaluate_equation("bkgd")
+ bkgd2 = recipe.bucky2.evaluate_equation("bkgd")
+
+ figs, axes = recipe.plot_recipe(
+ show=False,
+ return_fig=True,
+ data_label="I(Q) Data",
+ fit_label="I(Q) Fit",
+ diff_label="I(Q) diff",
+ xlabel=r"$Q (\AA^{-1})$",
+ ylabel="Intensity (arb. units)",
+ )
+ # "bucky1" was added to the recipe first, so its axes come first.
+ axes[0].plot(q, bkgd1, "c-", label="Bkgd1 Fit")
+ axes[0].legend(loc=1)
+ axes[1].plot(q, bkgd2, "c-", label="Bkgd2 Fit")
+ axes[1].legend(loc=1)
+
+ plt.show()
return
@@ -239,8 +229,8 @@ def main():
iq1_path = str((Path(__file__).parent / "C60_1.iq").resolve())
iq2_path = str((Path(__file__).parent / "C60_2.iq").resolve())
q = numpy.arange(1, 20, 0.05)
- makeData(strufile, q, iq1_path, 8.1, 101.68, 0.008, 0.12, 2, 0.01)
- makeData(strufile, q, iq2_path, 3.2, 101.68, 0.02, 0.003, 0, 1)
+ make_data(strufile, q, iq1_path, 8.1, 101.68, 0.008, 0.12, 2, 0.01)
+ make_data(strufile, q, iq2_path, 3.2, 101.68, 0.02, 0.003, 0, 1)
# Make the recipe
recipe = make_recipe(strufile, iq1_path, iq2_path)
@@ -253,22 +243,22 @@ def main():
# fit.
recipe.fix("all")
recipe.free("bcoeffs1")
- recipe.setWeight(recipe.bucky2, 0)
+ recipe.set_weight(recipe.bucky2, 0)
optimize_recipe(recipe)
# Now do the same for the second background
recipe.fix("all")
recipe.free("bcoeffs1")
- recipe.setWeight(recipe.bucky2, 1)
- recipe.setWeight(recipe.bucky1, 0)
+ recipe.set_weight(recipe.bucky2, 1)
+ recipe.set_weight(recipe.bucky1, 0)
optimize_recipe(recipe)
# Now refine everything with the structure parameters included
recipe.free("all")
- recipe.setWeight(recipe.bucky1, 1)
+ recipe.set_weight(recipe.bucky1, 1)
optimize_recipe(recipe)
# Generate and print the FitResults
res = FitResults(recipe)
- res.printResults()
+ res.print_results()
# Plot!
plot_results(recipe)
diff --git a/docs/examples/core/linefit/03-SrFit-demo-constraints-restraints.ipynb b/docs/examples/core/linefit/03-SrFit-demo-constraints-restraints.ipynb
index ba0b178..2d19c34 100644
--- a/docs/examples/core/linefit/03-SrFit-demo-constraints-restraints.ipynb
+++ b/docs/examples/core/linefit/03-SrFit-demo-constraints-restraints.ipynb
@@ -47,7 +47,7 @@
"source": [
"from diffpy.srfit.fitbase import Profile\n",
"linedata = Profile()\n",
- "linedata.setObservedProfile(xobs, yobs, dyobs)"
+ "linedata.set_observed_profile(xobs, yobs, dyobs)"
]
},
{
@@ -65,8 +65,8 @@
"source": [
"from diffpy.srfit.fitbase import FitContribution\n",
"linefit = FitContribution('linefit')\n",
- "linefit.setProfile(linedata)\n",
- "linefit.setEquation(\"A * x + B\")"
+ "linefit.set_profile(linedata)\n",
+ "linefit.set_equation(\"A * x + B\")"
]
},
{
@@ -155,7 +155,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "The `clearFitHooks()` function suppresses printout of iteration numbers. The `addContribution()` function includes the specified FitContribution in the FitRecipe, which acts as a top-level manager of all associated fits. "
+ "The `clear_fit_hooks()` function suppresses printout of iteration numbers. The `add_contribution()` function includes the specified FitContribution in the FitRecipe, which acts as a top-level manager of all associated fits. "
]
},
{
@@ -164,8 +164,8 @@
"metadata": {},
"outputs": [],
"source": [
- "rec.clearFitHooks()\n",
- "rec.addContribution(linefit)\n",
+ "rec.clear_fit_hooks()\n",
+ "rec.add_contribution(linefit)\n",
"rec.show()"
]
},
@@ -183,15 +183,15 @@
"metadata": {},
"outputs": [],
"source": [
- "rec.addVar(rec.linefit.A)\n",
- "rec.addVar(rec.linefit.B)"
+ "rec.add_variable(rec.linefit.A)\n",
+ "rec.add_variable(rec.linefit.B)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- " The call of the addVar function also created two attributes A and B for the rec object,\n",
+ " The call of the add_variable function also created two attributes A and B for the rec object,\n",
" which link to the A and B parameters of the linefit contribution.\n"
]
},
@@ -294,15 +294,14 @@
"metadata": {},
"outputs": [],
"source": [
- "plot(linedata.x, linedata.y, 'x', linedata.x, linedata.ycalc, '-')\n",
- "title('Line fit using the leastsq least-squares optimizer');"
+ "rec.plot_recipe(show_diff=False, title='Line fit using the leastsq least-squares optimizer')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "The `FitRecipe.scalarResidual()` function returns the sum of squares and can\n",
+ "The `FitRecipe.scalar_residual()` function returns the sum of squares and can\n",
"be used with a minimizer that requires a scalar function:"
]
},
@@ -313,10 +312,9 @@
"outputs": [],
"source": [
"from scipy.optimize import fmin\n",
- "fmin(rec.scalarResidual, [1, 1])\n",
+ "fmin(rec.scalar_residual, [1, 1])\n",
"print(rec.names, \"-->\", rec.values)\n",
- "plot(linedata.x, linedata.y, 'x', linedata.x, linedata.ycalc, '-')\n",
- "title('Line fit using the fmin scalar optimizer');"
+ "rec.plot_recipe(show_diff=False, title='Line fit using the fmin scalar optimizer')"
]
},
{
@@ -387,8 +385,7 @@
"source": [
"leastsq(rec.residual, rec.values)\n",
"print(FitResults(rec))\n",
- "plot(linedata.x, linedata.y, 'x', linedata.x, linedata.ycalc, '-')\n",
- "title('Line fit for variable B fixed to B=0');"
+ "rec.plot_recipe(show_diff=False, title='Line fit for variable B fixed to B=0')"
]
},
{
@@ -421,7 +418,7 @@
"metadata": {},
"outputs": [],
"source": [
- "rec.constrain(rec.A, \"2 * B\")"
+ "rec.add_constraint(rec.A, \"2 * B\")"
]
},
{
@@ -439,15 +436,14 @@
"source": [
"leastsq(rec.residual, rec.values)\n",
"print(FitResults(rec))\n",
- "plot(linedata.x, linedata.y, 'x', linedata.x, linedata.ycalc, '-')\n",
- "title('Line fit for variable A constrained to A = 2*B');"
+ "rec.plot_recipe(show_diff=False, title='Line fit for variable A constrained to A = 2*B')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "Constraint expressions can be removed by calling the unconstrain function."
+ "Constraint expressions can be removed by calling the remove_constraint function."
]
},
{
@@ -456,7 +452,7 @@
"metadata": {},
"outputs": [],
"source": [
- "rec.unconstrain(rec.A)"
+ "rec.remove_constraint(rec.A)"
]
},
{
@@ -474,7 +470,7 @@
"metadata": {},
"outputs": [],
"source": [
- "arst = rec.restrain(rec.A, ub=0.2, sig=0.001)"
+ "arst = rec.add_soft_bounds(rec.A, upper_bound=0.2, sig=0.001)"
]
},
{
@@ -492,8 +488,7 @@
"source": [
"leastsq(rec.residual, rec.values)\n",
"print(FitResults(rec))\n",
- "plot(linedata.x, linedata.y, 'x', linedata.x, linedata.ycalc, '-')\n",
- "title('Line fit with A restrained to an upper bound of 0.2');"
+ "rec.plot_recipe(show_diff=False, title='Line fit with A restrained to an upper bound of 0.2')"
]
}
],
diff --git a/docs/examples/core/linefit/SrFit-demo-constraints-restraints.py b/docs/examples/core/linefit/SrFit-demo-constraints-restraints.py
index 4e4a651..ea16837 100644
--- a/docs/examples/core/linefit/SrFit-demo-constraints-restraints.py
+++ b/docs/examples/core/linefit/SrFit-demo-constraints-restraints.py
@@ -26,14 +26,14 @@ def main():
# Create a Profile object to hold the data
# ----------------------------------------------------------------------
linedata = Profile()
- linedata.setObservedProfile(xobs, yobs, dyobs)
+ linedata.set_observed_profile(xobs, yobs, dyobs)
# ----------------------------------------------------------------------
# Define a FitContribution: linear model A*x + B
# ----------------------------------------------------------------------
linefit = FitContribution("linefit")
- linefit.setProfile(linedata)
- linefit.setEquation("A * x + B")
+ linefit.set_profile(linedata)
+ linefit.set_equation("A * x + B")
linefit.show()
@@ -55,13 +55,13 @@ def main():
# Create a FitRecipe to manage fitting
# ----------------------------------------------------------------------
rec = FitRecipe()
- rec.clearFitHooks()
- rec.addContribution(linefit)
+ rec.clear_fit_hooks()
+ rec.add_contribution(linefit)
rec.show()
# Add variables to be refined
- rec.addVar(rec.linefit.A)
- rec.addVar(rec.linefit.B)
+ rec.add_variable(rec.linefit.A)
+ rec.add_variable(rec.linefit.B)
print("rec.A =", rec.A)
print("rec.A.value =", rec.A.value)
@@ -77,19 +77,15 @@ def main():
print("After leastsq:", rec.names, "-->", rec.values)
linefit.show()
- plot(linedata.x, linedata.y, "x", linedata.x, linedata.ycalc, "-")
- title("Line fit using leastsq optimizer")
- plt.show()
+ rec.plot_recipe(show_diff=False, title="Line fit using leastsq optimizer")
# ----------------------------------------------------------------------
# Fit using scalar optimizer (fmin)
# ----------------------------------------------------------------------
- fmin(rec.scalarResidual, [1, 1])
+ fmin(rec.scalar_residual, [1, 1])
print("After fmin:", rec.names, "-->", rec.values)
- plot(linedata.x, linedata.y, "x", linedata.x, linedata.ycalc, "-")
- title("Line fit using fmin optimizer")
- plt.show()
+ rec.plot_recipe(show_diff=False, title="Line fit using fmin optimizer")
# Display fit results
res = FitResults(rec)
@@ -105,35 +101,31 @@ def main():
leastsq(rec.residual, rec.values)
print("Fit with B fixed to 0:", FitResults(rec))
- plot(linedata.x, linedata.y, "x", linedata.x, linedata.ycalc, "-")
- title("Line fit with B fixed at 0")
- plt.show()
+ rec.plot_recipe(show_diff=False, title="Line fit with B fixed at 0")
rec.free("all")
# ----------------------------------------------------------------------
# Example: Adding a constraint (A = 2*B)
# ----------------------------------------------------------------------
- rec.constrain(rec.A, "2 * B")
+ rec.add_constraint(rec.A, "2 * B")
leastsq(rec.residual, rec.values)
print("Fit with A constrained to 2*B:", FitResults(rec))
- plot(linedata.x, linedata.y, "x", linedata.x, linedata.ycalc, "-")
- title("Line fit with constraint A=2*B")
- plt.show()
+ rec.plot_recipe(show_diff=False, title="Line fit with constraint A=2*B")
- rec.unconstrain(rec.A)
+ rec.remove_constraint(rec.A)
# ----------------------------------------------------------------------
# Example: Adding a restraint (A close to <= 0.2 with penalty)
# ----------------------------------------------------------------------
- rec.restrain(rec.A, ub=0.2, sig=0.001)
+ rec.add_soft_bounds(rec.A, upper_bound=0.2, sig=0.001)
leastsq(rec.residual, rec.values)
print("Fit with A restrained to ub=0.2:", FitResults(rec))
- plot(linedata.x, linedata.y, "x", linedata.x, linedata.ycalc, "-")
- title("Line fit with restraint on A (ub=0.2)")
- plt.show()
+ rec.plot_recipe(
+ show_diff=False, title="Line fit with restraint on A (ub=0.2)"
+ )
if __name__ == "__main__":
diff --git a/docs/examples/pdf/ch03NiModelling/exercises/diffpy-cmi/fitBulkNi.ipynb b/docs/examples/pdf/ch03NiModelling/exercises/diffpy-cmi/fitBulkNi.ipynb
index ccee65e..7e578ea 100644
--- a/docs/examples/pdf/ch03NiModelling/exercises/diffpy-cmi/fitBulkNi.ipynb
+++ b/docs/examples/pdf/ch03NiModelling/exercises/diffpy-cmi/fitBulkNi.ipynb
@@ -64,8 +64,8 @@
"from diffpy.srfit.fitbase import FitResults\n",
"from diffpy.srfit.fitbase import Profile\n",
"from diffpy.srfit.pdf import PDFParser, PDFGenerator\n",
- "from diffpy.structure.parsers import getParser\n",
- "from diffpy.srfit.structure import constrainAsSpaceGroup"
+ "from diffpy.structure.parsers import get_parser\n",
+ "from diffpy.srfit.structure import constrain_as_space_group"
]
},
{
@@ -291,8 +291,8 @@
" # relevant info and load the structure in the CIF file. This\n",
" # includes the space group of the structure. We need this so we\n",
" # can constrain the structure parameters later on.\n",
- " p_cif = getParser('cif')\n",
- " stru1 = p_cif.parseFile(cif_path)\n",
+ " p_cif = get_parser('cif')\n",
+ " stru1 = p_cif.parse_file(cif_path)\n",
" sg = p_cif.spacegroup.short_name\n",
"\n",
" # 10: Create a Profile object for the experimental dataset.\n",
@@ -302,9 +302,9 @@
" # Q_max from the *.gr file, if the information is present.\n",
" profile = Profile()\n",
" parser = PDFParser()\n",
- " parser.parseFile(dat_path)\n",
- " profile.loadParsedData(parser)\n",
- " profile.setCalculationRange(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)\n",
+ " parser.parse_file(dat_path)\n",
+ " profile.load_parsed_data(parser)\n",
+ " profile.set_calculation_range(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)\n",
"\n",
" # 11: Create a PDF Generator object for a periodic structure model.\n",
" # Here we name it arbitrarily 'G1' and we give it the structure object.\n",
@@ -318,7 +318,7 @@
" # to this Fit Contribution object. The Fit Contribution holds\n",
" # the equation used to fit the PDF.\n",
" contribution = FitContribution(\"crystal\")\n",
- " contribution.addProfileGenerator(generator_crystal1)\n",
+ " contribution.add_profile_generator(generator_crystal1)\n",
"\n",
" # If you have a multi-core computer (you probably do),\n",
" # run your refinement in parallel!\n",
@@ -339,20 +339,20 @@
"\n",
" # 13: Set the experimental profile, within the Fit Contribution object,\n",
" # to the Profile object we created earlier.\n",
- " contribution.setProfile(profile, xname=\"r\")\n",
+ " contribution.set_profile(profile, xname=\"r\")\n",
"\n",
" # 14: Set an equation, within the Fit Contribution, based on your PDF\n",
" # Generators. Here we simply have one Generator, 'G1', and a scale variable,\n",
" # 's1'. Using this structure is a very flexible way of adding additional\n",
" # Generators (ie. multiple structural phases), experimental Profiles,\n",
" # PDF characteristic functions (ie. shape envelopes), and more.\n",
- " contribution.setEquation(\"s1*G1\")\n",
+ " contribution.set_equation(\"s1*G1\")\n",
"\n",
" # 15: Create the Fit Recipe object that holds all the details of the fit,\n",
" # defined in previous lines above. We give the Fit Recipe the Fit\n",
" # Contribution we created earlier.\n",
" recipe = FitRecipe()\n",
- " recipe.addContribution(contribution)\n",
+ " recipe.add_contribution(contribution)\n",
"\n",
" # 16: Initialize the instrument parameters, Q_damp and Q_broad, and\n",
" # assign Q_max and Q_min, all part of the PDF Generator object.\n",
@@ -368,26 +368,26 @@
"\n",
" # 17: Add a variable to the Fit Recipe object, initialize the variables\n",
" # with some value, and tag it with an arbitrary string. Here we add the scale\n",
- " # parameter from the Fit Contribution. The '.addVar' method can be\n",
+ " # parameter from the Fit Contribution. The '.add_variable' method can be\n",
" # used to add variables to the Fit Recipe.\n",
- " recipe.addVar(contribution.s1, SCALE_I, tag=\"scale\")\n",
+ " recipe.add_variable(contribution.s1, SCALE_I, tag=\"scale\")\n",
"\n",
" # 18: Configure some additional fit variables pertaining to symmetry.\n",
- " # We can use the srfit function 'constrainAsSpaceGroup' to constrain\n",
+ " # We can use the srfit function 'constrain_as_space_group' to constrain\n",
" # the lattice and ADP parameters according to the Fm-3m space group.\n",
" # First we establish the relevant parameters, then we loop through\n",
" # the parameters and activate and tag them. We must explicitly set the\n",
" # ADP parameters using 'value=' because CIF had no ADP data.\n",
- " spacegroupparams = constrainAsSpaceGroup(generator_crystal1.phase,\n",
+ " spacegroupparams = constrain_as_space_group(generator_crystal1.phase,\n",
" sg)\n",
" for par in spacegroupparams.latpars:\n",
- " recipe.addVar(par,\n",
+ " recipe.add_variable(par,\n",
" value=CUBICLAT_I,\n",
" fixed=False,\n",
" name=\"fcc_Lat\",\n",
" tag=\"lat\")\n",
" for par in spacegroupparams.adppars:\n",
- " recipe.addVar(par,\n",
+ " recipe.add_variable(par,\n",
" value=UISO_I,\n",
" fixed=False,\n",
" name=\"fcc_ADP\",\n",
@@ -397,16 +397,16 @@
" # These parameters are contained as part of the PDF Generator object\n",
" # and initialized with values as defined in the opening of the script.\n",
" # We give them unique names, and tag them with relevant strings.\n",
- " recipe.addVar(generator_crystal1.delta2,\n",
+ " recipe.add_variable(generator_crystal1.delta2,\n",
" name=\"Ni_Delta2\",\n",
" value=DELTA2_I,\n",
" tag=\"d2\")\n",
- " recipe.addVar(generator_crystal1.qdamp,\n",
+ " recipe.add_variable(generator_crystal1.qdamp,\n",
" fixed=False,\n",
" name=\"Calib_Qdamp\",\n",
" value=QDAMP_I,\n",
" tag=\"inst\")\n",
- " recipe.addVar(generator_crystal1.qbroad,\n",
+ " recipe.add_variable(generator_crystal1.qbroad,\n",
" fixed=False,\n",
" name=\"Calib_Qbroad\",\n",
" value=QBROAD_I,\n",
@@ -418,112 +418,6 @@
" # End of function"
]
},
- {
- "cell_type": "markdown",
- "metadata": {
- "pycharm": {
- "name": "#%% md\n"
- }
- },
- "source": [
- "21: We create a useful function 'plot_results' for writing a plot of the fit to disk.
\n",
- "We won't go into detail here as much of this is non-CMI specific"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "pycharm": {
- "name": "#%%\n"
- }
- },
- "outputs": [],
- "source": [
- "def plot_results(recipe, fig_name):\n",
- " \"\"\"\n",
- " Creates plots of the fitted PDF and residual, and writes them to disk\n",
- " as *.pdf files.\n",
- " Parameters\n",
- " ----------\n",
- " recipe : The optimized Fit Recipe object containing the PDF data\n",
- " we wish to plot.\n",
- " fig_name : Path object, the full path to the figure file to create..\n",
- " Returns\n",
- " ----------\n",
- " None\n",
- " \"\"\"\n",
- " if not isinstance(fig_name, Path):\n",
- " fig_name = Path(fig_name)\n",
- " plt.clf()\n",
- " plt.close('all')\n",
- "\n",
- " # Get an array of the r-values we fitted over.\n",
- " r = recipe.crystal.profile.x\n",
- "\n",
- " # Get an array of the observed PDF.\n",
- " g = recipe.crystal.profile.y\n",
- "\n",
- " # Get an array of the calculated PDF.\n",
- " gcalc = recipe.crystal.profile.ycalc\n",
- "\n",
- " # Make an array of identical shape as g which is offset from g.\n",
- " diffzero = -0.65 * max(g) * np.ones_like(g)\n",
- "\n",
- " # Calculate the residual (difference) array and offset it vertically.\n",
- " diff = g - gcalc + diffzero\n",
- "\n",
- " # Create a figure and an axis on which to plot\n",
- " fig, ax1 = plt.subplots(1, 1)\n",
- "\n",
- " # Plot the difference offset line\n",
- " ax1.plot(r, diffzero, lw=1.0, ls=\"--\", c=\"black\")\n",
- "\n",
- " # Plot the measured data\n",
- " ax1.plot(r,\n",
- " g,\n",
- " ls=\"None\",\n",
- " marker=\"o\",\n",
- " ms=5,\n",
- " mew=0.2,\n",
- " mfc=\"None\",\n",
- " label=\"G(r) Data\")\n",
- "\n",
- " # Plot the calculated data\n",
- " ax1.plot(r, gcalc, lw=1.3, label=\"G(r) Fit\")\n",
- "\n",
- " # Plot the difference\n",
- " ax1.plot(r, diff, lw=1.2, label=\"G(r) diff\")\n",
- "\n",
- " # Let's label the axes!\n",
- " ax1.set_xlabel(r\"r ($\\mathrm{\\AA}$)\")\n",
- " ax1.set_ylabel(r\"G ($\\mathrm{\\AA}$$^{-2}$)\")\n",
- "\n",
- " # Tune the tick markers. We are picky!\n",
- " ax1.tick_params(axis=\"both\",\n",
- " which=\"major\",\n",
- " top=True,\n",
- " right=True)\n",
- "\n",
- " # Set the boundaries on the x-axis\n",
- " ax1.set_xlim(r[0], r[-1])\n",
- "\n",
- " # We definitely want a legend!\n",
- " ax1.legend()\n",
- "\n",
- " # Let's use a tight layout. Shun wasted space!\n",
- " plt.tight_layout()\n",
- "\n",
- " # This is going to make a figure pop up on screen for you to view.\n",
- " # The script will pause until you close the figure!\n",
- " plt.show()\n",
- "\n",
- " # Let's save the figure!\n",
- " fig.savefig(fig_name.parent / f\"{fig_name.name}.pdf\", format=\"pdf\")\n",
- "\n",
- " # End of function"
- ]
- },
{
"cell_type": "markdown",
"metadata": {
@@ -610,23 +504,25 @@
" profile.savetxt(fitdir / f\"{basename}.fit\")\n",
"\n",
" # 26: We use the 'FitResults' method to parse out the results from\n",
- " # the optimized Fit Recipe, and 'printResults' to print them\n",
+ " # the optimized Fit Recipe, and 'print_results' to print them\n",
" # to the terminal.\n",
" res = FitResults(recipe)\n",
- " res.printResults()\n",
+ " res.print_results()\n",
"\n",
- " # 27: We use the 'saveResults' method of 'FitResults' to write a text file\n",
+ " # 27: We use the 'save_results' method of 'FitResults' to write a text file\n",
" # containing the fitted parameters and fit quality indices to disk.\n",
" # The file is named based on the basename we created earlier, and\n",
" # written to the 'resdir' directory.\n",
" header = \"crystal_HF.\\n\"\n",
- " res.saveResults(resdir / f\"{basename}.res\", header=header)\n",
- "\n",
- " # 28: We use the 'plot_results' method we created earlier to write a pdf file\n",
- " # containing the measured and fitted PDF with residual to disk.\n",
- " # The file is named based on the 'basename' we created earlier, and\n",
- " # written to the 'figdir' directory.\n",
- " plot_results(recipe, figdir / basename)\n",
+ " res.save_results(resdir / f\"{basename}.res\", header=header)\n",
+ "\n",
+ " # 28: Write a plot of the fit to a (pdf) file.\n",
+ " fig, ax1 = recipe.plot_recipe(\n",
+ " return_fig=True,\n",
+ " xlabel=r\"r ($\\mathrm{\\AA}$)\",\n",
+ " ylabel=r\"G ($\\mathrm{\\AA}$$^{-2}$)\",\n",
+ " )\n",
+ " fig.savefig(figdir / f\"{basename}.pdf\", format=\"pdf\")\n",
"\n",
" # End of function"
]
diff --git a/docs/examples/pdf/ch03NiModelling/exercises/diffpy-cmi/fitNPPt.ipynb b/docs/examples/pdf/ch03NiModelling/exercises/diffpy-cmi/fitNPPt.ipynb
index 88ee1b5..a464aca 100644
--- a/docs/examples/pdf/ch03NiModelling/exercises/diffpy-cmi/fitNPPt.ipynb
+++ b/docs/examples/pdf/ch03NiModelling/exercises/diffpy-cmi/fitNPPt.ipynb
@@ -48,9 +48,9 @@
"source": [
"from diffpy.srfit.fitbase import FitContribution, FitRecipe, FitResults, Profile\n",
"from diffpy.srfit.pdf import PDFParser, PDFGenerator\n",
- "from diffpy.structure.parsers import getParser\n",
- "from diffpy.srfit.pdf.characteristicfunctions import sphericalCF\n",
- "from diffpy.srfit.structure import constrainAsSpaceGroup"
+ "from diffpy.structure.parsers import get_parser\n",
+ "from diffpy.srfit.pdf.characteristicfunctions import spherical_particle\n",
+ "from diffpy.srfit.structure import constrain_as_space_group"
]
},
{
@@ -259,17 +259,17 @@
" \"\"\"\n",
" # 10: Create a CIF file parsing object, parse and load the structure, and\n",
" # grab the space group name.\n",
- " p_cif = getParser('cif')\n",
- " stru1 = p_cif.parseFile(cif_path)\n",
+ " p_cif = get_parser('cif')\n",
+ " stru1 = p_cif.parse_file(cif_path)\n",
" sg = p_cif.spacegroup.short_name\n",
"\n",
" # 11: Create a Profile object for the experimental dataset and\n",
" # tell this profile the range and mesh of points in r-space.\n",
" profile = Profile()\n",
" parser = PDFParser()\n",
- " parser.parseFile(dat_path)\n",
- " profile.loadParsedData(parser)\n",
- " profile.setCalculationRange(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)\n",
+ " parser.parse_file(dat_path)\n",
+ " profile.load_parsed_data(parser)\n",
+ " profile.set_calculation_range(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)\n",
"\n",
" # 12: Create a PDF Generator object for a periodic structure model.\n",
" generator_crystal1 = PDFGenerator(\"G1\")\n",
@@ -277,7 +277,7 @@
"\n",
" # 13: Create a Fit Contribution object.\n",
" contribution = FitContribution(\"crystal\")\n",
- " contribution.addProfileGenerator(generator_crystal1)\n",
+ " contribution.add_profile_generator(generator_crystal1)\n",
"\n",
" # If you have a multi-core computer (you probably do), run your refinement in parallel!\n",
" if RUN_PARALLEL:\n",
@@ -295,18 +295,18 @@
" print(\"\\nYou don't appear to have the necessary packages for parallelization\")\n",
"\n",
" # 14: Set the Fit Contribution profile to the Profile object.\n",
- " contribution.setProfile(profile, xname=\"r\")\n",
+ " contribution.set_profile(profile, xname=\"r\")\n",
"\n",
" # 15: Set an equation, based on your PDF generators. Here we add an extra layer\n",
" # of complexity, incorporating 'f' into our equation. This new term\n",
" # incorporates the effect of finite crystallite size damping on our PDF model.\n",
- " # In this case we use a function which models a spherical NP 'sphericalCF'.\n",
- " contribution.registerFunction(sphericalCF, name=\"f\")\n",
- " contribution.setEquation(\"s1*G1*f\")\n",
+ " # In this case we use a function which models a spherical NP 'spherical_particle'.\n",
+ " contribution.register_function(spherical_particle, name=\"f\")\n",
+ " contribution.set_equation(\"s1*G1*f\")\n",
"\n",
" # 16: Create the Fit Recipe object that holds all the details of the fit.\n",
" recipe = FitRecipe()\n",
- " recipe.addContribution(contribution)\n",
+ " recipe.add_contribution(contribution)\n",
"\n",
" # 17: Initialize the instrument parameters, Q_damp and Q_broad, and\n",
" # assign Q_max and Q_min.\n",
@@ -317,25 +317,25 @@
"\n",
" # 18: Add, initialize, and tag variables in the Fit Recipe object.\n",
" # In this case we also add 'psize', which is the NP size.\n",
- " recipe.addVar(contribution.s1, SCALE_I, tag=\"scale\")\n",
- " recipe.addVar(contribution.psize, PSIZE_I, tag=\"psize\")\n",
+ " recipe.add_variable(contribution.s1, SCALE_I, tag=\"scale\")\n",
+ " recipe.add_variable(contribution.psize, PSIZE_I, tag=\"psize\")\n",
"\n",
- " # 19: Use the srfit function 'constrainAsSpaceGroup' to constrain\n",
+ " # 19: Use the srfit function 'constrain_as_space_group' to constrain\n",
" # the lattice and ADP parameters according to the Fm-3m space group.\n",
- " spacegroupparams = constrainAsSpaceGroup(generator_crystal1.phase,\n",
+ " spacegroupparams = constrain_as_space_group(generator_crystal1.phase,\n",
" sg)\n",
" for par in spacegroupparams.latpars:\n",
- " recipe.addVar(par, value=CUBICLAT_I, fixed=False,\n",
+ " recipe.add_variable(par, value=CUBICLAT_I, fixed=False,\n",
" name=\"fcc_Lat\", tag=\"lat\")\n",
" for par in spacegroupparams.adppars:\n",
- " recipe.addVar(par, value=UISO_I, fixed=False,\n",
+ " recipe.add_variable(par, value=UISO_I, fixed=False,\n",
" name=\"fcc_Uiso\", tag=\"adp\")\n",
"\n",
" # 20: Add delta, but not instrumental parameters to Fit Recipe.\n",
" # The instrumental parameters will remain fixed at values obtained from\n",
" # the Ni calibrant in our previous example. As we have not added them through\n",
- " # recipe.addVar, they cannot be refined.\n",
- " recipe.addVar(generator_crystal1.delta2,\n",
+ " # recipe.add_variable, they cannot be refined.\n",
+ " recipe.add_variable(generator_crystal1.delta2,\n",
" name=\"Pt_Delta2\", value=DELTA2_I, tag=\"d2\")\n",
"\n",
" # 21: Return the Fit Recipe object to be optimized.\n",
@@ -344,102 +344,6 @@
" # End of function"
]
},
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "22 We create a useful function 'plot_results' for writing a plot of the fit to disk."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "def plot_results(recipe, fig_name):\n",
- " \"\"\"\n",
- " Creates plots of the fitted PDF and residual, and writes them to disk\n",
- " as *.pdf files.\n",
- " Parameters\n",
- " ----------\n",
- " recipe : The optimized Fit Recipe object containing the PDF data\n",
- " we wish to plot.\n",
- " fig_name : Path object, the full path to the figure file to create.\n",
- " Returns\n",
- " ----------\n",
- " None\n",
- " \"\"\"\n",
- " if not isinstance(fig_name, Path):\n",
- " fig_name = Path(fig_name)\n",
- " plt.clf()\n",
- " plt.close('all')\n",
- " # Get an array of the r-values we fitted over.\n",
- " r = recipe.crystal.profile.x\n",
- "\n",
- " # Get an array of the observed PDF.\n",
- " g = recipe.crystal.profile.y\n",
- "\n",
- " # Get an array of the calculated PDF.\n",
- " gcalc = recipe.crystal.profile.ycalc\n",
- "\n",
- " # Make an array of identical shape as g which is offset from g.\n",
- " diffzero = -0.65 * max(g) * np.ones_like(g)\n",
- "\n",
- " # Calculate the residual (difference) array and offset it vertically.\n",
- " diff = g - gcalc + diffzero\n",
- "\n",
- " # Create a figure and an axis on which to plot\n",
- " fig, ax1 = plt.subplots(1, 1)\n",
- "\n",
- " # Plot the difference offset line\n",
- " ax1.plot(r, diffzero, lw=1.0, ls=\"--\", c=\"black\")\n",
- "\n",
- " # Plot the measured data\n",
- " ax1.plot(r,\n",
- " g,\n",
- " ls=\"None\",\n",
- " marker=\"o\",\n",
- " ms=5,\n",
- " mew=0.2,\n",
- " mfc=\"None\",\n",
- " label=\"G(r) Data\")\n",
- "\n",
- " # Plot the calculated data\n",
- " ax1.plot(r, gcalc, lw=1.3, label=\"G(r) Fit\")\n",
- "\n",
- " # Plot the difference\n",
- " ax1.plot(r, diff, lw=1.2, label=\"G(r) diff\")\n",
- "\n",
- " # Let's label the axes!\n",
- " ax1.set_xlabel(r\"r ($\\mathrm{\\AA}$)\")\n",
- " ax1.set_ylabel(r\"G ($\\mathrm{\\AA}$$^{-2}$)\")\n",
- "\n",
- " # Tune the tick markers. We are picky!\n",
- " ax1.tick_params(axis=\"both\",\n",
- " which=\"major\",\n",
- " top=True,\n",
- " right=True)\n",
- "\n",
- " # Set the boundaries on the x-axis\n",
- " ax1.set_xlim(r[0], r[-1])\n",
- "\n",
- " # We definitely want a legend!\n",
- " ax1.legend()\n",
- "\n",
- " # Let's use a tight layout. Shun wasted space!\n",
- " plt.tight_layout()\n",
- "\n",
- " # This is going to make a figure pop up on screen for you to view.\n",
- " # The script will pause until you close the figure!\n",
- " plt.show()\n",
- "\n",
- " # Let's save the figure!\n",
- " fig.savefig(fig_name.parent / f\"{fig_name.name}.pdf\", format=\"pdf\")\n",
- "\n",
- " # End of function"
- ]
- },
{
"cell_type": "markdown",
"metadata": {},
@@ -505,14 +409,19 @@
"\n",
" # 27 Print the fit results to the terminal.\n",
" res = FitResults(recipe)\n",
- " res.printResults()\n",
+ " res.print_results()\n",
"\n",
" # 28 Write the fit results to a file.\n",
" header = \"crystal_HF.\\n\"\n",
- " res.saveResults(resdir / f\"{basename}.res\", header=header)\n",
+ " res.save_results(resdir / f\"{basename}.res\", header=header)\n",
"\n",
" # 29 Write a plot of the fit to a (pdf) file.\n",
- " plot_results(recipe, figdir / basename)\n",
+ " fig, ax1 = recipe.plot_recipe(\n",
+ " return_fig=True,\n",
+ " xlabel=r\"r ($\\mathrm{\\AA}$)\",\n",
+ " ylabel=r\"G ($\\mathrm{\\AA}$$^{-2}$)\",\n",
+ " )\n",
+ " fig.savefig(figdir / f\"{basename}.pdf\", format=\"pdf\")\n",
"\n",
" # End of function"
]
diff --git a/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi.py b/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi.py
index 599b0a2..f6be5e1 100644
--- a/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi.py
+++ b/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi.py
@@ -22,8 +22,8 @@
Profile,
)
from diffpy.srfit.pdf import PDFGenerator, PDFParser
-from diffpy.srfit.structure import constrainAsSpaceGroup
-from diffpy.structure.parsers import getParser
+from diffpy.srfit.structure import constrain_as_space_group
+from diffpy.structure.parsers import get_parser
plt.style.use(all_styles["bg-style"])
# Config
@@ -96,8 +96,8 @@ def make_recipe(cif_path, dat_path):
# relevant info and load the structure in the CIF file. This
# includes the space group of the structure. We need this so we
# can constrain the structure parameters later on.
- p_cif = getParser("cif")
- stru1 = p_cif.parseFile(cif_path)
+ p_cif = get_parser("cif")
+ stru1 = p_cif.parse_file(cif_path)
sg = p_cif.spacegroup.short_name
# 10: Create a Profile object for the experimental dataset.
@@ -107,9 +107,9 @@ def make_recipe(cif_path, dat_path):
# Q_max from the *.gr file, if the information is present.
profile = Profile()
parser = PDFParser()
- parser.parseFile(dat_path)
- profile.loadParsedData(parser)
- profile.setCalculationRange(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)
+ parser.parse_file(dat_path)
+ profile.load_parsed_data(parser)
+ profile.set_calculation_range(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)
# 11: Create a PDF Generator object for a periodic structure model.
# Here we name it arbitrarily 'G1' and we give it the structure object.
@@ -123,7 +123,7 @@ def make_recipe(cif_path, dat_path):
# to this Fit Contribution object. The Fit Contribution holds
# the equation used to fit the PDF.
contribution = FitContribution("crystal")
- contribution.addProfileGenerator(generator_crystal1)
+ contribution.add_profile_generator(generator_crystal1)
# If you have a multi-core computer (you probably do),
# run your refinement in parallel!
@@ -148,7 +148,7 @@ def make_recipe(cif_path, dat_path):
# 13: Set the experimental profile, within the Fit Contribution object,
# to the Profile object we created earlier.
- contribution.setProfile(profile, xname="r")
+ contribution.set_profile(profile, xname="r")
# 14: Set an equation, within the Fit Contribution, based on your PDF
# Generators. Here we simply have one Generator, 'G1', and a scale
@@ -156,13 +156,13 @@ def make_recipe(cif_path, dat_path):
# additional Generators (ie. multiple structural phases), experimental
# Profiles, PDF characteristic functions (ie. shape envelopes),
# and more.
- contribution.setEquation("s1*G1")
+ contribution.set_equation("s1*G1")
# 15: Create the Fit Recipe object that holds all the details of the fit,
# defined in previous lines above. We give the Fit Recipe the Fit
# Contribution we created earlier.
recipe = FitRecipe()
- recipe.addContribution(contribution)
+ recipe.add_contribution(contribution)
# 16: Initialize the instrument parameters, Q_damp and Q_broad, and
# assign Q_max and Q_min, all part of the PDF Generator object.
@@ -180,21 +180,21 @@ def make_recipe(cif_path, dat_path):
# with some value, and tag it with an arbitrary string. Here we add the
# scale parameter from the Fit Contribution. The '.addVar' method can be
# used to add variables to the Fit Recipe.
- recipe.addVar(contribution.s1, SCALE_I, tag="scale")
+ recipe.add_variable(contribution.s1, SCALE_I, tag="scale")
# 18: Configure some additional fit variables pertaining to symmetry.
- # We can use the srfit function 'constrainAsSpaceGroup' to constrain
+ # We can use the srfit function 'constrain_as_space_group' to constrain
# the lattice and ADP parameters according to the Fm-3m space group.
# First we establish the relevant parameters, then we loop through
# the parameters and activate and tag them. We must explicitly set the
# ADP parameters using 'value=' because CIF had no ADP data.
- spacegroupparams = constrainAsSpaceGroup(generator_crystal1.phase, sg)
+ spacegroupparams = constrain_as_space_group(generator_crystal1.phase, sg)
for par in spacegroupparams.latpars:
- recipe.addVar(
+ recipe.add_variable(
par, value=CUBICLAT_I, fixed=False, name="fcc_Lat", tag="lat"
)
for par in spacegroupparams.adppars:
- recipe.addVar(
+ recipe.add_variable(
par, value=UISO_I, fixed=False, name="fcc_ADP", tag="adp"
)
@@ -202,11 +202,11 @@ def make_recipe(cif_path, dat_path):
# These parameters are contained as part of the PDF Generator object
# and initialized with values as defined in the opening of the script.
# We give them unique names, and tag them with relevant strings.
- recipe.addVar(
+ recipe.add_variable(
generator_crystal1.delta2, name="Ni_Delta2", value=DELTA2_I, tag="d2"
)
- recipe.addVar(
+ recipe.add_variable(
generator_crystal1.qdamp,
fixed=False,
name="Calib_Qdamp",
@@ -214,7 +214,7 @@ def make_recipe(cif_path, dat_path):
tag="inst",
)
- recipe.addVar(
+ recipe.add_variable(
generator_crystal1.qbroad,
fixed=False,
name="Calib_Qbroad",
@@ -228,93 +228,6 @@ def make_recipe(cif_path, dat_path):
# End of function
-# 21: We create a useful function 'plot_results' for writing a plot of the fit
-# to disk. We won't go into detail here as much of this is non-CMI specific
-def plot_results(recipe, fig_name):
- """Creates plots of the fitted PDF and residual, and writes them to
- disk as *.pdf files.
-
- Parameters
- ----------
- recipe : The optimized Fit Recipe object containing the PDF data
- we wish to plot.
- fig_name : Path object, the full path to the figure file to create..
-
- Returns
- ----------
- None
- """
- if not isinstance(fig_name, Path):
- fig_name = Path(fig_name)
-
- plt.clf()
- plt.close("all")
-
- # Get an array of the r-values we fitted over.
- r = recipe.crystal.profile.x
-
- # Get an array of the observed PDF.
- g = recipe.crystal.profile.y
-
- # Get an array of the calculated PDF.
- gcalc = recipe.crystal.profile.ycalc
-
- # Make an array of identical shape as g which is offset from g.
- diffzero = -0.65 * max(g) * np.ones_like(g)
-
- # Calculate the residual (difference) array and offset it vertically.
- diff = g - gcalc + diffzero
-
- # Create a figure and an axis on which to plot
- fig, ax1 = plt.subplots(1, 1)
-
- # Plot the difference offset line
- ax1.plot(r, diffzero, lw=1.0, ls="--", c="black")
-
- # Plot the measured data
- ax1.plot(
- r,
- g,
- ls="None",
- marker="o",
- ms=5,
- mew=0.2,
- mfc="None",
- label="G(r) Data",
- )
-
- # Plot the calculated data
- ax1.plot(r, gcalc, lw=1.3, label="G(r) Fit")
-
- # Plot the difference
- ax1.plot(r, diff, lw=1.2, label="G(r) diff")
-
- # Let's label the axes!
- ax1.set_xlabel(r"r ($\mathrm{\AA}$)")
- ax1.set_ylabel(r"G ($\mathrm{\AA}$$^{-2}$)")
-
- # Tune the tick markers. We are picky!
- ax1.tick_params(axis="both", which="major", top=True, right=True)
-
- # Set the boundaries on the x-axis
- ax1.set_xlim(r[0], r[-1])
-
- # We definitely want a legend!
- ax1.legend()
-
- # Let's use a tight layout. Shun wasted space!
- plt.tight_layout()
-
- # This is going to make a figure pop up on screen for you to view.
- # The script will pause until you close the figure!
- plt.show()
-
- # Let's save the figure!
- fig.savefig(fig_name.parent / f"{fig_name.name}.pdf", format="pdf")
-
- # End of function
-
-
# 22: By Convention, this main function is where we do most of our work, and it
# is the bit of code which will be run when we issue 'python file.py'
# from a terminal.
@@ -387,20 +300,22 @@ def main():
# the optimized Fit Recipe, and 'printResults' to print them
# to the terminal.
res = FitResults(recipe)
- res.printResults()
+ res.print_results()
# 27: We use the 'saveResults' method of 'FitResults' to write a text file
# containing the fitted parameters and fit quality indices to disk.
# The file is named based on the basename we created earlier, and
# written to the 'resdir' directory.
header = "crystal_HF.\n"
- res.saveResults(resdir / f"{basename}.res", header=header)
+ res.save_results(resdir / f"{basename}.res", header=header)
- # 28: We use the 'plot_results' method we created earlier to write a pdf
- # file containing the measured and fitted PDF with residual to disk.
- # The file is named based on the 'basename' we created earlier, and
- # written to the 'figdir' directory.
- plot_results(recipe, figdir / basename)
+ # 28: Write a plot of the fit to a (pdf) file.
+ fig, ax1 = recipe.plot_recipe(
+ return_fig=True,
+ xlabel=r"r ($\mathrm{\AA}$)",
+ ylabel=r"G ($\mathrm{\AA}$$^{-2}$)",
+ )
+ fig.savefig(figdir / f"{basename}.pdf", format="pdf")
# End of function
diff --git a/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi_NPPt_soln2.ipynb b/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi_NPPt_soln2.ipynb
index 79e0c4c..6b883a8 100644
--- a/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi_NPPt_soln2.ipynb
+++ b/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi_NPPt_soln2.ipynb
@@ -124,12 +124,12 @@
" for name, crystal in crystals.items():\n",
" pg = PDFGenerator(name)\n",
" pg.setStructure(crystal, periodic=True)\n",
- " fc.addProfileGenerator(pg)\n",
+ " fc.add_profile_generator(pg)\n",
" for name, (f, argnames) in functions.items():\n",
- " fc.registerFunction(f, name=name, argnames=argnames)\n",
- " fc.setEquation(equation)\n",
- " fc.setProfile(profile, xname=\"r\", yname=\"G\", dyname=\"dG\")\n",
- " fr.addContribution(fc)\n",
+ " fc.register_function(f, name=name, argnames=argnames)\n",
+ " fc.set_equation(equation)\n",
+ " fc.set_profile(profile, xname=\"r\", yname=\"G\", dyname=\"dG\")\n",
+ " fr.add_contribution(fc)\n",
" return fr\n",
"\n",
"\n",
@@ -200,56 +200,56 @@
"\n",
" \"\"\"\n",
" name: str = pg.name\n",
- " recipe.addVar(\n",
+ " recipe.add_variable(\n",
" pg.scale,\n",
" name=_get_name(name, \"scale\"),\n",
" value=SCALE_I,\n",
" fixed=True,\n",
" tags=_get_tags(name, \"scale\")\n",
- " ).boundRange(0.)\n",
- " recipe.addVar( #Here we add Qdamp as a variable\n",
+ " ).bound_range(0.)\n",
+ " recipe.add_variable( #Here we add Qdamp as a variable\n",
" pg.qdamp,\n",
" name=_get_name(name, \"qdamp\"), \n",
" value=QDAMP_I, \n",
" fixed=True,\n",
" tags=_get_tags(name, \"qdamp\")\n",
- " ).boundRange(0.)\n",
- " recipe.addVar( #Here we add Qbroad as a variable\n",
+ " ).bound_range(0.)\n",
+ " recipe.add_variable( #Here we add Qbroad as a variable\n",
" pg.qbroad,\n",
" name=_get_name(name, \"qbroad\"), \n",
" value=QBROAD_I, \n",
" fixed=True,\n",
" tags=_get_tags(name, \"qbroad\")\n",
- " ).boundRange(0.) \n",
- " recipe.addVar(\n",
+ " ).bound_range(0.) \n",
+ " recipe.add_variable(\n",
" pg.delta2,\n",
" name=_get_name(name, \"delta2\"),\n",
" value=DELTA2_I,\n",
" fixed=True,\n",
" tags=_get_tags(name, \"delta2\")\n",
- " ).boundRange(0.)\n",
+ " ).bound_range(0.)\n",
" latpars = pg.phase.sgpars.latpars\n",
" for par in latpars:\n",
- " recipe.addVar(\n",
+ " recipe.add_variable(\n",
" par,\n",
" name=_get_name(name, par.name),\n",
" fixed=True,\n",
" tags=_get_tags(name, \"lat\")\n",
- " ).boundRange(0.)\n",
+ " ).bound_range(0.)\n",
" atoms: typing.List[ParameterSet] = pg.phase.getScatterers()\n",
" for atom in atoms:\n",
" par = atom.Biso\n",
- " recipe.addVar(\n",
+ " recipe.add_variable(\n",
" par,\n",
" name=_get_name(name, atom.name, \"Biso\"),\n",
" value=BISO_I,\n",
" fixed=True,\n",
" tags=_get_tags(name, \"adp\")\n",
- " ).boundRange(0.)\n",
+ " ).bound_range(0.)\n",
" xyzpars = pg.phase.sgpars.xyzpars\n",
" for par in xyzpars:\n",
" par_name = _rename_par(par.name, atoms)\n",
- " recipe.addVar(\n",
+ " recipe.add_variable(\n",
" par,\n",
" name=_get_name(name, par_name),\n",
" fixed=True,\n",
@@ -279,7 +279,7 @@
" \"\"\"\n",
" for name in names:\n",
" par = getattr(fc, name)\n",
- " recipe.addVar(\n",
+ " recipe.add_variable(\n",
" par,\n",
" value=100.,\n",
" fixed=True,\n",
@@ -318,7 +318,7 @@
" for name in crystals.keys():\n",
" pg: PDFGenerator = getattr(fc, name)\n",
" _add_params_in_pg(recipe, pg)\n",
- " recipe.clearFitHooks()\n",
+ " recipe.clear_fit_hooks()\n",
" return\n",
"\n",
"\n",
@@ -357,9 +357,9 @@
" meta_data = {}\n",
" crystals = {n: loadCrystal(f) for n, f in cif_files.items()}\n",
" pp = PDFParser()\n",
- " pp.parseFile(data_file)\n",
+ " pp.parse_file(data_file)\n",
" profile = Profile()\n",
- " profile.loadParsedData(pp)\n",
+ " profile.load_parsed_data(pp)\n",
" profile.meta.update(meta_data)\n",
" recipe = _create_recipe(equation, crystals, functions, profile, fc_name=fc_name)\n",
" _initialize_recipe(recipe, functions, crystals, fc_name=fc_name)\n",
@@ -422,7 +422,7 @@
" n = len(steps)\n",
" fc: FitContribution = getattr(recipe, fc_name)\n",
" p: Profile = fc.profile\n",
- " p.setCalculationRange(xmin=rmin, xmax=rmax, dx=rstep)\n",
+ " p.set_calculation_range(xmin=rmin, xmax=rmax, dx=rstep)\n",
" for step in steps:\n",
" recipe.fix(*step)\n",
" for i, step in enumerate(steps):\n",
@@ -430,11 +430,11 @@
" if print_step:\n",
" print(\n",
" \"Step {} / {}: refine {}\".format(\n",
- " i + 1, n, \", \".join(recipe.getNames())\n",
+ " i + 1, n, \", \".join(recipe.get_names())\n",
" ),\n",
" end=\"\\r\"\n",
" )\n",
- " least_squares(recipe.residual, recipe.getValues(), bounds=recipe.getBounds2(), **kwargs)\n",
+ " least_squares(recipe.residual, recipe.get_values(), bounds=recipe.get_bounds_array(), **kwargs)\n",
" return\n"
]
},
@@ -470,28 +470,18 @@
" -------\n",
" None.\n",
" \"\"\"\n",
- " # get data\n",
- " fc = getattr(recipe, fc_name)\n",
- " r = fc.profile.x\n",
- " g = fc.profile.y\n",
- " gcalc = fc.profile.ycalc\n",
- " if xlim is not None:\n",
- " sel = np.logical_and(r >= xlim[0], r <= xlim[1])\n",
- " r = r[sel]\n",
- " g = g[sel]\n",
- " gcalc = gcalc[sel]\n",
- " gdiff = g - gcalc\n",
- " diffzero = -0.8 * np.max(g) * np.ones_like(g)\n",
- " # plot figure\n",
- " _, ax = plt.subplots()\n",
- " ax.plot(r, g, 'bo', label=\"G(r) Data\")\n",
- " ax.plot(r, gcalc, 'r-', label=\"G(r) Fit\")\n",
- " ax.plot(r, gdiff + diffzero, 'g-', label=\"G(r) Diff\")\n",
- " ax.plot(r, diffzero, 'k-')\n",
- " ax.set_xlabel(r\"$r (\\AA)$\")\n",
- " ax.set_ylabel(r\"$G (\\AA^{-2})$\")\n",
- " ax.legend(loc=1)\n",
- " plt.show()\n",
+ " xmin, xmax = xlim if xlim is not None else (None, None)\n",
+ " recipe.plot_recipe(\n",
+ " xmin=xmin,\n",
+ " xmax=xmax,\n",
+ " data_style=\"o\",\n",
+ " data_label=\"G(r) Data\",\n",
+ " fit_label=\"G(r) Fit\",\n",
+ " diff_label=\"G(r) Diff\",\n",
+ " xlabel=r\"$r (\\AA)$\",\n",
+ " ylabel=r\"$G (\\AA^{-2})$\",\n",
+ " legend_loc=1,\n",
+ " )\n",
" return"
]
},
@@ -540,7 +530,7 @@
" d_path.mkdir(parents=True, exist_ok=True)\n",
" f_path = d_path.joinpath(file_stem)\n",
" fr = FitResults(recipe)\n",
- " fr.saveResults(str(f_path.with_suffix(\".res\")))\n",
+ " fr.save_results(str(f_path.with_suffix(\".res\")))\n",
" fc: FitContribution = getattr(recipe, fc_name)\n",
" profile: Profile = fc.profile\n",
" profile.savetxt(str(f_path.with_suffix(\".fgr\")))\n",
@@ -726,7 +716,7 @@
"metadata": {},
"source": [
"### Fit Ni - full range\n",
- "When we have a good fit for our data in a small range, we can increase the fit to the whole range. We will use the initializeRecipe function from diffpy to load the refined parameter values from the short range fit. "
+ "When we have a good fit for our data in a small range, we can increase the fit to the whole range. We will use the initialize_recipe_with_results method from diffpy to load the refined parameter values from the short range fit. "
]
},
{
@@ -743,9 +733,7 @@
" data_file=GR_FILE,\n",
")\n",
"\n",
- "from diffpy.srfit.fitbase.fitresults import initializeRecipe\n",
- "\n",
- "initializeRecipe(recipe, \"./Results/Ni/Ni_short_r.res\")"
+ "recipe.initialize_recipe_with_results(\"./Results/Ni/Ni_short_r.res\")"
]
},
{
@@ -859,7 +847,7 @@
"recipe = create_recipe_from_files(\n",
" \"sphere * Pt\",\n",
" cif_files={\"Pt\": CIF_FILE_Pt},\n",
- " functions={\"sphere\": (F.sphericalCF, [\"r\", \"Pt_size\"])},\n",
+ " functions={\"sphere\": (F.spherical_particle, [\"r\", \"Pt_size\"])},\n",
" data_file=GR_FILE_Pt,\n",
")"
]
@@ -879,8 +867,8 @@
"metadata": {},
"outputs": [],
"source": [
- "recipe.Pt_qdamp.setValue(QDAMP_Ni)\n",
- "recipe.Pt_qbroad.setValue(QBROAD_Ni)"
+ "recipe.Pt_qdamp.set_value(QDAMP_Ni)\n",
+ "recipe.Pt_qbroad.set_value(QBROAD_Ni)"
]
},
{
@@ -970,12 +958,12 @@
"recipe = create_recipe_from_files(\n",
" \"sphere * Pt\",\n",
" cif_files={\"Pt\": CIF_FILE_Pt},\n",
- " functions={\"sphere\": (F.sphericalCF, [\"r\", \"Pt_size\"])},\n",
+ " functions={\"sphere\": (F.spherical_particle, [\"r\", \"Pt_size\"])},\n",
" data_file=GR_FILE_Pt\n",
")\n",
"\n",
"\n",
- "initializeRecipe(recipe, \"./Results/Pt/Pt_short_r.res\")\n",
+ "recipe.initialize_recipe_with_results(\"./Results/Pt/Pt_short_r.res\")\n",
"\n",
"optimize_params(\n",
" recipe,\n",
diff --git a/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/fitNPPt.py b/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/fitNPPt.py
index f00afb4..981d03c 100644
--- a/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/fitNPPt.py
+++ b/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/fitNPPt.py
@@ -26,9 +26,9 @@
Profile,
)
from diffpy.srfit.pdf import PDFGenerator, PDFParser
-from diffpy.srfit.pdf.characteristicfunctions import sphericalCF
-from diffpy.srfit.structure import constrainAsSpaceGroup
-from diffpy.structure.parsers import getParser
+from diffpy.srfit.pdf.characteristicfunctions import spherical_particle
+from diffpy.srfit.structure import constrain_as_space_group
+from diffpy.structure.parsers import get_parser
plt.style.use(all_styles["bg-style"])
# Config ##############################
@@ -112,17 +112,17 @@ def make_recipe(cif_path, dat_path):
"""
# 10: Create a CIF file parsing object, parse and load the structure, and
# grab the space group name.
- p_cif = getParser("cif")
- stru1 = p_cif.parseFile(cif_path)
+ p_cif = get_parser("cif")
+ stru1 = p_cif.parse_file(cif_path)
sg = p_cif.spacegroup.short_name
# 11: Create a Profile object for the experimental dataset and
# tell this profile the range and mesh of points in r-space.
profile = Profile()
parser = PDFParser()
- parser.parseFile(dat_path)
- profile.loadParsedData(parser)
- profile.setCalculationRange(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)
+ parser.parse_file(dat_path)
+ profile.load_parsed_data(parser)
+ profile.set_calculation_range(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)
# 12: Create a PDF Generator object for a periodic structure model.
generator_crystal1 = PDFGenerator("G1")
@@ -130,7 +130,7 @@ def make_recipe(cif_path, dat_path):
# 13: Create a Fit Contribution object.
contribution = FitContribution("crystal")
- contribution.addProfileGenerator(generator_crystal1)
+ contribution.add_profile_generator(generator_crystal1)
# If you have a multi-core computer (you probably do), run your
# refinement in parallel!
@@ -154,19 +154,19 @@ def make_recipe(cif_path, dat_path):
)
# 14: Set the Fit Contribution profile to the Profile object.
- contribution.setProfile(profile, xname="r")
+ contribution.set_profile(profile, xname="r")
# 15: Set an equation, based on your PDF generators. Here we add an extra
# layer of complexity, incorporating 'f' into our equation. This new term
# incorporates the effect of finite crystallite size damping on our PDF
# model. In this case we use a function which models a
- # spherical NP 'sphericalCF'.
- contribution.registerFunction(sphericalCF, name="f")
- contribution.setEquation("s1*G1*f")
+ # spherical NP 'spherical_particle'.
+ contribution.register_function(spherical_particle, name="f")
+ contribution.set_equation("s1*G1*f")
# 16: Create the Fit Recipe object that holds all the details of the fit.
recipe = FitRecipe()
- recipe.addContribution(contribution)
+ recipe.add_contribution(contribution)
# 17: Initialize the instrument parameters, Q_damp and Q_broad, and
# assign Q_max and Q_min.
@@ -177,18 +177,20 @@ def make_recipe(cif_path, dat_path):
# 18: Add, initialize, and tag variables in the Fit Recipe object.
# In this case we also add 'psize', which is the NP size.
- recipe.addVar(contribution.s1, SCALE_I, tag="scale")
- recipe.addVar(contribution.psize, PSIZE_I, tag="psize")
+ recipe.add_variable(contribution.s1, SCALE_I, tag="scale")
+ recipe.add_variable(
+ contribution.particle_diameter, PSIZE_I, name="psize", tag="psize"
+ )
- # 19: Use the srfit function 'constrainAsSpaceGroup' to constrain
+ # 19: Use the srfit function 'constrain_as_space_group' to constrain
# the lattice and ADP parameters according to the Fm-3m space group.
- spacegroupparams = constrainAsSpaceGroup(generator_crystal1.phase, sg)
+ spacegroupparams = constrain_as_space_group(generator_crystal1.phase, sg)
for par in spacegroupparams.latpars:
- recipe.addVar(
+ recipe.add_variable(
par, value=CUBICLAT_I, fixed=False, name="fcc_Lat", tag="lat"
)
for par in spacegroupparams.adppars:
- recipe.addVar(
+ recipe.add_variable(
par, value=UISO_I, fixed=False, name="fcc_Uiso", tag="adp"
)
@@ -196,7 +198,7 @@ def make_recipe(cif_path, dat_path):
# The instrumental parameters will remain fixed at values obtained from
# the Ni calibrant in our previous example. As we have not added them
# through recipe.addVar, they cannot be refined.
- recipe.addVar(
+ recipe.add_variable(
generator_crystal1.delta2, name="Pt_Delta2", value=DELTA2_I, tag="d2"
)
@@ -206,92 +208,6 @@ def make_recipe(cif_path, dat_path):
# End of function
-# 22 We create a useful function 'plot_results' for writing a plot of the fit
-# to disk.
-def plot_results(recipe, fig_name):
- """Creates plots of the fitted PDF and residual, and writes them to
- disk as *.pdf files.
-
- Parameters
- ----------
- recipe : The optimized Fit Recipe object containing the PDF data
- we wish to plot.
- fig_name : Path object, the full path to the figure file to create.
-
- Returns
- ----------
- None
- """
- if not isinstance(fig_name, Path):
- fig_name = Path(fig_name)
-
- plt.clf()
- plt.close("all")
- # Get an array of the r-values we fitted over.
- r = recipe.crystal.profile.x
-
- # Get an array of the observed PDF.
- g = recipe.crystal.profile.y
-
- # Get an array of the calculated PDF.
- gcalc = recipe.crystal.profile.ycalc
-
- # Make an array of identical shape as g which is offset from g.
- diffzero = -0.65 * max(g) * np.ones_like(g)
-
- # Calculate the residual (difference) array and offset it vertically.
- diff = g - gcalc + diffzero
-
- # Create a figure and an axis on which to plot
- fig, ax1 = plt.subplots(1, 1)
-
- # Plot the difference offset line
- ax1.plot(r, diffzero, lw=1.0, ls="--", c="black")
-
- # Plot the measured data
- ax1.plot(
- r,
- g,
- ls="None",
- marker="o",
- ms=5,
- mew=0.2,
- mfc="None",
- label="G(r) Data",
- )
-
- # Plot the calculated data
- ax1.plot(r, gcalc, lw=1.3, label="G(r) Fit")
-
- # Plot the difference
- ax1.plot(r, diff, lw=1.2, label="G(r) diff")
-
- # Let's label the axes!
- ax1.set_xlabel(r"r ($\mathrm{\AA}$)")
- ax1.set_ylabel(r"G ($\mathrm{\AA}$$^{-2}$)")
-
- # Tune the tick markers. We are picky!
- ax1.tick_params(axis="both", which="major", top=True, right=True)
-
- # Set the boundaries on the x-axis
- ax1.set_xlim(r[0], r[-1])
-
- # We definitely want a legend!
- ax1.legend()
-
- # Let's use a tight layout. Shun wasted space!
- plt.tight_layout()
-
- # This is going to make a figure pop up on screen for you to view.
- # The script will pause until you close the figure!
- plt.show()
-
- # Let's save the figure!
- fig.savefig(fig_name.parent / f"{fig_name.name}.pdf", format="pdf")
-
- # End of function
-
-
# 23: We again create a 'main' function to be run when we execute the script.
def main():
"""This will run by default when the file is executed using 'python
@@ -305,7 +221,6 @@ def main():
----------
None
"""
-
# Make some folders to store our output files.
resdir = PWD / "res"
fitdir = PWD / "fit"
@@ -348,14 +263,19 @@ def main():
# 27 Print the fit results to the terminal.
res = FitResults(recipe)
- res.printResults()
+ res.print_results()
# 28 Write the fit results to a file.
header = "crystal_HF.\n"
- res.saveResults(resdir / f"{basename}.res", header=header)
+ res.save_results(resdir / f"{basename}.res", header=header)
# 29 Write a plot of the fit to a (pdf) file.
- plot_results(recipe, figdir / basename)
+ fig, ax1 = recipe.plot_recipe(
+ return_fig=True,
+ xlabel=r"r ($\mathrm{\AA}$)",
+ ylabel=r"G ($\mathrm{\AA}$$^{-2}$)",
+ )
+ fig.savefig(figdir / f"{basename}.pdf", format="pdf")
# End of function
diff --git a/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/helper_functions.py b/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/helper_functions.py
index ea2759d..1238cb2 100644
--- a/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/helper_functions.py
+++ b/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/helper_functions.py
@@ -1,8 +1,6 @@
import typing
from pathlib import Path
-import matplotlib.pyplot as plt
-import numpy as np
from pyobjcryst import loadCrystal
from pyobjcryst.crystal import Crystal
from scipy.optimize import least_squares
@@ -54,12 +52,12 @@ def _create_recipe(
for name, crystal in crystals.items():
pg = PDFGenerator(name)
pg.setStructure(crystal, periodic=True)
- fc.addProfileGenerator(pg)
+ fc.add_profile_generator(pg)
for name, (f, argnames) in functions.items():
- fc.registerFunction(f, name=name, argnames=argnames)
- fc.setEquation(equation)
- fc.setProfile(profile, xname="r", yname="G", dyname="dG")
- fr.addContribution(fc)
+ fc.register_function(f, name=name, argnames=argnames)
+ fc.set_equation(equation)
+ fc.set_profile(profile, xname="r", yname="G", dyname="dG")
+ fr.add_contribution(fc)
return fr
@@ -128,56 +126,56 @@ def _add_params_in_pg(recipe: FitRecipe, pg: PDFGenerator) -> None:
-------
"""
name: str = pg.name
- recipe.addVar(
+ recipe.add_variable(
pg.scale,
name=_get_name(name, "scale"),
value=0.4,
fixed=True,
tags=_get_tags(name, "scale"),
- ).boundRange(0.0)
- recipe.addVar( # Here we add Qdamp as a variable
+ ).bound_range(0.0)
+ recipe.add_variable( # Here we add Qdamp as a variable
pg.qdamp,
name=_get_name(name, "qdamp"),
value=0.04,
fixed=True,
tags=_get_tags(name, "qdamp"),
- ).boundRange(0.0)
- recipe.addVar( # Here we add Qbroad as a variable
+ ).bound_range(0.0)
+ recipe.add_variable( # Here we add Qbroad as a variable
pg.qbroad,
name=_get_name(name, "qbroad"),
value=0.02,
fixed=True,
tags=_get_tags(name, "qbroad"),
- ).boundRange(0.0)
- recipe.addVar(
+ ).bound_range(0.0)
+ recipe.add_variable(
pg.delta2,
name=_get_name(name, "delta2"),
value=2,
fixed=True,
tags=_get_tags(name, "delta2"),
- ).boundRange(0.0)
+ ).bound_range(0.0)
latpars = pg.phase.sgpars.latpars
for par in latpars:
- recipe.addVar(
+ recipe.add_variable(
par,
name=_get_name(name, par.name),
fixed=True,
tags=_get_tags(name, "lat"),
- ).boundRange(0.0)
+ ).bound_range(0.0)
atoms: typing.List[ParameterSet] = pg.phase.getScatterers()
for atom in atoms:
par = atom.Biso
- recipe.addVar(
+ recipe.add_variable(
par,
name=_get_name(name, atom.name, "Biso"),
value=0.02,
fixed=True,
tags=_get_tags(name, "adp"),
- ).boundRange(0.0)
+ ).bound_range(0.0)
xyzpars = pg.phase.sgpars.xyzpars
for par in xyzpars:
par_name = _rename_par(par.name, atoms)
- recipe.addVar(
+ recipe.add_variable(
par,
name=_get_name(name, par_name),
fixed=True,
@@ -206,7 +204,7 @@ def _add_params_in_fc(
"""
for name in names:
par = getattr(fc, name)
- recipe.addVar(par, value=100.0, fixed=True, tags=tags)
+ recipe.add_variable(par, value=100.0, fixed=True, tags=tags)
return
@@ -242,7 +240,7 @@ def _initialize_recipe(
for name in crystals.keys():
pg: PDFGenerator = getattr(fc, name)
_add_params_in_pg(recipe, pg)
- recipe.clearFitHooks()
+ recipe.clear_fit_hooks()
return
@@ -285,9 +283,9 @@ def create_recipe_from_files(
meta_data = {}
crystals = {n: loadCrystal(f) for n, f in cif_files.items()}
pp = PDFParser()
- pp.parseFile(data_file)
+ pp.parse_file(data_file)
profile = Profile()
- profile.loadParsedData(pp)
+ profile.load_parsed_data(pp)
profile.meta.update(meta_data)
recipe = _create_recipe(
equation, crystals, functions, profile, fc_name=fc_name
@@ -343,7 +341,7 @@ def optimize_params(
n = len(steps)
fc: FitContribution = getattr(recipe, fc_name)
p: Profile = fc.profile
- p.setCalculationRange(xmin=rmin, xmax=rmax, dx=rstep)
+ p.set_calculation_range(xmin=rmin, xmax=rmax, dx=rstep)
for step in steps:
recipe.fix(*step)
for i, step in enumerate(steps):
@@ -351,14 +349,14 @@ def optimize_params(
if print_step:
print(
"Step {} / {}: refine {}".format(
- i + 1, n, ", ".join(recipe.getNames())
+ i + 1, n, ", ".join(recipe.get_names())
),
end="\r",
)
least_squares(
recipe.residual,
- recipe.getValues(),
- bounds=recipe.getBounds2(),
+ recipe.get_values(),
+ bounds=recipe.get_bounds_array(),
**kwargs,
)
return
@@ -383,28 +381,18 @@ def visualize_fits(
-------
None.
"""
- # get data
- fc = getattr(recipe, fc_name)
- r = fc.profile.x
- g = fc.profile.y
- gcalc = fc.profile.ycalc
- if xlim is not None:
- sel = np.logical_and(r >= xlim[0], r <= xlim[1])
- r = r[sel]
- g = g[sel]
- gcalc = gcalc[sel]
- gdiff = g - gcalc
- diffzero = -0.8 * np.max(g) * np.ones_like(g)
- # plot figure
- _, ax = plt.subplots()
- ax.plot(r, g, "bo", label="G(r) Data")
- ax.plot(r, gcalc, "r-", label="G(r) Fit")
- ax.plot(r, gdiff + diffzero, "g-", label="G(r) Diff")
- ax.plot(r, diffzero, "k-")
- ax.set_xlabel(r"$r (\AA)$")
- ax.set_ylabel(r"$G (\AA^{-2})$")
- ax.legend(loc=1)
- plt.show()
+ xmin, xmax = xlim if xlim is not None else (None, None)
+ recipe.plot_recipe(
+ xmin=xmin,
+ xmax=xmax,
+ data_style="o",
+ data_label="G(r) Data",
+ fit_label="G(r) Fit",
+ diff_label="G(r) Diff",
+ xlabel=r"$r (\AA)$",
+ ylabel=r"$G (\AA^{-2})$",
+ legend_loc=1,
+ )
return
@@ -440,7 +428,7 @@ def save_results(
d_path.mkdir(parents=True, exist_ok=True)
f_path = d_path.joinpath(file_stem)
fr = FitResults(recipe)
- fr.saveResults(str(f_path.with_suffix(".res")))
+ fr.save_results(str(f_path.with_suffix(".res")))
fc: FitContribution = getattr(recipe, fc_name)
profile: Profile = fc.profile
profile.savetxt(str(f_path.with_suffix(".fgr")))
diff --git a/docs/examples/pdf/ch05Fit2Phase/solutions/diffpy-cmi/fit2P.py b/docs/examples/pdf/ch05Fit2Phase/solutions/diffpy-cmi/fit2P.py
index 3e12439..eed99ef 100644
--- a/docs/examples/pdf/ch05Fit2Phase/solutions/diffpy-cmi/fit2P.py
+++ b/docs/examples/pdf/ch05Fit2Phase/solutions/diffpy-cmi/fit2P.py
@@ -23,8 +23,8 @@
Profile,
)
from diffpy.srfit.pdf import PDFGenerator, PDFParser
-from diffpy.srfit.structure import constrainAsSpaceGroup
-from diffpy.structure.parsers import getParser
+from diffpy.srfit.structure import constrain_as_space_group
+from diffpy.structure.parsers import get_parser
plt.style.use(all_styles["bg-style"])
# Config ##############################
@@ -91,10 +91,10 @@ def make_recipe(cif_path1, cif_path2, dat_path):
"""
# 9: Create two CIF file parsing objects, parse and load the structures,
# and grab the space group names.
- p_cif1 = getParser("cif")
- p_cif2 = getParser("cif")
- stru1 = p_cif1.parseFile(cif_path1)
- stru2 = p_cif2.parseFile(cif_path2)
+ p_cif1 = get_parser("cif")
+ p_cif2 = get_parser("cif")
+ stru1 = p_cif1.parse_file(cif_path1)
+ stru2 = p_cif2.parse_file(cif_path2)
sg1 = p_cif1.spacegroup.short_name
sg2 = p_cif2.spacegroup.short_name
@@ -102,9 +102,9 @@ def make_recipe(cif_path1, cif_path2, dat_path):
# tell this profile the range and mesh of points in r-space.
profile = Profile()
parser = PDFParser()
- parser.parseFile(dat_path)
- profile.loadParsedData(parser)
- profile.setCalculationRange(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)
+ parser.parse_file(dat_path)
+ profile.load_parsed_data(parser)
+ profile.set_calculation_range(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)
# 11a: Create a PDF Generator object for a periodic structure model
# of phase 1.
@@ -121,8 +121,8 @@ def make_recipe(cif_path1, cif_path2, dat_path):
# represented by 'generator_crystal1' AND the phase represented
# by 'generator_crystal2'.
contribution = FitContribution("crystal")
- contribution.addProfileGenerator(generator_crystal1)
- contribution.addProfileGenerator(generator_crystal2)
+ contribution.add_profile_generator(generator_crystal1)
+ contribution.add_profile_generator(generator_crystal2)
# If you have a multi-core computer (you probably do), run your refinement
# in parallel!
@@ -146,7 +146,7 @@ def make_recipe(cif_path1, cif_path2, dat_path):
generator_crystal2.parallel(ncpu=ncpu, mapfunc=pool.map)
# 13: Set the Fit Contribution profile to the Profile object.
- contribution.setProfile(profile, xname="r")
+ contribution.set_profile(profile, xname="r")
# 14: Set an equation, based on your PDF generators. This is
# a more complicated case, since we have two phases. The equation
@@ -154,15 +154,15 @@ def make_recipe(cif_path1, cif_path2, dat_path):
# 'G_Si' and 'G_Ni' weighted by a refined scale term for each phase,
# 's1_Si' and '(1 - s1_Si)'. We also include a general 's2'
# to account for data scale.
- contribution.setEquation("s2*(s1_Si*G_Si + (1.0-s1_Si)*G_Ni)")
+ contribution.set_equation("s2*(s1_Si*G_Si + (1.0-s1_Si)*G_Ni)")
# 15: Create the Fit Recipe object that holds all the details of the fit.
recipe = FitRecipe()
- recipe.addContribution(contribution)
+ recipe.add_contribution(contribution)
# 16: Add, initialize, and tag the two scale variables.
- recipe.addVar(contribution.s1_Si, SCALE_I_SI, tag="scale")
- recipe.addVar(contribution.s2, DATA_SCALE_I, tag="scale")
+ recipe.add_variable(contribution.s1_Si, SCALE_I_SI, tag="scale")
+ recipe.add_variable(contribution.s2, DATA_SCALE_I, tag="scale")
# 17:This is new, we want to ensure that the data scale parameter 's2'
# is always positive, and the phase scale parameter 's1_Si' is always
@@ -171,12 +171,14 @@ def make_recipe(cif_path1, cif_path2, dat_path):
# our objective function such that if the parameter approaches a user
# defined upper or lower bound, the objective function will increase,
# driving the fit away from the boundary.
- recipe.restrain("s2", lb=0.0, scaled=True, sig=0.00001)
+ recipe.add_soft_bounds("s2", lower_bound=0.0, scaled=True, sig=0.00001)
- recipe.restrain("s1_Si", lb=0.0, ub=1.0, scaled=True, sig=0.00001)
+ recipe.add_soft_bounds(
+ "s1_Si", lower_bound=0.0, upper_bound=1.0, scaled=True, sig=0.00001
+ )
# 18a: This is a bit new. We will again use the srfit function
- # constrainAsSpaceGroup to constrain the lattice and ADP parameters
+ # constrain_as_space_group to constrain the lattice and ADP parameters
# according to the space group of each of the two phases.
# We loop through generators composed of PDF Generators
# and space groups specific to EACH of the TWO candidate phases.
@@ -194,22 +196,24 @@ def make_recipe(cif_path1, cif_path2, dat_path):
generator.setQmin(QMIN)
# 18c: Get the symmetry equivalent parameters for each phase.
- spacegroupparams = constrainAsSpaceGroup(generator.phase, space_group)
+ spacegroupparams = constrain_as_space_group(
+ generator.phase, space_group
+ )
# 18d: Loop over and constrain these parameters for each phase.
# Each parameter name gets the loop index 'i' appended so there
# are not parameter name collisions.
for par in spacegroupparams.latpars:
- recipe.addVar(
+ recipe.add_variable(
par, name=f"{par.name}_{name}", fixed=False, tag="lat"
)
for par in spacegroupparams.adppars:
- recipe.addVar(
+ recipe.add_variable(
par, name=f"{par.name}_{name}", fixed=False, tag="adp"
)
# 19: Add delta, but not instrumental parameters to Fit Recipe.
# One for each phase.
- recipe.addVar(
+ recipe.add_variable(
generator.delta1,
name=f"Delta1_{name}",
value=DELTA1_I_SI,
@@ -383,11 +387,11 @@ def main():
# 24 Print the fit results to the terminal.
res = FitResults(recipe)
- res.printResults()
+ res.print_results()
# 25 Write the fit results to a file.
header = "crystal_HF.\n"
- res.saveResults(resdir / f"{basename}.res", header=header)
+ res.save_results(resdir / f"{basename}.res", header=header)
# 26 Write a plot of the fit to a (pdf) file.
plot_results(recipe, figdir / basename)
diff --git a/docs/examples/pdf/ch06RefineCrystalStructureGen/solutions/diffpy-cmi/fitCrystalGen.py b/docs/examples/pdf/ch06RefineCrystalStructureGen/solutions/diffpy-cmi/fitCrystalGen.py
index 75a5c9c..c63fe52 100644
--- a/docs/examples/pdf/ch06RefineCrystalStructureGen/solutions/diffpy-cmi/fitCrystalGen.py
+++ b/docs/examples/pdf/ch06RefineCrystalStructureGen/solutions/diffpy-cmi/fitCrystalGen.py
@@ -23,9 +23,9 @@
Profile,
)
from diffpy.srfit.pdf import PDFGenerator, PDFParser
-from diffpy.srfit.structure import constrainAsSpaceGroup
+from diffpy.srfit.structure import constrain_as_space_group
from diffpy.structure.atom import Atom
-from diffpy.structure.parsers import getParser
+from diffpy.structure.parsers import get_parser
plt.style.use(all_styles["bg-style"])
@@ -88,8 +88,8 @@ def make_recipe(cif_path, dat_path):
"""
# 9: Create a CIF file parsing object, parse and load the structure, and
# grab the space group name.
- p_cif = getParser("cif")
- stru1 = p_cif.parseFile(cif_path)
+ p_cif = get_parser("cif")
+ stru1 = p_cif.parse_file(cif_path)
sg = p_cif.spacegroup.short_name
stru1.anisotropy = True
@@ -100,17 +100,17 @@ def make_recipe(cif_path, dat_path):
# coordinates, respectively.
for atom in stru1:
if "Ba" in atom.element:
- stru1.addNewAtom(Atom("K", xyz=atom.xyz))
+ stru1.add_new_atom(Atom("K", xyz=atom.xyz))
elif "Zn" in atom.element:
- stru1.addNewAtom(Atom("Mn", xyz=atom.xyz))
+ stru1.add_new_atom(Atom("Mn", xyz=atom.xyz))
# 11: Create a Profile object for the experimental dataset and
# tell this profile the range and mesh of points in r-space.
profile = Profile()
parser = PDFParser()
- parser.parseFile(dat_path)
- profile.loadParsedData(parser)
- profile.setCalculationRange(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)
+ parser.parse_file(dat_path)
+ profile.load_parsed_data(parser)
+ profile.set_calculation_range(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)
# 12: Create a PDF Generator object for a periodic structure model.
generator_crystal1 = PDFGenerator("G1")
@@ -118,7 +118,7 @@ def make_recipe(cif_path, dat_path):
# 13: Create a Fit Contribution object.
contribution = FitContribution("crystal")
- contribution.addProfileGenerator(generator_crystal1)
+ contribution.add_profile_generator(generator_crystal1)
# If you have a multi-core computer (you probably do), run your refinement
# in parallel!
@@ -141,15 +141,15 @@ def make_recipe(cif_path, dat_path):
generator_crystal1.parallel(ncpu=ncpu, mapfunc=pool.map)
# 14: Set the Fit Contribution profile to the Profile object.
- contribution.setProfile(profile, xname="r")
+ contribution.set_profile(profile, xname="r")
# 15: Set an equation, based on your PDF generators. This is
# again a simple case, with only a scale and a single PDF generator.
- contribution.setEquation("s1*G1")
+ contribution.set_equation("s1*G1")
# 16: Create the Fit Recipe object that holds all the details of the fit.
recipe = FitRecipe()
- recipe.addContribution(contribution)
+ recipe.add_contribution(contribution)
# 17: Initialize the instrument parameters, Q_damp and Q_broad, and
# assign Q_max and Q_min.
@@ -159,22 +159,22 @@ def make_recipe(cif_path, dat_path):
generator_crystal1.setQmin(QMIN)
# 18: Add, initialize, and tag the scale variable.
- recipe.addVar(contribution.s1, SCALE_I, tag="scale")
+ recipe.add_variable(contribution.s1, SCALE_I, tag="scale")
- # 19: Use the srfit function constrainAsSpaceGroup to constrain
+ # 19: Use the srfit function constrain_as_space_group to constrain
# the lattice and ADP parameters according to the I4/mmm space
# group setting.
- spacegroupparams = constrainAsSpaceGroup(generator_crystal1.phase, sg)
+ spacegroupparams = constrain_as_space_group(generator_crystal1.phase, sg)
for par in spacegroupparams.latpars:
- recipe.addVar(par, fixed=False, tag="lat")
+ recipe.add_variable(par, fixed=False, tag="lat")
for par in spacegroupparams.adppars:
- recipe.addVar(par, fixed=False, tag="adp")
+ recipe.add_variable(par, fixed=False, tag="adp")
for par in spacegroupparams.xyzpars:
- recipe.addVar(par, fixed=False, tag="xyz")
+ recipe.add_variable(par, fixed=False, tag="xyz")
# 20: Add delta, but not instrumental parameters to Fit Recipe.
- recipe.addVar(
+ recipe.add_variable(
generator_crystal1.delta1, name="Delta1", value=DELTA1_I, tag="d1"
)
@@ -182,21 +182,25 @@ def make_recipe(cif_path, dat_path):
# both Mn and K, so we need to add two new parameters, here called
# 'Mn_occ' and 'K_occ.' We give them the tag 'occs' and we initialize
# them with reasonable values as defined above.
- recipe.newVar(name="Mn_occ", value=MN_FRAC_I, fixed=True, tag="occs")
- recipe.newVar(name="K_occ", value=K_FRAC_I, fixed=True, tag="occs")
+ recipe.create_new_variable(
+ name="Mn_occ", value=MN_FRAC_I, fixed=True, tag="occs"
+ )
+ recipe.create_new_variable(
+ name="K_occ", value=K_FRAC_I, fixed=True, tag="occs"
+ )
# 22: Now, we want to constrain the occupancy of sites appropriately.
# To do this, we loop over all atoms in the structure, and if the
# atom label matches a pattern, we constrain the occuapncy appropriately.
for atom in recipe.crystal.G1.phase.atoms:
if "Ba" in atom.atom.label:
- recipe.constrain(atom.occupancy, "1.0 - K_occ")
+ recipe.add_constraint(atom.occupancy, "1.0 - K_occ")
if "K" in atom.atom.label:
- recipe.constrain(atom.occupancy, "K_occ")
+ recipe.add_constraint(atom.occupancy, "K_occ")
if "Zn" in atom.atom.label:
- recipe.constrain(atom.occupancy, "1.0 - Mn_occ")
+ recipe.add_constraint(atom.occupancy, "1.0 - Mn_occ")
if "Mn" in atom.atom.label:
- recipe.constrain(atom.occupancy, "Mn_occ")
+ recipe.add_constraint(atom.occupancy, "Mn_occ")
# 23: Return the Fit Recipe object to be optimized.
return recipe
@@ -204,93 +208,6 @@ def make_recipe(cif_path, dat_path):
# End of function
-# 24: We create a useful function 'plot_results' for writing a plot
-# of the fit to disk.
-def plot_results(recipe, fig_name):
- """Creates plots of the fitted PDF and residual, and writes them to
- disk as *.pdf files.
-
- Parameters
- ----------
- recipe : The optimized Fit Recipe object containing the PDF data
- we wish to plot.
- fig_name : Path object, the full path to the figure file to create..
-
- Returns
- ----------
- None
- """
- if not isinstance(fig_name, Path):
- fig_name = Path(fig_name)
-
- plt.clf()
- plt.close("all")
-
- # Get an array of the r-values we fitted over.
- r = recipe.crystal.profile.x
-
- # Get an array of the observed PDF.
- g = recipe.crystal.profile.y
-
- # Get an array of the calculated PDF.
- gcalc = recipe.crystal.profile.ycalc
-
- # Make an array of identical shape as g which is offset from g.
- diffzero = -0.65 * max(g) * np.ones_like(g)
-
- # Calculate the residual (difference) array and offset it vertically.
- diff = g - gcalc + diffzero
-
- # Create a figure and an axis on which to plot
- fig, ax1 = plt.subplots(1, 1)
-
- # Plot the difference offset line
- ax1.plot(r, diffzero, lw=1.0, ls="--", c="black")
-
- # Plot the measured data
- ax1.plot(
- r,
- g,
- ls="None",
- marker="o",
- ms=5,
- mew=0.2,
- mfc="None",
- label="G(r) Data",
- )
-
- # Plot the calculated data
- ax1.plot(r, gcalc, lw=1.3, label="G(r) Fit")
-
- # Plot the difference
- ax1.plot(r, diff, lw=1.2, label="G(r) diff")
-
- # Let's label the axes!
- ax1.set_xlabel(r"r ($\mathrm{\AA}$)")
- ax1.set_ylabel(r"G ($\mathrm{\AA}$$^{-2}$)")
-
- # Tune the tick markers. We are picky!
- ax1.tick_params(axis="both", which="major", top=True, right=True)
-
- # Set the boundaries on the x-axis
- ax1.set_xlim(r[0], r[-1])
-
- # We definitely want a legend!
- ax1.legend()
-
- # Let's use a tight layout. Shun wasted space!
- plt.tight_layout()
-
- # This is going to make a figure pop up on screen for you to view.
- # The script will pause until you close the figure!
- plt.show()
-
- # Let's save the figure!
- fig.savefig(fig_name.parent / f"{fig_name.name}.pdf", format="pdf")
-
- # End of function
-
-
# 25: We again create a 'main' function to be run when we execute the script.
def main():
"""This will run by default when the file is executed using "python
@@ -304,7 +221,6 @@ def main():
----------
None
"""
-
# Make some folders to store our output files.
resdir = PWD / "res"
fitdir = PWD / "fit"
@@ -346,14 +262,19 @@ def main():
# 29: Print the fit results to the terminal.
res = FitResults(recipe)
- res.printResults()
+ res.print_results()
# 30: Write the fit results to a file.
header = "crystal_HF.\n"
- res.saveResults(resdir / f"{basename}.res", header=header)
+ res.save_results(resdir / f"{basename}.res", header=header)
# 31: Write a plot of the fit to a (pdf) file.
- plot_results(recipe, figdir / basename)
+ fig, ax1 = recipe.plot_recipe(
+ return_fig=True,
+ xlabel=r"r ($\mathrm{\AA}$)",
+ ylabel=r"G ($\mathrm{\AA}$$^{-2}$)",
+ )
+ fig.savefig(figdir / f"{basename}.pdf", format="pdf")
# End of function
diff --git a/docs/examples/pdf/ch07StructuralPhaseTransitions/solutions/diffpy-cmi/fitTSeries.py b/docs/examples/pdf/ch07StructuralPhaseTransitions/solutions/diffpy-cmi/fitTSeries.py
index 654c50e..d675a77 100644
--- a/docs/examples/pdf/ch07StructuralPhaseTransitions/solutions/diffpy-cmi/fitTSeries.py
+++ b/docs/examples/pdf/ch07StructuralPhaseTransitions/solutions/diffpy-cmi/fitTSeries.py
@@ -22,8 +22,8 @@
Profile,
)
from diffpy.srfit.pdf import PDFGenerator, PDFParser
-from diffpy.srfit.structure import constrainAsSpaceGroup
-from diffpy.structure.parsers import getParser
+from diffpy.srfit.structure import constrain_as_space_group
+from diffpy.structure.parsers import get_parser
plt.style.use(all_styles["bg-style"])
@@ -97,17 +97,17 @@ def make_recipe(cif_path, dat_path):
# relevant info and load the structure in the CIF file. This
# includes the space group of the structure. We need this so we
# can constrain the structure parameters later on.
- p_cif = getParser("cif")
- stru1 = p_cif.parseFile(cif_path)
+ p_cif = get_parser("cif")
+ stru1 = p_cif.parse_file(cif_path)
sg = p_cif.spacegroup.short_name
# 10: Create a Profile object for the experimental dataset and
# tell this profile the range and mesh of points in r-space.
profile = Profile()
parser = PDFParser()
- parser.parseFile(dat_path)
- profile.loadParsedData(parser)
- profile.setCalculationRange(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)
+ parser.parse_file(dat_path)
+ profile.load_parsed_data(parser)
+ profile.set_calculation_range(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)
# 11: Create a PDF Generator object for a periodic structure model.
generator_crystal1 = PDFGenerator("G1")
@@ -115,7 +115,7 @@ def make_recipe(cif_path, dat_path):
# 12: Create a Fit Contribution object.
contribution = FitContribution("crystal")
- contribution.addProfileGenerator(generator_crystal1)
+ contribution.add_profile_generator(generator_crystal1)
# If you have a multi-core computer (you probably do), run your
# refinement in parallel!
@@ -138,15 +138,15 @@ def make_recipe(cif_path, dat_path):
generator_crystal1.parallel(ncpu=ncpu, mapfunc=pool.map)
# 13: Set the Fit Contribution profile to the Profile object.
- contribution.setProfile(profile, xname="r")
+ contribution.set_profile(profile, xname="r")
# 14: Set an equation, based on your PDF generators. This is
# again a simple case, with only a scale and a single PDF generator.
- contribution.setEquation("s1*G1")
+ contribution.set_equation("s1*G1")
# 15: Create the Fit Recipe object that holds all the details of the fit.
recipe = FitRecipe()
- recipe.addContribution(contribution)
+ recipe.add_contribution(contribution)
# 16: Initialize the instrument parameters, Q_damp and Q_broad, and
# assign Q_max and Q_min.
@@ -156,21 +156,21 @@ def make_recipe(cif_path, dat_path):
generator_crystal1.setQmin(QMIN)
# 17: Add, initialize, and tag the scale variable.
- recipe.addVar(contribution.s1, SCALE_I, tag="scale")
+ recipe.add_variable(contribution.s1, SCALE_I, tag="scale")
- # 18: Use the srfit function constrainAsSpaceGroup to constrain
+ # 18: Use the srfit function constrain_as_space_group to constrain
# the lattice, ADP parameters, and atomic positions according to
# the space group.
- spacegroupparams = constrainAsSpaceGroup(generator_crystal1.phase, sg)
+ spacegroupparams = constrain_as_space_group(generator_crystal1.phase, sg)
for par in spacegroupparams.latpars:
- recipe.addVar(par, fixed=False, tag="lat")
+ recipe.add_variable(par, fixed=False, tag="lat")
for par in spacegroupparams.adppars:
- recipe.addVar(par, fixed=False, tag="adp")
+ recipe.add_variable(par, fixed=False, tag="adp")
for par in spacegroupparams.xyzpars:
- recipe.addVar(par, fixed=False, tag="xyz")
+ recipe.add_variable(par, fixed=False, tag="xyz")
# 19: Add delta, but not instrumental parameters to Fit Recipe.
- recipe.addVar(
+ recipe.add_variable(
generator_crystal1.delta2, name="Delta2", value=DELTA2_I, tag="d2"
)
@@ -179,94 +179,6 @@ def make_recipe(cif_path, dat_path):
# End of function
-# 20: We create a useful function 'plot_results' for writing a plot
-# of the fit to disk.
-def plot_results(recipe, fig_name):
- """Creates plots of the fitted PDF and residual, and writes them to
- disk as *.pdf files.
-
- Parameters
- ----------
- recipe : The optimized Fit Recipe object containing the PDF data
- we wish to plot.
- fig_name : Path object, the full path to the figure file to create..
-
- Returns
- ----------
- None
- """
- if not isinstance(fig_name, Path):
- fig_name = Path(fig_name)
-
- plt.clf()
- plt.close("all")
-
- # Get an array of the r-values we fitted over.
- r = recipe.crystal.profile.x
-
- # Get an array of the observed PDF.
- g = recipe.crystal.profile.y
-
- # Get an array of the calculated PDF.
- gcalc = recipe.crystal.profile.ycalc
-
- # Make an array of identical shape as g which is offset from g.
- diffzero = -0.65 * max(g) * np.ones_like(g)
-
- # Calculate the residual (difference) array and offset it vertically.
- diff = g - gcalc + diffzero
-
- # Create a figure and an axis on which to plot
- fig, ax1 = plt.subplots(1, 1)
-
- # Plot the difference offset line
- ax1.plot(r, diffzero, lw=1.0, ls="--", c="black")
-
- # Plot the measured data
- ax1.plot(
- r,
- g,
- ls="None",
- marker="o",
- ms=5,
- mew=0.2,
- mfc="None",
- label="G(r) Data",
- )
-
- # Plot the calculated data
- ax1.plot(r, gcalc, lw=1.3, label="G(r) Fit")
-
- # Plot the difference
- ax1.plot(r, diff, lw=1.2, label="G(r) diff")
-
- # Let's label the axes!
- ax1.set_xlabel(r"r ($\mathrm{\AA}$)")
- ax1.set_ylabel(r"G ($\mathrm{\AA}$$^{-2}$)")
-
- # Tune the tick markers. We are picky!
- ax1.tick_params(axis="both", which="major", top=True, right=True)
-
- # Set the boundaries on the x-axis
- ax1.set_xlim(r[0], r[-1])
-
- # We definitely want a legend!
- ax1.legend()
-
- # Let's use a tight layout. Shun wasted space!
- plt.tight_layout()
-
- # This is going to make a figure pop up on screen for you to view.
- # The script will pause until you close the figure!
- if SHOW_PLOT:
- plt.show()
-
- # Let's save the figure!
- fig.savefig(fig_name.parent / f"{fig_name.name}.pdf", format="pdf")
-
- # End of function
-
-
# 21: We again create a 'main' function to be run when we execute the script.
def main():
"""This will run by default when the file is executed using 'python
@@ -280,7 +192,6 @@ def main():
----------
None
"""
-
# Make some folders to store our output files.
resdir = PWD / "res"
fitdir = PWD / "fit"
@@ -314,8 +225,8 @@ def main():
# the structure.
# Specifically, the short space group name. We need to replace any
# "/" with something else, as this will cause issues with naming.
- p_cif = getParser("cif")
- p_cif.parseFile(str(cif))
+ p_cif = get_parser("cif")
+ p_cif.parse_file(str(cif))
stru_type = p_cif.spacegroup.short_name.replace("/", "_on_")
# 28: We make our recipe with the first temperature/PDF file
@@ -340,10 +251,10 @@ def main():
# fit over.
profile = Profile()
parser = PDFParser()
- parser.parseFile(file)
- profile.loadParsedData(parser)
- recipe.crystal.setProfile(profile)
- recipe.crystal.profile.setCalculationRange(
+ parser.parse_file(file)
+ profile.load_parsed_data(parser)
+ recipe.crystal.set_profile(profile)
+ recipe.crystal.profile.set_calculation_range(
xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP
)
@@ -363,14 +274,20 @@ def main():
# 34: Print the fit results to the terminal.
res = FitResults(recipe)
- res.printResults()
+ res.print_results()
# 35: Write the fit results to a file.
header = "crystal_HF.\n"
- res.saveResults(resdir / f"{basename}.res", header=header)
+ res.save_results(resdir / f"{basename}.res", header=header)
# 36: Write a plot of the fit to a (pdf) file.
- plot_results(recipe, figdir / basename)
+ fig, ax1 = recipe.plot_recipe(
+ return_fig=True,
+ show=SHOW_PLOT,
+ xlabel=r"r ($\mathrm{\AA}$)",
+ ylabel=r"G ($\mathrm{\AA}$$^{-2}$)",
+ )
+ fig.savefig(figdir / f"{basename}.pdf", format="pdf")
# End of function
diff --git a/docs/examples/pdf/ch08NPRefinement/solutions/diffpy-cmi/fitCdSeNP.py b/docs/examples/pdf/ch08NPRefinement/solutions/diffpy-cmi/fitCdSeNP.py
index bdacb52..f28168e 100644
--- a/docs/examples/pdf/ch08NPRefinement/solutions/diffpy-cmi/fitCdSeNP.py
+++ b/docs/examples/pdf/ch08NPRefinement/solutions/diffpy-cmi/fitCdSeNP.py
@@ -10,7 +10,6 @@
# 1: Import relevant system packages that we will need...
from pathlib import Path
-import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import least_squares
@@ -22,9 +21,9 @@
Profile,
)
from diffpy.srfit.pdf import PDFGenerator, PDFParser
-from diffpy.srfit.pdf.characteristicfunctions import sphericalCF
-from diffpy.srfit.structure import constrainAsSpaceGroup
-from diffpy.structure.parsers import getParser
+from diffpy.srfit.pdf.characteristicfunctions import spherical_particle
+from diffpy.srfit.structure import constrain_as_space_group
+from diffpy.structure.parsers import get_parser
# Config ##############################
# 2: Give a file path to where your pdf (.gr) and (.cif) files are located.
@@ -95,17 +94,17 @@ def make_recipe_one_phase(cif_path, dat_path, adp_iso=True):
"""
# 10: Create a CIF file parsing object, parse and load the structure, and
# grab the space group name.
- p_cif = getParser("cif")
- stru1 = p_cif.parseFile(cif_path)
+ p_cif = get_parser("cif")
+ stru1 = p_cif.parse_file(cif_path)
sg = p_cif.spacegroup.short_name
# 11: Create a Profile object for the experimental dataset and
# tell this profile the range and mesh of points in r-space.
profile = Profile()
parser = PDFParser()
- parser.parseFile(dat_path)
- profile.loadParsedData(parser)
- profile.setCalculationRange(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)
+ parser.parse_file(dat_path)
+ profile.load_parsed_data(parser)
+ profile.set_calculation_range(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)
# 12: Create a PDF Generator object for a periodic structure model.
generator_crystal1 = PDFGenerator("G1")
@@ -113,7 +112,7 @@ def make_recipe_one_phase(cif_path, dat_path, adp_iso=True):
# 13: Create a Fit Contribution object.
contribution = FitContribution("crystal")
- contribution.addProfileGenerator(generator_crystal1)
+ contribution.add_profile_generator(generator_crystal1)
# If you have a multi-core computer (you probably do), run
# your refinement in parallel!
@@ -137,7 +136,7 @@ def make_recipe_one_phase(cif_path, dat_path, adp_iso=True):
)
# 14: Set the Fit Contribution profile to the Profile object.
- contribution.setProfile(profile, xname="r")
+ contribution.set_profile(profile, xname="r")
# 15: Set an equation, based on your PDF generators.
# Here we add an extra layer of complexity, incorporating
@@ -145,12 +144,12 @@ def make_recipe_one_phase(cif_path, dat_path, adp_iso=True):
# incorporates damping to our PDF to model the effect of
# finite crystallite size.
# In this case we use a function which models a spherical NP.
- contribution.registerFunction(sphericalCF, name="f")
- contribution.setEquation("s1*G1*f")
+ contribution.register_function(spherical_particle, name="f")
+ contribution.set_equation("s1*G1*f")
# 16: Create the Fit Recipe object that holds all the details of the fit.
recipe = FitRecipe()
- recipe.addContribution(contribution)
+ recipe.add_contribution(contribution)
# 17: Initialize the instrument parameters, Q_damp and Q_broad, and
# assign Q_max and Q_min.
@@ -161,9 +160,11 @@ def make_recipe_one_phase(cif_path, dat_path, adp_iso=True):
# 18: Add, initialize, and tag variables in the Fit Recipe object.
# In this case we also add psize, which is the NP size.
- recipe.addVar(contribution.s1, SCALE_I, tag="scale")
- recipe.addVar(contribution.psize, PSIZE_I, tag="psize")
- recipe.addVar(
+ recipe.add_variable(contribution.s1, SCALE_I, tag="scale")
+ recipe.add_variable(
+ contribution.particle_diameter, PSIZE_I, name="psize", tag="psize"
+ )
+ recipe.add_variable(
generator_crystal1.delta2, name="Delta2", value=DELTA2_I, tag="d2"
)
@@ -175,33 +176,37 @@ def make_recipe_one_phase(cif_path, dat_path, adp_iso=True):
# We pass in the boolean 'False' to the anisotropy attribute
# of the structure.
stru1.anisotropy = False
- # 21: Use the srfit function constrainAsSpaceGroup to constrain
+ # 21: Use the srfit function constrain_as_space_group to constrain
# the lattice and atomic positions according to the space group.
# Note we do not include ADPs in the following.
- spacegroupparams = constrainAsSpaceGroup(
+ spacegroupparams = constrain_as_space_group(
generator_crystal1.phase, sg, constrainadps=False
)
for par in spacegroupparams.latpars:
- recipe.addVar(par, fixed=False, tag="lat")
+ recipe.add_variable(par, fixed=False, tag="lat")
for par in spacegroupparams.xyzpars:
- recipe.addVar(par, fixed=False, tag="xyz")
+ recipe.add_variable(par, fixed=False, tag="xyz")
# 22: We create the variables of isotropic ADP and assign the initial
# value to them,
# specified above. In this portion of the 'if' statement, we use
# isotropic ADP for all atoms
- cd_uiso = recipe.newVar("Cd_Uiso", value=UISO_I, tag="adp")
- se_uiso = recipe.newVar("Se_Uiso", value=UISO_I, tag="adp")
+ cd_uiso = recipe.create_new_variable(
+ "Cd_Uiso", value=UISO_I, tag="adp"
+ )
+ se_uiso = recipe.create_new_variable(
+ "Se_Uiso", value=UISO_I, tag="adp"
+ )
# 23: For all atoms in the structure model, we constrain their
# Uiso according to their species.
atoms = generator_crystal1.phase.getScatterers()
for atom in atoms:
if atom.element == "Cd":
- recipe.constrain(atom.Uiso, cd_uiso)
+ recipe.add_constraint(atom.Uiso, cd_uiso)
elif atom.element == "Se":
- recipe.constrain(atom.Uiso, se_uiso)
+ recipe.add_constraint(atom.Uiso, se_uiso)
# 24: Now, we want to have one behavior if we desire isotropic ADPs
# and another behavior if we desire anistropic ADPs. To achieve this we
@@ -212,17 +217,19 @@ def make_recipe_one_phase(cif_path, dat_path, adp_iso=True):
# the structure.
stru1.anisotropy = True
- # 26: Use the srfit function constrainAsSpaceGroup to constrain
+ # 26: Use the srfit function constrain_as_space_group to constrain
# the lattice and atomic positions according to the space group.
# Note we do include ADPs in the following.
- spacegroupparams = constrainAsSpaceGroup(generator_crystal1.phase, sg)
+ spacegroupparams = constrain_as_space_group(
+ generator_crystal1.phase, sg
+ )
for par in spacegroupparams.latpars:
- recipe.addVar(par, fixed=False, tag="lat")
+ recipe.add_variable(par, fixed=False, tag="lat")
for par in spacegroupparams.adppars:
- recipe.addVar(par, fixed=False, tag="adp")
+ recipe.add_variable(par, fixed=False, tag="adp")
for par in spacegroupparams.xyzpars:
- recipe.addVar(par, fixed=False, tag="xyz")
+ recipe.add_variable(par, fixed=False, tag="xyz")
# 27: Return the Fit Recipe object to be optimized
return recipe
@@ -251,23 +258,23 @@ def make_recipe_two_phase(cif_path1, cif_path2, dat_path):
"""
# 29: Create a CIF file parsing object, parse and load the structure, and
# grab the space group name for the first structure.
- p_cif1 = getParser("cif")
- stru1 = p_cif1.parseFile(cif_path1)
+ p_cif1 = get_parser("cif")
+ stru1 = p_cif1.parse_file(cif_path1)
sg1 = p_cif1.spacegroup.short_name
# 30: Create a CIF file parsing object, parse and load the structure, and
# grab the space group name for the second structure.
- p_cif2 = getParser("cif")
- stru2 = p_cif2.parseFile(cif_path2)
+ p_cif2 = get_parser("cif")
+ stru2 = p_cif2.parse_file(cif_path2)
sg2 = p_cif2.spacegroup.short_name
# 31: Create a Profile object for the experimental dataset and
# tell this profile the range and mesh of points in r-space.
profile = Profile()
parser = PDFParser()
- parser.parseFile(dat_path)
- profile.loadParsedData(parser)
- profile.setCalculationRange(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)
+ parser.parse_file(dat_path)
+ profile.load_parsed_data(parser)
+ profile.set_calculation_range(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)
# 32: Create a PDF Generator object for a periodic structure model
# of phase 1.
@@ -288,8 +295,8 @@ def make_recipe_two_phase(cif_path1, cif_path2, dat_path):
# represented by "generator_crystal1" AND the phase represented
# by "generator_crystal2".
contribution = FitContribution("crystal")
- contribution.addProfileGenerator(generator_crystal1)
- contribution.addProfileGenerator(generator_crystal2)
+ contribution.add_profile_generator(generator_crystal1)
+ contribution.add_profile_generator(generator_crystal2)
# If you have a multi-core computer (you probably do), run your refinement
# in parallel!
@@ -313,7 +320,7 @@ def make_recipe_two_phase(cif_path1, cif_path2, dat_path):
)
# 35: Set the Fit Contribution profile to the Profile object.
- contribution.setProfile(profile, xname="r")
+ contribution.set_profile(profile, xname="r")
# 36: Set an equation, based on your PDF generators. Here we add an
# extra layer of complexity, incorporating "f" int our equation.
@@ -321,28 +328,34 @@ def make_recipe_two_phase(cif_path1, cif_path2, dat_path):
# effect of finite crystallite size.
# In this case we use a function which models a spherical NP.
# We use the same function for each phase.
- contribution.registerFunction(sphericalCF, name="f")
- contribution.setEquation("data_scale*(s1*G1*f + (1.0-s1)*G2*f)")
+ contribution.register_function(spherical_particle, name="f")
+ contribution.set_equation("data_scale*(s1*G1*f + (1.0-s1)*G2*f)")
# 37: Create the Fit Recipe object that holds all the details of the fit.
recipe = FitRecipe()
- recipe.addContribution(contribution)
+ recipe.add_contribution(contribution)
# 38: Add, initialize, and tag both scale parameters, the crystal size
# parameter,
# and a correlated motion parameter. We will use one correlated motion
# parameter across both phases.
- recipe.addVar(contribution.s1, SCALE_PHASE_I, tag="phase_scale")
- recipe.addVar(contribution.data_scale, DATA_SCALE_I, tag="scale")
- recipe.addVar(contribution.psize, PSIZE_I, tag="psize")
- delta2 = recipe.newVar("Delta2", value=DELTA2_I, tag="d2")
+ recipe.add_variable(contribution.s1, SCALE_PHASE_I, tag="phase_scale")
+ recipe.add_variable(contribution.data_scale, DATA_SCALE_I, tag="scale")
+ recipe.add_variable(
+ contribution.particle_diameter, PSIZE_I, name="psize", tag="psize"
+ )
+ delta2 = recipe.create_new_variable("Delta2", value=DELTA2_I, tag="d2")
# 39: restrain our new parameters.
- recipe.restrain("data_scale", lb=0.0, scaled=True, sig=0.00001)
+ recipe.add_soft_bounds(
+ "data_scale", lower_bound=0.0, scaled=True, sig=0.00001
+ )
- recipe.restrain("s1", lb=0.0, ub=1.0, scaled=True, sig=0.00001)
+ recipe.add_soft_bounds(
+ "s1", lower_bound=0.0, upper_bound=1.0, scaled=True, sig=0.00001
+ )
- recipe.restrain("psize", lb=0.0, scaled=True, sig=0.00001)
+ recipe.add_soft_bounds("psize", lower_bound=0.0, scaled=True, sig=0.00001)
# 40: Initialize the instrument parameters, Q_damp and Q_broad, and
# assign Q_max and Q_min.
@@ -354,8 +367,8 @@ def make_recipe_two_phase(cif_path1, cif_path2, dat_path):
# 41: We create the variables of ADP and assign the initial value to them,
# specified above. In this example, we use isotropic ADP for all atoms.
# We will use these across both phases
- cd_uiso = recipe.newVar("Cd_Uiso", value=UISO_I, tag="adp")
- se_uiso = recipe.newVar("Se_Uiso", value=UISO_I, tag="adp")
+ cd_uiso = recipe.create_new_variable("Cd_Uiso", value=UISO_I, tag="adp")
+ se_uiso = recipe.create_new_variable("Se_Uiso", value=UISO_I, tag="adp")
# 42: Now, we loop over our list of generators and space groups
for generator, sg in zip(generators, sgs):
@@ -365,27 +378,27 @@ def make_recipe_two_phase(cif_path1, cif_path2, dat_path):
# 44: constrain the delta2 parameter of each generator according to
# our parameter
- recipe.constrain(generator.delta2, delta2)
+ recipe.add_constraint(generator.delta2, delta2)
# 45: turn off anisotropy
generator.phase.stru.anisotropy = False
- # 46: Use the srfit function constrainAsSpaceGroup to constrain
+ # 46: Use the srfit function constrain_as_space_group to constrain
# the lattice, ADP parameters, and atomic positions according to the
# space group.
- spacegroupparams = constrainAsSpaceGroup(
+ spacegroupparams = constrain_as_space_group(
generator.phase, sg, constrainadps=False
)
for par in spacegroupparams.latpars:
- recipe.addVar(
+ recipe.add_variable(
par,
name=f"{par.name}_phase_{sg_clean}",
fixed=False,
tag="lat",
)
for par in spacegroupparams.xyzpars:
- recipe.addVar(
+ recipe.add_variable(
par,
name=f"{par.name}_phase_{sg_clean}",
fixed=False,
@@ -397,9 +410,9 @@ def make_recipe_two_phase(cif_path1, cif_path2, dat_path):
atoms = generator.phase.getScatterers()
for atom in atoms:
if atom.element == "Cd":
- recipe.constrain(atom.Uiso, cd_uiso)
+ recipe.add_constraint(atom.Uiso, cd_uiso)
elif atom.element == "Se":
- recipe.constrain(atom.Uiso, se_uiso)
+ recipe.add_constraint(atom.Uiso, se_uiso)
# 48: Return the Fit Recipe object to be optimized
return recipe
@@ -407,94 +420,6 @@ def make_recipe_two_phase(cif_path1, cif_path2, dat_path):
# End of function
-# We create a useful function 'plot_results' for writing a plot of the fit
-# to disk.
-def plot_results(recipe, fig_name):
- """Creates plots of the fitted PDF and residual, and writes them to
- disk as *.pdf files.
-
- Parameters
- ----------
- recipe : The optimized Fit Recipe object containing the PDF data
- we wish to plot.
- fig_name : Path object, the full path to the figure file to create..
-
- Returns
- ----------
- None
- """
- if not isinstance(fig_name, Path):
- fig_name = Path(fig_name)
-
- plt.clf()
- plt.close("all")
-
- # Get an array of the r-values we fitted over.
- r = recipe.crystal.profile.x
-
- # Get an array of the observed PDF.
- g = recipe.crystal.profile.y
-
- # Get an array of the calculated PDF.
- gcalc = recipe.crystal.profile.ycalc
-
- # Make an array of identical shape as g which is offset from g.
- diffzero = -0.65 * max(g) * np.ones_like(g)
-
- # Calculate the residual (difference) array and offset it vertically.
- diff = g - gcalc + diffzero
-
- # Create a figure and an axis on which to plot
- fig, ax1 = plt.subplots(1, 1)
-
- # Plot the difference offset line
- ax1.plot(r, diffzero, lw=1.0, ls="--", c="black")
-
- # Plot the measured data
- ax1.plot(
- r,
- g,
- ls="None",
- marker="o",
- ms=5,
- mew=0.2,
- mfc="None",
- label="G(r) Data",
- )
-
- # Plot the calculated data
- ax1.plot(r, gcalc, lw=1.3, label="G(r) Fit")
-
- # Plot the difference
- ax1.plot(r, diff, lw=1.2, label="G(r) diff")
-
- # Let's label the axes!
- ax1.set_xlabel(r"r ($\mathrm{\AA}$)")
- ax1.set_ylabel(r"G ($\mathrm{\AA}$$^{-2}$)")
-
- # Tune the tick markers. We are picky!
- ax1.tick_params(axis="both", which="major", top=True, right=True)
-
- # Set the boundaries on the x-axis
- ax1.set_xlim(r[0], r[-1])
-
- # We definitely want a legend!
- ax1.legend()
-
- # Let's use a tight layout. Shun wasted space!
- plt.tight_layout()
-
- # This is going to make a figure pop up on screen for you to view.
- # The script will pause until you close the figure!
- if SHOW_PLOT:
- plt.show()
-
- # Let's save the figure!
- fig.savefig(fig_name.parent / f"{fig_name.name}.pdf", format="pdf")
-
- # End of function
-
-
# 49: We again create a 'main' function to be run when we execute the script.
def main():
"""This will run by default when the file is executed using "python
@@ -508,7 +433,6 @@ def main():
----------
None
"""
-
# Make some folders to store our output files.
resdir = PWD / "res"
fitdir = PWD / "fit"
@@ -570,14 +494,20 @@ def main():
# 58: Print the fit results to the terminal.
res = FitResults(recipe)
- res.printResults()
+ res.print_results()
# 59: Write the fit results to a file.
header = "crystal_HF.\n"
- res.saveResults(resdir / f"{basename}.res", header=header)
+ res.save_results(resdir / f"{basename}.res", header=header)
# 60: Write a plot of the fit to a (pdf) file.
- plot_results(recipe, figdir / basename)
+ fig, ax1 = recipe.plot_recipe(
+ return_fig=True,
+ show=SHOW_PLOT,
+ xlabel=r"r ($\mathrm{\AA}$)",
+ ylabel=r"G ($\mathrm{\AA}$$^{-2}$)",
+ )
+ fig.savefig(figdir / f"{basename}.pdf", format="pdf")
# 61: Now we loop on every structure file we found as well as
# the identifying string we parsed from each file name.
@@ -616,7 +546,7 @@ def main():
recipe.fix("all")
recipe.free("adp")
if (
- np.all(["iso" in par for par in recipe.getNames()])
+ np.all(["iso" in par for par in recipe.get_names()])
and adp_symm == "anisotropic"
):
continue
@@ -641,14 +571,20 @@ def main():
# 68: Print the fit results to the terminal.
res = FitResults(recipe)
- res.printResults()
+ res.print_results()
# 69: Write the fit results to a file.
header = "crystal_HF.\n"
- res.saveResults(resdir / f"{basename}.res", header=header)
+ res.save_results(resdir / f"{basename}.res", header=header)
# 70: Write a plot of the fit to a (pdf) file.
- plot_results(recipe, figdir / basename)
+ fig, ax1 = recipe.plot_recipe(
+ return_fig=True,
+ show=SHOW_PLOT,
+ xlabel=r"r ($\mathrm{\AA}$)",
+ ylabel=r"G ($\mathrm{\AA}$$^{-2}$)",
+ )
+ fig.savefig(figdir / f"{basename}.pdf", format="pdf")
# End of function
diff --git a/docs/examples/pdf/ch11ClusterXYZ/solutions/diffpy-cmi/fitCdSeNP.py b/docs/examples/pdf/ch11ClusterXYZ/solutions/diffpy-cmi/fitCdSeNP.py
index 98fdae0..d541418 100644
--- a/docs/examples/pdf/ch11ClusterXYZ/solutions/diffpy-cmi/fitCdSeNP.py
+++ b/docs/examples/pdf/ch11ClusterXYZ/solutions/diffpy-cmi/fitCdSeNP.py
@@ -8,8 +8,6 @@
# 1: Import packages that we will need
from pathlib import Path
-import matplotlib as mpl
-import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import least_squares
@@ -79,16 +77,15 @@ def make_recipe(stru_path, dat_path):
fitrecipe : The initialized Fit Recipe object using the datname and
structure provided.
"""
-
stru1 = Structure(filename=str(stru_path))
# 9: Create a Profile object for the experimental dataset and
# tell this profile the range and mesh of points in r-space.
profile = Profile()
parser = PDFParser()
- parser.parseFile(dat_path)
- profile.loadParsedData(parser)
- profile.setCalculationRange(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)
+ parser.parse_file(dat_path)
+ profile.load_parsed_data(parser)
+ profile.set_calculation_range(xmin=PDF_RMIN, xmax=PDF_RMAX, dx=PDF_RSTEP)
# 10: Create a Debye PDF Generator object for the discrete structure model.
generator_cluster1 = DebyePDFGenerator("G1")
@@ -96,7 +93,7 @@ def make_recipe(stru_path, dat_path):
# 11: Create a Fit Contribution object.
contribution = FitContribution("cluster")
- contribution.addProfileGenerator(generator_cluster1)
+ contribution.add_profile_generator(generator_cluster1)
# If you have a multi-core computer (you probably do),
# run your refinement in parallel!
@@ -119,14 +116,14 @@ def make_recipe(stru_path, dat_path):
pool = Pool(processes=ncpu)
generator_cluster1.parallel(ncpu=ncpu, mapfunc=pool.map)
# 12: Set the Fit Contribution profile to the Profile object.
- contribution.setProfile(profile, xname="r")
+ contribution.set_profile(profile, xname="r")
# 13: Set an equation, based on your PDF generators.
- contribution.setEquation("s1*G1")
+ contribution.set_equation("s1*G1")
# 14: Create the Fit Recipe object that holds all the details of the fit.
recipe = FitRecipe()
- recipe.addContribution(contribution)
+ recipe.add_contribution(contribution)
# 15: Initialize the instrument parameters, Q_damp and Q_broad, and
# assign Q_max and Q_min.
@@ -137,7 +134,7 @@ def make_recipe(stru_path, dat_path):
# 16: Add, initialize, and tag variables in the Fit Recipe object.
# In this case we also add psize, which is the NP size.
- recipe.addVar(contribution.s1, SCALE_I, tag="scale")
+ recipe.add_variable(contribution.s1, SCALE_I, tag="scale")
# 17: Define a phase and lattice from the Debye PDF Generator
# object and assign an isotropic lattice expansion factor tagged
@@ -147,28 +144,28 @@ def make_recipe(stru_path, dat_path):
lattice1 = phase_cluster1.getLattice()
- recipe.newVar("zoomscale", ZOOMSCALE_I, tag="lat")
+ recipe.create_new_variable("zoomscale", ZOOMSCALE_I, tag="lat")
- recipe.constrain(lattice1.a, "zoomscale")
- recipe.constrain(lattice1.b, "zoomscale")
- recipe.constrain(lattice1.c, "zoomscale")
+ recipe.add_constraint(lattice1.a, "zoomscale")
+ recipe.add_constraint(lattice1.b, "zoomscale")
+ recipe.add_constraint(lattice1.c, "zoomscale")
# 18: Initialize an atoms object and constrain the isotropic
# Atomic Displacement Parameters (ADPs) per element.
atoms1 = phase_cluster1.getScatterers()
- recipe.newVar("Cd_Uiso", UISO_Cd_I, tag="adp")
- recipe.newVar("Se_Uiso", UISO_Se_I, tag="adp")
+ recipe.create_new_variable("Cd_Uiso", UISO_Cd_I, tag="adp")
+ recipe.create_new_variable("Se_Uiso", UISO_Se_I, tag="adp")
for atom in atoms1:
if atom.element.title() == "Cd":
- recipe.constrain(atom.Uiso, "Cd_Uiso")
+ recipe.add_constraint(atom.Uiso, "Cd_Uiso")
elif atom.element.title() == "Se":
- recipe.constrain(atom.Uiso, "Se_Uiso")
+ recipe.add_constraint(atom.Uiso, "Se_Uiso")
# 19: Add and tag a variable for correlated motion effects
- recipe.addVar(
+ recipe.add_variable(
generator_cluster1.delta2, name="CdSe_Delta2", value=DELTA2_I, tag="d2"
)
@@ -177,60 +174,6 @@ def make_recipe(stru_path, dat_path):
# End of function
-def plot_results(recipe, figname):
- """Creates plots of the fitted PDF and residual, and writes them to
- disk as *.pdf files.
-
- Parameters
- ----------
- recipe : The optimized Fit Recipe object containing the PDF data
- we wish to plot
- figname : string, the location and name of the figure file to create
-
- Returns
- ----------
- None
- """
- r = recipe.cluster.profile.x
-
- g = recipe.cluster.profile.y
- gcalc = recipe.cluster.profile.ycalc
- diffzero = -0.65 * max(g) * np.ones_like(g)
- diff = g - gcalc + diffzero
-
- mpl.rcParams.update(mpl.rcParamsDefault)
-
- fig, ax1 = plt.subplots(1, 1)
-
- ax1.plot(
- r,
- g,
- ls="None",
- marker="o",
- ms=5,
- mew=0.2,
- mfc="None",
- label="G(r) Data",
- )
-
- ax1.plot(r, gcalc, lw=1.3, label="G(r) Fit")
- ax1.plot(r, diff, lw=1.2, label="G(r) diff")
- ax1.plot(r, diffzero, lw=1.0, ls="--", c="black")
-
- ax1.set_xlabel(r"r($\mathrm{\AA}$)")
- ax1.set_ylabel(r"G($\mathrm{\AA}$$^{-2}$)")
- ax1.tick_params(axis="both", which="major", top=True, right=True)
-
- ax1.set_xlim(r[0], r[-1])
- ax1.legend()
-
- plt.tight_layout()
- plt.show()
- fig.savefig(figname.parent / f"{figname.name}.pdf", format="pdf")
-
- # End of function
-
-
def main():
"""This will run by default when the file is executed using "python
file.py" in the command line.
@@ -243,7 +186,6 @@ def main():
----------
None
"""
-
# Make some folders to store our output files.
resdir = PWD / "res"
fitdir = PWD / "fit"
@@ -283,14 +225,19 @@ def main():
# Print the fit results to the terminal.
res = FitResults(recipe)
- res.printResults()
+ res.print_results()
# Write the fit results to a file.
header = "crystal_HF.\n"
- res.saveResults(resdir / f"{basename}.res", header=header)
+ res.save_results(resdir / f"{basename}.res", header=header)
# Write a plot of the fit to a (pdf) file.
- plot_results(recipe, figdir / basename)
+ fig, ax1 = recipe.plot_recipe(
+ return_fig=True,
+ xlabel=r"r($\mathrm{\AA}$)",
+ ylabel=r"G($\mathrm{\AA}$$^{-2}$)",
+ )
+ fig.savefig(figdir / f"{basename}.pdf", format="pdf")
# End of function
diff --git a/docs/examples/pdf/nanoparticle-fit/coreshellnp.py b/docs/examples/pdf/nanoparticle-fit/coreshellnp.py
index 64da70a..92b6f9b 100644
--- a/docs/examples/pdf/nanoparticle-fit/coreshellnp.py
+++ b/docs/examples/pdf/nanoparticle-fit/coreshellnp.py
@@ -22,11 +22,9 @@
from pathlib import Path
-import matplotlib.pyplot as plt
from pyobjcryst import loadCrystal
from scipy.optimize import leastsq
-from diffpy.cmi.fit_tools import plot_results
from diffpy.srfit.fitbase import (
FitContribution,
FitRecipe,
@@ -40,15 +38,14 @@
def make_recipe(stru1, stru2, datname):
"""Create a fitting recipe for crystalline PDF data."""
-
# The Profile
profile = Profile()
# Load data and add it to the profile
parser = PDFParser()
- parser.parseFile(datname)
- profile.loadParsedData(parser)
- profile.setCalculationRange(xmin=1.5, xmax=45, dx=0.1)
+ parser.parse_file(datname)
+ profile.load_parsed_data(parser)
+ profile.set_calculation_range(xmin=1.5, xmax=45, dx=0.1)
# The ProfileGenerator
# In order to fit the core and shell phases simultaneously, we must use two
@@ -69,66 +66,73 @@ def make_recipe(stru1, stru2, datname):
# The FitContribution
# Add both generators and the profile to the FitContribution.
contribution = FitContribution("cdszns")
- contribution.addProfileGenerator(generator_cds)
- contribution.addProfileGenerator(generator_zns)
- contribution.setProfile(profile, xname="r")
+ contribution.add_profile_generator(generator_cds)
+ contribution.add_profile_generator(generator_zns)
+ contribution.set_profile(profile, xname="r")
# Set up the characteristic functions. We use a spherical CF for the core
# and a spherical shell CF for the shell. Since this is set up as two
# phases, we implicitly assume that the core-shell correlations contribute
# very little to the PDF.
- from diffpy.srfit.pdf.characteristicfunctions import shellCF, sphericalCF
+ from diffpy.srfit.pdf.characteristicfunctions import (
+ shell_particle,
+ spherical_particle,
+ )
- contribution.registerFunction(sphericalCF, name="f_CdS")
- contribution.registerFunction(shellCF, name="f_ZnS")
+ contribution.register_function(spherical_particle, name="f_CdS")
+ contribution.register_function(shell_particle, name="f_ZnS")
# Write the fitting equation. We want to sum the PDFs from each phase and
# multiply it by a scaling factor.
- contribution.setEquation("scale * (f_CdS * G_CdS + f_ZnS * G_ZnS)")
+ contribution.set_equation("scale * (f_CdS * G_CdS + f_ZnS * G_ZnS)")
# Make the FitRecipe and add the FitContribution.
recipe = FitRecipe()
- recipe.addContribution(contribution)
+ recipe.add_contribution(contribution)
# Vary the inner radius and thickness of the shell. Constrain the core
# diameter to twice the shell radius.
- recipe.addVar(contribution.radius, 15)
- recipe.addVar(contribution.thickness, 11)
- recipe.constrain(contribution.psize, "2 * radius")
+ recipe.add_variable(contribution.radius, 15)
+ recipe.add_variable(contribution.thickness, 11)
+ recipe.add_constraint(contribution.psize, "2 * radius")
# Configure the fit variables
# Start by configuring the scale factor and resolution factors.
# We want the sum of the phase scale factors to be 1.
- recipe.newVar("scale_CdS", 0.7)
- recipe.constrain(generator_cds.scale, "scale_CdS")
- recipe.constrain(generator_zns.scale, "1 - scale_CdS")
+ recipe.create_new_variable("scale_CdS", 0.7)
+ recipe.add_constraint(generator_cds.scale, "scale_CdS")
+ recipe.add_constraint(generator_zns.scale, "1 - scale_CdS")
# We also want the resolution factor to be the same on each.
# Vary the global scale as well.
- recipe.addVar(contribution.scale, 0.3)
+ recipe.add_variable(contribution.scale, 0.3)
# Now we can configure the structural parameters. We tag the different
# structural variables so we can easily turn them on and off in the
# subsequent refinement.
phase_cds = generator_cds.phase
for par in phase_cds.sgpars.latpars:
- recipe.addVar(par, name=par.name + "_cds", tag="lat")
+ recipe.add_variable(par, name=par.name + "_cds", tag="lat")
for par in phase_cds.sgpars.adppars:
- recipe.addVar(par, 1, name=par.name + "_cds", tag="adp")
- recipe.addVar(phase_cds.sgpars.xyzpars.z_1, name="z_1_cds", tag="xyz")
+ recipe.add_variable(par, 1, name=par.name + "_cds", tag="adp")
+ recipe.add_variable(
+ phase_cds.sgpars.xyzpars.z_1, name="z_1_cds", tag="xyz"
+ )
# Since we know these have stacking disorder, constrain the B33 adps for
# each atom type.
- recipe.constrain("B33_1_cds", "B33_0_cds")
- recipe.addVar(generator_cds.delta2, name="delta2_cds", value=5)
+ recipe.add_constraint("B33_1_cds", "B33_0_cds")
+ recipe.add_variable(generator_cds.delta2, name="delta2_cds", value=5)
phase_zns = generator_zns.phase
for par in phase_zns.sgpars.latpars:
- recipe.addVar(par, name=par.name + "_zns", tag="lat")
+ recipe.add_variable(par, name=par.name + "_zns", tag="lat")
for par in phase_zns.sgpars.adppars:
- recipe.addVar(par, 1, name=par.name + "_zns", tag="adp")
- recipe.addVar(phase_zns.sgpars.xyzpars.z_1, name="z_1_zns", tag="xyz")
- recipe.constrain("B33_1_zns", "B33_0_zns")
- recipe.addVar(generator_zns.delta2, name="delta2_zns", value=2.5)
+ recipe.add_variable(par, 1, name=par.name + "_zns", tag="adp")
+ recipe.add_variable(
+ phase_zns.sgpars.xyzpars.z_1, name="z_1_zns", tag="xyz"
+ )
+ recipe.add_constraint("B33_1_zns", "B33_0_zns")
+ recipe.add_variable(generator_zns.delta2, name="delta2_zns", value=2.5)
# Give the recipe away so it can be used!
return recipe
@@ -136,7 +140,6 @@ def make_recipe(stru1, stru2, datname):
def main():
"""Set up and refine the recipe."""
-
# Make the data and the recipe
base_path = Path(__file__).parent
cdsciffile = base_path / "CdS.cif"
@@ -179,14 +182,10 @@ def main():
# Generate and print the FitResults
res = FitResults(recipe)
- res.printResults()
+ res.print_results()
# Plot!
- r = recipe.cdszns.profile.x
- g = recipe.cdszns.profile.y
- gcalc = recipe.cdszns.profile.ycalc
- plot_results(r, g, gcalc)
- plt.show()
+ recipe.plot_recipe(xlabel=r"$r (\AA)$", ylabel=r"$G (\AA^{-2})$")
return
diff --git a/docs/source/tutorials/pdf.rst b/docs/source/tutorials/pdf.rst
index 52ad280..a8a0c8c 100644
--- a/docs/source/tutorials/pdf.rst
+++ b/docs/source/tutorials/pdf.rst
@@ -79,7 +79,7 @@ to fit the same Ni PDF with PDFgui.
from diffpy.srfit.fitbase import FitContribution, FitRecipe
from diffpy.srfit.fitbase import Profile
from diffpy.srfit.pdf import PDFParser, PDFGenerator
- from diffpy.structure.parsers import getParser
+ from diffpy.structure.parsers import get_parser
from diffpy.srfit.structure import constrainAsSpaceGroup
2. As a sanity check, lets load the cif and PDF data to see what they look like.
@@ -146,7 +146,7 @@ to fit the same Ni PDF with PDFgui.
def make_recipe(cif_path, dat_path):
# 1. Get structural info
- p_cif = getParser('cif') # Get the parser for CIF files
+ p_cif = get_parser('cif') # Get the parser for CIF files
stru = p_cif.parseFile(cif_path) # Using the parser, load the structure from the CIF
sg = p_cif.spacegroup.short_name # Get the space group to constrain the fit later on
diff --git a/news/update-dep-funcs.rst b/news/update-dep-funcs.rst
new file mode 100644
index 0000000..ba631b7
--- /dev/null
+++ b/news/update-dep-funcs.rst
@@ -0,0 +1,23 @@
+**Added:**
+
+* Update function names in examples to remove deprecated functions.
+
+**Changed:**
+
+*
+
+**Deprecated:**
+
+*
+
+**Removed:**
+
+*
+
+**Fixed:**
+
+*
+
+**Security:**
+
+*
diff --git a/requirements/packs/scripts/tar_url.txt b/requirements/packs/scripts/tar_url.txt
index 9317043..35d298f 100644
--- a/requirements/packs/scripts/tar_url.txt
+++ b/requirements/packs/scripts/tar_url.txt
@@ -1,5 +1,5 @@
https://github.com/diffpy/diffpy.srreal/archive/refs/tags/1.4.0.tar.gz
-https://github.com/diffpy/diffpy.srfit/archive/refs/tags/3.2.0.tar.gz
+https://github.com/diffpy/diffpy.srfit/archive/refs/tags/3.3.0.tar.gz
https://github.com/diffpy/pyobjcryst/archive/refs/tags/2025.1.0.tar.gz
-https://github.com/diffpy/diffpy.structure/archive/refs/tags/3.3.1.tar.gz
-https://github.com/diffpy/diffpy.utils/archive/refs/tags/3.7.1.tar.gz
+https://github.com/diffpy/diffpy.structure/archive/refs/tags/3.4.0.tar.gz
+https://github.com/diffpy/diffpy.utils/archive/refs/tags/3.7.2.tar.gz
diff --git a/src/diffpy/cmi/__init__.py b/src/diffpy/cmi/__init__.py
index e2392e6..51debbf 100644
--- a/src/diffpy/cmi/__init__.py
+++ b/src/diffpy/cmi/__init__.py
@@ -15,7 +15,6 @@
"""Complex modeling infrastructure:
a modular framework for multi-modal modeling of scientific data."""
-
__all__ = [
"__version__",
]
diff --git a/src/diffpy/cmi/cli.py b/src/diffpy/cmi/cli.py
index 1b3eb90..113636a 100644
--- a/src/diffpy/cmi/cli.py
+++ b/src/diffpy/cmi/cli.py
@@ -52,22 +52,21 @@ def _build_parser() -> argparse.ArgumentParser:
p = argparse.ArgumentParser(
prog="cmi",
description=(
- """\
-Welcome to diffpy.cmi, a complex modeling infrastructure for
-multi-modal analysis of scientific data.
-
-Diffpy.cmi is designed as an extensible complex modeling
-infrastructure. Users and developers can readily integrate
-novel data types and constraints into custom workflows. While
-widely used for advanced analysis of structural data, the
-framework is general and can be applied to any problem where
-model parameters are refined to fit calculated quantities to
-data.
-
-Diffpy.cmi is comprised of modular units called 'packs' and
-'profiles' that facilitate tailored installations for specific
-scientific applications. Run 'cmi info -h' for more details.
-"""
+ "\nWelcome to diffpy.cmi, a complex modeling "
+ "infrastructure for multi-modal analysis of "
+ "scientific data. "
+ "Diffpy.cmi is designed as an extensible complex "
+ "modeling infrastructure. Users and developers can "
+ "readily integrate novel data types and constraints "
+ "into custom workflows. While widely used for "
+ "advanced analysis of structural data, the framework "
+ "is general and can be applied to any problem where "
+ "model parameters are refined to fit calculated "
+ "quantities to data. "
+ "Diffpy.cmi is comprised of modular units called "
+ "'packs' and 'profiles' that facilitate tailored "
+ "installations for specific scientific applications. "
+ "Run 'cmi info -h' for more details."
),
formatter_class=argparse.RawDescriptionHelpFormatter,
)
@@ -92,19 +91,24 @@ def _build_parser() -> argparse.ArgumentParser:
"info",
help=("Prints info about packs, profiles, and examples.\n "),
description=(
- """
-Definitions:
-pack: A collection of data processing routines, models, and examples.
- For example, the 'pdf' pack contains packages used for modeling
- and refinement of the Atomic Pair Distribution Function (PDF).
-
-profile: A set of pre-defined packs or configurations for a specific
- scientific workflow. Profiles can be installed or customized
- for different use cases.
-
-examples: Example scripts or folders that can be copied locally using
- 'cmi copy '.
- """
+ "\n"
+ "Definitions:\n"
+ "pack: A collection of data processing routines, models, "
+ "and examples.\n"
+ " For example, the 'pdf' pack contains packages used "
+ "for modeling\n"
+ " and refinement of the Atomic Pair Distribution "
+ "Function (PDF).\n"
+ "\n"
+ "profile: A set of pre-defined packs or configurations for a "
+ "specific\n"
+ " scientific workflow. Profiles can be installed or "
+ "customized\n"
+ " for different use cases.\n"
+ "\n"
+ "examples: Example scripts or folders that can be copied "
+ "locally using\n"
+ " 'cmi copy '.\n"
),
formatter_class=argparse.RawDescriptionHelpFormatter,
)
diff --git a/src/diffpy/cmi/fit_tools.py b/src/diffpy/cmi/fit_tools.py
index ff8920d..ab2fb00 100644
--- a/src/diffpy/cmi/fit_tools.py
+++ b/src/diffpy/cmi/fit_tools.py
@@ -37,7 +37,7 @@ def optimize_recipe(recipe, optimizer: str = "leastsq", **kwargs):
)
function = optimizers[optimizer]
- x0 = recipe.getValues()
+ x0 = recipe.get_values()
residuals = recipe.residual
if optimizer == "leastsq":
print("Optimizing using scipy.optimize.leastsq")