From 07637de04d9cf90d3680903046a8032b6b533c04 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2024 17:38:27 +0000 Subject: [PATCH] [pre-commit.ci] auto fixes from pre-commit hooks --- devutils/makesdist | 38 +-- doc/examples/coreshellnp.py | 57 ++-- doc/examples/crystalpdf.py | 26 +- doc/examples/crystalpdfall.py | 78 +++--- doc/examples/crystalpdfobjcryst.py | 17 +- doc/examples/crystalpdftwodata.py | 36 +-- doc/examples/crystalpdftwophase.py | 43 ++- doc/examples/data/ni.iq | 1 - doc/examples/debyemodel.py | 43 +-- doc/examples/debyemodelII.py | 28 +- doc/examples/ellipsoidsas.py | 20 +- doc/examples/gaussiangenerator.py | 17 +- doc/examples/gaussianrecipe.py | 16 +- doc/examples/interface.py | 9 +- doc/examples/npintensity.py | 56 ++-- doc/examples/npintensityII.py | 84 +++--- doc/examples/nppdfcrystal.py | 29 +- doc/examples/nppdfobjcryst.py | 30 +- doc/examples/nppdfsas.py | 37 +-- doc/examples/simplepdf.py | 17 +- doc/examples/simplepdftwophase.py | 30 +- doc/examples/simplerecipe.py | 3 + doc/examples/threedoublepeaks.py | 57 ++-- .../api/diffpy.srfit.equation.literals.rst | 1 - doc/source/api/diffpy.srfit.equation.rst | 1 - .../api/diffpy.srfit.equation.visitors.rst | 1 - doc/source/api/diffpy.srfit.fitbase.rst | 1 - doc/source/api/diffpy.srfit.interface.rst | 1 - doc/source/api/diffpy.srfit.pdf.rst | 1 - doc/source/api/diffpy.srfit.rst | 1 - doc/source/api/diffpy.srfit.sas.rst | 1 - doc/source/api/diffpy.srfit.structure.rst | 1 - doc/source/api/diffpy.srfit.util.rst | 1 - src/diffpy/__init__.py | 1 - src/diffpy/srfit/equation/__init__.py | 1 - src/diffpy/srfit/equation/builder.py | 111 +++++--- src/diffpy/srfit/equation/equationmod.py | 26 +- .../srfit/equation/literals/__init__.py | 59 ++-- src/diffpy/srfit/equation/literals/abcs.py | 15 +- .../srfit/equation/literals/argument.py | 10 +- src/diffpy/srfit/equation/literals/literal.py | 6 +- .../srfit/equation/literals/operators.py | 32 ++- .../srfit/equation/visitors/__init__.py | 6 +- .../srfit/equation/visitors/argfinder.py | 3 +- src/diffpy/srfit/equation/visitors/printer.py | 16 +- src/diffpy/srfit/equation/visitors/swapper.py | 3 +- .../srfit/equation/visitors/validator.py | 15 +- src/diffpy/srfit/equation/visitors/visitor.py | 4 +- src/diffpy/srfit/exceptions.py | 2 + src/diffpy/srfit/fitbase/__init__.py | 17 +- src/diffpy/srfit/fitbase/calculator.py | 8 +- src/diffpy/srfit/fitbase/configurable.py | 1 + src/diffpy/srfit/fitbase/constraint.py | 8 +- src/diffpy/srfit/fitbase/fitcontribution.py | 44 ++- src/diffpy/srfit/fitbase/fithook.py | 16 +- src/diffpy/srfit/fitbase/fitrecipe.py | 115 ++++---- src/diffpy/srfit/fitbase/fitresults.py | 109 ++++---- src/diffpy/srfit/fitbase/parameter.py | 35 +-- src/diffpy/srfit/fitbase/parameterset.py | 3 +- src/diffpy/srfit/fitbase/profile.py | 59 ++-- src/diffpy/srfit/fitbase/profilegenerator.py | 7 +- src/diffpy/srfit/fitbase/profileparser.py | 5 +- src/diffpy/srfit/fitbase/recipeorganizer.py | 137 +++++----- src/diffpy/srfit/fitbase/restraint.py | 10 +- src/diffpy/srfit/fitbase/simplerecipe.py | 25 +- src/diffpy/srfit/fitbase/validatable.py | 4 +- src/diffpy/srfit/interface/__init__.py | 3 + src/diffpy/srfit/interface/interface.py | 19 +- src/diffpy/srfit/pdf/__init__.py | 2 +- src/diffpy/srfit/pdf/basepdfgenerator.py | 31 +-- .../srfit/pdf/characteristicfunctions.py | 157 +++++++---- src/diffpy/srfit/pdf/debyepdfgenerator.py | 13 +- src/diffpy/srfit/pdf/pdfcontribution.py | 25 +- src/diffpy/srfit/pdf/pdfgenerator.py | 7 +- src/diffpy/srfit/pdf/pdfparser.py | 39 +-- src/diffpy/srfit/sas/__init__.py | 5 +- src/diffpy/srfit/sas/prcalculator.py | 6 +- src/diffpy/srfit/sas/sasgenerator.py | 1 + src/diffpy/srfit/sas/sasimport.py | 24 +- src/diffpy/srfit/sas/sasparameter.py | 5 +- src/diffpy/srfit/sas/sasparser.py | 6 +- src/diffpy/srfit/sas/sasprofile.py | 2 +- src/diffpy/srfit/structure/__init__.py | 4 + src/diffpy/srfit/structure/bvsrestraint.py | 18 +- src/diffpy/srfit/structure/cctbxparset.py | 56 ++-- src/diffpy/srfit/structure/diffpyparset.py | 74 +++-- src/diffpy/srfit/structure/objcrystparset.py | 257 +++++++++--------- src/diffpy/srfit/structure/sgconstraints.py | 161 ++++++----- src/diffpy/srfit/structure/srrealparset.py | 5 +- src/diffpy/srfit/tests/__init__.py | 26 +- src/diffpy/srfit/tests/speedtest.py | 120 ++++---- src/diffpy/srfit/tests/testbuilder.py | 71 +++-- .../tests/testcharacteristicfunctions.py | 45 ++- src/diffpy/srfit/tests/testconstraint.py | 4 +- src/diffpy/srfit/tests/testcontribution.py | 76 +++--- src/diffpy/srfit/tests/testdiffpyparset.py | 37 ++- src/diffpy/srfit/tests/testequation.py | 35 ++- src/diffpy/srfit/tests/testfitrecipe.py | 62 ++--- src/diffpy/srfit/tests/testfitresults.py | 8 +- src/diffpy/srfit/tests/testliterals.py | 56 ++-- src/diffpy/srfit/tests/testobjcrystparset.py | 154 +++++------ src/diffpy/srfit/tests/testparameter.py | 19 +- src/diffpy/srfit/tests/testpdf.py | 142 ++++++---- src/diffpy/srfit/tests/testprofile.py | 66 +++-- .../srfit/tests/testprofilegenerator.py | 11 +- src/diffpy/srfit/tests/testrecipeorganizer.py | 127 ++++----- src/diffpy/srfit/tests/testrestraint.py | 7 +- src/diffpy/srfit/tests/testsas.py | 35 +-- src/diffpy/srfit/tests/testsgconstraints.py | 64 +++-- src/diffpy/srfit/tests/testtagmanager.py | 24 +- src/diffpy/srfit/tests/testvisitors.py | 6 +- src/diffpy/srfit/tests/testweakrefcallable.py | 54 ++-- src/diffpy/srfit/tests/utils.py | 37 ++- src/diffpy/srfit/util/__init__.py | 9 +- src/diffpy/srfit/util/argbinders.py | 9 +- src/diffpy/srfit/util/inpututils.py | 3 +- src/diffpy/srfit/util/nameutils.py | 8 +- src/diffpy/srfit/util/observable.py | 8 +- src/diffpy/srfit/util/tagmanager.py | 9 - src/diffpy/srfit/util/weakrefcallable.py | 24 +- 120 files changed, 2060 insertions(+), 1911 deletions(-) diff --git a/devutils/makesdist b/devutils/makesdist index 6aaae616..e77257ea 100755 --- a/devutils/makesdist +++ b/devutils/makesdist @@ -1,51 +1,57 @@ #!/usr/bin/env python -'''Create source distribution tar.gz archive, where each file belongs +"""Create source distribution tar.gz archive, where each file belongs to a root user and modification time is set to the git commit time. -''' +""" -import sys +import glob +import gzip import os import subprocess -import glob +import sys import tarfile -import gzip BASEDIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) sys.path.insert(0, BASEDIR) -from setup import versiondata, FALLBACK_VERSION -timestamp = versiondata.getint('DEFAULT', 'timestamp') +from setup import FALLBACK_VERSION, versiondata -vfb = versiondata.get('DEFAULT', 'version').split('.post')[0] + '.post0' +timestamp = versiondata.getint("DEFAULT", "timestamp") + +vfb = versiondata.get("DEFAULT", "version").split(".post")[0] + ".post0" emsg = "Invalid FALLBACK_VERSION. Expected %r got %r." assert vfb == FALLBACK_VERSION, emsg % (vfb, FALLBACK_VERSION) + def inform(s): sys.stdout.write(s) sys.stdout.flush() return + inform('Run "setup.py sdist --formats=tar" ') -cmd_sdist = [sys.executable] + 'setup.py sdist --formats=tar'.split() -ec = subprocess.call(cmd_sdist, cwd=BASEDIR, stdout=open(os.devnull, 'w')) -if ec: sys.exit(ec) +cmd_sdist = [sys.executable] + "setup.py sdist --formats=tar".split() +ec = subprocess.call(cmd_sdist, cwd=BASEDIR, stdout=open(os.devnull, "w")) +if ec: + sys.exit(ec) inform("[done]\n") -tarname = max(glob.glob(BASEDIR + '/dist/*.tar'), key=os.path.getmtime) +tarname = max(glob.glob(BASEDIR + "/dist/*.tar"), key=os.path.getmtime) tfin = tarfile.open(tarname) -fpout = gzip.GzipFile(tarname + '.gz', 'w', mtime=0) -tfout = tarfile.open(fileobj=fpout, mode='w') +fpout = gzip.GzipFile(tarname + ".gz", "w", mtime=0) +tfout = tarfile.open(fileobj=fpout, mode="w") + def fixtarinfo(tinfo): tinfo.uid = tinfo.gid = 0 - tinfo.uname = tinfo.gname = 'root' + tinfo.uname = tinfo.gname = "root" tinfo.mtime = timestamp tinfo.mode &= ~0o022 return tinfo -inform('Filter %s --> %s.gz ' % (2 * (os.path.basename(tarname),))) + +inform("Filter %s --> %s.gz " % (2 * (os.path.basename(tarname),))) for ti in tfin: tfout.addfile(fixtarinfo(ti), tfin.extractfile(ti)) diff --git a/doc/examples/coreshellnp.py b/doc/examples/coreshellnp.py index 9c806647..7e464c74 100644 --- a/doc/examples/coreshellnp.py +++ b/doc/examples/coreshellnp.py @@ -22,17 +22,15 @@ """ import numpy -from scipy.optimize import leastsq - from pyobjcryst import loadCrystal +from scipy.optimize import leastsq +from diffpy.srfit.fitbase import FitContribution, FitRecipe, FitResults, Profile from diffpy.srfit.pdf import PDFGenerator, PDFParser -from diffpy.srfit.fitbase import Profile -from diffpy.srfit.fitbase import FitContribution, FitRecipe -from diffpy.srfit.fitbase import FitResults ####### Example Code + def makeRecipe(stru1, stru2, datname): """Create a fitting recipe for crystalline PDF data.""" @@ -43,7 +41,7 @@ def makeRecipe(stru1, stru2, datname): parser = PDFParser() parser.parseFile(datname) profile.loadParsedData(parser) - profile.setCalculationRange(xmin=1.5, xmax = 45, dx = 0.1) + profile.setCalculationRange(xmin=1.5, xmax=45, dx=0.1) ## The ProfileGenerator # In order to fit the core and shell phases simultaneously, we must use two @@ -66,15 +64,16 @@ def makeRecipe(stru1, stru2, datname): contribution = FitContribution("cdszns") contribution.addProfileGenerator(generator_cds) contribution.addProfileGenerator(generator_zns) - contribution.setProfile(profile, xname = "r") + contribution.setProfile(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 sphericalCF, shellCF - contribution.registerFunction(sphericalCF, name = "f_CdS") - contribution.registerFunction(shellCF, name = "f_ZnS") + from diffpy.srfit.pdf.characteristicfunctions import shellCF, sphericalCF + + contribution.registerFunction(sphericalCF, name="f_CdS") + contribution.registerFunction(shellCF, name="f_ZnS") # Write the fitting equation. We want to sum the PDFs from each phase and # multiply it by a scaling factor. @@ -106,27 +105,28 @@ def makeRecipe(stru1, stru2, datname): # subsequent refinement. phase_cds = generator_cds.phase for par in phase_cds.sgpars.latpars: - recipe.addVar(par, name = par.name + "_cds", tag = "lat") + recipe.addVar(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.addVar(par, 1, name=par.name + "_cds", tag="adp") + recipe.addVar(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.addVar(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.addVar(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.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.addVar(generator_zns.delta2, name="delta2_zns", value=2.5) # Give the recipe away so it can be used! return recipe + def plotResults(recipe): """Plot the results contained within a refined FitRecipe.""" @@ -138,10 +138,11 @@ def plotResults(recipe): diff = g - gcalc + diffzero import pylab - pylab.plot(r,g,'bo',label="G(r) Data") - pylab.plot(r, gcalc,'r-',label="G(r) Fit") - pylab.plot(r,diff,'g-',label="G(r) diff") - pylab.plot(r,diffzero,'k-') + + pylab.plot(r, g, "bo", label="G(r) Data") + pylab.plot(r, gcalc, "r-", label="G(r) Fit") + pylab.plot(r, diff, "g-", label="G(r) diff") + pylab.plot(r, diffzero, "k-") pylab.xlabel(r"$r (\AA)$") pylab.ylabel(r"$G (\AA^{-2})$") pylab.legend(loc=1) @@ -163,6 +164,7 @@ def main(): stru2 = loadCrystal(znsciffile) recipe = makeRecipe(stru1, stru2, data) from diffpy.srfit.fitbase.fithook import PlotFitHook + recipe.pushFitHook(PlotFitHook()) recipe.fithooks[0].verbose = 3 @@ -172,23 +174,23 @@ def main(): # Start with the lattice parameters. In makeRecipe, these were tagged with # "lat". Here is how we use that. recipe.free("lat") - leastsq(recipe.residual, recipe.values, maxfev = 50) + leastsq(recipe.residual, recipe.values, maxfev=50) # Now the scale and phase fraction. recipe.free("scale", "scale_CdS") - leastsq(recipe.residual, recipe.values, maxfev = 50) + leastsq(recipe.residual, recipe.values, maxfev=50) # The ADPs. recipe.free("adp") - leastsq(recipe.residual, recipe.values, maxfev = 100) + leastsq(recipe.residual, recipe.values, maxfev=100) # The delta2 parameters. recipe.free("delta2_cds", "delta2_zns") - leastsq(recipe.residual, recipe.values, maxfev = 50) + leastsq(recipe.residual, recipe.values, maxfev=50) # The shape parameters. recipe.free("radius", "thickness") - leastsq(recipe.residual, recipe.values, maxfev = 50) + leastsq(recipe.residual, recipe.values, maxfev=50) # The positional parameters. recipe.free("xyz") @@ -202,6 +204,7 @@ def main(): plotResults(recipe) return + if __name__ == "__main__": main() diff --git a/doc/examples/crystalpdf.py b/doc/examples/crystalpdf.py index ced49e9a..f410f3c9 100644 --- a/doc/examples/crystalpdf.py +++ b/doc/examples/crystalpdf.py @@ -26,17 +26,15 @@ """ import numpy +from gaussianrecipe import scipyOptimize -from diffpy.structure import Structure +from diffpy.srfit.fitbase import FitContribution, FitRecipe, FitResults, Profile from diffpy.srfit.pdf import PDFGenerator, PDFParser -from diffpy.srfit.fitbase import Profile -from diffpy.srfit.fitbase import FitContribution, FitRecipe -from diffpy.srfit.fitbase import FitResults - -from gaussianrecipe import scipyOptimize +from diffpy.structure import Structure ####### Example Code + def makeRecipe(ciffile, datname): """Create a fitting recipe for crystalline PDF data.""" @@ -53,7 +51,7 @@ def makeRecipe(ciffile, datname): parser = PDFParser() parser.parseFile(datname) profile.loadParsedData(parser) - profile.setCalculationRange(xmax = 20) + profile.setCalculationRange(xmax=20) ## The ProfileGenerator # The PDFGenerator is for configuring and calculating a PDF profile. Here, @@ -72,7 +70,7 @@ def makeRecipe(ciffile, datname): # before. contribution = FitContribution("nickel") contribution.addProfileGenerator(generator) - contribution.setProfile(profile, xname = "r") + contribution.setProfile(profile, xname="r") ## Make the FitRecipe and add the FitContribution. recipe = FitRecipe() @@ -95,6 +93,7 @@ def makeRecipe(ciffile, datname): # documentation for more details. The 'constrainAsSpaceGroup' method may # create new Parameters, which it returns in a SpaceGroupParameters object. from diffpy.srfit.structure import constrainAsSpaceGroup + sgpars = constrainAsSpaceGroup(phase, "Fm-3m") # The SpaceGroupParameters object returned by 'constrainAsSpaceGroup' holds @@ -124,6 +123,7 @@ def makeRecipe(ciffile, datname): # Give the recipe away so it can be used! return recipe + def plotResults(recipe): """Plot the results contained within a refined FitRecipe.""" @@ -135,10 +135,11 @@ def plotResults(recipe): diff = g - gcalc + diffzero import pylab - pylab.plot(r,g,'bo',label="G(r) Data") - pylab.plot(r, gcalc,'r-',label="G(r) Fit") - pylab.plot(r,diff,'g-',label="G(r) diff") - pylab.plot(r,diffzero,'k-') + + pylab.plot(r, g, "bo", label="G(r) Data") + pylab.plot(r, gcalc, "r-", label="G(r) Fit") + pylab.plot(r, diff, "g-", label="G(r) diff") + pylab.plot(r, diffzero, "k-") pylab.xlabel(r"$r (\AA)$") pylab.ylabel(r"$G (\AA^{-2})$") pylab.legend(loc=1) @@ -146,6 +147,7 @@ def plotResults(recipe): pylab.show() return + if __name__ == "__main__": # Make the data and the recipe diff --git a/doc/examples/crystalpdfall.py b/doc/examples/crystalpdfall.py index c79cf6c5..4cd860c1 100644 --- a/doc/examples/crystalpdfall.py +++ b/doc/examples/crystalpdfall.py @@ -20,36 +20,34 @@ """ import numpy - +from gaussianrecipe import scipyOptimize from pyobjcryst import loadCrystal +from diffpy.srfit.fitbase import FitContribution, FitRecipe, FitResults, Profile from diffpy.srfit.pdf import PDFGenerator, PDFParser -from diffpy.srfit.fitbase import Profile -from diffpy.srfit.fitbase import FitContribution, FitRecipe -from diffpy.srfit.fitbase import FitResults - -from gaussianrecipe import scipyOptimize ####### Example Code + def makeProfile(datafile): """Make an place data within a Profile.""" profile = Profile() parser = PDFParser() parser.parseFile(datafile) profile.loadParsedData(parser) - profile.setCalculationRange(xmax = 20) + profile.setCalculationRange(xmax=20) return profile + def makeContribution(name, generator, profile): """Make a FitContribution and add a generator and profile.""" contribution = FitContribution(name) contribution.addProfileGenerator(generator) - contribution.setProfile(profile, xname = "r") + contribution.setProfile(profile, xname="r") return contribution -def makeRecipe(ciffile_ni, ciffile_si, xdata_ni, ndata_ni, xdata_si, - xdata_sini): + +def makeRecipe(ciffile_ni, ciffile_si, xdata_ni, ndata_ni, xdata_si, xdata_sini): """Create a fitting recipe for crystalline PDF data.""" ## The Profiles @@ -85,8 +83,7 @@ def makeRecipe(ciffile_ni, ciffile_si, xdata_ni, ndata_ni, xdata_si, xcontribution_ni = makeContribution("xnickel", xgenerator_ni, xprofile_ni) xcontribution_si = makeContribution("xsilicon", xgenerator_si, xprofile_si) ncontribution_ni = makeContribution("nnickel", ngenerator_ni, nprofile_ni) - xcontribution_sini = makeContribution("xsini", xgenerator_sini_ni, - xprofile_sini) + xcontribution_sini = makeContribution("xsini", xgenerator_sini_ni, xprofile_sini) xcontribution_sini.addProfileGenerator(xgenerator_sini_si) xcontribution_sini.setEquation("scale * (xG_sini_ni + xG_sini_si)") @@ -105,22 +102,22 @@ def makeRecipe(ciffile_ni, ciffile_si, xdata_ni, ndata_ni, xdata_si, # Now we vary and constrain Parameters as before. for par in phase_ni.sgpars: - recipe.addVar(par, name = par.name + "_ni") + recipe.addVar(par, name=par.name + "_ni") delta2_ni = recipe.newVar("delta2_ni", 2.5) recipe.constrain(xgenerator_ni.delta2, delta2_ni) recipe.constrain(ngenerator_ni.delta2, delta2_ni) recipe.constrain(xgenerator_sini_ni.delta2, delta2_ni) for par in phase_si.sgpars: - recipe.addVar(par, name = par.name + "_si") + recipe.addVar(par, name=par.name + "_si") delta2_si = recipe.newVar("delta2_si", 2.5) recipe.constrain(xgenerator_si.delta2, delta2_si) recipe.constrain(xgenerator_sini_si.delta2, delta2_si) # Now the experimental parameters - recipe.addVar(xgenerator_ni.scale, name = "xscale_ni") - recipe.addVar(xgenerator_si.scale, name = "xscale_si") - recipe.addVar(ngenerator_ni.scale, name = "nscale_ni") + recipe.addVar(xgenerator_ni.scale, name="xscale_ni") + recipe.addVar(xgenerator_si.scale, name="xscale_si") + recipe.addVar(ngenerator_ni.scale, name="nscale_ni") recipe.addVar(xcontribution_sini.scale, 1.0, "xscale_sini") recipe.newVar("pscale_sini_ni", 0.8) recipe.constrain(xgenerator_sini_ni.scale, "pscale_sini_ni") @@ -137,6 +134,7 @@ def makeRecipe(ciffile_ni, ciffile_si, xdata_ni, ndata_ni, xdata_si, # Give the recipe away so it can be used! return recipe + def plotResults(recipe): """Plot the results contained within a refined FitRecipe.""" @@ -145,65 +143,66 @@ def plotResults(recipe): xr_ni = xnickel.profile.x xg_ni = xnickel.profile.y xgcalc_ni = xnickel.profile.ycalc - xdiffzero_ni = -0.8 * max(xg_ni) * numpy.ones_like(xg_ni) + xdiffzero_ni = -0.8 * max(xg_ni) * numpy.ones_like(xg_ni) xdiff_ni = xg_ni - xgcalc_ni + xdiffzero_ni xsilicon = recipe.xsilicon xr_si = xsilicon.profile.x xg_si = xsilicon.profile.y xgcalc_si = xsilicon.profile.ycalc - xdiffzero_si = -0.8 * max(xg_si) * numpy.ones_like(xg_si) + xdiffzero_si = -0.8 * max(xg_si) * numpy.ones_like(xg_si) xdiff_si = xg_si - xgcalc_si + xdiffzero_si nnickel = recipe.nnickel nr_ni = nnickel.profile.x ng_ni = nnickel.profile.y ngcalc_ni = nnickel.profile.ycalc - ndiffzero_ni = -0.8 * max(ng_ni) * numpy.ones_like(ng_ni) + ndiffzero_ni = -0.8 * max(ng_ni) * numpy.ones_like(ng_ni) ndiff_ni = ng_ni - ngcalc_ni + ndiffzero_ni xsini = recipe.xsini xr_sini = xsini.profile.x xg_sini = xsini.profile.y xgcalc_sini = xsini.profile.ycalc - xdiffzero_sini = -0.8 * max(xg_sini) * numpy.ones_like(xg_sini) + xdiffzero_sini = -0.8 * max(xg_sini) * numpy.ones_like(xg_sini) xdiff_sini = xg_sini - xgcalc_sini + xdiffzero_sini - import pylab + pylab.subplot(2, 2, 1) - pylab.plot(xr_ni,xg_ni,'bo',label="G(r) x-ray nickel Data") - pylab.plot(xr_ni,xgcalc_ni,'r-',label="G(r) x-ray nickel Fit") - pylab.plot(xr_ni,xdiff_ni,'g-',label="G(r) x-ray nickel diff") - pylab.plot(xr_ni,xdiffzero_ni,'k-') + pylab.plot(xr_ni, xg_ni, "bo", label="G(r) x-ray nickel Data") + pylab.plot(xr_ni, xgcalc_ni, "r-", label="G(r) x-ray nickel Fit") + pylab.plot(xr_ni, xdiff_ni, "g-", label="G(r) x-ray nickel diff") + pylab.plot(xr_ni, xdiffzero_ni, "k-") pylab.xlabel(r"$r (\AA)$") pylab.ylabel(r"$G (\AA^{-2})$") pylab.legend(loc=1) pylab.subplot(2, 2, 2) - pylab.plot(xr_si,xg_si,'bo',label="G(r) x-ray silicon Data") - pylab.plot(xr_si,xgcalc_si,'r-',label="G(r) x-ray silicon Fit") - pylab.plot(xr_si,xdiff_si,'g-',label="G(r) x-ray silicon diff") - pylab.plot(xr_si,xdiffzero_si,'k-') + pylab.plot(xr_si, xg_si, "bo", label="G(r) x-ray silicon Data") + pylab.plot(xr_si, xgcalc_si, "r-", label="G(r) x-ray silicon Fit") + pylab.plot(xr_si, xdiff_si, "g-", label="G(r) x-ray silicon diff") + pylab.plot(xr_si, xdiffzero_si, "k-") pylab.legend(loc=1) pylab.subplot(2, 2, 3) - pylab.plot(nr_ni,ng_ni,'bo',label="G(r) neutron nickel Data") - pylab.plot(nr_ni,ngcalc_ni,'r-',label="G(r) neutron nickel Fit") - pylab.plot(nr_ni,ndiff_ni,'g-',label="G(r) neutron nickel diff") - pylab.plot(nr_ni,ndiffzero_ni,'k-') + pylab.plot(nr_ni, ng_ni, "bo", label="G(r) neutron nickel Data") + pylab.plot(nr_ni, ngcalc_ni, "r-", label="G(r) neutron nickel Fit") + pylab.plot(nr_ni, ndiff_ni, "g-", label="G(r) neutron nickel diff") + pylab.plot(nr_ni, ndiffzero_ni, "k-") pylab.legend(loc=1) pylab.subplot(2, 2, 4) - pylab.plot(xr_sini,xg_sini,'bo',label="G(r) x-ray sini Data") - pylab.plot(xr_sini,xgcalc_sini,'r-',label="G(r) x-ray sini Fit") - pylab.plot(xr_sini,xdiff_sini,'g-',label="G(r) x-ray sini diff") - pylab.plot(xr_sini,xdiffzero_sini,'k-') + pylab.plot(xr_sini, xg_sini, "bo", label="G(r) x-ray sini Data") + pylab.plot(xr_sini, xgcalc_sini, "r-", label="G(r) x-ray sini Fit") + pylab.plot(xr_sini, xdiff_sini, "g-", label="G(r) x-ray sini diff") + pylab.plot(xr_sini, xdiffzero_sini, "k-") pylab.legend(loc=1) pylab.show() return + if __name__ == "__main__": # Make the data and the recipe @@ -215,8 +214,7 @@ def plotResults(recipe): xdata_sini = "data/si90ni10-q27r60-xray.gr" # Make the recipe - recipe = makeRecipe(ciffile_ni, ciffile_si, xdata_ni, ndata_ni, xdata_si, - xdata_sini) + recipe = makeRecipe(ciffile_ni, ciffile_si, xdata_ni, ndata_ni, xdata_si, xdata_sini) # Optimize scipyOptimize(recipe) diff --git a/doc/examples/crystalpdfobjcryst.py b/doc/examples/crystalpdfobjcryst.py index c7201493..103762bf 100644 --- a/doc/examples/crystalpdfobjcryst.py +++ b/doc/examples/crystalpdfobjcryst.py @@ -20,18 +20,16 @@ by the ObjCrystCrystalParSet structure adapter. """ +from crystalpdf import plotResults +from gaussianrecipe import scipyOptimize from pyobjcryst import loadCrystal +from diffpy.srfit.fitbase import FitContribution, FitRecipe, FitResults, Profile from diffpy.srfit.pdf import PDFGenerator, PDFParser -from diffpy.srfit.fitbase import Profile -from diffpy.srfit.fitbase import FitContribution, FitRecipe -from diffpy.srfit.fitbase import FitResults - -from gaussianrecipe import scipyOptimize -from crystalpdf import plotResults ####### Example Code + def makeRecipe(ciffile, datname): """Create a fitting recipe for crystalline PDF data.""" @@ -46,7 +44,7 @@ def makeRecipe(ciffile, datname): parser = PDFParser() parser.parseFile(datname) profile.loadParsedData(parser) - profile.setCalculationRange(xmax = 20) + profile.setCalculationRange(xmax=20) ## The ProfileGenerator # This time we use the CreateCrystalFromCIF method of pyobjcryst.crystal to @@ -60,7 +58,7 @@ def makeRecipe(ciffile, datname): ## The FitContribution contribution = FitContribution("nickel") contribution.addProfileGenerator(generator) - contribution.setProfile(profile, xname = "r") + contribution.setProfile(profile, xname="r") # Make the FitRecipe and add the FitContribution. recipe = FitRecipe() @@ -89,7 +87,7 @@ def makeRecipe(ciffile, datname): for par in phase.sgpars: recipe.addVar(par) # set the initial thermal factor to a non-zero value - assert hasattr(recipe, 'B11_0') + assert hasattr(recipe, "B11_0") recipe.B11_0 = 0.1 # We now select non-structural parameters to refine. @@ -103,6 +101,7 @@ def makeRecipe(ciffile, datname): # Give the recipe away so it can be used! return recipe + if __name__ == "__main__": # Make the data and the recipe diff --git a/doc/examples/crystalpdftwodata.py b/doc/examples/crystalpdftwodata.py index a43da784..f8b21362 100644 --- a/doc/examples/crystalpdftwodata.py +++ b/doc/examples/crystalpdftwodata.py @@ -22,18 +22,15 @@ """ import numpy - +from gaussianrecipe import scipyOptimize from pyobjcryst import loadCrystal +from diffpy.srfit.fitbase import FitContribution, FitRecipe, FitResults, Profile from diffpy.srfit.pdf import PDFGenerator, PDFParser -from diffpy.srfit.fitbase import Profile -from diffpy.srfit.fitbase import FitContribution, FitRecipe -from diffpy.srfit.fitbase import FitResults - -from gaussianrecipe import scipyOptimize ####### Example Code + def makeRecipe(ciffile, xdatname, ndatname): """Create a fitting recipe for crystalline PDF data.""" @@ -47,12 +44,12 @@ def makeRecipe(ciffile, xdatname, ndatname): parser = PDFParser() parser.parseFile(xdatname) xprofile.loadParsedData(parser) - xprofile.setCalculationRange(xmax = 20) + xprofile.setCalculationRange(xmax=20) parser = PDFParser() parser.parseFile(ndatname) nprofile.loadParsedData(parser) - nprofile.setCalculationRange(xmax = 20) + nprofile.setCalculationRange(xmax=20) ## The ProfileGenerators # We need one of these for the x-ray data. @@ -83,11 +80,11 @@ def makeRecipe(ciffile, xdatname, ndatname): # We associate the x-ray PDFGenerator and Profile in one FitContribution... xcontribution = FitContribution("xnickel") xcontribution.addProfileGenerator(xgenerator) - xcontribution.setProfile(xprofile, xname = "r") + xcontribution.setProfile(xprofile, xname="r") # and the neutron objects in another. ncontribution = FitContribution("nnickel") ncontribution.addProfileGenerator(ngenerator) - ncontribution.setProfile(nprofile, xname = "r") + ncontribution.setProfile(nprofile, xname="r") # This example is different than the previous ones in that we are composing # a residual function from other residuals (one for the x-ray contribution @@ -132,6 +129,7 @@ def makeRecipe(ciffile, xdatname, ndatname): # Give the recipe away so it can be used! return recipe + def plotResults(recipe): """Plot the results contained within a refined FitRecipe.""" @@ -149,18 +147,19 @@ def plotResults(recipe): ndiff = ng - ngcalc + ndiffzero import pylab + pylab.subplot(2, 1, 1) - pylab.plot(xr,xg,'bo',label="G(r) x-ray Data") - pylab.plot(xr,xgcalc,'r-',label="G(r) x-ray Fit") - pylab.plot(xr,xdiff,'g-',label="G(r) x-ray diff") - pylab.plot(xr,xdiffzero,'k-') + pylab.plot(xr, xg, "bo", label="G(r) x-ray Data") + pylab.plot(xr, xgcalc, "r-", label="G(r) x-ray Fit") + pylab.plot(xr, xdiff, "g-", label="G(r) x-ray diff") + pylab.plot(xr, xdiffzero, "k-") pylab.legend(loc=1) pylab.subplot(2, 1, 2) - pylab.plot(nr,ng,'bo',label="G(r) neutron Data") - pylab.plot(nr,ngcalc,'r-',label="G(r) neutron Fit") - pylab.plot(nr,ndiff,'g-',label="G(r) neutron diff") - pylab.plot(nr,ndiffzero,'k-') + pylab.plot(nr, ng, "bo", label="G(r) neutron Data") + pylab.plot(nr, ngcalc, "r-", label="G(r) neutron Fit") + pylab.plot(nr, ndiff, "g-", label="G(r) neutron diff") + pylab.plot(nr, ndiffzero, "k-") pylab.xlabel(r"$r (\AA)$") pylab.ylabel(r"$G (\AA^{-2})$") pylab.legend(loc=1) @@ -168,6 +167,7 @@ def plotResults(recipe): pylab.show() return + if __name__ == "__main__": # Make the data and the recipe diff --git a/doc/examples/crystalpdftwophase.py b/doc/examples/crystalpdftwophase.py index df7cce77..57f83e53 100644 --- a/doc/examples/crystalpdftwophase.py +++ b/doc/examples/crystalpdftwophase.py @@ -22,18 +22,15 @@ """ import numpy - +from gaussianrecipe import scipyOptimize from pyobjcryst import loadCrystal +from diffpy.srfit.fitbase import FitContribution, FitRecipe, FitResults, Profile from diffpy.srfit.pdf import PDFGenerator, PDFParser -from diffpy.srfit.fitbase import Profile -from diffpy.srfit.fitbase import FitContribution, FitRecipe -from diffpy.srfit.fitbase import FitResults - -from gaussianrecipe import scipyOptimize ####### Example Code + def makeRecipe(niciffile, siciffile, datname): """Create a fitting recipe for crystalline PDF data.""" @@ -44,7 +41,7 @@ def makeRecipe(niciffile, siciffile, datname): parser = PDFParser() parser.parseFile(datname) profile.loadParsedData(parser) - profile.setCalculationRange(xmax = 20) + profile.setCalculationRange(xmax=20) ## The ProfileGenerator # In order to fit two phases simultaneously, we must use two PDFGenerators. @@ -72,7 +69,7 @@ def makeRecipe(niciffile, siciffile, datname): contribution = FitContribution("nisi") contribution.addProfileGenerator(generator_ni) contribution.addProfileGenerator(generator_si) - contribution.setProfile(profile, xname = "r") + contribution.setProfile(profile, xname="r") # Write the fitting equation. We want to sum the PDFs from each phase and # multiply it by a scaling factor. We also want a certain phase scaling @@ -105,13 +102,13 @@ def makeRecipe(niciffile, siciffile, datname): # First the nickel parameters phase_ni = generator_ni.phase for par in phase_ni.sgpars: - recipe.addVar(par, name = par.name + "_ni") - recipe.addVar(generator_ni.delta2, name = "delta2_ni") + recipe.addVar(par, name=par.name + "_ni") + recipe.addVar(generator_ni.delta2, name="delta2_ni") # Next the silicon parameters phase_si = generator_si.phase for par in phase_si.sgpars: - recipe.addVar(par, name = par.name + "_si") - recipe.addVar(generator_si.delta2, name = "delta2_si") + recipe.addVar(par, name=par.name + "_si") + recipe.addVar(generator_si.delta2, name="delta2_si") # We have prior information from the earlier examples so we'll use it here # in the form of restraints. @@ -121,22 +118,23 @@ def makeRecipe(niciffile, siciffile, datname): # derived has no uncertainty. Thus, we will tell the recipe to scale the # residual, which means that it will be weighted as much as the average # data point during the fit. - recipe.restrain("a_ni", lb = 3.527, ub = 3.527, scaled = True) + recipe.restrain("a_ni", lb=3.527, ub=3.527, scaled=True) # Now we do the same with the delta2 and Biso parameters (remember that # Biso = 8*pi**2*Uiso) - recipe.restrain("delta2_ni", lb = 2.22, ub = 2.22, scaled = True) - recipe.restrain("Biso_0_ni", lb = 0.454, ub = 0.454, scaled = True) + recipe.restrain("delta2_ni", lb=2.22, ub=2.22, scaled=True) + recipe.restrain("Biso_0_ni", lb=0.454, ub=0.454, scaled=True) # # We can do the same with the silicon values. We haven't done a thorough # job of measuring the uncertainties in the results, so we'll scale these # as well. - recipe.restrain("a_si", lb = 5.430, ub = 5.430, scaled = True) - recipe.restrain("delta2_si", lb = 3.54, ub = 3.54, scaled = True) - recipe.restrain("Biso_0_si", lb = 0.645, ub = 0.645, scaled = True) + recipe.restrain("a_si", lb=5.430, ub=5.430, scaled=True) + recipe.restrain("delta2_si", lb=3.54, ub=3.54, scaled=True) + recipe.restrain("Biso_0_si", lb=0.645, ub=0.645, scaled=True) # Give the recipe away so it can be used! return recipe + def plotResults(recipe): """Plot the results contained within a refined FitRecipe.""" @@ -148,10 +146,11 @@ def plotResults(recipe): diff = g - gcalc + diffzero import pylab - pylab.plot(r,g,'bo',label="G(r) Data") - pylab.plot(r, gcalc,'r-',label="G(r) Fit") - pylab.plot(r,diff,'g-',label="G(r) diff") - pylab.plot(r,diffzero,'k-') + + pylab.plot(r, g, "bo", label="G(r) Data") + pylab.plot(r, gcalc, "r-", label="G(r) Fit") + pylab.plot(r, diff, "g-", label="G(r) diff") + pylab.plot(r, diffzero, "k-") pylab.xlabel(r"$r (\AA)$") pylab.ylabel(r"$G (\AA^{-2})$") pylab.legend(loc=1) diff --git a/doc/examples/data/ni.iq b/doc/examples/data/ni.iq index 917301a1..56594ba3 100644 --- a/doc/examples/data/ni.iq +++ b/doc/examples/data/ni.iq @@ -2462,4 +2462,3 @@ 26.123511 0 26.133371 0 26.143228 0 - diff --git a/doc/examples/debyemodel.py b/doc/examples/debyemodel.py index 79bf7add..abdcd169 100644 --- a/doc/examples/debyemodel.py +++ b/doc/examples/debyemodel.py @@ -34,11 +34,10 @@ """ import numpy - -from diffpy.srfit.fitbase import FitContribution, FitRecipe, Profile, FitResults - from gaussianrecipe import scipyOptimize +from diffpy.srfit.fitbase import FitContribution, FitRecipe, FitResults, Profile + # The data data = """\ 015.0 0.00334 0.00013 @@ -56,6 +55,7 @@ ####### Example Code + def makeRecipe(): """Make the recipe for the fit. @@ -86,7 +86,7 @@ def makeRecipe(): # Load data and add it to the profile. It is our responsibility to get our # data into the profile. - xydy = numpy.array(map(float, data.split()), dtype=float).reshape(-1,3) + xydy = numpy.array(map(float, data.split()), dtype=float).reshape(-1, 3) x, y, dy = numpy.hsplit(xydy, 3) profile.setObservedProfile(x, y, dy) @@ -146,11 +146,12 @@ def makeRecipe(): # 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.restrain(recipe.offset, lb=0, scaled=True) # We're done setting up the recipe. We can now do other things with it. return recipe + def plotResults(recipe): """Plot the results contained within a refined FitRecipe.""" @@ -163,15 +164,17 @@ def plotResults(recipe): Ucalc = recipe.pb.profile.ycalc import pylab - pylab.plot(T,U,'o',label="Pb $U_{iso}$ Data") - pylab.plot(T,Ucalc) + + pylab.plot(T, U, "o", label="Pb $U_{iso}$ Data") + pylab.plot(T, Ucalc) pylab.xlabel("T (K)") pylab.ylabel(r"$U_{iso} (\AA^2)$") - pylab.legend(loc = (0.0,0.8)) + pylab.legend(loc=(0.0, 0.8)) pylab.show() return + def main(): """The workflow of creating, running and inspecting a fit.""" @@ -197,12 +200,14 @@ def main(): # as we treat them as if existing in some external library that we cannot # modify. + def debye(T, m, thetaD): """A wrapped version of 'adps' that can handle an array of T-values.""" y = numpy.array([adps(m, thetaD, x) for x in T]) return y -def adps(m,thetaD,T): + +def adps(m, thetaD, T): """Calculates atomic displacement factors within the Debye model = (3h^2/4 pi^2 m kB thetaD)(phi(thetaD/T)/(ThetaD/T) + 1/4) @@ -216,9 +221,9 @@ def adps(m,thetaD,T): Uiso -- float -- the thermal factor from the Debye recipe at temp T """ - h = 6.6260755e-34 # Planck's constant. J.s of m^2.kg/s + h = 6.6260755e-34 # Planck's constant. J.s of m^2.kg/s kB = 1.3806503e-23 # Boltzmann's constant. J/K - amu = 1.66053886e-27 # Atomic mass unit. kg + amu = 1.66053886e-27 # Atomic mass unit. kg def __phi(x): """evaluates the phi integral needed in Debye calculation @@ -232,26 +237,24 @@ def __phi(x): phi -- float -- value of the phi function """ - def __debyeKernel(xi): - """function needed by debye calculators - """ - y = xi/(numpy.exp(xi)-1) + def __debyeKernel(xi): + """function needed by debye calculators""" + y = xi / (numpy.exp(xi) - 1) return y import scipy.integrate int = scipy.integrate.quad(__debyeKernel, 0, x) - phi = (1/x) * int[0] + phi = (1 / x) * int[0] return phi - m = m * amu - u2 = (3*h**2 / (4 * numpy.pi**2 *m *kB *thetaD))*\ - (__phi(thetaD/T)/(thetaD/T) + 1./4.) + u2 = (3 * h**2 / (4 * numpy.pi**2 * m * kB * thetaD)) * (__phi(thetaD / T) / (thetaD / T) + 1.0 / 4.0) + + return u2 * 1e20 - return u2*1e20 if __name__ == "__main__": diff --git a/doc/examples/debyemodelII.py b/doc/examples/debyemodelII.py index 0e5e3542..fcfa841d 100644 --- a/doc/examples/debyemodelII.py +++ b/doc/examples/debyemodelII.py @@ -34,12 +34,13 @@ done. """ -from diffpy.srfit.fitbase import FitRecipe, FitResults - from debyemodel import makeRecipe, scipyOptimize +from diffpy.srfit.fitbase import FitRecipe, FitResults + ####### Example Code + def makeRecipeII(): """Make a recipe for fitting low and high temperature regions. @@ -81,8 +82,8 @@ def makeRecipeII(): # 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.addVar(recipe.lowT.offset, name="lowToffset") + recipe.addVar(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) @@ -90,6 +91,7 @@ def makeRecipeII(): recipe.constrain(recipe.highT.thetaD, "thetaD") return recipe + def plotResults(recipe): """Display the results contained within a refined FitRecipe.""" @@ -99,8 +101,8 @@ def plotResults(recipe): # 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') + 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 @@ -114,18 +116,20 @@ def plotResults(recipe): # 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) - pylab.plot(T,lowU,label=lbl1) - pylab.plot(T,highU,label=lbl2) + + 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) + 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(loc = (0.0,0.8)) + pylab.legend(loc=(0.0, 0.8)) pylab.show() return + def main(): # Create the recipe diff --git a/doc/examples/ellipsoidsas.py b/doc/examples/ellipsoidsas.py index 87c4d016..430f964a 100644 --- a/doc/examples/ellipsoidsas.py +++ b/doc/examples/ellipsoidsas.py @@ -16,14 +16,14 @@ """Example of a refinement of SAS I(Q) data to an ellipsoidal model. """ -from diffpy.srfit.sas import SASGenerator, SASParser -from diffpy.srfit.fitbase import FitContribution, FitRecipe -from diffpy.srfit.fitbase import FitResults, Profile - from gaussianrecipe import scipyOptimize +from diffpy.srfit.fitbase import FitContribution, FitRecipe, FitResults, Profile +from diffpy.srfit.sas import SASGenerator, SASParser + ####### Example Code + def makeRecipe(datname): """Create a fitting recipe for ellipsoidal SAS data.""" @@ -45,6 +45,7 @@ def makeRecipe(datname): # data. The documentation for the various sas models can be found at # http://www.sasview.org. from sas.models.EllipsoidModel import EllipsoidModel + model = EllipsoidModel() generator = SASGenerator("generator", model) @@ -53,7 +54,7 @@ def makeRecipe(datname): # before. contribution = FitContribution("ellipsoid") contribution.addProfileGenerator(generator) - contribution.setProfile(profile, xname = "q") + contribution.setProfile(profile, xname="q") # We want to fit the log of the signal to the log of the data so that the # higher-Q information remains significant. There are no I(Q) uncertainty @@ -81,6 +82,7 @@ def makeRecipe(datname): # Give the recipe away so it can be used! return recipe + def plotResults(recipe): """Plot the results contained within a refined FitRecipe.""" @@ -91,9 +93,10 @@ def plotResults(recipe): diff = y - ycalc + min(y) import pylab - pylab.loglog(r,y,'bo',label="I(Q) Data") - pylab.loglog(r, ycalc,'r-',label="I(Q) Fit") - pylab.loglog(r,diff,'g-',label="I(Q) diff") + + pylab.loglog(r, y, "bo", label="I(Q) Data") + pylab.loglog(r, ycalc, "r-", label="I(Q) Fit") + pylab.loglog(r, diff, "g-", label="I(Q) diff") pylab.xlabel(r"$Q (\AA^{-1})$") pylab.ylabel("$I (arb. units)$") pylab.legend(loc=1) @@ -101,6 +104,7 @@ def plotResults(recipe): pylab.show() return + if __name__ == "__main__": # Make the data and the recipe diff --git a/doc/examples/gaussiangenerator.py b/doc/examples/gaussiangenerator.py index 7b0818b8..cdf0a7fa 100644 --- a/doc/examples/gaussiangenerator.py +++ b/doc/examples/gaussiangenerator.py @@ -41,11 +41,11 @@ from numpy import exp -from diffpy.srfit.fitbase import ProfileGenerator, Profile -from diffpy.srfit.fitbase import FitContribution, FitRecipe +from diffpy.srfit.fitbase import FitContribution, FitRecipe, Profile, ProfileGenerator ####### Example Code + class GaussianGenerator(ProfileGenerator): """A class for calculating a Gaussian profile. @@ -86,9 +86,9 @@ def __init__(self, name): # ProfileGenerator. The signature is # _newParameter(name, value). # See the API for full details. - self._newParameter('A', 1.0) - self._newParameter('x0', 0.0) - self._newParameter('sigma', 1.0) + self._newParameter("A", 1.0) + self._newParameter("x0", 0.0) + self._newParameter("sigma", 1.0) return def __call__(self, x): @@ -107,13 +107,15 @@ def __call__(self, x): # Now we can use them. Note that we imported exp from numpy at the top # of the module. - y = A * exp(-0.5*(x-x0)**2/sigma**2) + y = A * exp(-0.5 * (x - x0) ** 2 / sigma**2) # Now return the value. return y + # End class GaussianGenerator + def makeRecipe(): """Create a recipe that uses the GaussianGenerator. @@ -159,7 +161,7 @@ def makeRecipe(): # gaussianrecipe.py so we can expect the same output. recipe.addVar(generator.A, 1) recipe.addVar(generator.x0, 5) - recipe.addVar(generator.sigma, name = "sig") + recipe.addVar(generator.sigma, name="sig") recipe.sig.value = 1 # Give the recipe away so it can be used! @@ -171,6 +173,7 @@ def makeRecipe(): # We can use main from gaussianrecipe.py, since this doesn't care if we use # a ProfileGenerator or not. from gaussianrecipe import main + main() # End of file diff --git a/doc/examples/gaussianrecipe.py b/doc/examples/gaussianrecipe.py index b4bb404d..7e1ed938 100644 --- a/doc/examples/gaussianrecipe.py +++ b/doc/examples/gaussianrecipe.py @@ -46,10 +46,11 @@ from __future__ import print_function -from diffpy.srfit.fitbase import FitContribution, FitRecipe, Profile, FitResults +from diffpy.srfit.fitbase import FitContribution, FitRecipe, FitResults, Profile ####### Example Code + def main(): """The workflow of creating, running and inspecting a fit.""" @@ -150,11 +151,12 @@ def makeRecipe(): # 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.addVar(contribution.sigma, name="sig") recipe.sig.value = 1 return recipe + def scipyOptimize(recipe): """Optimize the recipe created above using scipy. @@ -169,11 +171,13 @@ def scipyOptimize(recipe): # (recipe.residual) and the starting values of the Variables # (recipe.getValues()). from scipy.optimize.minpack import leastsq + print("Fit using scipy's LM optimizer") leastsq(recipe.residual, recipe.getValues()) return + def plotResults(recipe): """Plot the results contained within a refined FitRecipe.""" @@ -189,15 +193,17 @@ def plotResults(recipe): # 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(loc = (0.0,0.8)) + + pylab.plot(x, y, "b.", label="observed Gaussian") + pylab.plot(x, ycalc, "g-", label="calculated Gaussian") + pylab.legend(loc=(0.0, 0.8)) pylab.xlabel("x") pylab.ylabel("y") pylab.show() return + if __name__ == "__main__": main() diff --git a/doc/examples/interface.py b/doc/examples/interface.py index 106af7a2..1f33ad4e 100644 --- a/doc/examples/interface.py +++ b/doc/examples/interface.py @@ -19,10 +19,11 @@ the diffpy.srfit.interface.interface.py module. """ -from diffpy.srfit.fitbase import FitContribution, FitRecipe, Profile, FitResults +from diffpy.srfit.fitbase import FitContribution, FitRecipe, FitResults, Profile ####### Example Code + def main(): p = Profile() @@ -47,11 +48,12 @@ def main(): # loosely tying parameters to a value. r = FitRecipe() r |= c - r += (c.A, 0.5), (c.x0, 5), 'sig' - r *= c.sigma, 'sig' + r += (c.A, 0.5), (c.x0, 5), "sig" + r *= c.sigma, "sig" r %= c.A, 0.5, 0.5 from gaussianrecipe import scipyOptimize + scipyOptimize(r) res = FitResults(r) @@ -59,6 +61,7 @@ def main(): res.printResults() # Plot the results. from gaussianrecipe import plotResults + plotResults(r) return diff --git a/doc/examples/npintensity.py b/doc/examples/npintensity.py index 91a2b55d..f4988e9a 100644 --- a/doc/examples/npintensity.py +++ b/doc/examples/npintensity.py @@ -45,16 +45,14 @@ from __future__ import print_function import numpy +from gaussianrecipe import scipyOptimize -from diffpy.srfit.fitbase import ProfileGenerator, Profile -from diffpy.srfit.fitbase import FitContribution, FitRecipe -from diffpy.srfit.fitbase import FitResults +from diffpy.srfit.fitbase import FitContribution, FitRecipe, FitResults, Profile, ProfileGenerator from diffpy.srfit.structure.diffpyparset import DiffpyStructureParSet -from gaussianrecipe import scipyOptimize - ####### Example Code + class IntensityGenerator(ProfileGenerator): """A class for calculating intensity using the Debye equation. @@ -136,6 +134,7 @@ def setStructure(self, strufile): """ # Load the structure from file from diffpy.structure import Structure + stru = Structure() stru.read(strufile) @@ -167,6 +166,7 @@ def __call__(self, q): print("iofq called", self.count) return iofq(self.phase.stru, q) + # End class IntensityGenerator @@ -200,7 +200,7 @@ def makeRecipe(strufile, datname): # use it in equations with this name. contribution = FitContribution("bucky") contribution.addProfileGenerator(generator) - contribution.setProfile(profile, xname = "q") + contribution.setProfile(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 @@ -233,8 +233,9 @@ def makeRecipe(strufile, datname): # function and registering it with the FitContribution. pi = numpy.pi exp = numpy.exp + def gaussian(q, q0, width): - return 1/(2*pi*width**2)**0.5 * exp(-0.5 * ((q-q0)/width)**2) + return 1 / (2 * pi * width**2) ** 0.5 * exp(-0.5 * ((q - q0) / width) ** 2) # This registers the python function and extracts the name and creates # Parameters from the arguments. @@ -294,6 +295,7 @@ def gaussian(q, q0, width): # Give the recipe away so it can be used! return recipe + def main(): # Make the data and the recipe @@ -315,14 +317,15 @@ def main(): # 'iofq' from the IntensityGenerator. 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) + footer = "iofq called %i%% of the time" % int(100.0 * calcount / rescount) + res.printResults(footer=footer) # Plot! plotResults(recipe) return + def plotResults(recipe): """Plot the results contained within a refined FitRecipe.""" @@ -335,10 +338,11 @@ def plotResults(recipe): diff = I - Icalc import pylab - pylab.plot(q,I,'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.plot(q, I, "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) @@ -371,9 +375,9 @@ def iofq(S, q): # The precision of distance measurements deltad = 1e-6 - dmult = int(1/deltad) + dmult = int(1 / deltad) deltau = deltad**2 - umult = int(1/deltau) + umult = int(1 / deltau) pairdict = {} elcount = {} @@ -395,11 +399,11 @@ def iofq(S, q): # Get the distance to the desired precision d = S.distance(i, j) - D = int(d*dmult) + D = int(d * dmult) # Get the DW factor to the same precision ss = S[i].Uisoequiv + S[j].Uisoequiv - SS = int(ss*umult) + SS = int(ss * umult) # Record the multiplicity of this pair key = (els[0], els[1], D, SS) @@ -439,6 +443,7 @@ def iofq(S, q): return y + def getXScatteringFactor(el, q): """Get the x-ray scattering factor for an element over the q range. @@ -447,15 +452,17 @@ def getXScatteringFactor(el, q): """ try: import cctbx.eltbx.xray_scattering as xray + wk1995 = xray.wk1995(el) g = wk1995.fetch() # at_stol - at sin(theta)/lambda = Q/(4*pi) - f = numpy.asarray( map( g.at_stol, q/(4*numpy.pi) ) ) + f = numpy.asarray(map(g.at_stol, q / (4 * numpy.pi))) return f except ImportError: return 1 -def makeData(strufile, q, datname, scale, a, Uiso, sig, bkgc, nl = 1): + +def makeData(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 @@ -474,6 +481,7 @@ def makeData(strufile, q, datname, scale, a, Uiso, sig, bkgc, nl = 1): """ from diffpy.structure import Structure + S = Structure() S.read(strufile) @@ -487,11 +495,11 @@ def makeData(strufile, q, datname, scale, a, Uiso, sig, bkgc, nl = 1): # We want to broaden the peaks as well. This simulates instrument effects. q0 = q[len(q) // 2] - g = numpy.exp(-0.5*((q-q0)/sig)**2) - y = numpy.convolve(y, g, mode='same')/sum(g) + g = numpy.exp(-0.5 * ((q - q0) / sig) ** 2) + y = numpy.convolve(y, g, mode="same") / sum(g) # Add a polynomial background. - bkgd = (q + bkgc)**2 * (1.5*max(q) - q)**5 + bkgd = (q + bkgc) ** 2 * (1.5 * max(q) - q) ** 5 bkgd *= 0.2 * max(y) / max(bkgd) y += bkgd @@ -500,11 +508,11 @@ def makeData(strufile, q, datname, scale, a, Uiso, sig, bkgc, nl = 1): y *= scale # Calculate the uncertainty - u = (y/nl)**0.5 + u = (y / nl) ** 0.5 # And apply the noise if nl > 0: - y = numpy.random.poisson(y*nl) / nl + y = numpy.random.poisson(y * nl) / nl # Now save it numpy.savetxt(datname, numpy.transpose([q, y, u])) diff --git a/doc/examples/npintensityII.py b/doc/examples/npintensityII.py index 7ab98dce..27623c3c 100644 --- a/doc/examples/npintensityII.py +++ b/doc/examples/npintensityII.py @@ -35,15 +35,14 @@ """ import numpy - -from diffpy.srfit.fitbase import FitContribution, FitRecipe, Profile, FitResults -from npintensity import IntensityGenerator -from npintensity import makeData - from gaussianrecipe import scipyOptimize +from npintensity import IntensityGenerator, makeData + +from diffpy.srfit.fitbase import FitContribution, FitRecipe, FitResults, Profile ####### Example Code + def makeRecipe(strufile, datname1, datname2): """Create a recipe that uses the IntensityGenerator. @@ -85,10 +84,10 @@ def makeRecipe(strufile, datname1, datname2): # Create the FitContributions. contribution1 = FitContribution("bucky1") contribution1.addProfileGenerator(generator1) - contribution1.setProfile(profile1, xname = "q") + contribution1.setProfile(profile1, xname="q") contribution2 = FitContribution("bucky2") contribution2.addProfileGenerator(generator2) - contribution2.setProfile(profile2, xname = "q") + contribution2.setProfile(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 @@ -105,8 +104,9 @@ def makeRecipe(strufile, datname1, datname2): # We will create the broadening function by registering a python function. pi = numpy.pi exp = numpy.exp + def gaussian(q, q0, width): - return 1/(2*pi*width**2)**0.5 * exp(-0.5 * ((q-q0)/width)**2) + return 1 / (2 * pi * width**2) ** 0.5 * exp(-0.5 * ((q - q0) / width) ** 2) contribution1.registerFunction(gaussian) contribution2.registerFunction(gaussian) @@ -128,32 +128,32 @@ def gaussian(q, q0, width): # 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.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") # 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.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") # We can also refine structural parameters. We only have to do this once, # since each generator holds the same DiffpyStructureParSet. @@ -175,6 +175,7 @@ def gaussian(q, q0, width): # Give the recipe away so it can be used! return recipe + def plotResults(recipe): """Plot the results contained within a refined FitRecipe.""" @@ -197,18 +198,19 @@ def plotResults(recipe): 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.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.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) @@ -216,6 +218,7 @@ def plotResults(recipe): pylab.show() return + def main(): # Make two different data sets, each from the same structure, but with @@ -258,6 +261,7 @@ def main(): return + if __name__ == "__main__": main() diff --git a/doc/examples/nppdfcrystal.py b/doc/examples/nppdfcrystal.py index 46ffb848..d637f9e1 100644 --- a/doc/examples/nppdfcrystal.py +++ b/doc/examples/nppdfcrystal.py @@ -26,15 +26,12 @@ """ import numpy - +from gaussianrecipe import scipyOptimize from pyobjcryst import loadCrystal +from diffpy.srfit.fitbase import FitContribution, FitRecipe, FitResults, Profile from diffpy.srfit.pdf import PDFGenerator, PDFParser -from diffpy.srfit.fitbase import Profile -from diffpy.srfit.fitbase import FitContribution, FitRecipe -from diffpy.srfit.fitbase import FitResults -from gaussianrecipe import scipyOptimize def makeRecipe(ciffile, grdata): """Make a recipe to model a crystal-like nanoparticle PDF.""" @@ -45,10 +42,10 @@ def makeRecipe(ciffile, grdata): pdfparser = PDFParser() pdfparser.parseFile(grdata) pdfprofile.loadParsedData(pdfparser) - pdfprofile.setCalculationRange(xmin = 0.1, xmax = 20) + pdfprofile.setCalculationRange(xmin=0.1, xmax=20) pdfcontribution = FitContribution("pdf") - pdfcontribution.setProfile(pdfprofile, xname = "r") + pdfcontribution.setProfile(pdfprofile, xname="r") pdfgenerator = PDFGenerator("G") pdfgenerator.setQmax(30.0) @@ -58,7 +55,8 @@ def makeRecipe(ciffile, grdata): # Register the nanoparticle shape factor. from diffpy.srfit.pdf.characteristicfunctions import sphericalCF - pdfcontribution.registerFunction(sphericalCF, name = "f") + + pdfcontribution.registerFunction(sphericalCF, name="f") # Now we set up the fitting equation. pdfcontribution.setEquation("f * G") @@ -79,6 +77,7 @@ def makeRecipe(ciffile, grdata): return recipe + def plotResults(recipe): """Plot the results contained within a refined FitRecipe.""" @@ -96,12 +95,13 @@ def plotResults(recipe): fr *= max(g) / fr[0] import pylab - pylab.plot(r,g,'bo',label="G(r) Data") - pylab.plot(r, gcryst,'y--',label="G(r) Crystal") - pylab.plot(r, fr,'k--',label="f(r) calculated (scaled)") - pylab.plot(r, gcalc,'r-',label="G(r) Fit") - pylab.plot(r,diff,'g-',label="G(r) diff") - pylab.plot(r, diffzero,'k-') + + pylab.plot(r, g, "bo", label="G(r) Data") + pylab.plot(r, gcryst, "y--", label="G(r) Crystal") + pylab.plot(r, fr, "k--", label="f(r) calculated (scaled)") + pylab.plot(r, gcalc, "r-", label="G(r) Fit") + pylab.plot(r, diff, "g-", label="G(r) diff") + pylab.plot(r, diffzero, "k-") pylab.xlabel(r"$r (\AA)$") pylab.ylabel(r"$G (\AA^{-2})$") pylab.legend(loc=1) @@ -109,6 +109,7 @@ def plotResults(recipe): pylab.show() return + if __name__ == "__main__": ciffile = "data/pb.cif" diff --git a/doc/examples/nppdfobjcryst.py b/doc/examples/nppdfobjcryst.py index bab460fc..472f6460 100644 --- a/doc/examples/nppdfobjcryst.py +++ b/doc/examples/nppdfobjcryst.py @@ -21,13 +21,12 @@ import numpy -from diffpy.srfit.fitbase import Profile -from diffpy.srfit.fitbase import FitContribution, FitRecipe -from diffpy.srfit.fitbase import FitResults +from diffpy.srfit.fitbase import FitContribution, FitRecipe, FitResults, Profile from diffpy.srfit.pdf import DebyePDFGenerator ####### Example Code + def makeRecipe(molecule, datname): """Create a recipe that uses the DebyePDFGenerator.""" @@ -49,7 +48,7 @@ def makeRecipe(molecule, datname): ## The FitContribution contribution = FitContribution("bucky") contribution.addProfileGenerator(generator) - contribution.setProfile(profile, xname = "r") + contribution.setProfile(profile, xname="r") # Make a FitRecipe. recipe = FitRecipe() @@ -92,7 +91,7 @@ def makeRecipe(molecule, datname): # This creates a Parameter that moves the second atom according to the # bond length. Note that each Parameter needs a unique name. - par = c60.addBondLengthParameter("rad%i"%i, center, atom) + par = c60.addBondLengthParameter("rad%i" % i, center, atom) recipe.constrain(par, radius) # Add the correlation term, scale. The scale is too short to effectively @@ -103,6 +102,7 @@ def makeRecipe(molecule, datname): # Give the recipe away so it can be used! return recipe + def plotResults(recipe): """Plot the results contained within a refined FitRecipe.""" @@ -110,14 +110,15 @@ def plotResults(recipe): r = recipe.bucky.profile.x g = recipe.bucky.profile.y gcalc = recipe.bucky.profile.ycalc - diffzero = -0.8 * max(g) * numpy.ones_like(g) + diffzero = -0.8 * max(g) * numpy.ones_like(g) diff = g - gcalc + diffzero import pylab - pylab.plot(r,g,'ob',label="G(r) Data") - pylab.plot(r,gcalc,'-r',label="G(r) Fit") - pylab.plot(r,diff,'-g',label="G(r) diff") - pylab.plot(r,diffzero,'-k') + + pylab.plot(r, g, "ob", label="G(r) Data") + pylab.plot(r, gcalc, "-r", label="G(r) Fit") + pylab.plot(r, diff, "-g", label="G(r) diff") + pylab.plot(r, diffzero, "-k") pylab.xlabel(r"$r (\AA)$") pylab.ylabel(r"$G (\AA^{-2})$") pylab.legend(loc=1) @@ -125,6 +126,7 @@ def plotResults(recipe): pylab.show() return + def main(): molecule = makeC60() @@ -135,6 +137,7 @@ def main(): # Optimize from scipy.optimize import leastsq + leastsq(recipe.residual, recipe.getValues()) # Print results @@ -146,8 +149,8 @@ def main(): return -c60xyz = \ -""" + +c60xyz = """ 3.451266498 0.685000000 0.000000000 3.451266498 -0.685000000 0.000000000 -3.451266498 0.685000000 0.000000000 @@ -210,6 +213,7 @@ def main(): -2.279809890 -2.580456608 -0.724000000 """ + def makeC60(): """Make the C60 molecule using pyobjcryst.""" @@ -236,7 +240,7 @@ def makeC60(): # Add the other atoms. They will be named C1, C2, ..., C60. for i, l in enumerate(c60xyz.strip().splitlines()): x, y, z = map(float, l.split()) - m.AddAtom(x, y, z, sp, "C%i"%(i+1)) + m.AddAtom(x, y, z, sp, "C%i" % (i + 1)) return m diff --git a/doc/examples/nppdfsas.py b/doc/examples/nppdfsas.py index b5975345..2a4a8543 100644 --- a/doc/examples/nppdfsas.py +++ b/doc/examples/nppdfsas.py @@ -24,17 +24,14 @@ """ import numpy - +from gaussianrecipe import scipyOptimize from pyobjcryst import loadCrystal +from diffpy.srfit.fitbase import FitContribution, FitRecipe, FitResults, Profile from diffpy.srfit.pdf import PDFGenerator, PDFParser from diffpy.srfit.pdf.characteristicfunctions import SASCF -from diffpy.srfit.sas import SASParser, SASGenerator -from diffpy.srfit.fitbase import Profile -from diffpy.srfit.fitbase import FitContribution, FitRecipe -from diffpy.srfit.fitbase import FitResults +from diffpy.srfit.sas import SASGenerator, SASParser -from gaussianrecipe import scipyOptimize def makeRecipe(ciffile, grdata, iqdata): """Make complex-modeling recipe where I(q) and G(r) are fit @@ -50,10 +47,10 @@ def makeRecipe(ciffile, grdata, iqdata): pdfparser = PDFParser() pdfparser.parseFile(grdata) pdfprofile.loadParsedData(pdfparser) - pdfprofile.setCalculationRange(xmin = 0.1, xmax = 20) + pdfprofile.setCalculationRange(xmin=0.1, xmax=20) pdfcontribution = FitContribution("pdf") - pdfcontribution.setProfile(pdfprofile, xname = "r") + pdfcontribution.setProfile(pdfprofile, xname="r") pdfgenerator = PDFGenerator("G") pdfgenerator.setQmax(30.0) @@ -75,6 +72,7 @@ def makeRecipe(ciffile, grdata, iqdata): sascontribution.setProfile(sasprofile) from sas.models.EllipsoidModel import EllipsoidModel + model = EllipsoidModel() sasgenerator = SASGenerator("generator", model) sascontribution.addProfileGenerator(sasgenerator) @@ -105,7 +103,7 @@ def makeRecipe(ciffile, grdata, iqdata): recipe.addVar(pdfgenerator.delta2, 0) # SAS - recipe.addVar(sasgenerator.scale, 1, name = "iqscale") + recipe.addVar(sasgenerator.scale, 1, name="iqscale") recipe.addVar(sasgenerator.radius_a, 10) recipe.addVar(sasgenerator.radius_b, 10) @@ -117,16 +115,17 @@ def makeRecipe(ciffile, grdata, iqdata): return recipe + def fitRecipe(recipe): """We refine in stages to help the refinement converge.""" # Tune SAS. recipe.setWeight(recipe.pdf, 0) recipe.fix("all") - recipe.free("radius_a", "radius_b", iqscale = 1e8) - recipe.constrain('radius_b', 'radius_a') + recipe.free("radius_a", "radius_b", iqscale=1e8) + recipe.constrain("radius_b", "radius_a") scipyOptimize(recipe) - recipe.unconstrain('radius_b') + recipe.unconstrain("radius_b") # Tune PDF recipe.setWeight(recipe.pdf, 1) @@ -143,6 +142,7 @@ def fitRecipe(recipe): return + def plotResults(recipe): """Plot the results contained within a refined FitRecipe.""" @@ -160,12 +160,13 @@ def plotResults(recipe): fr *= max(g) / fr[0] import pylab - pylab.plot(r,g,'bo',label="G(r) Data") - pylab.plot(r, gcryst,'y--',label="G(r) Crystal") - pylab.plot(r, fr,'k--',label="f(r) calculated (scaled)") - pylab.plot(r, gcalc,'r-',label="G(r) Fit") - pylab.plot(r, diff,'g-',label="G(r) diff") - pylab.plot(r, diffzero,'k-') + + pylab.plot(r, g, "bo", label="G(r) Data") + pylab.plot(r, gcryst, "y--", label="G(r) Crystal") + pylab.plot(r, fr, "k--", label="f(r) calculated (scaled)") + pylab.plot(r, gcalc, "r-", label="G(r) Fit") + pylab.plot(r, diff, "g-", label="G(r) diff") + pylab.plot(r, diffzero, "k-") pylab.xlabel(r"$r (\AA)$") pylab.ylabel(r"$G (\AA^{-2})$") pylab.legend(loc=1) diff --git a/doc/examples/simplepdf.py b/doc/examples/simplepdf.py index df95bbd2..bbea1b56 100644 --- a/doc/examples/simplepdf.py +++ b/doc/examples/simplepdf.py @@ -19,22 +19,23 @@ It uses the PDFContribution class to simplify fit setup. """ -from diffpy.structure import Structure -from diffpy.srfit.pdf import PDFContribution -from diffpy.srfit.fitbase import FitRecipe, FitResults - -from gaussianrecipe import scipyOptimize from crystalpdf import plotResults +from gaussianrecipe import scipyOptimize + +from diffpy.srfit.fitbase import FitRecipe, FitResults +from diffpy.srfit.pdf import PDFContribution +from diffpy.structure import Structure ####### Example Code + def makeRecipe(ciffile, datname): """Create a fitting recipe for crystalline PDF data.""" # Work directly with a custom PDFContribution to load the data contribution = PDFContribution("nickel") contribution.loadData(datname) - contribution.setCalculationRange(xmin = 1, xmax = 20, dx = 0.1) + contribution.setCalculationRange(xmin=1, xmax=20, dx=0.1) # and the phase stru = Structure() @@ -49,6 +50,7 @@ def makeRecipe(ciffile, datname): phase = contribution.nickel.phase from diffpy.srfit.structure import constrainAsSpaceGroup + sgpars = constrainAsSpaceGroup(phase, "Fm-3m") for par in sgpars.latpars: @@ -57,12 +59,13 @@ def makeRecipe(ciffile, datname): recipe.addVar(par, 0.005) recipe.addVar(contribution.scale, 1) - recipe.addVar(contribution.qdamp, 0.03, fixed = True) + recipe.addVar(contribution.qdamp, 0.03, fixed=True) recipe.addVar(contribution.nickel.delta2, 5) # Give the recipe away so it can be used! return recipe + if __name__ == "__main__": # Make the data and the recipe diff --git a/doc/examples/simplepdftwophase.py b/doc/examples/simplepdftwophase.py index f000926a..b6a663eb 100644 --- a/doc/examples/simplepdftwophase.py +++ b/doc/examples/simplepdftwophase.py @@ -15,23 +15,23 @@ """Example of a simplified PDF refinement of two-phase structure.""" +from crystalpdftwophase import plotResults +from gaussianrecipe import scipyOptimize from pyobjcryst import loadCrystal -from diffpy.srfit.pdf import PDFContribution from diffpy.srfit.fitbase import FitRecipe, FitResults - -from gaussianrecipe import scipyOptimize -from crystalpdftwophase import plotResults +from diffpy.srfit.pdf import PDFContribution ####### Example Code + def makeRecipe(niciffile, siciffile, datname): """Create a fitting recipe for crystalline PDF data.""" # Load data and add it to the profile contribution = PDFContribution("nisi") contribution.loadData(datname) - contribution.setCalculationRange(xmax = 20) + contribution.setCalculationRange(xmax=20) stru = loadCrystal(niciffile) contribution.addStructure("ni", stru) @@ -66,13 +66,13 @@ def makeRecipe(niciffile, siciffile, datname): # above. phase_ni = contribution.ni.phase for par in phase_ni.sgpars: - recipe.addVar(par, name = par.name + "_ni") - recipe.addVar(contribution.ni.delta2, name = "delta2_ni") + recipe.addVar(par, name=par.name + "_ni") + recipe.addVar(contribution.ni.delta2, name="delta2_ni") # Next the silicon parameters phase_si = contribution.si.phase for par in phase_si.sgpars: - recipe.addVar(par, name = par.name + "_si") - recipe.addVar(contribution.si.delta2, name = "delta2_si") + recipe.addVar(par, name=par.name + "_si") + recipe.addVar(contribution.si.delta2, name="delta2_si") # We have prior information from the earlier examples so we'll use it here # in the form of restraints. @@ -82,18 +82,18 @@ def makeRecipe(niciffile, siciffile, datname): # derived has no uncertainty. Thus, we will tell the recipe to scale the # residual, which means that it will be weighted as much as the average # data point during the fit. - recipe.restrain("a_ni", lb = 3.527, ub = 3.527, scaled = True) + recipe.restrain("a_ni", lb=3.527, ub=3.527, scaled=True) # Now we do the same with the delta2 and Biso parameters (remember that # Biso = 8*pi**2*Uiso) - recipe.restrain("delta2_ni", lb = 2.22, ub = 2.22, scaled = True) - recipe.restrain("Biso_0_ni", lb = 0.454, ub = 0.454, scaled = True) + recipe.restrain("delta2_ni", lb=2.22, ub=2.22, scaled=True) + recipe.restrain("Biso_0_ni", lb=0.454, ub=0.454, scaled=True) # # We can do the same with the silicon values. We haven't done a thorough # job of measuring the uncertainties in the results, so we'll scale these # as well. - recipe.restrain("a_si", lb = 5.430, ub = 5.430, scaled = True) - recipe.restrain("delta2_si", lb = 3.54, ub = 3.54, scaled = True) - recipe.restrain("Biso_0_si", lb = 0.645, ub = 0.645, scaled = True) + recipe.restrain("a_si", lb=5.430, ub=5.430, scaled=True) + recipe.restrain("delta2_si", lb=3.54, ub=3.54, scaled=True) + recipe.restrain("Biso_0_si", lb=0.645, ub=0.645, scaled=True) # Give the recipe away so it can be used! return recipe diff --git a/doc/examples/simplerecipe.py b/doc/examples/simplerecipe.py index 45b8785f..50a48696 100644 --- a/doc/examples/simplerecipe.py +++ b/doc/examples/simplerecipe.py @@ -24,6 +24,7 @@ ####### Example Code + def main(): """Set up a simple recipe in a few lines.""" @@ -46,6 +47,7 @@ def main(): # We explicitly optimize the residual method of the SimpleRecipe from scipy.optimize import leastsq + leastsq(recipe.residual, recipe.values) # Print the results @@ -53,6 +55,7 @@ def main(): return + if __name__ == "__main__": main() diff --git a/doc/examples/threedoublepeaks.py b/doc/examples/threedoublepeaks.py index 35b7597b..6e3ceea8 100644 --- a/doc/examples/threedoublepeaks.py +++ b/doc/examples/threedoublepeaks.py @@ -20,10 +20,11 @@ import numpy -from diffpy.srfit.fitbase import FitContribution, FitRecipe, Profile, FitResults +from diffpy.srfit.fitbase import FitContribution, FitRecipe, FitResults, Profile ####### Example Code + def makeRecipe(): """Make a FitRecipe for fitting three double-gaussian curves to data. @@ -48,15 +49,15 @@ def makeRecipe(): # Create the contribution contribution = FitContribution("peaks") - contribution.setProfile(profile, xname = "t") + contribution.setProfile(profile, xname="t") pi = numpy.pi exp = numpy.exp # This is a building-block of our profile function def gaussian(t, mu, sig): - return 1/(2*pi*sig**2)**0.5 * exp(-0.5 * ((t-mu)/sig)**2) + return 1 / (2 * pi * sig**2) ** 0.5 * exp(-0.5 * ((t - mu) / sig) ** 2) - contribution.registerFunction(gaussian, name = "peakshape") + contribution.registerFunction(gaussian, name="peakshape") def delta(t, mu): """Calculate a delta-function. @@ -83,10 +84,11 @@ def delta(t, mu): + 0.23*convolve( delta(t, mu22), peakshape(t, c, sig22) ) ) + \ A3 * ( convolve( delta(t, mu31), peakshape(t, c, sig31) ) \ + 0.23*convolve( delta(t, mu32), peakshape(t, c, sig32) ) ) + \ - bkgd") + bkgd" + ) # c is the center of the gaussian. - contribution.c.value = x[len(x) // 2] + contribution.c.value = x[len(x) // 2] ## The FitRecipe # The FitRecipe lets us define what we want to fit. It is where we can @@ -109,12 +111,13 @@ def delta(t, mu): recipe.addVar(contribution.mu31, 33.0) # Constrain the position of the second double peak - from numpy import sin, arcsin + from numpy import arcsin, sin + def peakloc(mu): """Calculate the location of the second peak given the first.""" l1 = 1.012 l2 = 1.0 - return 180 / pi * arcsin( pi / 180 * l2 * sin(mu) / l1 ) + return 180 / pi * arcsin(pi / 180 * l2 * sin(mu) / l1) recipe.registerFunction(peakloc) recipe.constrain(contribution.mu12, "peakloc(mu11)") @@ -128,7 +131,7 @@ def peakloc(mu): def sig(sig0, dsig, mu): """Calculate the peak broadening with respect to position.""" - return sig0 * (1 - dsig * mu**2); + return sig0 * (1 - dsig * mu**2) recipe.registerFunction(sig) recipe.fix("mu") @@ -136,25 +139,23 @@ def sig(sig0, dsig, mu): recipe.sig0.value = 0.001 recipe.dsig.value = 4.0 recipe.constrain(contribution.sig11, "sig(sig0, dsig, mu11)") - recipe.constrain(contribution.sig12, "sig(sig0, dsig, mu12)", - ns = {"mu12" : contribution.mu12} ) + recipe.constrain(contribution.sig12, "sig(sig0, dsig, mu12)", ns={"mu12": contribution.mu12}) recipe.constrain(contribution.sig21, "sig(sig0, dsig, mu21)") - recipe.constrain(contribution.sig22, "sig(sig0, dsig, mu22)", - ns = {"mu22" : contribution.mu22} ) + recipe.constrain(contribution.sig22, "sig(sig0, dsig, mu22)", ns={"mu22": contribution.mu22}) recipe.constrain(contribution.sig31, "sig(sig0, dsig, mu31)") - recipe.constrain(contribution.sig32, "sig(sig0, dsig, mu32)", - ns = {"mu32" : contribution.mu32} ) + recipe.constrain(contribution.sig32, "sig(sig0, dsig, mu32)", ns={"mu32": contribution.mu32}) # Also the background - recipe.addVar(contribution.b0, 0, tag = "bkgd") - recipe.addVar(contribution.b1, 0, tag = "bkgd") - recipe.addVar(contribution.b2, 0, tag = "bkgd") - recipe.addVar(contribution.b3, 0, tag = "bkgd") - recipe.addVar(contribution.b4, 0, tag = "bkgd") - recipe.addVar(contribution.b5, 0, tag = "bkgd") - recipe.addVar(contribution.b6, 0, tag = "bkgd") + recipe.addVar(contribution.b0, 0, tag="bkgd") + recipe.addVar(contribution.b1, 0, tag="bkgd") + recipe.addVar(contribution.b2, 0, tag="bkgd") + recipe.addVar(contribution.b3, 0, tag="bkgd") + recipe.addVar(contribution.b4, 0, tag="bkgd") + recipe.addVar(contribution.b5, 0, tag="bkgd") + recipe.addVar(contribution.b6, 0, tag="bkgd") return recipe + def scipyOptimize(recipe): """Optimize the recipe created above using scipy. @@ -169,6 +170,7 @@ def scipyOptimize(recipe): # (recipe.residual) and the starting values of the Variables # (recipe.getValues()). from scipy.optimize.minpack import leastsq + print("Fit using scipy's LM optimizer") leastsq(recipe.residual, recipe.getValues()) @@ -190,16 +192,18 @@ def plotResults(recipe): # This stuff is specific to pylab from the matplotlib distribution. import pylab - pylab.plot(x, y, 'b.', label = "observed profile") - pylab.plot(x, ycalc, 'r-', label = "calculated profile") - pylab.plot(x, y - ycalc - 0.1 * max(y), 'g-', label = "difference") - pylab.legend(loc = (0.0,0.8)) + + pylab.plot(x, y, "b.", label="observed profile") + pylab.plot(x, ycalc, "r-", label="calculated profile") + pylab.plot(x, y - ycalc - 0.1 * max(y), "g-", label="difference") + pylab.legend(loc=(0.0, 0.8)) pylab.xlabel("x") pylab.ylabel("y") pylab.show() return + def steerFit(recipe): """Steer the fit for this problem. @@ -219,6 +223,7 @@ def steerFit(recipe): return + if __name__ == "__main__": # Create the recipe diff --git a/doc/source/api/diffpy.srfit.equation.literals.rst b/doc/source/api/diffpy.srfit.equation.literals.rst index 6875b5ef..20679c3e 100644 --- a/doc/source/api/diffpy.srfit.equation.literals.rst +++ b/doc/source/api/diffpy.srfit.equation.literals.rst @@ -42,4 +42,3 @@ diffpy.srfit.equation.literals.operators module :members: :undoc-members: :show-inheritance: - diff --git a/doc/source/api/diffpy.srfit.equation.rst b/doc/source/api/diffpy.srfit.equation.rst index f7a47192..ef74cf23 100644 --- a/doc/source/api/diffpy.srfit.equation.rst +++ b/doc/source/api/diffpy.srfit.equation.rst @@ -35,4 +35,3 @@ diffpy.srfit.equation.equationmod module :members: :undoc-members: :show-inheritance: - diff --git a/doc/source/api/diffpy.srfit.equation.visitors.rst b/doc/source/api/diffpy.srfit.equation.visitors.rst index 54e10bc6..88c35374 100644 --- a/doc/source/api/diffpy.srfit.equation.visitors.rst +++ b/doc/source/api/diffpy.srfit.equation.visitors.rst @@ -50,4 +50,3 @@ diffpy.srfit.equation.visitors.printer module :members: :undoc-members: :show-inheritance: - diff --git a/doc/source/api/diffpy.srfit.fitbase.rst b/doc/source/api/diffpy.srfit.fitbase.rst index 5c092c9f..19bc255e 100644 --- a/doc/source/api/diffpy.srfit.fitbase.rst +++ b/doc/source/api/diffpy.srfit.fitbase.rst @@ -138,4 +138,3 @@ diffpy.srfit.fitbase.profileparser module :members: :undoc-members: :show-inheritance: - diff --git a/doc/source/api/diffpy.srfit.interface.rst b/doc/source/api/diffpy.srfit.interface.rst index 40b829d7..92497fea 100644 --- a/doc/source/api/diffpy.srfit.interface.rst +++ b/doc/source/api/diffpy.srfit.interface.rst @@ -18,4 +18,3 @@ diffpy.srfit.interface.interface module :members: :undoc-members: :show-inheritance: - diff --git a/doc/source/api/diffpy.srfit.pdf.rst b/doc/source/api/diffpy.srfit.pdf.rst index 60f3e947..424c7f16 100644 --- a/doc/source/api/diffpy.srfit.pdf.rst +++ b/doc/source/api/diffpy.srfit.pdf.rst @@ -58,4 +58,3 @@ diffpy.srfit.pdf.pdfcontribution module :members: :undoc-members: :show-inheritance: - diff --git a/doc/source/api/diffpy.srfit.rst b/doc/source/api/diffpy.srfit.rst index 9eef9e38..8f840d0c 100644 --- a/doc/source/api/diffpy.srfit.rst +++ b/doc/source/api/diffpy.srfit.rst @@ -32,4 +32,3 @@ diffpy.srfit.exceptions module :members: :undoc-members: :show-inheritance: - diff --git a/doc/source/api/diffpy.srfit.sas.rst b/doc/source/api/diffpy.srfit.sas.rst index fbc67925..8ad88d91 100644 --- a/doc/source/api/diffpy.srfit.sas.rst +++ b/doc/source/api/diffpy.srfit.sas.rst @@ -58,4 +58,3 @@ diffpy.srfit.sas.sasgenerator module :members: :undoc-members: :show-inheritance: - diff --git a/doc/source/api/diffpy.srfit.structure.rst b/doc/source/api/diffpy.srfit.structure.rst index 1fa5326d..59063abd 100644 --- a/doc/source/api/diffpy.srfit.structure.rst +++ b/doc/source/api/diffpy.srfit.structure.rst @@ -66,4 +66,3 @@ diffpy.srfit.structure.sgconstraints module :members: :undoc-members: :show-inheritance: - diff --git a/doc/source/api/diffpy.srfit.util.rst b/doc/source/api/diffpy.srfit.util.rst index b96e6945..2471e5ad 100644 --- a/doc/source/api/diffpy.srfit.util.rst +++ b/doc/source/api/diffpy.srfit.util.rst @@ -58,4 +58,3 @@ diffpy.srfit.util.weakrefcallable module :members: :undoc-members: :show-inheritance: - diff --git a/src/diffpy/__init__.py b/src/diffpy/__init__.py index 08edc76b..903acd5f 100644 --- a/src/diffpy/__init__.py +++ b/src/diffpy/__init__.py @@ -21,4 +21,3 @@ __path__ = extend_path(__path__, __name__) # End of file - diff --git a/src/diffpy/srfit/equation/__init__.py b/src/diffpy/srfit/equation/__init__.py index 135a6af2..6a248b32 100644 --- a/src/diffpy/srfit/equation/__init__.py +++ b/src/diffpy/srfit/equation/__init__.py @@ -29,5 +29,4 @@ from diffpy.srfit.equation.equationmod import Equation - # End of file diff --git a/src/diffpy/srfit/equation/builder.py b/src/diffpy/srfit/equation/builder.py index e35e9e11..1b1f6601 100644 --- a/src/diffpy/srfit/equation/builder.py +++ b/src/diffpy/srfit/equation/builder.py @@ -77,9 +77,16 @@ > eq = beq.makeEquation() """ -__all__ = ["EquationFactory", "BaseBuilder", "ArgumentBuilder", - "OperatorBuilder", "wrapArgument", "wrapOperator", "wrapFunction", - "getBuilder"] +__all__ = [ + "EquationFactory", + "BaseBuilder", + "ArgumentBuilder", + "OperatorBuilder", + "wrapArgument", + "wrapOperator", + "wrapFunction", + "getBuilder", +] # NOTE - the builder cannot handle numpy arrays on the left of a binary # operation because the array will automatically loop the operator of the @@ -91,13 +98,13 @@ import inspect import numbers -import numpy +import numpy import six import diffpy.srfit.equation.literals as literals -from diffpy.srfit.equation.literals.literal import Literal from diffpy.srfit.equation.equationmod import Equation +from diffpy.srfit.equation.literals.literal import Literal class EquationFactory(object): @@ -125,8 +132,7 @@ def __init__(self): self.registerConstant("e", numpy.e) return - def makeEquation(self, eqstr, buildargs = True, argclass = - literals.Argument, argkw = {}): + def makeEquation(self, eqstr, buildargs=True, argclass=literals.Argument, argkw={}): """Make an equation from an equation string. Arguments @@ -152,7 +158,7 @@ def makeEquation(self, eqstr, buildargs = True, argclass = # handle scalar numbers or numpy arrays if isinstance(beq, (numbers.Number, numpy.ndarray)): lit = literals.Argument(value=beq, const=True) - eq = Equation(name='', root=lit) + eq = Equation(name="", root=lit) else: eq = beq.getEquation() self.equations.add(eq) @@ -255,7 +261,6 @@ def deRegisterBuilder(self, name): del self.builders[name] return - def wipeout(self, eq): """Invalidate the specified equation and remove it from the factory. @@ -272,11 +277,10 @@ def wipeout(self, eq): self.equations.discard(eq) # invalidate this equation to clean up any observer relations of # objects in the factory towards its literals tree. - nan = literals.Argument('nan', value=numpy.nan, const=True) + nan = literals.Argument("nan", value=numpy.nan, const=True) eq.setRoot(nan) return - def _prepareBuilders(self, eqstr, buildargs, argclass, argkw): """Prepare builders so that equation string can be evaluated. @@ -309,14 +313,14 @@ def _prepareBuilders(self, eqstr, buildargs, argclass, argkw): # this is disallowed. if not buildargs and eqargs: eqargsstr = ", ".join(eqargs) - msg = "The equation contains undefined arguments: %s"%eqargsstr + msg = "The equation contains undefined arguments: %s" % eqargsstr raise ValueError(msg) # Make the arguments newargs = set() for argname in eqargs: - arg = argclass(name = argname, **argkw) - argbuilder = ArgumentBuilder(name = argname, arg = arg) + arg = argclass(name=argname, **argkw) + argbuilder = ArgumentBuilder(name=argname, arg=arg) newargs.add(arg) self.registerBuilder(argname, argbuilder) @@ -333,8 +337,8 @@ def _getUndefinedArgs(self, eqstr): Raises SyntaxError if the equation string uses invalid syntax. """ - import tokenize import token + import tokenize interface = six.StringIO(eqstr).readline # output is an iterator. Each entry (token) is a 5-tuple @@ -353,7 +357,7 @@ def _getUndefinedArgs(self, eqstr): if tok[0] in (token.NAME, token.OP): args.add(tok[1]) except tokenize.TokenError: - m = "invalid syntax: '%s'"%eqstr + m = "invalid syntax: '%s'" % eqstr raise SyntaxError(m) # Scan the tokens for names that do not correspond to registered @@ -363,18 +367,22 @@ def _getUndefinedArgs(self, eqstr): # Move genuine varibles to the eqargs dictionary if ( # Check registered builders - tok in self.builders or + tok in self.builders + or # Check symbols - tok in EquationFactory.symbols or + tok in EquationFactory.symbols + or # Check ignored characters tok in EquationFactory.ignore - ): + ): args.remove(tok) return args + # End class EquationFactory + class BaseBuilder(object): """Class for building equations. @@ -392,11 +400,9 @@ def __init__(self): def __call__(self, *args): """Raises exception for easier debugging.""" - m = "%s (%s) cannot accept arguments"%\ - (self.literal.name, self.__class__.__name__) + m = "%s (%s) cannot accept arguments" % (self.literal.name, self.__class__.__name__) raise TypeError(m) - def getEquation(self): """Get the equation built by this object. @@ -404,11 +410,11 @@ def getEquation(self): name of the root node. """ # We need to make a name for this, so we name it after its root - name = "_eq_%s"%self.literal.name + name = "_eq_%s" % self.literal.name eq = Equation(name, self.literal) return eq - def __evalBinary(self, other, OperatorClass, onleft = True): + def __evalBinary(self, other, OperatorClass, onleft=True): """Evaluate a binary function. Other can be an BaseBuilder or a constant. @@ -498,8 +504,10 @@ def __rmod__(self, other): def __neg__(self): return self.__evalUnary(literals.NegationOperator) + ## These are used by the class. + class ArgumentBuilder(BaseBuilder): """BaseBuilder wrapper around an Argument literal. @@ -510,7 +518,7 @@ class ArgumentBuilder(BaseBuilder): literal -- The Argument wrapped by this instance. """ - def __init__(self, value = None, name = None, const = False, arg = None): + def __init__(self, value=None, name=None, const=False, arg=None): """Create an ArgumentBuilder instance, containing a new Argument. Arguments @@ -524,14 +532,15 @@ def __init__(self, value = None, name = None, const = False, arg = None): """ BaseBuilder.__init__(self) if arg is None: - self.literal = literals.Argument(value=value, name=name, - const=const) + self.literal = literals.Argument(value=value, name=name, const=const) else: self.literal = arg return + # end class ArgumentBuilder + class OperatorBuilder(BaseBuilder): """BaseBuilder wrapper around an Operator literal. @@ -540,7 +549,7 @@ class OperatorBuilder(BaseBuilder): name -- The name of the operator to be wrapped """ - def __init__(self, name, op = None): + def __init__(self, name, op=None): """Wrap an Operator or a function by name. Arguments @@ -573,43 +582,48 @@ def __call__(self, *args): self.literal = literals.UFuncOperator(ufunc) # Here the Operator is already specified. We can copy its attributes # to a new Operator inside of the new OperatorBuilder. - op = literals.makeOperator(name=self.literal.name, - symbol=self.literal.symbol, - nin=self.literal.nin, - nout=self.literal.nout, - operation=self.literal.operation) + op = literals.makeOperator( + name=self.literal.name, + symbol=self.literal.symbol, + nin=self.literal.nin, + nout=self.literal.nout, + operation=self.literal.operation, + ) newobj.literal = op # Now that we have a literal, let's check our inputs literal = newobj.literal if literal.nin >= 0 and len(args) != literal.nin: - raise ValueError("%s takes %i arguments (%i given)"%\ - (self.literal, self.literal.nin, len(args))) + raise ValueError("%s takes %i arguments (%i given)" % (self.literal, self.literal.nin, len(args))) # Wrap scalar arguments for i, arg in enumerate(args): # Wrap the argument if it is not already if not isinstance(arg, BaseBuilder): - name = self.name + "_%i"%i - arg = ArgumentBuilder(value = arg, name = name, const = True) + name = self.name + "_%i" % i + arg = ArgumentBuilder(value=arg, name=name, const=True) newobj.literal.addLiteral(arg.literal) return newobj + # end class OperatorBuilder # Utility functions + def wrapArgument(name, arg): """Wrap an Argument as a builder.""" - argbuilder = ArgumentBuilder(arg = arg) + argbuilder = ArgumentBuilder(arg=arg) return argbuilder + def wrapOperator(name, op): """Wrap an Operator as a builder.""" opbuilder = OperatorBuilder(name, op) return opbuilder + def wrapFunction(name, func, nin=2, nout=1): """Wrap a function in an OperatorBuilder instance. @@ -620,19 +634,19 @@ def wrapFunction(name, func, nin=2, nout=1): Returns the OperatorBuilder instance that wraps the function. """ - op = literals.makeOperator(name=name, symbol=name, - nin=nin, nout=nout, - operation=func) + op = literals.makeOperator(name=name, symbol=name, nin=nin, nout=nout, operation=func) # Create the OperatorBuilder opbuilder = OperatorBuilder(name, op) return opbuilder + def getBuilder(name): """Get an operator from the global builders dictionary.""" return _builders[name] + def __wrapNumpyOperators(): """Export all numpy operators as OperatorBuilder instances in the module namespace. @@ -642,8 +656,11 @@ def __wrapNumpyOperators(): if isinstance(op, numpy.ufunc): _builders[name] = OperatorBuilder(name) return + + __wrapNumpyOperators() + # Register other functions as well def __wrapSrFitOperators(): """Export all non-base operators from the @@ -653,16 +670,20 @@ def __wrapSrFitOperators(): 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) + is_exported_type = lambda cls: ( + inspect.isclass(cls) + and issubclass(cls, opmod.Operator) + and not inspect.isabstract(cls) + and not cls in excluded_types + ) # create OperatorBuilder objects 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) return + + __wrapSrFitOperators() # End of file diff --git a/src/diffpy/srfit/equation/equationmod.py b/src/diffpy/srfit/equation/equationmod.py index a48d6dad..60dd2c62 100644 --- a/src/diffpy/srfit/equation/equationmod.py +++ b/src/diffpy/srfit/equation/equationmod.py @@ -42,9 +42,10 @@ from collections import OrderedDict -from diffpy.srfit.equation.visitors import validate, getArgs, swap -from diffpy.srfit.equation.literals.operators import Operator from diffpy.srfit.equation.literals.literal import Literal +from diffpy.srfit.equation.literals.operators import Operator +from diffpy.srfit.equation.visitors import getArgs, swap, validate + class Equation(Operator): """Class for holding and evaluating a Literal tree. @@ -81,7 +82,7 @@ class Equation(Operator): nin = None nout = 1 - def __init__(self, name = None, root = None): + def __init__(self, name=None, root=None): """Initialize. name -- A name for this Equation. @@ -93,7 +94,7 @@ def __init__(self, name = None, root = None): # Operator stuff. We circumvent Operator.__init__ since we're using # args as a property. We cannot set it, as the Operator tries to do. if name is None and root is not None: - name = "eq_%s"%root.name + name = "eq_%s" % root.name Literal.__init__(self, name) self.root = None self.argdict = OrderedDict() @@ -101,12 +102,10 @@ def __init__(self, name = None, root = None): self.setRoot(root) return - @property def symbol(self): return self.name - def operation(self, *args, **kw): """Evaluate this Equation object. @@ -117,7 +116,6 @@ def operation(self, *args, **kw): """ return self.__call__(*args, **kw) - def _getArgs(self): return list(self.argdict.values()) @@ -126,16 +124,13 @@ def _getArgs(self): def __getattr__(self, name): """Gives access to the Arguments as attributes.""" # Avoid infinite loop on argdict lookup. - argdict = object.__getattribute__(self, 'argdict') + argdict = object.__getattribute__(self, "argdict") if not name in argdict: raise AttributeError("No argument named '%s' here" % name) return argdict[name] - # Ensure there is no __dir__ override in the base class. - assert (getattr(Operator, '__dir__', None) is - getattr(object, '__dir__', None)) - + assert getattr(Operator, "__dir__", None) is getattr(object, "__dir__", None) def __dir__(self): "Return sorted list of attributes for this object." @@ -144,7 +139,6 @@ def __dir__(self): rv = sorted(rv) return rv - def setRoot(self, root): """Set the root of the Literal tree. @@ -167,14 +161,13 @@ def setRoot(self, root): # Get the args args = getArgs(root, getconsts=False) - self.argdict = OrderedDict( [(arg.name, arg) for arg in args] ) + self.argdict = OrderedDict([(arg.name, arg) for arg in args]) # Set Operator attributes self.nin = len(self.args) return - def __call__(self, *args, **kw): """Call the equation. @@ -196,7 +189,7 @@ def __call__(self, *args, **kw): for name, val in kw.items(): arg = self.argdict.get(name) if arg is None: - raise ValueError("No argument named '%s' here"%name) + raise ValueError("No argument named '%s' here" % name) arg.setValue(val) self._value = self.root.getValue() @@ -224,4 +217,5 @@ def identify(self, visitor): """Identify self to a visitor.""" return visitor.onEquation(self) + # End of file diff --git a/src/diffpy/srfit/equation/literals/__init__.py b/src/diffpy/srfit/equation/literals/__init__.py index 34c38cef..1632316c 100644 --- a/src/diffpy/srfit/equation/literals/__init__.py +++ b/src/diffpy/srfit/equation/literals/__init__.py @@ -25,32 +25,47 @@ (http://en.wikipedia.org/wiki/Visitor_pattern). """ -__all__ = ["Argument", "Operator", "BinaryOperator", "CustomOperator", - "AdditionOperator", "SubtractionOperator", - "MultiplicationOperator", "DivisionOperator", "ExponentiationOperator", - "RemainderOperator", "NegationOperator", "ConvolutionOperator", - "SumOperator", "UFuncOperator", "ArrayOperator", "PolyvalOperator", - "makeOperator"] +__all__ = [ + "Argument", + "Operator", + "BinaryOperator", + "CustomOperator", + "AdditionOperator", + "SubtractionOperator", + "MultiplicationOperator", + "DivisionOperator", + "ExponentiationOperator", + "RemainderOperator", + "NegationOperator", + "ConvolutionOperator", + "SumOperator", + "UFuncOperator", + "ArrayOperator", + "PolyvalOperator", + "makeOperator", +] # Import the operators from diffpy.srfit.equation.literals.argument import Argument -from diffpy.srfit.equation.literals.operators import Operator -from diffpy.srfit.equation.literals.operators import BinaryOperator -from diffpy.srfit.equation.literals.operators import CustomOperator -from diffpy.srfit.equation.literals.operators import AdditionOperator -from diffpy.srfit.equation.literals.operators import SubtractionOperator -from diffpy.srfit.equation.literals.operators import MultiplicationOperator -from diffpy.srfit.equation.literals.operators import DivisionOperator -from diffpy.srfit.equation.literals.operators import ExponentiationOperator -from diffpy.srfit.equation.literals.operators import RemainderOperator -from diffpy.srfit.equation.literals.operators import NegationOperator -from diffpy.srfit.equation.literals.operators import ConvolutionOperator -from diffpy.srfit.equation.literals.operators import UFuncOperator -from diffpy.srfit.equation.literals.operators import SumOperator -from diffpy.srfit.equation.literals.operators import ArrayOperator -from diffpy.srfit.equation.literals.operators import PolyvalOperator -from diffpy.srfit.equation.literals.operators import makeOperator +from diffpy.srfit.equation.literals.operators import ( + AdditionOperator, + ArrayOperator, + BinaryOperator, + ConvolutionOperator, + CustomOperator, + DivisionOperator, + ExponentiationOperator, + MultiplicationOperator, + NegationOperator, + Operator, + PolyvalOperator, + RemainderOperator, + SubtractionOperator, + SumOperator, + UFuncOperator, + makeOperator, +) # End of file diff --git a/src/diffpy/srfit/equation/literals/abcs.py b/src/diffpy/srfit/equation/literals/abcs.py index 05099162..2186b9bb 100644 --- a/src/diffpy/srfit/equation/literals/abcs.py +++ b/src/diffpy/srfit/equation/literals/abcs.py @@ -28,13 +28,16 @@ class LiteralABC(object): """Abstract Base Class for Literal. See Literal for usage.""" @abstractmethod - def identify(self, visitor): pass + def identify(self, visitor): + pass @abstractmethod - def getValue(self): pass + def getValue(self): + pass name = abstractproperty(None, None) + # End class LiteralABC @@ -42,11 +45,13 @@ class ArgumentABC(LiteralABC): """Abstract Base Class for Argument. See Argument for usage.""" @abstractmethod - def setValue(self, value): pass + def setValue(self, value): + pass const = abstractproperty(None, None) value = abstractproperty(None, None) + # End class ArgumentABC @@ -54,7 +59,8 @@ class OperatorABC(LiteralABC): """Abstract Base Class for Operator. See Operator for usage.""" @abstractmethod - def addLiteral(self, literal): pass + def addLiteral(self, literal): + pass args = abstractproperty(None, None) nin = abstractproperty(None, None) @@ -63,4 +69,5 @@ def addLiteral(self, literal): pass symbol = abstractproperty(None, None) value = abstractproperty(None, None) + # End class OperatorABC diff --git a/src/diffpy/srfit/equation/literals/argument.py b/src/diffpy/srfit/equation/literals/argument.py index ccd9a124..0843e7c5 100644 --- a/src/diffpy/srfit/equation/literals/argument.py +++ b/src/diffpy/srfit/equation/literals/argument.py @@ -21,10 +21,12 @@ __all__ = ["Argument"] -from numpy import ndarray, array_equal +from numpy import array_equal, ndarray + from diffpy.srfit.equation.literals.abcs import ArgumentABC from diffpy.srfit.equation.literals.literal import Literal + class Argument(Literal, ArgumentABC): """Argument class. @@ -39,7 +41,7 @@ class Argument(Literal, ArgumentABC): const = None - def __init__(self, name = None, value = None, const = False): + def __init__(self, name=None, value=None, const=False): """Initialization.""" Literal.__init__(self, name) self.const = const @@ -69,7 +71,7 @@ def setValue(self, val): self.notify() return - value = property( lambda self: self.getValue(), - lambda self, val: self.setValue(val)) + value = property(lambda self: self.getValue(), lambda self, val: self.setValue(val)) + # End of file diff --git a/src/diffpy/srfit/equation/literals/literal.py b/src/diffpy/srfit/equation/literals/literal.py index f1f460f4..26523ac0 100644 --- a/src/diffpy/srfit/equation/literals/literal.py +++ b/src/diffpy/srfit/equation/literals/literal.py @@ -25,7 +25,8 @@ from diffpy.srfit.equation.literals.abcs import LiteralABC from diffpy.srfit.util.observable import Observable -class Literal(Observable,LiteralABC): + +class Literal(Observable, LiteralABC): """Abstract class for equation pieces, such as operators and arguments. Literal derives from Observable. See diffpy.srfit.util.observable. @@ -64,6 +65,7 @@ def _flush(self, other): return def __str__(self): - return "%s(%s)"%(self.__class__.__name__, self.name) + return "%s(%s)" % (self.__class__.__name__, self.name) + # End of file diff --git a/src/diffpy/srfit/equation/literals/operators.py b/src/diffpy/srfit/equation/literals/operators.py index 0a3f679e..3c279397 100644 --- a/src/diffpy/srfit/equation/literals/operators.py +++ b/src/diffpy/srfit/equation/literals/operators.py @@ -25,10 +25,21 @@ but they all identify themselves with the Visitor.onOperator method. """ -__all__ = ["Operator", "AdditionOperator", "SubtractionOperator", - "MultiplicationOperator", "DivisionOperator", "ExponentiationOperator", - "RemainderOperator", "NegationOperator", "ConvolutionOperator", - "SumOperator", "UFuncOperator", "ArrayOperator", "PolyvalOperator"] +__all__ = [ + "Operator", + "AdditionOperator", + "SubtractionOperator", + "MultiplicationOperator", + "DivisionOperator", + "ExponentiationOperator", + "RemainderOperator", + "NegationOperator", + "ConvolutionOperator", + "SumOperator", + "UFuncOperator", + "ArrayOperator", + "PolyvalOperator", +] import numpy @@ -71,13 +82,11 @@ class Operator(Literal, OperatorABC): # _value : float, numpy.ndarray or None # The last value of the operator or None. - # We must declare the abstract `args` here. args = None # default for the value _value = None - def __init__(self, name=None): """Initialize the operator object with the specified name. @@ -91,7 +100,6 @@ def __init__(self, name=None): self.args = [] return - def identify(self, visitor): """Identify self to a visitor.""" return visitor.onOperator(self) @@ -124,7 +132,7 @@ def getValue(self): def _loopCheck(self, literal): """Check if a literal causes self-reference.""" if literal is self: - raise ValueError("'%s' causes self-reference"%literal) + raise ValueError("'%s' causes self-reference" % literal) # Check to see if I am a dependency of the literal. if hasattr(literal, "args"): @@ -206,6 +214,7 @@ def makeOperator(name, symbol, operation, nin, nout): op.nout = nout return op + # Some specified operators @@ -278,10 +287,10 @@ def _conv(v1, v2): # Find the centroid of the first signal s1 = sum(v1) x1 = numpy.arange(len(v1), dtype=float) - c1idx = numpy.sum(v1 * x1)/s1 + c1idx = numpy.sum(v1 * x1) / s1 # Find the centroid of the convolution xc = numpy.arange(len(c), dtype=float) - ccidx = numpy.sum(c * xc)/sum(c) + ccidx = numpy.sum(c * xc) / sum(c) # Interpolate the convolution such that the centroids line up. This # uses linear interpolation. shift = ccidx - c1idx @@ -291,7 +300,7 @@ def _conv(v1, v2): # Normalize sc = sum(c) if sc > 0: - c *= s1/sc + c *= s1 / sc return c @@ -370,4 +379,5 @@ class PolyvalOperator(BinaryOperator): operation = staticmethod(numpy.polyval) pass + # End of file diff --git a/src/diffpy/srfit/equation/visitors/__init__.py b/src/diffpy/srfit/equation/visitors/__init__.py index b4014c3e..c329a324 100644 --- a/src/diffpy/srfit/equation/visitors/__init__.py +++ b/src/diffpy/srfit/equation/visitors/__init__.py @@ -27,11 +27,11 @@ from diffpy.srfit.equation.visitors.argfinder import ArgFinder from diffpy.srfit.equation.visitors.printer import Printer -from diffpy.srfit.equation.visitors.validator import Validator from diffpy.srfit.equation.visitors.swapper import Swapper +from diffpy.srfit.equation.visitors.validator import Validator -def getArgs(literal, getconsts = True): +def getArgs(literal, getconsts=True): """Get the Arguments of a Literal tree. getconsts -- If True (default), then Arguments designated as constant @@ -72,7 +72,7 @@ def validate(literal): v = Validator() errors = literal.identify(v) if errors: - m = "Errors found in Literal tree '%s'\n"%literal + m = "Errors found in Literal tree '%s'\n" % literal m += "\n".join(errors) raise ValueError(m) return diff --git a/src/diffpy/srfit/equation/visitors/argfinder.py b/src/diffpy/srfit/equation/visitors/argfinder.py index ab26a695..3a45460c 100644 --- a/src/diffpy/srfit/equation/visitors/argfinder.py +++ b/src/diffpy/srfit/equation/visitors/argfinder.py @@ -32,7 +32,7 @@ class ArgFinder(Visitor): """ - def __init__(self, getconsts = True): + def __init__(self, getconsts=True): """Initialize. Arguments @@ -61,4 +61,5 @@ def onOperator(self, op): arg.identify(self) return self.args + # End of file diff --git a/src/diffpy/srfit/equation/visitors/printer.py b/src/diffpy/srfit/equation/visitors/printer.py index 9b98414c..c48e8c9c 100644 --- a/src/diffpy/srfit/equation/visitors/printer.py +++ b/src/diffpy/srfit/equation/visitors/printer.py @@ -25,6 +25,7 @@ from diffpy.srfit.equation.visitors.visitor import Visitor + class Printer(Visitor): """Printer for printing a Literal tree. @@ -44,13 +45,11 @@ def __init__(self): self.reset() return - def reset(self): """Reset the out put string.""" self.output = "" return - @property def eqskip(self): """Pattern for equation objects to be skipped. @@ -70,7 +69,6 @@ def eqskip(self, value): self._eqpat = re.compile(value) return - def onArgument(self, arg): """Process an Argument node. @@ -82,7 +80,6 @@ def onArgument(self, arg): self.output += str(arg.name) return self.output - def onOperator(self, op): """Process an Operator node.""" # We have to deal with infix operators @@ -93,31 +90,30 @@ def onOperator(self, op): self.output += str(op.name) + "(" for idx, literal in enumerate(op.args): - if idx != 0: self.output += ", " + if idx != 0: + self.output += ", " literal.identify(self) self.output += ")" return self.output - def onEquation(self, eq): """Process an Equation node.""" - skipthis = (self._eqpat is not None and eq.name and - self._eqpat.match(eq.name)) + skipthis = self._eqpat is not None and eq.name and self._eqpat.match(eq.name) if skipthis: self.onArgument(eq) else: eq.root.identify(self) return self.output - def _onInfix(self, op): """Process infix operators.""" self.output += "(" op.args[0].identify(self) - self.output += " %s "%op.symbol + self.output += " %s " % op.symbol op.args[1].identify(self) self.output += ")" return + # End of file diff --git a/src/diffpy/srfit/equation/visitors/swapper.py b/src/diffpy/srfit/equation/visitors/swapper.py index 0b52a558..1ac9e8c9 100644 --- a/src/diffpy/srfit/equation/visitors/swapper.py +++ b/src/diffpy/srfit/equation/visitors/swapper.py @@ -20,6 +20,7 @@ from diffpy.srfit.equation.visitors.visitor import Visitor + class Swapper(Visitor): """Swapper for swapping out one literal for another in a literal tree. @@ -113,7 +114,6 @@ def onOperator(self, op): newlit.addObserver(op._flush) op._flush(other=()) - self._swap = False return @@ -143,4 +143,5 @@ def onEquation(self, eq): return + # End of file diff --git a/src/diffpy/srfit/equation/visitors/validator.py b/src/diffpy/srfit/equation/visitors/validator.py index c99b6abe..1ccbdbab 100644 --- a/src/diffpy/srfit/equation/visitors/validator.py +++ b/src/diffpy/srfit/equation/visitors/validator.py @@ -61,7 +61,7 @@ def onArgument(self, arg): """ if not isinstance(arg, ArgumentABC): - m = msg%(arg, ArgumentABC.__name__) + m = msg % (arg, ArgumentABC.__name__) self.errors.append(m) self._nin = 1 return self.errors @@ -75,24 +75,24 @@ def onOperator(self, op): """ if not isinstance(op, OperatorABC): - m = msg%(op, OperatorABC.__name__) + m = msg % (op, OperatorABC.__name__) self.errors.append(m) # Can only process single-valued functions if op.nout != 1: - m = "'%s' is not single-valued (nout != 1)"%op + m = "'%s' is not single-valued (nout != 1)" % op self.errors.append(m) # Check name if op.name is None: - m = "'%s' does not have a name"%op + m = "'%s' does not have a name" % op self.errors.append(m) # Check symbol if op.symbol is None: - m = "'%s' does not have a symbol"%op + m = "'%s' does not have a symbol" % op self.errors.append(m) # Check operation without evaluating it if op.operation is None: - m = "'%s' does not define and operation"%op + m = "'%s' does not define and operation" % op self.errors.append(m) localnin = 0 @@ -103,10 +103,11 @@ def onOperator(self, op): # Check the input/output balance if op.nin >= 0 and localnin != op.nin: - m = "'%s' requires %i inputs but receives %i"%(op, op.nin, localnin) + m = "'%s' requires %i inputs but receives %i" % (op, op.nin, localnin) self.errors.append(m) self._nin = op.nout return self.errors + # End of file diff --git a/src/diffpy/srfit/equation/visitors/visitor.py b/src/diffpy/srfit/equation/visitors/visitor.py index ef4eaa65..75f0efa9 100644 --- a/src/diffpy/srfit/equation/visitors/visitor.py +++ b/src/diffpy/srfit/equation/visitors/visitor.py @@ -29,6 +29,7 @@ __all__ = ["Visitor"] + class Visitor(object): """Abstract class for all visitors to a Literal tree. @@ -55,8 +56,7 @@ def onEquation(self, eq): # throw an exception def _abstract(self, method): - raise NotImplementedError( - "class '%s' should override method '%s'" % (self.__class__.__name__, method)) + raise NotImplementedError("class '%s' should override method '%s'" % (self.__class__.__name__, method)) # End of file diff --git a/src/diffpy/srfit/exceptions.py b/src/diffpy/srfit/exceptions.py index eed5a572..7d93fbb2 100644 --- a/src/diffpy/srfit/exceptions.py +++ b/src/diffpy/srfit/exceptions.py @@ -20,9 +20,11 @@ class SrFitError(Exception): """Generic error in SrFit expressions or recipe.""" + pass class ParseError(Exception): """Exception used by ProfileParsers.""" + pass diff --git a/src/diffpy/srfit/fitbase/__init__.py b/src/diffpy/srfit/fitbase/__init__.py index 48b96c79..f07cfd6c 100644 --- a/src/diffpy/srfit/fitbase/__init__.py +++ b/src/diffpy/srfit/fitbase/__init__.py @@ -28,17 +28,26 @@ http://www.reflectometry.org/danse/park.html """ -__all__ = ['Calculator', 'FitContribution', 'FitHook', 'FitRecipe', - 'FitResults', 'initializeRecipe', 'PlotFitHook', 'Profile', - 'ProfileGenerator', 'SimpleRecipe'] +__all__ = [ + "Calculator", + "FitContribution", + "FitHook", + "FitRecipe", + "FitResults", + "initializeRecipe", + "PlotFitHook", + "Profile", + "ProfileGenerator", + "SimpleRecipe", +] from diffpy.srfit.fitbase.calculator import Calculator from diffpy.srfit.fitbase.fitcontribution import FitContribution from diffpy.srfit.fitbase.fithook import FitHook, PlotFitHook from diffpy.srfit.fitbase.fitrecipe import FitRecipe -from diffpy.srfit.fitbase.simplerecipe import SimpleRecipe from diffpy.srfit.fitbase.fitresults import FitResults, initializeRecipe from diffpy.srfit.fitbase.profile import Profile from diffpy.srfit.fitbase.profilegenerator import ProfileGenerator +from diffpy.srfit.fitbase.simplerecipe import SimpleRecipe # End of file diff --git a/src/diffpy/srfit/fitbase/calculator.py b/src/diffpy/srfit/fitbase/calculator.py index 43f91ec1..ee36f4af 100644 --- a/src/diffpy/srfit/fitbase/calculator.py +++ b/src/diffpy/srfit/fitbase/calculator.py @@ -26,8 +26,9 @@ __all__ = ["Calculator"] -from diffpy.srfit.fitbase.parameterset import ParameterSet from diffpy.srfit.equation.literals.operators import Operator +from diffpy.srfit.fitbase.parameterset import ParameterSet + class Calculator(Operator, ParameterSet): """Base class for calculators. @@ -75,12 +76,10 @@ def __init__(self, name): Operator.__init__(self, name) return - @property def symbol(self): return self.name - # Overload me! def __call__(self, *args): """Calculate something. @@ -92,12 +91,10 @@ def __call__(self, *args): """ return 0 - def operation(self, *args): self._value = self.__call__(*args) return self._value - def _validate(self): """Validate my state. @@ -112,4 +109,5 @@ def _validate(self): return + # End class Calculator diff --git a/src/diffpy/srfit/fitbase/configurable.py b/src/diffpy/srfit/fitbase/configurable.py index 652cad0d..dab99dda 100644 --- a/src/diffpy/srfit/fitbase/configurable.py +++ b/src/diffpy/srfit/fitbase/configurable.py @@ -54,6 +54,7 @@ def _storeConfigurable(self, obj): self._configobjs.add(obj) return + # End class Configurable # End of file diff --git a/src/diffpy/srfit/fitbase/constraint.py b/src/diffpy/srfit/fitbase/constraint.py index 82c54897..2c0ca8f9 100644 --- a/src/diffpy/srfit/fitbase/constraint.py +++ b/src/diffpy/srfit/fitbase/constraint.py @@ -41,7 +41,7 @@ class Constraint(Validatable): """ def __init__(self): - """Initialization. """ + """Initialization.""" self.par = None self.eq = None return @@ -57,10 +57,10 @@ def constrain(self, par, eq): """ if par.const: - raise ValueError("The parameter '%s' is constant"%par) + raise ValueError("The parameter '%s' is constant" % par) if par.constrained: - raise ValueError("The parameter '%s' is already constrained"%par) + raise ValueError("The parameter '%s' is already constrained" % par) par.constrained = True @@ -100,6 +100,7 @@ def _validate(self): raise SrFitError("eq is None") self.par._validate() from diffpy.srfit.equation.visitors import validate + try: validate(self.eq) except ValueError as e: @@ -117,4 +118,5 @@ def _validate(self): return + # End of file diff --git a/src/diffpy/srfit/fitbase/fitcontribution.py b/src/diffpy/srfit/fitbase/fitcontribution.py index 1e80ce0e..d2982fd9 100644 --- a/src/diffpy/srfit/fitbase/fitcontribution.py +++ b/src/diffpy/srfit/fitbase/fitcontribution.py @@ -25,11 +25,12 @@ __all__ = ["FitContribution"] -from diffpy.srfit.fitbase.parameterset import ParameterSet -from diffpy.srfit.fitbase.recipeorganizer import equationFromString +from diffpy.srfit.exceptions import SrFitError from diffpy.srfit.fitbase.parameter import ParameterProxy +from diffpy.srfit.fitbase.parameterset import ParameterSet from diffpy.srfit.fitbase.profile import Profile -from diffpy.srfit.exceptions import SrFitError +from diffpy.srfit.fitbase.recipeorganizer import equationFromString + class FitContribution(ParameterSet): """FitContribution class. @@ -80,7 +81,7 @@ def __init__(self, name): self._manage(self._generators) return - def setProfile(self, profile, xname = None, yname = None, dyname = None): + def setProfile(self, profile, xname=None, yname=None, dyname=None): """Assign the Profile for this FitContribution. profile -- A Profile that specifies the calculation points and that @@ -121,9 +122,9 @@ def setProfile(self, profile, xname = None, yname = None, dyname = None): xpar = ParameterProxy(xname, self.profile.xpar) ypar = ParameterProxy(yname, self.profile.ypar) dypar = ParameterProxy(dyname, self.profile.dypar) - self.addParameter(xpar, check = False) - self.addParameter(ypar, check = False) - self.addParameter(dypar, check = False) + self.addParameter(xpar, check=False) + self.addParameter(ypar, check=False) + self.addParameter(dypar, check=False) # If we have ProfileGenerators, set their Profiles. for gen in self._generators.values(): @@ -131,12 +132,11 @@ def setProfile(self, profile, xname = None, yname = None, dyname = None): # If we have _eq, but not _reseq, set the residual if self._eq is not None and self._reseq is None: - self.setResidualEquation('chiv') + self.setResidualEquation("chiv") return - - def addProfileGenerator(self, gen, name = None): + def addProfileGenerator(self, gen, name=None): """Add a ProfileGenerator to be used by this FitContribution. The ProfileGenerator is given a name so that it can be used as part of @@ -176,7 +176,7 @@ def addProfileGenerator(self, gen, name = None): return - def setEquation(self, eqstr, ns = {}): + def setEquation(self, eqstr, ns={}): """Set the profile equation for the FitContribution. This sets the equation that will be used when generating the residual @@ -197,8 +197,7 @@ def setEquation(self, eqstr, ns = {}): """ # Build the equation instance. - eq = equationFromString(eqstr, self._eqfactory, - buildargs=True, ns=ns) + eq = equationFromString(eqstr, self._eqfactory, buildargs=True, ns=ns) eq.name = "eq" # Register any new Parameters. @@ -212,11 +211,10 @@ def setEquation(self, eqstr, ns = {}): # Set the residual if we need to if self.profile is not None and self._reseq is None: - self.setResidualEquation('chiv') + self.setResidualEquation("chiv") return - def getEquation(self): """Get math expression string for the active profile equation. @@ -224,12 +222,12 @@ def getEquation(self): equation has not been set yet. """ from diffpy.srfit.equation.visitors import getExpression + rv = "" if self._eq is not None: rv = getExpression(self._eq) return rv - def setResidualEquation(self, eqstr): """Set the residual equation for the FitContribution. @@ -271,7 +269,6 @@ def setResidualEquation(self, eqstr): return - def getResidualEquation(self): """Get math expression string for the active residual equation. @@ -279,12 +276,12 @@ def getResidualEquation(self): equation has not been configured yet. """ from diffpy.srfit.equation.visitors import getExpression + rv = "" if self._reseq is not None: - rv = getExpression(self._reseq, eqskip='eq$') + rv = getExpression(self._reseq, eqskip="eq$") return rv - def residual(self): """Calculate the residual for this fitcontribution. @@ -306,16 +303,13 @@ def residual(self): # the following will not recompute the equation. return self._reseq() - def evaluate(self): - """Evaluate the contribution equation and update profile.ycalc. - """ + """Evaluate the contribution equation and update profile.ycalc.""" yc = self._eq() if self.profile is not None: self.profile.ycalc = yc return yc - def _validate(self): """Validate my state. @@ -332,6 +326,7 @@ def _validate(self): # Try to get the value of eq. from diffpy.srfit.equation.visitors import validate + try: validate(self._eq) except ValueError as e: @@ -343,7 +338,7 @@ def _validate(self): try: val = self._eq() except TypeError as e: - raise SrFitError("_eq cannot be evaluated: %s"%e) + raise SrFitError("_eq cannot be evaluated: %s" % e) if val is None: raise SrFitError("_eq evaluates to None") @@ -361,4 +356,5 @@ def _validate(self): raise SrFitError("residual evaluates to None") return + # End of file diff --git a/src/diffpy/srfit/fitbase/fithook.py b/src/diffpy/srfit/fitbase/fithook.py index 7dc2de96..98d8757a 100644 --- a/src/diffpy/srfit/fitbase/fithook.py +++ b/src/diffpy/srfit/fitbase/fithook.py @@ -71,8 +71,10 @@ def postcall(self, recipe, chiv): """ return + # End class FitHook + class PrintFitHook(FitHook): """Base class for inspecting the progress of a FitRecipe refinement. @@ -148,14 +150,16 @@ def postcall(self, recipe, chiv): print("Variables") vnames = recipe.getNames() vals = recipe.getValues() - byname = lambda nv : sortKeyForNumericString(nv[0]) + byname = lambda nv: sortKeyForNumericString(nv[0]) items = sorted(zip(vnames, vals), key=byname) for name, val in items: print(" %s = %f" % (name, val)) return + # End class PrintFitHook + # TODO - Display the chi^2 on the plot during refinement. class PlotFitHook(FitHook): """This FitHook has live plotting of whatever is being refined.""" @@ -185,20 +189,20 @@ def reset(self, recipe): # Create a subplot if nc > 1: - pylab.subplot(nrows, ncols, idx+1) - pdata = pylab.plot(p.x, p.y, 'bo')[0] - pfit = pylab.plot(p.x, p.y, 'r-')[0] + pylab.subplot(nrows, ncols, idx + 1) + pdata = pylab.plot(p.x, p.y, "bo")[0] + pfit = pylab.plot(p.x, p.y, "r-")[0] self._plots.append((pdata, pfit)) pylab.xlabel(xname) pylab.ylabel(yname) pylab.title(name) # Set up some event handling, so things behave nicely. - #def redraw(event): + # def redraw(event): # canvas = event.canvas # canvas.draw() # return - #pylab.connect('resize_event', redraw) + # pylab.connect('resize_event', redraw) return diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index c367f78b..347ce0b9 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -35,14 +35,15 @@ __all__ = ["FitRecipe"] from collections import OrderedDict -from numpy import array, concatenate, sqrt, dot + import six +from numpy import array, concatenate, dot, sqrt -from diffpy.srfit.interface import _fitrecipe_interface -from diffpy.srfit.util.tagmanager import TagManager +from diffpy.srfit.fitbase.fithook import PrintFitHook from diffpy.srfit.fitbase.parameter import ParameterProxy from diffpy.srfit.fitbase.recipeorganizer import RecipeOrganizer -from diffpy.srfit.fitbase.fithook import PrintFitHook +from diffpy.srfit.interface import _fitrecipe_interface +from diffpy.srfit.util.tagmanager import TagManager class FitRecipe(_fitrecipe_interface, RecipeOrganizer): @@ -87,18 +88,20 @@ class FitRecipe(_fitrecipe_interface, RecipeOrganizer): bounds2 -- Bounds on parameters (read only). See getBounds2. """ - fixednames = property(lambda self: - [v.name for v in self._parameters.values() - if not (self.isFree(v) or self.isConstrained(v))], - doc='names of the fixed refinable variables') - fixedvalues = property(lambda self: - array([v.value for v in self._parameters.values() - if not (self.isFree(v) or self.isConstrained(v))]), - doc='values of the fixed refinable variables') + fixednames = property( + lambda self: [v.name for v in self._parameters.values() if not (self.isFree(v) or self.isConstrained(v))], + doc="names of the fixed refinable variables", + ) + fixedvalues = property( + lambda self: array( + [v.value for v in self._parameters.values() if not (self.isFree(v) or self.isConstrained(v))] + ), + doc="values of the fixed refinable variables", + ) bounds = property(lambda self: self.getBounds()) bounds2 = property(lambda self: self.getBounds2()) - def __init__(self, name = "fit"): + def __init__(self, name="fit"): """Initialization.""" RecipeOrganizer.__init__(self, name) self.fithooks = [] @@ -119,7 +122,7 @@ def __init__(self, name = "fit"): return - def pushFitHook(self, fithook, index = None): + def pushFitHook(self, fithook, index=None): """Add a FitHook to be called within the residual method. The hook is an object for reporting updates, or more fundamentally, @@ -138,7 +141,7 @@ def pushFitHook(self, fithook, index = None): self._updateConfiguration() return - def popFitHook(self, fithook = None, index = -1): + def popFitHook(self, fithook=None, index=-1): """Remove a FitHook by index or reference. fithook -- FitHook instance to remove from the sequence. If this is @@ -164,7 +167,7 @@ def clearFitHooks(self): del self.fithooks[:] return - def addContribution(self, con, weight = 1.0): + def addContribution(self, con, weight=1.0): """Add a FitContribution to the FitRecipe. con -- The FitContribution to be stored. @@ -203,7 +206,7 @@ def removeParameterSet(self, parset): self._removeObject(parset, self._parsets) return - def residual(self, p = []): + def residual(self, p=[]): """Calculate the vector residual to be optimized. Arguments @@ -234,22 +237,22 @@ def residual(self, p = []): con.update() # Calculate the bare chiv - chiv = concatenate([ - wi * ci.residual().flatten() - for wi, ci in zip(self._weights, self._contributions.values())]) + chiv = concatenate( + [wi * ci.residual().flatten() for wi, ci in zip(self._weights, self._contributions.values())] + ) # Calculate the point-average chi^2 - w = dot(chiv, chiv)/len(chiv) + w = dot(chiv, chiv) / len(chiv) # Now we must append the restraints - penalties = [ sqrt(res.penalty(w)) for res in self._restraintlist ] - chiv = concatenate( [ chiv, penalties ] ) + penalties = [sqrt(res.penalty(w)) for res in self._restraintlist] + chiv = concatenate([chiv, penalties]) for fithook in self.fithooks: fithook.postcall(self, chiv) return chiv - def scalarResidual(self, p = []): + def scalarResidual(self, p=[]): """Calculate the scalar residual to be optimized. Arguments @@ -267,7 +270,7 @@ def scalarResidual(self, p = []): chiv = self.residual(p) return dot(chiv, chiv) - def __call__(self, p = []): + def __call__(self, p=[]): """Same as scalarResidual method.""" return self.scalarResidual(p) @@ -318,14 +321,12 @@ def __verifyProfiles(self): # Check for profile values for con in self._contributions.values(): if con.profile is None: - m = "FitContribution '%s' does not have a Profile"%con.name + m = "FitContribution '%s' does not have a Profile" % con.name raise AttributeError(m) - if con.profile.x is None or\ - con.profile.y is None or\ - con.profile.dy is None: + if con.profile.x is None or con.profile.y is None or con.profile.dy is None: - m = "Profile for '%s' is missing data"%con.name - raise AttributeError(m) + m = "Profile for '%s' is missing data" % con.name + raise AttributeError(m) return def __verifyParameters(self): @@ -344,7 +345,7 @@ def __verifyParameters(self): for par in badpars: objlist = self._locateManagedObject(par) names = [obj.name for obj in objlist] - badnames.append( ".".join(names) ) + badnames.append(".".join(names)) # Construct an error message, if necessary m = "" @@ -362,14 +363,15 @@ def __verifyParameters(self): def __collectConstraintsAndRestraints(self): """Collect the Constraints and Restraints from subobjects.""" - from itertools import chain from functools import cmp_to_key + from itertools import chain + rset = set(self._restraints) cdict = {} for org in chain(self._contributions.values(), self._parsets.values()): - rset.update( org._getRestraints() ) - cdict.update( org._getConstraints() ) + rset.update(org._getRestraints()) + cdict.update(org._getConstraints()) cdict.update(self._constraints) # The order of the restraint list does not matter @@ -386,7 +388,7 @@ def __collectConstraintsAndRestraints(self): # Now check the constraint's equation for constrained arguments for arg in con.eq.args: if arg in cdict: - depmap[con].add( cdict[arg] ) + depmap[con].add(cdict[arg]) # Turn the dependency map into multi-level map. def _extendDeps(con): @@ -422,8 +424,7 @@ def cmp(x, y): # Variable manipulation - def addVar(self, par, value = None, name = None, fixed = False, tag = None, - tags = []): + def addVar(self, par, value=None, name=None, fixed=False, tag=None, tags=[]): """Add a variable to be refined. par -- A Parameter that will be varied during a fit. @@ -448,10 +449,10 @@ def addVar(self, par, value = None, name = None, fixed = False, tag = None, name = name or par.name if par.const: - raise ValueError("The parameter '%s' is constant"%par) + raise ValueError("The parameter '%s' is constant" % par) if par.constrained: - raise ValueError("The parameter '%s' is constrained"%par) + raise ValueError("The parameter '%s' is constrained" % par) var = ParameterProxy(name, par) if value is not None: @@ -487,13 +488,12 @@ def delVar(self, var): def __delattr__(self, name): if name in self._parameters: - self.delVar( self._parameters[name] ) + self.delVar(self._parameters[name]) return super(FitRecipe, self).__delattr__(name) return - - def newVar(self, name, value = None, fixed = False, tag = None, tags = []): + def newVar(self, name, value=None, fixed=False, tag=None, tags=[]): """Create a new variable of the fit. This method lets new variables be created that are not tied to a @@ -543,7 +543,6 @@ def _newParameter(self, name, value, check=True): self.fix(par.name) return par - def __getVarAndCheck(self, var): """Get the actual variable from var @@ -579,14 +578,14 @@ def __getVarsFromArgs(self, *args, **kw): badtags = strargs - alltags if badtags: names = ",".join(badtags) - raise ValueError("Variables or tags cannot be found (%s)"% names) + raise ValueError("Variables or tags cannot be found (%s)" % names) # Check that variables are valid allvars = set(self._parameters.values()) badvars = varargs - allvars if badvars: names = ",".join(v.name for v in badvars) - raise ValueError("Variables cannot be found (%s)"% names) + raise ValueError("Variables cannot be found (%s)" % names) # Make sure that we only have parameters in kw kwnames = set(kw.keys()) @@ -594,7 +593,7 @@ def __getVarsFromArgs(self, *args, **kw): badkw = kwnames - allnames if badkw: names = ",".join(badkw) - raise ValueError("Tags cannot be passed as keywords (%s)"% names) + raise ValueError("Tags cannot be passed as keywords (%s)" % names) # Now get all the objects referred to in the arguments. varargs |= self._tagmanager.union(*strargs) @@ -616,7 +615,6 @@ def fix(self, *args, **kw): # Check the inputs and get the variables from them varargs = self.__getVarsFromArgs(*args, **kw) - # Fix all of these for var in varargs: self._tagmanager.tag(var, self._fixedtag) @@ -656,7 +654,7 @@ def free(self, *args, **kw): def isFree(self, var): """Check if a variable is fixed.""" - return (not self._tagmanager.hasTags(var, self._fixedtag)) + return not self._tagmanager.hasTags(var, self._fixedtag) def unconstrain(self, *pars): """Unconstrain a Parameter. @@ -692,7 +690,7 @@ def unconstrain(self, *pars): return - def constrain(self, par, con, ns = {}): + def constrain(self, par, con, ns={}): """Constrain a parameter to an equation. Note that only one constraint can exist on a Parameter at a time. @@ -722,13 +720,13 @@ def constrain(self, par, con, ns = {}): if par is None: par = ns.get(name) if par is None: - raise ValueError("The parameter '%s' cannot be found"%name) + raise ValueError("The parameter '%s' cannot be found" % name) if con in self._parameters.keys(): con = self._parameters[con] if par.const: - raise ValueError("The parameter '%s' is constant"%par) + raise ValueError("The parameter '%s' is constant" % par) # This will pass the value of a constrained parameter to the initial # value of a parameter constraint. @@ -744,11 +742,9 @@ def constrain(self, par, con, ns = {}): RecipeOrganizer.constrain(self, par, con, ns) return - def getValues(self): """Get the current values of the variables in a list.""" - return array([v.value for v in self._parameters.values() if - self.isFree(v)]) + return array([v.value for v in self._parameters.values() if self.isFree(v)]) def getNames(self): """Get the names of the variables in a list.""" @@ -772,7 +768,7 @@ def getBounds2(self): ub = array([b[1] for b in bounds]) return lb, ub - def boundsToRestraints(self, sig = 1, scaled = False): + def boundsToRestraints(self, sig=1, scaled=False): """Turn all bounded parameters into restraints. The bounds become limits on the restraint. @@ -785,13 +781,13 @@ def boundsToRestraints(self, sig = 1, scaled = False): if not hasattr(sig, "__iter__"): sig = [sig] * len(pars) for par, x in zip(pars, sig): - self.restrain(par, par.bounds[0], par.bounds[1], sig = x, - scaled = scaled) + self.restrain(par, par.bounds[0], par.bounds[1], sig=x, scaled=scaled) return def _applyValues(self, p): """Apply variable values to the variables.""" - if len(p) == 0: return + if len(p) == 0: + return vargen = (v for v in self._parameters.values() if self.isFree(v)) for var, pval in zip(vargen, p): var.setValue(pval) @@ -802,4 +798,5 @@ def _updateConfiguration(self): self._ready = False return + # End of file diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index 6cde340d..e01aa300 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -25,12 +25,13 @@ __all__ = ["FitResults", "ContributionResults", "initializeRecipe"] import re -import numpy from collections import OrderedDict -from diffpy.srfit.util.inpututils import inputToString +import numpy + from diffpy.srfit.util import _DASHEDLINE from diffpy.srfit.util import sortKeyForNumericString as numstr +from diffpy.srfit.util.inpututils import inputToString class FitResults(object): @@ -70,8 +71,7 @@ class FitResults(object): """ - def __init__(self, recipe, update = True, showfixed = True, showcon = - False): + def __init__(self, recipe, update=True, showfixed=True, showcon=False): """Initialize the attributes. recipe -- The recipe containing the results @@ -139,8 +139,7 @@ def update(self): self._calculateCovariance() # Get the variable uncertainties - self.varunc = [self.cov[i,i]**0.5 for i in \ - range(len(self.varnames))] + self.varunc = [self.cov[i, i] ** 0.5 for i in range(len(self.varnames))] # Get the constraint uncertainties self._calculateConstraintUncertainties() @@ -170,8 +169,8 @@ def _calculateCovariance(self): """ try: J = self._calculateJacobian() - u,s,vh = numpy.linalg.svd(J,0) - self.cov = numpy.dot(vh.T.conj()/s**2,vh) + u, s, vh = numpy.linalg.svd(J, 0) + 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) @@ -207,7 +206,7 @@ def _calculateJacobian(self): # The list of constraint derivatives with respect to variables # The forward difference would be faster, but perhaps not as accurate. conr = [] - for k,v in enumerate(pvals): + for k, v in enumerate(pvals): h = delta[k] pvals[k] = v + h rk = self.recipe.residual(pvals) @@ -227,14 +226,14 @@ def _calculateJacobian(self): val = con.par.getValue() if numpy.isscalar(val): cond[i] -= con.par.getValue() - cond[i] /= 2*h + cond[i] /= 2 * h else: cond[i] = 0.0 conr.append(cond) pvals[k] = v - r.append(rk/(2*h)) + r.append(rk / (2 * h)) # Reset the constrained parameters to their original values for con in recipe._oconstraints: @@ -294,7 +293,7 @@ def _calculateConstraintUncertainties(self): self.conunc.append(sig2c**0.5) return - def formatResults(self, header = "", footer = "", update = False): + def formatResults(self, header="", footer="", update=False): """Format the results and return them in a string. This function is called by printResults and saveResults. Overloading @@ -313,7 +312,7 @@ def formatResults(self, header = "", footer = "", update = False): lines = [] corrmin = 0.25 p = self.precision - pe = "%-" + "%i.%ie" % (p+6, p) + pe = "%-" + "%i.%ie" % (p + 6, p) pet = "%" + ".%ie" % (p,) # Check to see if the uncertainty values are reliable. certain = True @@ -340,12 +339,12 @@ def formatResults(self, header = "", footer = "", update = False): lines.append(l) lines.append(_DASHEDLINE) formatstr = "%-14s %.8f" - lines.append(formatstr%("Residual",self.residual)) - lines.append(formatstr%("Contributions", self.residual - self.penalty)) - lines.append(formatstr%("Restraints", self.penalty)) - lines.append(formatstr%("Chi2",self.chi2)) - lines.append(formatstr%("Reduced Chi2",self.rchi2)) - lines.append(formatstr%("Rw",self.rw)) + lines.append(formatstr % ("Residual", self.residual)) + lines.append(formatstr % ("Contributions", self.residual - self.penalty)) + lines.append(formatstr % ("Restraints", self.penalty)) + lines.append(formatstr % ("Chi2", self.chi2)) + lines.append(formatstr % ("Reduced Chi2", self.rchi2)) + lines.append(formatstr % ("Rw", self.rw)) ## Per-FitContribution results if len(self.conresults) > 1: @@ -362,12 +361,12 @@ def formatResults(self, header = "", footer = "", update = False): for name in keys: res = self.conresults[name] lines.append("") - namestr = name + " (%f)"%res.weight + namestr = name + " (%f)" % res.weight lines.append(namestr) - lines.append("-"*len(namestr)) - lines.append(formatstr%("Residual",res.residual)) - lines.append(formatstr%("Chi2",res.chi2)) - lines.append(formatstr%("Rw",res.rw)) + lines.append("-" * len(namestr)) + lines.append(formatstr % ("Residual", res.residual)) + lines.append(formatstr % ("Chi2", res.chi2)) + lines.append(formatstr % ("Rw", res.rw)) ## The variables if self.varnames: @@ -375,7 +374,7 @@ def formatResults(self, header = "", footer = "", update = False): l = "Variables" if not certain: m = "Uncertainties invalid" - l += " (%s)"%m + l += " (%s)" % m lines.append(l) lines.append(_DASHEDLINE) @@ -385,11 +384,11 @@ def formatResults(self, header = "", footer = "", update = False): varlines = [] w = max(map(len, varnames)) - w = str(w+1) + w = str(w + 1) # Format the lines - formatstr = "%-"+w+"s " + pe + " +/- " + pet + formatstr = "%-" + w + "s " + pe + " +/- " + pet for name, val, unc in zip(varnames, varvals, varunc): - varlines.append(formatstr%(name, val, unc)) + varlines.append(formatstr % (name, val, unc)) varlines.sort() lines.extend(varlines) @@ -401,14 +400,13 @@ def formatResults(self, header = "", footer = "", update = False): lines.append("Fixed Variables") lines.append(_DASHEDLINE) w = max(map(len, self.fixednames)) - w = str(w+1) - formatstr = "%-"+w+"s " + pet + w = str(w + 1) + formatstr = "%-" + w + "s " + pet for name, val in zip(self.fixednames, self.fixedvals): - varlines.append(formatstr%(name, val)) + varlines.append(formatstr % (name, val)) varlines.sort() lines.extend(varlines) - ## The constraints if self.connames and self.showcon: lines.append("") @@ -432,16 +430,16 @@ def formatResults(self, header = "", footer = "", update = False): vals[name] = (val, unc) keys.sort(key=numstr) - w = str(w+1) - formatstr = "%-"+w+"s %- 15f +/- %-15f" + w = str(w + 1) + formatstr = "%-" + w + "s %- 15f +/- %-15f" for name in keys: val, unc = vals[name] - lines.append(formatstr%(name, val, unc)) + lines.append(formatstr % (name, val, unc)) ## Variable correlations lines.append("") - corint = int(corrmin*100) - l = "Variable Correlations greater than %i%%"%corint + corint = int(corrmin * 100) + l = "Variable Correlations greater than %i%%" % corint if not certain: l += " (Correlations invalid)" lines.append(l) @@ -451,33 +449,32 @@ def formatResults(self, header = "", footer = "", update = False): n = len(self.varnames) for i in range(n): for j in range(i + 1, n): - name = "corr(%s, %s)"%(varnames[i], varnames[j]) - val = (self.cov[i,j]/(self.cov[i,i] * self.cov[j,j])**0.5) + name = "corr(%s, %s)" % (varnames[i], varnames[j]) + val = self.cov[i, j] / (self.cov[i, i] * self.cov[j, j]) ** 0.5 if abs(val) > corrmin: cornames.append(name) tup.append((val, name)) - tup.sort(key=lambda vn : abs(vn[0])) + tup.sort(key=lambda vn: abs(vn[0])) tup.reverse() if cornames: w = max(map(len, cornames)) w = str(w + 1) - formatstr = "%-"+w+"s %.4f" + formatstr = "%-" + w + "s %.4f" for val, name in tup: - lines.append(formatstr%(name, val)) + lines.append(formatstr % (name, val)) else: - lines.append("No correlations greater than %i%%"%corint) - + lines.append("No correlations greater than %i%%" % corint) # User-defined footer if footer: lines.append(footer) - out = "\n".join(lines) + '\n' + out = "\n".join(lines) + "\n" return out - def printResults(self, header = "", footer = "", update = False): + def printResults(self, header="", footer="", update=False): """Format and print the results. header -- A header to add to the output (default "") @@ -491,8 +488,7 @@ def printResults(self, header = "", footer = "", update = False): def __str__(self): return self.formatResults() - - def saveResults(self, filename, header = "", footer = "", update = False): + def saveResults(self, filename, header="", footer="", update=False): """Format and save the results. filename - Name of the save file. @@ -502,20 +498,23 @@ def saveResults(self, filename, header = "", footer = "", update = False): """ # Save the time and user - from time import ctime from getpass import getuser + from time import ctime + myheader = "Results written: " + ctime() + "\n" myheader += "produced by " + getuser() + "\n" header = myheader + header res = self.formatResults(header, footer, update) - f = open(filename, 'w') + f = open(filename, "w") f.write(res) f.close() return + # End class FitResults + class ContributionResults(object): """Class for processing, storing FitContribution results. @@ -609,13 +608,14 @@ def _calculateMetrics(self): # We take absolute values in case the signal is complex num = numpy.abs(self.y - self.ycalc) y = numpy.abs(self.y) - chiv = num/self.dy + chiv = num / self.dy self.cumchi2 = numpy.cumsum(chiv**2) # avoid index error for empty array self.chi2 = self.cumchi2[-1:].sum() yw = y / self.dy yw2tot = numpy.dot(yw, yw) - if yw2tot == 0.0: yw2tot = 1.0 + if yw2tot == 0.0: + yw2tot = 1.0 self.cumrw = numpy.sqrt(self.cumchi2 / yw2tot) # avoid index error for empty array self.rw = self.cumrw[-1:].sum() @@ -624,6 +624,7 @@ def _calculateMetrics(self): # End class ContributionResults + def resultsDictionary(results): """Get dictionary of results from file. @@ -636,8 +637,7 @@ def resultsDictionary(results): """ resstr = inputToString(results) - rx = {'f' : r"[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?", - 'n' : r'[a-zA-Z_]\w*'} + rx = {"f": r"[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?", "n": r"[a-zA-Z_]\w*"} pat = r"(%(n)s)\s+(%(f)s)" % rx matches = re.findall(pat, resstr) @@ -646,6 +646,7 @@ def resultsDictionary(results): mpairs = dict(matches) return mpairs + def initializeRecipe(recipe, results): """Initialize the variables of a recipe from a results file. diff --git a/src/diffpy/srfit/fitbase/parameter.py b/src/diffpy/srfit/fitbase/parameter.py index 277bfc52..8ef3b083 100644 --- a/src/diffpy/srfit/fitbase/parameter.py +++ b/src/diffpy/srfit/fitbase/parameter.py @@ -29,12 +29,12 @@ import numpy -from diffpy.srfit.exceptions import SrFitError from diffpy.srfit.equation.literals import Argument -from diffpy.srfit.util.nameutils import validateName -from diffpy.srfit.util.argbinders import bind2nd -from diffpy.srfit.interface import _parameter_interface +from diffpy.srfit.exceptions import SrFitError from diffpy.srfit.fitbase.validatable import Validatable +from diffpy.srfit.interface import _parameter_interface +from diffpy.srfit.util.argbinders import bind2nd +from diffpy.srfit.util.nameutils import validateName class Parameter(_parameter_interface, Argument, Validatable): @@ -53,7 +53,7 @@ class Parameter(_parameter_interface, Argument, Validatable): """ - def __init__(self, name, value = None, const = False): + def __init__(self, name, value=None, const=False): """Initialization. name -- The name of this Parameter (must be a valid attribute @@ -86,7 +86,7 @@ def setValue(self, val): Argument.setValue(self, val) return self - def setConst(self, const = True, value = None): + def setConst(self, const=True, value=None): """Toggle the Parameter as constant. const -- Flag indicating if the parameter is constant (default @@ -103,7 +103,6 @@ def setConst(self, const = True, value = None): self.setValue(value) return self - def boundRange(self, lb=None, ub=None): """Set lower and upper bound of the Parameter. @@ -118,8 +117,7 @@ def boundRange(self, lb=None, ub=None): self.bounds[1] = ub return self - - def boundWindow(self, lr = 0, ur = None): + def boundWindow(self, lr=0, ur=None): """Create bounds centered on the current value of the Parameter. lr -- The radius of the lower bound (default 0). The lower bound is @@ -148,11 +146,13 @@ def _validate(self): """ if self.value is None: - raise SrFitError("value of '%s' is None"%self.name) + raise SrFitError("value of '%s' is None" % self.name) return + # End class Parameter + class ParameterProxy(Parameter): """A Parameter proxy for another parameter. @@ -165,7 +165,6 @@ class ParameterProxy(Parameter): """ - def __init__(self, name, par): """Initialization. @@ -185,8 +184,7 @@ def __init__(self, name, par): @property def constrained(self): - """A flag indicating if the proxied Parameter is constrained. - """ + """A flag indicating if the proxied Parameter is constrained.""" return self.par.constrained @constrained.setter @@ -194,7 +192,6 @@ def constrained(self, value): self.par.constrained = bool(value) return - @property def bounds(self): """List of lower and upper bounds of the proxied Parameter. @@ -209,7 +206,6 @@ def bounds(self, value): self.par.bounds = value return - @property def _observers(self): return self.par._observers @@ -220,27 +216,22 @@ def _observers(self): def setValue(self, val): return self.par.setValue(val) - @wraps(Parameter.getValue) def getValue(self): return self.par.getValue() - @wraps(Parameter.setConst) def setConst(self, const=True, value=None): return self.par.setConst(const, value) - @wraps(Parameter.boundRange) def boundRange(self, lb=None, ub=None): return self.par.boundRange(lb, ub) - @wraps(Parameter.boundWindow) def boundWindow(self, lr=0, ur=None): return self.par.boundWindow(lr, ur) - def _validate(self): """Validate my state. @@ -254,6 +245,7 @@ def _validate(self): self.par._validate() return + # End class ParameterProxy @@ -265,7 +257,7 @@ class ParameterAdapter(Parameter): """ - def __init__(self, name, obj, getter = None, setter = None, attr = None): + def __init__(self, name, obj, getter=None, setter=None, attr=None): """Wrap an object as a Parameter. name -- The name of this Parameter. @@ -326,6 +318,7 @@ def setValue(self, value): self.notify() return self + # End class ParameterAdapter # End of file diff --git a/src/diffpy/srfit/fitbase/parameterset.py b/src/diffpy/srfit/fitbase/parameterset.py index a13d7ea5..ef64c8e9 100644 --- a/src/diffpy/srfit/fitbase/parameterset.py +++ b/src/diffpy/srfit/fitbase/parameterset.py @@ -98,7 +98,7 @@ def removeParameterSet(self, parset): self._removeObject(parset, self._parsets) return - def setConst(self, const = True): + def setConst(self, const=True): """Set every parameter within the set to a constant. const -- Flag indicating if the parameter is constant (default @@ -110,6 +110,7 @@ def setConst(self, const = True): return + # End class ParameterSet # End of file diff --git a/src/diffpy/srfit/fitbase/profile.py b/src/diffpy/srfit/fitbase/profile.py index 292fdb89..02145e93 100644 --- a/src/diffpy/srfit/fitbase/profile.py +++ b/src/diffpy/srfit/fitbase/profile.py @@ -23,13 +23,13 @@ __all__ = ["Parameter", "Profile"] -import six import numpy +import six -from diffpy.srfit.util.observable import Observable +from diffpy.srfit.exceptions import SrFitError from diffpy.srfit.fitbase.parameter import Parameter from diffpy.srfit.fitbase.validatable import Validatable -from diffpy.srfit.exceptions import SrFitError +from diffpy.srfit.util.observable import Observable # This is the roundoff tolerance for selecting bounds on arrays. epsilon = 1e-8 @@ -88,19 +88,15 @@ def __init__(self): return # We want x, y, ycalc and dy to stay in-sync with xpar, ypar and dypar - x = property( lambda self : self.xpar.getValue(), - lambda self, val : self.xpar.setValue(val) ) - y = property( lambda self : self.ypar.getValue(), - lambda self, val : self.ypar.setValue(val) ) - dy = property( lambda self : self.dypar.getValue(), - lambda self, val : self.dypar.setValue(val) ) - ycalc = property( lambda self : self.ycpar.getValue(), - lambda self, val : self.ycpar.setValue(val) ) + x = property(lambda self: self.xpar.getValue(), lambda self, val: self.xpar.setValue(val)) + y = property(lambda self: self.ypar.getValue(), lambda self, val: self.ypar.setValue(val)) + dy = property(lambda self: self.dypar.getValue(), lambda self, val: self.dypar.setValue(val)) + ycalc = property(lambda self: self.ycpar.getValue(), lambda self, val: self.ycpar.setValue(val)) # We want xobs, yobs and dyobs to be read-only - xobs = property( lambda self: self._xobs ) - yobs = property( lambda self: self._yobs ) - dyobs = property( lambda self: self._dyobs ) + xobs = property(lambda self: self._xobs) + yobs = property(lambda self: self._yobs) + dyobs = property(lambda self: self._dyobs) def loadParsedData(self, parser): """Load parsed data from a ProfileParser. @@ -113,7 +109,7 @@ def loadParsedData(self, parser): self.setObservedProfile(x, y, dy) return - def setObservedProfile(self, xobs, yobs, dyobs = None): + def setObservedProfile(self, xobs, yobs, dyobs=None): """Set the observed profile. Arguments @@ -182,29 +178,27 @@ def setCalculationRange(self, xmin=None, xmax=None, dx=None): """ if self.xobs is None: raise AttributeError("No observed profile") + # local helper function def _isobs(a): if not isinstance(a, six.string_types): return False - if a != 'obs': + if a != "obs": raise ValueError('Must be either float or "obs".') return True + # resolve new low and high bounds for x - lo = (self.x[0] if xmin is None else - self.xobs[0] if _isobs(xmin) else float(xmin)) + lo = self.x[0] if xmin is None else self.xobs[0] if _isobs(xmin) else float(xmin) lo = max(lo, self.xobs[0]) - hi = (self.x[-1] if xmax is None else - self.xobs[-1] if _isobs(xmax) else float(xmax)) + hi = self.x[-1] if xmax is None else self.xobs[-1] if _isobs(xmax) else float(xmax) hi = min(hi, self.xobs[-1]) # determine if we need to clip the original grid clip = True step = None ncur = len(self.x) - stepcur = (1 if ncur < 2 - else (self.x[-1] - self.x[0]) / (ncur - 1.0)) + stepcur = 1 if ncur < 2 else (self.x[-1] - self.x[0]) / (ncur - 1.0) nobs = len(self.xobs) - stepobs = (1 if nobs < 2 - else (self.xobs[-1] - self.xobs[0]) / (nobs - 1.0)) + stepobs = 1 if nobs < 2 else (self.xobs[-1] - self.xobs[0]) / (nobs - 1.0) if dx is None: # check if xobs overlaps with x i0 = numpy.fabs(self.xobs - self.x[0]).argmin() @@ -244,7 +238,6 @@ def _isobs(a): self.setCalculationPoints(x1) return - def setCalculationPoints(self, x): """Set the calculation points. @@ -258,8 +251,8 @@ def setCalculationPoints(self, x): """ x = numpy.asarray(x) if self.xobs is not None: - x = x[ x >= self.xobs[0] - epsilon ] - x = x[ x <= self.xobs[-1] + epsilon ] + x = x[x >= self.xobs[0] - epsilon] + x = x[x <= self.xobs[-1] + epsilon] self.x = x if self.yobs is not None: self.y = rebinArray(self.yobs, self.xobs, self.x) @@ -268,8 +261,8 @@ def setCalculationPoints(self, x): if (self.dyobs == 1).all(): self.dy = numpy.ones_like(self.x) else: - # FIXME - This does not follow error propogation rules and it - # introduces (more) correlation between the data points. + # FIXME - This does not follow error propogation rules and it + # introduces (more) correlation between the data points. self.dy = rebinArray(self.dyobs, self.xobs, self.x) return @@ -309,7 +302,6 @@ def loadtxt(self, *args, **kw): self.setObservedProfile(x, y, dy) return x, y, dy - def savetxt(self, fname, **kwargs): """Call `numpy.savetxt` with x, ycalc, y, dy. @@ -337,12 +329,11 @@ def savetxt(self, fname, **kwargs): raise SrFitError("ycalc is None") y = self.y dy = self.dy - kwargs.setdefault('header', 'x ycalc y dy') + kwargs.setdefault("header", "x ycalc y dy") data = numpy.transpose([x, ycalc, y, dy]) numpy.savetxt(fname, data, **kwargs) return - def _flush(self, other): """Invalidate cached state. @@ -362,8 +353,7 @@ def _validate(self): Raises SrFitError if validation fails. """ - datanotset = any(v is None for v in - [self.x, self.y, self.dy, self.xobs, self.yobs, self.dyobs]) + datanotset = any(v is None for v in [self.x, self.y, self.dy, self.xobs, self.yobs, self.dyobs]) if datanotset: raise SrFitError("Missing data") if len(self.x) != len(self.y) or len(self.x) != len(self.dy): @@ -373,6 +363,7 @@ def _validate(self): # End class Profile + def rebinArray(A, xold, xnew): """Rebin the an array by interpolating over the new x range. diff --git a/src/diffpy/srfit/fitbase/profilegenerator.py b/src/diffpy/srfit/fitbase/profilegenerator.py index 5d0fed84..80a5958b 100644 --- a/src/diffpy/srfit/fitbase/profilegenerator.py +++ b/src/diffpy/srfit/fitbase/profilegenerator.py @@ -45,8 +45,8 @@ from diffpy.srfit.equation.literals.operators import Operator -from diffpy.srfit.fitbase.parameterset import ParameterSet from diffpy.srfit.exceptions import SrFitError +from diffpy.srfit.fitbase.parameterset import ParameterSet class ProfileGenerator(Operator, ParameterSet): @@ -95,7 +95,6 @@ class ProfileGenerator(Operator, ParameterSet): nin = 0 nout = 1 - def __init__(self, name): """Initialize the attributes.""" Operator.__init__(self) @@ -104,7 +103,6 @@ def __init__(self, name): self.meta = {} return - @property def symbol(self): return self.name @@ -131,7 +129,6 @@ def operation(self): y = self.__call__(self.profile.x) return y - def setProfile(self, profile): """Assign the profile. @@ -147,7 +144,7 @@ def setProfile(self, profile): self._flush(other=(self,)) # Merge the profiles metadata with our own - self.meta.update( self.profile.meta ) + self.meta.update(self.profile.meta) self.processMetaData() return diff --git a/src/diffpy/srfit/fitbase/profileparser.py b/src/diffpy/srfit/fitbase/profileparser.py index 8dff0cf2..40812224 100644 --- a/src/diffpy/srfit/fitbase/profileparser.py +++ b/src/diffpy/srfit/fitbase/profileparser.py @@ -105,7 +105,7 @@ def parseFile(self, filename): Raises ParseError if the file cannot be parsed """ - infile = open(filename, 'r') + infile = open(filename, "r") self._banks = [] self._meta = {} filestring = infile.read() @@ -155,7 +155,7 @@ def selectBank(self, index): self._x, self._y, self._dx, self._dy = self._banks[index] return - def getData(self, index = None): + def getData(self, index=None): """Get the data. This method should only be called after the data has been parsed. The @@ -179,4 +179,5 @@ def getMetaData(self): """Get the parsed metadata.""" return self._meta + # End of ProfileParser diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index e3c95267..bbec6072 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -23,26 +23,25 @@ __all__ = ["RecipeContainer", "RecipeOrganizer", "equationFromString"] -from numpy import inf +import re from collections import OrderedDict from itertools import chain, groupby -import re import six +from numpy import inf +from diffpy.srfit.equation import Equation +from diffpy.srfit.equation.builder import EquationFactory +from diffpy.srfit.fitbase.configurable import Configurable from diffpy.srfit.fitbase.constraint import Constraint -from diffpy.srfit.fitbase.restraint import Restraint from diffpy.srfit.fitbase.parameter import Parameter -from diffpy.srfit.fitbase.configurable import Configurable +from diffpy.srfit.fitbase.restraint import Restraint from diffpy.srfit.fitbase.validatable import Validatable - -from diffpy.srfit.util.observable import Observable -from diffpy.srfit.equation import Equation -from diffpy.srfit.equation.builder import EquationFactory -from diffpy.srfit.util.nameutils import validateName from diffpy.srfit.interface import _recipeorganizer_interface from diffpy.srfit.util import _DASHEDLINE from diffpy.srfit.util import sortKeyForNumericString as numstr +from diffpy.srfit.util.nameutils import validateName +from diffpy.srfit.util.observable import Observable class RecipeContainer(Observable, Configurable, Validatable): @@ -109,7 +108,6 @@ def _iterManaged(self): """Get iterator over managed objects.""" return chain(*(d.values() for d in self.__managed)) - def iterPars(self, pattern="", recurse=True): """Iterate over the Parameters contained in this object. @@ -137,7 +135,6 @@ def iterPars(self, pattern="", recurse=True): yield par return - def __iter__(self): """Iterate over top-level parameters.""" return iter(self._parameters.values()) @@ -158,12 +155,13 @@ def __getattr__(self, name): raise AttributeError(name) return arg - # Ensure there is no __dir__ override in the base class. - assert (getattr(Observable, '__dir__', None) is - getattr(Configurable, '__dir__', None) is - getattr(Validatable, '__dir__', None) is - getattr(object, '__dir__', None)) + assert ( + getattr(Observable, "__dir__", None) + is getattr(Configurable, "__dir__", None) + is getattr(Validatable, "__dir__", None) + is getattr(object, "__dir__", None) + ) def __dir__(self): "Return sorted list of attributes for this object." @@ -175,7 +173,6 @@ def __dir__(self): rv = sorted(rv) return rv - # Needed by __setattr__ _parameters = OrderedDict() __managed = [] @@ -192,12 +189,11 @@ def __setattr__(self, name, value): m = self.get(name) if m is not None: - raise AttributeError("Cannot set '%s'"%name) + raise AttributeError("Cannot set '%s'" % name) super(RecipeContainer, self).__setattr__(name, value) return - def __delattr__(self, name): """Delete parameters with del. @@ -205,17 +201,17 @@ def __delattr__(self, name): configuration changes that are not yet handled in a general way. """ if name in self._parameters: - self._removeParameter( self._parameters[name] ) + self._removeParameter(self._parameters[name]) return m = self.get(name) if m is not None: - raise AttributeError("Cannot delete '%s'"%name) + raise AttributeError("Cannot delete '%s'" % name) super(RecipeContainer, self).__delattr__(name) return - def get(self, name, default = None): + def get(self, name, default=None): """Get a managed object.""" for d in self.__managed: arg = d.get(name) @@ -232,7 +228,7 @@ def getValues(self): """Get the values of managed parameters.""" return [p.value for p in self._parameters.values()] - def _addObject(self, obj, d, check = True): + def _addObject(self, obj, d, check=True): """Add an object to a managed dictionary. obj -- The object to be stored. @@ -253,14 +249,12 @@ def _addObject(self, obj, d, check = True): # Check for extant object in d with same name oldobj = d.get(obj.name) if check and oldobj is not None: - message = "%s with name '%s' already exists"%\ - (obj.__class__.__name__, obj.name) + message = "%s with name '%s' already exists" % (obj.__class__.__name__, obj.name) raise ValueError(message) # Check for object with same name in other dictionary. if oldobj is None and self.get(obj.name) is not None: - message = "Non-%s with name '%s' already exists"%\ - (obj.__class__.__name__, obj.name) + message = "Non-%s with name '%s' already exists" % (obj.__class__.__name__, obj.name) raise ValueError(message) # Detach the old object, if there is one @@ -346,6 +340,7 @@ def _validate(self): # End class RecipeContainer + class RecipeOrganizer(_recipeorganizer_interface, RecipeContainer): """Extended base class for organizing pieces of a FitRecipe. @@ -436,7 +431,7 @@ def _removeParameter(self, par): self._eqfactory.deRegisterBuilder(par.name) return - def registerCalculator(self, f, argnames = None): + def registerCalculator(self, f, argnames=None): """Register a Calculator so it can be used within equation strings. A Calculator is an elaborate function that can organize Parameters. @@ -456,7 +451,7 @@ def registerCalculator(self, f, argnames = None): if argnames is None: fncode = f.__call__.__func__.__code__ argnames = list(fncode.co_varnames) - argnames = argnames[1:fncode.co_argcount] + argnames = argnames[1 : fncode.co_argcount] for pname in argnames: if pname not in self._eqfactory.builders: @@ -469,7 +464,7 @@ def registerCalculator(self, f, argnames = None): eq = self._eqfactory.makeEquation(f.name) return eq - def registerFunction(self, f, name = None, argnames = None): + def registerFunction(self, f, name=None, argnames=None): """Register a function so it can be used within equation strings. This creates a function with this class that can be used within string @@ -523,12 +518,12 @@ def registerFunction(self, f, name = None, argnames = None): fncode = f.__code__ # check class method elif inspect.ismethod(f): - fncode = f.__func__.__code__ - offset = 1 + fncode = f.__func__.__code__ + offset = 1 # check functor - elif hasattr(f, "__call__") and hasattr(f.__call__, '__func__'): - fncode = f.__call__.__func__.__code__ - offset = 1 + elif hasattr(f, "__call__") and hasattr(f.__call__, "__func__"): + fncode = f.__call__.__func__.__code__ + offset = 1 else: m = "Cannot extract name or argnames" raise ValueError(m) @@ -536,14 +531,14 @@ def registerFunction(self, f, name = None, argnames = None): # Extract the name if name is None: name = fncode.co_name - if name == '': + if name == "": m = "You must supply a name name for a lambda function" raise ValueError(m) # Extract the arguments if argnames is None: argnames = list(fncode.co_varnames) - argnames = argnames[offset:fncode.co_argcount] + argnames = argnames[offset : fncode.co_argcount] #### End introspection code @@ -554,6 +549,7 @@ def registerFunction(self, f, name = None, argnames = None): # Initialize and register from diffpy.srfit.fitbase.calculator import Calculator + if isinstance(f, Calculator): for pname in argnames: par = self.get(pname) @@ -567,7 +563,7 @@ def registerFunction(self, f, name = None, argnames = None): return eq - def registerStringFunction(self, fstr, name, ns = {}): + def registerStringFunction(self, fstr, name, ns={}): """Register a string function. This creates a function with this class that can be used within string @@ -589,8 +585,7 @@ def registerStringFunction(self, fstr, name, ns = {}): """ # Build the equation instance. - eq = equationFromString(fstr, self._eqfactory, ns = ns, buildargs = - True) + eq = equationFromString(fstr, self._eqfactory, ns=ns, buildargs=True) eq.name = name # Register any new Parameters. @@ -601,8 +596,7 @@ def registerStringFunction(self, fstr, name, ns = {}): argnames = eq.argdict.keys() return self.registerFunction(eq, name, argnames) - - def evaluateEquation(self, eqstr, ns = {}): + def evaluateEquation(self, eqstr, ns={}): """Evaluate a string equation. eqstr -- A string equation to evaluate. The equation is evaluated at @@ -620,8 +614,7 @@ def evaluateEquation(self, eqstr, ns = {}): self._eqfactory.wipeout(eq) return rv - - def constrain(self, par, con, ns = {}): + def constrain(self, par, con, ns={}): """Constrain a parameter to an equation. Note that only one constraint can exist on a Parameter at a time. @@ -651,16 +644,16 @@ def constrain(self, par, con, ns = {}): raise ValueError("The parameter cannot be found") if par.const: - raise ValueError("The parameter '%s' is constant"%par) + raise ValueError("The parameter '%s' is constant" % par) if isinstance(con, six.string_types): eqstr = con eq = equationFromString(con, self._eqfactory, ns) else: - eq = Equation(root = con) + eq = Equation(root=con) eqstr = con.name - eq.name = "_constraint_%s"%par.name + eq.name = "_constraint_%s" % par.name # Make and store the constraint con = Constraint() @@ -683,7 +676,7 @@ def isConstrained(self, par): name = par par = self.get(name) - return (par in self._constraints) + return par in self._constraints def unconstrain(self, *pars): """Unconstrain a Parameter. @@ -719,7 +712,7 @@ def unconstrain(self, *pars): return - def getConstrainedPars(self, recurse = False): + def getConstrainedPars(self, recurse=False): """Get a list of constrained managed Parameters in this object. recurse -- Recurse into managed objects and retrive their constrained @@ -728,7 +721,7 @@ def getConstrainedPars(self, recurse = False): const = self._getConstraints(recurse) return const.keys() - def clearConstraints(self, recurse = False): + def clearConstraints(self, recurse=False): """Clear all constraints managed by this organizer. recurse -- Recurse into managed objects and clear all constraints @@ -741,13 +734,12 @@ def clearConstraints(self, recurse = False): self.unconstrain(*self._constraints) if recurse: - f = lambda m : hasattr(m, "clearConstraints") + f = lambda m: hasattr(m, "clearConstraints") for m in filter(f, self._iterManaged()): m.clearConstraints(recurse) return - def restrain(self, res, lb = -inf, ub = inf, sig = 1, scaled = False, ns = - {}): + def restrain(self, res, lb=-inf, ub=inf, sig=1, scaled=False, ns={}): """Restrain an expression to specified bounds res -- An equation string or Parameter to restrain. @@ -778,7 +770,7 @@ def restrain(self, res, lb = -inf, ub = inf, sig = 1, scaled = False, ns = eqstr = res eq = equationFromString(res, self._eqfactory, ns) else: - eq = Equation(root = res) + eq = Equation(root=res) eqstr = res.name # Make and store the restraint @@ -816,7 +808,7 @@ def unrestrain(self, *ress): return - def clearRestraints(self, recurse = False): + def clearRestraints(self, recurse=False): """Clear all restraints. recurse -- Recurse into managed objects and clear all restraints @@ -825,33 +817,33 @@ def clearRestraints(self, recurse = False): self.unrestrain(*self._restraints) if recurse: - f = lambda m : hasattr(m, "clearRestraints") + f = lambda m: hasattr(m, "clearRestraints") for m in filter(f, self._iterManaged()): m.clearRestraints(recurse) return - def _getConstraints(self, recurse = True): + def _getConstraints(self, recurse=True): """Get the constrained Parameters for this and managed sub-objects.""" constraints = {} if recurse: - f = lambda m : hasattr(m, "_getConstraints") + f = lambda m: hasattr(m, "_getConstraints") for m in filter(f, self._iterManaged()): - constraints.update( m._getConstraints(recurse) ) + constraints.update(m._getConstraints(recurse)) - constraints.update( self._constraints) + constraints.update(self._constraints) return constraints - def _getRestraints(self, recurse = True): + def _getRestraints(self, recurse=True): """Get the Restraints for this and embedded ParameterSets. This returns a set of Restraint objects. """ restraints = set(self._restraints) if recurse: - f = lambda m : hasattr(m, "_getRestraints") + f = lambda m: hasattr(m, "_getRestraints") for m in filter(f, self._iterManaged()): - restraints.update( m._getRestraints(recurse) ) + restraints.update(m._getRestraints(recurse)) return restraints @@ -889,9 +881,8 @@ def _formatManaged(self, prefix=""): if self._parameters: w0 = max(len(n) for n in self._parameters) w1 = ((w0 + len(prefix) + 1) // 4 + 1) * 4 - fmt = formatstr.replace('W', str(w1)) - lines.extend(fmt.format(prefix + n, p.value) - for n, p in self._parameters.items()) + fmt = formatstr.replace("W", str(w1)) + lines.extend(fmt.format(prefix + n, p.value) for n, p in self._parameters.items()) # Recurse into managed objects. for obj in self._iterManaged(): if hasattr(obj, "_formatManaged"): @@ -901,7 +892,6 @@ def _formatManaged(self, prefix=""): lines.extend(tlines) return lines - def _formatConstraints(self): """Format constraints for showing. @@ -927,7 +917,6 @@ def _formatConstraints(self): clines.sort(key=numstr) return clines - def _formatRestraints(self): """Format restraints for showing. @@ -943,13 +932,11 @@ def _formatRestraints(self): rset = self._getRestraints() rlines = [] for res in rset: - line = "%s: lb = %f, ub = %f, sig = %f, scaled = %s"%\ - (res.eqstr, res.lb, res.ub, res.sig, res.scaled) + line = "%s: lb = %f, ub = %f, sig = %f, scaled = %s" % (res.eqstr, res.lb, res.ub, res.sig, res.scaled) rlines.append(line) rlines.sort(key=numstr) return rlines - def show(self, pattern="", textwidth=78): """Show the configuration hierarchy on the screen. @@ -965,8 +952,7 @@ 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 = lambda s: (len(s.split(None, 1)) < 2 or regexp.search(s.split(None, 1)[0])) # Show sub objects and their parameters lines = [] tlines = self._formatManaged() @@ -1007,10 +993,11 @@ def show(self, pattern="", textwidth=78): print("\n".join(s[:tw] for s in lines)) return + # End RecipeOrganizer -def equationFromString(eqstr, factory, ns = {}, buildargs = False, - argclass = Parameter, argkw = {}): + +def equationFromString(eqstr, factory, ns={}, buildargs=False, argclass=Parameter, argkw={}): """Make an equation from a string. eqstr -- A string representation of the equation. The equation must diff --git a/src/diffpy/srfit/fitbase/restraint.py b/src/diffpy/srfit/fitbase/restraint.py index 4ff2c1fa..3488e50f 100644 --- a/src/diffpy/srfit/fitbase/restraint.py +++ b/src/diffpy/srfit/fitbase/restraint.py @@ -25,8 +25,8 @@ from numpy import inf -from diffpy.srfit.fitbase.validatable import Validatable from diffpy.srfit.exceptions import SrFitError +from diffpy.srfit.fitbase.validatable import Validatable class Restraint(Validatable): @@ -49,7 +49,7 @@ class Restraint(Validatable): """ - def __init__(self, eq, lb = -inf, ub = inf, sig = 1, scaled = False): + def __init__(self, eq, lb=-inf, ub=inf, sig=1, scaled=False): """Restrain an equation to specified bounds. eq -- An equation whose evaluation is compared against the @@ -71,7 +71,7 @@ def __init__(self, eq, lb = -inf, ub = inf, sig = 1, scaled = False): self.scaled = bool(scaled) return - def penalty(self, w = 1.0): + def penalty(self, w=1.0): """Calculate the penalty of the restraint. w -- The point-average chi^2 which is optionally used to scale the @@ -81,7 +81,7 @@ def penalty(self, w = 1.0): """ val = self.eq() - penalty = (max(0, self.lb - val, val - self.ub) / self.sig)**2 + penalty = (max(0, self.lb - val, val - self.ub) / self.sig) ** 2 if self.scaled: penalty *= w @@ -99,6 +99,7 @@ def _validate(self): if self.eq is None: raise SrFitError("eq is None") from diffpy.srfit.equation.visitors import validate + try: validate(self.eq) except ValueError as e: @@ -115,6 +116,7 @@ def _validate(self): return + # End class Restraint # End of file diff --git a/src/diffpy/srfit/fitbase/simplerecipe.py b/src/diffpy/srfit/fitbase/simplerecipe.py index 9cb5cfe2..da9809c1 100644 --- a/src/diffpy/srfit/fitbase/simplerecipe.py +++ b/src/diffpy/srfit/fitbase/simplerecipe.py @@ -16,8 +16,8 @@ """Simple FitRecipe class that includes a FitContribution and Profile. """ -from diffpy.srfit.fitbase.fitrecipe import FitRecipe from diffpy.srfit.fitbase.fitcontribution import FitContribution +from diffpy.srfit.fitbase.fitrecipe import FitRecipe from diffpy.srfit.fitbase.fitresults import FitResults from diffpy.srfit.fitbase.profile import Profile @@ -68,7 +68,7 @@ class SimpleRecipe(FitRecipe): """ - def __init__(self, name = "fit", conclass = FitContribution): + def __init__(self, name="fit", conclass=FitContribution): """Initialization.""" FitRecipe.__init__(self, name) self.fithooks[0].verbose = 3 @@ -76,11 +76,10 @@ def __init__(self, name = "fit", conclass = FitContribution): self.profile = Profile() contribution.setProfile(self.profile) self.addContribution(contribution) - self.results = FitResults(self, update = False) + self.results = FitResults(self, update=False) # Adopt all the FitContribution methods - public = [aname for aname in dir(contribution) if aname not in - dir(self) and not aname.startswith("_")] + public = [aname for aname in dir(contribution) if aname not in dir(self) and not aname.startswith("_")] for mname in public: method = getattr(contribution, mname) setattr(self, mname, method) @@ -95,7 +94,7 @@ def loadParsedData(self, parser): """ return self.profile.loadParsedData(parser) - def setObservedProfile(self, xobs, yobs, dyobs = None): + def setObservedProfile(self, xobs, yobs, dyobs=None): """Set the observed profile. Arguments @@ -111,7 +110,6 @@ def setObservedProfile(self, xobs, yobs, dyobs = None): """ return self.profile.setObservedProfile(xobs, yobs, dyobs) - def setCalculationRange(self, xmin=None, xmax=None, dx=None): """Set epsilon-inclusive calculation range. @@ -146,7 +144,6 @@ def setCalculationRange(self, xmin=None, xmax=None, dx=None): """ return self.profile.setCalculationRange(xmin, xmax, dx) - def setCalculationPoints(self, x): """Set the calculation points. @@ -178,7 +175,7 @@ def loadtxt(self, *args, **kw): return self.profile.loadtxt(*args, **kw) # FitContribution - def setEquation(self, eqstr, ns = {}): + def setEquation(self, eqstr, ns={}): """Set the profile equation for the FitContribution. This sets the equation that will be used when generating the residual. @@ -195,11 +192,12 @@ def setEquation(self, eqstr, ns = {}): variable. """ - self.contribution.setEquation(eqstr, ns = {}) + self.contribution.setEquation(eqstr, ns={}) # Extract variables for par in self.contribution: # Skip Profile Parameters - if par.name in ("x", "y", "dy"): continue + if par.name in ("x", "y", "dy"): + continue if par.value is None: par.value = 0 if par.name not in self._parameters: @@ -212,7 +210,7 @@ def __call__(self): # FitResults methods - def printResults(self, header = "", footer = ""): + def printResults(self, header="", footer=""): """Format and print the results. header -- A header to add to the output (default "") @@ -222,7 +220,7 @@ def printResults(self, header = "", footer = ""): self.results.printResults(header, footer, True) return - def saveResults(self, filename, header = "", footer = ""): + def saveResults(self, filename, header="", footer=""): """Format and save the results. filename - Name of the save file. @@ -232,6 +230,7 @@ def saveResults(self, filename, header = "", footer = ""): """ self.results.saveResults(filename, header, footer, True) + # End class SimpleRecipe # End of file diff --git a/src/diffpy/srfit/fitbase/validatable.py b/src/diffpy/srfit/fitbase/validatable.py index c4db72c7..110dbbe0 100644 --- a/src/diffpy/srfit/fitbase/validatable.py +++ b/src/diffpy/srfit/fitbase/validatable.py @@ -38,7 +38,8 @@ def _validateOthers(self, iterable): """ for obj in iterable: - if obj is self: continue + if obj is self: + continue if isinstance(obj, Validatable): obj._validate() @@ -56,6 +57,7 @@ def _validate(self): # Then validate others. return + # End class Validatable # End of file diff --git a/src/diffpy/srfit/interface/__init__.py b/src/diffpy/srfit/interface/__init__.py index 8f6bd3a7..d3675428 100644 --- a/src/diffpy/srfit/interface/__init__.py +++ b/src/diffpy/srfit/interface/__init__.py @@ -22,12 +22,15 @@ from diffpy.srfit.interface.interface import ParameterInterface + _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/interface/interface.py b/src/diffpy/srfit/interface/interface.py index 94c5fb6d..31d9b869 100644 --- a/src/diffpy/srfit/interface/interface.py +++ b/src/diffpy/srfit/interface/interface.py @@ -21,8 +21,7 @@ objects. See individual interface classes for specifics. """ -__all__ = ["ParameterInterface", "FitRecipeInterface", - "RecipeOrganizerInterface"] +__all__ = ["ParameterInterface", "FitRecipeInterface", "RecipeOrganizerInterface"] import six @@ -45,10 +44,12 @@ def __lshift__(self, v): self.value = v return self + # End class ParameterInterface # ---------------------------------------------------------------------------- + class RecipeOrganizerInterface(object): """Mix-in class for enhancing the RecipeOrganizer interface.""" @@ -79,6 +80,7 @@ def __iadd__(self, args): This accepts arguments for a single function call. """ + # Want to detect _addParameter or _newParameter def f(*args): if isinstance(args[0], six.string_types): @@ -90,10 +92,12 @@ def f(*args): _applyargs(args, f) return self + # End class RecipeOrganizerInterface # ---------------------------------------------------------------------------- + class FitRecipeInterface(object): """Mix-in class for enhancing the FitRecipe interface.""" @@ -115,6 +119,7 @@ def __iadd__(self, args): This accepts a single argument or an iterable of single arguments or argument tuples. """ + # Want to detect addVar or newVar def f(*args): if isinstance(args[0], six.string_types): @@ -126,10 +131,12 @@ def f(*args): _applymanyargs(args, f) return self + # End class FitRecipeInterface # Local helper functions ----------------------------------------------------- + def _applymanyargs(args, f): """Apply arguments to a function. @@ -138,18 +145,19 @@ def _applymanyargs(args, f): (arg1, arg2, ...) ((arg1a, arg1b, ...), ...) """ - if not hasattr(args, '__iter__'): + if not hasattr(args, "__iter__"): f(args) return for arg in args: - if hasattr(arg, '__iter__'): + if hasattr(arg, "__iter__"): f(*arg) else: f(arg) return + def _applyargs(args, f): """Apply arguments to a function. @@ -158,10 +166,11 @@ def _applyargs(args, f): (arg1, arg2, ...) ((arg1a, arg1b, ...), ...) """ - if not hasattr(args, '__iter__'): + if not hasattr(args, "__iter__"): f(args) else: f(*args) return + # End of file diff --git a/src/diffpy/srfit/pdf/__init__.py b/src/diffpy/srfit/pdf/__init__.py index 956264e0..d0e7db8d 100644 --- a/src/diffpy/srfit/pdf/__init__.py +++ b/src/diffpy/srfit/pdf/__init__.py @@ -18,9 +18,9 @@ __all__ = ["PDFGenerator", "DebyePDFGenerator", "PDFContribution", "PDFParser"] -from diffpy.srfit.pdf.pdfgenerator import PDFGenerator from diffpy.srfit.pdf.debyepdfgenerator import DebyePDFGenerator from diffpy.srfit.pdf.pdfcontribution import PDFContribution +from diffpy.srfit.pdf.pdfgenerator import PDFGenerator from diffpy.srfit.pdf.pdfparser import PDFParser # End of file diff --git a/src/diffpy/srfit/pdf/basepdfgenerator.py b/src/diffpy/srfit/pdf/basepdfgenerator.py index f0f2747f..e6f6af7b 100644 --- a/src/diffpy/srfit/pdf/basepdfgenerator.py +++ b/src/diffpy/srfit/pdf/basepdfgenerator.py @@ -23,15 +23,15 @@ import numpy +from diffpy.srfit.exceptions import SrFitError from diffpy.srfit.fitbase import ProfileGenerator from diffpy.srfit.fitbase.parameter import ParameterAdapter from diffpy.srfit.structure import struToParameterSet -from diffpy.srfit.exceptions import SrFitError - # FIXME - Parameter creation will have to be smarter once deeper calculator # configuration is enabled. + class BasePDFGenerator(ProfileGenerator): """Base class for calculating PDF profiles using SrReal. @@ -74,7 +74,7 @@ class BasePDFGenerator(ProfileGenerator): """ - def __init__(self, name = "pdf"): + def __init__(self, name="pdf"): """Initialize the generator.""" ProfileGenerator.__init__(self, name) @@ -88,7 +88,7 @@ def __init__(self, name = "pdf"): return - _parnames = ['delta1', 'delta2', 'qbroad', 'scale', 'qdamp'] + _parnames = ["delta1", "delta2", "qbroad", "scale", "qdamp"] def _setCalculator(self, calc): """Set the SrReal calulator instance. @@ -99,13 +99,11 @@ def _setCalculator(self, calc): """ self._calc = calc for pname in self.__class__._parnames: - self.addParameter( - ParameterAdapter(pname, self._calc, attr = pname) - ) + self.addParameter(ParameterAdapter(pname, self._calc, attr=pname)) self.processMetaData() return - def parallel(self, ncpu, mapfunc = None): + def parallel(self, ncpu, mapfunc=None): """Run calculation in parallel. ncpu -- Number of parallel processes. Revert to serial mode when 1. @@ -115,8 +113,9 @@ def parallel(self, ncpu, mapfunc = None): No return value. """ from diffpy.srreal.parallel import createParallelCalculator + calc_serial = self._calc - if hasattr(calc_serial, 'pqobj'): + if hasattr(calc_serial, "pqobj"): calc_serial = calc_serial.pqobj # revert to serial calculator for ncpu <= 1 if ncpu <= 1: @@ -127,6 +126,7 @@ def parallel(self, ncpu, mapfunc = None): # ncpu = min(ncpu, multiprocessing.cpu_count()) if mapfunc is None: import multiprocessing + self._pool = multiprocessing.Pool(ncpu) mapfunc = self._pool.imap_unordered @@ -157,7 +157,7 @@ def processMetaData(self): return - def setScatteringType(self, stype = "X"): + def setScatteringType(self, stype="X"): """Set the scattering type. stype -- "X" for x-ray, "N" for neutron, "E" for electrons, @@ -186,8 +186,7 @@ def getQmax(self): return self._calc.qmax def setQmin(self, qmin): - """Set the qmin value. - """ + """Set the qmin value.""" self._calc.qmin = qmin self.meta["qmin"] = self.getQmin() return @@ -196,7 +195,7 @@ def getQmin(self): """Get the qmin value.""" return self._calc.qmin - def setStructure(self, stru, name = "phase", periodic = True): + def setStructure(self, stru, name="phase", periodic=True): """Set the structure that will be used to calculate the PDF. This creates a DiffpyStructureParSet, ObjCrystCrystalParSet or @@ -222,8 +221,7 @@ def setStructure(self, stru, name = "phase", periodic = True): self.setPhase(parset, periodic) return - - def setPhase(self, parset, periodic = True): + def setPhase(self, parset, periodic=True): """Set the phase that will be used to calculate the PDF. Set the phase directly with a DiffpyStructureParSet, @@ -258,7 +256,7 @@ def _prepare(self, r): ndiv = max(len(r) - 1, 1) self._calc.rstep = (hi - lo) / ndiv self._calc.rmin = lo - self._calc.rmax = hi + 0.5*self._calc.rstep + self._calc.rmax = hi + 0.5 * self._calc.rstep return def _validate(self): @@ -298,4 +296,5 @@ def __call__(self, r): y = numpy.interp(r, rcalc, y) return y + # End class BasePDFGenerator diff --git a/src/diffpy/srfit/pdf/characteristicfunctions.py b/src/diffpy/srfit/pdf/characteristicfunctions.py index 0d38a2a6..10139dac 100644 --- a/src/diffpy/srfit/pdf/characteristicfunctions.py +++ b/src/diffpy/srfit/pdf/characteristicfunctions.py @@ -25,14 +25,22 @@ the 'registerFunction' method of that class. """ -__all__ = ["sphericalCF", "spheroidalCF", "spheroidalCF2", - "lognormalSphericalCF", "sheetCF", "shellCF", "shellCF2", "SASCF"] +__all__ = [ + "sphericalCF", + "spheroidalCF", + "spheroidalCF2", + "lognormalSphericalCF", + "sheetCF", + "shellCF", + "shellCF2", + "SASCF", +] import numpy -from numpy import pi, sqrt, log, exp, log2, ceil, sign from numpy import arctan as atan from numpy import arctanh as atanh -from numpy.fft import ifft, fftfreq +from numpy import ceil, exp, log, log2, pi, sign, sqrt +from numpy.fft import fftfreq, ifft from scipy.special import erf from diffpy.srfit.fitbase.calculator import Calculator @@ -51,11 +59,12 @@ def sphericalCF(r, psize): f = numpy.zeros(numpy.shape(r), dtype=float) if psize > 0: x = numpy.array(r, dtype=float) / psize - inside = (x < 1.0) + inside = x < 1.0 xin = x[inside] - f[inside] = 1.0 - 1.5*xin + 0.5*xin*xin*xin + f[inside] = 1.0 - 1.5 * xin + 0.5 * xin * xin * xin return f + def spheroidalCF(r, erad, prad): """Spheroidal characteristic function specified using radii. @@ -73,6 +82,7 @@ def spheroidalCF(r, erad, prad): pelpt = 1.0 * prad / erad return spheroidalCF2(r, psize, pelpt) + def spheroidalCF2(r, psize, axrat): """Spheroidal nanoparticle characteristic function. @@ -93,8 +103,8 @@ def spheroidalCF2(r, psize, axrat): # to simplify the equations v = pelpt d = 1.0 * psize - d2 = d*d - v2 = v*v + d2 = d * d + v2 = v * v if v == 1: return sphericalCF(r, psize) @@ -102,40 +112,59 @@ def spheroidalCF2(r, psize, axrat): rx = r if v < 1: - r = rx[rx <= v*psize] - r2 = r*r - f1 = 1 - 3*r/(4*d*v)*(1-r2/(4*d2)*(1+2.0/(3*v2))) \ - - 3*r/(4*d)*(1-r2/(4*d2))*v/sqrt(1-v2)*atanh(sqrt(1-v2)) - - r = rx[numpy.logical_and(rx > v*psize, rx <= psize)] - r2 = r*r - f2 = (3*d/(8*r)*(1+r2/(2*d2))*sqrt(1-r2/d2) \ - - 3*r/(4*d)*(1-r2/(4*d2))*atanh(sqrt(1-r2/d2)) \ - ) * v/sqrt(1-v2) + r = rx[rx <= v * psize] + r2 = r * r + f1 = ( + 1 + - 3 * r / (4 * d * v) * (1 - r2 / (4 * d2) * (1 + 2.0 / (3 * v2))) + - 3 * r / (4 * d) * (1 - r2 / (4 * d2)) * v / sqrt(1 - v2) * atanh(sqrt(1 - v2)) + ) + + r = rx[numpy.logical_and(rx > v * psize, rx <= psize)] + r2 = r * r + f2 = ( + ( + 3 * d / (8 * r) * (1 + r2 / (2 * d2)) * sqrt(1 - r2 / d2) + - 3 * r / (4 * d) * (1 - r2 / (4 * d2)) * atanh(sqrt(1 - r2 / d2)) + ) + * v + / sqrt(1 - v2) + ) r = rx[rx > psize] f3 = numpy.zeros_like(r) - f = numpy.concatenate((f1,f2,f3)) + f = numpy.concatenate((f1, f2, f3)) elif v > 1: r = rx[rx <= psize] - r2 = r*r - f1 = 1 - 3*r/(4*d*v)*(1-r2/(4*d2)*(1+2.0/(3*v2))) \ - - 3*r/(4*d)*(1-r2/(4*d2))*v/sqrt(v2-1)*atan(sqrt(v2-1)) - - r = rx[numpy.logical_and(rx > psize, rx <= v*psize)] - r2 = r*r - f2 = 1 - 3*r/(4*d*v)*(1-r2/(4*d2)*(1+2.0/(3*v2))) \ - - 3.0/8*(1+r2/(2*d2))*sqrt(1-d2/r2)*v/sqrt(v2-1) \ - - 3*r/(4*d)*(1-r2/(4*d2))*v/sqrt(v2-1) \ - * (atan(sqrt(v2-1)) - atan(sqrt(r2/d2-1))) - - r = rx[rx > v*psize] + r2 = r * r + f1 = ( + 1 + - 3 * r / (4 * d * v) * (1 - r2 / (4 * d2) * (1 + 2.0 / (3 * v2))) + - 3 * r / (4 * d) * (1 - r2 / (4 * d2)) * v / sqrt(v2 - 1) * atan(sqrt(v2 - 1)) + ) + + r = rx[numpy.logical_and(rx > psize, rx <= v * psize)] + r2 = r * r + f2 = ( + 1 + - 3 * r / (4 * d * v) * (1 - r2 / (4 * d2) * (1 + 2.0 / (3 * v2))) + - 3.0 / 8 * (1 + r2 / (2 * d2)) * sqrt(1 - d2 / r2) * v / sqrt(v2 - 1) + - 3 + * r + / (4 * d) + * (1 - r2 / (4 * d2)) + * v + / sqrt(v2 - 1) + * (atan(sqrt(v2 - 1)) - atan(sqrt(r2 / d2 - 1))) + ) + + r = rx[rx > v * psize] f3 = numpy.zeros_like(r) - f = numpy.concatenate((f1,f2,f3)) + f = numpy.concatenate((f1, f2, f3)) return f @@ -166,19 +195,25 @@ def lognormalSphericalCF(r, psize, psig): Source unknown """ - if psize <= 0: return numpy.zeros_like(r) - if psig <= 0: return sphericalCF(r, psize) + if psize <= 0: + return numpy.zeros_like(r) + if psig <= 0: + return sphericalCF(r, psize) - erfc = lambda x: 1.0-erf(x) + 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; - if mu < 0: return numpy.zeros_like(r) + s = sqrt(log(psig * psig / (1.0 * psize * psize) + 1)) + mu = log(psize) - s * s / 2 + if mu < 0: + return numpy.zeros_like(r) + + return ( + 0.5 * erfc((-mu - 3 * s * s + log(r)) / (sqrt2 * s)) + + 0.25 * r * r * r * erfc((-mu + log(r)) / (sqrt2 * s)) * exp(-3 * mu - 4.5 * s * s) + - 0.75 * r * erfc((-mu - 2 * s * s + log(r)) / (sqrt2 * s)) * exp(-mu - 2.5 * s * s) + ) - return 0.5*erfc((-mu-3*s*s+log(r))/(sqrt2*s)) \ - + 0.25*r*r*r*erfc((-mu+log(r))/(sqrt2*s))*exp(-3*mu-4.5*s*s) \ - - 0.75*r*erfc((-mu-2*s*s+log(r))/(sqrt2*s))*exp(-mu-2.5*s*s) def sheetCF(r, sthick): """Nanosheet characteristic function. @@ -217,10 +252,11 @@ def shellCF(r, radius, thickness): From Lei et al., Phys. Rev. B, 80, 024118 (2009) """ - d = 1.0*thickness - a = 1.0*radius + d/2.0 + d = 1.0 * thickness + a = 1.0 * radius + d / 2.0 return shellCF2(r, a, d) + def shellCF2(r, a, delta): """Spherical shell characteristic function. @@ -232,22 +268,24 @@ def shellCF2(r, a, delta): From Lei et al., Phys. Rev. B, 80, 024118 (2009) """ - a = 1.0*a - d = 1.0*delta + a = 1.0 * a + d = 1.0 * delta a2 = a**2 d2 = d**2 - dmr = d-r + dmr = d - r dmr2 = dmr**2 - f = r * (16*a*a2 + 12*a*d*dmr + 36*a2*(2*d-r) + 3*dmr2*(2*d+r)) \ - + 2*dmr2 * (r*(2*d+r)-12*a2) * sign(dmr) \ - - 2*(2*a-r)**2 * (r*(4*a+r)-3*d2) * sign(2*a-r) \ - + r*(4*a-2*d+r)*(2*a-d-r)**2*sign(2*a-d-r) + f = ( + r * (16 * a * a2 + 12 * a * d * dmr + 36 * a2 * (2 * d - r) + 3 * dmr2 * (2 * d + r)) + + 2 * dmr2 * (r * (2 * d + r) - 12 * a2) * sign(dmr) + - 2 * (2 * a - r) ** 2 * (r * (4 * a + r) - 3 * d2) * sign(2 * a - r) + + r * (4 * a - 2 * d + r) * (2 * a - d - r) ** 2 * sign(2 * a - d - r) + ) - f[r > 2*a+d] = 0 + f[r > 2 * a + d] = 0 - den = 8.0*r*d*(12*a2+d2) - zmask = (den == 0.0) + den = 8.0 * r * d * (12 * a2 + d2) + zmask = den == 0.0 vmask = ~zmask f[vmask] /= den[vmask] f[zmask] = 1 @@ -286,6 +324,7 @@ def __init__(self, name, model): self._model = model from diffpy.srfit.sas.sasparameter import SASParameter + # Wrap normal parameters for parname in model.params: par = SASParameter(parname, model) @@ -327,11 +366,11 @@ def __call__(self, r): rmax = max(ed, 2 * r[-1]) dq = pi / rmax qmax = pi / dr - numpoints = int(2**(ceil(log2(qmax/dq)))) + numpoints = int(2 ** (ceil(log2(qmax / dq)))) qmax = dq * numpoints # Calculate F(q) = q * I(q) from model - q = fftfreq(int(qmax/dq)) * qmax + q = fftfreq(int(qmax / dq)) * qmax fq = q * self._model.evalDistribution(q) # Calculate g(r) and the effective r-points @@ -340,20 +379,20 @@ def __call__(self, r): gr = ifft(fq).imag # Calculate full-fr for normalization - assert (rp[0] == 0.0) + assert rp[0] == 0.0 frp = numpy.zeros_like(gr) frp[1:] = gr[1:] / rp[1:] # Inerpolate onto requested grid, do not use data after jump in rp - assert (numpoints % 2 == 0) + assert numpoints % 2 == 0 nhalf = numpoints / 2 fr = numpy.interp(r, rp[:nhalf], gr[:nhalf]) - vmask = (r != 0) + vmask = r != 0 fr[vmask] /= r[vmask] # Normalize. We approximate fr[0] by using the fact that f(r) is linear # at low r. By definition, fr[0] should equal 1. - fr0 = 2*frp[2] - frp[1] + fr0 = 2 * frp[2] - frp[1] fr /= fr0 # Fix potential divide-by-zero issue, fr is 1 at r == 0 diff --git a/src/diffpy/srfit/pdf/debyepdfgenerator.py b/src/diffpy/srfit/pdf/debyepdfgenerator.py index dd70d055..fcfaa577 100644 --- a/src/diffpy/srfit/pdf/debyepdfgenerator.py +++ b/src/diffpy/srfit/pdf/debyepdfgenerator.py @@ -66,7 +66,7 @@ class DebyePDFGenerator(BasePDFGenerator): """ - def setStructure(self, stru, name = "phase", periodic = False): + def setStructure(self, stru, name="phase", periodic=False): """Set the structure that will be used to calculate the PDF. This creates a DiffpyStructureParSet, ObjCrystCrystalParSet or @@ -86,8 +86,7 @@ def setStructure(self, stru, name = "phase", periodic = False): """ return BasePDFGenerator.setStructure(self, stru, name, periodic) - - def setPhase(self, parset, periodic = False): + def setPhase(self, parset, periodic=False): """Set the phase that will be used to calculate the PDF. Set the phase directly with a DiffpyStructureParSet, @@ -106,15 +105,15 @@ def setPhase(self, parset, periodic = False): """ return BasePDFGenerator.setPhase(self, parset, periodic) - - def __init__(self, name = "pdf"): - """Initialize the generator. - """ + def __init__(self, name="pdf"): + """Initialize the generator.""" from diffpy.srreal.pdfcalculator import DebyePDFCalculator + BasePDFGenerator.__init__(self, name) self._setCalculator(DebyePDFCalculator()) return + # End class DebyePDFGenerator # End of file diff --git a/src/diffpy/srfit/pdf/pdfcontribution.py b/src/diffpy/srfit/pdf/pdfcontribution.py index 1700eb5a..de485428 100644 --- a/src/diffpy/srfit/pdf/pdfcontribution.py +++ b/src/diffpy/srfit/pdf/pdfcontribution.py @@ -20,8 +20,8 @@ __all__ = ["PDFContribution"] -from diffpy.srfit.fitbase import FitContribution -from diffpy.srfit.fitbase import Profile +from diffpy.srfit.fitbase import FitContribution, Profile + class PDFContribution(FitContribution): """PDFContribution class. @@ -72,7 +72,7 @@ def __init__(self, name): self._meta = {} # Add the profile profile = Profile() - self.setProfile(profile, xname = "r") + self.setProfile(profile, xname="r") # Need a parameter for the overall scale, in the case that this is a # multi-phase fit. @@ -96,10 +96,12 @@ def loadData(self, data): """ # Get the data into a string from diffpy.srfit.util.inpututils import inputToString + datstr = inputToString(data) # Load data with a PDFParser from diffpy.srfit.pdf.pdfparser import PDFParser + parser = PDFParser() parser.parseString(datstr) @@ -107,7 +109,6 @@ def loadData(self, data): self.profile.loadParsedData(parser) return - def setCalculationRange(self, xmin=None, xmax=None, dx=None): """Set epsilon-inclusive calculation range. @@ -142,7 +143,6 @@ def setCalculationRange(self, xmin=None, xmax=None, dx=None): """ return self.profile.setCalculationRange(xmin, xmax, dx) - def savetxt(self, fname, **kwargs): """Call numpy.savetxt with x, ycalc, y, dy @@ -154,7 +154,7 @@ def savetxt(self, fname, **kwargs): # Phase methods - def addStructure(self, name, stru, periodic = True): + def addStructure(self, name, stru, periodic=True): """Add a phase that goes into the PDF calculation. name -- A name to give the generator that will manage the PDF @@ -180,9 +180,11 @@ def addStructure(self, name, stru, periodic = True): # Based on periodic, create the proper generator. if periodic: from diffpy.srfit.pdf.pdfgenerator import PDFGenerator + gen = PDFGenerator(name) else: from diffpy.srfit.pdf.debyepdfgenerator import DebyePDFGenerator + gen = DebyePDFGenerator(name) # Set up the generator @@ -191,7 +193,7 @@ def addStructure(self, name, stru, periodic = True): return gen.phase - def addPhase(self, name, parset, periodic = True): + def addPhase(self, name, parset, periodic=True): """Add a phase that goes into the PDF calculation. name -- A name to give the generator that will manage the PDF @@ -218,9 +220,11 @@ def addPhase(self, name, parset, periodic = True): # Based on periodic, create the proper generator. if periodic: from diffpy.srfit.pdf.pdfgenerator import PDFGenerator + gen = PDFGenerator(name) else: from diffpy.srfit.pdf.debyepdfgenerator import DebyePDFGenerator + gen = DebyePDFGenerator(name) # Set up the generator @@ -268,8 +272,7 @@ def _getMetaValue(self, kwd): val = self.profile.meta.get(kwd) return val - - def setScatteringType(self, type = "X"): + def setScatteringType(self, type="X"): """Set the scattering type. type -- "X" for x-ray or "N" for neutron @@ -298,8 +301,7 @@ def getQmax(self): return self._getMetaValue("qmax") def setQmin(self, qmin): - """Set the qmin value. - """ + """Set the qmin value.""" self._meta["qmin"] = qmin for gen in self._generators.values(): gen.setQmin(qmin) @@ -309,4 +311,5 @@ def getQmin(self): """Get the qmin value.""" return self._getMetaValue("qmin") + # End of file diff --git a/src/diffpy/srfit/pdf/pdfgenerator.py b/src/diffpy/srfit/pdf/pdfgenerator.py index 5a118ceb..d7ae7851 100644 --- a/src/diffpy/srfit/pdf/pdfgenerator.py +++ b/src/diffpy/srfit/pdf/pdfgenerator.py @@ -66,12 +66,13 @@ class PDFGenerator(BasePDFGenerator): """ - def __init__(self, name = "pdf"): - """Initialize the generator. - """ + def __init__(self, name="pdf"): + """Initialize the generator.""" from diffpy.srreal.pdfcalculator import PDFCalculator + BasePDFGenerator.__init__(self, name) self._setCalculator(PDFCalculator()) return + # End class PDFGenerator diff --git a/src/diffpy/srfit/pdf/pdfparser.py b/src/diffpy/srfit/pdf/pdfparser.py index 945c5184..84d9d060 100644 --- a/src/diffpy/srfit/pdf/pdfparser.py +++ b/src/diffpy/srfit/pdf/pdfparser.py @@ -23,11 +23,13 @@ __all__ = ["PDFParser"] import re + import numpy from diffpy.srfit.exceptions import ParseError from diffpy.srfit.fitbase.profileparser import ProfileParser + class PDFParser(ProfileParser): """Class for holding a diffraction pattern. @@ -91,15 +93,15 @@ def parseString(self, patstring): """ # useful regex patterns: - rx = { 'f' : r'[-+]?(\d+(\.\d*)?|\d*\.\d+)([eE][-+]?\d+)?' } + rx = {"f": r"[-+]?(\d+(\.\d*)?|\d*\.\d+)([eE][-+]?\d+)?"} # find where does the data start - res = re.search(r'^#+ start data\s*(?:#.*\s+)*', patstring, re.M) + res = re.search(r"^#+ start data\s*(?:#.*\s+)*", patstring, re.M) # start_data is position where the first data line starts if res: start_data = res.end() else: # find line that starts with a floating point number - regexp = r'^\s*%(f)s' % rx + regexp = r"^\s*%(f)s" % rx res = re.search(regexp, patstring, re.M) if res: start_data = res.start() @@ -109,19 +111,19 @@ def parseString(self, patstring): databody = patstring[start_data:].strip() # find where the metadata starts - metadata = '' - res = re.search(r'^#+\ +metadata\b\n', header, re.M) + metadata = "" + res = re.search(r"^#+\ +metadata\b\n", header, re.M) if res: - metadata = header[res.end():] - header = header[:res.start()] + metadata = header[res.end() :] + header = header[: res.start()] # parse header meta = self._meta # stype - if re.search('(x-?ray|PDFgetX)', header, re.I): - meta["stype"] = 'X' - elif re.search('(neutron|PDFgetN)', header, re.I): - meta["stype"] = 'N' + if re.search("(x-?ray|PDFgetX)", header, re.I): + meta["stype"] = "X" + elif re.search("(neutron|PDFgetN)", header, re.I): + meta["stype"] = "N" # qmin regexp = r"\bqmin *= *(%(f)s)\b" % rx res = re.search(regexp, header, re.I) @@ -156,12 +158,12 @@ def parseString(self, patstring): regexp = r"\b(?:temp|temperature|T)\ *=\ *(%(f)s)\b" % rx res = re.search(regexp, header) if res: - meta['temperature'] = float(res.groups()[0]) + meta["temperature"] = float(res.groups()[0]) # doping regexp = r"\b(?:x|doping)\ *=\ *(%(f)s)\b" % rx res = re.search(regexp, header) if res: - meta['doping'] = float(res.groups()[0]) + meta["doping"] = float(res.groups()[0]) # parsing gerneral metadata if metadata: @@ -170,12 +172,12 @@ def parseString(self, patstring): res = re.search(regexp, metadata, re.M) if res: meta[res.groups()[0]] = float(res.groups()[1]) - metadata = metadata[res.end():] + metadata = metadata[res.end() :] else: break # read actual data - robs, Gobs, drobs, dGobs - inf_or_nan = re.compile('(?i)^[+-]?(NaN|Inf)\\b') + inf_or_nan = re.compile("(?i)^[+-]?(NaN|Inf)\\b") has_drobs = True has_dGobs = True # raise ParseError if something goes wrong @@ -190,15 +192,13 @@ def parseString(self, patstring): robs.append(float(v[0])) Gobs.append(float(v[1])) # drobs is valid if all values are defined and positive - has_drobs = (has_drobs and - len(v) > 2 and not inf_or_nan.match(v[2])) + has_drobs = has_drobs and len(v) > 2 and not inf_or_nan.match(v[2]) if has_drobs: v2 = float(v[2]) has_drobs = v2 > 0.0 drobs.append(v2) # dGobs is valid if all values are defined and positive - has_dGobs = (has_dGobs and - len(v) > 3 and not inf_or_nan.match(v[3])) + has_dGobs = has_dGobs and len(v) > 3 and not inf_or_nan.match(v[3]) if has_dGobs: v3 = float(v[3]) has_dGobs = v3 > 0.0 @@ -220,4 +220,5 @@ def parseString(self, patstring): self._banks.append([robs, Gobs, drobs, dGobs]) return + # End of PDFParser diff --git a/src/diffpy/srfit/sas/__init__.py b/src/diffpy/srfit/sas/__init__.py index c454a86e..d414207d 100644 --- a/src/diffpy/srfit/sas/__init__.py +++ b/src/diffpy/srfit/sas/__init__.py @@ -16,12 +16,11 @@ """SAS calculation tools. """ -__all__ = ["SASGenerator", "SASParser", "SASProfile", "PrCalculator", - "CFCalculator"] +__all__ = ["SASGenerator", "SASParser", "SASProfile", "PrCalculator", "CFCalculator"] +from .prcalculator import CFCalculator, PrCalculator from .sasgenerator import SASGenerator from .sasparser import SASParser from .sasprofile import SASProfile -from .prcalculator import PrCalculator, CFCalculator # End of file diff --git a/src/diffpy/srfit/sas/prcalculator.py b/src/diffpy/srfit/sas/prcalculator.py index 0ce1ad41..edb1da18 100644 --- a/src/diffpy/srfit/sas/prcalculator.py +++ b/src/diffpy/srfit/sas/prcalculator.py @@ -67,7 +67,8 @@ def __init__(self, name): global Invertor if Invertor is None: from diffpy.srfit.sas.sasimport import sasimport - Invertor = sasimport('sas.pr.invertor').Invertor + + Invertor = sasimport("sas.pr.invertor").Invertor self._invertor = Invertor() @@ -97,8 +98,10 @@ def __call__(self, r): pr = numpy.array(pr) return self.scale.value * pr + # End class PrCalculator + class CFCalculator(PrCalculator): """A class for calculating the characteristic function (CF) from data. @@ -130,4 +133,5 @@ def __call__(self, r): fr[0] = 1 return fr + # End class CFCalculator diff --git a/src/diffpy/srfit/sas/sasgenerator.py b/src/diffpy/srfit/sas/sasgenerator.py index 74a60594..dbf3f4a1 100644 --- a/src/diffpy/srfit/sas/sasgenerator.py +++ b/src/diffpy/srfit/sas/sasgenerator.py @@ -69,4 +69,5 @@ def __call__(self, q): """Calculate I(Q) for the BaseModel.""" return self._model.evalDistribution(q) + # End class SASGenerator diff --git a/src/diffpy/srfit/sas/sasimport.py b/src/diffpy/srfit/sas/sasimport.py index ba39fb4a..e3e15100 100644 --- a/src/diffpy/srfit/sas/sasimport.py +++ b/src/diffpy/srfit/sas/sasimport.py @@ -17,6 +17,7 @@ Universal import functions for volatile SasView/SansViews API-s. """ + def sasimport(modname): """Import specified module from the SasView sas package. @@ -25,41 +26,44 @@ def sasimport(modname): When specified import does not work directly, try older API-s and raise DeprecationWarning. Raise ImportError if nothing works. """ - if not modname.startswith('sas.'): + if not modname.startswith("sas."): emsg = 'Module name must start with "sas."' raise ValueError(emsg) mobj = None # standard import try: - exec('import %s as mobj' % modname) + exec("import %s as mobj" % modname) except ImportError: pass else: return mobj # revert to the old sans namespace, sas --> sans - modsans = 'sans' + modname[3:] + modsans = "sans" + modname[3:] import warnings - wfmt = ("Using obsolete package %r instead of %r. Please install " - "SasView 3.1 or the srfit-sasview package from Anaconda.") + + wfmt = ( + "Using obsolete package %r instead of %r. Please install " + "SasView 3.1 or the srfit-sasview package from Anaconda." + ) wmsg = wfmt % (modsans, modname) try: - exec('import %s as mobj' % modsans) + exec("import %s as mobj" % modsans) warnings.warn(wmsg, DeprecationWarning) except ImportError: pass else: return mobj # finally check the oldest DataLoader API for sas.dataloader - if modname.startswith('sas.dataloader'): - modloader = 'DataLoader' + modname[14:] + if modname.startswith("sas.dataloader"): + modloader = "DataLoader" + modname[14:] wmsg = wfmt % (modloader, modname) try: - exec('import %s as mobj' % modloader) + exec("import %s as mobj" % modloader) warnings.warn(wmsg, DeprecationWarning) except ImportError: pass else: return mobj # Obsolete API-s failed here. Import again and let it raise ImportError. - exec('import %s as mobj' % modname) + exec("import %s as mobj" % modname) raise AssertionError("The import above was supposed to fail.") diff --git a/src/diffpy/srfit/sas/sasparameter.py b/src/diffpy/srfit/sas/sasparameter.py index 7f3886d4..fbf841aa 100644 --- a/src/diffpy/srfit/sas/sasparameter.py +++ b/src/diffpy/srfit/sas/sasparameter.py @@ -43,7 +43,7 @@ class SASParameter(Parameter): """ - def __init__(self, name, model, parname = None): + def __init__(self, name, model, parname=None): """Create the Parameter. name -- Name of the Parameter @@ -60,7 +60,7 @@ def __init__(self, name, model, parname = None): def getValue(self): """Get the value of the Parameter.""" - value = self._model.getParam(self._parname) + value = self._model.getParam(self._parname) return value def setValue(self, value): @@ -70,4 +70,5 @@ def setValue(self, value): self.notify() return self + # End of class SASParameter diff --git a/src/diffpy/srfit/sas/sasparser.py b/src/diffpy/srfit/sas/sasparser.py index 3177954a..bf3cec74 100644 --- a/src/diffpy/srfit/sas/sasparser.py +++ b/src/diffpy/srfit/sas/sasparser.py @@ -83,7 +83,7 @@ def parseFile(self, filename): """ - Loader = sasimport('sas.dataloader.loader').Loader + Loader = sasimport("sas.dataloader.loader").Loader loader = Loader() try: @@ -117,8 +117,9 @@ def parseString(self, patstring): """ # This calls on parseFile, as that is how the sas data loader works. import tempfile + fh, fn = tempfile.mkstemp() - outfile = open(fn, 'w') + outfile = open(fn, "w") fn.write(patstring) outfile.close() self.parseFile(fn) @@ -127,6 +128,7 @@ def parseString(self, patstring): # Close the temporary file and delete it import os + os.close(fh) os.remove(fn) return diff --git a/src/diffpy/srfit/sas/sasprofile.py b/src/diffpy/srfit/sas/sasprofile.py index ef0bff3c..e35adfb1 100644 --- a/src/diffpy/srfit/sas/sasprofile.py +++ b/src/diffpy/srfit/sas/sasprofile.py @@ -75,7 +75,7 @@ def __init__(self, datainfo): self._dyobs = self._datainfo.dy return - def setObservedProfile(self, xobs, yobs, dyobs = None): + def setObservedProfile(self, xobs, yobs, dyobs=None): """Set the observed profile. This is overloaded to change the value within the datainfo object. diff --git a/src/diffpy/srfit/structure/__init__.py b/src/diffpy/srfit/structure/__init__.py index 54618c4c..5904f06f 100644 --- a/src/diffpy/srfit/structure/__init__.py +++ b/src/diffpy/srfit/structure/__init__.py @@ -32,18 +32,22 @@ def struToParameterSet(name, stru): """ from diffpy.srfit.structure.diffpyparset import DiffpyStructureParSet + if DiffpyStructureParSet.canAdapt(stru): return DiffpyStructureParSet(name, stru) from diffpy.srfit.structure.objcrystparset import ObjCrystCrystalParSet + if ObjCrystCrystalParSet.canAdapt(stru): return ObjCrystCrystalParSet(name, stru) from diffpy.srfit.structure.objcrystparset import ObjCrystMoleculeParSet + if ObjCrystMoleculeParSet.canAdapt(stru): return ObjCrystMoleculeParSet(name, stru) from diffpy.srfit.structure.cctbxparset import CCTBXCrystalParSet + if CCTBXCrystalParSet.canAdapt(stru): return CCTBXCrystalParSet(name, stru) diff --git a/src/diffpy/srfit/structure/bvsrestraint.py b/src/diffpy/srfit/structure/bvsrestraint.py index 38a5ea7a..43d9a6ba 100644 --- a/src/diffpy/srfit/structure/bvsrestraint.py +++ b/src/diffpy/srfit/structure/bvsrestraint.py @@ -21,8 +21,8 @@ __all__ = ["BVSRestraint"] -from diffpy.srfit.fitbase.restraint import Restraint from diffpy.srfit.exceptions import SrFitError +from diffpy.srfit.fitbase.restraint import Restraint class BVSRestraint(Restraint): @@ -41,7 +41,7 @@ class BVSRestraint(Restraint): """ - def __init__(self, parset, sig = 1, scaled = False): + def __init__(self, parset, sig=1, scaled=False): """Initialize the Restraint. parset -- SrRealParSet that creates this BVSRestraint. @@ -52,13 +52,14 @@ def __init__(self, parset, sig = 1, scaled = False): """ from diffpy.srreal.bvscalculator import BVSCalculator + self._calc = BVSCalculator() self._parset = parset self.sig = float(sig) self.scaled = bool(scaled) return - def penalty(self, w = 1.0): + def penalty(self, w=1.0): """Calculate the penalty of the restraint. w -- The point-average chi^2 which is optionally used to scale the @@ -74,7 +75,8 @@ def penalty(self, w = 1.0): penalty /= self.sig**2 # Optionally scale by w - if self.scaled: penalty *= w + if self.scaled: + penalty *= w return penalty @@ -85,16 +87,20 @@ def _validate(self): """ from numpy import nan + p = self.penalty() if p is None or p is nan: raise SrFitError("Cannot evaluate penalty") v = self._calc.value if len(v) > 1 and not v.any(): - emsg = ("Bond valence sums are all zero. Check atom symbols in " - "the structure or define custom bond-valence parameters.") + emsg = ( + "Bond valence sums are all zero. Check atom symbols in " + "the structure or define custom bond-valence parameters." + ) raise SrFitError(emsg) return # End of class BVSRestraint + # End of file diff --git a/src/diffpy/srfit/structure/cctbxparset.py b/src/diffpy/srfit/structure/cctbxparset.py index f3b04d8b..28f24bd1 100644 --- a/src/diffpy/srfit/structure/cctbxparset.py +++ b/src/diffpy/srfit/structure/cctbxparset.py @@ -32,8 +32,7 @@ from diffpy.srfit.fitbase.parameterset import ParameterSet from diffpy.srfit.structure.basestructureparset import BaseStructureParSet -__all__ = ["CCTBXScattererParSet", "CCTBXUnitCellParSet", - "CCTBXCrystalParSet"] +__all__ = ["CCTBXScattererParSet", "CCTBXUnitCellParSet", "CCTBXCrystalParSet"] class CCTBXScattererParSet(ParameterSet): @@ -65,16 +64,11 @@ def __init__(self, name, strups, idx): self.idx = idx # x, y, z, occupancy - self.addParameter(ParameterAdapter("x", None, self._xyzgetter(0), - self._xyzsetter(0))) - self.addParameter(ParameterAdapter("y", None, self._xyzgetter(1), - self._xyzsetter(1))) - self.addParameter(ParameterAdapter("z", None, self._xyzgetter(2), - self._xyzsetter(2))) - self.addParameter(ParameterAdapter("occupancy", None, self._getocc, - self._setocc)) - self.addParameter(ParameterAdapter("Uiso", None, self._getuiso, - self._setuiso)) + self.addParameter(ParameterAdapter("x", None, self._xyzgetter(0), self._xyzsetter(0))) + self.addParameter(ParameterAdapter("y", None, self._xyzgetter(1), self._xyzsetter(1))) + self.addParameter(ParameterAdapter("z", None, self._xyzgetter(2), self._xyzsetter(2))) + self.addParameter(ParameterAdapter("occupancy", None, self._getocc, self._setocc)) + self.addParameter(ParameterAdapter("Uiso", None, self._getuiso, self._setuiso)) return # Getters and setters @@ -115,8 +109,10 @@ def _getElem(self): element = property(_getElem) + # End class CCTBXScattererParSet + class CCTBXUnitCellParSet(ParameterSet): """A wrapper for cctbx unit_cell object. @@ -137,18 +133,12 @@ def __init__(self, strups): self.strups = strups self._latpars = list(self.strups.stru.unit_cell().parameters()) - self.addParameter(ParameterAdapter("a", None, self._latgetter(0), - self._latsetter(0))) - self.addParameter(ParameterAdapter("b", None, self._latgetter(1), - self._latsetter(1))) - self.addParameter(ParameterAdapter("c", None, self._latgetter(2), - self._latsetter(2))) - self.addParameter(ParameterAdapter("alpha", None, self._latgetter(3), - self._latsetter(3))) - self.addParameter(ParameterAdapter("beta", None, self._latgetter(4), - self._latsetter(4))) - self.addParameter(ParameterAdapter("gamma", None, self._latgetter(5), - self._latsetter(5))) + self.addParameter(ParameterAdapter("a", None, self._latgetter(0), self._latsetter(0))) + self.addParameter(ParameterAdapter("b", None, self._latgetter(1), self._latsetter(1))) + self.addParameter(ParameterAdapter("c", None, self._latgetter(2), self._latsetter(2))) + self.addParameter(ParameterAdapter("alpha", None, self._latgetter(3), self._latsetter(3))) + self.addParameter(ParameterAdapter("beta", None, self._latgetter(4), self._latsetter(4))) + self.addParameter(ParameterAdapter("gamma", None, self._latgetter(5), self._latsetter(5))) return @@ -173,6 +163,7 @@ def f(dummy, value): # FIXME - Special positions should be constant. + class CCTBXCrystalParSet(BaseStructureParSet): """A wrapper for CCTBX structure. @@ -201,14 +192,15 @@ def __init__(self, name, stru): for s in stru.scatterers(): el = s.element_symbol() i = cdict.get(el, 0) - sname = "%s%i"%(el,i) - cdict[el] = i+1 + sname = "%s%i" % (el, i) + cdict[el] = i + 1 scatterer = CCTBXScattererParSet(sname, self, i) self.addParameterSet(scatterer) self.scatterers.append(scatterer) # Constrain the lattice from diffpy.srfit.structure.sgconstraints import _constrainSpaceGroup + symbol = self.getSpaceGroup() _constrainSpaceGroup(self, symbol) @@ -231,16 +223,11 @@ def update(self): # Create the symmetry object from cctbx.crystal import symmetry - symm = symmetry( - unit_cell = self.unitcell._latpars, - space_group_symbol = sgn - ) + + symm = symmetry(unit_cell=self.unitcell._latpars, space_group_symbol=sgn) # Now the new structure - newstru = stru.__class__( - crystal_symmetry = symm, - scatterers = stru.scatterers() - ) + newstru = stru.__class__(crystal_symmetry=symm, scatterers=stru.scatterers()) self.unitcell._latpars = list(newstru.unit_cell().parameters()) @@ -278,5 +265,4 @@ def getSpaceGroup(self): return t.lookup_symbol() - # End class CCTBXCrystalParSet diff --git a/src/diffpy/srfit/structure/diffpyparset.py b/src/diffpy/srfit/structure/diffpyparset.py index 4278bf13..bd8d6de4 100644 --- a/src/diffpy/srfit/structure/diffpyparset.py +++ b/src/diffpy/srfit/structure/diffpyparset.py @@ -30,8 +30,7 @@ __all__ = ["DiffpyStructureParSet"] -from diffpy.srfit.fitbase.parameter import ParameterProxy -from diffpy.srfit.fitbase.parameter import ParameterAdapter +from diffpy.srfit.fitbase.parameter import ParameterAdapter, ParameterProxy from diffpy.srfit.fitbase.parameterset import ParameterSet from diffpy.srfit.structure.srrealparset import SrRealParSet from diffpy.srfit.util.argbinders import bind2nd @@ -94,24 +93,21 @@ def __init__(self, name, atom): self.atom = atom a = atom # x, y, z, occupancy - self.addParameter(ParameterAdapter("x", a, _xyzgetter(0), - _xyzsetter(0))) - self.addParameter(ParameterAdapter("y", a, _xyzgetter(1), - _xyzsetter(1))) - self.addParameter(ParameterAdapter("z", a, _xyzgetter(2), - _xyzsetter(2))) - occupancy = ParameterAdapter("occupancy", a, attr = "occupancy") + self.addParameter(ParameterAdapter("x", a, _xyzgetter(0), _xyzsetter(0))) + self.addParameter(ParameterAdapter("y", a, _xyzgetter(1), _xyzsetter(1))) + self.addParameter(ParameterAdapter("z", a, _xyzgetter(2), _xyzsetter(2))) + occupancy = ParameterAdapter("occupancy", a, attr="occupancy") self.addParameter(occupancy) self.addParameter(ParameterProxy("occ", occupancy)) # U - self.addParameter(ParameterAdapter("U11", a, attr = "U11")) - self.addParameter(ParameterAdapter("U22", a, attr = "U22")) - self.addParameter(ParameterAdapter("U33", a, attr = "U33")) - U12 = ParameterAdapter("U12", a, attr = "U12") + self.addParameter(ParameterAdapter("U11", a, attr="U11")) + self.addParameter(ParameterAdapter("U22", a, attr="U22")) + self.addParameter(ParameterAdapter("U33", a, attr="U33")) + U12 = ParameterAdapter("U12", a, attr="U12") U21 = ParameterProxy("U21", U12) - U13 = ParameterAdapter("U13", a, attr = "U13") + U13 = ParameterAdapter("U13", a, attr="U13") U31 = ParameterProxy("U31", U13) - U23 = ParameterAdapter("U23", a, attr = "U23") + U23 = ParameterAdapter("U23", a, attr="U23") U32 = ParameterProxy("U32", U23) self.addParameter(U12) self.addParameter(U21) @@ -119,16 +115,16 @@ def __init__(self, name, atom): self.addParameter(U31) self.addParameter(U23) self.addParameter(U32) - self.addParameter(ParameterAdapter("Uiso", a, attr = "Uisoequiv")) + self.addParameter(ParameterAdapter("Uiso", a, attr="Uisoequiv")) # B - self.addParameter(ParameterAdapter("B11", a, attr = "B11")) - self.addParameter(ParameterAdapter("B22", a, attr = "B22")) - self.addParameter(ParameterAdapter("B33", a, attr = "B33")) - B12 = ParameterAdapter("B12", a, attr = "B12") + self.addParameter(ParameterAdapter("B11", a, attr="B11")) + self.addParameter(ParameterAdapter("B22", a, attr="B22")) + self.addParameter(ParameterAdapter("B33", a, attr="B33")) + B12 = ParameterAdapter("B12", a, attr="B12") B21 = ParameterProxy("B21", B12) - B13 = ParameterAdapter("B13", a, attr = "B13") + B13 = ParameterAdapter("B13", a, attr="B13") B31 = ParameterProxy("B31", B13) - B23 = ParameterAdapter("B23", a, attr = "B23") + B23 = ParameterAdapter("B23", a, attr="B23") B32 = ParameterProxy("B32", B23) self.addParameter(B12) self.addParameter(B21) @@ -136,7 +132,7 @@ def __init__(self, name, atom): self.addParameter(B31) self.addParameter(B23) self.addParameter(B32) - self.addParameter(ParameterAdapter("Biso", a, attr = "Bisoequiv")) + self.addParameter(ParameterAdapter("Biso", a, attr="Bisoequiv")) return def __repr__(self): @@ -150,12 +146,14 @@ def _setElem(self, el): element = property(_getElem, _setElem, "type of atom") + # End class DiffpyAtomParSet def _latgetter(par): return bind2nd(getattr, par) + def _latsetter(par): return bind2nd(setattr, par) @@ -186,23 +184,18 @@ def __init__(self, lattice): self.angunits = "deg" self.lattice = lattice l = lattice - self.addParameter(ParameterAdapter("a", l, _latgetter("a"), - _latsetter("a"))) - self.addParameter(ParameterAdapter("b", l, _latgetter("b"), - _latsetter("b"))) - self.addParameter(ParameterAdapter("c", l, _latgetter("c"), - _latsetter("c"))) - self.addParameter(ParameterAdapter("alpha", l, _latgetter("alpha"), - _latsetter("alpha"))) - self.addParameter(ParameterAdapter("beta", l, _latgetter("beta"), - _latsetter("beta"))) - self.addParameter(ParameterAdapter("gamma", l, _latgetter("gamma"), - _latsetter("gamma"))) + self.addParameter(ParameterAdapter("a", l, _latgetter("a"), _latsetter("a"))) + self.addParameter(ParameterAdapter("b", l, _latgetter("b"), _latsetter("b"))) + self.addParameter(ParameterAdapter("c", l, _latgetter("c"), _latsetter("c"))) + self.addParameter(ParameterAdapter("alpha", l, _latgetter("alpha"), _latsetter("alpha"))) + self.addParameter(ParameterAdapter("beta", l, _latgetter("beta"), _latsetter("beta"))) + self.addParameter(ParameterAdapter("gamma", l, _latgetter("gamma"), _latsetter("gamma"))) return def __repr__(self): return repr(self.lattice) + # End class DiffpyLatticeParSet @@ -242,11 +235,11 @@ def __init__(self, name, stru): for a in stru: el = a.element.title() # Try to sanitize the name. - el = el.replace("+","p") - el = el.replace("-","m") + el = el.replace("+", "p") + el = el.replace("-", "m") i = cdict.get(el, 0) - aname = "%s%i"%(el,i) - cdict[el] = i+1 + aname = "%s%i" % (el, i) + cdict[el] = i + 1 atom = DiffpyAtomParSet(aname, a) self.addParameterSet(atom) self.atoms.append(atom) @@ -264,6 +257,7 @@ def getLattice(self): def canAdapt(self, stru): """Return whether the structure can be adapted by this class.""" from diffpy.structure import Structure + return isinstance(stru, Structure) def getScatterers(self): @@ -286,7 +280,9 @@ def _getSrRealStructure(self): """ from diffpy.srreal.structureadapter import nometa + stru = SrRealParSet._getSrRealStructure(self) return nometa(stru) + # End class DiffpyStructureParSet diff --git a/src/diffpy/srfit/structure/objcrystparset.py b/src/diffpy/srfit/structure/objcrystparset.py index ac4f3b43..3a8d2045 100644 --- a/src/diffpy/srfit/structure/objcrystparset.py +++ b/src/diffpy/srfit/structure/objcrystparset.py @@ -40,13 +40,16 @@ __all__ = ["ObjCrystMoleculeParSet", "ObjCrystCrystalParSet"] import numpy - -from pyobjcryst.molecule import GetBondLength, GetBondAngle, GetDihedralAngle -from pyobjcryst.molecule import StretchModeBondLength, StretchModeBondAngle -from pyobjcryst.molecule import StretchModeTorsion - -from diffpy.srfit.fitbase.parameter import Parameter, ParameterAdapter -from diffpy.srfit.fitbase.parameter import ParameterProxy +from pyobjcryst.molecule import ( + GetBondAngle, + GetBondLength, + GetDihedralAngle, + StretchModeBondAngle, + StretchModeBondLength, + StretchModeTorsion, +) + +from diffpy.srfit.fitbase.parameter import Parameter, ParameterAdapter, ParameterProxy from diffpy.srfit.fitbase.parameterset import ParameterSet from diffpy.srfit.structure.srrealparset import SrRealParSet @@ -83,11 +86,10 @@ def __init__(self, name, scat, parent): self.parent = parent # x, y, z, occ - self.addParameter(ParameterAdapter("x", self.scat, attr = "X")) - self.addParameter(ParameterAdapter("y", self.scat, attr = "Y")) - self.addParameter(ParameterAdapter("z", self.scat, attr = "Z")) - self.addParameter(ParameterAdapter("occ", self.scat, attr = - "Occupancy")) + self.addParameter(ParameterAdapter("x", self.scat, attr="X")) + self.addParameter(ParameterAdapter("y", self.scat, attr="Y")) + self.addParameter(ParameterAdapter("z", self.scat, attr="Z")) + self.addParameter(ParameterAdapter("occ", self.scat, attr="Occupancy")) return def isDummy(self): @@ -101,6 +103,7 @@ def hasScatterers(self): # End class ObjCrystScattererParSet + class ObjCrystAtomParSet(ObjCrystScattererParSet): """A adaptor for a pyobjcryst.Atom. @@ -135,15 +138,15 @@ def __init__(self, name, atom, parent): sp = atom.GetScatteringPower() # The B-parameters - self.addParameter(ParameterAdapter("Biso", sp, attr = "Biso")) - self.addParameter(ParameterAdapter("B11", sp, attr = "B11")) - self.addParameter(ParameterAdapter("B22", sp, attr = "B22")) - self.addParameter(ParameterAdapter("B33", sp, attr = "B33")) - B12 = ParameterAdapter("B12", sp, attr = "B12") + self.addParameter(ParameterAdapter("Biso", sp, attr="Biso")) + self.addParameter(ParameterAdapter("B11", sp, attr="B11")) + self.addParameter(ParameterAdapter("B22", sp, attr="B22")) + self.addParameter(ParameterAdapter("B33", sp, attr="B33")) + B12 = ParameterAdapter("B12", sp, attr="B12") B21 = ParameterProxy("B21", B12) - B13 = ParameterAdapter("B13", sp, attr = "B13") + B13 = ParameterAdapter("B13", sp, attr="B13") B31 = ParameterProxy("B31", B13) - B23 = ParameterAdapter("B23", sp, attr = "B23") + B23 = ParameterAdapter("B23", sp, attr="B23") B32 = ParameterProxy("B32", B23) self.addParameter(B12) self.addParameter(B21) @@ -163,8 +166,10 @@ def _getElem(self): element = property(_getElem) + # End class ObjCrystAtomParSet + class ObjCrystMoleculeParSet(ObjCrystScattererParSet): """A adaptor for a pyobjcryst.Molecule. @@ -188,7 +193,7 @@ class ObjCrystMoleculeParSet(ObjCrystScattererParSet): """ - def __init__(self, name, molecule, parent = None): + def __init__(self, name, molecule, parent=None): """Initialize name -- The name of the scatterer @@ -200,10 +205,10 @@ def __init__(self, name, molecule, parent = None): self.stru = molecule # Add orientiation quaternion - self.addParameter(ParameterAdapter("q0", self.scat, attr = "Q0")) - self.addParameter(ParameterAdapter("q1", self.scat, attr = "Q1")) - self.addParameter(ParameterAdapter("q2", self.scat, attr = "Q2")) - self.addParameter(ParameterAdapter("q3", self.scat, attr = "Q3")) + self.addParameter(ParameterAdapter("q0", self.scat, attr="Q0")) + self.addParameter(ParameterAdapter("q1", self.scat, attr="Q1")) + self.addParameter(ParameterAdapter("q2", self.scat, attr="Q2")) + self.addParameter(ParameterAdapter("q3", self.scat, attr="Q3")) # Wrap the MolAtoms within the molecule self.atoms = [] @@ -215,7 +220,7 @@ def __init__(self, name, molecule, parent = None): if not name: raise AttributeError("Each MolAtom must have a name") if name in anames: - raise AttributeError("MolAtom name '%s' is duplicated"%name) + raise AttributeError("MolAtom name '%s' is duplicated" % name) atom = ObjCrystMolAtomParSet(name, a, self) atom.molecule = self @@ -229,10 +234,11 @@ def __init__(self, name, molecule, parent = None): def canAdapt(self, stru): """Return whether the structure can be adapted by this class.""" from pyobjcryst.molecule import Molecule + return isinstance(stru, Molecule) # Part of SrRealParSet interface - def useSymmetry(self, use = True): + def useSymmetry(self, use=True): """Set this structure to use symmetry. This structure object does not support symmetry. @@ -327,18 +333,17 @@ def wrapStretchModeParameters(self): atom1 = getattr(self, name1) atom2 = getattr(self, name2) - par = ObjCrystBondLengthParameter(name, atom1, atom2, mode = mode) + par = ObjCrystBondLengthParameter(name, atom1, atom2, mode=mode) atoms = [] for a in mode.GetAtoms(): name = a.GetName() - atoms.append( getattr(self, name) ) + atoms.append(getattr(self, name)) par.AddAtoms(atoms) self.addParameter(par) - for mode in self.scat.GetStretchModeBondAngleList(): name1 = mode.mpAtom0.GetName() name2 = mode.mpAtom1.GetName() @@ -350,21 +355,19 @@ def wrapStretchModeParameters(self): atom2 = getattr(self, name2) atom3 = getattr(self, name3) - par = ObjCrystBondAngleParameter(name, atom1, atom2, atom3, mode = - mode) + par = ObjCrystBondAngleParameter(name, atom1, atom2, atom3, mode=mode) atoms = [] for a in mode.GetAtoms(): name = a.GetName() - atoms.append( getattr(self, name) ) + atoms.append(getattr(self, name)) par.AddAtoms(atoms) self.addParameter(par) return - def restrainBondLength(self, atom1, atom2, length, sigma, delta, scaled = - False): + def restrainBondLength(self, atom1, atom2, length, sigma, delta, scaled=False): """Add a bond length restraint. This creates an instance of ObjCrystBondLengthRestraint and adds it to @@ -388,8 +391,7 @@ def restrainBondLength(self, atom1, atom2, length, sigma, delta, scaled = return res - def restrainBondLengthParameter(self, par, length, sigma, delta, scaled = - False): + def restrainBondLengthParameter(self, par, length, sigma, delta, scaled=False): """Add a bond length restraint. This creates an instance of ObjCrystBondLengthRestraint and adds it to @@ -407,11 +409,9 @@ def restrainBondLengthParameter(self, par, length, sigma, delta, scaled = 'unrestrain' method. """ - return self.restrainBondLength(par.atom1, par.atom2, length, sigma, - delta, scaled) + return self.restrainBondLength(par.atom1, par.atom2, length, sigma, delta, scaled) - def restrainBondAngle(self, atom1, atom2, atom3, angle, sigma, delta, - scaled = False): + def restrainBondAngle(self, atom1, atom2, atom3, angle, sigma, delta, scaled=False): """Add a bond angle restraint. This creates an instance of ObjCrystBondAngleRestraint and adds it to @@ -432,14 +432,12 @@ def restrainBondAngle(self, atom1, atom2, atom3, angle, sigma, delta, 'unrestrain' method. """ - res = ObjCrystBondAngleRestraint(atom1, atom2, atom3, angle, sigma, - delta, scaled) + res = ObjCrystBondAngleRestraint(atom1, atom2, atom3, angle, sigma, delta, scaled) self._restraints.add(res) return res - def restrainBondAngleParameter(self, par, angle, sigma, delta, - scaled = False): + def restrainBondAngleParameter(self, par, angle, sigma, delta, scaled=False): """Add a bond angle restraint. This creates an instance of ObjCrystBondAngleRestraint and adds it to @@ -457,11 +455,9 @@ def restrainBondAngleParameter(self, par, angle, sigma, delta, 'unrestrain' method. """ - return self.restrainBondAngle(par.atom1, par.atom2, par.atom3, angle, - sigma, delta, scaled) + return self.restrainBondAngle(par.atom1, par.atom2, par.atom3, angle, sigma, delta, scaled) - def restrainDihedralAngle(self, atom1, atom2, atom3, atom4, angle, sigma, - delta, scaled = False): + def restrainDihedralAngle(self, atom1, atom2, atom3, atom4, angle, sigma, delta, scaled=False): """Add a dihedral angle restraint. This creates an instance of ObjCrystDihedralAngleRestraint and adds it @@ -482,14 +478,12 @@ def restrainDihedralAngle(self, atom1, atom2, atom3, atom4, angle, sigma, 'unrestrain' method. """ - res = ObjCrystDihedralAngleRestraint(atom1, atom2, atom3, atom4, angle, - sigma, delta, scaled) + res = ObjCrystDihedralAngleRestraint(atom1, atom2, atom3, atom4, angle, sigma, delta, scaled) self._restraints.add(res) return res - def restrainDihedralAngleParameter(self, par, angle, sigma, delta, - scaled = False): + def restrainDihedralAngleParameter(self, par, angle, sigma, delta, scaled=False): """Add a dihedral angle restraint. This creates an instance of ObjCrystDihedralAngleRestraint and adds it @@ -508,11 +502,9 @@ def restrainDihedralAngleParameter(self, par, angle, sigma, delta, 'unrestrain' method. """ - return self.restrainDihedralAngle(par.atom1, par.atom2, par.atom3, - par.atom4, angle, sigma, delta, scaled) + return self.restrainDihedralAngle(par.atom1, par.atom2, par.atom3, par.atom4, angle, sigma, delta, scaled) - def addBondLengthParameter(self, name, atom1, atom2, value = None, const = - False): + def addBondLengthParameter(self, name, atom1, atom2, value=None, const=False): """Add a bond length to the Molecule. This creates a ObjCrystBondLengthParameter to the @@ -536,8 +528,7 @@ def addBondLengthParameter(self, name, atom1, atom2, value = None, const = return par - def addBondAngleParameter(self, name, atom1, atom2, atom3, value = None, - const = False): + def addBondAngleParameter(self, name, atom1, atom2, atom3, value=None, const=False): """Add a bond angle to the Molecule. This creates a ObjCrystBondAngleParameter to the ObjCrystMoleculeParSet @@ -558,14 +549,12 @@ def addBondAngleParameter(self, name, atom1, atom2, atom3, value = None, Returns the new ObjCrystBondAngleParameter. """ - par = ObjCrystBondAngleParameter(name, atom1, atom2, atom3, value, - const) + par = ObjCrystBondAngleParameter(name, atom1, atom2, atom3, value, const) self.addParameter(par) return par - def addDihedralAngleParameter(self, name, atom1, atom2, atom3, atom4, value - = None, const = False): + def addDihedralAngleParameter(self, name, atom1, atom2, atom3, atom4, value=None, const=False): """Add a dihedral angle to the Molecule. This creates a ObjCrystDihedralAngleParameter to the @@ -588,14 +577,15 @@ def addDihedralAngleParameter(self, name, atom1, atom2, atom3, atom4, value Returns the new ObjCrystDihedralAngleParameter. """ - par = ObjCrystDihedralAngleParameter(name, atom1, atom2, atom3, atom4, - value, const) + par = ObjCrystDihedralAngleParameter(name, atom1, atom2, atom3, atom4, value, const) self.addParameter(par) return par + # End class ObjCrystMoleculeParSet + class ObjCrystMolAtomParSet(ObjCrystScattererParSet): """A adaptor for an pyobjcryst.molecule.MolAtom. @@ -634,15 +624,15 @@ def __init__(self, name, scat, parent): # Only wrap this if there is a scattering power if sp is not None: - self.addParameter(ParameterAdapter("Biso", sp, attr = "Biso")) - self.addParameter(ParameterAdapter("B11", sp, attr = "B11")) - self.addParameter(ParameterAdapter("B22", sp, attr = "B22")) - self.addParameter(ParameterAdapter("B33", sp, attr = "B33")) - B12 = ParameterAdapter("B12", sp, attr = "B12") + self.addParameter(ParameterAdapter("Biso", sp, attr="Biso")) + self.addParameter(ParameterAdapter("B11", sp, attr="B11")) + self.addParameter(ParameterAdapter("B22", sp, attr="B22")) + self.addParameter(ParameterAdapter("B33", sp, attr="B33")) + B12 = ParameterAdapter("B12", sp, attr="B12") B21 = ParameterProxy("B21", B12) - B13 = ParameterAdapter("B13", sp, attr = "B13") + B13 = ParameterAdapter("B13", sp, attr="B13") B31 = ParameterProxy("B31", B13) - B23 = ParameterAdapter("B23", sp, attr = "B23") + B23 = ParameterAdapter("B23", sp, attr="B23") B32 = ParameterProxy("B32", B23) self.addParameter(B12) self.addParameter(B21) @@ -667,8 +657,10 @@ def isDummy(self): """Indicate whether this atom is a dummy atom.""" return self.scat.IsDummy() + # End class ObjCrystMolAtomParSet + class ObjCrystMoleculeRestraint(object): """Base class for adapting pyobjcryst Molecule restraints to srfit. @@ -685,7 +677,7 @@ class ObjCrystMoleculeRestraint(object): """ - def __init__(self, res, scaled = False): + def __init__(self, res, scaled=False): """Create a Restraint-like from a pyobjcryst Molecule restraint. res -- The pyobjcryst Molecule restraint. @@ -698,7 +690,7 @@ def __init__(self, res, scaled = False): self.scaled = scaled return - def penalty(self, w = 1.0): + def penalty(self, w=1.0): """Calculate the penalty of the restraint. w -- The point-average chi^2 which is optionally used to scale the @@ -710,8 +702,10 @@ def penalty(self, w = 1.0): penalty *= w return penalty + # End class ObjCrystMoleculeRestraint + class ObjCrystBondLengthRestraint(ObjCrystMoleculeRestraint): """Restrain the distance between two atoms. @@ -728,7 +722,7 @@ class ObjCrystBondLengthRestraint(ObjCrystMoleculeRestraint): """ - def __init__(self, atom1, atom2, length, sigma, delta, scaled = False): + def __init__(self, atom1, atom2, length, sigma, delta, scaled=False): """Create a bond length restraint. atom1 -- First atom (ObjCrystMolAtomParSet) in the bond @@ -751,15 +745,14 @@ def __init__(self, atom1, atom2, length, sigma, delta, scaled = False): return # Give access to the parameters of the restraint - length = property( lambda self: self.res.GetLength0(), - lambda self, val: self.res.SetLength0(val)) - sigma = property( lambda self: self.res.GetLengthSigma(), - lambda self, val: self.res.SetLengthSigma(val)) - delta = property( lambda self: self.res.GetLengthDelta(), - lambda self, val: self.res.SetLengthDelta(val)) + length = property(lambda self: self.res.GetLength0(), lambda self, val: self.res.SetLength0(val)) + sigma = property(lambda self: self.res.GetLengthSigma(), lambda self, val: self.res.SetLengthSigma(val)) + delta = property(lambda self: self.res.GetLengthDelta(), lambda self, val: self.res.SetLengthDelta(val)) + # End class ObjCrystBondLengthRestraint + class ObjCrystBondAngleRestraint(ObjCrystMoleculeRestraint): """Restrain the angle defined by three atoms. @@ -777,8 +770,7 @@ class ObjCrystBondAngleRestraint(ObjCrystMoleculeRestraint): """ - def __init__(self, atom1, atom2, atom3, angle, sigma, delta, scaled = - False): + def __init__(self, atom1, atom2, atom3, angle, sigma, delta, scaled=False): """Create a bond angle restraint. atom1 -- First atom (ObjCrystMolAtomParSet) in the bond angle @@ -798,22 +790,20 @@ def __init__(self, atom1, atom2, atom3, angle, sigma, delta, scaled = self.atom3 = atom3 m = self.atom1.scat.GetMolecule() - res = m.AddBondAngle(atom1.scat, atom2.scat, atom3.scat, angle, - sigma, delta) + res = m.AddBondAngle(atom1.scat, atom2.scat, atom3.scat, angle, sigma, delta) ObjCrystMoleculeRestraint.__init__(self, res, scaled) return # Give access to the parameters of the restraint - angle = property( lambda self: self.res.GetAngle0(), - lambda self, val: self.res.SetAngle0(val)) - sigma = property( lambda self: self.res.GetAngleSigma(), - lambda self, val: self.res.SetAngleSigma(val)) - delta = property( lambda self: self.res.GetAngleDelta(), - lambda self, val: self.res.SetAngleDelta(val)) + angle = property(lambda self: self.res.GetAngle0(), lambda self, val: self.res.SetAngle0(val)) + sigma = property(lambda self: self.res.GetAngleSigma(), lambda self, val: self.res.SetAngleSigma(val)) + delta = property(lambda self: self.res.GetAngleDelta(), lambda self, val: self.res.SetAngleDelta(val)) + # End class ObjCrystBondAngleRestraint + class ObjCrystDihedralAngleRestraint(ObjCrystMoleculeRestraint): """Restrain the dihedral (torsion) angle defined by four atoms. @@ -832,8 +822,7 @@ class ObjCrystDihedralAngleRestraint(ObjCrystMoleculeRestraint): """ - def __init__(self, atom1, atom2, atom3, atom4, angle, sigma, delta, scaled - = False): + def __init__(self, atom1, atom2, atom3, atom4, angle, sigma, delta, scaled=False): """Create a dihedral angle restraint. atom1 -- First atom (ObjCrystMolAtomParSet) in the angle @@ -854,22 +843,20 @@ def __init__(self, atom1, atom2, atom3, atom4, angle, sigma, delta, scaled self.atom4 = atom4 m = self.atom1.scat.GetMolecule() - res = m.AddDihedralAngle(atom1.scat, atom2.scat, atom3.scat, - atom4.scat, angle, sigma, delta) + res = m.AddDihedralAngle(atom1.scat, atom2.scat, atom3.scat, atom4.scat, angle, sigma, delta) ObjCrystMoleculeRestraint.__init__(self, res, scaled) return # Give access to the parameters of the restraint - angle = property( lambda self: self.res.GetAngle0(), - lambda self, val: self.res.SetAngle0(val)) - sigma = property( lambda self: self.res.GetAngleSigma(), - lambda self, val: self.res.SetAngleSigma(val)) - delta = property( lambda self: self.res.GetAngleDelta(), - lambda self, val: self.res.SetAngleDelta(val)) + angle = property(lambda self: self.res.GetAngle0(), lambda self, val: self.res.SetAngle0(val)) + sigma = property(lambda self: self.res.GetAngleSigma(), lambda self, val: self.res.SetAngleSigma(val)) + delta = property(lambda self: self.res.GetAngleDelta(), lambda self, val: self.res.SetAngleDelta(val)) + # End class ObjCrystDihedralAngleRestraint + class StretchModeParameter(Parameter): """Partial Parameter class encapsulating pyobjcryst stretch modes. @@ -887,7 +874,7 @@ class StretchModeParameter(Parameter): """ - def __init__(self, name, value = None, const = False): + def __init__(self, name, value=None, const=False): """Initialization. name -- The name of this Parameter (must be a valid attribute @@ -966,8 +953,10 @@ def notify(self, other=()): Parameter.notify(self, other) return + # End class StretchModeParameter + class ObjCrystBondLengthParameter(StretchModeParameter): """Class for abstracting a bond length in a Molecule to a Parameter. @@ -1016,8 +1005,7 @@ class ObjCrystBondLengthParameter(StretchModeParameter): """ - def __init__(self, name, atom1, atom2, value = None, const = False, mode = - None): + def __init__(self, name, atom1, atom2, value=None, const=False, mode=None): """Create a ObjCrystBondLengthParameter. name -- The name of the ObjCrystBondLengthParameter @@ -1061,7 +1049,7 @@ def __init__(self, name, atom1, atom2, value = None, const = False, mode = return - def setConst(self, const = True, value = None): + def setConst(self, const=True, value=None): """Toggle the Parameter as constant. This sets the underlying ObjCrystMolAtomParSet positions const as well. @@ -1098,6 +1086,7 @@ def getValue(self): # End class ObjCrystBondLengthParameter + class ObjCrystBondAngleParameter(StretchModeParameter): """Class for abstracting a bond angle in a Molecule to a Parameter. @@ -1132,8 +1121,7 @@ class ObjCrystBondAngleParameter(StretchModeParameter): """ - def __init__(self, name, atom1, atom2, atom3, value = None, const = False, - mode = None): + def __init__(self, name, atom1, atom2, atom3, value=None, const=False, mode=None): """Create a ObjCrystBondAngleParameter. name -- The name of the ObjCrystBondAngleParameter. @@ -1155,8 +1143,7 @@ def __init__(self, name, atom1, atom2, atom3, value = None, const = False, # Create the stretch mode self.mode = mode if mode is None: - self.mode = StretchModeBondAngle(atom1.scat, atom2.scat, - atom3.scat, None) + self.mode = StretchModeBondAngle(atom1.scat, atom2.scat, atom3.scat, None) # We only add the last atom. This is the one that will move self.mode.AddAtom(atom3.scat) self.matoms = set([atom3]) @@ -1180,7 +1167,7 @@ def __init__(self, name, atom1, atom2, atom3, value = None, const = False, return - def setConst(self, const = True, value = None): + def setConst(self, const=True, value=None): """Toggle the Parameter as constant. This sets the underlying ObjCrystMolAtomParSet positions const as well. @@ -1208,14 +1195,15 @@ def getValue(self): """ if self._value is None: - val = GetBondAngle(self.atom1.scat, self.atom2.scat, - self.atom3.scat) + val = GetBondAngle(self.atom1.scat, self.atom2.scat, self.atom3.scat) Parameter.setValue(self, val) return self._value + # End class ObjCrystBondAngleParameter + class ObjCrystDihedralAngleParameter(StretchModeParameter): """Class for abstracting a dihedral angle in a Molecule to a Parameter. @@ -1253,8 +1241,7 @@ class ObjCrystDihedralAngleParameter(StretchModeParameter): """ - def __init__(self, name, atom1, atom2, atom3, atom4, value = None, const = - False, mode = None): + def __init__(self, name, atom1, atom2, atom3, atom4, value=None, const=False, mode=None): """Create a ObjCrystDihedralAngleParameter. name -- The name of the ObjCrystDihedralAngleParameter @@ -1298,14 +1285,13 @@ def __init__(self, name, atom1, atom2, atom3, atom4, value = None, const = # We do this last so the atoms are defined before we set any values. if value is None: - value = GetDihedralAngle(atom1.scat, atom2.scat, atom3.scat, - atom4.scat) + value = GetDihedralAngle(atom1.scat, atom2.scat, atom3.scat, atom4.scat) StretchModeParameter.__init__(self, name, value, const) self.setConst(const) return - def setConst(self, const = True, value = None): + def setConst(self, const=True, value=None): """Toggle the Parameter as constant. This sets the underlying ObjCrystMolAtomParSet positions const as well. @@ -1333,14 +1319,15 @@ def getValue(self): """ if self._value is None: - val = GetDihedralAngle(self.atom1.scat, self.atom2.scat, - self.atom3.scat, self.atom4.scat) + val = GetDihedralAngle(self.atom1.scat, self.atom2.scat, self.atom3.scat, self.atom4.scat) Parameter.setValue(self, val) return self._value + # End class ObjCrystDihedralAngleParameter + class ObjCrystCrystalParSet(SrRealParSet): """A adaptor for pyobjcryst.crystal.Crystal instance. @@ -1381,14 +1368,12 @@ def __init__(self, name, cryst): self.stru = cryst self._sgpars = None - self.addParameter(ParameterAdapter("a", self.stru, attr = "a")) - self.addParameter(ParameterAdapter("b", self.stru, attr = "b")) - self.addParameter(ParameterAdapter("c", self.stru, attr = "c")) - self.addParameter(ParameterAdapter("alpha", self.stru, attr = - "alpha")) - self.addParameter(ParameterAdapter("beta", self.stru, attr = "beta")) - self.addParameter(ParameterAdapter("gamma", self.stru, attr = - "gamma")) + self.addParameter(ParameterAdapter("a", self.stru, attr="a")) + self.addParameter(ParameterAdapter("b", self.stru, attr="b")) + self.addParameter(ParameterAdapter("c", self.stru, attr="c")) + self.addParameter(ParameterAdapter("alpha", self.stru, attr="alpha")) + self.addParameter(ParameterAdapter("beta", self.stru, attr="beta")) + self.addParameter(ParameterAdapter("gamma", self.stru, attr="gamma")) # Now we must loop over the scatterers and create parameter sets from # them. @@ -1401,7 +1386,7 @@ def __init__(self, name, cryst): if not name: raise ValueError("Each Scatterer must have a name") if name in snames: - raise ValueError("Scatterer name '%s' is duplicated"%name) + raise ValueError("Scatterer name '%s' is duplicated" % name) # Now create the proper object cname = s.GetClassName() @@ -1410,7 +1395,7 @@ def __init__(self, name, cryst): elif cname == "Molecule": parset = ObjCrystMoleculeParSet(name, s, self) else: - raise TypeError("Unrecognized scatterer '%s'"%cname) + raise TypeError("Unrecognized scatterer '%s'" % cname) self.addParameterSet(parset) self.scatterers.append(parset) @@ -1424,11 +1409,13 @@ def _constrainSpaceGroup(self): return self._sgpars sg = self._createSpaceGroup(self.stru.GetSpaceGroup()) from diffpy.srfit.structure.sgconstraints import _constrainAsSpaceGroup + adpsymbols = ["B11", "B22", "B33", "B12", "B13", "B23"] isosymbol = "Biso" sgoffset = [0, 0, 0] - self._sgpars = _constrainAsSpaceGroup(self, sg, self.scatterers, - sgoffset, adpsymbols = adpsymbols, isosymbol = isosymbol) + self._sgpars = _constrainAsSpaceGroup( + self, sg, self.scatterers, sgoffset, adpsymbols=adpsymbols, isosymbol=isosymbol + ) return self._sgpars sgpars = property(_constrainSpaceGroup) @@ -1445,11 +1432,13 @@ def _createSpaceGroup(sgobjcryst): """ import copy + from diffpy.structure.spacegroups import GetSpaceGroup, SymOp + name = sgobjcryst.GetName() extnstr = ":%s" % sgobjcryst.GetExtension() if name.endswith(extnstr): - name = name[:-len(extnstr)] + name = name[: -len(extnstr)] # Get whatever spacegroup we can get by name. This will set the proper # crystal system. Creating a copy of the singleton from GetSpaceGroup, @@ -1465,7 +1454,7 @@ def _createSpaceGroup(sgobjcryst): for shift, rot in symops: tv = trans + shift tv -= numpy.floor(tv) - sg.symop_list.append( SymOp(rot, tv) ) + sg.symop_list.append(SymOp(rot, tv)) if sgobjcryst.IsCentrosymmetric(): center = sgobjcryst.GetInversionCenter() @@ -1473,7 +1462,7 @@ def _createSpaceGroup(sgobjcryst): for shift, rot in symops: tv = center - trans - shift tv -= numpy.floor(tv) - sg.symop_list.append( SymOp(-rot , tv) ) + sg.symop_list.append(SymOp(-rot, tv)) return sg @@ -1481,6 +1470,7 @@ def _createSpaceGroup(sgobjcryst): def canAdapt(self, stru): """Return whether the structure can be adapted by this class.""" from pyobjcryst.crystal import Crystal + return isinstance(stru, Crystal) def getLattice(self): @@ -1498,4 +1488,5 @@ def getScatterers(self): """ return self.scatterers + # End class ObjCrystCrystalParSet diff --git a/src/diffpy/srfit/structure/sgconstraints.py b/src/diffpy/srfit/structure/sgconstraints.py index 4f64eb3f..cb370adf 100644 --- a/src/diffpy/srfit/structure/sgconstraints.py +++ b/src/diffpy/srfit/structure/sgconstraints.py @@ -17,17 +17,25 @@ import re + import numpy -from diffpy.srfit.fitbase.recipeorganizer import RecipeContainer from diffpy.srfit.fitbase.parameter import ParameterProxy +from diffpy.srfit.fitbase.recipeorganizer import RecipeContainer __all__ = ["constrainAsSpaceGroup"] -def constrainAsSpaceGroup(phase, spacegroup, scatterers = None, - sgoffset = [0, 0, 0], constrainlat = True, constrainadps = True, - adpsymbols = None, isosymbol = "Uiso"): +def constrainAsSpaceGroup( + phase, + spacegroup, + scatterers=None, + sgoffset=[0, 0, 0], + constrainlat=True, + constrainadps=True, + adpsymbols=None, + isosymbol="Uiso", +): """Constrain the structure to the space group. This applies space group constraints to a StructureParSet with P1 @@ -85,14 +93,23 @@ def constrainAsSpaceGroup(phase, spacegroup, scatterers = None, sg = spacegroup if not isinstance(spacegroup, SpaceGroup): sg = GetSpaceGroup(spacegroup) - sgp = _constrainAsSpaceGroup(phase, sg, scatterers, sgoffset, - constrainlat, constrainadps, adpsymbols, isosymbol) + sgp = _constrainAsSpaceGroup( + phase, sg, scatterers, sgoffset, constrainlat, constrainadps, adpsymbols, isosymbol + ) return sgp -def _constrainAsSpaceGroup(phase, sg, scatterers = None, - sgoffset = [0, 0, 0], constrainlat = True, constrainadps = True, - adpsymbols = None, isosymbol = "Uiso"): + +def _constrainAsSpaceGroup( + phase, + sg, + scatterers=None, + sgoffset=[0, 0, 0], + constrainlat=True, + constrainadps=True, + adpsymbols=None, + isosymbol="Uiso", +): """Restricted interface to constrainAsSpaceGroup. Arguments: As constrainAsSpaceGroup, except @@ -107,13 +124,14 @@ def _constrainAsSpaceGroup(phase, sg, scatterers = None, if adpsymbols is None: adpsymbols = stdUsymbols - sgp = SpaceGroupParameters(phase, sg, scatterers, sgoffset, - constrainlat, constrainadps, adpsymbols, isosymbol) + sgp = SpaceGroupParameters(phase, sg, scatterers, sgoffset, constrainlat, constrainadps, adpsymbols, isosymbol) return sgp + # End constrainAsSpaceGroup + class BaseSpaceGroupParameters(RecipeContainer): """Base class for holding space group Parameters. @@ -128,7 +146,7 @@ class is to make it easy to access the free variables of a structure for """ - def __init__(self, name = "sgpars"): + def __init__(self, name="sgpars"): """Create the BaseSpaceGroupParameters object. This initializes the attributes. @@ -137,7 +155,7 @@ def __init__(self, name = "sgpars"): RecipeContainer.__init__(self, name) return - def addParameter(self, par, check = True): + def addParameter(self, par, check=True): """Store a Parameter. par -- The Parameter to be stored. @@ -151,8 +169,10 @@ def addParameter(self, par, check = True): RecipeContainer._addObject(self, par, self._parameters, check) return + # End class BaseSpaceGroupParameters + class SpaceGroupParameters(BaseSpaceGroupParameters): """Class for holding and creating space group Parameters. @@ -183,8 +203,7 @@ class SpaceGroupParameters(BaseSpaceGroupParameters): """ - def __init__(self, phase, sg, scatterers, sgoffset, constrainlat, - constrainadps, adpsymbols, isosymbol): + def __init__(self, phase, sg, scatterers, sgoffset, constrainlat, constrainadps, adpsymbols, isosymbol): """Create the SpaceGroupParameters object. Arguments: @@ -226,13 +245,12 @@ def __init__(self, phase, sg, scatterers, sgoffset, constrainlat, def __iter__(self): """Iterate over top-level parameters.""" - if self._latpars is None or\ - self._xyzpars is None or\ - self._adppars is None: - self._makeConstraints() + if self._latpars is None or self._xyzpars is None or self._adppars is None: + self._makeConstraints() return RecipeContainer.__iter__(self) latpars = property(lambda self: self._getLatPars()) + def _getLatPars(self): """Accessor for _latpars.""" if self._latpars is None: @@ -240,9 +258,10 @@ def _getLatPars(self): return self._latpars xyzpars = property(lambda self: self._getXYZPars()) + def _getXYZPars(self): """Accessor for _xyzpars.""" - positions = [] + positions = [] for scatterer in self.scatterers: xyz = [scatterer.x, scatterer.y, scatterer.z] positions.append([p.value for p in xyz]) @@ -251,9 +270,10 @@ def _getXYZPars(self): return self._xyzpars adppars = property(lambda self: self._getADPPars()) + def _getADPPars(self): """Accessor for _adppars.""" - positions = [] + positions = [] for scatterer in self.scatterers: xyz = [scatterer.x, scatterer.y, scatterer.z] positions.append([p.value for p in xyz]) @@ -274,7 +294,7 @@ def _makeConstraints(self): scatterers = self.scatterers # Prepare positions - positions = [] + positions = [] for scatterer in scatterers: xyz = [scatterer.x, scatterer.y, scatterer.z] positions.append([p.value for p in xyz]) @@ -285,7 +305,6 @@ def _makeConstraints(self): return - def _clearConstraints(self): """Clear old constraints. @@ -309,8 +328,7 @@ def _clearConstraints(self): if self.constrainlat: lattice = phase.getLattice() - latpars = [lattice.a, lattice.b, lattice.c, lattice.alpha, - lattice.beta, lattice.gamma] + latpars = [lattice.a, lattice.b, lattice.c, lattice.alpha, lattice.beta, lattice.gamma] for par in latpars: if lattice.isConstrained(par): lattice.unconstrain(par) @@ -338,7 +356,8 @@ def _clearConstraints(self): def _constrainLattice(self): """Constrain the lattice parameters.""" - if not self.constrainlat: return + if not self.constrainlat: + return phase = self.phase sg = self.sg @@ -354,8 +373,7 @@ def _constrainLattice(self): # Now get the unconstrained, non-constant lattice pars and store them. self._latpars = BaseSpaceGroupParameters("latpars") - latpars = [lattice.a, lattice.b, lattice.c, lattice.alpha, - lattice.beta, lattice.gamma] + latpars = [lattice.a, lattice.b, lattice.c, lattice.alpha, lattice.beta, lattice.gamma] pars = [p for p in latpars if not p.const and not p.constrained] for par in pars: # FIXME - the original parameter will still appear as @@ -385,9 +403,9 @@ def _constrainXYZs(self, positions): self._xyzpars = BaseSpaceGroupParameters("xyzpars") # Make proxies to the free xyz parameters - xyznames = [name[:1]+"_"+name[1:] for name, val in g.pospars] + xyznames = [name[:1] + "_" + name[1:] for name, val in g.pospars] for pname in xyznames: - name, idx = pname.rsplit('_', 1) + name, idx = pname.rsplit("_", 1) idx = int(idx) par = scatterers[idx].get(name) newpar = self.__addPar(pname, par) @@ -400,8 +418,7 @@ def _constrainXYZs(self, positions): # Extract the constraint equation from the formula for parname, formula in fp.items(): - _makeconstraint(parname, formula, scatterer, idx, - self._parameters) + _makeconstraint(parname, formula, scatterer, idx, self._parameters) return @@ -412,10 +429,10 @@ def _constrainADPs(self, positions): """ - from diffpy.structure.symmetryutilities import stdUsymbols - from diffpy.structure.symmetryutilities import SymmetryConstraints + from diffpy.structure.symmetryutilities import SymmetryConstraints, stdUsymbols - if not self.constrainadps: return + if not self.constrainadps: + return sg = self.sg sgoffset = self.sgoffset @@ -438,10 +455,10 @@ def _constrainADPs(self, positions): nonadps.append(sidx) continue - Uij = numpy.zeros((3,3), dtype=float) + Uij = numpy.zeros((3, 3), dtype=float) for idx, par in enumerate(pars): i, j = _idxtoij[idx] - Uij[i,j] = Uij[j,i] = par.getValue() + Uij[i, j] = Uij[j, i] = par.getValue() Uijs.append(Uij) @@ -461,7 +478,7 @@ def _constrainADPs(self, positions): isoidx = [] isonames = [] for pname in adpnames: - name, idx = pname.rsplit('_', 1) + name, idx = pname.rsplit("_", 1) idx = int(idx) # Check for isotropic ADPs scatterer = scatterers[idx] @@ -482,24 +499,24 @@ def _constrainADPs(self, positions): # Constrain dependent isotropics for idx, isoname in zip(isoidx[:], isonames): for j in g.coremap[idx]: - if j == idx: continue + if j == idx: + continue isoidx.append(j) scatterer = scatterers[j] - scatterer.constrain(isosymbol, isoname, ns = self._parameters) + scatterer.constrain(isosymbol, isoname, ns=self._parameters) fadp = g.UFormulas(adpnames) # Constrain dependent anisotropics. We use the fact that an # anisotropic cannot be dependent on an isotropic. for idx, tmp in enumerate(zip(scatterers, fadp)): - if idx in isoidx: continue + if idx in isoidx: + continue scatterer, fa = tmp # Extract the constraint equation from the formula for stdparname, formula in fa.items(): pname = adpmap[stdparname] - _makeconstraint(pname, formula, scatterer, idx, - self._parameters) - + _makeconstraint(pname, formula, scatterer, idx, self._parameters) def __addPar(self, parname, par): """Constrain a parameter via proxy with a specified name @@ -512,18 +529,19 @@ def __addPar(self, parname, par): self.addParameter(newpar) return newpar + # End class SpaceGroupParameters # crystal system rules # ref: Benjamin, W. A., Introduction to crystallography, # New York (1969), p.60 -def _constrainTriclinic(lattice): - """Make constraints for Triclinic systems. - """ +def _constrainTriclinic(lattice): + """Make constraints for Triclinic systems.""" return + def _constrainMonoclinic(lattice): """Make constraints for Monoclinic systems. @@ -532,7 +550,8 @@ def _constrainMonoclinic(lattice): """ afactor = 1 - if lattice.angunits == "rad": afactor = deg2rad + if lattice.angunits == "rad": + afactor = deg2rad ang90 = 90.0 * afactor lattice.alpha.setConst(True, ang90) beta = lattice.beta.getValue() @@ -544,6 +563,7 @@ def _constrainMonoclinic(lattice): lattice.beta.setConst(True, ang90) return + def _constrainOrthorhombic(lattice): """Make constraints for Orthorhombic systems. @@ -551,13 +571,15 @@ def _constrainOrthorhombic(lattice): """ afactor = 1 - if lattice.angunits == "rad": afactor = deg2rad + if lattice.angunits == "rad": + afactor = deg2rad ang90 = 90.0 * afactor lattice.alpha.setConst(True, ang90) lattice.beta.setConst(True, ang90) lattice.gamma.setConst(True, ang90) return + def _constrainTetragonal(lattice): """Make constraints for Tetragonal systems. @@ -565,7 +587,8 @@ def _constrainTetragonal(lattice): """ afactor = 1 - if lattice.angunits == "rad": afactor = deg2rad + if lattice.angunits == "rad": + afactor = deg2rad ang90 = 90.0 * afactor lattice.alpha.setConst(True, ang90) lattice.beta.setConst(True, ang90) @@ -573,6 +596,7 @@ def _constrainTetragonal(lattice): lattice.constrain(lattice.b, lattice.a) return + def _constrainTrigonal(lattice): """Make constraints for Trigonal systems. @@ -582,7 +606,8 @@ def _constrainTrigonal(lattice): """ afactor = 1 - if lattice.angunits == "rad": afactor = deg2rad + if lattice.angunits == "rad": + afactor = deg2rad ang90 = 90.0 * afactor ang120 = 120.0 * afactor if lattice.gamma.getValue() == ang120: @@ -597,6 +622,7 @@ def _constrainTrigonal(lattice): lattice.constrain(lattice.gamma, lattice.alpha) return + def _constrainHexagonal(lattice): """Make constraints for Hexagonal systems. @@ -605,7 +631,8 @@ def _constrainHexagonal(lattice): """ afactor = 1 - if lattice.angunits == "rad": afactor = deg2rad + if lattice.angunits == "rad": + afactor = deg2rad ang90 = 90.0 * afactor ang120 = 120.0 * afactor lattice.constrain(lattice.b, lattice.a) @@ -614,6 +641,7 @@ def _constrainHexagonal(lattice): lattice.gamma.setConst(True, ang120) return + def _constrainCubic(lattice): """Make constraints for Cubic systems. @@ -621,7 +649,8 @@ def _constrainCubic(lattice): """ afactor = 1 - if lattice.angunits == "rad": afactor = deg2rad + if lattice.angunits == "rad": + afactor = deg2rad ang90 = 90.0 * afactor lattice.constrain(lattice.b, lattice.a) lattice.constrain(lattice.c, lattice.a) @@ -630,19 +659,21 @@ def _constrainCubic(lattice): lattice.gamma.setConst(True, ang90) return + # This is used to map the correct crystal system to the proper constraint # function. _constraintMap = { - "Triclinic" : _constrainTriclinic, - "Monoclinic" : _constrainMonoclinic, - "Orthorhombic" : _constrainOrthorhombic, - "Tetragonal" : _constrainTetragonal, - "Trigonal" : _constrainTrigonal, - "Hexagonal" : _constrainHexagonal, - "Cubic" : _constrainCubic + "Triclinic": _constrainTriclinic, + "Monoclinic": _constrainMonoclinic, + "Orthorhombic": _constrainOrthorhombic, + "Tetragonal": _constrainTetragonal, + "Trigonal": _constrainTrigonal, + "Hexagonal": _constrainHexagonal, + "Cubic": _constrainCubic, } -def _makeconstraint(parname, formula, scatterer, idx, ns = {}): + +def _makeconstraint(parname, formula, scatterer, idx, ns={}): """Constrain a parameter according to a formula. parname -- Name of parameter @@ -659,10 +690,10 @@ def _makeconstraint(parname, formula, scatterer, idx, ns = {}): if par is None: return - compname = "%s_%i"%(parname, idx) + compname = "%s_%i" % (parname, idx) # Check to see if this parameter is free - pat = r'%s *([+-] *\d+)?$' % compname + pat = r"%s *([+-] *\d+)?$" % compname if re.match(pat, formula): return par @@ -675,9 +706,10 @@ def _makeconstraint(parname, formula, scatterer, idx, ns = {}): # If we got here, then we have a constraint equation # Fix any division issues formula = formula.replace("/", "*1.0/") - scatterer.constrain(par, formula, ns = ns) + scatterer.constrain(par, formula, ns=ns) return + def _getFloat(formula): """Get a float from a formula string, or None if this is not possible.""" try: @@ -685,6 +717,7 @@ def _getFloat(formula): except NameError: return None + # Constants needed above _idxtoij = [(0, 0), (1, 1), (2, 2), (0, 1), (0, 2), (1, 2)] deg2rad = numpy.pi / 180 diff --git a/src/diffpy/srfit/structure/srrealparset.py b/src/diffpy/srfit/structure/srrealparset.py index e1376288..c3c505aa 100644 --- a/src/diffpy/srfit/structure/srrealparset.py +++ b/src/diffpy/srfit/structure/srrealparset.py @@ -42,7 +42,7 @@ def __init__(self, *args, **kw): self.stru = None return - def restrainBVS(self, sig = 1, scaled = False): + def restrainBVS(self, sig=1, scaled=False): """Restrain the bond-valence sum to zero. This adds a penalty to the cost function equal to @@ -70,7 +70,7 @@ def restrainBVS(self, sig = 1, scaled = False): # Return the Restraint object return res - def useSymmetry(self, use = True): + def useSymmetry(self, use=True): """Set this structure to use symmetry. This determines how the structure is treated by SrReal calculators. @@ -91,6 +91,7 @@ def _getSrRealStructure(self): """ from diffpy.srreal.structureadapter import nosymmetry + if self._usesymmetry: return self.stru return nosymmetry(self.stru) diff --git a/src/diffpy/srfit/tests/__init__.py b/src/diffpy/srfit/tests/__init__.py index 845b5c39..81caf417 100644 --- a/src/diffpy/srfit/tests/__init__.py +++ b/src/diffpy/srfit/tests/__init__.py @@ -16,8 +16,8 @@ """Unit tests for diffpy.srfit. """ -import unittest import logging +import unittest # create logger instance for the tests subpackage logging.basicConfig() @@ -25,8 +25,8 @@ del logging -def testsuite(pattern=''): - '''Create a unit tests suite for diffpy.srfit package. +def testsuite(pattern=""): + """Create a unit tests suite for diffpy.srfit package. Parameters ---------- @@ -39,14 +39,16 @@ def testsuite(pattern=''): ------- suite : `unittest.TestSuite` The TestSuite object containing the matching tests. - ''' + """ import re - from os.path import dirname from itertools import chain + from os.path import dirname + from pkg_resources import resource_filename + loader = unittest.defaultTestLoader - thisdir = resource_filename(__name__, '') - depth = __name__.count('.') + 1 + thisdir = resource_filename(__name__, "") + depth = __name__.count(".") + 1 topdir = thisdir for i in range(depth): topdir = dirname(topdir) @@ -56,12 +58,12 @@ def testsuite(pattern=''): rx = re.compile(pattern) tsuites = list(chain.from_iterable(suite_all)) tsok = all(isinstance(ts, unittest.TestSuite) for ts in tsuites) - if not tsok: # pragma: no cover + if not tsok: # pragma: no cover return suite_all tcases = chain.from_iterable(tsuites) for tc in tcases: - tcwords = tc.id().split('.') - shortname = '.'.join(tcwords[-3:]) + tcwords = tc.id().split(".") + shortname = ".".join(tcwords[-3:]) if rx.search(shortname): suite.addTest(tc) # verify all tests are found for an empty pattern. @@ -70,12 +72,12 @@ def testsuite(pattern=''): def test(): - '''Execute all unit tests for the diffpy.srfit package. + """Execute all unit tests for the diffpy.srfit package. Returns ------- result : `unittest.TestResult` - ''' + """ suite = testsuite() runner = unittest.TextTestRunner() result = runner.run(suite) diff --git a/src/diffpy/srfit/tests/speedtest.py b/src/diffpy/srfit/tests/speedtest.py index 373d5843..b822f968 100644 --- a/src/diffpy/srfit/tests/speedtest.py +++ b/src/diffpy/srfit/tests/speedtest.py @@ -18,11 +18,11 @@ from __future__ import print_function import random + import numpy -import diffpy.srfit.equation.visitors as visitors import diffpy.srfit.equation.literals as literals - +import diffpy.srfit.equation.visitors as visitors from diffpy.srfit.tests.utils import _makeArgs x = numpy.arange(0, 20, 0.05) @@ -57,7 +57,7 @@ def makeLazyEquation(): mult2.addLiteral(exp) v2.setValue(x) - v3.setValue(50*x) + v3.setValue(50 * x) v5.setValue(2.11) v6.setValue(numpy.e) @@ -75,23 +75,27 @@ def _f(a, b, c, d, e): return _f + def makeEquation1(): """Make the same equation as the lazy one.""" - y = 50*x + y = 50 * x def _f(a, b, c, d, e): - return ((a+x)*(y-b))**c * d**e + return ((a + x) * (y - b)) ** c * d**e return _f + def timeFunction(f, *args, **kw): """Time a function in ms.""" import time + t1 = time.time() f(*args, **kw) t2 = time.time() - return (t2-t1)*1000 + return (t2 - t1) * 1000 + def speedTest1(): f1 = makeLazyEquation() @@ -102,7 +106,7 @@ def speedTest1(): total1 = 0 total2 = 0 for i in range(len(args)): - args[i] = 10*random.random() + args[i] = 10 * random.random() print("Changing argument %i" % (i + 1)) t1 = timeFunction(f1, *args) t2 = timeFunction(f2, *args) @@ -114,11 +118,13 @@ def speedTest1(): print("Totals:") print("lazy", total1) print("regular", total2) - print("Ratio (lazy/regular)", total1/total2) + print("Ratio (lazy/regular)", total1 / total2) + -def speedTest2(mutate = 2): +def speedTest2(mutate=2): from diffpy.srfit.equation.builder import EquationFactory + factory = EquationFactory() x = numpy.arange(0, 20, 0.05) @@ -144,17 +150,19 @@ def speedTest2(mutate = 2): eq.b7.setValue(2.0) eq.b8.setValue(2.0) - from numpy import exp - from numpy import polyval + from numpy import exp, polyval + def f(A0, qsig, sigma1, sigma2, b1, b2, b3, b4, b5, b6, b7, b8): - return A0*exp(-(x*qsig)**2)*(exp(-((x-1.0)/sigma1)**2)+exp(-((x-2.0)/sigma2)**2)) + polyval([b8, b7, b6, b5,b4,b3,b2,b1],x) + return A0 * exp(-((x * qsig) ** 2)) * ( + exp(-(((x - 1.0) / sigma1) ** 2)) + exp(-(((x - 2.0) / sigma2) ** 2)) + ) + polyval([b8, b7, b6, b5, b4, b3, b2, b1], x) tnpy = 0 teq = 0 # Randomly change variables numargs = len(eq.args) choices = range(numargs) - args = [0.0]*(len(eq.args)) + args = [0.0] * (len(eq.args)) # The call-loop random.seed() @@ -174,15 +182,15 @@ def f(A0, qsig, sigma1, sigma2, b1, b2, b3, b4, b5, b6, b7, b8): tnpy += timeFunction(f, *args) teq += timeFunction(eq, *args) - print("Average call time (%i calls, %i mutations/call):" % - (numcalls, mutate)) - print("numpy: ", tnpy/numcalls) - print("equation: ", teq/numcalls) - print("ratio: ", teq/tnpy) + print("Average call time (%i calls, %i mutations/call):" % (numcalls, mutate)) + print("numpy: ", tnpy / numcalls) + print("equation: ", teq / numcalls) + print("ratio: ", teq / tnpy) return -def speedTest3(mutate = 2): + +def speedTest3(mutate=2): """Test wrt sympy. Results - sympy is 10 to 24 times faster without using arrays (ouch!). @@ -192,6 +200,7 @@ def speedTest3(mutate = 2): """ from diffpy.srfit.equation.builder import EquationFactory + factory = EquationFactory() x = numpy.arange(0, 20, 0.05) @@ -217,17 +226,25 @@ def speedTest3(mutate = 2): eq.b7.setValue(2.0) eq.b8.setValue(2.0) - from sympy import var, exp, lambdify from numpy import polyval - A0, qsig, sigma1, sigma2, b1, b2, b3, b4, b5, b6, b7, b8, xx = vars = var("A0 qsig sigma1 sigma2 b1 b2 b3 b4 b5 b6 b7 b8 xx") - f = lambdify(vars, A0*exp(-(xx*qsig)**2)*(exp(-((xx-1.0)/sigma1)**2)+exp(-((xx-2.0)/sigma2)**2)) + polyval([b1, b2, b3, b4, b5, b6, b7, b8], xx), "numpy") + from sympy import exp, lambdify, var + + A0, qsig, sigma1, sigma2, b1, b2, b3, b4, b5, b6, b7, b8, xx = vars = var( + "A0 qsig sigma1 sigma2 b1 b2 b3 b4 b5 b6 b7 b8 xx" + ) + f = lambdify( + vars, + A0 * exp(-((xx * qsig) ** 2)) * (exp(-(((xx - 1.0) / sigma1) ** 2)) + exp(-(((xx - 2.0) / sigma2) ** 2))) + + polyval([b1, b2, b3, b4, b5, b6, b7, b8], xx), + "numpy", + ) tnpy = 0 teq = 0 # Randomly change variables numargs = len(eq.args) choices = range(numargs) - args = [1.0]*(len(eq.args)) + args = [1.0] * (len(eq.args)) args.append(x) # The call-loop @@ -248,15 +265,15 @@ def speedTest3(mutate = 2): teq += timeFunction(eq, *(args[:-1])) tnpy += timeFunction(f, *args) - print("Average call time (%i calls, %i mutations/call):" % - (numcalls, mutate)) - print("sympy: ", tnpy/numcalls) - print("equation: ", teq/numcalls) - print("ratio: ", teq/tnpy) + print("Average call time (%i calls, %i mutations/call):" % (numcalls, mutate)) + print("sympy: ", tnpy / numcalls) + print("equation: ", teq / numcalls) + print("ratio: ", teq / tnpy) return -def speedTest4(mutate = 2): + +def speedTest4(mutate=2): """Test wrt sympy. Results - sympy is 10 to 24 times faster without using arrays (ouch!). @@ -266,6 +283,7 @@ def speedTest4(mutate = 2): """ from diffpy.srfit.equation.builder import EquationFactory + factory = EquationFactory() x = numpy.arange(0, 20, 0.05) @@ -276,8 +294,9 @@ def speedTest4(mutate = 2): factory.registerConstant("x", x) eq = factory.makeEquation(eqstr) - from sympy import var, lambdify from numpy import polyval + from sympy import lambdify, var + b1, b2, b3, b4, b5, b6, b7, b8, xx = vars = var("b1 b2 b3 b4 b5 b6 b7 b8 xx") f = lambdify(vars, polyval([b1, b2, b3, b4, b5, b6, b7, b8], xx), "numpy") @@ -286,7 +305,7 @@ def speedTest4(mutate = 2): # Randomly change variables numargs = len(eq.args) choices = range(numargs) - args = [1.0]*(len(eq.args)) + args = [1.0] * (len(eq.args)) args.append(x) # The call-loop @@ -307,18 +326,19 @@ def speedTest4(mutate = 2): teq += timeFunction(eq, *(args[:-1])) tnpy += timeFunction(f, *args) - print("Average call time (%i calls, %i mutations/call):" % - (numcalls, mutate)) - print("sympy: ", tnpy/numcalls) - print("equation: ", teq/numcalls) - print("ratio: ", teq/tnpy) + print("Average call time (%i calls, %i mutations/call):" % (numcalls, mutate)) + print("sympy: ", tnpy / numcalls) + print("equation: ", teq / numcalls) + print("ratio: ", teq / tnpy) return -def weightedTest(mutate = 2): + +def weightedTest(mutate=2): """Show the benefits of a properly balanced equation tree.""" from diffpy.srfit.equation.builder import EquationFactory + factory = EquationFactory() x = numpy.arange(0, 10, 0.01) @@ -338,20 +358,21 @@ def weightedTest(mutate = 2): eq.b7.setValue(2.0) eq.b8.setValue(2.0) - #scale = visitors.NodeWeigher() - #eq.root.identify(scale) - #print(scale.output) + # scale = visitors.NodeWeigher() + # eq.root.identify(scale) + # print(scale.output) from numpy import polyval + def f(b1, b2, b3, b4, b5, b6, b7, b8): - return polyval([b8, b7, b6, b5,b4,b3,b2,b1],x) + return polyval([b8, b7, b6, b5, b4, b3, b2, b1], x) tnpy = 0 teq = 0 # Randomly change variables numargs = len(eq.args) choices = range(numargs) - args = [0.1]*numargs + args = [0.1] * numargs # The call-loop random.seed() @@ -367,23 +388,24 @@ def f(b1, b2, b3, b4, b5, b6, b7, b8): c.remove(idx) args[idx] = random.random() - #print(args) + # print(args) # Time the different functions with these arguments teq += timeFunction(eq, *args) tnpy += timeFunction(f, *args) - print("Average call time (%i calls, %i mutations/call):" % - (numcalls, mutate)) - print("numpy: ", tnpy/numcalls) - print("equation: ", teq/numcalls) - print("ratio: ", teq/tnpy) + print("Average call time (%i calls, %i mutations/call):" % (numcalls, mutate)) + print("numpy: ", tnpy / numcalls) + print("equation: ", teq / numcalls) + print("ratio: ", teq / tnpy) return + def profileTest(): from diffpy.srfit.builder import EquationFactory + factory = EquationFactory() x = numpy.arange(0, 10, 0.001) @@ -406,7 +428,7 @@ def profileTest(): mutate = 8 numargs = len(eq.args) choices = range(numargs) - args = [0.1]*numargs + args = [0.1] * numargs # The call-loop random.seed() diff --git a/src/diffpy/srfit/tests/testbuilder.py b/src/diffpy/srfit/tests/testbuilder.py index 15a7ae84..9cd08f5f 100644 --- a/src/diffpy/srfit/tests/testbuilder.py +++ b/src/diffpy/srfit/tests/testbuilder.py @@ -21,8 +21,7 @@ import diffpy.srfit.equation.builder as builder import diffpy.srfit.equation.literals as literals -from diffpy.srfit.tests.utils import _makeArgs -from diffpy.srfit.tests.utils import noObserversInGlobalBuilders +from diffpy.srfit.tests.utils import _makeArgs, noObserversInGlobalBuilders class TestBuilder(unittest.TestCase): @@ -52,7 +51,6 @@ def testRegisterArg(self): self.assertTrue(noObserversInGlobalBuilders()) return - def testRegisterOperator(self): """Try to use an operator without arguments in an equation.""" @@ -86,13 +84,13 @@ def testRegisterOperator(self): self.assertTrue(noObserversInGlobalBuilders()) return - def testSwapping(self): def g1(v1, v2, v3, v4): return (v1 + v2) * (v3 + v4) + def g2(v1): - return 0.5*v1 + return 0.5 * v1 factory = builder.EquationFactory() v1, v2, v3, v4, v5 = _makeArgs(5) @@ -149,7 +147,7 @@ def g2(v1): def testParseEquation(self): - from numpy import sin, divide, sqrt, array_equal, e + from numpy import array_equal, divide, e, sin, sqrt factory = builder.EquationFactory() @@ -163,8 +161,8 @@ def testParseEquation(self): 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) - self.assertTrue(array_equal(eq(), f(A,x,B,C))) + f = lambda A, x, B, C: A * sin(0.5 * x) + divide(B, C) + self.assertTrue(array_equal(eq(), f(A, x, B, C))) # Make sure that the arguments of eq are listed in the order in which # they appear in the equations. @@ -176,8 +174,8 @@ def testParseEquation(self): sigma = 0.1 eq.x.setValue(x) eq.sigma.setValue(sigma) - f = lambda x, sigma : sqrt(e**(-0.5*(x/sigma)**2)) - self.assertTrue(numpy.allclose(eq(), f(x,sigma))) + f = lambda x, sigma: sqrt(e ** (-0.5 * (x / sigma) ** 2)) + self.assertTrue(numpy.allclose(eq(), f(x, sigma))) self.assertEqual(eq.args, [eq.x, eq.sigma]) @@ -186,14 +184,14 @@ def testParseEquation(self): eq = factory.makeEquation("sqrt(e**(-0.5*(x/sigma)**2))") self.assertTrue("sigma" in eq.argdict) self.assertTrue("x" not in eq.argdict) - self.assertTrue(numpy.allclose(eq(sigma=sigma), f(x,sigma))) + self.assertTrue(numpy.allclose(eq(sigma=sigma), f(x, sigma))) self.assertEqual(eq.args, [eq.sigma]) # Equation with user-defined functions factory.registerFunction("myfunc", eq, ["sigma"]) eq2 = factory.makeEquation("c*myfunc(sigma)") - self.assertTrue(numpy.allclose(eq2(c=2, sigma=sigma), 2*f(x,sigma))) + self.assertTrue(numpy.allclose(eq2(c=2, sigma=sigma), 2 * f(x, sigma))) self.assertTrue("sigma" in eq2.argdict) self.assertTrue("c" in eq2.argdict) self.assertEqual(eq2.args, [eq2.c, eq2.sigma]) @@ -201,35 +199,32 @@ def testParseEquation(self): self.assertTrue(noObserversInGlobalBuilders()) return - def test_parse_constant(self): - """Verify parsing of constant numeric expressions. - """ + """Verify parsing of constant numeric expressions.""" factory = builder.EquationFactory() - eq = factory.makeEquation('3.12 + 2') + eq = factory.makeEquation("3.12 + 2") self.assertTrue(isinstance(eq, builder.Equation)) self.assertEqual(set(), factory.equations) self.assertEqual(5.12, eq()) self.assertRaises(ValueError, eq, 3) return - def testBuildEquation(self): from numpy import array_equal # simple equation sin = builder.getBuilder("sin") - a = builder.ArgumentBuilder(name="a", value = 1) - A = builder.ArgumentBuilder(name="A", value = 2) + a = builder.ArgumentBuilder(name="a", value=1) + A = builder.ArgumentBuilder(name="A", value=2) x = numpy.arange(0, numpy.pi, 0.1) - beq = A*sin(a*x) + beq = A * sin(a * x) eq = beq.getEquation() self.assertTrue("a" in eq.argdict) self.assertTrue("A" in eq.argdict) - self.assertTrue(array_equal(eq(), 2*numpy.sin(x))) + self.assertTrue(array_equal(eq(), 2 * numpy.sin(x))) self.assertEqual(eq.args, [eq.A, eq.a]) @@ -238,13 +233,13 @@ def testBuildEquation(self): # custom function def _f(a, b): - return (a-b)*1.0/(a+b) + return (a - b) * 1.0 / (a + b) f = builder.wrapFunction("f", _f, 2, 1) - a = builder.ArgumentBuilder(name="a", value = 2) - b = builder.ArgumentBuilder(name="b", value = 1) + a = builder.ArgumentBuilder(name="a", value=2) + b = builder.ArgumentBuilder(name="b", value=1) - beq = sin(f(a,b)) + beq = sin(f(a, b)) eq = beq.getEquation() self.assertEqual(eq(), numpy.sin(_f(2, 1))) @@ -252,32 +247,32 @@ def _f(a, b): sqrt = builder.getBuilder("sqrt") e = numpy.e _x = numpy.arange(0, 1, 0.05) - x = builder.ArgumentBuilder(name="x", value = _x, const = True) - sigma = builder.ArgumentBuilder(name="sigma", value = 0.1) - beq = sqrt(e**(-0.5*(x/sigma)**2)) + x = builder.ArgumentBuilder(name="x", value=_x, const=True) + 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)) - self.assertTrue(numpy.allclose(eq(), numpy.sqrt(e**(-0.5*(_x/0.1)**2)))) + f = lambda x, sigma: sqrt(e ** (-0.5 * (x / sigma) ** 2)) + self.assertTrue(numpy.allclose(eq(), numpy.sqrt(e ** (-0.5 * (_x / 0.1) ** 2)))) # Equation with Equation - A = builder.ArgumentBuilder(name="A", value = 2) - B = builder.ArgumentBuilder(name="B", value = 4) + A = builder.ArgumentBuilder(name="A", value=2) + B = builder.ArgumentBuilder(name="B", value=4) beq = A + B eq = beq.getEquation() E = builder.wrapOperator("eq", eq) - eq2 = (2*E).getEquation() + eq2 = (2 * E).getEquation() # Make sure these evaulate to the same thing self.assertEqual(eq.args, [A.literal, B.literal]) - self.assertEqual(2*eq(), eq2()) + self.assertEqual(2 * eq(), eq2()) # Pass new arguments to the equation - C = builder.ArgumentBuilder(name="C", value = 5) - D = builder.ArgumentBuilder(name="D", value = 6) - eq3 = (E(C, D)+1).getEquation() + C = builder.ArgumentBuilder(name="C", value=5) + D = builder.ArgumentBuilder(name="D", value=6) + eq3 = (E(C, D) + 1).getEquation() self.assertEqual(12, eq3()) # Pass old and new arguments to the equation # If things work right, A has been given the value of C in the last # evaluation (5) - eq4 = (3*E(A, D)-1).getEquation() + eq4 = (3 * E(A, D) - 1).getEquation() self.assertEqual(32, eq4()) # Try to pass the wrong number of arguments self.assertRaises(ValueError, E, A) diff --git a/src/diffpy/srfit/tests/testcharacteristicfunctions.py b/src/diffpy/srfit/tests/testcharacteristicfunctions.py index e619f4fc..62e4d1da 100644 --- a/src/diffpy/srfit/tests/testcharacteristicfunctions.py +++ b/src/diffpy/srfit/tests/testcharacteristicfunctions.py @@ -19,52 +19,52 @@ import numpy -from diffpy.srfit.tests.utils import has_sas, _msg_nosas from diffpy.srfit.sas.sasimport import sasimport +from diffpy.srfit.tests.utils import _msg_nosas, has_sas # Global variables to be assigned in setUp cf = None # ---------------------------------------------------------------------------- + @unittest.skipUnless(has_sas, _msg_nosas) class TestSASCF(unittest.TestCase): def setUp(self): global cf import diffpy.srfit.pdf.characteristicfunctions as cf - return + return def testSphere(self): radius = 25 # Calculate sphere cf from SphereModel - SphereModel = sasimport('sas.models.SphereModel').SphereModel + SphereModel = sasimport("sas.models.SphereModel").SphereModel model = SphereModel() model.setParam("radius", radius) ff = cf.SASCF("sphere", model) - r = numpy.arange(1, 60, 0.1, dtype = float) + r = numpy.arange(1, 60, 0.1, dtype=float) fr1 = ff(r) # Calculate sphere cf analytically - fr2 = cf.sphericalCF(r, 2*radius) + fr2 = cf.sphericalCF(r, 2 * radius) diff = fr1 - fr2 res = numpy.dot(diff, diff) res /= numpy.dot(fr2, fr2) self.assertAlmostEqual(0, res, 4) return - def testSpheroid(self): prad = 20.9 erad = 33.114 # Calculate cf from EllipsoidModel - EllipsoidModel = sasimport('sas.models.EllipsoidModel').EllipsoidModel + EllipsoidModel = sasimport("sas.models.EllipsoidModel").EllipsoidModel model = EllipsoidModel() model.setParam("radius_a", prad) model.setParam("radius_b", erad) ff = cf.SASCF("spheroid", model) - r = numpy.arange(0, 100, 1/numpy.pi, dtype = float) + r = numpy.arange(0, 100, 1 / numpy.pi, dtype=float) fr1 = ff(r) # Calculate cf analytically @@ -75,17 +75,16 @@ def testSpheroid(self): self.assertAlmostEqual(0, res, 4) return - def testShell(self): radius = 19.2 thickness = 7.8 # Calculate cf from VesicleModel - VesicleModel = sasimport('sas.models.VesicleModel').VesicleModel + VesicleModel = sasimport("sas.models.VesicleModel").VesicleModel model = VesicleModel() model.setParam("radius", radius) model.setParam("thickness", thickness) ff = cf.SASCF("vesicle", model) - r = numpy.arange(0, 99.45, 0.1, dtype = float) + r = numpy.arange(0, 99.45, 0.1, dtype=float) fr1 = ff(r) # Calculate sphere cf analytically @@ -96,23 +95,22 @@ def testShell(self): self.assertAlmostEqual(0, res, 4) return - def testCylinder(self): """Make sure cylinder works over different r-ranges""" radius = 100 length = 30 - CylinderModel = sasimport('sas.models.CylinderModel').CylinderModel + CylinderModel = sasimport("sas.models.CylinderModel").CylinderModel model = CylinderModel() model.setParam("radius", radius) model.setParam("length", length) ff = cf.SASCF("cylinder", model) - r1 = numpy.arange(0, 10, 0.1, dtype = float) - r2 = numpy.arange(0, 50, 0.1, dtype = float) - r3 = numpy.arange(0, 100, 0.1, dtype = float) - r4 = numpy.arange(0, 500, 0.1, dtype = float) + r1 = numpy.arange(0, 10, 0.1, dtype=float) + r2 = numpy.arange(0, 50, 0.1, dtype=float) + r3 = numpy.arange(0, 100, 0.1, dtype=float) + r4 = numpy.arange(0, 500, 0.1, dtype=float) fr1 = ff(r1) fr2 = ff(r2) @@ -120,36 +118,37 @@ def testCylinder(self): fr4 = ff(r4) d = fr1 - numpy.interp(r1, r2, fr2) - res12 = numpy.dot(d,d) + res12 = numpy.dot(d, d) res12 /= numpy.dot(fr1, fr1) self.assertAlmostEqual(0, res12, 4) d = fr1 - numpy.interp(r1, r3, fr3) - res13 = numpy.dot(d,d) + res13 = numpy.dot(d, d) res13 /= numpy.dot(fr1, fr1) self.assertAlmostEqual(0, res13, 4) d = fr1 - numpy.interp(r1, r4, fr4) - res14 = numpy.dot(d,d) + res14 = numpy.dot(d, d) res14 /= numpy.dot(fr1, fr1) self.assertAlmostEqual(0, res14, 4) d = fr2 - numpy.interp(r2, r3, fr3) - res23 = numpy.dot(d,d) + res23 = numpy.dot(d, d) res23 /= numpy.dot(fr2, fr2) self.assertAlmostEqual(0, res23, 4) d = fr2 - numpy.interp(r2, r4, fr4) - res24 = numpy.dot(d,d) + res24 = numpy.dot(d, d) res24 /= numpy.dot(fr2, fr2) self.assertAlmostEqual(0, res24, 4) d = fr3 - numpy.interp(r3, r4, fr4) - res34 = numpy.dot(d,d) + res34 = numpy.dot(d, d) res34 /= numpy.dot(fr3, fr3) self.assertAlmostEqual(0, res34, 4) return + # End of class TestSASCF if __name__ == "__main__": diff --git a/src/diffpy/srfit/tests/testconstraint.py b/src/diffpy/srfit/tests/testconstraint.py index c2501f14..57440096 100644 --- a/src/diffpy/srfit/tests/testconstraint.py +++ b/src/diffpy/srfit/tests/testconstraint.py @@ -17,10 +17,10 @@ import unittest +from diffpy.srfit.equation.builder import EquationFactory from diffpy.srfit.fitbase.constraint import Constraint -from diffpy.srfit.fitbase.recipeorganizer import equationFromString from diffpy.srfit.fitbase.parameter import Parameter -from diffpy.srfit.equation.builder import EquationFactory +from diffpy.srfit.fitbase.recipeorganizer import equationFromString class TestConstraint(unittest.TestCase): diff --git a/src/diffpy/srfit/tests/testcontribution.py b/src/diffpy/srfit/tests/testcontribution.py index c28e9958..7e0eb8fd 100644 --- a/src/diffpy/srfit/tests/testcontribution.py +++ b/src/diffpy/srfit/tests/testcontribution.py @@ -17,13 +17,13 @@ import unittest -from numpy import arange, dot, array_equal, sin +from numpy import arange, array_equal, dot, sin +from diffpy.srfit.exceptions import SrFitError from diffpy.srfit.fitbase.fitcontribution import FitContribution -from diffpy.srfit.fitbase.profilegenerator import ProfileGenerator -from diffpy.srfit.fitbase.profile import Profile from diffpy.srfit.fitbase.parameter import Parameter -from diffpy.srfit.exceptions import SrFitError +from diffpy.srfit.fitbase.profile import Profile +from diffpy.srfit.fitbase.profilegenerator import ProfileGenerator from diffpy.srfit.tests.utils import noObserversInGlobalBuilders @@ -47,16 +47,15 @@ def testSetProfile(self): self.assertTrue(fc._eq is None) self.assertTrue(fc._reseq is None) # check type checking - fc1 = FitContribution('test1') - self.assertRaises(TypeError, fc1.setProfile, 'invalid') + fc1 = FitContribution("test1") + self.assertRaises(TypeError, fc1.setProfile, "invalid") # check if residual equation is set up when possible - fc2 = FitContribution('test2') - fc2.setEquation('A * x') + fc2 = FitContribution("test2") + fc2.setEquation("A * x") fc2.setProfile(profile) self.assertFalse(fc2._reseq is None) return - def testAddProfileGenerator(self): fc = self.fitcontribution gen = self.gen @@ -115,7 +114,7 @@ def testReplacements(self): profile = self.profile profile.setObservedProfile(xobs, yobs) xobs2 = arange(0, 10, 0.8) - yobs2 = 0.5*xobs2 + yobs2 = 0.5 * xobs2 profile2 = Profile() profile2.setObservedProfile(xobs2, yobs2) gen = self.gen @@ -145,7 +144,6 @@ def testReplacements(self): self.assertEqual(len(xobs2), len(fc.residual())) return - def testResidual(self): """Test the residual, which requires all other methods.""" fc = self.fitcontribution @@ -195,7 +193,7 @@ def testResidual(self): self.assertTrue(fc._eq._value is None) self.assertTrue(fc._reseq._value is None) xobs = arange(0, 10, 0.5) - yobs = 9*sin(xobs) + yobs = 9 * sin(xobs) profile.setObservedProfile(xobs, yobs) self.assertTrue(fc._eq._value is None) self.assertTrue(fc._reseq._value is None) @@ -207,25 +205,23 @@ def testResidual(self): fc.setEquation("2*I") fc.setResidualEquation("resv") chiv = fc.residual() - self.assertAlmostEqual(sum((2*xobs-yobs)**2)/sum(yobs**2), - dot(chiv, chiv)) + self.assertAlmostEqual(sum((2 * xobs - yobs) ** 2) / sum(yobs**2), dot(chiv, chiv)) # Make a custom residual. fc.setResidualEquation("abs(eq-y)**0.5") chiv = fc.residual() - self.assertAlmostEqual(sum(abs(2*xobs-yobs)), dot(chiv, chiv)) + self.assertAlmostEqual(sum(abs(2 * xobs - yobs)), dot(chiv, chiv)) # Test configuration checks - fc1 = FitContribution('test1') - self.assertRaises(SrFitError, fc1.setResidualEquation, 'chiv') + fc1 = FitContribution("test1") + self.assertRaises(SrFitError, fc1.setResidualEquation, "chiv") fc1.setProfile(self.profile) - self.assertRaises(SrFitError, fc1.setResidualEquation, 'chiv') - fc1.setEquation('A * x') - fc1.setResidualEquation('chiv') + self.assertRaises(SrFitError, fc1.setResidualEquation, "chiv") + fc1.setEquation("A * x") + fc1.setResidualEquation("chiv") self.assertTrue(noObserversInGlobalBuilders()) return - def test_setEquation(self): """Check replacement of removed parameters.""" fc = self.fitcontribution @@ -234,61 +230,55 @@ def test_setEquation(self): self.assertEqual(7, fc.evaluate()) fc.removeParameter(fc.x) x = arange(0, 10, 0.5) - fc.newParameter('x', x) + fc.newParameter("x", x) self.assertTrue(array_equal(5 + x, fc.evaluate())) self.assertTrue(noObserversInGlobalBuilders()) return - def test_getEquation(self): """Check getting the current profile simulation formula.""" fc = self.fitcontribution - self.assertEqual('', fc.getEquation()) + self.assertEqual("", fc.getEquation()) fc.setEquation("A * sin(x + 5)") - self.assertEqual('(A * sin((x + 5)))', fc.getEquation()) + self.assertEqual("(A * sin((x + 5)))", fc.getEquation()) self.assertTrue(noObserversInGlobalBuilders()) return - def test_getResidualEquation(self): """Check getting the current formula for residual equation.""" fc = self.fitcontribution - self.assertEqual('', fc.getResidualEquation()) + self.assertEqual("", fc.getResidualEquation()) fc.setProfile(self.profile) - fc.setEquation('A * x + B') - self.assertEqual('((eq - y) / dy)', fc.getResidualEquation()) - fc.setResidualEquation('2 * (eq - y)') - self.assertEqual('(2 * (eq - y))', fc.getResidualEquation()) + fc.setEquation("A * x + B") + self.assertEqual("((eq - y) / dy)", fc.getResidualEquation()) + fc.setResidualEquation("2 * (eq - y)") + self.assertEqual("(2 * (eq - y))", fc.getResidualEquation()) return - def test_releaseOldEquations(self): - """Ensure EquationFactory does not hold to obsolete Equations. - """ + """Ensure EquationFactory does not hold to obsolete Equations.""" fc = self.fitcontribution self.assertEqual(0, len(fc._eqfactory.equations)) for i in range(5): - fc.setEquation('A * x + B') + fc.setEquation("A * x + B") self.assertEqual(1, len(fc._eqfactory.equations)) fc.setProfile(self.profile) for i in range(5): - fc.setResidualEquation('chiv') + fc.setResidualEquation("chiv") self.assertEqual(2, len(fc._eqfactory.equations)) return - def test_registerFunction(self): - """Ensure registered function works after second setEquation call. - """ + """Ensure registered function works after second setEquation call.""" fc = self.fitcontribution - fsquare = lambda x : x**2 - fc.registerFunction(fsquare, name='fsquare') - fc.setEquation('fsquare') + fsquare = lambda x: x**2 + fc.registerFunction(fsquare, name="fsquare") + fc.setEquation("fsquare") fc.x.setValue(5) self.assertEqual(25, fc.evaluate()) fc.x << 6 self.assertEqual(36, fc.evaluate()) - fc.setEquation('fsquare + 5') + fc.setEquation("fsquare + 5") self.assertEqual(41, fc.evaluate()) fc.x << -1 self.assertEqual(6, fc.evaluate()) diff --git a/src/diffpy/srfit/tests/testdiffpyparset.py b/src/diffpy/srfit/tests/testdiffpyparset.py index fb9a2990..b423ff13 100644 --- a/src/diffpy/srfit/tests/testdiffpyparset.py +++ b/src/diffpy/srfit/tests/testdiffpyparset.py @@ -15,36 +15,37 @@ """Tests for diffpy.srfit.structure package.""" -import unittest import pickle +import unittest import numpy -from diffpy.srfit.tests.utils import has_structure, _msg_nostructure +from diffpy.srfit.tests.utils import _msg_nostructure, has_structure # Global variables to be assigned in setUp Atom = Lattice = Structure = DiffpyStructureParSet = None # ---------------------------------------------------------------------------- + @unittest.skipUnless(has_structure, _msg_nostructure) class TestParameterAdapter(unittest.TestCase): def setUp(self): global Atom, Lattice, Structure, DiffpyStructureParSet - from diffpy.structure import Atom, Lattice, Structure from diffpy.srfit.structure.diffpyparset import DiffpyStructureParSet - return + from diffpy.structure import Atom, Lattice, Structure + return def testDiffpyStructureParSet(self): """Test the structure conversion.""" - a1 = Atom("Cu", xyz = numpy.array([.0, .1, .2]), Uisoequiv = 0.003) - a2 = Atom("Ag", xyz = numpy.array([.3, .4, .5]), Uisoequiv = 0.002) + a1 = Atom("Cu", xyz=numpy.array([0.0, 0.1, 0.2]), Uisoequiv=0.003) + a2 = Atom("Ag", xyz=numpy.array([0.3, 0.4, 0.5]), Uisoequiv=0.002) l = Lattice(2.5, 2.5, 2.5, 90, 90, 90) - dsstru = Structure([a1,a2], l) + dsstru = Structure([a1, a2], l) # Structure makes copies a1 = dsstru[0] a2 = dsstru[1] @@ -63,14 +64,14 @@ def _testAtoms(): self.assertEqual(a2.Bisoequiv, s.Ag0.Biso.getValue()) for i in range(1, 4): for j in range(i, 4): - uijstru = getattr(a1, "U%i%i"%(i,j)) - uij = getattr(s.Cu0, "U%i%i"%(i,j)).getValue() - uji = getattr(s.Cu0, "U%i%i"%(j,i)).getValue() + uijstru = getattr(a1, "U%i%i" % (i, j)) + uij = getattr(s.Cu0, "U%i%i" % (i, j)).getValue() + uji = getattr(s.Cu0, "U%i%i" % (j, i)).getValue() self.assertEqual(uijstru, uij) self.assertEqual(uijstru, uji) - bijstru = getattr(a1, "B%i%i"%(i,j)) - bij = getattr(s.Cu0, "B%i%i"%(i,j)).getValue() - bji = getattr(s.Cu0, "B%i%i"%(j,i)).getValue() + bijstru = getattr(a1, "B%i%i" % (i, j)) + bij = getattr(s.Cu0, "B%i%i" % (i, j)).getValue() + bji = getattr(s.Cu0, "B%i%i" % (j, i)).getValue() self.assertEqual(bijstru, bij) self.assertEqual(bijstru, bji) @@ -79,7 +80,6 @@ def _testAtoms(): self.assertEqual(a1.xyz[2], s.Cu0.z.getValue()) return - def _testLattice(): # Test the lattice @@ -114,10 +114,8 @@ def _testLattice(): self.assertNotEqual(d, dsstru.lattice.dist(a1.xyz, a2.xyz)) return - def test___repr__(self): - """Test representation of DiffpyStructureParSet objects. - """ + """Test representation of DiffpyStructureParSet objects.""" lat = Lattice(3, 3, 2, 90, 90, 90) atom = Atom("C", [0, 0.2, 0.5]) stru = Structure([atom], lattice=lat) @@ -127,10 +125,8 @@ def test___repr__(self): self.assertEqual(repr(atom), repr(dsps.atoms[0])) return - def test_pickling(self): - """Test pickling of DiffpyStructureParSet. - """ + """Test pickling of DiffpyStructureParSet.""" stru = Structure([Atom("C", [0, 0.2, 0.5])]) dsps = DiffpyStructureParSet("dsps", stru) data = pickle.dumps(dsps) @@ -139,6 +135,7 @@ def test_pickling(self): self.assertEqual(0.2, dsps2.atoms[0].y.value) return + # End of class TestParameterAdapter if __name__ == "__main__": diff --git a/src/diffpy/srfit/tests/testequation.py b/src/diffpy/srfit/tests/testequation.py index 34b79361..8d264451 100644 --- a/src/diffpy/srfit/tests/testequation.py +++ b/src/diffpy/srfit/tests/testequation.py @@ -19,8 +19,7 @@ import diffpy.srfit.equation.literals as literals from diffpy.srfit.equation import Equation -from diffpy.srfit.tests.utils import _makeArgs -from diffpy.srfit.tests.utils import noObserversInGlobalBuilders +from diffpy.srfit.tests.utils import _makeArgs, noObserversInGlobalBuilders class TestEquation(unittest.TestCase): @@ -74,18 +73,18 @@ def testSimpleFunction(self): self.assertTrue(v3 is eq.v3) self.assertTrue(v4 is eq.v4) - self.assertEqual(20, eq()) # 20 = 2.5*(1+3)*(4-2) - self.assertEqual(20, eq.getValue()) # same as above - self.assertEqual(20, eq.value) # same as above - self.assertEqual(25, eq(v1=2)) # 25 = 2.5*(2+3)*(4-2) - self.assertEqual(50, eq(v2=0)) # 50 = 2.5*(2+3)*(4-0) - self.assertEqual(30, eq(v3=1)) # 30 = 2.5*(2+1)*(4-0) - self.assertEqual(0, eq(v4=0)) # 20 = 2.5*(2+1)*(0-0) + self.assertEqual(20, eq()) # 20 = 2.5*(1+3)*(4-2) + self.assertEqual(20, eq.getValue()) # same as above + self.assertEqual(20, eq.value) # same as above + self.assertEqual(25, eq(v1=2)) # 25 = 2.5*(2+3)*(4-2) + self.assertEqual(50, eq(v2=0)) # 50 = 2.5*(2+3)*(4-0) + self.assertEqual(30, eq(v3=1)) # 30 = 2.5*(2+1)*(4-0) + self.assertEqual(0, eq(v4=0)) # 20 = 2.5*(2+1)*(0-0) # Try some swapping eq.swap(v4, v1) self.assertTrue(eq._value is None) - self.assertEqual(15, eq()) # 15 = 2.5*(2+1)*(2-0) + self.assertEqual(15, eq()) # 15 = 2.5*(2+1)*(2-0) args = eq.args self.assertTrue(v4 not in args) @@ -160,18 +159,18 @@ def testEmbeddedEquation(self): self.assertTrue(eq._value is None) v1.value = 1 - self.assertEqual(20, eq()) # 20 = 2.5*(1+3)*(4-2) - self.assertEqual(20, eq.getValue()) # same as above - self.assertEqual(20, eq.value) # same as above - self.assertEqual(25, eq(v1=2)) # 25 = 2.5*(2+3)*(4-2) - self.assertEqual(50, eq(v2=0)) # 50 = 2.5*(2+3)*(4-0) - self.assertEqual(30, eq(v3=1)) # 30 = 2.5*(2+1)*(4-0) - self.assertEqual(0, eq(v4=0)) # 20 = 2.5*(2+1)*(0-0) + self.assertEqual(20, eq()) # 20 = 2.5*(1+3)*(4-2) + self.assertEqual(20, eq.getValue()) # same as above + self.assertEqual(20, eq.value) # same as above + self.assertEqual(25, eq(v1=2)) # 25 = 2.5*(2+3)*(4-2) + self.assertEqual(50, eq(v2=0)) # 50 = 2.5*(2+3)*(4-0) + self.assertEqual(30, eq(v3=1)) # 30 = 2.5*(2+1)*(4-0) + self.assertEqual(0, eq(v4=0)) # 20 = 2.5*(2+1)*(0-0) # Try some swapping. eq.swap(v4, v1) self.assertTrue(eq._value is None) - self.assertEqual(15, eq()) # 15 = 2.5*(2+1)*(2-0) + self.assertEqual(15, eq()) # 15 = 2.5*(2+1)*(2-0) args = eq.args self.assertTrue(v4 not in args) diff --git a/src/diffpy/srfit/tests/testfitrecipe.py b/src/diffpy/srfit/tests/testfitrecipe.py index 3df264e9..11645991 100644 --- a/src/diffpy/srfit/tests/testfitrecipe.py +++ b/src/diffpy/srfit/tests/testfitrecipe.py @@ -17,12 +17,12 @@ import unittest -from numpy import linspace, array_equal, pi, sin, dot +from numpy import array_equal, dot, linspace, pi, sin -from diffpy.srfit.fitbase.fitrecipe import FitRecipe from diffpy.srfit.fitbase.fitcontribution import FitContribution -from diffpy.srfit.fitbase.profile import Profile +from diffpy.srfit.fitbase.fitrecipe import FitRecipe from diffpy.srfit.fitbase.parameter import Parameter +from diffpy.srfit.fitbase.profile import Profile from diffpy.srfit.tests.utils import capturestdout @@ -53,8 +53,8 @@ def testFixFree(self): recipe = self.recipe con = self.fitcontribution - recipe.addVar(con.A, 2, tag = "tagA") - recipe.addVar(con.k, 1, tag = "tagk") + recipe.addVar(con.A, 2, tag="tagA") + recipe.addVar(con.k, 1, tag="tagk") recipe.addVar(con.c, 0) recipe.newVar("B", 0) @@ -78,7 +78,7 @@ def testFixFree(self): self.assertTrue(recipe.isFree(recipe.k)) self.assertTrue(recipe.isFree(recipe.c)) self.assertTrue(recipe.isFree(recipe.B)) - recipe.fix(recipe.A, "tagk", c = 3) + recipe.fix(recipe.A, "tagk", c=3) self.assertFalse(recipe.isFree(recipe.A)) self.assertFalse(recipe.isFree(recipe.k)) self.assertFalse(recipe.isFree(recipe.c)) @@ -91,7 +91,7 @@ def testFixFree(self): self.assertFalse(recipe.isFree(recipe.B)) self.assertRaises(ValueError, recipe.free, "junk") - self.assertRaises(ValueError, recipe.fix, tagA = 1) + self.assertRaises(ValueError, recipe.fix, tagA=1) self.assertRaises(ValueError, recipe.fix, "junk") return @@ -143,7 +143,6 @@ def testVars(self): self.assertTrue(2 in values) return - def testResidual(self): """Test the residual and everything that can change it.""" @@ -153,16 +152,15 @@ def testResidual(self): # Change the c value to 1 so that the equation evaluates as sin(x+1) x = self.profile.x - y = sin(x+1) + y = sin(x + 1) self.recipe.cont.c.setValue(1) res = self.recipe.residual() - self.assertTrue( array_equal(y-self.profile.y, res) ) + self.assertTrue(array_equal(y - self.profile.y, res)) # Try some constraints # Make c = 2*A, A = Avar var = self.recipe.newVar("Avar") - self.recipe.constrain(self.fitcontribution.c, "2*A", - {"A" : self.fitcontribution.A}) + self.recipe.constrain(self.fitcontribution.c, "2*A", {"A": self.fitcontribution.A}) self.assertEqual(2, self.fitcontribution.c.value) self.recipe.constrain(self.fitcontribution.A, var) self.assertEqual(1, var.getValue()) @@ -171,9 +169,9 @@ def testResidual(self): self.assertEqual(2, self.fitcontribution.c.value) # The equation should evaluate to sin(x+2) x = self.profile.x - y = sin(x+2) + y = sin(x + 2) res = self.recipe.residual() - self.assertTrue( array_equal(y-self.profile.y, res) ) + self.assertTrue(array_equal(y - self.profile.y, res)) # Now try some restraints. We want c to be exactly zero. It should give # a penalty of (c-0)**2, which is 4 in this case @@ -181,7 +179,7 @@ def testResidual(self): self.recipe._ready = False res = self.recipe.residual() chi2 = 4 + dot(y - self.profile.y, y - self.profile.y) - self.assertAlmostEqual(chi2, dot(res, res) ) + self.assertAlmostEqual(chi2, dot(res, res)) # Clear the constraint and restore the value of c to 0. This should # give us chi2 = 0 again. @@ -189,7 +187,7 @@ def testResidual(self): self.fitcontribution.c.setValue(0) res = self.recipe.residual([self.recipe.cont.A.getValue()]) chi2 = 0 - self.assertAlmostEqual(chi2, dot(res, res) ) + self.assertAlmostEqual(chi2, dot(res, res)) # Remove the restraint and variable self.recipe.unrestrain(r1) @@ -197,15 +195,15 @@ def testResidual(self): self.recipe._ready = False res = self.recipe.residual() chi2 = 0 - self.assertAlmostEqual(chi2, dot(res, res) ) + self.assertAlmostEqual(chi2, dot(res, res)) # Add constraints at the fitcontribution level. self.fitcontribution.constrain(self.fitcontribution.c, "2*A") # This should evaluate to sin(x+2) x = self.profile.x - y = sin(x+2) + y = sin(x + 2) res = self.recipe.residual() - self.assertTrue( array_equal(y-self.profile.y, res) ) + self.assertTrue(array_equal(y - self.profile.y, res)) # Add a restraint at the fitcontribution level. r1 = self.fitcontribution.restrain(self.fitcontribution.c, 0, 0, 1) @@ -213,9 +211,9 @@ def testResidual(self): # The chi2 is the same as above, plus 4 res = self.recipe.residual() x = self.profile.x - y = sin(x+2) + y = sin(x + 2) chi2 = 4 + dot(y - self.profile.y, y - self.profile.y) - self.assertAlmostEqual(chi2, dot(res, res) ) + self.assertAlmostEqual(chi2, dot(res, res)) # Remove those self.fitcontribution.unrestrain(r1) @@ -224,7 +222,7 @@ def testResidual(self): self.fitcontribution.c.setValue(0) res = self.recipe.residual() chi2 = 0 - self.assertAlmostEqual(chi2, dot(res, res) ) + self.assertAlmostEqual(chi2, dot(res, res)) # Now try to use the observed profile inside of the equation # Set the equation equal to the data @@ -239,29 +237,29 @@ def testResidual(self): return - def testPrintFitHook(self): "check output from default PrintFitHook." self.recipe.addVar(self.fitcontribution.c) - self.recipe.restrain('c', lb=5) - pfh, = self.recipe.getFitHooks() + self.recipe.restrain("c", lb=5) + (pfh,) = self.recipe.getFitHooks() out = capturestdout(self.recipe.scalarResidual) - self.assertEqual('', out) + self.assertEqual("", out) pfh.verbose = 1 out = capturestdout(self.recipe.scalarResidual) self.assertTrue(out.strip().isdigit()) - self.assertFalse('\nRestraints:' in out) + self.assertFalse("\nRestraints:" in out) pfh.verbose = 2 out = capturestdout(self.recipe.scalarResidual) - self.assertTrue('\nResidual:' in out) - self.assertTrue('\nRestraints:' in out) - self.assertFalse('\nVariables' in out) + self.assertTrue("\nResidual:" in out) + self.assertTrue("\nRestraints:" in out) + self.assertFalse("\nVariables" in out) pfh.verbose = 3 out = capturestdout(self.recipe.scalarResidual) - self.assertTrue('\nVariables' in out) - self.assertTrue('c = ' in out) + self.assertTrue("\nVariables" in out) + self.assertTrue("c = " in out) return + # End of class TestFitRecipe # ---------------------------------------------------------------------------- diff --git a/src/diffpy/srfit/tests/testfitresults.py b/src/diffpy/srfit/tests/testfitresults.py index c5d6c9cc..18d65435 100644 --- a/src/diffpy/srfit/tests/testfitresults.py +++ b/src/diffpy/srfit/tests/testfitresults.py @@ -33,7 +33,7 @@ def setUp(self): self.Aval = 5.77619823e-01 self.sigval = -9.22758690e-01 - self.x0val = 6.12422115e+00 + self.x0val = 6.12422115e00 return def testInitializeFromFileName(self): @@ -52,7 +52,7 @@ def testInitializeFromFileObj(self): self.assertEqual(0, recipe.A.value) self.assertEqual(0, recipe.sig.value) self.assertEqual(0, recipe.x0.value) - infile = open(self.filename, 'r') + infile = open(self.filename, "r") initializeRecipe(recipe, infile) self.assertFalse(infile.closed) infile.close() @@ -61,13 +61,12 @@ def testInitializeFromFileObj(self): self.assertAlmostEqual(self.x0val, recipe.x0.value) return - def testInitializeFromString(self): recipe = self.recipe self.assertEqual(0, recipe.A.value) self.assertEqual(0, recipe.sig.value) self.assertEqual(0, recipe.x0.value) - infile = open(self.filename, 'r') + infile = open(self.filename, "r") resstr = infile.read() infile.close() initializeRecipe(recipe, resstr) @@ -76,6 +75,7 @@ def testInitializeFromString(self): self.assertAlmostEqual(self.x0val, recipe.x0.value) return + if __name__ == "__main__": unittest.main() diff --git a/src/diffpy/srfit/tests/testliterals.py b/src/diffpy/srfit/tests/testliterals.py index 7667be3e..99c1aa24 100644 --- a/src/diffpy/srfit/tests/testliterals.py +++ b/src/diffpy/srfit/tests/testliterals.py @@ -24,6 +24,7 @@ # ---------------------------------------------------------------------------- + class TestArgument(unittest.TestCase): def testInit(self): @@ -34,7 +35,6 @@ def testInit(self): self.assertTrue(None is a.name) return - def testIdentity(self): """Make sure an Argument is an Argument.""" a = literals.Argument() @@ -42,7 +42,6 @@ def testIdentity(self): self.assertTrue(isinstance(a, abcs.ArgumentABC)) return - def testValue(self): """Test value setting.""" @@ -59,16 +58,16 @@ def testValue(self): self.assertAlmostEqual(3.14, a.getValue()) return + # ---------------------------------------------------------------------------- + class TestCustomOperator(unittest.TestCase): def setUp(self): - self.op = literals.makeOperator( - name="add", symbol="+", operation=numpy.add, nin=2, nout=1) + self.op = literals.makeOperator(name="add", symbol="+", operation=numpy.add, nin=2, nout=1) return - def testInit(self): """Test that everthing initializes as expected.""" op = self.op @@ -80,7 +79,6 @@ def testInit(self): self.assertEqual([], op.args) return - def testIdentity(self): """Make sure an Argument is an Argument.""" op = self.op @@ -88,13 +86,12 @@ def testIdentity(self): self.assertTrue(isinstance(op, abcs.OperatorABC)) return - def testValue(self): """Test value.""" # Test addition and operations op = self.op - a = literals.Argument(value = 0) - b = literals.Argument(value = 0) + a = literals.Argument(value=0) + b = literals.Argument(value=0) op.addLiteral(a) op.addLiteral(b) @@ -113,7 +110,6 @@ def testValue(self): return - def testAddLiteral(self): """Test adding a literal to an operator node.""" op = self.op @@ -123,8 +119,8 @@ def testAddLiteral(self): self.assertEqual(op.getValue(), 1) # Test addition and operations - a = literals.Argument(name = "a", value = 0) - b = literals.Argument(name = "b", value = 0) + a = literals.Argument(name="a", value=0) + b = literals.Argument(name="b", value=0) op.addLiteral(a) self.assertRaises(ValueError, op.getValue) @@ -140,21 +136,21 @@ def testAddLiteral(self): # Test for self-references # Try to add self - op1 = literals.makeOperator(name="add", symbol="+", - operation=numpy.add, nin=2, nout=1) + op1 = literals.makeOperator(name="add", symbol="+", operation=numpy.add, nin=2, nout=1) op1.addLiteral(a) self.assertRaises(ValueError, op1.addLiteral, op1) # Try to add argument that contains self - op2 = literals.makeOperator( - name="sub", symbol="-", operation=numpy.subtract, nin=2, nout=1) + op2 = literals.makeOperator(name="sub", symbol="-", operation=numpy.subtract, nin=2, nout=1) op2.addLiteral(op1) self.assertRaises(ValueError, op1.addLiteral, op2) return + # ---------------------------------------------------------------------------- + class TestConvolutionOperator(unittest.TestCase): def testValue(self): @@ -169,10 +165,10 @@ def testValue(self): mu2 = 2.5 sig2 = 0.4 - g1 = exp(-0.5*((x-mu1)/sig1)**2) - a1 = literals.Argument(name = "g1", value = g1) - g2 = exp(-0.5*((x-mu2)/sig2)**2) - a2 = literals.Argument(name = "g2", value = g2) + g1 = exp(-0.5 * ((x - mu1) / sig1) ** 2) + a1 = literals.Argument(name="g1", value=g1) + g2 = exp(-0.5 * ((x - mu2) / sig2) ** 2) + a2 = literals.Argument(name="g2", value=g2) op = literals.ConvolutionOperator() op.addLiteral(a1) @@ -181,24 +177,25 @@ def testValue(self): g3c = op.value mu3 = mu1 - sig3 = (sig1**2 + sig2**2)**0.5 - g3 = exp(-0.5*((x-mu3)/sig3)**2) - g3 *= sum(g1)/sum(g3) + sig3 = (sig1**2 + sig2**2) ** 0.5 + g3 = exp(-0.5 * ((x - mu3) / sig3) ** 2) + g3 *= sum(g1) / sum(g3) self.assertAlmostEqual(sum(g3c), sum(g3)) - self.assertAlmostEqual(0, sum((g3-g3c)**2)) + self.assertAlmostEqual(0, sum((g3 - g3c) ** 2)) return + # ---------------------------------------------------------------------------- + class TestArrayOperator(unittest.TestCase): def test_value(self): - """Check ArrayOperator.value. - """ - x = literals.Argument('x', 1.0) - y = literals.Argument('y', 2.0) - z = literals.Argument('z', 3.0) + """Check ArrayOperator.value.""" + x = literals.Argument("x", 1.0) + y = literals.Argument("y", 2.0) + z = literals.Argument("z", 3.0) # check empty array op = literals.ArrayOperator() self.assertEqual(0, len(op.value)) @@ -213,6 +210,7 @@ def test_value(self): self.assertTrue(numpy.array_equal([1, 2, 7], op.value)) return + # ---------------------------------------------------------------------------- if __name__ == "__main__": diff --git a/src/diffpy/srfit/tests/testobjcrystparset.py b/src/diffpy/srfit/tests/testobjcrystparset.py index 34cc2aa8..a3b236c0 100644 --- a/src/diffpy/srfit/tests/testobjcrystparset.py +++ b/src/diffpy/srfit/tests/testobjcrystparset.py @@ -19,7 +19,7 @@ import numpy -from diffpy.srfit.tests.utils import has_pyobjcryst, _msg_nopyobjcryst +from diffpy.srfit.tests.utils import _msg_nopyobjcryst, has_pyobjcryst # Global variables to be assigned in setUp ObjCrystCrystalParSet = spacegroups = None @@ -89,6 +89,7 @@ -2.279809890 -2.580456608 -0.724000000 """ + def makeC60(): """Make a crystal containing the C60 molecule using pyobjcryst.""" pi = numpy.pi @@ -99,28 +100,32 @@ def makeC60(): c.AddScatterer(m) sp = ScatteringPowerAtom("C", "C") - sp.SetBiso(8*pi*pi*0.003) - #c.AddScatteringPower(sp) + sp.SetBiso(8 * pi * pi * 0.003) + # c.AddScatteringPower(sp) for i, l in enumerate(c60xyz.strip().splitlines()): x, y, z = map(float, l.split()) - m.AddAtom(x, y, z, sp, "C%i"%i) + m.AddAtom(x, y, z, sp, "C%i" % i) return c + # ---------------------------------------------------------------------------- + @unittest.skipUnless(has_pyobjcryst, _msg_nopyobjcryst) class TestParameterAdapter(unittest.TestCase): def setUp(self): global ObjCrystCrystalParSet, Crystal, Atom, Molecule global ScatteringPowerAtom - from diffpy.srfit.structure.objcrystparset import ObjCrystCrystalParSet - from pyobjcryst.crystal import Crystal from pyobjcryst.atom import Atom + from pyobjcryst.crystal import Crystal from pyobjcryst.molecule import Molecule from pyobjcryst.scatteringpower import ScatteringPowerAtom + + from diffpy.srfit.structure.objcrystparset import ObjCrystCrystalParSet + self.occryst = makeC60() self.ocmol = self.occryst.GetScatterer("c60") return @@ -130,7 +135,6 @@ def tearDown(self): del self.ocmol return - def testObjCrystParSet(self): """Test the structure conversion.""" @@ -181,7 +185,6 @@ def _testMolecule(): self.assertAlmostEqual(ocsp.Biso, a.Biso.getValue()) return - _testCrystal() _testMolecule() @@ -196,17 +199,16 @@ def _testMolecule(): _testMolecule() ## Now change values from the srfit StructureParSet - cryst.c60.C44.x.setValue( 1.1 ) - cryst.c60.C44.occ.setValue( 1.1 ) - cryst.c60.C44.Biso.setValue( 1.1 ) - cryst.c60.q3.setValue( 1.1 ) + cryst.c60.C44.x.setValue(1.1) + cryst.c60.C44.occ.setValue(1.1) + cryst.c60.C44.Biso.setValue(1.1) + cryst.c60.q3.setValue(1.1) cryst.a.setValue(1.1) _testCrystal() _testMolecule() return - def testImplicitBondLengthRestraints(self): """Test the structure with implicit bond lengths.""" occryst = self.occryst @@ -233,7 +235,6 @@ def testImplicitBondLengthRestraints(self): return - def testImplicitBondAngleRestraints(self): """Test the structure with implicit bond angles.""" occryst = self.occryst @@ -260,17 +261,14 @@ def testImplicitBondAngleRestraints(self): return - def testImplicitDihedralAngleRestraints(self): """Test the structure with implicit dihedral angles.""" occryst = self.occryst ocmol = self.ocmol # Add some bond angles to the molecule - ocmol.AddDihedralAngle(ocmol[0], ocmol[5], ocmol[8], ocmol[41], 1.1, - 0.1, 0.1) - ocmol.AddDihedralAngle(ocmol[0], ocmol[7], ocmol[44], ocmol[2], 1.3, - 0.1, 0.1) + ocmol.AddDihedralAngle(ocmol[0], ocmol[5], ocmol[8], ocmol[41], 1.1, 0.1, 0.1) + ocmol.AddDihedralAngle(ocmol[0], ocmol[7], ocmol[44], ocmol[2], 1.3, 0.1, 0.1) # make our crystal cryst = ObjCrystCrystalParSet("bucky", occryst) @@ -289,13 +287,11 @@ def testImplicitDihedralAngleRestraints(self): return - def testImplicitStretchModes(self): """Test the molecule with implicit stretch modes.""" # Not sure how to make this happen. pass - def testExplicitBondLengthRestraints(self): """Test the structure with explicit bond lengths.""" occryst = self.occryst @@ -321,7 +317,6 @@ def testExplicitBondLengthRestraints(self): return - def testExplicitBondAngleRestraints(self): """Test the structure with explicit bond angles. @@ -337,10 +332,8 @@ def testExplicitBondAngleRestraints(self): m = cryst.c60 # restrain some bond angles - res0 = m.restrainBondAngle(m.atoms[0], m.atoms[5], m.atoms[8], 3.3, - 0.1, 0.1) - res1 = m.restrainBondAngle(m.atoms[0], m.atoms[7], m.atoms[44], 3.3, - 0.1, 0.1) + res0 = m.restrainBondAngle(m.atoms[0], m.atoms[5], m.atoms[8], 3.3, 0.1, 0.1) + res1 = m.restrainBondAngle(m.atoms[0], m.atoms[7], m.atoms[44], 3.3, 0.1, 0.1) # make sure that we have some restraints in the molecule self.assertTrue(2, len(m._restraints)) @@ -353,7 +346,6 @@ def testExplicitBondAngleRestraints(self): return - def testExplicitDihedralAngleRestraints(self): """Test the structure with explicit dihedral angles.""" occryst = self.occryst @@ -364,11 +356,8 @@ def testExplicitDihedralAngleRestraints(self): m = cryst.c60 # Restrain some dihedral angles. - res0 = m.restrainDihedralAngle(m.atoms[0], m.atoms[5], m.atoms[8], - m.atoms[41], 1.1, 0.1, 0.1) - res1 = m.restrainDihedralAngle(m.atoms[0], m.atoms[7], m.atoms[44], - m.atoms[2], 1.1, 0.1, 0.1) - + res0 = m.restrainDihedralAngle(m.atoms[0], m.atoms[5], m.atoms[8], m.atoms[41], 1.1, 0.1, 0.1) + res1 = m.restrainDihedralAngle(m.atoms[0], m.atoms[7], m.atoms[44], m.atoms[2], 1.1, 0.1, 0.1) # make sure that we have some restraints in the molecule self.assertTrue(2, len(m._restraints)) @@ -381,7 +370,6 @@ def testExplicitDihedralAngleRestraints(self): return - def testExplicitBondLengthParameter(self): """Test adding bond length parameters to the molecule.""" occryst = self.occryst @@ -401,48 +389,45 @@ def testExplicitBondLengthParameter(self): xyz0 = numpy.array([a0.x.getValue(), a0.y.getValue(), a0.z.getValue()]) xyz7 = numpy.array([a7.x.getValue(), a7.y.getValue(), a7.z.getValue()]) - xyz20 = numpy.array([a20.x.getValue(), a20.y.getValue(), - a20.z.getValue()]) + xyz20 = numpy.array([a20.x.getValue(), a20.y.getValue(), a20.z.getValue()]) dd = xyz0 - xyz7 - d0 = numpy.dot(dd, dd)**0.5 + d0 = numpy.dot(dd, dd) ** 0.5 self.assertAlmostEqual(d0, p1.getValue(), 6) # Record the unit direction of change for later - u = dd/d0 + u = dd / d0 # Change the value scale = 1.05 - p1.setValue(scale*d0) + p1.setValue(scale * d0) # Verify that it has changed. - self.assertAlmostEqual(scale*d0, p1.getValue()) + self.assertAlmostEqual(scale * d0, p1.getValue()) xyz0a = numpy.array([a0.x.getValue(), a0.y.getValue(), a0.z.getValue()]) xyz7a = numpy.array([a7.x.getValue(), a7.y.getValue(), a7.z.getValue()]) - xyz20a = numpy.array([a20.x.getValue(), a20.y.getValue(), - a20.z.getValue()]) + xyz20a = numpy.array([a20.x.getValue(), a20.y.getValue(), a20.z.getValue()]) dda = xyz0a - xyz7a - d1 = numpy.dot(dda, dda)**0.5 + d1 = numpy.dot(dda, dda) ** 0.5 - self.assertAlmostEqual(scale*d0, d1) + self.assertAlmostEqual(scale * d0, d1) # Verify that only the second and third atoms have moved. self.assertTrue(numpy.array_equal(xyz0, xyz0a)) - xyz7calc = xyz7 + (1-scale)*d0*u + xyz7calc = xyz7 + (1 - scale) * d0 * u for i in range(3): self.assertAlmostEqual(xyz7a[i], xyz7calc[i], 6) - xyz20calc = xyz20 + (1-scale)*d0*u + xyz20calc = xyz20 + (1 - scale) * d0 * u for i in range(3): self.assertAlmostEqual(xyz20a[i], xyz20calc[i], 6) return - def testExplicitBondAngleParameter(self): """Test adding bond angle parameters to the molecule.""" occryst = self.occryst @@ -458,18 +443,15 @@ def testExplicitBondAngleParameter(self): xyz0 = numpy.array([a0.x.getValue(), a0.y.getValue(), a0.z.getValue()]) xyz7 = numpy.array([a7.x.getValue(), a7.y.getValue(), a7.z.getValue()]) - xyz20 = numpy.array([a20.x.getValue(), a20.y.getValue(), - a20.z.getValue()]) - xyz25 = numpy.array([a25.x.getValue(), a25.y.getValue(), - a25.z.getValue()]) - + xyz20 = numpy.array([a20.x.getValue(), a20.y.getValue(), a20.z.getValue()]) + xyz25 = numpy.array([a25.x.getValue(), a25.y.getValue(), a25.z.getValue()]) v1 = xyz7 - xyz0 - d1 = numpy.dot(v1, v1)**0.5 + d1 = numpy.dot(v1, v1) ** 0.5 v2 = xyz7 - xyz20 - d2 = numpy.dot(v2, v2)**0.5 + d2 = numpy.dot(v2, v2) ** 0.5 - angle0 = numpy.arccos(numpy.dot(v1, v2)/(d1*d2)) + angle0 = numpy.arccos(numpy.dot(v1, v2) / (d1 * d2)) # Add a parameter p1 = m.addBondAngleParameter("C0720", a0, a7, a20) @@ -480,26 +462,24 @@ def testExplicitBondAngleParameter(self): # Change the value scale = 1.05 - p1.setValue(scale*angle0) + p1.setValue(scale * angle0) # Verify that it has changed. - self.assertAlmostEqual(scale*angle0, p1.getValue(), 6) + self.assertAlmostEqual(scale * angle0, p1.getValue(), 6) xyz0a = numpy.array([a0.x.getValue(), a0.y.getValue(), a0.z.getValue()]) xyz7a = numpy.array([a7.x.getValue(), a7.y.getValue(), a7.z.getValue()]) - xyz20a = numpy.array([a20.x.getValue(), a20.y.getValue(), - a20.z.getValue()]) - xyz25a = numpy.array([a25.x.getValue(), a25.y.getValue(), - a25.z.getValue()]) + xyz20a = numpy.array([a20.x.getValue(), a20.y.getValue(), a20.z.getValue()]) + xyz25a = numpy.array([a25.x.getValue(), a25.y.getValue(), a25.z.getValue()]) v1a = xyz7a - xyz0a - d1a = numpy.dot(v1a, v1a)**0.5 + d1a = numpy.dot(v1a, v1a) ** 0.5 v2a = xyz7a - xyz20a - d2a = numpy.dot(v2a, v2a)**0.5 + d2a = numpy.dot(v2a, v2a) ** 0.5 - angle1 = numpy.arccos(numpy.dot(v1a, v2a)/(d1a*d2a)) + angle1 = numpy.arccos(numpy.dot(v1a, v2a) / (d1a * d2a)) - self.assertAlmostEqual(scale*angle0, angle1) + self.assertAlmostEqual(scale * angle0, angle1) # Verify that only the last two atoms have moved. @@ -510,7 +490,6 @@ def testExplicitBondAngleParameter(self): return - def testExplicitDihedralAngleParameter(self): """Test adding dihedral angle parameters to the molecule.""" occryst = self.occryst @@ -527,13 +506,9 @@ def testExplicitDihedralAngleParameter(self): xyz0 = numpy.array([a0.x.getValue(), a0.y.getValue(), a0.z.getValue()]) xyz7 = numpy.array([a7.x.getValue(), a7.y.getValue(), a7.z.getValue()]) - xyz20 = numpy.array([a20.x.getValue(), a20.y.getValue(), - a20.z.getValue()]) - xyz25 = numpy.array([a25.x.getValue(), a25.y.getValue(), - a25.z.getValue()]) - xyz33 = numpy.array([a33.x.getValue(), a33.y.getValue(), - a33.z.getValue()]) - + xyz20 = numpy.array([a20.x.getValue(), a20.y.getValue(), a20.z.getValue()]) + xyz25 = numpy.array([a25.x.getValue(), a25.y.getValue(), a25.z.getValue()]) + xyz33 = numpy.array([a33.x.getValue(), a33.y.getValue(), a33.z.getValue()]) v12 = xyz0 - xyz7 v23 = xyz7 - xyz20 @@ -541,9 +516,9 @@ def testExplicitDihedralAngleParameter(self): v123 = numpy.cross(v12, v23) v234 = numpy.cross(v23, v34) - d123 = numpy.dot(v123, v123)**0.5 - d234 = numpy.dot(v234, v234)**0.5 - angle0 = -numpy.arccos(numpy.dot(v123, v234)/(d123*d234)) + d123 = numpy.dot(v123, v123) ** 0.5 + d234 = numpy.dot(v234, v234) ** 0.5 + angle0 = -numpy.arccos(numpy.dot(v123, v234) / (d123 * d234)) # Add a parameter p1 = m.addDihedralAngleParameter("C072025", a0, a7, a20, a25) @@ -554,19 +529,16 @@ def testExplicitDihedralAngleParameter(self): # Change the value scale = 1.05 - p1.setValue(scale*angle0) + p1.setValue(scale * angle0) # Verify that it has changed. - self.assertAlmostEqual(scale*angle0, p1.getValue(), 6) + self.assertAlmostEqual(scale * angle0, p1.getValue(), 6) xyz0a = numpy.array([a0.x.getValue(), a0.y.getValue(), a0.z.getValue()]) xyz7a = numpy.array([a7.x.getValue(), a7.y.getValue(), a7.z.getValue()]) - xyz20a = numpy.array([a20.x.getValue(), a20.y.getValue(), - a20.z.getValue()]) - xyz25a = numpy.array([a25.x.getValue(), a25.y.getValue(), - a25.z.getValue()]) - xyz33a = numpy.array([a33.x.getValue(), a33.y.getValue(), - a33.z.getValue()]) + xyz20a = numpy.array([a20.x.getValue(), a20.y.getValue(), a20.z.getValue()]) + xyz25a = numpy.array([a25.x.getValue(), a25.y.getValue(), a25.z.getValue()]) + xyz33a = numpy.array([a33.x.getValue(), a33.y.getValue(), a33.z.getValue()]) v12a = xyz0a - xyz7a v23a = xyz7a - xyz20a @@ -574,11 +546,11 @@ def testExplicitDihedralAngleParameter(self): v123a = numpy.cross(v12a, v23a) v234a = numpy.cross(v23a, v34a) - d123a = numpy.dot(v123a, v123a)**0.5 - d234a = numpy.dot(v234a, v234a)**0.5 - angle1 = -numpy.arccos(numpy.dot(v123a, v234a)/(d123a*d234a)) + d123a = numpy.dot(v123a, v123a) ** 0.5 + d234a = numpy.dot(v234a, v234a) ** 0.5 + angle1 = -numpy.arccos(numpy.dot(v123a, v234a) / (d123a * d234a)) - self.assertAlmostEqual(scale*angle0, angle1) + self.assertAlmostEqual(scale * angle0, angle1) # Verify that only the last two atoms have moved. @@ -590,10 +562,12 @@ def testExplicitDihedralAngleParameter(self): return + # End of class TestParameterAdapter # ---------------------------------------------------------------------------- + @unittest.skipUnless(has_pyobjcryst, _msg_nopyobjcryst) class TestCreateSpaceGroup(unittest.TestCase): """Test space group creation from pyobjcryst structures. @@ -612,6 +586,7 @@ def setUp(self): def getObjCrystParSetSpaceGroup(sg): """Make an ObjCrystCrystalParSet with the proper space group.""" from pyobjcryst.spacegroup import SpaceGroup + sgobjcryst = SpaceGroup(sg.short_name) sgnew = ObjCrystCrystalParSet._createSpaceGroup(sgobjcryst) return sgnew @@ -619,7 +594,7 @@ def getObjCrystParSetSpaceGroup(sg): @staticmethod def hashDiffPySpaceGroup(sg): lines = [str(sg.number % 1000)] + sorted(map(str, sg.iter_symops())) - s = '\n'.join(lines) + s = "\n".join(lines) return s def sgsEquivalent(self, sg1, sg2): @@ -640,7 +615,7 @@ def xtestCreateSpaceGroup(self): for smbls in sgtbx.space_group_symbol_iterator(): shn = smbls.hermann_mauguin() - short_name = shn.replace(' ', '') + short_name = shn.replace(" ", "") if spacegroups.IsSpaceGroupIdentifier(short_name): sg = spacegroups.GetSpaceGroup(shn) sgnew = self.getObjCrystParSetSpaceGroup(sg) @@ -648,6 +623,7 @@ def xtestCreateSpaceGroup(self): self.assertTrue(self.sgsEquivalent(sg, sgnew)) return + # End of class TestCreateSpaceGroup if __name__ == "__main__": diff --git a/src/diffpy/srfit/tests/testparameter.py b/src/diffpy/srfit/tests/testparameter.py index 76eaee3b..d3baea2c 100644 --- a/src/diffpy/srfit/tests/testparameter.py +++ b/src/diffpy/srfit/tests/testparameter.py @@ -17,8 +17,7 @@ import unittest -from diffpy.srfit.fitbase.parameter import Parameter -from diffpy.srfit.fitbase.parameter import ParameterAdapter, ParameterProxy +from diffpy.srfit.fitbase.parameter import Parameter, ParameterAdapter, ParameterProxy class TestParameter(unittest.TestCase): @@ -32,16 +31,17 @@ def testSetValue(self): # 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 ) + self.assertTrue(l.getValue() is x) + self.assertTrue(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 ) + self.assertTrue(l.getValue() is y) + self.assertTrue(l.value is y) # Back to scalar l.setValue(1.01) @@ -49,6 +49,7 @@ def testSetValue(self): self.assertAlmostEqual(1.01, l.value) return + class TestParameterProxy(unittest.TestCase): def testProxy(self): @@ -73,6 +74,7 @@ def testProxy(self): return + class TestParameterAdapter(unittest.TestCase): def testWrapper(self): @@ -83,8 +85,7 @@ def testWrapper(self): l = Parameter("l", 3.14) # Try Accessor adaptation - la = ParameterAdapter("l", l, getter = Parameter.getValue, setter = - Parameter.setValue) + la = ParameterAdapter("l", l, getter=Parameter.getValue, setter=Parameter.setValue) self.assertEqual(l.name, la.name) self.assertEqual(l.getValue(), la.getValue()) @@ -98,7 +99,7 @@ def testWrapper(self): self.assertEqual(l.getValue(), la.getValue()) # Try Attribute adaptation - la = ParameterAdapter("l", l, attr = "value") + la = ParameterAdapter("l", l, attr="value") self.assertEqual(l.name, la.name) self.assertEqual("value", la.attr) diff --git a/src/diffpy/srfit/tests/testpdf.py b/src/diffpy/srfit/tests/testpdf.py index 426b7d81..793179c4 100644 --- a/src/diffpy/srfit/tests/testpdf.py +++ b/src/diffpy/srfit/tests/testpdf.py @@ -15,26 +15,24 @@ """Tests for pdf package.""" -import unittest -import pickle import io +import pickle +import unittest import numpy -from diffpy.srfit.tests.utils import datafile -from diffpy.srfit.tests.utils import has_srreal, _msg_nosrreal -from diffpy.srfit.tests.utils import has_structure, _msg_nostructure -from diffpy.srfit.pdf import PDFGenerator, PDFParser, PDFContribution from diffpy.srfit.exceptions import SrFitError +from diffpy.srfit.pdf import PDFContribution, PDFGenerator, PDFParser +from diffpy.srfit.tests.utils import _msg_nosrreal, _msg_nostructure, datafile, has_srreal, has_structure # ---------------------------------------------------------------------------- + class TestPDFParset(unittest.TestCase): def setUp(self): return - def testParser1(self): data = datafile("ni-q27r100-neutron.gr") parser = PDFParser() @@ -42,16 +40,16 @@ def testParser1(self): meta = parser._meta - self.assertEqual(data, meta['filename']) - self.assertEqual(1, meta['nbanks']) - self.assertEqual('N', meta['stype']) - self.assertEqual(27, meta['qmax']) - self.assertEqual(300, meta.get('temperature')) - self.assertEqual(None, meta.get('qdamp')) - self.assertEqual(None, meta.get('qbroad')) - self.assertEqual(None, meta.get('spdiameter')) - self.assertEqual(None, meta.get('scale')) - self.assertEqual(None, meta.get('doping')) + self.assertEqual(data, meta["filename"]) + self.assertEqual(1, meta["nbanks"]) + self.assertEqual("N", meta["stype"]) + self.assertEqual(27, meta["qmax"]) + self.assertEqual(300, meta.get("temperature")) + self.assertEqual(None, meta.get("qdamp")) + self.assertEqual(None, meta.get("qbroad")) + self.assertEqual(None, meta.get("spdiameter")) + self.assertEqual(None, meta.get("scale")) + self.assertEqual(None, meta.get("doping")) x, y, dx, dy = parser.getData() self.assertTrue(dx is None) @@ -62,15 +60,13 @@ def testParser1(self): res = numpy.dot(diff, diff) self.assertAlmostEqual(0, res) - testy = numpy.array([1.144, 2.258, 3.312, 4.279, 5.135, 5.862, 6.445, - 6.875, 7.150, 7.272]) + testy = numpy.array([1.144, 2.258, 3.312, 4.279, 5.135, 5.862, 6.445, 6.875, 7.150, 7.272]) diff = testy - y[:10] res = numpy.dot(diff, diff) self.assertAlmostEqual(0, res) return - def testParser2(self): data = datafile("si-q27r60-xray.gr") parser = PDFParser() @@ -78,16 +74,16 @@ def testParser2(self): meta = parser._meta - self.assertEqual(data, meta['filename']) - self.assertEqual(1, meta['nbanks']) - self.assertEqual('X', meta['stype']) - self.assertEqual(27, meta['qmax']) - self.assertEqual(300, meta.get('temperature')) - self.assertEqual(None, meta.get('qdamp')) - self.assertEqual(None, meta.get('qbroad')) - self.assertEqual(None, meta.get('spdiameter')) - self.assertEqual(None, meta.get('scale')) - self.assertEqual(None, meta.get('doping')) + self.assertEqual(data, meta["filename"]) + self.assertEqual(1, meta["nbanks"]) + self.assertEqual("X", meta["stype"]) + self.assertEqual(27, meta["qmax"]) + self.assertEqual(300, meta.get("temperature")) + self.assertEqual(None, meta.get("qdamp")) + self.assertEqual(None, meta.get("qbroad")) + self.assertEqual(None, meta.get("spdiameter")) + self.assertEqual(None, meta.get("scale")) + self.assertEqual(None, meta.get("doping")) x, y, dx, dy = parser.getData() testx = numpy.linspace(0.01, 60, 5999, endpoint=False) @@ -95,15 +91,38 @@ def testParser2(self): res = numpy.dot(diff, diff) self.assertAlmostEqual(0, res) - testy = numpy.array([0.1105784, 0.2199684, 0.3270088, 0.4305913, - 0.5296853, 0.6233606, 0.7108060, 0.7913456, 0.8644501, 0.9297440]) + testy = numpy.array( + [ + 0.1105784, + 0.2199684, + 0.3270088, + 0.4305913, + 0.5296853, + 0.6233606, + 0.7108060, + 0.7913456, + 0.8644501, + 0.9297440, + ] + ) diff = testy - y[:10] res = numpy.dot(diff, diff) self.assertAlmostEqual(0, res) - testdy = numpy.array([0.001802192, 0.003521449, 0.005079115, - 0.006404892, 0.007440527, 0.008142955, 0.008486813, 0.008466340, - 0.008096858, 0.007416456]) + testdy = numpy.array( + [ + 0.001802192, + 0.003521449, + 0.005079115, + 0.006404892, + 0.007440527, + 0.008142955, + 0.008486813, + 0.008466340, + 0.008096858, + 0.007416456, + ] + ) diff = testdy - dy[:10] res = numpy.dot(diff, diff) self.assertAlmostEqual(0, res) @@ -111,10 +130,12 @@ def testParser2(self): self.assertTrue(dx is None) return + # End of class TestPDFParset # ---------------------------------------------------------------------------- + @unittest.skipUnless(has_srreal, _msg_nosrreal) @unittest.skipUnless(has_structure, _msg_nostructure) class TestPDFGenerator(unittest.TestCase): @@ -123,15 +144,15 @@ def setUp(self): self.gen = PDFGenerator() return - def testGenerator(self): qmax = 27.0 gen = self.gen - gen.setScatteringType('N') - self.assertEqual('N', gen.getScatteringType()) + gen.setScatteringType("N") + self.assertEqual("N", gen.getScatteringType()) gen.setQmax(qmax) self.assertAlmostEqual(qmax, gen.getQmax()) from diffpy.structure import PDFFitStructure + stru = PDFFitStructure() ciffile = datafile("ni.cif") stru.read(ciffile) @@ -158,12 +179,13 @@ def testGenerator(self): # output, we just have to make sure we can calculate from the # PDFGenerator interface. from diffpy.srreal.pdfcalculator import PDFCalculator + calc = PDFCalculator() calc.rstep = r[1] - r[0] calc.rmin = r[0] calc.rmax = r[-1] + 0.5 * calc.rstep calc.qmax = qmax - calc.setScatteringFactorTableByType('N') + calc.setScatteringFactorTableByType("N") calc.eval(stru) yref = calc.pdf @@ -172,10 +194,8 @@ def testGenerator(self): self.assertAlmostEqual(0, res) return - def test_setQmin(self): - """Verify qmin is propagated to the calculator object. - """ + """Verify qmin is propagated to the calculator object.""" gen = self.gen self.assertEqual(0, gen.getQmin()) self.assertEqual(0, gen._calc.qmin) @@ -184,37 +204,37 @@ def test_setQmin(self): self.assertEqual(0.93, gen._calc.qmin) return + # End of class TestPDFGenerator # ---------------------------------------------------------------------------- + @unittest.skipUnless(has_srreal, _msg_nosrreal) @unittest.skipUnless(has_structure, _msg_nostructure) class TestPDFContribution(unittest.TestCase): def setUp(self): - self.pc = PDFContribution('pdf') + self.pc = PDFContribution("pdf") return - def test_setQmax(self): - """check PDFContribution.setQmax() - """ + """check PDFContribution.setQmax()""" from diffpy.structure import Structure + pc = self.pc pc.setQmax(21) - pc.addStructure('empty', Structure()) + pc.addStructure("empty", Structure()) self.assertEqual(21, pc.empty.getQmax()) pc.setQmax(22) self.assertEqual(22, pc.getQmax()) self.assertEqual(22, pc.empty.getQmax()) return - def test_getQmax(self): - """check PDFContribution.getQmax() - """ + """check PDFContribution.getQmax()""" from diffpy.structure import Structure + # cover all code branches in PDFContribution._getMetaValue # (1) contribution metadata pc1 = self.pc @@ -222,54 +242,56 @@ def test_getQmax(self): pc1.setQmax(17) self.assertEqual(17, pc1.getQmax()) # (2) contribution metadata - pc2 = PDFContribution('pdf') - pc2.addStructure('empty', Structure()) + pc2 = PDFContribution("pdf") + pc2.addStructure("empty", Structure()) pc2.empty.setQmax(18) self.assertEqual(18, pc2.getQmax()) # (3) profile metadata - pc3 = PDFContribution('pdf') - pc3.profile.meta['qmax'] = 19 + pc3 = PDFContribution("pdf") + pc3.profile.meta["qmax"] = 19 self.assertEqual(19, pc3.getQmax()) return - def test_savetxt(self): "check PDFContribution.savetxt()" from diffpy.structure import Structure + pc = self.pc pc.loadData(datafile("si-q27r60-xray.gr")) pc.setCalculationRange(0, 10) - pc.addStructure('empty', Structure()) + pc.addStructure("empty", Structure()) fp = io.BytesIO() self.assertRaises(SrFitError, pc.savetxt, fp) pc.evaluate() pc.savetxt(fp) txt = fp.getvalue().decode() - nlines = len(txt.strip().split('\n')) + nlines = len(txt.strip().split("\n")) self.assertEqual(1001, nlines) return - def test_pickling(self): "validate PDFContribution.residual() after pickling." from itertools import chain + from diffpy.structure import loadStructure + pc = self.pc pc.loadData(datafile("ni-q27r100-neutron.gr")) ni = loadStructure(datafile("ni.cif")) ni.Uisoequiv = 0.003 - pc.addStructure('ni', ni) + pc.addStructure("ni", ni) pc.setCalculationRange(0, 10) pc2 = pickle.loads(pickle.dumps(pc)) res0 = pc.residual() self.assertTrue(numpy.array_equal(res0, pc2.residual())) - for p in chain(pc.iterPars('Uiso'), pc2.iterPars('Uiso')): + for p in chain(pc.iterPars("Uiso"), pc2.iterPars("Uiso")): p.value = 0.004 res1 = pc.residual() self.assertFalse(numpy.allclose(res0, res1)) self.assertTrue(numpy.array_equal(res1, pc2.residual())) return + # End of class TestPDFContribution # ---------------------------------------------------------------------------- diff --git a/src/diffpy/srfit/tests/testprofile.py b/src/diffpy/srfit/tests/testprofile.py index 78f221d9..428fcac2 100644 --- a/src/diffpy/srfit/tests/testprofile.py +++ b/src/diffpy/srfit/tests/testprofile.py @@ -15,14 +15,14 @@ """Tests for refinableobj module.""" -import unittest -import re import io +import re +import unittest -from numpy import array, arange, array_equal, ones_like, allclose +from numpy import allclose, arange, array, array_equal, ones_like -from diffpy.srfit.fitbase.profile import Profile from diffpy.srfit.exceptions import SrFitError +from diffpy.srfit.fitbase.profile import Profile from diffpy.srfit.tests.utils import datafile @@ -55,9 +55,9 @@ def testSetObservedProfile(self): prof = self.profile prof.setObservedProfile(x, y, dy) - self.assertTrue( array_equal(x, prof.xobs) ) - self.assertTrue( array_equal(y, prof.yobs) ) - self.assertTrue( array_equal(dy, prof.dyobs) ) + self.assertTrue(array_equal(x, prof.xobs)) + self.assertTrue(array_equal(y, prof.yobs)) + self.assertTrue(array_equal(dy, prof.dyobs)) # Make a profile with undefined dy x = arange(0, 10, 0.1) @@ -66,18 +66,17 @@ def testSetObservedProfile(self): self.profile.setObservedProfile(x, y, dy) - self.assertTrue( array_equal(x, prof.xobs) ) - self.assertTrue( array_equal(y, prof.yobs) ) - self.assertTrue( array_equal(ones_like(prof.xobs), prof.dyobs)) + self.assertTrue(array_equal(x, prof.xobs)) + self.assertTrue(array_equal(y, prof.yobs)) + self.assertTrue(array_equal(ones_like(prof.xobs), prof.dyobs)) # Get the ranged profile to make sure its the same - self.assertTrue( array_equal(x, prof.x) ) - self.assertTrue( array_equal(y, prof.y) ) - self.assertTrue( array_equal(ones_like(prof.xobs), prof.dy)) + self.assertTrue(array_equal(x, prof.x)) + self.assertTrue(array_equal(y, prof.y)) + self.assertTrue(array_equal(ones_like(prof.xobs), prof.dy)) return - def testSetCalculationRange(self): """Test the setCalculationRange method.""" x = arange(2, 9.6, 0.5) @@ -110,26 +109,24 @@ def testSetCalculationRange(self): self.assertTrue(array_equal(y, prof.y)) self.assertTrue(array_equal(dy, prof.dy)) # Test xmin > xmax - self.assertRaises(ValueError, prof.setCalculationRange, - xmin=10, xmax=3) + self.assertRaises(ValueError, prof.setCalculationRange, xmin=10, xmax=3) # Test xmax - xmin < dx - self.assertRaises(ValueError, prof.setCalculationRange, - xmin=3, xmax=3.9, dx=1.0) + self.assertRaises(ValueError, prof.setCalculationRange, xmin=3, xmax=3.9, dx=1.0) # Test dx <= 0 self.assertRaises(ValueError, prof.setCalculationRange, dx=0) self.assertRaises(ValueError, prof.setCalculationRange, dx=-0.000001) # using string other than 'obs' - self.assertRaises(ValueError, prof.setCalculationRange, xmin='oobs') - self.assertRaises(ValueError, prof.setCalculationRange, xmax='oobs') - self.assertRaises(ValueError, prof.setCalculationRange, dx='oobs') + self.assertRaises(ValueError, prof.setCalculationRange, xmin="oobs") + self.assertRaises(ValueError, prof.setCalculationRange, xmax="oobs") + self.assertRaises(ValueError, prof.setCalculationRange, dx="oobs") # This should be alright prof.setCalculationRange(3, 5) - prof.setCalculationRange(xmin='obs', xmax=7, dx=0.001) + prof.setCalculationRange(xmin="obs", xmax=7, dx=0.001) self.assertEqual(5001, len(prof.x)) self.assertEqual(len(prof.x), len(prof.y)) self.assertEqual(len(prof.x), len(prof.dy)) # Test an internal bound - prof.setCalculationRange(4, 7, dx='obs') + prof.setCalculationRange(4, 7, dx="obs") self.assertTrue(array_equal(prof.x, arange(4, 7.1, 0.5))) self.assertTrue(array_equal(prof.y, arange(4, 7.1, 0.5))) self.assertTrue(array_equal(prof.y, arange(4, 7.1, 0.5))) @@ -158,7 +155,6 @@ def testSetCalculationRange(self): self.assertTrue(array_equal(prof.x, arange(4.5, 6.1, 0.5))) return - def testSetCalculationPoints(self): """Test the setCalculationPoints method.""" prof = self.profile @@ -170,11 +166,11 @@ def testSetCalculationPoints(self): # Test without data xcalc = arange(3, 12.2, 0.2) prof.setCalculationPoints(xcalc) - self.assertTrue( array_equal(xcalc, prof.x) ) + self.assertTrue(array_equal(xcalc, prof.x)) # Add the data. This should change the bounds of the calculation array. prof.setObservedProfile(x, y, dy) - self.assertTrue( array_equal(arange(3, 10.1, 0.2), prof.x ) ) + self.assertTrue(array_equal(arange(3, 10.1, 0.2), prof.x)) return @@ -190,17 +186,17 @@ def _test(p): self.assertAlmostEqual(1.802192e-3, p.dy[0]) # Test normal load - prof.loadtxt(data, usecols=(0,1,3)) + prof.loadtxt(data, usecols=(0, 1, 3)) _test(prof) # Test trying to not set unpack - prof.loadtxt(data, usecols=(0,1,3), unpack = False) + prof.loadtxt(data, usecols=(0, 1, 3), unpack=False) _test(prof) - prof.loadtxt(data, float, '#', None, None, 0, (0,1,3), False) + prof.loadtxt(data, float, "#", None, None, 0, (0, 1, 3), False) _test(prof) # Try not including dy - prof.loadtxt(data, usecols=(0,1)) + prof.loadtxt(data, usecols=(0, 1)) self.assertAlmostEqual(1e-2, prof.x[0]) self.assertAlmostEqual(1.105784e-1, prof.y[0]) self.assertAlmostEqual(1, prof.dy[0]) @@ -209,23 +205,23 @@ def _test(p): self.assertRaises(ValueError, prof.loadtxt, data, usecols=(0,)) return - def test_savetxt(self): "Check the savetxt method." prof = self.profile - self.assertRaises(SrFitError, prof.savetxt, 'foo') + self.assertRaises(SrFitError, prof.savetxt, "foo") xobs = arange(-2, 3.01, 0.25) - yobs = xobs ** 2 + yobs = xobs**2 prof.setObservedProfile(xobs, yobs) prof.ycalc = yobs.copy() fp = io.BytesIO() prof.savetxt(fp) txt = fp.getvalue().decode() - self.assertTrue(re.match(r'^# x +ycalc +y +dy\b', txt)) - nlines = len(txt.strip().split('\n')) + self.assertTrue(re.match(r"^# x +ycalc +y +dy\b", txt)) + nlines = len(txt.strip().split("\n")) self.assertEqual(22, nlines) return + # End of class TestProfile # ---------------------------------------------------------------------------- diff --git a/src/diffpy/srfit/tests/testprofilegenerator.py b/src/diffpy/srfit/tests/testprofilegenerator.py index 4fb43002..07c02037 100644 --- a/src/diffpy/srfit/tests/testprofilegenerator.py +++ b/src/diffpy/srfit/tests/testprofilegenerator.py @@ -20,8 +20,8 @@ from numpy import arange, array_equal -from diffpy.srfit.fitbase.profilegenerator import ProfileGenerator from diffpy.srfit.fitbase.profile import Profile +from diffpy.srfit.fitbase.profilegenerator import ProfileGenerator class TestProfileGenerator(unittest.TestCase): @@ -34,7 +34,6 @@ def setUp(self): self.gen.setProfile(self.profile) return - def testOperation(self): """Test the operation method.""" gen = self.gen @@ -49,7 +48,6 @@ def testOperation(self): self.assertTrue(array_equal(2 * prof.x, val)) return - def testUpdate(self): """Update and change the profile to make sure generator is flushed.""" gen = self.gen @@ -77,18 +75,17 @@ def testUpdate(self): self.assertTrue(array_equal(x, gen.value)) return - def test_pickling(self): - """Test pickling of ProfileGenerator. - """ + """Test pickling of ProfileGenerator.""" data = pickle.dumps(self.gen) gen2 = pickle.loads(data) - self.assertEqual('test', gen2.name) + self.assertEqual("test", gen2.name) x = self.profile.x self.assertTrue(array_equal(x, gen2.operation())) self.assertTrue(array_equal(3 * x, gen2(3 * x))) return + # End of class TestProfileGenerator if __name__ == "__main__": diff --git a/src/diffpy/srfit/tests/testrecipeorganizer.py b/src/diffpy/srfit/tests/testrecipeorganizer.py index 08efde92..f080c28b 100644 --- a/src/diffpy/srfit/tests/testrecipeorganizer.py +++ b/src/diffpy/srfit/tests/testrecipeorganizer.py @@ -17,18 +17,17 @@ import unittest +import numpy + from diffpy.srfit.equation.builder import EquationFactory from diffpy.srfit.fitbase.calculator import Calculator from diffpy.srfit.fitbase.parameter import Parameter -from diffpy.srfit.fitbase.recipeorganizer import equationFromString -from diffpy.srfit.fitbase.recipeorganizer import RecipeContainer -from diffpy.srfit.fitbase.recipeorganizer import RecipeOrganizer +from diffpy.srfit.fitbase.recipeorganizer import RecipeContainer, RecipeOrganizer, equationFromString from diffpy.srfit.tests.utils import capturestdout -import numpy - # ---------------------------------------------------------------------------- + class TestEquationFromString(unittest.TestCase): def testEquationFromString(self): @@ -56,7 +55,7 @@ def testEquationFromString(self): self.assertRaises(ValueError, equationFromString, "p1+p2+p3", factory) # Pass that argument in the ns dictionary - eq = equationFromString("p1+p2+p3", factory, {"p3":p3}) + eq = equationFromString("p1+p2+p3", factory, {"p3": p3}) self.assertEqual(3, len(eq.args)) self.assertTrue(p1 in eq.args) self.assertTrue(p2 in eq.args) @@ -67,17 +66,17 @@ def testEquationFromString(self): self.assertTrue("p3" not in factory.builders) # Pass and use an unregistered parameter - self.assertRaises(ValueError, equationFromString, "p1+p2+p3+p4", - factory, {"p3":p3}) + self.assertRaises(ValueError, equationFromString, "p1+p2+p3+p4", factory, {"p3": p3}) # Try to overload a registered parameter - self.assertRaises(ValueError, equationFromString, "p1+p2", - factory, {"p2":p4}) + self.assertRaises(ValueError, equationFromString, "p1+p2", factory, {"p2": p4}) return + # ---------------------------------------------------------------------------- + class TestRecipeContainer(unittest.TestCase): def setUp(self): @@ -107,14 +106,18 @@ def testAccessors(self): self.assertTrue(m1.m2.p2 is p2) self.assertTrue(m1[0] is p1) - self.assertTrue(m1[0:] == [p1,]) + self.assertTrue( + m1[0:] + == [ + p1, + ] + ) self.assertTrue(m2[0] is p2) self.assertEqual(1, len(m1)) self.assertEqual(1, len(m2)) return - def testLocateManagedObject(self): """Test the locateManagedObject method.""" m1 = self.m @@ -155,8 +158,10 @@ def testLocateManagedObject(self): return + # ---------------------------------------------------------------------------- + class TestRecipeOrganizer(unittest.TestCase): def setUp(self): @@ -169,7 +174,6 @@ def setUp(self): def tearDown(self): return - def testNewParameter(self): """Test the addParameter method.""" @@ -186,7 +190,6 @@ def testNewParameter(self): self.assertTrue(p2 is m.p2) return - def testAddParameter(self): """Test the addParameter method.""" @@ -261,7 +264,6 @@ def testConstrain(self): self.assertEqual(0, len(self.m._constraints)) self.m.constrain(p1, "2*p2") - self.assertTrue(p1.constrained) self.assertTrue(p1 in self.m._constraints) self.assertEqual(1, len(self.m._constraints)) @@ -273,7 +275,7 @@ def testConstrain(self): # Check errors on unregistered parameters self.assertRaises(ValueError, self.m.constrain, p1, "2*p3") - self.assertRaises(ValueError, self.m.constrain, p1, "2*p2", {"p2":p3}) + self.assertRaises(ValueError, self.m.constrain, p1, "2*p2", {"p2": p3}) # Remove the constraint self.m.unconstrain(p1) @@ -298,21 +300,21 @@ def testRestrain(self): self.m._eqfactory.registerArgument("p2", p2) self.assertEqual(0, len(self.m._restraints)) - r = self.m.restrain("p1+p2", ub = 10) + r = self.m.restrain("p1+p2", ub=10) self.assertEqual(1, len(self.m._restraints)) p2.setValue(10) self.assertEqual(1, r.penalty()) self.m.unrestrain(r) self.assertEqual(0, len(self.m._restraints)) - r = self.m.restrain(p1, ub = 10) + r = self.m.restrain(p1, ub=10) self.assertEqual(1, len(self.m._restraints)) p1.setValue(11) self.assertEqual(1, r.penalty()) # Check errors on unregistered parameters self.assertRaises(ValueError, self.m.restrain, "2*p3") - self.assertRaises(ValueError, self.m.restrain, "2*p2", ns = {"p2":p3}) + self.assertRaises(ValueError, self.m.restrain, "2*p2", ns={"p2": p3}) return def testGetConstraints(self): @@ -384,7 +386,7 @@ def __call__(self, x): A = self.A.getValue() c = self.center.getValue() w = self.width.getValue() - return A * numpy.exp(-0.5*((x-c)/w)**2) + return A * numpy.exp(-0.5 * ((x - c) / w) ** 2) # End class GCalc @@ -397,27 +399,27 @@ def __call__(self, x): self.m.g.center.setValue(3.0) - self.assertTrue(numpy.array_equal(numpy.exp(-0.5*((x-3.0)/0.1)**2), - g(x))) + self.assertTrue(numpy.array_equal(numpy.exp(-0.5 * ((x - 3.0) / 0.1) ** 2), g(x))) self.m.g.center.setValue(5.0) - self.assertTrue(numpy.array_equal(numpy.exp(-0.5*((x-5.0)/0.1)**2), - g(x))) + self.assertTrue(numpy.array_equal(numpy.exp(-0.5 * ((x - 5.0) / 0.1) ** 2), g(x))) # Use this in another equation eq = self.m.registerStringFunction("g/x - 1", "pdf") - self.assertTrue(numpy.array_equal(g(x)/x - 1, eq())) + self.assertTrue(numpy.array_equal(g(x) / x - 1, eq())) return def testRegisterFunction(self): """Test registering various functions.""" + def g1(A, c, w, x): - return A * numpy.exp(-0.5*((x-c)/w)**2) + return A * numpy.exp(-0.5 * ((x - c) / w) ** 2) + def g2(A): - return A+1 + return A + 1 eq = self.m.registerFunction(g1, "g") @@ -430,12 +432,11 @@ def g2(A): self.m.c.setValue(3.0) self.m.w.setValue(0.1) - self.assertTrue(numpy.array_equal(numpy.exp(-0.5*((x-3.0)/0.1)**2), - eq())) + self.assertTrue(numpy.array_equal(numpy.exp(-0.5 * ((x - 3.0) / 0.1) ** 2), eq())) # Use this in another equation eq2 = self.m.registerStringFunction("g/x - 1", "pdf") - self.assertTrue(numpy.array_equal(eq()/x - 1, eq2())) + self.assertTrue(numpy.array_equal(eq() / x - 1, eq2())) # Make sure we can swap out "g". self.m.registerFunction(g2, "g") @@ -443,8 +444,11 @@ def g2(A): # Try a bound method class temp(object): - def eval(self): return 1.23 - def __call__(self): return 4.56 + def eval(self): + return 1.23 + + def __call__(self): + return 4.56 t = temp() eq = self.m.registerFunction(t.eval, "eval") @@ -494,50 +498,48 @@ def testRegisterStringFunction(self): return - def test_releaseOldEquations(self): - """Verify EquationFactory does not hold temporary equations. - """ - self.m._newParameter('x', 12) - self.assertEqual(36, self.m.evaluateEquation('3 * x')) + """Verify EquationFactory does not hold temporary equations.""" + self.m._newParameter("x", 12) + self.assertEqual(36, self.m.evaluateEquation("3 * x")) self.assertEqual(0, len(self.m._eqfactory.equations)) return - def test_show(self): - """Verify output from the show function. - """ + """Verify output from the show function.""" + def capture_show(*args, **kwargs): rv = capturestdout(self.m.show, *args, **kwargs) return rv - self.assertEqual('', capture_show()) - self.m._newParameter('x', 1) - self.m._newParameter('y', 2) + + self.assertEqual("", capture_show()) + self.m._newParameter("x", 1) + self.m._newParameter("y", 2) out1 = capture_show() - lines1 = out1.strip().split('\n') + lines1 = out1.strip().split("\n") self.assertEqual(4, len(lines1)) - self.assertTrue('Parameters' in lines1) - self.assertFalse('Constraints' in lines1) - self.assertFalse('Restraints' in lines1) - self.m._newParameter('z', 7) - self.m.constrain('y', '3 * z') + self.assertTrue("Parameters" in lines1) + self.assertFalse("Constraints" in lines1) + self.assertFalse("Restraints" in lines1) + self.m._newParameter("z", 7) + self.m.constrain("y", "3 * z") out2 = capture_show() - lines2 = out2.strip().split('\n') + lines2 = out2.strip().split("\n") self.assertEqual(9, len(lines2)) - self.assertTrue('Parameters' in lines2) - self.assertTrue('Constraints' in lines2) - self.assertFalse('Restraints' in lines2) - self.m.restrain('z', lb=2, ub=3, sig=0.001) + self.assertTrue("Parameters" in lines2) + self.assertTrue("Constraints" in lines2) + self.assertFalse("Restraints" in lines2) + self.m.restrain("z", lb=2, ub=3, sig=0.001) out3 = capture_show() - lines3 = out3.strip().split('\n') + lines3 = out3.strip().split("\n") self.assertEqual(13, len(lines3)) - self.assertTrue('Parameters' in lines3) - self.assertTrue('Constraints' in lines3) - self.assertTrue('Restraints' in lines3) - out4 = capture_show(pattern='x') - lines4 = out4.strip().split('\n') + self.assertTrue("Parameters" in lines3) + self.assertTrue("Constraints" in lines3) + self.assertTrue("Restraints" in lines3) + out4 = capture_show(pattern="x") + lines4 = out4.strip().split("\n") self.assertEqual(9, len(lines4)) - out5 = capture_show(pattern='^') + out5 = capture_show(pattern="^") self.assertEqual(out3, out5) # check output with another level of hierarchy self.m._addObject(RecipeOrganizer("foo"), self.m._containers) @@ -545,11 +547,12 @@ def capture_show(*args, **kwargs): out6 = capture_show() self.assertTrue("foo.bar" in out6) # filter out foo.bar - out7 = capture_show('^(?!foo).') + out7 = capture_show("^(?!foo).") self.assertFalse("foo.bar" in out7) self.assertEqual(out3, out7) return + # ---------------------------------------------------------------------------- if __name__ == "__main__": diff --git a/src/diffpy/srfit/tests/testrestraint.py b/src/diffpy/srfit/tests/testrestraint.py index 2968dd32..610a62ab 100644 --- a/src/diffpy/srfit/tests/testrestraint.py +++ b/src/diffpy/srfit/tests/testrestraint.py @@ -17,10 +17,10 @@ import unittest -from diffpy.srfit.fitbase.restraint import Restraint -from diffpy.srfit.fitbase.recipeorganizer import equationFromString -from diffpy.srfit.fitbase.parameter import Parameter from diffpy.srfit.equation.builder import EquationFactory +from diffpy.srfit.fitbase.parameter import Parameter +from diffpy.srfit.fitbase.recipeorganizer import equationFromString +from diffpy.srfit.fitbase.restraint import Restraint class TestRestraint(unittest.TestCase): @@ -63,6 +63,7 @@ def testRestraint(self): # Make a really large number to check the upper bound import numpy + r.ub = numpy.inf p1.setValue(1e100) self.assertEqual(0, r.penalty()) diff --git a/src/diffpy/srfit/tests/testsas.py b/src/diffpy/srfit/tests/testsas.py index 9122cf97..2e94114f 100644 --- a/src/diffpy/srfit/tests/testsas.py +++ b/src/diffpy/srfit/tests/testsas.py @@ -20,12 +20,12 @@ import numpy from diffpy.srfit.sas import SASGenerator, SASParser, SASProfile -from diffpy.srfit.tests.utils import datafile -from diffpy.srfit.tests.utils import has_sas, _msg_nosas from diffpy.srfit.sas.sasimport import sasimport +from diffpy.srfit.tests.utils import _msg_nosas, datafile, has_sas # ---------------------------------------------------------------------------- + @unittest.skipUnless(has_sas, _msg_nosas) class TestSASParser(unittest.TestCase): @@ -36,43 +36,47 @@ def testParser(self): x, y, dx, dy = parser.getData() - testx = numpy.array([0.002618, 0.007854, 0.01309, 0.01832, 0.02356, - 0.02879, 0.03402, 0.03925, 0.04448, 0.0497]) + testx = numpy.array( + [0.002618, 0.007854, 0.01309, 0.01832, 0.02356, 0.02879, 0.03402, 0.03925, 0.04448, 0.0497] + ) diff = testx - x res = numpy.dot(diff, diff) self.assertAlmostEqual(0, res) - testy = numpy.array([ 0.02198, 0.02201, 0.02695, 0.02645, 0.03024, - 0.3927, 7.305, 17.43, 13.43, 8.346]) + testy = numpy.array([0.02198, 0.02201, 0.02695, 0.02645, 0.03024, 0.3927, 7.305, 17.43, 13.43, 8.346]) diff = testy - y res = numpy.dot(diff, diff) self.assertAlmostEqual(0, res) - testdy = numpy.array([ 0.002704, 0.001643, 0.002452, 0.001769, - 0.001531, 0.1697, 1.006, 0.5351, 0.3677, 0.191]) + testdy = numpy.array( + [0.002704, 0.001643, 0.002452, 0.001769, 0.001531, 0.1697, 1.006, 0.5351, 0.3677, 0.191] + ) diff = testdy - dy res = numpy.dot(diff, diff) self.assertAlmostEqual(0, res) - testdx = numpy.array([0.0004091, 0.005587, 0.005598, 0.005624, - 0.005707, 0.005975, 0.006264, 0.006344, 0.006424, 0.006516]) + testdx = numpy.array( + [0.0004091, 0.005587, 0.005598, 0.005624, 0.005707, 0.005975, 0.006264, 0.006344, 0.006424, 0.006516] + ) diff = testdx - dx res = numpy.dot(diff, diff) self.assertAlmostEqual(0, res) return + # End of class TestSASParser # ---------------------------------------------------------------------------- + @unittest.skipUnless(has_sas, _msg_nosas) class TestSASGenerator(unittest.TestCase): def testGenerator(self): # Test generator output - SphereModel = sasimport('sas.models.SphereModel').SphereModel + SphereModel = sasimport("sas.models.SphereModel").SphereModel model = SphereModel() gen = SASGenerator("sphere", model) @@ -88,8 +92,7 @@ def testGenerator(self): self.assertEqual(defval, par.getValue()) self.assertEqual(defval, model.getParam(pname)) - - r = numpy.arange(1, 10, 0.1, dtype = float) + r = numpy.arange(1, 10, 0.1, dtype=float) y = gen(r) refy = model.evalDistribution(r) diff = y - refy @@ -98,16 +101,15 @@ def testGenerator(self): return - def testGenerator2(self): # Test generator with a profile - EllipsoidModel = sasimport('sas.models.EllipsoidModel').EllipsoidModel + EllipsoidModel = sasimport("sas.models.EllipsoidModel").EllipsoidModel model = EllipsoidModel() gen = SASGenerator("ellipsoid", model) # Load the data using SAS tools - Loader = sasimport('sas.dataloader.loader').Loader + Loader = sasimport("sas.dataloader.loader").Loader loader = Loader() data = datafile("sas_ellipsoid_testdata.txt") datainfo = loader.load(data) @@ -125,6 +127,7 @@ def testGenerator2(self): self.assertAlmostEqual(0, res) return + # End of class TestSASGenerator if __name__ == "__main__": diff --git a/src/diffpy/srfit/tests/testsgconstraints.py b/src/diffpy/srfit/tests/testsgconstraints.py index 01c4d49b..01bb8545 100644 --- a/src/diffpy/srfit/tests/testsgconstraints.py +++ b/src/diffpy/srfit/tests/testsgconstraints.py @@ -19,12 +19,11 @@ import numpy -from diffpy.srfit.tests.utils import datafile -from diffpy.srfit.tests.utils import has_pyobjcryst, _msg_nopyobjcryst -from diffpy.srfit.tests.utils import has_structure, _msg_nostructure +from diffpy.srfit.tests.utils import _msg_nopyobjcryst, _msg_nostructure, datafile, has_pyobjcryst, has_structure # ---------------------------------------------------------------------------- + class TestSGConstraints(unittest.TestCase): @unittest.skipUnless(has_pyobjcryst, _msg_nopyobjcryst) @@ -51,16 +50,16 @@ def test_ObjCryst_constrainSpaceGroup(self): # Check the orthorhombic lattice l = stru.getLattice() - self.assertTrue( l.alpha.const ) - self.assertTrue( l.beta.const ) - self.assertTrue( l.gamma.const ) - self.assertEqual(pi/2, l.alpha.getValue()) - self.assertEqual(pi/2, l.beta.getValue()) - self.assertEqual(pi/2, l.gamma.getValue()) - - self.assertFalse( l.a.const ) - self.assertFalse( l.b.const ) - self.assertFalse( l.c.const ) + self.assertTrue(l.alpha.const) + self.assertTrue(l.beta.const) + self.assertTrue(l.gamma.const) + self.assertEqual(pi / 2, l.alpha.getValue()) + self.assertEqual(pi / 2, l.beta.getValue()) + self.assertEqual(pi / 2, l.gamma.getValue()) + + self.assertFalse(l.a.const) + self.assertFalse(l.b.const) + self.assertFalse(l.c.const) self.assertEqual(0, len(l._constraints)) # Now make sure the scatterers are constrained properly @@ -96,12 +95,12 @@ def test_ObjCryst_constrainSpaceGroup(self): # Nor can we make them into variables from diffpy.srfit.fitbase.fitrecipe import FitRecipe + f = FitRecipe() self.assertRaises(ValueError, f.addVar, mn.x) return - @unittest.skipUnless(has_structure, _msg_nostructure) def test_DiffPy_constrainAsSpaceGroup(self): """Test the constrainAsSpaceGroup function.""" @@ -111,14 +110,14 @@ def test_DiffPy_constrainAsSpaceGroup(self): stru = makeLaMnO3_P1() parset = DiffpyStructureParSet("LaMnO3", stru) - sgpars = constrainAsSpaceGroup(parset, "P b n m", - scatterers = parset.getScatterers()[::2], - constrainadps = True) + sgpars = constrainAsSpaceGroup( + parset, "P b n m", scatterers=parset.getScatterers()[::2], constrainadps=True + ) # Make sure that the new parameters were created for par in sgpars: self.assertNotEqual(None, par) - self.assertNotEqual(None, par.getValue() ) + self.assertNotEqual(None, par.getValue()) # Test the unconstrained atoms for scatterer in parset.getScatterers()[1::2]: @@ -137,10 +136,13 @@ def test_DiffPy_constrainAsSpaceGroup(self): def _consttest(par): return par.const + def _constrainedtest(par): return par.constrained + def _proxytest(par): return par in proxied + def _alltests(par): return _consttest(par) or _constrainedtest(par) or _proxytest(par) @@ -152,26 +154,24 @@ def _alltests(par): self.assertTrue(test) test = False - for par in [scatterer.U11, scatterer.U22, scatterer.U33, - scatterer.U12, scatterer.U13, scatterer.U23]: + for par in [scatterer.U11, scatterer.U22, scatterer.U33, scatterer.U12, scatterer.U13, scatterer.U23]: test |= _alltests(par) self.assertTrue(test) return - @unittest.skipUnless(has_structure, _msg_nostructure) def test_ConstrainAsSpaceGroup_args(self): - """Test the arguments processing of constrainAsSpaceGroup function. - """ + """Test the arguments processing of constrainAsSpaceGroup function.""" from diffpy.srfit.structure.diffpyparset import DiffpyStructureParSet from diffpy.srfit.structure.sgconstraints import constrainAsSpaceGroup from diffpy.structure.spacegroups import GetSpaceGroup + stru = makeLaMnO3_P1() parset = DiffpyStructureParSet("LaMnO3", stru) sgpars = constrainAsSpaceGroup(parset, "P b n m") - sg = GetSpaceGroup('P b n m') + sg = GetSpaceGroup("P b n m") parset2 = DiffpyStructureParSet("LMO", makeLaMnO3_P1()) sgpars2 = constrainAsSpaceGroup(parset2, sg) list(sgpars) @@ -179,20 +179,23 @@ def test_ConstrainAsSpaceGroup_args(self): self.assertEqual(sgpars.names, sgpars2.names) return + # End of class TestSGConstraints # Local helper functions ----------------------------------------------------- + def makeLaMnO3_P1(): from diffpy.structure import Structure + stru = Structure() - stru.read(datafile('LaMnO3.stru')) + stru.read(datafile("LaMnO3.stru")) return stru def makeLaMnO3(): - from pyobjcryst.crystal import Crystal from pyobjcryst.atom import Atom + from pyobjcryst.crystal import Crystal from pyobjcryst.scatteringpower import ScatteringPowerAtom pi = numpy.pi @@ -201,31 +204,32 @@ def makeLaMnO3(): crystal.SetName("LaMnO3") # La1 sp = ScatteringPowerAtom("La1", "La") - sp.SetBiso(8*pi*pi*0.003) + sp.SetBiso(8 * pi * pi * 0.003) atom = Atom(0.996096, 0.0321494, 0.25, "La1", sp) crystal.AddScatteringPower(sp) crystal.AddScatterer(atom) # Mn1 sp = ScatteringPowerAtom("Mn1", "Mn") - sp.SetBiso(8*pi*pi*0.003) + sp.SetBiso(8 * pi * pi * 0.003) atom = Atom(0, 0.5, 0, "Mn1", sp) crystal.AddScatteringPower(sp) crystal.AddScatterer(atom) # O1 sp = ScatteringPowerAtom("O1", "O") - sp.SetBiso(8*pi*pi*0.003) + sp.SetBiso(8 * pi * pi * 0.003) atom = Atom(0.0595746, 0.496164, 0.25, "O1", sp) crystal.AddScatteringPower(sp) crystal.AddScatterer(atom) # O2 sp = ScatteringPowerAtom("O2", "O") - sp.SetBiso(8*pi*pi*0.003) + sp.SetBiso(8 * pi * pi * 0.003) atom = Atom(0.720052, 0.289387, 0.0311126, "O2", sp) crystal.AddScatteringPower(sp) crystal.AddScatterer(atom) return crystal + # ---------------------------------------------------------------------------- if __name__ == "__main__": diff --git a/src/diffpy/srfit/tests/testtagmanager.py b/src/diffpy/srfit/tests/testtagmanager.py index 5518f3aa..c481cf2f 100644 --- a/src/diffpy/srfit/tests/testtagmanager.py +++ b/src/diffpy/srfit/tests/testtagmanager.py @@ -20,6 +20,7 @@ from diffpy.srfit.util.tagmanager import TagManager + ############################################################################## class TestTagManager(unittest.TestCase): @@ -32,8 +33,7 @@ def tearDown(self): return def test_tag(self): - """check TagManager.tag() - """ + """check TagManager.tag()""" m = self.m obj = 3 m.tag(obj, "3", "three") @@ -48,8 +48,7 @@ def test_tag(self): return def test_untag(self): - """check TagManager.untag() - """ + """check TagManager.untag()""" m = self.m obj = 3 m.tag(obj, "3", "three", "tri", "tres", "trois") @@ -70,12 +69,11 @@ def test_untag(self): return def test_union_and_intersection(self): - """check TagManager.union() and TagManager.intersection() - """ + """check TagManager.union() and TagManager.intersection()""" m = self.m m.tag(3, "3", "number") m.tag(4, "4", "number") - objs = set([3,4]) + objs = set([3, 4]) self.assertEqual(m.union(), set()) self.assertEqual(m.union("number"), objs) self.assertEqual(m.union("3"), set([3])) @@ -95,22 +93,22 @@ def test_union_and_intersection(self): return def test_hasTags(self): - """check TagManager.hasTags() - """ + """check TagManager.hasTags()""" m = self.m m.tag(3, "3", "number") m.tag(4, "4", "number") - self.assertTrue( m.hasTags(3, "3") ) - self.assertTrue( m.hasTags(3, "3", "number") ) - self.assertFalse( m.hasTags(3, "3", "4") ) + self.assertTrue(m.hasTags(3, "3")) + self.assertTrue(m.hasTags(3, "3", "number")) + self.assertFalse(m.hasTags(3, "3", "4")) self.assertRaises(KeyError, m.hasTags, 3, "fail") m.silent = True self.assertFalse(m.hasTags(3, "fail")) return + # End of class TestTagManager -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() # End of file diff --git a/src/diffpy/srfit/tests/testvisitors.py b/src/diffpy/srfit/tests/testvisitors.py index 0250f064..bbde25eb 100644 --- a/src/diffpy/srfit/tests/testvisitors.py +++ b/src/diffpy/srfit/tests/testvisitors.py @@ -17,10 +17,11 @@ import unittest -import diffpy.srfit.equation.visitors as visitors import diffpy.srfit.equation.literals as literals +import diffpy.srfit.equation.visitors as visitors from diffpy.srfit.tests.utils import _makeArgs + class TestValidator(unittest.TestCase): def testSimpleFunction(self): @@ -72,6 +73,7 @@ def testSimpleFunction(self): # Fix the operation of plus import numpy + plus.operation = numpy.add validator.reset() mult.identify(validator) @@ -85,6 +87,7 @@ def testSimpleFunction(self): return + class TestArgFinder(unittest.TestCase): def testSimpleFunction(self): @@ -134,6 +137,7 @@ def testArg(self): self.assertTrue(args[0] is v1) return + class TestSwapper(unittest.TestCase): def testSimpleFunction(self): diff --git a/src/diffpy/srfit/tests/testweakrefcallable.py b/src/diffpy/srfit/tests/testweakrefcallable.py index a3d589ca..f3a9ece4 100644 --- a/src/diffpy/srfit/tests/testweakrefcallable.py +++ b/src/diffpy/srfit/tests/testweakrefcallable.py @@ -18,46 +18,42 @@ """ -import unittest import pickle +import unittest from diffpy.srfit.fitbase import FitContribution from diffpy.srfit.fitbase.parameter import Parameter -from diffpy.srfit.util.weakrefcallable import weak_ref, WeakBoundMethod +from diffpy.srfit.util.weakrefcallable import WeakBoundMethod, weak_ref # ---------------------------------------------------------------------------- + class TestWeakBoundMethod(unittest.TestCase): def setUp(self): - self.f = FitContribution('f') - self.f.setEquation('7') + self.f = FitContribution("f") + self.f.setEquation("7") self.w = weak_ref(self.f._eq._flush, fallback=_fallback_example) return - def tearDown(self): self.f = None self.assertTrue(None is self.w._wref()) - obj, args, kw = self.w('any', 'argument', foo=37) + obj, args, kw = self.w("any", "argument", foo=37) self.assertTrue(obj is self.w) - self.assertEqual(('any', 'argument'), args) - self.assertEqual({'foo' : 37}, kw) + self.assertEqual(("any", "argument"), args) + self.assertEqual({"foo": 37}, kw) return - def test___init__(self): - """check WeakBoundMethod.__init__() - """ + """check WeakBoundMethod.__init__()""" self.assertTrue(self.w.fallback is _fallback_example) wf = weak_ref(self.f._flush) self.assertTrue(None is wf.fallback) return - def test___call__(self): - """check WeakBoundMethod.__call__() - """ + """check WeakBoundMethod.__call__()""" f = self.f self.assertEqual(7, f.evaluate()) self.assertEqual(7, f._eq._value) @@ -65,18 +61,16 @@ def test___call__(self): self.w(()) self.assertTrue(None is f._eq._value) # check WeakBoundMethod behavior with no fallback - x = Parameter('x', value=3) + x = Parameter("x", value=3) wgetx = weak_ref(x.getValue) self.assertEqual(3, wgetx()) del x self.assertRaises(ReferenceError, wgetx) return - def test___hash__(self): - """check WeakBoundMethod.__hash__() - """ - f1 = FitContribution('f1') + """check WeakBoundMethod.__hash__()""" + f1 = FitContribution("f1") w1 = weak_ref(f1._flush) h0 = hash(w1) del f1 @@ -87,11 +81,9 @@ def test___hash__(self): self.assertEqual(hash(w1c1), hash(w1c2)) return - def test___eq__(self): - """check WeakBoundMethod.__eq__() - """ - f1 = FitContribution('f1') + """check WeakBoundMethod.__eq__()""" + f1 = FitContribution("f1") w1 = weak_ref(f1._flush) w2 = weak_ref(f1._flush) self.assertEqual(w1, w2) @@ -108,10 +100,8 @@ def test___eq__(self): self.assertEqual(w1, w1cc) return - def test_pickling(self): - """Verify unpickling works when it involves __hash__ call. - """ + """Verify unpickling works when it involves __hash__ call.""" holder = set([self.w]) objs = [holder, self.f._eq, self.w] data = pickle.dumps(objs) @@ -121,13 +111,11 @@ def test_pickling(self): self.assertTrue(feq2 is w2._wref()) return - def test_observable_deregistration(self): - """check if Observable drops dead Observer. - """ + """check if Observable drops dead Observer.""" f = self.f - x = f.newParameter('x', 5) - f.setEquation('3 * x') + x = f.newParameter("x", 5) + f.setEquation("3 * x") self.assertEqual(15, f.evaluate()) self.assertEqual(15, f._eq._value) # get one of the observer callables that are associated with f @@ -146,15 +134,17 @@ def test_observable_deregistration(self): self.assertEqual(0, len(x._observers)) return + # End of class TestWeakBoundMethod # Local Routines ------------------------------------------------------------- + def _fallback_example(wbm, *args, **kwargs): return (wbm, args, kwargs) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() # End of file diff --git a/src/diffpy/srfit/tests/utils.py b/src/diffpy/srfit/tests/utils.py index 963bbd64..71c6b135 100644 --- a/src/diffpy/srfit/tests/utils.py +++ b/src/diffpy/srfit/tests/utils.py @@ -16,64 +16,71 @@ """Helper routines for testing.""" import sys + import six import diffpy.srfit.equation.literals as literals from diffpy.srfit.sas.sasimport import sasimport from diffpy.srfit.tests import logger - # Resolve availability of optional third-party packages. # srfit-sasview or sasview try: _msg_nosas = "No module named 'sas.pr.invertor'" - sasimport('sas.pr.invertor') + sasimport("sas.pr.invertor") _msg_nosas = "No module named 'sas.models'" - sasimport('sas.models') + sasimport("sas.models") has_sas = True except ImportError as e: has_sas = False - logger.warning('%s, SaS tests skipped.', e) + logger.warning("%s, SaS tests skipped.", e) # diffpy.structure _msg_nostructure = "No module named 'diffpy.structure'" try: - import diffpy.structure as m; del m + import diffpy.structure as m + + del m has_structure = True except ImportError: has_structure = False - logger.warning('Cannot import diffpy.structure, Structure tests skipped.') + logger.warning("Cannot import diffpy.structure, Structure tests skipped.") # pyobjcryst _msg_nopyobjcryst = "No module named 'pyobjcryst'" try: - import pyobjcryst as m; del m + import pyobjcryst as m + + del m has_pyobjcryst = True except ImportError: has_pyobjcryst = False - logger.warning('Cannot import pyobjcryst, pyobjcryst tests skipped.') + logger.warning("Cannot import pyobjcryst, pyobjcryst tests skipped.") # diffpy.srreal _msg_nosrreal = "No module named 'diffpy.srreal'" try: - import diffpy.srreal.pdfcalculator as m; del m + import diffpy.srreal.pdfcalculator as m + + del m has_srreal = True except ImportError: has_srreal = False - logger.warning('Cannot import diffpy.srreal, PDF tests skipped.') + logger.warning("Cannot import diffpy.srreal, PDF tests skipped.") # Helper functions for testing ----------------------------------------------- + def _makeArgs(num): args = [] for i in range(num): - j=i+1 - args.append(literals.Argument(name="v%i"%j, value=j)) + j = i + 1 + args.append(literals.Argument(name="v%i" % j, value=j)) return args @@ -83,6 +90,7 @@ def noObserversInGlobalBuilders(): Ensure objects are not immortal due to a reference from static value. """ from diffpy.srfit.equation.builder import _builders + rv = True for n, b in _builders.items(): if b.literal and b.literal._observers: @@ -93,13 +101,13 @@ def noObserversInGlobalBuilders(): def datafile(filename): from pkg_resources import resource_filename + rv = resource_filename(__name__, "testdata/" + filename) return rv def capturestdout(f, *args, **kwargs): - """Capture the standard output from a call of function f. - """ + """Capture the standard output from a call of function f.""" savestdout = sys.stdout fp = six.StringIO() try: @@ -109,4 +117,5 @@ def capturestdout(f, *args, **kwargs): sys.stdout = savestdout return fp.getvalue() + # End of file diff --git a/src/diffpy/srfit/util/__init__.py b/src/diffpy/srfit/util/__init__.py index dd586190..c26dd72e 100644 --- a/src/diffpy/srfit/util/__init__.py +++ b/src/diffpy/srfit/util/__init__.py @@ -17,7 +17,7 @@ Utilities and constants used throughout SrFit. """ -_DASHEDLINE = 78 * '-' +_DASHEDLINE = 78 * "-" def sortKeyForNumericString(s): @@ -41,12 +41,13 @@ def sortKeyForNumericString(s): """ if sortKeyForNumericString._rx is None: import re - sortKeyForNumericString._rx = re.compile(r'(\d+)') + + sortKeyForNumericString._rx = re.compile(r"(\d+)") rx = sortKeyForNumericString._rx - rv = tuple((int(w) if i % 2 else w) - for i, w in enumerate(rx.split(s))) + rv = tuple((int(w) if i % 2 else w) for i, w in enumerate(rx.split(s))) return rv + sortKeyForNumericString._rx = None # End of file diff --git a/src/diffpy/srfit/util/argbinders.py b/src/diffpy/srfit/util/argbinders.py index a49aec02..c2934dde 100644 --- a/src/diffpy/srfit/util/argbinders.py +++ b/src/diffpy/srfit/util/argbinders.py @@ -19,17 +19,14 @@ class bind2nd(object): - - '''Freeze second argument of a callable object to a given constant. - ''' + """Freeze second argument of a callable object to a given constant.""" def __init__(self, func, arg1): - """Freeze the second argument of function func to arg1. - """ + """Freeze the second argument of function func to arg1.""" self.func = func self.arg1 = arg1 return def __call__(self, *args, **kwargs): - boundargs = ((args[0], self.arg1) + args[1:]) + boundargs = (args[0], self.arg1) + args[1:] return self.func(*boundargs, **kwargs) diff --git a/src/diffpy/srfit/util/inpututils.py b/src/diffpy/srfit/util/inpututils.py index e2b06988..aba08b1f 100644 --- a/src/diffpy/srfit/util/inpututils.py +++ b/src/diffpy/srfit/util/inpututils.py @@ -41,11 +41,12 @@ def inputToString(inpt): # TODO remove handling of string input accept only file or filename # FIXME check for typos in the file name elif os.path.exists(inpt) or (len(inpt) < 80 and inpt.count("\n") == 0): - with open(inpt, 'r') as infile: + with open(inpt, "r") as infile: inptstr = infile.read() else: inptstr = inpt return inptstr + # End of file diff --git a/src/diffpy/srfit/util/nameutils.py b/src/diffpy/srfit/util/nameutils.py index ddfe27a2..4f6cf326 100644 --- a/src/diffpy/srfit/util/nameutils.py +++ b/src/diffpy/srfit/util/nameutils.py @@ -19,7 +19,7 @@ import re -reident = re.compile(r'^[a-zA-Z_]\w*$') +reident = re.compile(r"^[a-zA-Z_]\w*$") def isIdentifier(s): @@ -27,7 +27,8 @@ def isIdentifier(s): From http://code.activestate.com/recipes/413487/ """ - if reident.match(s) is None: return False + if reident.match(s) is None: + return False return True @@ -38,7 +39,8 @@ def validateName(name): """ # Check that the name is valid if not isIdentifier(name): - raise ValueError("Name '%s' is not a valid identifier"%name) + raise ValueError("Name '%s' is not a valid identifier" % name) return + # End of file diff --git a/src/diffpy/srfit/util/observable.py b/src/diffpy/srfit/util/observable.py index 9bb88024..dc671409 100644 --- a/src/diffpy/srfit/util/observable.py +++ b/src/diffpy/srfit/util/observable.py @@ -39,7 +39,6 @@ class Observable(object): """ - def notify(self, other=()): """ Notify all observers @@ -51,7 +50,6 @@ def notify(self, other=()): callable(semaphors) return - # callback management def addObserver(self, callable): """ @@ -61,7 +59,6 @@ def addObserver(self, callable): self._observers.add(f) return - def removeObserver(self, callable): """ Remove callable from the set of observers @@ -70,7 +67,6 @@ def removeObserver(self, callable): self._observers.remove(f) return - def hasObserver(self, callable): """ True if `callable` is present in the set of observers. @@ -79,17 +75,18 @@ def hasObserver(self, callable): rv = f in self._observers return rv - # meta methods def __init__(self, **kwds): super(Observable, self).__init__(**kwds) self._observers = set() return + # end of class Observable # Local helpers -------------------------------------------------------------- + def _fbRemoveObserver(fobs, semaphors): # Remove WeakBoundMethod `fobs` from the observers of notifying object. # This is called from Observable.notify when the WeakBoundMethod @@ -98,4 +95,5 @@ def _fbRemoveObserver(fobs, semaphors): observable.removeObserver(fobs) return + # end of file diff --git a/src/diffpy/srfit/util/tagmanager.py b/src/diffpy/srfit/util/tagmanager.py index 585ca336..b702722d 100644 --- a/src/diffpy/srfit/util/tagmanager.py +++ b/src/diffpy/srfit/util/tagmanager.py @@ -42,12 +42,10 @@ def __init__(self): self.silent = True return - def alltags(self): """Get all tags managed by the TagManager.""" return self._tagdict.keys() - def tag(self, obj, *tags): """Tag an object. @@ -64,7 +62,6 @@ def tag(self, obj, *tags): oset.add(obj) return - def untag(self, obj, *tags): """Remove tags from an object. @@ -87,7 +84,6 @@ def untag(self, obj, *tags): return - def tags(self, obj): """Get all tags on an object. @@ -96,7 +92,6 @@ def tags(self, obj): tags = [k for (k, v) in self._tagdict.items() if obj in v] return tags - def hasTags(self, obj, *tags): """Determine if an object has all passed tags. @@ -106,7 +101,6 @@ def hasTags(self, obj, *tags): result = all(obj in s for s in setgen) return result - def union(self, *tags): """Get all objects that have any of the passed tags. @@ -119,7 +113,6 @@ def union(self, *tags): objs = functools.reduce(set.union, setgen) return objs - def intersection(self, *tags): """Get all objects that have all of the passed tags. @@ -131,7 +124,6 @@ def intersection(self, *tags): objs = functools.reduce(set.intersection, setgen) return objs - def verifyTags(self, *tags): """Check that tags are all extant. @@ -146,7 +138,6 @@ def verifyTags(self, *tags): return True - def __getObjectSet(self, tag): """Helper function for getting an object set with given tag. diff --git a/src/diffpy/srfit/util/weakrefcallable.py b/src/diffpy/srfit/util/weakrefcallable.py index 7afac822..92ead114 100644 --- a/src/diffpy/srfit/util/weakrefcallable.py +++ b/src/diffpy/srfit/util/weakrefcallable.py @@ -18,8 +18,8 @@ """ -import weakref import types +import weakref import six @@ -49,7 +49,7 @@ class WeakBoundMethod(object): This is only used for pickling. """ - __slots__ = ('function', 'fallback', '_wref', '_class') + __slots__ = ("function", "fallback", "_wref", "_class") def __init__(self, f, fallback=None): """Create a weak reference wrapper to bound method. @@ -72,7 +72,6 @@ def __init__(self, f, fallback=None): self._wref = weakref.ref(f.__self__) return - def __call__(self, *args, **kwargs): """Call the wrapped method if the weak-referenced object is alive. @@ -98,28 +97,24 @@ def __call__(self, *args, **kwargs): emsg = "Object bound to {} does not exist.".format(self.function) raise ReferenceError(emsg) - # support use of this class in hashed collections def __hash__(self): return hash((self.function, self._wref)) - def __eq__(self, other): - rv = (self.function == other.function and - (self._wref == other._wref or - None is self._wref() is other._wref())) + rv = self.function == other.function and ( + self._wref == other._wref or None is self._wref() is other._wref() + ) return rv - def __ne__(self, other): return not self.__eq__(other) # support pickling of this type def __getstate__(self): - """Return state with a resolved weak reference. - """ + """Return state with a resolved weak reference.""" mobj = self._wref() nm = self.function.__name__ amsg = "Unable to pickle this unbound function by name." @@ -130,10 +125,8 @@ def __getstate__(self): state = (self._class, nm, self.fallback, mobj) return state - def __setstate__(self, state): - """Restore the weak reference in this wrapper upon unpickling. - """ + """Restore the weak reference in this wrapper upon unpickling.""" (self._class, nm, self.fallback, mobj) = state self.function = getattr(self._class, nm) if mobj is None: @@ -144,15 +137,16 @@ def __setstate__(self, state): self._wref = weakref.ref(mobj) return - @staticmethod def __mimic_empty_ref(): return None + # end of class WeakBoundMethod # ---------------------------------------------------------------------------- + def weak_ref(f, fallback=None): """Create weak-reference wrapper to a bound method.