diff --git a/doc/examples/crystalpdf.py b/doc/examples/crystalpdf.py index 0d668da5..41dbca6d 100644 --- a/doc/examples/crystalpdf.py +++ b/doc/examples/crystalpdf.py @@ -36,13 +36,14 @@ from diffpy.srfit.pdf import PDFGenerator, PDFParser from diffpy.structure import Structure -####### Example Code +###### +# Example Code def makeRecipe(ciffile, datname): """Create a fitting recipe for crystalline PDF data.""" - ## The Profile + # The Profile # This will be used to store the observed and calculated PDF profile. profile = Profile() @@ -57,7 +58,7 @@ def makeRecipe(ciffile, datname): profile.loadParsedData(parser) profile.setCalculationRange(xmax=20) - ## The ProfileGenerator + # The ProfileGenerator # The PDFGenerator is for configuring and calculating a PDF profile. Here, # we want to refine a Structure object from diffpy.structure. We tell the # PDFGenerator that with the 'setStructure' method. All other configuration @@ -69,18 +70,18 @@ def makeRecipe(ciffile, datname): stru.read(ciffile) generator.setStructure(stru) - ## The FitContribution + # The FitContribution # Here we associate the Profile and ProfileGenerator, as has been done # before. contribution = FitContribution("nickel") contribution.addProfileGenerator(generator) contribution.setProfile(profile, xname="r") - ## Make the FitRecipe and add the FitContribution. + # Make the FitRecipe and add the FitContribution. recipe = FitRecipe() recipe.addContribution(contribution) - ## Configure the fit variables + # Configure the fit variables # The PDFGenerator class holds the ParameterSet associated with the # Structure passed above in a data member named "phase". (We could have diff --git a/doc/examples/crystalpdfall.py b/doc/examples/crystalpdfall.py index 918b7a9d..056f8a80 100644 --- a/doc/examples/crystalpdfall.py +++ b/doc/examples/crystalpdfall.py @@ -30,7 +30,8 @@ ) from diffpy.srfit.pdf import PDFGenerator, PDFParser -####### Example Code +###### +# Example Code def makeProfile(datafile): @@ -56,14 +57,14 @@ def makeRecipe( ): """Create a fitting recipe for crystalline PDF data.""" - ## The Profiles + # The Profiles # We need a profile for each data set. xprofile_ni = makeProfile(xdata_ni) xprofile_si = makeProfile(xdata_si) nprofile_ni = makeProfile(ndata_ni) xprofile_sini = makeProfile(xdata_sini) - ## The ProfileGenerators + # The ProfileGenerators # We create one for each phase and share the phases. xgenerator_ni = PDFGenerator("xG_ni") stru = loadCrystal(ciffile_ni) @@ -84,7 +85,7 @@ def makeRecipe( xgenerator_sini_si = PDFGenerator("xG_sini_si") xgenerator_sini_si.setPhase(phase_si) - ## The FitContributions + # The FitContributions # We one of these for each data set. xcontribution_ni = makeContribution("xnickel", xgenerator_ni, xprofile_ni) xcontribution_si = makeContribution("xsilicon", xgenerator_si, xprofile_si) diff --git a/doc/examples/crystalpdfobjcryst.py b/doc/examples/crystalpdfobjcryst.py index 48f94e0e..49195434 100644 --- a/doc/examples/crystalpdfobjcryst.py +++ b/doc/examples/crystalpdfobjcryst.py @@ -31,13 +31,14 @@ ) from diffpy.srfit.pdf import PDFGenerator, PDFParser -####### Example Code +###### +# Example Code def makeRecipe(ciffile, datname): """Create a fitting recipe for crystalline PDF data.""" - ## The Profile + # The Profile # This will be used to store the observed and calculated PDF profile. profile = Profile() @@ -50,7 +51,7 @@ def makeRecipe(ciffile, datname): profile.loadParsedData(parser) profile.setCalculationRange(xmax=20) - ## The ProfileGenerator + # The ProfileGenerator # This time we use the CreateCrystalFromCIF method of pyobjcryst.crystal to # create a Crystal object. That object is passed to the PDFGenerator as in # the previous example. @@ -59,7 +60,7 @@ def makeRecipe(ciffile, datname): generator.setStructure(stru) generator.setQmax(40.0) - ## The FitContribution + # The FitContribution contribution = FitContribution("nickel") contribution.addProfileGenerator(generator) contribution.setProfile(profile, xname="r") @@ -68,7 +69,7 @@ def makeRecipe(ciffile, datname): recipe = FitRecipe() recipe.addContribution(contribution) - ## Configure the fit variables + # Configure the fit variables # As before, we get a handle to the structure parameter set. In this case, # it is a ObjCrystCrystalParSet instance that was created when we called diff --git a/doc/examples/crystalpdftwodata.py b/doc/examples/crystalpdftwodata.py index cd2aa0c6..debefc0f 100644 --- a/doc/examples/crystalpdftwodata.py +++ b/doc/examples/crystalpdftwodata.py @@ -32,13 +32,14 @@ ) from diffpy.srfit.pdf import PDFGenerator, PDFParser -####### Example Code +###### +# Example Code def makeRecipe(ciffile, xdatname, ndatname): """Create a fitting recipe for crystalline PDF data.""" - ## The Profiles + # The Profiles # We need a profile for each data set. This means that we will need two # FitContributions as well. xprofile = Profile() @@ -55,7 +56,7 @@ def makeRecipe(ciffile, xdatname, ndatname): nprofile.loadParsedData(parser) nprofile.setCalculationRange(xmax=20) - ## The ProfileGenerators + # The ProfileGenerators # We need one of these for the x-ray data. xgenerator = PDFGenerator("G") stru = loadCrystal(ciffile) @@ -80,7 +81,7 @@ def makeRecipe(ciffile, xdatname, ndatname): ngenerator = PDFGenerator("G") ngenerator.setPhase(xgenerator.phase) - ## The FitContributions + # The FitContributions # We associate the x-ray PDFGenerator and Profile in one FitContribution... xcontribution = FitContribution("xnickel") xcontribution.addProfileGenerator(xgenerator) diff --git a/doc/examples/crystalpdftwophase.py b/doc/examples/crystalpdftwophase.py index b0fcf30d..98a87905 100644 --- a/doc/examples/crystalpdftwophase.py +++ b/doc/examples/crystalpdftwophase.py @@ -32,13 +32,14 @@ ) from diffpy.srfit.pdf import PDFGenerator, PDFParser -####### Example Code +###### +# Example Code def makeRecipe(niciffile, siciffile, datname): """Create a fitting recipe for crystalline PDF data.""" - ## The Profile + # The Profile profile = Profile() # Load data and add it to the profile @@ -47,7 +48,7 @@ def makeRecipe(niciffile, siciffile, datname): profile.loadParsedData(parser) profile.setCalculationRange(xmax=20) - ## The ProfileGenerator + # The ProfileGenerator # In order to fit two phases simultaneously, we must use two PDFGenerators. # PDFGenerator is designed to take care of as little information as it # must. (Don't do too much, and do it well.) A PDFGenerator can generate @@ -67,7 +68,7 @@ def makeRecipe(niciffile, siciffile, datname): stru = loadCrystal(siciffile) generator_si.setStructure(stru) - ## The FitContribution + # The FitContribution # Add both generators to the FitContribution. Add the Profile. This will # send the metadata to the generators. contribution = FitContribution("nisi") @@ -85,7 +86,7 @@ def makeRecipe(niciffile, siciffile, datname): recipe = FitRecipe() recipe.addContribution(contribution) - ## Configure the fit variables + # 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_ni", 0.1) diff --git a/doc/examples/debyemodel.py b/doc/examples/debyemodel.py index 0ec673a7..e3b6c212 100644 --- a/doc/examples/debyemodel.py +++ b/doc/examples/debyemodel.py @@ -57,7 +57,8 @@ 500.0 0.03946 0.00250 """ -####### Example Code +###### +# Example Code def makeRecipe(): @@ -84,7 +85,7 @@ def makeRecipe(): won't do that here. """ - ## The Profile + # The Profile # Create a Profile to hold the experimental and calculated signal. profile = Profile() @@ -94,7 +95,7 @@ def makeRecipe(): x, y, dy = numpy.hsplit(xydy, 3) profile.setObservedProfile(x, y, dy) - ## The FitContribution + # The FitContribution # The FitContribution associates the profile with the Debye function. contribution = FitContribution("pb") # Tell the contribution about the Profile. We will need to use the @@ -127,7 +128,7 @@ def makeRecipe(): # can specify that as well. contribution.setEquation("debye(T, 207.2, abs(thetaD)) + offset") - ## The FitRecipe + # The FitRecipe # The FitRecipe lets us define what we want to fit. It is where we can # create variables, constraints and restraints. If we had multiple profiles # to fit simultaneously, the contribution from each could be added to the diff --git a/doc/examples/debyemodelII.py b/doc/examples/debyemodelII.py index 6ff8d1e6..9872f71d 100644 --- a/doc/examples/debyemodelII.py +++ b/doc/examples/debyemodelII.py @@ -37,7 +37,8 @@ from diffpy.srfit.fitbase import FitRecipe, FitResults -####### Example Code +###### +# Example Code def makeRecipeII(): diff --git a/doc/examples/ellipsoidsas.py b/doc/examples/ellipsoidsas.py index b3e8d18e..23ee5f08 100644 --- a/doc/examples/ellipsoidsas.py +++ b/doc/examples/ellipsoidsas.py @@ -24,13 +24,14 @@ ) from diffpy.srfit.sas import SASGenerator, SASParser -####### Example Code +###### +# Example Code def makeRecipe(datname): """Create a fitting recipe for ellipsoidal SAS data.""" - ## The Profile + # The Profile # This will be used to store the observed and calculated I(Q) data. profile = Profile() @@ -40,7 +41,7 @@ def makeRecipe(datname): parser.parseFile(datname) profile.loadParsedData(parser) - ## The ProfileGenerator + # The ProfileGenerator # The SASGenerator is for configuring and calculating a SAS profile. We use # a sas model to configure and serve as the calculation engine of the # generator. This allows us to use the full sas model creation @@ -52,7 +53,7 @@ def makeRecipe(datname): model = EllipsoidModel() generator = SASGenerator("generator", model) - ## The FitContribution + # The FitContribution # Here we associate the Profile and ProfileGenerator, as has been done # before. contribution = FitContribution("ellipsoid") @@ -65,11 +66,11 @@ def makeRecipe(datname): # will have on the estimated parameter uncertainties. contribution.setResidualEquation("log(eq) - log(y)") - ## Make the FitRecipe and add the FitContribution. + # Make the FitRecipe and add the FitContribution. recipe = FitRecipe() recipe.addContribution(contribution) - ## Configure the fit variables + # Configure the fit variables # The SASGenerator uses the parameters from the params and dispersion # attributes of the model. These vary from model to model, but are adopted # as SrFit Parameters within the generator. Whereas the dispersion diff --git a/doc/examples/gaussiangenerator.py b/doc/examples/gaussiangenerator.py index 6df50694..fedff5a5 100644 --- a/doc/examples/gaussiangenerator.py +++ b/doc/examples/gaussiangenerator.py @@ -47,7 +47,8 @@ ProfileGenerator, ) -####### Example Code +###### +# Example Code class GaussianGenerator(ProfileGenerator): @@ -124,7 +125,7 @@ def makeRecipe(): associate this with a Profile, and use this to define a FitRecipe. """ - ## The Profile + # The Profile # Create a Profile to hold the experimental and calculated signal. profile = Profile() @@ -132,12 +133,12 @@ def makeRecipe(): # numpy. profile.loadtxt("data/gaussian.dat") - ## The ProfileGenerator + # The ProfileGenerator # Create a GaussianGenerator named "g". This will be the name we use to # refer to the generator from within the FitContribution equation. generator = GaussianGenerator("g") - ## The FitContribution + # The FitContribution # Create a FitContribution that will associate the Profile with the # GaussianGenerator. The GaussianGenerator will be accessible as an # attribute of the FitContribution by its name ("g"). Note that this will @@ -146,7 +147,7 @@ def makeRecipe(): contribution.addProfileGenerator(generator) contribution.setProfile(profile) - ## The FitRecipe + # The FitRecipe # Now we create the FitRecipe and add the FitContribution. recipe = FitRecipe() recipe.addContribution(contribution) diff --git a/doc/examples/gaussianrecipe.py b/doc/examples/gaussianrecipe.py index 8f762ba7..646afc71 100644 --- a/doc/examples/gaussianrecipe.py +++ b/doc/examples/gaussianrecipe.py @@ -52,7 +52,8 @@ Profile, ) -####### Example Code +###### +# Example Code def main(): @@ -95,7 +96,7 @@ def makeRecipe(): optimized. See the 'scipyOptimize' function. """ - ## The Profile + # The Profile # Create a Profile to hold the experimental and calculated signal. profile = Profile() @@ -103,7 +104,7 @@ def makeRecipe(): # numpy. profile.loadtxt("data/gaussian.dat") - ## The FitContribution + # The FitContribution # The FitContribution associates the Profile with a fitting equation. The # FitContribution also stores the parameters of the fitting equation. We # give our FitContribution then name "g1". We will be able to access the @@ -131,7 +132,7 @@ def makeRecipe(): # attribute. Parameters also have a 'name' attribute. contribution.A.value = 1.0 - ## The FitRecipe + # The FitRecipe # The FitRecipe lets us define what we want to fit. It is where we can # create variables, constraints and restraints. recipe = FitRecipe() diff --git a/doc/examples/interface.py b/doc/examples/interface.py index 5b1a250e..ee70e699 100644 --- a/doc/examples/interface.py +++ b/doc/examples/interface.py @@ -25,7 +25,8 @@ Profile, ) -####### Example Code +###### +# Example Code def main(): diff --git a/doc/examples/npintensity.py b/doc/examples/npintensity.py index 64498fc6..210aa4c6 100644 --- a/doc/examples/npintensity.py +++ b/doc/examples/npintensity.py @@ -55,7 +55,8 @@ ) from diffpy.srfit.structure.diffpyparset import DiffpyStructureParSet -####### Example Code +###### +# Example Code class IntensityGenerator(ProfileGenerator): @@ -181,21 +182,21 @@ def makeRecipe(strufile, datname): associate this with a Profile, and use this to define a FitRecipe. """ - ## The Profile + # The Profile # Create a Profile. This will hold the experimental and calculated signal. profile = Profile() # Load data and add it to the profile x, y, u = profile.loadtxt(datname) - ## The ProfileGenerator + # The ProfileGenerator # Create an IntensityGenerator named "I". This will be the name we use to # 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) - ## The FitContribution + # The FitContribution # Create a FitContribution, that will associate the Profile with the # ProfileGenerator. The ProfileGenerator will be accessible as an # attribute of the FitContribution by its name ("I"). We also want to tell @@ -339,14 +340,14 @@ def plotResults(recipe): # All this should be pretty familiar by now. q = recipe.bucky.profile.x - I = recipe.bucky.profile.y + Imeas = recipe.bucky.profile.y Icalc = recipe.bucky.profile.ycalc bkgd = recipe.bucky.evaluateEquation("bkgd") - diff = I - Icalc + diff = Imeas - Icalc import pylab - pylab.plot(q, I, "ob", label="I(Q) Data") + 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") diff --git a/doc/examples/npintensityII.py b/doc/examples/npintensityII.py index e4607f90..45751d47 100644 --- a/doc/examples/npintensityII.py +++ b/doc/examples/npintensityII.py @@ -44,7 +44,8 @@ Profile, ) -####### Example Code +###### +# Example Code def makeRecipe(strufile, datname1, datname2): @@ -62,7 +63,7 @@ def makeRecipe(strufile, datname1, datname2): structure) in both generators. """ - ## The Profiles + # The Profiles # Create two Profiles for the two FitContributions. profile1 = Profile() profile2 = Profile() @@ -71,7 +72,7 @@ def makeRecipe(strufile, datname1, datname2): profile1.loadtxt(datname1) x, y, u = profile2.loadtxt(datname2) - ## The ProfileGenerators + # The ProfileGenerators # Create two IntensityGenerators named "I". There will not be a name # conflict, since the name is only meaningful within the FitContribution # that holds the ProfileGenerator. Load the structure into one and make @@ -84,7 +85,7 @@ def makeRecipe(strufile, datname1, datname2): generator2 = IntensityGenerator("I") generator2.addParameterSet(generator1.phase) - ## The FitContributions + # The FitContributions # Create the FitContributions. contribution1 = FitContribution("bucky1") contribution1.addProfileGenerator(generator1) diff --git a/doc/examples/nppdfobjcryst.py b/doc/examples/nppdfobjcryst.py index ad420944..a05dbaa8 100644 --- a/doc/examples/nppdfobjcryst.py +++ b/doc/examples/nppdfobjcryst.py @@ -28,20 +28,21 @@ ) from diffpy.srfit.pdf import DebyePDFGenerator -####### Example Code +###### +# Example Code def makeRecipe(molecule, datname): """Create a recipe that uses the DebyePDFGenerator.""" - ## The Profile + # The Profile profile = Profile() # Load data and add it to the profile profile.loadtxt(datname) profile.setCalculationRange(xmin=1.2, xmax=8) - ## The ProfileGenerator + # The ProfileGenerator # Create a DebyePDFGenerator named "G". generator = DebyePDFGenerator("G") generator.setStructure(molecule) @@ -49,7 +50,7 @@ def makeRecipe(molecule, datname): generator.setQmin(0.68) generator.setQmax(22) - ## The FitContribution + # The FitContribution contribution = FitContribution("bucky") contribution.addProfileGenerator(generator) contribution.setProfile(profile, xname="r") diff --git a/doc/examples/simplepdf.py b/doc/examples/simplepdf.py index dc36862a..027a6d76 100644 --- a/doc/examples/simplepdf.py +++ b/doc/examples/simplepdf.py @@ -25,7 +25,8 @@ from diffpy.srfit.pdf import PDFContribution from diffpy.structure import Structure -####### Example Code +###### +# Example Code def makeRecipe(ciffile, datname): @@ -41,11 +42,11 @@ def makeRecipe(ciffile, datname): stru.read(ciffile) contribution.addStructure("nickel", stru) - ## Make the FitRecipe and add the FitContribution. + # Make the FitRecipe and add the FitContribution. recipe = FitRecipe() recipe.addContribution(contribution) - ## Configure the fit variables + # Configure the fit variables phase = contribution.nickel.phase from diffpy.srfit.structure import constrainAsSpaceGroup diff --git a/doc/examples/simplepdftwophase.py b/doc/examples/simplepdftwophase.py index 526c4780..a8017c23 100644 --- a/doc/examples/simplepdftwophase.py +++ b/doc/examples/simplepdftwophase.py @@ -21,7 +21,8 @@ from diffpy.srfit.fitbase import FitRecipe, FitResults from diffpy.srfit.pdf import PDFContribution -####### Example Code +###### +# Example Code def makeRecipe(niciffile, siciffile, datname): @@ -42,7 +43,7 @@ def makeRecipe(niciffile, siciffile, datname): recipe = FitRecipe() recipe.addContribution(contribution) - ## Configure the fit variables + # 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_ni", 0.1) diff --git a/doc/examples/simplerecipe.py b/doc/examples/simplerecipe.py index 92ed185e..0ec297a5 100644 --- a/doc/examples/simplerecipe.py +++ b/doc/examples/simplerecipe.py @@ -21,7 +21,8 @@ from diffpy.srfit.fitbase import SimpleRecipe -####### Example Code +###### +# Example Code def main(): diff --git a/doc/examples/threedoublepeaks.py b/doc/examples/threedoublepeaks.py index 75c3d9ef..c0c91400 100644 --- a/doc/examples/threedoublepeaks.py +++ b/doc/examples/threedoublepeaks.py @@ -25,7 +25,8 @@ Profile, ) -####### Example Code +###### +# Example Code def makeRecipe(): @@ -42,7 +43,7 @@ def makeRecipe(): For this example, we use l1 = 1.012, l2 = 1.0 and r = 0.23. """ - ## The Profile + # The Profile # Create a Profile to hold the experimental and calculated signal. profile = Profile() x, y, dy = profile.loadtxt("data/threedoublepeaks.dat") @@ -89,7 +90,7 @@ def delta(t, mu): # c is the center of the gaussian. contribution.c.value = x[len(x) // 2] - ## The FitRecipe + # The FitRecipe # The FitRecipe lets us define what we want to fit. It is where we can # create variables, constraints and restraints. recipe = FitRecipe() diff --git a/src/diffpy/__init__.py b/src/diffpy/__init__.py index 406751a6..3254c0a6 100644 --- a/src/diffpy/__init__.py +++ b/src/diffpy/__init__.py @@ -4,7 +4,8 @@ # (c) 2008-2025 The Trustees of Columbia University in the City of New York. # All rights reserved. # -# File coded by: Chris Farrow and Billinge Group members and community contributors. +# File coded by: Chris Farrow and Billinge Group members and community +# contributors. # # See GitHub contributions for a more detailed list of contributors. # https://github.com/diffpy/diffpy.srfit/graphs/contributors diff --git a/src/diffpy/srfit/__init__.py b/src/diffpy/srfit/__init__.py index 79dc93c5..0374fdcf 100644 --- a/src/diffpy/srfit/__init__.py +++ b/src/diffpy/srfit/__init__.py @@ -4,7 +4,8 @@ # (c) 2008-2025 The Trustees of Columbia University in the City of New York. # All rights reserved. # -# File coded by: Christopher Farrow, Pavol Juhas, and members of the Billinge Group. +# File coded by: Christopher Farrow, Pavol Juhas, and members of the +# Billinge Group. # # See GitHub contributions for a more detailed list of contributors. # https://github.com/diffpy/diffpy.srfit/graphs/contributors diff --git a/src/diffpy/srfit/equation/builder.py b/src/diffpy/srfit/equation/builder.py index d19a17a4..dcd58ca2 100644 --- a/src/diffpy/srfit/equation/builder.py +++ b/src/diffpy/srfit/equation/builder.py @@ -75,6 +75,17 @@ > beq = c*f(a,b) > eq = beq.makeEquation() """ +import inspect +import numbers +import token +import tokenize + +import numpy +import six + +import diffpy.srfit.equation.literals as literals +from diffpy.srfit.equation.equationmod import Equation +from diffpy.srfit.equation.literals.literal import Literal __all__ = [ "EquationFactory", @@ -95,17 +106,6 @@ _builders = {} -import inspect -import numbers - -import numpy -import six - -import diffpy.srfit.equation.literals as literals -from diffpy.srfit.equation.equationmod import Equation -from diffpy.srfit.equation.literals.literal import Literal - - class EquationFactory(object): """A Factory for equations. @@ -113,7 +113,8 @@ class EquationFactory(object): factory, indexed by name. newargs -- A set of new arguments created by makeEquation. This is redefined whenever makeEquation is called. - equations -- Set of equations that have been built by the EquationFactory. + equations -- Set of equations that have been built by the + EquationFactory. """ symbols = ("+", "-", "*", "/", "**", "%", "|") @@ -213,10 +214,10 @@ def registerFunction(self, name, func, argnames): if n not in self.builders: self.registerConstant(n, 0) opbuilder = wrapFunction(name, func, len(argnames)) - for n in argnames: - b = self.builders[n] - l = b.literal - opbuilder.literal.addLiteral(l) + for argname in argnames: + builder = self.builders[argname] + argliteral = builder.literal + opbuilder.literal.addLiteral(argliteral) return self.registerBuilder(name, opbuilder) @@ -341,9 +342,6 @@ def _getUndefinedArgs(self, eqstr): Raises SyntaxError if the equation string uses invalid syntax. """ - import token - import tokenize - interface = six.StringIO(eqstr).readline # output is an iterator. Each entry (token) is a 5-tuple # token[0] = token type @@ -512,7 +510,7 @@ def __neg__(self): return self.__evalUnary(literals.NegationOperator) -## These are used by the class. +# These are used by the class. class ArgumentBuilder(BaseBuilder): @@ -681,15 +679,18 @@ def __wrapSrFitOperators(): instances in the module namespace.""" opmod = literals.operators excluded_types = set((opmod.CustomOperator, opmod.UFuncOperator)) + # check if opmod member should be wrapped as OperatorBuilder - is_exported_type = lambda cls: ( - inspect.isclass(cls) - and issubclass(cls, opmod.Operator) - and not inspect.isabstract(cls) - and not cls in excluded_types - ) + def _is_exported_type(cls): + return ( + inspect.isclass(cls) + and issubclass(cls, opmod.Operator) + and not inspect.isabstract(cls) + and cls not in excluded_types + ) + # create OperatorBuilder objects - for nm, opclass in inspect.getmembers(opmod, is_exported_type): + for nm, opclass in inspect.getmembers(opmod, _is_exported_type): op = opclass() assert op.name, "Unnamed Operator should never appear here." _builders[op.name] = OperatorBuilder(op.name, op) diff --git a/src/diffpy/srfit/equation/equationmod.py b/src/diffpy/srfit/equation/equationmod.py index 091f7a55..2b9c116e 100644 --- a/src/diffpy/srfit/equation/equationmod.py +++ b/src/diffpy/srfit/equation/equationmod.py @@ -117,7 +117,7 @@ def __getattr__(self, name): """Gives access to the Arguments as attributes.""" # Avoid infinite loop on argdict lookup. argdict = object.__getattribute__(self, "argdict") - if not name in argdict: + if name not in argdict: raise AttributeError("No argument named '%s' here" % name) return argdict[name] diff --git a/src/diffpy/srfit/equation/literals/operators.py b/src/diffpy/srfit/equation/literals/operators.py index cfe612e9..1f26c2e6 100644 --- a/src/diffpy/srfit/equation/literals/operators.py +++ b/src/diffpy/srfit/equation/literals/operators.py @@ -122,7 +122,7 @@ def addLiteral(self, literal): def getValue(self): """Get or evaluate the value of the operator.""" if self._value is None: - vals = [l.value for l in self.args] + vals = [arg.value for arg in self.args] self._value = self.operation(*vals) return self._value @@ -135,8 +135,8 @@ def _loopCheck(self, literal): # Check to see if I am a dependency of the literal. if hasattr(literal, "args"): - for l in literal.args: - self._loopCheck(l) + for lit_arg in literal.args: + self._loopCheck(lit_arg) return diff --git a/src/diffpy/srfit/fitbase/fithook.py b/src/diffpy/srfit/fitbase/fithook.py index 35e775f6..01bb2652 100644 --- a/src/diffpy/srfit/fitbase/fithook.py +++ b/src/diffpy/srfit/fitbase/fithook.py @@ -144,13 +144,17 @@ def postcall(self, recipe, chiv): print("Variables") vnames = recipe.getNames() vals = recipe.getValues() - byname = lambda nv: sortKeyForNumericString(nv[0]) - items = sorted(zip(vnames, vals), key=byname) + # byname = _byname() + items = sorted(zip(vnames, vals), key=_byname) for name, val in items: print(" %s = %f" % (name, val)) return +def _byname(nv): + return sortKeyForNumericString(nv[0]) + + # End class PrintFitHook diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index 26c32f5b..12c15120 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -108,8 +108,8 @@ def __init__(self, recipe, update=True, showfixed=True, showcon=False): def update(self): """Update the results according to the current state of the recipe.""" - ## Note that the order of these operations are chosen to reduce - ## computation time. + # Note that the order of these operations are chosen to reduce + # computation time. recipe = self.recipe @@ -173,8 +173,8 @@ def _calculateCovariance(self): self.cov = numpy.dot(vh.T.conj() / s**2, vh) except numpy.linalg.LinAlgError: self.messages.append("Cannot compute covariance matrix.") - l = len(self.varvals) - self.cov = numpy.zeros((l, l), dtype=float) + lvarvals = len(self.varvals) + self.cov = numpy.zeros((lvarvals, lvarvals), dtype=float) return def _calculateJacobian(self): @@ -324,17 +324,19 @@ def formatResults(self, header="", footer="", update=False): lines.append(header) if not certain: - l = "Some quantities invalid due to missing profile uncertainty" - if not l in self.messages: - self.messages.append(l) + err_msg = ( + "Some quantities invalid due to missing profile uncertainty" + ) + if err_msg not in self.messages: + self.messages.append(err_msg) lines.extend(self.messages) - ## Overall results - l = "Overall" + # Overall results + err_msg = "Overall" if not certain: - l += " (Chi2 and Reduced Chi2 invalid)" - lines.append(l) + err_msg += " (Chi2 and Reduced Chi2 invalid)" + lines.append(err_msg) lines.append(_DASHEDLINE) formatstr = "%-14s %.8f" lines.append(formatstr % ("Residual", self.residual)) @@ -346,16 +348,16 @@ def formatResults(self, header="", footer="", update=False): lines.append(formatstr % ("Reduced Chi2", self.rchi2)) lines.append(formatstr % ("Rw", self.rw)) - ## Per-FitContribution results + # Per-FitContribution results if len(self.conresults) > 1: keys = list(self.conresults.keys()) keys.sort(key=numstr) lines.append("") - l = "Contributions" + err_msg = "Contributions" if not certain: - l += " (Chi2 and Reduced Chi2 invalid)" - lines.append(l) + err_msg += " (Chi2 and Reduced Chi2 invalid)" + lines.append(err_msg) lines.append(_DASHEDLINE) formatstr = "%-10s %-42.8f" for name in keys: @@ -368,14 +370,14 @@ def formatResults(self, header="", footer="", update=False): lines.append(formatstr % ("Chi2", res.chi2)) lines.append(formatstr % ("Rw", res.rw)) - ## The variables + # The variables if self.varnames: lines.append("") - l = "Variables" + err_msg = "Variables" if not certain: - m = "Uncertainties invalid" - l += " (%s)" % m - lines.append(l) + err_msg2 = "Uncertainties invalid" + err_msg += " (%s)" % err_msg2 + lines.append(err_msg) lines.append(_DASHEDLINE) varnames = self.varnames @@ -407,13 +409,13 @@ def formatResults(self, header="", footer="", update=False): varlines.sort() lines.extend(varlines) - ## The constraints + # The constraints if self.connames and self.showcon: lines.append("") - l = "Constrained Parameters" + err_msg = "Constrained Parameters" if not certain: - l += " (Uncertainties invalid)" - lines.append(l) + err_msg += " (Uncertainties invalid)" + lines.append(err_msg) lines.append(_DASHEDLINE) w = 0 @@ -436,13 +438,13 @@ def formatResults(self, header="", footer="", update=False): val, unc = vals[name] lines.append(formatstr % (name, val, unc)) - ## Variable correlations + # Variable correlations lines.append("") corint = int(corrmin * 100) - l = "Variable Correlations greater than %i%%" % corint + err_msg = "Variable Correlations greater than %i%%" % corint if not certain: - l += " (Correlations invalid)" - lines.append(l) + err_msg += " (Correlations invalid)" + lines.append(err_msg) lines.append(_DASHEDLINE) tup = [] cornames = [] @@ -563,8 +565,8 @@ def __init__(self, con, weight, fitres): def _init(self, con, weight, fitres): """Initialize the attributes, for real.""" - ## Note that the order of these operations is chosen to reduce - ## computation time. + # Note that the order of these operations is chosen to reduce + # computation time. if con.profile is None: return diff --git a/src/diffpy/srfit/fitbase/parameter.py b/src/diffpy/srfit/fitbase/parameter.py index 21625b6d..e9e6cf8b 100644 --- a/src/diffpy/srfit/fitbase/parameter.py +++ b/src/diffpy/srfit/fitbase/parameter.py @@ -253,17 +253,18 @@ def __init__(self, name, obj, getter=None, setter=None, attr=None): name -- The name of this Parameter. obj -- The object to be wrapped. getter -- The unbound function that can be used to access the - attribute containing the parameter value. getter(obj) should - return the Parameter value. If getter is None (default), - it is assumed that an attribute is accessed via attr. If - attr is also specified, then the Parameter value will be - accessed via getter(obj, attr). - setter -- The unbound function that can be used to modify the - attribute containing the parameter value. setter(obj, value) - should set the attribute to the passed value. If setter is - None (default), it is assumed that an attribute is accessed + attribute containing the parameter value. getter(obj) + should return the Parameter value. If getter is None + (default), it is assumed that an attribute is accessed via attr. If attr is also specified, then the Parameter - value will be set via setter(obj, attr, value). + value will be accessed via getter(obj, attr). + setter -- The unbound function that can be used to modify the + attribute containing the parameter value. + setter(obj, value) should set the attribute to the + passed value. If setter is None (default), it is assumed + that an attribute is accessed via attr. If attr is also + specified, then the Parameter value will be set via + setter(obj, attr, value). attr -- The name of the attribute that contains the value of the parameter. If attr is None (default), then both getter and setter must be specified. diff --git a/src/diffpy/srfit/fitbase/profile.py b/src/diffpy/srfit/fitbase/profile.py index 0da465fb..da0e04ce 100644 --- a/src/diffpy/srfit/fitbase/profile.py +++ b/src/diffpy/srfit/fitbase/profile.py @@ -47,8 +47,8 @@ class Profile(Observable, Validatable): xobs -- Read-only property of _xobs. _yobs -- A numpy array of the observed signal (default None) yobs -- Read-only property of _yobs. - _dyobs -- A numpy array of the uncertainty of the observed signal (default - None, optional). + _dyobs -- A numpy array of the uncertainty of the observed signal + (default None, optional). dyobs -- Read-only property of _dyobs. x -- A numpy array of the calculated independent variable (default None, property for xpar accessors). diff --git a/src/diffpy/srfit/fitbase/profilegenerator.py b/src/diffpy/srfit/fitbase/profilegenerator.py index c1f0d2e7..2df9916e 100644 --- a/src/diffpy/srfit/fitbase/profilegenerator.py +++ b/src/diffpy/srfit/fitbase/profilegenerator.py @@ -111,7 +111,7 @@ def __call__(self, x): """ return x - ## No need to overload anything below here + # No need to overload anything below here def operation(self): """Evaluate the profile. diff --git a/src/diffpy/srfit/fitbase/profileparser.py b/src/diffpy/srfit/fitbase/profileparser.py index c38af1a0..fd2d8d04 100644 --- a/src/diffpy/srfit/fitbase/profileparser.py +++ b/src/diffpy/srfit/fitbase/profileparser.py @@ -34,7 +34,8 @@ class ProfileParser(object): _format -- Name of the data format that this parses (string, default ""). The format string is a unique identifier for the data format handled by the parser. - _banks -- The data from each bank. Each bank contains a (x, y, dx, dy) + _banks -- The data from each bank. Each bank contains a (x, y, dx, + dy) tuple: x -- A numpy array containing the independent variable read from the file. diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index e4902734..ea2641cb 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -24,6 +24,7 @@ import re from collections import OrderedDict +from functools import partial from itertools import chain, groupby import six @@ -510,7 +511,7 @@ def registerFunction(self, f, name=None, argnames=None): self._eqfactory.registerOperator(name, f) return f - #### Introspection code + # Introspection code if name is None or argnames is None: import inspect @@ -547,7 +548,7 @@ def registerFunction(self, f, name=None, argnames=None): argnames = list(fncode.co_varnames) argnames = argnames[offset : fncode.co_argcount] - #### End introspection code + # End introspection code # Make missing Parameters for pname in argnames: @@ -741,8 +742,7 @@ def clearConstraints(self, recurse=False): self.unconstrain(*self._constraints) if recurse: - f = lambda m: hasattr(m, "clearConstraints") - for m in filter(f, self._iterManaged()): + for m in filter(_has_clear_constraints, self._iterManaged()): m.clearConstraints(recurse) return @@ -822,19 +822,16 @@ def clearRestraints(self, recurse=False): found there as well. """ self.unrestrain(*self._restraints) - if recurse: - f = lambda m: hasattr(m, "clearRestraints") - for m in filter(f, self._iterManaged()): - m.clearRestraints(recurse) + for msg in filter(_has_clear_restraints, self._iterManaged()): + msg.clearRestraints(recurse) return def _getConstraints(self, recurse=True): """Get the constrained Parameters for this and managed sub-objects.""" constraints = {} if recurse: - f = lambda m: hasattr(m, "_getConstraints") - for m in filter(f, self._iterManaged()): + for m in filter(_has_get_constraints, self._iterManaged()): constraints.update(m._getConstraints(recurse)) constraints.update(self._constraints) @@ -848,8 +845,7 @@ def _getRestraints(self, recurse=True): """ restraints = set(self._restraints) if recurse: - f = lambda m: hasattr(m, "_getRestraints") - for m in filter(f, self._iterManaged()): + for m in filter(_has_get_restraints, self._iterManaged()): restraints.update(m._getRestraints(recurse)) return restraints @@ -968,15 +964,13 @@ def show(self, pattern="", textwidth=78): the screen width. Do not trim when negative or 0. """ regexp = re.compile(pattern) - pmatch = lambda s: ( - len(s.split(None, 1)) < 2 or regexp.search(s.split(None, 1)[0]) - ) + _pmatch_with_re = partial(_pmatch, regexp=regexp) # Show sub objects and their parameters lines = [] tlines = self._formatManaged() if tlines: lines.extend(["Parameters", _DASHEDLINE]) - linesok = filter(pmatch, tlines) + linesok = filter(_pmatch_with_re, tlines) lastnotblank = False # squeeze repeated blank lines for lastnotblank, g in groupby(linesok, bool): @@ -1002,7 +996,7 @@ def show(self, pattern="", textwidth=78): if lines: lines.append("") lines.extend(["Restraints", _DASHEDLINE]) - lines.extend(filter(pmatch, tlines)) + lines.extend(filter(_pmatch_with_re, tlines)) # Determine effective text width tw. tw = textwidth if (textwidth is not None and textwidth > 0) else None @@ -1057,3 +1051,24 @@ def equationFromString( factory.deRegisterBuilder(name) return eq + + +def _has_clear_constraints(msg): + return hasattr(msg, "clearConstraints") + + +def _has_clear_restraints(msg): + return hasattr(msg, "clearRestraints") + + +def _has_get_restraints(msg): + return hasattr(msg, "_getRestraints") + + +def _has_get_constraints(msg): + return hasattr(msg, "_getConstraints") + + +def _pmatch(inp_str, regexp): + parts = inp_str.split(None, 1) + return len(parts) < 2 or regexp.search(parts[0]) diff --git a/src/diffpy/srfit/interface/__init__.py b/src/diffpy/srfit/interface/__init__.py index a611f118..3157c1ec 100644 --- a/src/diffpy/srfit/interface/__init__.py +++ b/src/diffpy/srfit/interface/__init__.py @@ -20,16 +20,14 @@ """ -from diffpy.srfit.interface.interface import ParameterInterface +from diffpy.srfit.interface.interface import ( + FitRecipeInterface, + ParameterInterface, + RecipeOrganizerInterface, +) _parameter_interface = ParameterInterface - -from diffpy.srfit.interface.interface import RecipeOrganizerInterface - _recipeorganizer_interface = RecipeOrganizerInterface - -from diffpy.srfit.interface.interface import FitRecipeInterface - _fitrecipe_interface = FitRecipeInterface # End of file diff --git a/src/diffpy/srfit/pdf/characteristicfunctions.py b/src/diffpy/srfit/pdf/characteristicfunctions.py index 3f8a1473..a8718e57 100644 --- a/src/diffpy/srfit/pdf/characteristicfunctions.py +++ b/src/diffpy/srfit/pdf/characteristicfunctions.py @@ -216,8 +216,6 @@ def lognormalSphericalCF(r, psize, psig): if psig <= 0: return sphericalCF(r, psize) - erfc = lambda x: 1.0 - erf(x) - sqrt2 = sqrt(2.0) s = sqrt(log(psig * psig / (1.0 * psize * psize) + 1)) mu = log(psize) - s * s / 2 @@ -427,4 +425,8 @@ def __call__(self, r): return fr +def erfc(x): + return 1.0 - erf(x) + + # End of file diff --git a/src/diffpy/srfit/pdf/pdfparser.py b/src/diffpy/srfit/pdf/pdfparser.py index 9eb5595f..d3a617b9 100644 --- a/src/diffpy/srfit/pdf/pdfparser.py +++ b/src/diffpy/srfit/pdf/pdfparser.py @@ -38,15 +38,15 @@ class PDFParser(ProfileParser): _format -- Name of the data format that this parses (string, default ""). The format string is a unique identifier for the data format handled by the parser. - _banks -- The data from each bank. Each bank contains a (x, y, dx, dy) - tuple: + _banks -- The data from each bank. Each bank contains a + (x, y, dx, dy) tuple: x -- A numpy array containing the independent variable read from the file. y -- A numpy array containing the profile from the file. dx -- A numpy array containing the uncertainty in x - read from the file. This is 0 if the uncertainty - cannot be read. + read from the file. This is 0 if the + uncertainty cannot be read. dy -- A numpy array containing the uncertainty read from the file. This is 0 if the uncertainty cannot be read. diff --git a/src/diffpy/srfit/sas/prcalculator.py b/src/diffpy/srfit/sas/prcalculator.py index 0af67260..1dc6414d 100644 --- a/src/diffpy/srfit/sas/prcalculator.py +++ b/src/diffpy/srfit/sas/prcalculator.py @@ -23,6 +23,8 @@ __all__ = ["PrCalculator", "CFCalculator"] +from functools import partial + import numpy from diffpy.srfit.fitbase import Calculator @@ -90,12 +92,15 @@ def __call__(self, r): self._invertor.y = iq self._invertor.err = diq c, c_cov = self._invertor.invert_optimize() - l = lambda x: self._invertor.pr(c, x) - pr = map(l, r) + _inverted_w_c = partial(self._inverted, c=c) + pr = map(_inverted_w_c, r) pr = numpy.array(pr) return self.scale.value * pr + def _inverted(self, x, c): + self._invertor.pr(c, x) + # End class PrCalculator diff --git a/src/diffpy/srfit/sas/sasparser.py b/src/diffpy/srfit/sas/sasparser.py index 69f94904..113648e9 100644 --- a/src/diffpy/srfit/sas/sasparser.py +++ b/src/diffpy/srfit/sas/sasparser.py @@ -36,15 +36,15 @@ class SASParser(ProfileParser): _format -- Name of the data format that this parses (string, default ""). The format string is a unique identifier for the data format handled by the parser. - _banks -- The data from each bank. Each bank contains a (x, y, dx, dy) - tuple: + _banks -- The data from each bank. Each bank contains a + (x, y, dx, dy) tuple: x -- A numpy array containing the independent variable read from the file. y -- A numpy array containing the profile from the file. dx -- A numpy array containing the uncertainty in x - read from the file. This is 0 if the uncertainty - cannot be read. + read from the file. This is 0 if the + uncertainty cannot be read. dy -- A numpy array containing the uncertainty read from the file. This is 0 if the uncertainty cannot be read. diff --git a/src/diffpy/srfit/sas/sasprofile.py b/src/diffpy/srfit/sas/sasprofile.py index b18dfa76..517b2de1 100644 --- a/src/diffpy/srfit/sas/sasprofile.py +++ b/src/diffpy/srfit/sas/sasprofile.py @@ -36,8 +36,8 @@ class SASProfile(Profile): xobs -- Read-only property of _xobs. _yobs -- A numpy array of the observed signal (default None) yobs -- Read-only property of _yobs. - _dyobs -- A numpy array of the uncertainty of the observed signal (default - None, optional). + _dyobs -- A numpy array of the uncertainty of the observed signal + (default None, optional). dyobs -- Read-only property of _dyobs. x -- A numpy array of the calculated independent variable (default None, property for xpar accessors). diff --git a/src/diffpy/srfit/structure/__init__.py b/src/diffpy/srfit/structure/__init__.py index d1a1ecd1..b48bb60d 100644 --- a/src/diffpy/srfit/structure/__init__.py +++ b/src/diffpy/srfit/structure/__init__.py @@ -16,6 +16,8 @@ interface and automatic structure constraint generation from space group information.""" +from diffpy.srfit.structure.sgconstraints import constrainAsSpaceGroup + def struToParameterSet(name, stru): """Creates a ParameterSet from an structure. @@ -51,8 +53,6 @@ def struToParameterSet(name, stru): raise TypeError("Unadaptable structure format") -from diffpy.srfit.structure.sgconstraints import constrainAsSpaceGroup - # silence pyflakes checker assert constrainAsSpaceGroup diff --git a/src/diffpy/srfit/structure/objcrystparset.py b/src/diffpy/srfit/structure/objcrystparset.py index 3dab67f2..5feef034 100644 --- a/src/diffpy/srfit/structure/objcrystparset.py +++ b/src/diffpy/srfit/structure/objcrystparset.py @@ -378,8 +378,10 @@ def restrainBondLength( by the unrestrained point-average chi^2 (chi^2/numpoints) (default False) - Returns the ObjCrystBondLengthRestraint object for use with the 'unrestrain' - method. + Returns + ------- + The ObjCrystBondLengthRestraint object for use with the + 'unrestrain' method. """ res = ObjCrystBondLengthRestraint( atom1, atom2, length, sigma, delta, scaled @@ -586,7 +588,8 @@ def addDihedralAngleParameter( ObjCrystMoleculeParSet that can be adjusted during the fit. name -- The name of the ObjCrystDihedralAngleParameter. - atom1 -- The first atom (ObjCrystMolAtomParSet) in the dihderal angle + atom1 -- The first atom (ObjCrystMolAtomParSet) in the dihderal + angle. atom2 -- The second (central) atom (ObjCrystMolAtomParSet) in the dihderal angle atom3 -- The third (central) atom (ObjCrystMolAtomParSet) in the @@ -1486,8 +1489,8 @@ def _createSpaceGroup(sgobjcryst): sgobjcryst -- A pyobjcryst.spacegroup.SpaceGroup instance. This uses the actual space group operations from the - pyobjcryst.spacegroup.SpaceGroup instance so there is no ambiguity about - the actual space group. + pyobjcryst.spacegroup.SpaceGroup instance so there is no ambiguity + about the actual space group. """ import copy diff --git a/src/diffpy/srfit/structure/sgconstraints.py b/src/diffpy/srfit/structure/sgconstraints.py index c3b0d005..68cb7734 100644 --- a/src/diffpy/srfit/structure/sgconstraints.py +++ b/src/diffpy/srfit/structure/sgconstraints.py @@ -362,7 +362,7 @@ def _clearConstraints(self): lattice.unconstrain(par) par.setConst(False) - ## Clear ADPs + # Clear ADPs if self.constrainadps: for scatterer in scatterers: if isosymbol: diff --git a/src/diffpy/srfit/version.py b/src/diffpy/srfit/version.py index a0caae47..f0833049 100644 --- a/src/diffpy/srfit/version.py +++ b/src/diffpy/srfit/version.py @@ -4,7 +4,8 @@ # (c) 2008-2025 The Trustees of Columbia University in the City of New York. # All rights reserved. # -# File coded by: Christopher Farrow, Pavol Juhas, and members of the Billinge Group. +# File coded by: Christopher Farrow, Pavol Juhas, and members of the +# Billinge Group. # # See GitHub contributions for a more detailed list of contributors. # https://github.com/diffpy/diffpy.srfit/graphs/contributors diff --git a/tests/conftest.py b/tests/conftest.py index bd53d38d..4b8af955 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,9 +1,7 @@ import importlib.resources -import json import logging import sys from functools import lru_cache -from pathlib import Path import pytest import six @@ -86,21 +84,6 @@ def pyobjcryst_available(): return has_pyobjcryst() -@pytest.fixture(scope="session") -def user_filesystem(tmp_path): - base_dir = Path(tmp_path) - home_dir = base_dir / "home_dir" - home_dir.mkdir(parents=True, exist_ok=True) - cwd_dir = base_dir / "cwd_dir" - cwd_dir.mkdir(parents=True, exist_ok=True) - - home_config_data = {"username": "home_username", "email": "home@email.com"} - with open(home_dir / "diffpyconfig.json", "w") as f: - json.dump(home_config_data, f) - - yield tmp_path - - @pytest.fixture(scope="session") def datafile(): """Fixture to load a test data file from the testdata package directory.""" diff --git a/tests/test_builder.py b/tests/test_builder.py index dfabc8fb..4045dd6d 100644 --- a/tests/test_builder.py +++ b/tests/test_builder.py @@ -145,8 +145,6 @@ def g2(v1): def testParseEquation(noObserversInGlobalBuilders): - from numpy import array_equal, divide, e, sin, sqrt - factory = builder.EquationFactory() # Scalar equation @@ -159,8 +157,7 @@ def testParseEquation(noObserversInGlobalBuilders): eq.x.setValue(x) eq.B.setValue(B) eq.C.setValue(C) - f = lambda A, x, B, C: A * sin(0.5 * x) + divide(B, C) - assert array_equal(eq(), f(A, x, B, C)) + assert numpy.array_equal(eq(), f_equation(A, x, B, C)) # Make sure that the arguments of eq are listed in the order in which # they appear in the equations. @@ -172,9 +169,7 @@ def testParseEquation(noObserversInGlobalBuilders): sigma = 0.1 eq.x.setValue(x) eq.sigma.setValue(sigma) - f = lambda x, sigma: sqrt(e ** (-0.5 * (x / sigma) ** 2)) - assert numpy.allclose(eq(), f(x, sigma)) - + assert numpy.allclose(eq(), gaussian_test(x, sigma)) assert eq.args == [eq.x, eq.sigma] # Equation with constants @@ -182,13 +177,13 @@ def testParseEquation(noObserversInGlobalBuilders): eq = factory.makeEquation("sqrt(e**(-0.5*(x/sigma)**2))") assert "sigma" in eq.argdict assert "x" not in eq.argdict - assert numpy.allclose(eq(sigma=sigma), f(x, sigma)) + assert numpy.allclose(eq(sigma=sigma), gaussian_test(x, sigma)) assert eq.args == [eq.sigma] # Equation with user-defined functions factory.registerFunction("myfunc", eq, ["sigma"]) eq2 = factory.makeEquation("c*myfunc(sigma)") - assert numpy.allclose(eq2(c=2, sigma=sigma), 2 * f(x, sigma)) + assert numpy.allclose(eq2(c=2, sigma=sigma), 2 * gaussian_test(x, sigma)) assert "sigma" in eq2.argdict assert "c" in eq2.argdict assert eq2.args == [eq2.c, eq2.sigma] @@ -251,8 +246,7 @@ def _f(a, b): sigma = builder.ArgumentBuilder(name="sigma", value=0.1) beq = sqrt(e ** (-0.5 * (x / sigma) ** 2)) eq = beq.getEquation() - f = lambda x, sigma: sqrt(e ** (-0.5 * (x / sigma) ** 2)) - assert numpy.allclose(eq(), numpy.sqrt(e ** (-0.5 * (_x / 0.1) ** 2))) + assert numpy.allclose(eq(), numpy.sqrt(numpy.exp(-0.5 * (_x / 0.1) ** 2))) # Equation with Equation A = builder.ArgumentBuilder(name="A", value=2) @@ -283,5 +277,9 @@ def _f(a, b): return -if __name__ == "__main__": - unittest.main() +def f_equation(a, x, b, c): + return a * numpy.sin(0.5 * x) + numpy.divide(b, c) + + +def gaussian_test(x, sigma): + return numpy.sqrt(numpy.exp(-0.5 * (x / sigma) ** 2)) diff --git a/tests/test_characteristicfunctions.py b/tests/test_characteristicfunctions.py index dd846baf..ecbbf0e0 100644 --- a/tests/test_characteristicfunctions.py +++ b/tests/test_characteristicfunctions.py @@ -22,8 +22,9 @@ import diffpy.srfit.pdf.characteristicfunctions as cf from diffpy.srfit.sas.sasimport import sasimport -# Global variables to be assigned in setUp -cf = None +# # Global variables to be assigned in setUp +# cf = None +# Fixme: remove this code if imports don't break on testing # ---------------------------------------------------------------------------- diff --git a/tests/test_contribution.py b/tests/test_contribution.py index 4461647d..4d3fc7e3 100644 --- a/tests/test_contribution.py +++ b/tests/test_contribution.py @@ -170,8 +170,7 @@ def test_releaseOldEquations(self): def test_registerFunction(self): """Ensure registered function works after second setEquation call.""" fc = self.fitcontribution - fsquare = lambda x: x**2 - fc.registerFunction(fsquare, name="fsquare") + fc.registerFunction(_fsquare, name="fsquare") fc.setEquation("fsquare") fc.x.setValue(5) self.assertEqual(25, fc.evaluate()) @@ -184,6 +183,10 @@ def test_registerFunction(self): return +def _fsquare(x): + return x**2 + + def testResidual(noObserversInGlobalBuilders): """Test the residual, which requires all other methods.""" gen = ProfileGenerator("test") diff --git a/tests/test_parameter.py b/tests/test_parameter.py index 56e00d4f..04ecd4c7 100644 --- a/tests/test_parameter.py +++ b/tests/test_parameter.py @@ -27,29 +27,29 @@ class TestParameter(unittest.TestCase): def testSetValue(self): """Test initialization.""" - l = Parameter("l") + par_l = Parameter("l") - l.setValue(3.14) - self.assertAlmostEqual(3.14, l.getValue()) + par_l.setValue(3.14) + self.assertAlmostEqual(3.14, par_l.getValue()) # Try array import numpy x = numpy.arange(0, 10, 0.1) - l.setValue(x) - self.assertTrue(l.getValue() is x) - self.assertTrue(l.value is x) + par_l.setValue(x) + self.assertTrue(par_l.getValue() is x) + self.assertTrue(par_l.value is x) # Change the array y = numpy.arange(0, 10, 0.5) - l.value = y - self.assertTrue(l.getValue() is y) - self.assertTrue(l.value is y) + par_l.value = y + self.assertTrue(par_l.getValue() is y) + self.assertTrue(par_l.value is y) # Back to scalar - l.setValue(1.01) - self.assertAlmostEqual(1.01, l.getValue()) - self.assertAlmostEqual(1.01, l.value) + par_l.setValue(1.01) + self.assertAlmostEqual(1.01, par_l.getValue()) + self.assertAlmostEqual(1.01, par_l.value) return @@ -57,23 +57,23 @@ class TestParameterProxy(unittest.TestCase): def testProxy(self): """Test the ParameterProxy class.""" - l = Parameter("l", 3.14) + par_l = Parameter("l", 3.14) # Try Accessor adaptation - la = ParameterProxy("l2", l) + la = ParameterProxy("l2", par_l) self.assertEqual("l2", la.name) - self.assertEqual(l.getValue(), la.getValue()) + self.assertEqual(par_l.getValue(), la.getValue()) # Change the parameter - l.value = 2.3 - self.assertEqual(l.getValue(), la.getValue()) - self.assertEqual(l.value, la.value) + par_l.value = 2.3 + self.assertEqual(par_l.getValue(), la.getValue()) + self.assertEqual(par_l.value, la.value) # Change the proxy la.value = 3.2 - self.assertEqual(l.getValue(), la.getValue()) - self.assertEqual(l.value, la.value) + self.assertEqual(par_l.getValue(), la.getValue()) + self.assertEqual(par_l.value, la.value) return @@ -85,38 +85,38 @@ def testWrapper(self): This adapts a Parameter to the Parameter interface. :) """ - l = Parameter("l", 3.14) + par_l = Parameter("l", 3.14) # Try Accessor adaptation la = ParameterAdapter( - "l", l, getter=Parameter.getValue, setter=Parameter.setValue + "l", par_l, getter=Parameter.getValue, setter=Parameter.setValue ) - self.assertEqual(l.name, la.name) - self.assertEqual(l.getValue(), la.getValue()) + self.assertEqual(par_l.name, la.name) + self.assertEqual(par_l.getValue(), la.getValue()) # Change the parameter - l.setValue(2.3) - self.assertEqual(l.getValue(), la.getValue()) + par_l.setValue(2.3) + self.assertEqual(par_l.getValue(), la.getValue()) # Change the adapter la.setValue(3.2) - self.assertEqual(l.getValue(), la.getValue()) + self.assertEqual(par_l.getValue(), la.getValue()) # Try Attribute adaptation - la = ParameterAdapter("l", l, attr="value") + la = ParameterAdapter("l", par_l, attr="value") - self.assertEqual(l.name, la.name) + self.assertEqual(par_l.name, la.name) self.assertEqual("value", la.attr) - self.assertEqual(l.getValue(), la.getValue()) + self.assertEqual(par_l.getValue(), la.getValue()) # Change the parameter - l.setValue(2.3) - self.assertEqual(l.getValue(), la.getValue()) + par_l.setValue(2.3) + self.assertEqual(par_l.getValue(), la.getValue()) # Change the adapter la.setValue(3.2) - self.assertEqual(l.getValue(), la.getValue()) + self.assertEqual(par_l.getValue(), la.getValue()) return diff --git a/tests/utils.py b/tests/utils.py deleted file mode 100644 index 4574cf27..00000000 --- a/tests/utils.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python -############################################################################## -# -# diffpy.srfit by DANSE Diffraction group -# Simon J. L. Billinge -# (c) 2010 The Trustees of Columbia University -# in the City of New York. All rights reserved. -# -# File coded by: Pavol Juhas -# -# See AUTHORS.txt for a list of people who contributed. -# See LICENSE_DANSE.txt for license information. -# -############################################################################## -"""Helper routines for testing.""" - -import sys - -import six - -import diffpy.srfit.equation.literals as literals -from diffpy.srfit.sas.sasimport import sasimport -from tests import logger - -# Helper functions for testing ----------------------------------------------- - - -def capturestdout(f, *args, **kwargs): - """Capture the standard output from a call of function f.""" - savestdout = sys.stdout - fp = six.StringIO() - try: - sys.stdout = fp - f(*args, **kwargs) - finally: - sys.stdout = savestdout - return fp.getvalue() - - -# End of file