From 4b1beaaccfe161b684527f00db6fc835e77013b1 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Feb 2026 12:09:21 -0500 Subject: [PATCH 001/193] deprecate addProfileGenerator --- docs/examples/coreshellnp.py | 4 ++-- docs/examples/crystalpdf.py | 2 +- docs/examples/crystalpdfall.py | 4 ++-- docs/examples/crystalpdfobjcryst.py | 2 +- docs/examples/crystalpdftwodata.py | 4 ++-- docs/examples/crystalpdftwophase.py | 4 ++-- docs/examples/ellipsoidsas.py | 2 +- docs/examples/gaussiangenerator.py | 2 +- docs/examples/npintensity.py | 2 +- docs/examples/npintensityII.py | 4 ++-- docs/examples/nppdfcrystal.py | 2 +- docs/examples/nppdfobjcryst.py | 2 +- docs/examples/nppdfsas.py | 4 ++-- src/diffpy/srfit/fitbase/fitcontribution.py | 21 ++++++++++++++++++++- src/diffpy/srfit/pdf/pdfcontribution.py | 2 +- tests/test_contribution.py | 18 +++++++++++++++--- 16 files changed, 55 insertions(+), 24 deletions(-) diff --git a/docs/examples/coreshellnp.py b/docs/examples/coreshellnp.py index 5b8c6eb2..deef927f 100644 --- a/docs/examples/coreshellnp.py +++ b/docs/examples/coreshellnp.py @@ -66,8 +66,8 @@ def makeRecipe(stru1, stru2, datname): # The FitContribution # Add both generators and the profile to the FitContribution. contribution = FitContribution("cdszns") - contribution.addProfileGenerator(generator_cds) - contribution.addProfileGenerator(generator_zns) + contribution.add_profile_generator(generator_cds) + contribution.add_profile_generator(generator_zns) contribution.set_profile(profile, xname="r") # Set up the characteristic functions. We use a spherical CF for the core diff --git a/docs/examples/crystalpdf.py b/docs/examples/crystalpdf.py index 835eb977..c3f1122c 100644 --- a/docs/examples/crystalpdf.py +++ b/docs/examples/crystalpdf.py @@ -74,7 +74,7 @@ def makeRecipe(ciffile, datname): # Here we associate the Profile and ProfileGenerator, as has been done # before. contribution = FitContribution("nickel") - contribution.addProfileGenerator(generator) + contribution.add_profile_generator(generator) contribution.set_profile(profile, xname="r") # Make the FitRecipe and add the FitContribution. diff --git a/docs/examples/crystalpdfall.py b/docs/examples/crystalpdfall.py index 8926952a..365e6f34 100644 --- a/docs/examples/crystalpdfall.py +++ b/docs/examples/crystalpdfall.py @@ -47,7 +47,7 @@ def makeProfile(datafile): def makeContribution(name, generator, profile): """Make a FitContribution and add a generator and profile.""" contribution = FitContribution(name) - contribution.addProfileGenerator(generator) + contribution.add_profile_generator(generator) contribution.set_profile(profile, xname="r") return contribution @@ -93,7 +93,7 @@ def makeRecipe( xcontribution_sini = makeContribution( "xsini", xgenerator_sini_ni, xprofile_sini ) - xcontribution_sini.addProfileGenerator(xgenerator_sini_si) + xcontribution_sini.add_profile_generator(xgenerator_sini_si) xcontribution_sini.setEquation("scale * (xG_sini_ni + xG_sini_si)") # As explained in another example, we want to minimize using Rw^2. diff --git a/docs/examples/crystalpdfobjcryst.py b/docs/examples/crystalpdfobjcryst.py index d28af6a3..f7236bcc 100644 --- a/docs/examples/crystalpdfobjcryst.py +++ b/docs/examples/crystalpdfobjcryst.py @@ -62,7 +62,7 @@ def makeRecipe(ciffile, datname): # The FitContribution contribution = FitContribution("nickel") - contribution.addProfileGenerator(generator) + contribution.add_profile_generator(generator) contribution.set_profile(profile, xname="r") # Make the FitRecipe and add the FitContribution. diff --git a/docs/examples/crystalpdftwodata.py b/docs/examples/crystalpdftwodata.py index b13da27f..fda20258 100644 --- a/docs/examples/crystalpdftwodata.py +++ b/docs/examples/crystalpdftwodata.py @@ -84,11 +84,11 @@ def makeRecipe(ciffile, xdatname, ndatname): # The FitContributions # We associate the x-ray PDFGenerator and Profile in one FitContribution... xcontribution = FitContribution("xnickel") - xcontribution.addProfileGenerator(xgenerator) + xcontribution.add_profile_generator(xgenerator) xcontribution.set_profile(xprofile, xname="r") # and the neutron objects in another. ncontribution = FitContribution("nnickel") - ncontribution.addProfileGenerator(ngenerator) + ncontribution.add_profile_generator(ngenerator) ncontribution.set_profile(nprofile, xname="r") # This example is different than the previous ones in that we are composing diff --git a/docs/examples/crystalpdftwophase.py b/docs/examples/crystalpdftwophase.py index 95e659b7..a47ff46e 100644 --- a/docs/examples/crystalpdftwophase.py +++ b/docs/examples/crystalpdftwophase.py @@ -72,8 +72,8 @@ def makeRecipe(niciffile, siciffile, datname): # Add both generators to the FitContribution. Add the Profile. This will # send the metadata to the generators. contribution = FitContribution("nisi") - contribution.addProfileGenerator(generator_ni) - contribution.addProfileGenerator(generator_si) + contribution.add_profile_generator(generator_ni) + contribution.add_profile_generator(generator_si) contribution.set_profile(profile, xname="r") # Write the fitting equation. We want to sum the PDFs from each phase and diff --git a/docs/examples/ellipsoidsas.py b/docs/examples/ellipsoidsas.py index 5c0826ec..35d8abd7 100644 --- a/docs/examples/ellipsoidsas.py +++ b/docs/examples/ellipsoidsas.py @@ -57,7 +57,7 @@ def makeRecipe(datname): # Here we associate the Profile and ProfileGenerator, as has been done # before. contribution = FitContribution("ellipsoid") - contribution.addProfileGenerator(generator) + contribution.add_profile_generator(generator) contribution.set_profile(profile, xname="q") # We want to fit the log of the signal to the log of the data so that the diff --git a/docs/examples/gaussiangenerator.py b/docs/examples/gaussiangenerator.py index f806e4a2..4f24b73c 100644 --- a/docs/examples/gaussiangenerator.py +++ b/docs/examples/gaussiangenerator.py @@ -144,7 +144,7 @@ def makeRecipe(): # attribute of the FitContribution by its name ("g"). Note that this will # set the fitting equation to "g", which calls the GaussianGenerator. contribution = FitContribution("g1") - contribution.addProfileGenerator(generator) + contribution.add_profile_generator(generator) contribution.set_profile(profile) # The FitRecipe diff --git a/docs/examples/npintensity.py b/docs/examples/npintensity.py index c193922e..5793d318 100644 --- a/docs/examples/npintensity.py +++ b/docs/examples/npintensity.py @@ -203,7 +203,7 @@ def makeRecipe(strufile, datname): # the FitContribution to name the x-variable of the profile "q", so we can # use it in equations with this name. contribution = FitContribution("bucky") - contribution.addProfileGenerator(generator) + contribution.add_profile_generator(generator) contribution.set_profile(profile, xname="q") # Now we're ready to define the fitting equation for the FitContribution. diff --git a/docs/examples/npintensityII.py b/docs/examples/npintensityII.py index 552eba96..44716cab 100644 --- a/docs/examples/npintensityII.py +++ b/docs/examples/npintensityII.py @@ -88,10 +88,10 @@ def makeRecipe(strufile, datname1, datname2): # The FitContributions # Create the FitContributions. contribution1 = FitContribution("bucky1") - contribution1.addProfileGenerator(generator1) + contribution1.add_profile_generator(generator1) contribution1.set_profile(profile1, xname="q") contribution2 = FitContribution("bucky2") - contribution2.addProfileGenerator(generator2) + contribution2.add_profile_generator(generator2) contribution2.set_profile(profile2, xname="q") # Now we're ready to define the fitting equation for each FitContribution. diff --git a/docs/examples/nppdfcrystal.py b/docs/examples/nppdfcrystal.py index 49ed32e6..fdaa3a8f 100644 --- a/docs/examples/nppdfcrystal.py +++ b/docs/examples/nppdfcrystal.py @@ -54,7 +54,7 @@ def makeRecipe(ciffile, grdata): pdfgenerator.setQmax(30.0) stru = loadCrystal(ciffile) pdfgenerator.setStructure(stru) - pdfcontribution.addProfileGenerator(pdfgenerator) + pdfcontribution.add_profile_generator(pdfgenerator) # Register the nanoparticle shape factor. from diffpy.srfit.pdf.characteristicfunctions import sphericalCF diff --git a/docs/examples/nppdfobjcryst.py b/docs/examples/nppdfobjcryst.py index 70c0bf83..25a9444d 100644 --- a/docs/examples/nppdfobjcryst.py +++ b/docs/examples/nppdfobjcryst.py @@ -52,7 +52,7 @@ def makeRecipe(molecule, datname): # The FitContribution contribution = FitContribution("bucky") - contribution.addProfileGenerator(generator) + contribution.add_profile_generator(generator) contribution.set_profile(profile, xname="r") # Make a FitRecipe. diff --git a/docs/examples/nppdfsas.py b/docs/examples/nppdfsas.py index 665e2377..08619722 100644 --- a/docs/examples/nppdfsas.py +++ b/docs/examples/nppdfsas.py @@ -58,7 +58,7 @@ def makeRecipe(ciffile, grdata, iqdata): pdfgenerator.setQmax(30.0) stru = loadCrystal(ciffile) pdfgenerator.setStructure(stru) - pdfcontribution.addProfileGenerator(pdfgenerator) + pdfcontribution.add_profile_generator(pdfgenerator) pdfcontribution.setResidualEquation("resv") # Create a SAS contribution as well. We assume the nanoparticle is roughly @@ -77,7 +77,7 @@ def makeRecipe(ciffile, grdata, iqdata): model = EllipsoidModel() sasgenerator = SASGenerator("generator", model) - sascontribution.addProfileGenerator(sasgenerator) + sascontribution.add_profile_generator(sasgenerator) sascontribution.setResidualEquation("resv") # Now we set up a characteristic function calculator that depends on the diff --git a/src/diffpy/srfit/fitbase/fitcontribution.py b/src/diffpy/srfit/fitbase/fitcontribution.py index 71048092..bbb23fb3 100644 --- a/src/diffpy/srfit/fitbase/fitcontribution.py +++ b/src/diffpy/srfit/fitbase/fitcontribution.py @@ -41,6 +41,13 @@ removal_version, ) +addprofilegenerator_dep_msg = build_deprecation_message( + base, + "addProfileGenerator", + "add_profile_generator", + removal_version, +) + class FitContribution(ParameterSet): """FitContribution class. @@ -179,7 +186,7 @@ def setProfile(self, profile, xname=None, yname=None, dyname=None): profile, xname=xname, yname=yname, dyname=dyname ) - def addProfileGenerator(self, gen, name=None): + def add_profile_generator(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 @@ -223,6 +230,18 @@ def addProfileGenerator(self, gen, name=None): return + @deprecated(addprofilegenerator_dep_msg) + def addProfileGenerator(self, gen, name=None): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use + diffpy.srfit.fitbase.FitContribution.add_profile_generator + instead. + """ + self.add_profile_generator(gen, name=name) + return + def setEquation(self, eqstr, ns={}): """Set the profile equation for the FitContribution. diff --git a/src/diffpy/srfit/pdf/pdfcontribution.py b/src/diffpy/srfit/pdf/pdfcontribution.py index bcd694ff..4809676c 100644 --- a/src/diffpy/srfit/pdf/pdfcontribution.py +++ b/src/diffpy/srfit/pdf/pdfcontribution.py @@ -273,7 +273,7 @@ def _setup_generator(self, gen): with setStructure or setPhase. """ # Add the generator to this FitContribution - self.addProfileGenerator(gen) + self.add_profile_generator(gen) # Set the proper equation for the fit, depending on the number of # phases we have. diff --git a/tests/test_contribution.py b/tests/test_contribution.py index 1332de33..37eae01b 100644 --- a/tests/test_contribution.py +++ b/tests/test_contribution.py @@ -67,6 +67,18 @@ def testAddProfileGenerator(self): self.assertTrue(fc._eq is not None) return + def test_add_profile_generator(self): + fc = self.fitcontribution + gen = self.gen + fc.add_profile_generator(gen, "gen") + + xobs = arange(0, 10, 0.5) + self.assertTrue(array_equal(xobs, gen(xobs))) + + self.assertTrue(gen.profile is None) + self.assertTrue(fc._eq is not None) + return + def testInteraction(self): """Test the interaction between the profile and profile generator.""" fc = self.fitcontribution @@ -75,7 +87,7 @@ def testInteraction(self): # Add the calculator and profile fc.set_profile(profile) - fc.addProfileGenerator(gen, "I") + fc.add_profile_generator(gen, "I") # Check attributes are created self.assertTrue(fc.profile is profile) @@ -120,7 +132,7 @@ def testReplacements(self): # Validate equations fc.set_profile(profile) - fc.addProfileGenerator(gen, "I") + fc.add_profile_generator(gen, "I") self.assertTrue(array_equal(gen.value, xobs)) self.assertTrue(array_equal(fc._eq(), xobs)) self.assertAlmostEqual(0, sum(fc._reseq())) @@ -196,7 +208,7 @@ def testResidual(noObserversInGlobalBuilders): # Add the calculator and profile fc.set_profile(profile) assert fc.profile is profile - fc.addProfileGenerator(gen, "I") + fc.add_profile_generator(gen, "I") assert fc._eq._value is None assert fc._reseq._value is None assert 1 == len(fc._generators) From 64b1ae92b8e170d3edcba5c9fc6c99f383e8b59c Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Feb 2026 12:10:10 -0500 Subject: [PATCH 002/193] update api docs --- .../api/diffpy.srfit.equation.literals.rst | 32 +++--- docs/source/api/diffpy.srfit.equation.rst | 23 ++-- .../api/diffpy.srfit.equation.visitors.rst | 36 +++---- docs/source/api/diffpy.srfit.fitbase.rst | 102 +++++++++--------- docs/source/api/diffpy.srfit.interface.rst | 18 ++-- docs/source/api/diffpy.srfit.pdf.rst | 44 ++++---- docs/source/api/diffpy.srfit.rst | 35 +++--- docs/source/api/diffpy.srfit.sas.rst | 44 ++++---- docs/source/api/diffpy.srfit.structure.rst | 54 +++++----- docs/source/api/diffpy.srfit.util.rst | 40 ++++--- 10 files changed, 222 insertions(+), 206 deletions(-) diff --git a/docs/source/api/diffpy.srfit.equation.literals.rst b/docs/source/api/diffpy.srfit.equation.literals.rst index 35b905b1..20679c3e 100644 --- a/docs/source/api/diffpy.srfit.equation.literals.rst +++ b/docs/source/api/diffpy.srfit.equation.literals.rst @@ -1,27 +1,34 @@ +:tocdepth: -1 + diffpy.srfit.equation.literals package ====================================== +.. automodule:: diffpy.srfit.equation.literals + :members: + :undoc-members: + :show-inheritance: + Submodules ---------- -diffpy.srfit.equation.literals.abcs module ------------------------------------------- +diffpy.srfit.equation.literals.argument module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.equation.literals.abcs +.. automodule:: diffpy.srfit.equation.literals.argument :members: :undoc-members: :show-inheritance: -diffpy.srfit.equation.literals.argument module ----------------------------------------------- +diffpy.srfit.equation.literals.abcs module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.equation.literals.argument +.. automodule:: diffpy.srfit.equation.literals.abcs :members: :undoc-members: :show-inheritance: diffpy.srfit.equation.literals.literal module ---------------------------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: diffpy.srfit.equation.literals.literal :members: @@ -29,18 +36,9 @@ diffpy.srfit.equation.literals.literal module :show-inheritance: diffpy.srfit.equation.literals.operators module ------------------------------------------------ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: diffpy.srfit.equation.literals.operators :members: :undoc-members: :show-inheritance: - - -Module contents ---------------- - -.. automodule:: diffpy.srfit.equation.literals - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/api/diffpy.srfit.equation.rst b/docs/source/api/diffpy.srfit.equation.rst index f5642da1..ef74cf23 100644 --- a/docs/source/api/diffpy.srfit.equation.rst +++ b/docs/source/api/diffpy.srfit.equation.rst @@ -1,19 +1,27 @@ +:tocdepth: -1 + diffpy.srfit.equation package ============================= +.. automodule:: diffpy.srfit.equation + :members: + :undoc-members: + :show-inheritance: + Subpackages ----------- .. toctree:: + :titlesonly: - diffpy.srfit.equation.literals diffpy.srfit.equation.visitors + diffpy.srfit.equation.literals Submodules ---------- diffpy.srfit.equation.builder module ------------------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: diffpy.srfit.equation.builder :members: @@ -21,18 +29,9 @@ diffpy.srfit.equation.builder module :show-inheritance: diffpy.srfit.equation.equationmod module ----------------------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: diffpy.srfit.equation.equationmod :members: :undoc-members: :show-inheritance: - - -Module contents ---------------- - -.. automodule:: diffpy.srfit.equation - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/api/diffpy.srfit.equation.visitors.rst b/docs/source/api/diffpy.srfit.equation.visitors.rst index de17f93d..88c35374 100644 --- a/docs/source/api/diffpy.srfit.equation.visitors.rst +++ b/docs/source/api/diffpy.srfit.equation.visitors.rst @@ -1,54 +1,52 @@ +:tocdepth: -1 + diffpy.srfit.equation.visitors package ====================================== -Submodules ----------- - -diffpy.srfit.equation.visitors.argfinder module ------------------------------------------------ - -.. automodule:: diffpy.srfit.equation.visitors.argfinder +.. automodule:: diffpy.srfit.equation.visitors :members: :undoc-members: :show-inheritance: -diffpy.srfit.equation.visitors.printer module ---------------------------------------------- +Submodules +---------- -.. automodule:: diffpy.srfit.equation.visitors.printer +diffpy.srfit.equation.visitors.validator module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: diffpy.srfit.equation.visitors.validator :members: :undoc-members: :show-inheritance: diffpy.srfit.equation.visitors.swapper module ---------------------------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: diffpy.srfit.equation.visitors.swapper :members: :undoc-members: :show-inheritance: -diffpy.srfit.equation.visitors.validator module ------------------------------------------------ +diffpy.srfit.equation.visitors.argfinder module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.equation.visitors.validator +.. automodule:: diffpy.srfit.equation.visitors.argfinder :members: :undoc-members: :show-inheritance: diffpy.srfit.equation.visitors.visitor module ---------------------------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: diffpy.srfit.equation.visitors.visitor :members: :undoc-members: :show-inheritance: +diffpy.srfit.equation.visitors.printer module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Module contents ---------------- - -.. automodule:: diffpy.srfit.equation.visitors +.. automodule:: diffpy.srfit.equation.visitors.printer :members: :undoc-members: :show-inheritance: diff --git a/docs/source/api/diffpy.srfit.fitbase.rst b/docs/source/api/diffpy.srfit.fitbase.rst index 44093442..19bc255e 100644 --- a/docs/source/api/diffpy.srfit.fitbase.rst +++ b/docs/source/api/diffpy.srfit.fitbase.rst @@ -1,142 +1,140 @@ +:tocdepth: -1 + diffpy.srfit.fitbase package ============================ -Submodules ----------- - -diffpy.srfit.fitbase.calculator module --------------------------------------- - -.. automodule:: diffpy.srfit.fitbase.calculator +.. automodule:: diffpy.srfit.fitbase :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.configurable module ----------------------------------------- +Submodules +---------- -.. automodule:: diffpy.srfit.fitbase.configurable +diffpy.srfit.fitbase.simplerecipe module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: diffpy.srfit.fitbase.simplerecipe :members: :undoc-members: :show-inheritance: diffpy.srfit.fitbase.constraint module --------------------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: diffpy.srfit.fitbase.constraint :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.fitcontribution module -------------------------------------------- - -.. automodule:: diffpy.srfit.fitbase.fitcontribution - :members: - :undoc-members: - :show-inheritance: - diffpy.srfit.fitbase.fithook module ------------------------------------ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: diffpy.srfit.fitbase.fithook :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.fitrecipe module -------------------------------------- +diffpy.srfit.fitbase.fitresults module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.fitbase.fitrecipe +.. automodule:: diffpy.srfit.fitbase.fitresults :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.fitresults module --------------------------------------- +diffpy.srfit.fitbase.profilegenerator module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.fitbase.fitresults +.. automodule:: diffpy.srfit.fitbase.profilegenerator :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.parameter module -------------------------------------- +diffpy.srfit.fitbase.validatable module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.fitbase.parameter +.. automodule:: diffpy.srfit.fitbase.validatable :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.parameterset module ----------------------------------------- +diffpy.srfit.fitbase.configurable module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.fitbase.parameterset +.. automodule:: diffpy.srfit.fitbase.configurable :members: :undoc-members: :show-inheritance: diffpy.srfit.fitbase.profile module ------------------------------------ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: diffpy.srfit.fitbase.profile :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.profilegenerator module --------------------------------------------- +diffpy.srfit.fitbase.restraint module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.fitbase.profilegenerator +.. automodule:: diffpy.srfit.fitbase.restraint :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.profileparser module ------------------------------------------ +diffpy.srfit.fitbase.fitcontribution module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.fitbase.profileparser +.. automodule:: diffpy.srfit.fitbase.fitcontribution :members: :undoc-members: :show-inheritance: diffpy.srfit.fitbase.recipeorganizer module -------------------------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: diffpy.srfit.fitbase.recipeorganizer :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.restraint module -------------------------------------- +diffpy.srfit.fitbase.fitrecipe module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.fitbase.restraint +.. automodule:: diffpy.srfit.fitbase.fitrecipe :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.simplerecipe module ----------------------------------------- +diffpy.srfit.fitbase.parameterset module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.fitbase.simplerecipe +.. automodule:: diffpy.srfit.fitbase.parameterset :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.validatable module ---------------------------------------- +diffpy.srfit.fitbase.calculator module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.fitbase.validatable +.. automodule:: diffpy.srfit.fitbase.calculator :members: :undoc-members: :show-inheritance: +diffpy.srfit.fitbase.parameter module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: diffpy.srfit.fitbase.parameter + :members: + :undoc-members: + :show-inheritance: -Module contents ---------------- +diffpy.srfit.fitbase.profileparser module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.fitbase +.. automodule:: diffpy.srfit.fitbase.profileparser :members: :undoc-members: :show-inheritance: diff --git a/docs/source/api/diffpy.srfit.interface.rst b/docs/source/api/diffpy.srfit.interface.rst index 4b6296a8..92497fea 100644 --- a/docs/source/api/diffpy.srfit.interface.rst +++ b/docs/source/api/diffpy.srfit.interface.rst @@ -1,22 +1,20 @@ +:tocdepth: -1 + diffpy.srfit.interface package ============================== -Submodules ----------- - -diffpy.srfit.interface.interface module ---------------------------------------- - -.. automodule:: diffpy.srfit.interface.interface +.. automodule:: diffpy.srfit.interface :members: :undoc-members: :show-inheritance: +Submodules +---------- -Module contents ---------------- +diffpy.srfit.interface.interface module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.interface +.. automodule:: diffpy.srfit.interface.interface :members: :undoc-members: :show-inheritance: diff --git a/docs/source/api/diffpy.srfit.pdf.rst b/docs/source/api/diffpy.srfit.pdf.rst index a336a375..424c7f16 100644 --- a/docs/source/api/diffpy.srfit.pdf.rst +++ b/docs/source/api/diffpy.srfit.pdf.rst @@ -1,62 +1,60 @@ +:tocdepth: -1 + diffpy.srfit.pdf package ======================== +.. automodule:: diffpy.srfit.pdf + :members: + :undoc-members: + :show-inheritance: + Submodules ---------- -diffpy.srfit.pdf.basepdfgenerator module ----------------------------------------- +diffpy.srfit.pdf.debyepdfgenerator module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.pdf.basepdfgenerator +.. automodule:: diffpy.srfit.pdf.debyepdfgenerator :members: :undoc-members: :show-inheritance: diffpy.srfit.pdf.characteristicfunctions module ------------------------------------------------ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: diffpy.srfit.pdf.characteristicfunctions :members: :undoc-members: :show-inheritance: -diffpy.srfit.pdf.debyepdfgenerator module ------------------------------------------ - -.. automodule:: diffpy.srfit.pdf.debyepdfgenerator - :members: - :undoc-members: - :show-inheritance: - -diffpy.srfit.pdf.pdfcontribution module ---------------------------------------- +diffpy.srfit.pdf.pdfparser module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.pdf.pdfcontribution +.. automodule:: diffpy.srfit.pdf.pdfparser :members: :undoc-members: :show-inheritance: diffpy.srfit.pdf.pdfgenerator module ------------------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: diffpy.srfit.pdf.pdfgenerator :members: :undoc-members: :show-inheritance: -diffpy.srfit.pdf.pdfparser module ---------------------------------- +diffpy.srfit.pdf.basepdfgenerator module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.pdf.pdfparser +.. automodule:: diffpy.srfit.pdf.basepdfgenerator :members: :undoc-members: :show-inheritance: +diffpy.srfit.pdf.pdfcontribution module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Module contents ---------------- - -.. automodule:: diffpy.srfit.pdf +.. automodule:: diffpy.srfit.pdf.pdfcontribution :members: :undoc-members: :show-inheritance: diff --git a/docs/source/api/diffpy.srfit.rst b/docs/source/api/diffpy.srfit.rst index ebff42c6..8f840d0c 100644 --- a/docs/source/api/diffpy.srfit.rst +++ b/docs/source/api/diffpy.srfit.rst @@ -1,9 +1,7 @@ :tocdepth: -1 -|title| -======= - -.. |title| replace:: diffpy.srfit package +diffpy.srfit package +==================== .. automodule:: diffpy.srfit :members: @@ -14,12 +12,23 @@ Subpackages ----------- .. toctree:: - diffpy.srfit.equation - diffpy.srfit.equation.literals - diffpy.srfit.equation.visitors - diffpy.srfit.fitbase - diffpy.srfit.interface - diffpy.srfit.pdf - diffpy.srfit.sas - diffpy.srfit.structure - diffpy.srfit.util + :titlesonly: + + diffpy.srfit.interface + diffpy.srfit.equation + diffpy.srfit.util + diffpy.srfit.pdf + diffpy.srfit.sas + diffpy.srfit.fitbase + diffpy.srfit.structure + +Submodules +---------- + +diffpy.srfit.exceptions module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: diffpy.srfit.exceptions + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/diffpy.srfit.sas.rst b/docs/source/api/diffpy.srfit.sas.rst index 40f24b3d..8ad88d91 100644 --- a/docs/source/api/diffpy.srfit.sas.rst +++ b/docs/source/api/diffpy.srfit.sas.rst @@ -1,54 +1,60 @@ +:tocdepth: -1 + diffpy.srfit.sas package ======================== +.. automodule:: diffpy.srfit.sas + :members: + :undoc-members: + :show-inheritance: + Submodules ---------- -diffpy.srfit.sas.prcalculator module ------------------------------------- +diffpy.srfit.sas.sasparser module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.sas.prcalculator +.. automodule:: diffpy.srfit.sas.sasparser :members: :undoc-members: :show-inheritance: -diffpy.srfit.sas.sasgenerator module ------------------------------------- +diffpy.srfit.sas.prcalculator module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.sas.sasgenerator +.. automodule:: diffpy.srfit.sas.prcalculator :members: :undoc-members: :show-inheritance: -diffpy.srfit.sas.sasparameter module ------------------------------------- +diffpy.srfit.sas.sasprofile module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.sas.sasparameter +.. automodule:: diffpy.srfit.sas.sasprofile :members: :undoc-members: :show-inheritance: -diffpy.srfit.sas.sasparser module ---------------------------------- +diffpy.srfit.sas.sasparameter module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.sas.sasparser +.. automodule:: diffpy.srfit.sas.sasparameter :members: :undoc-members: :show-inheritance: -diffpy.srfit.sas.sasprofile module ----------------------------------- +diffpy.srfit.sas.sasimport module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.sas.sasprofile +.. automodule:: diffpy.srfit.sas.sasimport :members: :undoc-members: :show-inheritance: +diffpy.srfit.sas.sasgenerator module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Module contents ---------------- - -.. automodule:: diffpy.srfit.sas +.. automodule:: diffpy.srfit.sas.sasgenerator :members: :undoc-members: :show-inheritance: diff --git a/docs/source/api/diffpy.srfit.structure.rst b/docs/source/api/diffpy.srfit.structure.rst index 1bb5dd22..59063abd 100644 --- a/docs/source/api/diffpy.srfit.structure.rst +++ b/docs/source/api/diffpy.srfit.structure.rst @@ -1,70 +1,68 @@ +:tocdepth: -1 + diffpy.srfit.structure package ============================== +.. automodule:: diffpy.srfit.structure + :members: + :undoc-members: + :show-inheritance: + Submodules ---------- -diffpy.srfit.structure.basestructureparset module -------------------------------------------------- +diffpy.srfit.structure.objcrystparset module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.structure.basestructureparset +.. automodule:: diffpy.srfit.structure.objcrystparset :members: :undoc-members: :show-inheritance: -diffpy.srfit.structure.bvsrestraint module ------------------------------------------- +diffpy.srfit.structure.basestructureparset module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.structure.bvsrestraint +.. automodule:: diffpy.srfit.structure.basestructureparset :members: :undoc-members: :show-inheritance: -diffpy.srfit.structure.cctbxparset module ------------------------------------------ +diffpy.srfit.structure.srrealparset module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.structure.cctbxparset +.. automodule:: diffpy.srfit.structure.srrealparset :members: :undoc-members: :show-inheritance: diffpy.srfit.structure.diffpyparset module ------------------------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: diffpy.srfit.structure.diffpyparset :members: :undoc-members: :show-inheritance: -diffpy.srfit.structure.objcrystparset module --------------------------------------------- - -.. automodule:: diffpy.srfit.structure.objcrystparset - :members: - :undoc-members: - :show-inheritance: - -diffpy.srfit.structure.sgconstraints module -------------------------------------------- +diffpy.srfit.structure.cctbxparset module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.structure.sgconstraints +.. automodule:: diffpy.srfit.structure.cctbxparset :members: :undoc-members: :show-inheritance: -diffpy.srfit.structure.srrealparset module ------------------------------------------- +diffpy.srfit.structure.bvsrestraint module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.structure.srrealparset +.. automodule:: diffpy.srfit.structure.bvsrestraint :members: :undoc-members: :show-inheritance: +diffpy.srfit.structure.sgconstraints module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Module contents ---------------- - -.. automodule:: diffpy.srfit.structure +.. automodule:: diffpy.srfit.structure.sgconstraints :members: :undoc-members: :show-inheritance: diff --git a/docs/source/api/diffpy.srfit.util.rst b/docs/source/api/diffpy.srfit.util.rst index 64541ce6..2471e5ad 100644 --- a/docs/source/api/diffpy.srfit.util.rst +++ b/docs/source/api/diffpy.srfit.util.rst @@ -1,46 +1,60 @@ +:tocdepth: -1 + diffpy.srfit.util package ========================= +.. automodule:: diffpy.srfit.util + :members: + :undoc-members: + :show-inheritance: + Submodules ---------- diffpy.srfit.util.inpututils module ------------------------------------ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: diffpy.srfit.util.inpututils :members: :undoc-members: :show-inheritance: -diffpy.srfit.util.nameutils module ----------------------------------- +diffpy.srfit.util.observable module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.util.nameutils +.. automodule:: diffpy.srfit.util.observable :members: :undoc-members: :show-inheritance: -diffpy.srfit.util.observable module ------------------------------------ +diffpy.srfit.util.tagmanager module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.util.observable +.. automodule:: diffpy.srfit.util.tagmanager :members: :undoc-members: :show-inheritance: -diffpy.srfit.util.tagmanager module ------------------------------------ +diffpy.srfit.util.argbinders module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.util.tagmanager +.. automodule:: diffpy.srfit.util.argbinders :members: :undoc-members: :show-inheritance: +diffpy.srfit.util.nameutils module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Module contents ---------------- +.. automodule:: diffpy.srfit.util.nameutils + :members: + :undoc-members: + :show-inheritance: -.. automodule:: diffpy.srfit.util +diffpy.srfit.util.weakrefcallable module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: diffpy.srfit.util.weakrefcallable :members: :undoc-members: :show-inheritance: From 7a9a4626dc443980b888b55974a6e219754a19a9 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Feb 2026 12:35:36 -0500 Subject: [PATCH 003/193] mock utils and pyobjcryst for doc rendering --- docs/source/conf.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/source/conf.py b/docs/source/conf.py index aa4fd14b..6f33a1b7 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -55,6 +55,11 @@ "m2r2", ] +autodoc_mock_imports = [ + "diffpy.utils", + "pyobjcryst", +] + # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] From a9053e3e864e5b5aa23069304900d0d923494339 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Feb 2026 12:36:40 -0500 Subject: [PATCH 004/193] news --- news/addprofilegenerator-dep.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/addprofilegenerator-dep.rst diff --git a/news/addprofilegenerator-dep.rst b/news/addprofilegenerator-dep.rst new file mode 100644 index 00000000..3a281ff7 --- /dev/null +++ b/news/addprofilegenerator-dep.rst @@ -0,0 +1,23 @@ +**Added:** + +* Added ``add_profile_generator`` to replace deprecated function. + +**Changed:** + +* + +**Deprecated:** + +* Deprecated ``addProfileGenerator`` for removal in 4.0.0. + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 8663f1272a77981d83fd399d25a176fb28c471cd Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Feb 2026 12:42:47 -0500 Subject: [PATCH 005/193] restore api docs --- .../api/diffpy.srfit.equation.literals.rst | 32 +++--- docs/source/api/diffpy.srfit.equation.rst | 23 ++-- .../api/diffpy.srfit.equation.visitors.rst | 36 ++++--- docs/source/api/diffpy.srfit.fitbase.rst | 102 +++++++++--------- docs/source/api/diffpy.srfit.interface.rst | 18 ++-- docs/source/api/diffpy.srfit.pdf.rst | 44 ++++---- docs/source/api/diffpy.srfit.rst | 35 +++--- docs/source/api/diffpy.srfit.sas.rst | 44 ++++---- docs/source/api/diffpy.srfit.structure.rst | 54 +++++----- docs/source/api/diffpy.srfit.util.rst | 40 +++---- 10 files changed, 206 insertions(+), 222 deletions(-) diff --git a/docs/source/api/diffpy.srfit.equation.literals.rst b/docs/source/api/diffpy.srfit.equation.literals.rst index 20679c3e..35b905b1 100644 --- a/docs/source/api/diffpy.srfit.equation.literals.rst +++ b/docs/source/api/diffpy.srfit.equation.literals.rst @@ -1,34 +1,27 @@ -:tocdepth: -1 - diffpy.srfit.equation.literals package ====================================== -.. automodule:: diffpy.srfit.equation.literals - :members: - :undoc-members: - :show-inheritance: - Submodules ---------- -diffpy.srfit.equation.literals.argument module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.equation.literals.abcs module +------------------------------------------ -.. automodule:: diffpy.srfit.equation.literals.argument +.. automodule:: diffpy.srfit.equation.literals.abcs :members: :undoc-members: :show-inheritance: -diffpy.srfit.equation.literals.abcs module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.equation.literals.argument module +---------------------------------------------- -.. automodule:: diffpy.srfit.equation.literals.abcs +.. automodule:: diffpy.srfit.equation.literals.argument :members: :undoc-members: :show-inheritance: diffpy.srfit.equation.literals.literal module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +--------------------------------------------- .. automodule:: diffpy.srfit.equation.literals.literal :members: @@ -36,9 +29,18 @@ diffpy.srfit.equation.literals.literal module :show-inheritance: diffpy.srfit.equation.literals.operators module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +----------------------------------------------- .. automodule:: diffpy.srfit.equation.literals.operators :members: :undoc-members: :show-inheritance: + + +Module contents +--------------- + +.. automodule:: diffpy.srfit.equation.literals + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/diffpy.srfit.equation.rst b/docs/source/api/diffpy.srfit.equation.rst index ef74cf23..f5642da1 100644 --- a/docs/source/api/diffpy.srfit.equation.rst +++ b/docs/source/api/diffpy.srfit.equation.rst @@ -1,27 +1,19 @@ -:tocdepth: -1 - diffpy.srfit.equation package ============================= -.. automodule:: diffpy.srfit.equation - :members: - :undoc-members: - :show-inheritance: - Subpackages ----------- .. toctree:: - :titlesonly: - diffpy.srfit.equation.visitors diffpy.srfit.equation.literals + diffpy.srfit.equation.visitors Submodules ---------- diffpy.srfit.equation.builder module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +------------------------------------ .. automodule:: diffpy.srfit.equation.builder :members: @@ -29,9 +21,18 @@ diffpy.srfit.equation.builder module :show-inheritance: diffpy.srfit.equation.equationmod module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +---------------------------------------- .. automodule:: diffpy.srfit.equation.equationmod :members: :undoc-members: :show-inheritance: + + +Module contents +--------------- + +.. automodule:: diffpy.srfit.equation + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/diffpy.srfit.equation.visitors.rst b/docs/source/api/diffpy.srfit.equation.visitors.rst index 88c35374..de17f93d 100644 --- a/docs/source/api/diffpy.srfit.equation.visitors.rst +++ b/docs/source/api/diffpy.srfit.equation.visitors.rst @@ -1,52 +1,54 @@ -:tocdepth: -1 - diffpy.srfit.equation.visitors package ====================================== -.. automodule:: diffpy.srfit.equation.visitors +Submodules +---------- + +diffpy.srfit.equation.visitors.argfinder module +----------------------------------------------- + +.. automodule:: diffpy.srfit.equation.visitors.argfinder :members: :undoc-members: :show-inheritance: -Submodules ----------- - -diffpy.srfit.equation.visitors.validator module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.equation.visitors.printer module +--------------------------------------------- -.. automodule:: diffpy.srfit.equation.visitors.validator +.. automodule:: diffpy.srfit.equation.visitors.printer :members: :undoc-members: :show-inheritance: diffpy.srfit.equation.visitors.swapper module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +--------------------------------------------- .. automodule:: diffpy.srfit.equation.visitors.swapper :members: :undoc-members: :show-inheritance: -diffpy.srfit.equation.visitors.argfinder module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.equation.visitors.validator module +----------------------------------------------- -.. automodule:: diffpy.srfit.equation.visitors.argfinder +.. automodule:: diffpy.srfit.equation.visitors.validator :members: :undoc-members: :show-inheritance: diffpy.srfit.equation.visitors.visitor module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +--------------------------------------------- .. automodule:: diffpy.srfit.equation.visitors.visitor :members: :undoc-members: :show-inheritance: -diffpy.srfit.equation.visitors.printer module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.equation.visitors.printer +Module contents +--------------- + +.. automodule:: diffpy.srfit.equation.visitors :members: :undoc-members: :show-inheritance: diff --git a/docs/source/api/diffpy.srfit.fitbase.rst b/docs/source/api/diffpy.srfit.fitbase.rst index 19bc255e..44093442 100644 --- a/docs/source/api/diffpy.srfit.fitbase.rst +++ b/docs/source/api/diffpy.srfit.fitbase.rst @@ -1,140 +1,142 @@ -:tocdepth: -1 - diffpy.srfit.fitbase package ============================ -.. automodule:: diffpy.srfit.fitbase +Submodules +---------- + +diffpy.srfit.fitbase.calculator module +-------------------------------------- + +.. automodule:: diffpy.srfit.fitbase.calculator :members: :undoc-members: :show-inheritance: -Submodules ----------- - -diffpy.srfit.fitbase.simplerecipe module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.fitbase.configurable module +---------------------------------------- -.. automodule:: diffpy.srfit.fitbase.simplerecipe +.. automodule:: diffpy.srfit.fitbase.configurable :members: :undoc-members: :show-inheritance: diffpy.srfit.fitbase.constraint module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------------------------------- .. automodule:: diffpy.srfit.fitbase.constraint :members: :undoc-members: :show-inheritance: +diffpy.srfit.fitbase.fitcontribution module +------------------------------------------- + +.. automodule:: diffpy.srfit.fitbase.fitcontribution + :members: + :undoc-members: + :show-inheritance: + diffpy.srfit.fitbase.fithook module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +----------------------------------- .. automodule:: diffpy.srfit.fitbase.fithook :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.fitresults module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.fitbase.fitrecipe module +------------------------------------- -.. automodule:: diffpy.srfit.fitbase.fitresults +.. automodule:: diffpy.srfit.fitbase.fitrecipe :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.profilegenerator module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.fitbase.fitresults module +-------------------------------------- -.. automodule:: diffpy.srfit.fitbase.profilegenerator +.. automodule:: diffpy.srfit.fitbase.fitresults :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.validatable module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.fitbase.parameter module +------------------------------------- -.. automodule:: diffpy.srfit.fitbase.validatable +.. automodule:: diffpy.srfit.fitbase.parameter :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.configurable module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.fitbase.parameterset module +---------------------------------------- -.. automodule:: diffpy.srfit.fitbase.configurable +.. automodule:: diffpy.srfit.fitbase.parameterset :members: :undoc-members: :show-inheritance: diffpy.srfit.fitbase.profile module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +----------------------------------- .. automodule:: diffpy.srfit.fitbase.profile :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.restraint module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.fitbase.profilegenerator module +-------------------------------------------- -.. automodule:: diffpy.srfit.fitbase.restraint +.. automodule:: diffpy.srfit.fitbase.profilegenerator :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.fitcontribution module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.fitbase.profileparser module +----------------------------------------- -.. automodule:: diffpy.srfit.fitbase.fitcontribution +.. automodule:: diffpy.srfit.fitbase.profileparser :members: :undoc-members: :show-inheritance: diffpy.srfit.fitbase.recipeorganizer module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +------------------------------------------- .. automodule:: diffpy.srfit.fitbase.recipeorganizer :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.fitrecipe module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.fitbase.restraint module +------------------------------------- -.. automodule:: diffpy.srfit.fitbase.fitrecipe +.. automodule:: diffpy.srfit.fitbase.restraint :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.parameterset module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.fitbase.simplerecipe module +---------------------------------------- -.. automodule:: diffpy.srfit.fitbase.parameterset +.. automodule:: diffpy.srfit.fitbase.simplerecipe :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.calculator module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.fitbase.validatable module +--------------------------------------- -.. automodule:: diffpy.srfit.fitbase.calculator +.. automodule:: diffpy.srfit.fitbase.validatable :members: :undoc-members: :show-inheritance: -diffpy.srfit.fitbase.parameter module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. automodule:: diffpy.srfit.fitbase.parameter - :members: - :undoc-members: - :show-inheritance: -diffpy.srfit.fitbase.profileparser module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Module contents +--------------- -.. automodule:: diffpy.srfit.fitbase.profileparser +.. automodule:: diffpy.srfit.fitbase :members: :undoc-members: :show-inheritance: diff --git a/docs/source/api/diffpy.srfit.interface.rst b/docs/source/api/diffpy.srfit.interface.rst index 92497fea..4b6296a8 100644 --- a/docs/source/api/diffpy.srfit.interface.rst +++ b/docs/source/api/diffpy.srfit.interface.rst @@ -1,20 +1,22 @@ -:tocdepth: -1 - diffpy.srfit.interface package ============================== -.. automodule:: diffpy.srfit.interface - :members: - :undoc-members: - :show-inheritance: - Submodules ---------- diffpy.srfit.interface.interface module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +--------------------------------------- .. automodule:: diffpy.srfit.interface.interface :members: :undoc-members: :show-inheritance: + + +Module contents +--------------- + +.. automodule:: diffpy.srfit.interface + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/diffpy.srfit.pdf.rst b/docs/source/api/diffpy.srfit.pdf.rst index 424c7f16..a336a375 100644 --- a/docs/source/api/diffpy.srfit.pdf.rst +++ b/docs/source/api/diffpy.srfit.pdf.rst @@ -1,60 +1,62 @@ -:tocdepth: -1 - diffpy.srfit.pdf package ======================== -.. automodule:: diffpy.srfit.pdf - :members: - :undoc-members: - :show-inheritance: - Submodules ---------- -diffpy.srfit.pdf.debyepdfgenerator module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.pdf.basepdfgenerator module +---------------------------------------- -.. automodule:: diffpy.srfit.pdf.debyepdfgenerator +.. automodule:: diffpy.srfit.pdf.basepdfgenerator :members: :undoc-members: :show-inheritance: diffpy.srfit.pdf.characteristicfunctions module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +----------------------------------------------- .. automodule:: diffpy.srfit.pdf.characteristicfunctions :members: :undoc-members: :show-inheritance: -diffpy.srfit.pdf.pdfparser module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.pdf.debyepdfgenerator module +----------------------------------------- -.. automodule:: diffpy.srfit.pdf.pdfparser +.. automodule:: diffpy.srfit.pdf.debyepdfgenerator + :members: + :undoc-members: + :show-inheritance: + +diffpy.srfit.pdf.pdfcontribution module +--------------------------------------- + +.. automodule:: diffpy.srfit.pdf.pdfcontribution :members: :undoc-members: :show-inheritance: diffpy.srfit.pdf.pdfgenerator module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +------------------------------------ .. automodule:: diffpy.srfit.pdf.pdfgenerator :members: :undoc-members: :show-inheritance: -diffpy.srfit.pdf.basepdfgenerator module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.pdf.pdfparser module +--------------------------------- -.. automodule:: diffpy.srfit.pdf.basepdfgenerator +.. automodule:: diffpy.srfit.pdf.pdfparser :members: :undoc-members: :show-inheritance: -diffpy.srfit.pdf.pdfcontribution module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.pdf.pdfcontribution +Module contents +--------------- + +.. automodule:: diffpy.srfit.pdf :members: :undoc-members: :show-inheritance: diff --git a/docs/source/api/diffpy.srfit.rst b/docs/source/api/diffpy.srfit.rst index 8f840d0c..ebff42c6 100644 --- a/docs/source/api/diffpy.srfit.rst +++ b/docs/source/api/diffpy.srfit.rst @@ -1,7 +1,9 @@ :tocdepth: -1 -diffpy.srfit package -==================== +|title| +======= + +.. |title| replace:: diffpy.srfit package .. automodule:: diffpy.srfit :members: @@ -12,23 +14,12 @@ Subpackages ----------- .. toctree:: - :titlesonly: - - diffpy.srfit.interface - diffpy.srfit.equation - diffpy.srfit.util - diffpy.srfit.pdf - diffpy.srfit.sas - diffpy.srfit.fitbase - diffpy.srfit.structure - -Submodules ----------- - -diffpy.srfit.exceptions module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. automodule:: diffpy.srfit.exceptions - :members: - :undoc-members: - :show-inheritance: + diffpy.srfit.equation + diffpy.srfit.equation.literals + diffpy.srfit.equation.visitors + diffpy.srfit.fitbase + diffpy.srfit.interface + diffpy.srfit.pdf + diffpy.srfit.sas + diffpy.srfit.structure + diffpy.srfit.util diff --git a/docs/source/api/diffpy.srfit.sas.rst b/docs/source/api/diffpy.srfit.sas.rst index 8ad88d91..40f24b3d 100644 --- a/docs/source/api/diffpy.srfit.sas.rst +++ b/docs/source/api/diffpy.srfit.sas.rst @@ -1,60 +1,54 @@ -:tocdepth: -1 - diffpy.srfit.sas package ======================== -.. automodule:: diffpy.srfit.sas - :members: - :undoc-members: - :show-inheritance: - Submodules ---------- -diffpy.srfit.sas.sasparser module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.sas.prcalculator module +------------------------------------ -.. automodule:: diffpy.srfit.sas.sasparser +.. automodule:: diffpy.srfit.sas.prcalculator :members: :undoc-members: :show-inheritance: -diffpy.srfit.sas.prcalculator module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.sas.sasgenerator module +------------------------------------ -.. automodule:: diffpy.srfit.sas.prcalculator +.. automodule:: diffpy.srfit.sas.sasgenerator :members: :undoc-members: :show-inheritance: -diffpy.srfit.sas.sasprofile module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.sas.sasparameter module +------------------------------------ -.. automodule:: diffpy.srfit.sas.sasprofile +.. automodule:: diffpy.srfit.sas.sasparameter :members: :undoc-members: :show-inheritance: -diffpy.srfit.sas.sasparameter module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.sas.sasparser module +--------------------------------- -.. automodule:: diffpy.srfit.sas.sasparameter +.. automodule:: diffpy.srfit.sas.sasparser :members: :undoc-members: :show-inheritance: -diffpy.srfit.sas.sasimport module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.sas.sasprofile module +---------------------------------- -.. automodule:: diffpy.srfit.sas.sasimport +.. automodule:: diffpy.srfit.sas.sasprofile :members: :undoc-members: :show-inheritance: -diffpy.srfit.sas.sasgenerator module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.sas.sasgenerator +Module contents +--------------- + +.. automodule:: diffpy.srfit.sas :members: :undoc-members: :show-inheritance: diff --git a/docs/source/api/diffpy.srfit.structure.rst b/docs/source/api/diffpy.srfit.structure.rst index 59063abd..1bb5dd22 100644 --- a/docs/source/api/diffpy.srfit.structure.rst +++ b/docs/source/api/diffpy.srfit.structure.rst @@ -1,68 +1,70 @@ -:tocdepth: -1 - diffpy.srfit.structure package ============================== -.. automodule:: diffpy.srfit.structure - :members: - :undoc-members: - :show-inheritance: - Submodules ---------- -diffpy.srfit.structure.objcrystparset module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.structure.basestructureparset module +------------------------------------------------- -.. automodule:: diffpy.srfit.structure.objcrystparset +.. automodule:: diffpy.srfit.structure.basestructureparset :members: :undoc-members: :show-inheritance: -diffpy.srfit.structure.basestructureparset module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.structure.bvsrestraint module +------------------------------------------ -.. automodule:: diffpy.srfit.structure.basestructureparset +.. automodule:: diffpy.srfit.structure.bvsrestraint :members: :undoc-members: :show-inheritance: -diffpy.srfit.structure.srrealparset module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.structure.cctbxparset module +----------------------------------------- -.. automodule:: diffpy.srfit.structure.srrealparset +.. automodule:: diffpy.srfit.structure.cctbxparset :members: :undoc-members: :show-inheritance: diffpy.srfit.structure.diffpyparset module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +------------------------------------------ .. automodule:: diffpy.srfit.structure.diffpyparset :members: :undoc-members: :show-inheritance: -diffpy.srfit.structure.cctbxparset module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.structure.objcrystparset module +-------------------------------------------- -.. automodule:: diffpy.srfit.structure.cctbxparset +.. automodule:: diffpy.srfit.structure.objcrystparset :members: :undoc-members: :show-inheritance: -diffpy.srfit.structure.bvsrestraint module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.structure.sgconstraints module +------------------------------------------- -.. automodule:: diffpy.srfit.structure.bvsrestraint +.. automodule:: diffpy.srfit.structure.sgconstraints :members: :undoc-members: :show-inheritance: -diffpy.srfit.structure.sgconstraints module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.structure.srrealparset module +------------------------------------------ -.. automodule:: diffpy.srfit.structure.sgconstraints +.. automodule:: diffpy.srfit.structure.srrealparset + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: diffpy.srfit.structure :members: :undoc-members: :show-inheritance: diff --git a/docs/source/api/diffpy.srfit.util.rst b/docs/source/api/diffpy.srfit.util.rst index 2471e5ad..64541ce6 100644 --- a/docs/source/api/diffpy.srfit.util.rst +++ b/docs/source/api/diffpy.srfit.util.rst @@ -1,60 +1,46 @@ -:tocdepth: -1 - diffpy.srfit.util package ========================= -.. automodule:: diffpy.srfit.util - :members: - :undoc-members: - :show-inheritance: - Submodules ---------- diffpy.srfit.util.inpututils module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +----------------------------------- .. automodule:: diffpy.srfit.util.inpututils :members: :undoc-members: :show-inheritance: -diffpy.srfit.util.observable module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.util.nameutils module +---------------------------------- -.. automodule:: diffpy.srfit.util.observable +.. automodule:: diffpy.srfit.util.nameutils :members: :undoc-members: :show-inheritance: -diffpy.srfit.util.tagmanager module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.util.observable module +----------------------------------- -.. automodule:: diffpy.srfit.util.tagmanager +.. automodule:: diffpy.srfit.util.observable :members: :undoc-members: :show-inheritance: -diffpy.srfit.util.argbinders module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +diffpy.srfit.util.tagmanager module +----------------------------------- -.. automodule:: diffpy.srfit.util.argbinders +.. automodule:: diffpy.srfit.util.tagmanager :members: :undoc-members: :show-inheritance: -diffpy.srfit.util.nameutils module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.srfit.util.nameutils - :members: - :undoc-members: - :show-inheritance: +Module contents +--------------- -diffpy.srfit.util.weakrefcallable module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. automodule:: diffpy.srfit.util.weakrefcallable +.. automodule:: diffpy.srfit.util :members: :undoc-members: :show-inheritance: From 92e8158c8745c8d9f74b89bb449f730a96c6ae10 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Feb 2026 13:23:49 -0500 Subject: [PATCH 006/193] revert conf.py commit --- docs/source/conf.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 6f33a1b7..aa4fd14b 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -55,11 +55,6 @@ "m2r2", ] -autodoc_mock_imports = [ - "diffpy.utils", - "pyobjcryst", -] - # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] From d4b71dd45c4dede9d041fd14f338824d848632eb Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Feb 2026 13:48:42 -0500 Subject: [PATCH 007/193] deprecate addContribution and replace with add_contribution --- docs/examples/coreshellnp.py | 2 +- docs/examples/crystalpdf.py | 2 +- docs/examples/crystalpdfall.py | 8 ++-- docs/examples/crystalpdfobjcryst.py | 2 +- docs/examples/crystalpdftwodata.py | 4 +- docs/examples/crystalpdftwophase.py | 2 +- docs/examples/debyemodel.py | 2 +- docs/examples/debyemodelII.py | 4 +- docs/examples/ellipsoidsas.py | 2 +- docs/examples/gaussiangenerator.py | 2 +- docs/examples/gaussianrecipe.py | 2 +- docs/examples/npintensity.py | 2 +- docs/examples/npintensityII.py | 4 +- docs/examples/nppdfcrystal.py | 2 +- docs/examples/nppdfobjcryst.py | 2 +- docs/examples/nppdfsas.py | 4 +- docs/examples/simplepdf.py | 2 +- docs/examples/simplepdftwophase.py | 2 +- docs/examples/threedoublepeaks.py | 2 +- src/diffpy/srfit/fitbase/fitrecipe.py | 20 ++++++++- src/diffpy/srfit/fitbase/simplerecipe.py | 2 +- src/diffpy/srfit/interface/interface.py | 2 +- tests/conftest.py | 6 +-- tests/test_fitrecipe.py | 52 +++++++++++++++++++++++- 24 files changed, 100 insertions(+), 34 deletions(-) diff --git a/docs/examples/coreshellnp.py b/docs/examples/coreshellnp.py index 5b8c6eb2..a66b1b62 100644 --- a/docs/examples/coreshellnp.py +++ b/docs/examples/coreshellnp.py @@ -85,7 +85,7 @@ def makeRecipe(stru1, stru2, datname): # Make the FitRecipe and add the FitContribution. recipe = FitRecipe() - recipe.addContribution(contribution) + recipe.add_contribution(contribution) # Vary the inner radius and thickness of the shell. Constrain the core # diameter to twice the shell radius. diff --git a/docs/examples/crystalpdf.py b/docs/examples/crystalpdf.py index 835eb977..36f33ad4 100644 --- a/docs/examples/crystalpdf.py +++ b/docs/examples/crystalpdf.py @@ -79,7 +79,7 @@ def makeRecipe(ciffile, datname): # Make the FitRecipe and add the FitContribution. recipe = FitRecipe() - recipe.addContribution(contribution) + recipe.add_contribution(contribution) # Configure the fit variables diff --git a/docs/examples/crystalpdfall.py b/docs/examples/crystalpdfall.py index 8926952a..d43e98c1 100644 --- a/docs/examples/crystalpdfall.py +++ b/docs/examples/crystalpdfall.py @@ -104,10 +104,10 @@ def makeRecipe( # Make the FitRecipe and add the FitContributions. recipe = FitRecipe() - recipe.addContribution(xcontribution_ni) - recipe.addContribution(xcontribution_si) - recipe.addContribution(ncontribution_ni) - recipe.addContribution(xcontribution_sini) + recipe.add_contribution(xcontribution_ni) + recipe.add_contribution(xcontribution_si) + recipe.add_contribution(ncontribution_ni) + recipe.add_contribution(xcontribution_sini) # Now we vary and constrain Parameters as before. for par in phase_ni.sgpars: diff --git a/docs/examples/crystalpdfobjcryst.py b/docs/examples/crystalpdfobjcryst.py index d28af6a3..e04f26f0 100644 --- a/docs/examples/crystalpdfobjcryst.py +++ b/docs/examples/crystalpdfobjcryst.py @@ -67,7 +67,7 @@ def makeRecipe(ciffile, datname): # Make the FitRecipe and add the FitContribution. recipe = FitRecipe() - recipe.addContribution(contribution) + recipe.add_contribution(contribution) # Configure the fit variables diff --git a/docs/examples/crystalpdftwodata.py b/docs/examples/crystalpdftwodata.py index b13da27f..c6080232 100644 --- a/docs/examples/crystalpdftwodata.py +++ b/docs/examples/crystalpdftwodata.py @@ -110,8 +110,8 @@ def makeRecipe(ciffile, xdatname, ndatname): # Make the FitRecipe and add the FitContributions. recipe = FitRecipe() - recipe.addContribution(xcontribution) - recipe.addContribution(ncontribution) + recipe.add_contribution(xcontribution) + recipe.add_contribution(ncontribution) # Now we vary and constrain Parameters as before. recipe.addVar(xgenerator.scale, 1, "xscale") diff --git a/docs/examples/crystalpdftwophase.py b/docs/examples/crystalpdftwophase.py index 95e659b7..c2acfffc 100644 --- a/docs/examples/crystalpdftwophase.py +++ b/docs/examples/crystalpdftwophase.py @@ -84,7 +84,7 @@ def makeRecipe(niciffile, siciffile, datname): # Make the FitRecipe and add the FitContribution. recipe = FitRecipe() - recipe.addContribution(contribution) + recipe.add_contribution(contribution) # Configure the fit variables # Start by configuring the scale factor and resolution factors. diff --git a/docs/examples/debyemodel.py b/docs/examples/debyemodel.py index 6abbb04c..d9009127 100644 --- a/docs/examples/debyemodel.py +++ b/docs/examples/debyemodel.py @@ -134,7 +134,7 @@ def makeRecipe(): # to fit simultaneously, the contribution from each could be added to the # recipe. recipe = FitRecipe() - recipe.addContribution(contribution) + recipe.add_contribution(contribution) # Specify which Parameters we want to refine. diff --git a/docs/examples/debyemodelII.py b/docs/examples/debyemodelII.py index 9872f71d..bc50fe54 100644 --- a/docs/examples/debyemodelII.py +++ b/docs/examples/debyemodelII.py @@ -71,8 +71,8 @@ def makeRecipeII(): # Now create a fresh FitRecipe to work with and add to it the two # FitContributions. recipe = FitRecipe() - recipe.addContribution(lowT) - recipe.addContribution(highT) + recipe.add_contribution(lowT) + recipe.add_contribution(highT) # Change the fit ranges of the Profiles embedded within the # FitContributions. We want to fit one of the contributions at low diff --git a/docs/examples/ellipsoidsas.py b/docs/examples/ellipsoidsas.py index 5c0826ec..1777da3f 100644 --- a/docs/examples/ellipsoidsas.py +++ b/docs/examples/ellipsoidsas.py @@ -68,7 +68,7 @@ def makeRecipe(datname): # Make the FitRecipe and add the FitContribution. recipe = FitRecipe() - recipe.addContribution(contribution) + recipe.add_contribution(contribution) # Configure the fit variables # The SASGenerator uses the parameters from the params and dispersion diff --git a/docs/examples/gaussiangenerator.py b/docs/examples/gaussiangenerator.py index f806e4a2..718116e7 100644 --- a/docs/examples/gaussiangenerator.py +++ b/docs/examples/gaussiangenerator.py @@ -150,7 +150,7 @@ def makeRecipe(): # The FitRecipe # Now we create the FitRecipe and add the FitContribution. recipe = FitRecipe() - recipe.addContribution(contribution) + recipe.add_contribution(contribution) # Specify which Parameters we want to vary in the fit. This will add # Variables to the FitRecipe that directly modify the Parameters of the diff --git a/docs/examples/gaussianrecipe.py b/docs/examples/gaussianrecipe.py index 4641f9ec..c203052f 100644 --- a/docs/examples/gaussianrecipe.py +++ b/docs/examples/gaussianrecipe.py @@ -140,7 +140,7 @@ def makeRecipe(): # Here we tell the FitRecipe to use our FitContribution. When the FitRecipe # calculates its residual function, it will call on the FitContribution to # do part of the work. - recipe.addContribution(contribution) + recipe.add_contribution(contribution) # Specify which Parameters we want to vary in the fit. This will add # Variables to the FitRecipe that directly modify the Parameters of the diff --git a/docs/examples/npintensity.py b/docs/examples/npintensity.py index c193922e..c0a05096 100644 --- a/docs/examples/npintensity.py +++ b/docs/examples/npintensity.py @@ -260,7 +260,7 @@ def gaussian(q, q0, width): # Make the FitRecipe and add the FitContribution. recipe = FitRecipe() - recipe.addContribution(contribution) + recipe.add_contribution(contribution) # Specify which parameters we want to refine. recipe.addVar(contribution.b0, 0) diff --git a/docs/examples/npintensityII.py b/docs/examples/npintensityII.py index 552eba96..eb2e5179 100644 --- a/docs/examples/npintensityII.py +++ b/docs/examples/npintensityII.py @@ -130,8 +130,8 @@ def gaussian(q, q0, width): # Make a FitRecipe and associate the FitContributions. recipe = FitRecipe() - recipe.addContribution(contribution1) - recipe.addContribution(contribution2) + recipe.add_contribution(contribution1) + recipe.add_contribution(contribution2) # Specify which Parameters we want to refine. We want to refine the # background that we just defined in the FitContributions. We have to do diff --git a/docs/examples/nppdfcrystal.py b/docs/examples/nppdfcrystal.py index 49ed32e6..e55bc828 100644 --- a/docs/examples/nppdfcrystal.py +++ b/docs/examples/nppdfcrystal.py @@ -67,7 +67,7 @@ def makeRecipe(ciffile, grdata): # Now make the recipe. Make sure we fit the characteristic function shape # parameters, in this case 'psize', which is the diameter of the particle. recipe = FitRecipe() - recipe.addContribution(pdfcontribution) + recipe.add_contribution(pdfcontribution) phase = pdfgenerator.phase for par in phase.sgpars: diff --git a/docs/examples/nppdfobjcryst.py b/docs/examples/nppdfobjcryst.py index 70c0bf83..038a8372 100644 --- a/docs/examples/nppdfobjcryst.py +++ b/docs/examples/nppdfobjcryst.py @@ -57,7 +57,7 @@ def makeRecipe(molecule, datname): # Make a FitRecipe. recipe = FitRecipe() - recipe.addContribution(contribution) + recipe.add_contribution(contribution) # Specify which parameters we want to refine. We'll be using the # MoleculeParSet within the generator, so let's get a handle to it. See the diff --git a/docs/examples/nppdfsas.py b/docs/examples/nppdfsas.py index 665e2377..54dea79b 100644 --- a/docs/examples/nppdfsas.py +++ b/docs/examples/nppdfsas.py @@ -93,8 +93,8 @@ def makeRecipe(ciffile, grdata, iqdata): # Moving on recipe = FitRecipe() - recipe.addContribution(pdfcontribution) - recipe.addContribution(sascontribution) + recipe.add_contribution(pdfcontribution) + recipe.add_contribution(sascontribution) # PDF phase = pdfgenerator.phase diff --git a/docs/examples/simplepdf.py b/docs/examples/simplepdf.py index 027a6d76..4574a5d7 100644 --- a/docs/examples/simplepdf.py +++ b/docs/examples/simplepdf.py @@ -44,7 +44,7 @@ def makeRecipe(ciffile, datname): # Make the FitRecipe and add the FitContribution. recipe = FitRecipe() - recipe.addContribution(contribution) + recipe.add_contribution(contribution) # Configure the fit variables phase = contribution.nickel.phase diff --git a/docs/examples/simplepdftwophase.py b/docs/examples/simplepdftwophase.py index a8017c23..e00ae302 100644 --- a/docs/examples/simplepdftwophase.py +++ b/docs/examples/simplepdftwophase.py @@ -41,7 +41,7 @@ def makeRecipe(niciffile, siciffile, datname): # Make the FitRecipe and add the FitContribution. recipe = FitRecipe() - recipe.addContribution(contribution) + recipe.add_contribution(contribution) # Configure the fit variables # Start by configuring the scale factor and resolution factors. diff --git a/docs/examples/threedoublepeaks.py b/docs/examples/threedoublepeaks.py index 60f16f64..e336fff1 100644 --- a/docs/examples/threedoublepeaks.py +++ b/docs/examples/threedoublepeaks.py @@ -98,7 +98,7 @@ def delta(t, mu): # Here we tell the FitRecipe to use our FitContribution. When the FitRecipe # calculates its residual function, it will call on the FitContribution to # do part of the work. - recipe.addContribution(contribution) + recipe.add_contribution(contribution) # Vary the amplitudes for each double peak recipe.addVar(contribution.A1, 100) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 4d7be2c9..4568f7a7 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -45,9 +45,16 @@ from diffpy.srfit.fitbase.recipeorganizer import RecipeOrganizer from diffpy.srfit.interface import _fitrecipe_interface from diffpy.srfit.util.tagmanager import TagManager +from diffpy.utils._deprecator import build_deprecation_message, deprecated plt.style.use(all_styles["bg-style"]) +base = "diffpy.srfit.fitbase.FitRecipe" +removal_version = "4.0.0" +addcontrib_dep_msg = build_deprecation_message( + base, "addContribution", "add_contribution", removal_version +) + class FitRecipe(_fitrecipe_interface, RecipeOrganizer): """FitRecipe class. @@ -238,7 +245,7 @@ def clearFitHooks(self): del self.fithooks[:] return - def addContribution(self, con, weight=1.0): + def add_contribution(self, con, weight=1.0): """Add a FitContribution to the FitRecipe. Attributes @@ -255,6 +262,17 @@ def addContribution(self, con, weight=1.0): self._weights.append(weight) return + @deprecated(addcontrib_dep_msg) + def addContribution(self, con, weight=1.0): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.add_contribution + instead. + """ + self.add_contribution(con, weight) + return + def setWeight(self, con, weight): """Set the weight of a FitContribution.""" idx = list(self._contributions.values()).index(con) diff --git a/src/diffpy/srfit/fitbase/simplerecipe.py b/src/diffpy/srfit/fitbase/simplerecipe.py index 81a0094a..2dfbe167 100644 --- a/src/diffpy/srfit/fitbase/simplerecipe.py +++ b/src/diffpy/srfit/fitbase/simplerecipe.py @@ -94,7 +94,7 @@ def __init__(self, name="fit", conclass=FitContribution): contribution = conclass("contribution") self.profile = Profile() contribution.set_profile(self.profile) - self.addContribution(contribution) + self.add_contribution(contribution) self.results = FitResults(self, update=False) # Adopt all the FitContribution methods diff --git a/src/diffpy/srfit/interface/interface.py b/src/diffpy/srfit/interface/interface.py index 63ccb573..f2b3ea17 100644 --- a/src/diffpy/srfit/interface/interface.py +++ b/src/diffpy/srfit/interface/interface.py @@ -115,7 +115,7 @@ def __ior__(self, args): This accepts a single argument. """ - self.addContribution(args) + self.add_contribution(args) return self def __iadd__(self, args): diff --git a/tests/conftest.py b/tests/conftest.py index f251746f..4f03b166 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -157,7 +157,7 @@ def build_recipe_one_contribution(): contribution.set_profile(profile) contribution.setEquation("A*sin(k*x + c)") recipe = FitRecipe() - recipe.addContribution(contribution) + recipe.add_contribution(contribution) recipe.addVar(contribution.A, 1) recipe.addVar(contribution.k, 1) recipe.addVar(contribution.c, 1) @@ -182,8 +182,8 @@ def build_recipe_two_contributions(): contribution2.set_profile(profile2) contribution2.setEquation("B*sin(m*x + d)") recipe = FitRecipe() - recipe.addContribution(contribution1) - recipe.addContribution(contribution2) + recipe.add_contribution(contribution1) + recipe.add_contribution(contribution2) recipe.addVar(contribution1.A, 1) recipe.addVar(contribution1.k, 1) recipe.addVar(contribution1.c, 1) diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 53fe7d72..0f8761ac 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -51,7 +51,7 @@ def setUp(self): self.fitcontribution.k.setValue(1) self.fitcontribution.c.setValue(0) - self.recipe.addContribution(self.fitcontribution) + self.recipe.add_contribution(self.fitcontribution) return def testFixFree(self): @@ -291,6 +291,54 @@ def testPrintFitHook(capturestdout): return +def test_add_contribution(capturestdout): + """Duplicated test of PrintFitHooks except addContribution method has + changed to the new add_contribution method. This is because addContribution + is deprecated. + + Remove this test after addContribution is removed and update + testPrintFitHook to use add_contribution instead of addContribution. + """ + recipe = FitRecipe("recipe") + recipe.fithooks[0].verbose = 0 + + # Set up the Profile + profile = Profile() + x = linspace(0, pi, 10) + y = sin(x) + profile.setObservedProfile(x, y) + + # Set up the FitContribution + fitcontribution = FitContribution("cont") + fitcontribution.set_profile(profile) + fitcontribution.setEquation("A*sin(k*x + c)") + fitcontribution.A.setValue(1) + fitcontribution.k.setValue(1) + fitcontribution.c.setValue(0) + + recipe.add_contribution(fitcontribution) + + recipe.addVar(fitcontribution.c) + recipe.restrain("c", lb=5) + (pfh,) = recipe.getFitHooks() + out = capturestdout(recipe.scalarResidual) + assert "" == out + pfh.verbose = 1 + out = capturestdout(recipe.scalarResidual) + assert out.strip().isdigit() + assert "\nRestraints:" not in out + pfh.verbose = 2 + out = capturestdout(recipe.scalarResidual) + assert "\nResidual:" in out + assert "\nRestraints:" in out + assert "\nVariables" not in out + pfh.verbose = 3 + out = capturestdout(recipe.scalarResidual) + assert "\nVariables" in out + assert "c = " in out + return + + def optimize_recipe(recipe): recipe.fithooks[0].verbose = 0 residuals = recipe.residual @@ -327,7 +375,7 @@ def build_recipe_from_datafile(datafile): contribution.set_profile(profile) contribution.setEquation("m*x + b") recipe = FitRecipe() - recipe.addContribution(contribution) + recipe.add_contribution(contribution) recipe.addVar(contribution.m, 1) recipe.addVar(contribution.b, 0) return recipe From bc0ce35c63f8e94b55ae043d5efcc46026f4c356 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Feb 2026 13:49:52 -0500 Subject: [PATCH 008/193] news --- news/addcontrib-dep.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/addcontrib-dep.rst diff --git a/news/addcontrib-dep.rst b/news/addcontrib-dep.rst new file mode 100644 index 00000000..8a8cf420 --- /dev/null +++ b/news/addcontrib-dep.rst @@ -0,0 +1,23 @@ +**Added:** + +* Added ``add_contribution`` in replace of ``addContribution``. + +**Changed:** + +* + +**Deprecated:** + +* Deprecated ``addContribution`` for removal in 4.0.0. + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From d1e139ff2a957ed08b3fa5b0c8a7307772c1c23d Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Feb 2026 14:20:07 -0500 Subject: [PATCH 009/193] deprecate setEquation and replace with set_equation --- docs/examples/coreshellnp.py | 2 +- docs/examples/crystalpdfall.py | 2 +- docs/examples/crystalpdftwophase.py | 2 +- docs/examples/debyemodel.py | 2 +- docs/examples/gaussiangenerator.py | 5 +-- docs/examples/gaussianrecipe.py | 2 +- docs/examples/interface.py | 2 +- docs/examples/npintensity.py | 2 +- docs/examples/npintensityII.py | 4 +-- docs/examples/nppdfcrystal.py | 2 +- docs/examples/nppdfsas.py | 2 +- docs/examples/simplerecipe.py | 2 +- docs/examples/threedoublepeaks.py | 2 +- src/diffpy/srfit/fitbase/fitcontribution.py | 20 +++++++++++- src/diffpy/srfit/fitbase/simplerecipe.py | 4 +-- src/diffpy/srfit/pdf/pdfcontribution.py | 2 +- tests/conftest.py | 6 ++-- tests/test_contribution.py | 36 ++++++++++++++------- tests/test_fitrecipe.py | 10 +++--- tests/test_weakrefcallable.py | 4 +-- 20 files changed, 73 insertions(+), 40 deletions(-) diff --git a/docs/examples/coreshellnp.py b/docs/examples/coreshellnp.py index 5b8c6eb2..e887ed40 100644 --- a/docs/examples/coreshellnp.py +++ b/docs/examples/coreshellnp.py @@ -81,7 +81,7 @@ def makeRecipe(stru1, stru2, datname): # Write the fitting equation. We want to sum the PDFs from each phase and # multiply it by a scaling factor. - contribution.setEquation("scale * (f_CdS * G_CdS + f_ZnS * G_ZnS)") + contribution.set_equation("scale * (f_CdS * G_CdS + f_ZnS * G_ZnS)") # Make the FitRecipe and add the FitContribution. recipe = FitRecipe() diff --git a/docs/examples/crystalpdfall.py b/docs/examples/crystalpdfall.py index 8926952a..8ae55df5 100644 --- a/docs/examples/crystalpdfall.py +++ b/docs/examples/crystalpdfall.py @@ -94,7 +94,7 @@ def makeRecipe( "xsini", xgenerator_sini_ni, xprofile_sini ) xcontribution_sini.addProfileGenerator(xgenerator_sini_si) - xcontribution_sini.setEquation("scale * (xG_sini_ni + xG_sini_si)") + xcontribution_sini.set_equation("scale * (xG_sini_ni + xG_sini_si)") # As explained in another example, we want to minimize using Rw^2. xcontribution_ni.setResidualEquation("resv") diff --git a/docs/examples/crystalpdftwophase.py b/docs/examples/crystalpdftwophase.py index 95e659b7..a133f982 100644 --- a/docs/examples/crystalpdftwophase.py +++ b/docs/examples/crystalpdftwophase.py @@ -80,7 +80,7 @@ def makeRecipe(niciffile, siciffile, datname): # multiply it by a scaling factor. We also want a certain phase scaling # relationship between the PDFs which we will enforce with constraints in # the FitRecipe. - contribution.setEquation("scale * (G_ni + G_si)") + contribution.set_equation("scale * (G_ni + G_si)") # Make the FitRecipe and add the FitContribution. recipe = FitRecipe() diff --git a/docs/examples/debyemodel.py b/docs/examples/debyemodel.py index 6abbb04c..b093d1f7 100644 --- a/docs/examples/debyemodel.py +++ b/docs/examples/debyemodel.py @@ -126,7 +126,7 @@ def makeRecipe(): # the debye equation to be positive, so we specify the input as abs(thetaD) # in the equation below. Furthermore, we know 'm', the mass of lead, so we # can specify that as well. - contribution.setEquation("debye(T, 207.2, abs(thetaD)) + offset") + contribution.set_equation("debye(T, 207.2, abs(thetaD)) + offset") # The FitRecipe # The FitRecipe lets us define what we want to fit. It is where we can diff --git a/docs/examples/gaussiangenerator.py b/docs/examples/gaussiangenerator.py index f806e4a2..9bd7e24a 100644 --- a/docs/examples/gaussiangenerator.py +++ b/docs/examples/gaussiangenerator.py @@ -33,8 +33,9 @@ Extensions -- Remove the amplitude from GaussianGenerator and instead use the 'setEquation' - method of the FitContribution to account for it. Note that the +- Remove the amplitude from GaussianGenerator and instead use the + 'set_equation' method of the + FitContribution to account for it. Note that the GaussianGenerator will be accessible by its name, "g". """ diff --git a/docs/examples/gaussianrecipe.py b/docs/examples/gaussianrecipe.py index 4641f9ec..1dfc583e 100644 --- a/docs/examples/gaussianrecipe.py +++ b/docs/examples/gaussianrecipe.py @@ -124,7 +124,7 @@ def makeRecipe(): # contribution by name. Since we told the contribution that our # independent variable is named "x", this value will be substituted into # the fitting equation whenever it is called. - contribution.setEquation("A * exp(-0.5*(x-x0)**2/sigma**2)") + contribution.set_equation("A * exp(-0.5*(x-x0)**2/sigma**2)") # To demonstrate how these parameters are used, we will give "A" an initial # value. Note that Parameters are not numbers, but are containers for diff --git a/docs/examples/interface.py b/docs/examples/interface.py index 4611ee6b..640aebc0 100644 --- a/docs/examples/interface.py +++ b/docs/examples/interface.py @@ -38,7 +38,7 @@ def main(): # "<<" - Inject a parameter value c = FitContribution("g1") c.set_profile(p) - c.setEquation("A * exp(-0.5*(x-x0)**2/sigma**2)") + c.set_equation("A * exp(-0.5*(x-x0)**2/sigma**2)") c.A << 0.5 c.x0 << 5 c.sigma << 1 diff --git a/docs/examples/npintensity.py b/docs/examples/npintensity.py index c193922e..2b1624a2 100644 --- a/docs/examples/npintensity.py +++ b/docs/examples/npintensity.py @@ -256,7 +256,7 @@ def gaussian(q, q0, width): # convolve the signal with the Gaussian to broaden it. Recall that we don't # need to supply arguments to the registered functions unless we want to # make changes to their input values. - contribution.setEquation("scale * convolve(I, gaussian) + bkgd") + contribution.set_equation("scale * convolve(I, gaussian) + bkgd") # Make the FitRecipe and add the FitContribution. recipe = FitRecipe() diff --git a/docs/examples/npintensityII.py b/docs/examples/npintensityII.py index 552eba96..2390d352 100644 --- a/docs/examples/npintensityII.py +++ b/docs/examples/npintensityII.py @@ -125,8 +125,8 @@ def gaussian(q, q0, width): # Now we can incorporate the scale and bkgd into our calculation. We also # convolve the signal with the gaussian to broaden it. - contribution1.setEquation("scale * convolve(I, gaussian) + bkgd") - contribution2.setEquation("scale * convolve(I, gaussian) + bkgd") + contribution1.set_equation("scale * convolve(I, gaussian) + bkgd") + contribution2.set_equation("scale * convolve(I, gaussian) + bkgd") # Make a FitRecipe and associate the FitContributions. recipe = FitRecipe() diff --git a/docs/examples/nppdfcrystal.py b/docs/examples/nppdfcrystal.py index 49ed32e6..8a9e8667 100644 --- a/docs/examples/nppdfcrystal.py +++ b/docs/examples/nppdfcrystal.py @@ -62,7 +62,7 @@ def makeRecipe(ciffile, grdata): pdfcontribution.registerFunction(sphericalCF, name="f") # Now we set up the fitting equation. - pdfcontribution.setEquation("f * G") + pdfcontribution.set_equation("f * G") # Now make the recipe. Make sure we fit the characteristic function shape # parameters, in this case 'psize', which is the diameter of the particle. diff --git a/docs/examples/nppdfsas.py b/docs/examples/nppdfsas.py index 665e2377..98a8cde7 100644 --- a/docs/examples/nppdfsas.py +++ b/docs/examples/nppdfsas.py @@ -89,7 +89,7 @@ def makeRecipe(ciffile, grdata, iqdata): pdfcontribution.registerCalculator(cfcalculator) # The PDF for a nanoscale crystalline is approximated by # Gnano = f * Gcryst - pdfcontribution.setEquation("f * G") + pdfcontribution.set_equation("f * G") # Moving on recipe = FitRecipe() diff --git a/docs/examples/simplerecipe.py b/docs/examples/simplerecipe.py index 0ec297a5..ef1f9a5e 100644 --- a/docs/examples/simplerecipe.py +++ b/docs/examples/simplerecipe.py @@ -38,7 +38,7 @@ def main(): # Set the equation. The variable "x" is taken from the data that was just # loaded. The other variables, "A", "x0" and "sigma" are turned into # attributes with an initial value of 0. - recipe.setEquation("A * exp(-0.5*(x-x0)**2/sigma**2)") + recipe.set_equation("A * exp(-0.5*(x-x0)**2/sigma**2)") # We can give them other values here. recipe.A = 1 diff --git a/docs/examples/threedoublepeaks.py b/docs/examples/threedoublepeaks.py index 60f16f64..fa45e2de 100644 --- a/docs/examples/threedoublepeaks.py +++ b/docs/examples/threedoublepeaks.py @@ -77,7 +77,7 @@ def delta(t, mu): contribution.registerStringFunction(bkgdstr, "bkgd") # Now define our fitting equation. We will hardcode the peak ratios. - contribution.setEquation( + contribution.set_equation( "A1 * ( convolve( delta(t, mu11), peakshape(t, c, sig11) ) \ + 0.23*convolve( delta(t, mu12), peakshape(t, c, sig12) ) ) + \ A2 * ( convolve( delta(t, mu21), peakshape(t, c, sig21) ) \ diff --git a/src/diffpy/srfit/fitbase/fitcontribution.py b/src/diffpy/srfit/fitbase/fitcontribution.py index 71048092..9b887bbb 100644 --- a/src/diffpy/srfit/fitbase/fitcontribution.py +++ b/src/diffpy/srfit/fitbase/fitcontribution.py @@ -41,6 +41,13 @@ removal_version, ) +setequation_dep_msg = build_deprecation_message( + base, + "setEquation", + "set_equation", + removal_version, +) + class FitContribution(ParameterSet): """FitContribution class. @@ -223,7 +230,7 @@ def addProfileGenerator(self, gen, name=None): return - def setEquation(self, eqstr, ns={}): + def set_equation(self, eqstr, ns={}): """Set the profile equation for the FitContribution. This sets the equation that will be used when generating the residual @@ -266,6 +273,17 @@ def setEquation(self, eqstr, ns={}): return + @deprecated(setequation_dep_msg) + def setEquation(self, eqstr, ns={}): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitContribution.set_equation + instead. + """ + self.set_equation(eqstr, ns=ns) + return + def getEquation(self): """Get math expression string for the active profile equation. diff --git a/src/diffpy/srfit/fitbase/simplerecipe.py b/src/diffpy/srfit/fitbase/simplerecipe.py index 81a0094a..6a857d62 100644 --- a/src/diffpy/srfit/fitbase/simplerecipe.py +++ b/src/diffpy/srfit/fitbase/simplerecipe.py @@ -201,7 +201,7 @@ def loadtxt(self, *args, **kw): return self.profile.loadtxt(*args, **kw) # FitContribution - def setEquation(self, eqstr, ns={}): + def set_equation(self, eqstr, ns={}): """Set the profile equation for the FitContribution. This sets the equation that will be used when generating the residual. @@ -222,7 +222,7 @@ def setEquation(self, eqstr, ns={}): Raises ValueError if ns uses a name that is already used for a variable. """ - self.contribution.setEquation(eqstr, ns={}) + self.contribution.set_equation(eqstr, ns={}) # Extract variables for par in self.contribution: # Skip Profile Parameters diff --git a/src/diffpy/srfit/pdf/pdfcontribution.py b/src/diffpy/srfit/pdf/pdfcontribution.py index bcd694ff..1b4cfe3e 100644 --- a/src/diffpy/srfit/pdf/pdfcontribution.py +++ b/src/diffpy/srfit/pdf/pdfcontribution.py @@ -280,7 +280,7 @@ def _setup_generator(self, gen): gnames = self._generators.keys() eqstr = " + ".join(gnames) eqstr = "scale * (%s)" % eqstr - self.setEquation(eqstr) + self.set_equation(eqstr) # Update with our metadata gen.meta.update(self._meta) diff --git a/tests/conftest.py b/tests/conftest.py index f251746f..c9ace579 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -155,7 +155,7 @@ def build_recipe_one_contribution(): profile.setObservedProfile(x, y) contribution = FitContribution("c1") contribution.set_profile(profile) - contribution.setEquation("A*sin(k*x + c)") + contribution.set_equation("A*sin(k*x + c)") recipe = FitRecipe() recipe.addContribution(contribution) recipe.addVar(contribution.A, 1) @@ -173,14 +173,14 @@ def build_recipe_two_contributions(): profile1.setObservedProfile(x, y1) contribution1 = FitContribution("c1") contribution1.set_profile(profile1) - contribution1.setEquation("A*sin(k*x + c)") + contribution1.set_equation("A*sin(k*x + c)") profile2 = Profile() y2 = 0.5 * sin(2 * x) profile2.setObservedProfile(x, y2) contribution2 = FitContribution("c2") contribution2.set_profile(profile2) - contribution2.setEquation("B*sin(m*x + d)") + contribution2.set_equation("B*sin(m*x + d)") recipe = FitRecipe() recipe.addContribution(contribution1) recipe.addContribution(contribution2) diff --git a/tests/test_contribution.py b/tests/test_contribution.py index 1332de33..114c39af 100644 --- a/tests/test_contribution.py +++ b/tests/test_contribution.py @@ -50,7 +50,7 @@ def testset_profile(self): self.assertRaises(TypeError, fc1.setProfile, "invalid") # check if residual equation is set up when possible fc2 = FitContribution("test2") - fc2.setEquation("A * x") + fc2.set_equation("A * x") fc2.set_profile(profile) self.assertFalse(fc2._reseq is None) return @@ -148,7 +148,7 @@ def test_getResidualEquation(self): fc = self.fitcontribution self.assertEqual("", fc.getResidualEquation()) fc.set_profile(self.profile) - fc.setEquation("A * x + B") + fc.set_equation("A * x + B") self.assertEqual("((eq - y) / dy)", fc.getResidualEquation()) fc.setResidualEquation("2 * (eq - y)") self.assertEqual("(2 * (eq - y))", fc.getResidualEquation()) @@ -159,7 +159,7 @@ def test_releaseOldEquations(self): fc = self.fitcontribution self.assertEqual(0, len(fc._eqfactory.equations)) for i in range(5): - fc.setEquation("A * x + B") + fc.set_equation("A * x + B") self.assertEqual(1, len(fc._eqfactory.equations)) fc.set_profile(self.profile) for i in range(5): @@ -168,15 +168,15 @@ def test_releaseOldEquations(self): return def test_registerFunction(self): - """Ensure registered function works after second setEquation call.""" + """Ensure registered function works after second set_equation call.""" fc = self.fitcontribution fc.registerFunction(_fsquare, name="fsquare") - fc.setEquation("fsquare") + fc.set_equation("fsquare") fc.x.setValue(5) self.assertEqual(25, fc.evaluate()) fc.x << 6 self.assertEqual(36, fc.evaluate()) - fc.setEquation("fsquare + 5") + fc.set_equation("fsquare + 5") self.assertEqual(41, fc.evaluate()) fc.x << -1 self.assertEqual(6, fc.evaluate()) @@ -215,7 +215,7 @@ def testResidual(noObserversInGlobalBuilders): assert dot(chiv, chiv) == pytest.approx(0) # Now change the equation - fc.setEquation("2*I") + fc.set_equation("2*I") assert fc._eq._value is None assert fc._reseq._value is None chiv = fc.residual() @@ -224,7 +224,7 @@ def testResidual(noObserversInGlobalBuilders): # Try to add a parameter c = Parameter("c", 2) fc._add_parameter(c) - fc.setEquation("c*I") + fc.set_equation("c*I") assert fc._eq._value is None assert fc._reseq._value is None chiv = fc.residual() @@ -232,7 +232,7 @@ def testResidual(noObserversInGlobalBuilders): # Try something more complex c.setValue(3) - fc.setEquation("c**2*sin(I)") + fc.set_equation("c**2*sin(I)") assert fc._eq._value is None assert fc._reseq._value is None xobs = arange(0, 10, 0.5) @@ -245,7 +245,7 @@ def testResidual(noObserversInGlobalBuilders): assert dot(chiv, chiv) == pytest.approx(0) # Choose a new residual. - fc.setEquation("2*I") + fc.set_equation("2*I") fc.setResidualEquation("resv") chiv = fc.residual() assert dot(chiv, chiv) == pytest.approx( @@ -264,7 +264,7 @@ def testResidual(noObserversInGlobalBuilders): fc1.set_profile(profile) with pytest.raises(SrFitError): fc1.setResidualEquation("chiv") - fc1.setEquation("A * x") + fc1.set_equation("A * x") fc1.setResidualEquation("chiv") assert noObserversInGlobalBuilders return @@ -284,6 +284,20 @@ def test_setEquation(noObserversInGlobalBuilders): return +def test_set_equation(noObserversInGlobalBuilders): + """Check replacement of removed parameters.""" + fc = FitContribution("test") + fc.set_equation("x + 5") + fc.x.setValue(2) + assert 7 == fc.evaluate() + fc.removeParameter(fc.x) + x = arange(0, 10, 0.5) + fc.newParameter("x", x) + assert np.array_equal(5 + x, fc.evaluate()) + assert noObserversInGlobalBuilders + return + + def test_getEquation(noObserversInGlobalBuilders): """Check getting the current profile simulation formula.""" fc = FitContribution("test") diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 53fe7d72..b22c421c 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -46,7 +46,7 @@ def setUp(self): # Set up the FitContribution self.fitcontribution = FitContribution("cont") self.fitcontribution.set_profile(self.profile) - self.fitcontribution.setEquation("A*sin(k*x + c)") + self.fitcontribution.set_equation("A*sin(k*x + c)") self.fitcontribution.A.setValue(1) self.fitcontribution.k.setValue(1) self.fitcontribution.c.setValue(0) @@ -233,12 +233,12 @@ def testResidual(self): # Now try to use the observed profile inside of the equation # Set the equation equal to the data - self.fitcontribution.setEquation("y") + self.fitcontribution.set_equation("y") res = self.recipe.residual() self.assertAlmostEqual(0, dot(res, res)) # Now add the uncertainty. This should give dy/dy = 1 for the residual - self.fitcontribution.setEquation("y+dy") + self.fitcontribution.set_equation("y+dy") res = self.recipe.residual() self.assertAlmostEqual(len(res), dot(res, res)) @@ -263,7 +263,7 @@ def testPrintFitHook(capturestdout): # Set up the FitContribution fitcontribution = FitContribution("cont") fitcontribution.set_profile(profile) - fitcontribution.setEquation("A*sin(k*x + c)") + fitcontribution.set_equation("A*sin(k*x + c)") fitcontribution.A.setValue(1) fitcontribution.k.setValue(1) fitcontribution.c.setValue(0) @@ -325,7 +325,7 @@ def build_recipe_from_datafile(datafile): contribution = FitContribution("c") contribution.set_profile(profile) - contribution.setEquation("m*x + b") + contribution.set_equation("m*x + b") recipe = FitRecipe() recipe.addContribution(contribution) recipe.addVar(contribution.m, 1) diff --git a/tests/test_weakrefcallable.py b/tests/test_weakrefcallable.py index 5d44d18b..fd3488ac 100644 --- a/tests/test_weakrefcallable.py +++ b/tests/test_weakrefcallable.py @@ -29,7 +29,7 @@ class TestWeakBoundMethod(unittest.TestCase): def setUp(self): self.f = FitContribution("f") - self.f.setEquation("7") + self.f.set_equation("7") self.w = weak_ref(self.f._eq._flush, fallback=_fallback_example) return @@ -112,7 +112,7 @@ def test_observable_deregistration(self): """Check if Observable drops dead Observer.""" f = self.f x = f.newParameter("x", 5) - f.setEquation("3 * x") + f.set_equation("3 * x") self.assertEqual(15, f.evaluate()) self.assertEqual(15, f._eq._value) # get one of the observer callables that are associated with f From f435f4aa270742a54cf27436b9aca11c27b30cdc Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Feb 2026 14:24:13 -0500 Subject: [PATCH 010/193] more set_equation replacements --- src/diffpy/srfit/fitbase/fitcontribution.py | 2 +- tests/test_contribution.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitcontribution.py b/src/diffpy/srfit/fitbase/fitcontribution.py index 9b887bbb..97a26c81 100644 --- a/src/diffpy/srfit/fitbase/fitcontribution.py +++ b/src/diffpy/srfit/fitbase/fitcontribution.py @@ -226,7 +226,7 @@ def addProfileGenerator(self, gen, name=None): # Make this our equation if we don't have one. This will set the # residual equation if necessary. if self._eq is None: - self.setEquation(name) + self.set_equation(name) return diff --git a/tests/test_contribution.py b/tests/test_contribution.py index 114c39af..de004fe4 100644 --- a/tests/test_contribution.py +++ b/tests/test_contribution.py @@ -302,7 +302,7 @@ def test_getEquation(noObserversInGlobalBuilders): """Check getting the current profile simulation formula.""" fc = FitContribution("test") assert "" == fc.getEquation() - fc.setEquation("A * sin(x + 5)") + fc.set_equation("A * sin(x + 5)") assert "(A * sin((x + 5)))" == fc.getEquation() assert noObserversInGlobalBuilders return From 1f41bc9da34fb5e44cd3e4bc30e1f61ea04f5604 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Feb 2026 14:24:56 -0500 Subject: [PATCH 011/193] news --- news/setequation-dep.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/setequation-dep.rst diff --git a/news/setequation-dep.rst b/news/setequation-dep.rst new file mode 100644 index 00000000..cb6fe13b --- /dev/null +++ b/news/setequation-dep.rst @@ -0,0 +1,23 @@ +**Added:** + +* Added ``set_equation`` method to replace ``setEquation``. + +**Changed:** + +* + +**Deprecated:** + +* Deprecated ``setEquation`` for removal in 4.0.0. + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From f18871bf6edfb7dd8a91d6ab93d615f0f270a933 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Feb 2026 14:26:41 -0500 Subject: [PATCH 012/193] reorder dep message to prevent merge conflicts --- src/diffpy/srfit/fitbase/fitcontribution.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitcontribution.py b/src/diffpy/srfit/fitbase/fitcontribution.py index 97a26c81..b00b66ec 100644 --- a/src/diffpy/srfit/fitbase/fitcontribution.py +++ b/src/diffpy/srfit/fitbase/fitcontribution.py @@ -34,17 +34,18 @@ base = "diffpy.srfit.fitbase.FitContribution" removal_version = "4.0.0" -setprofile_dep_msg = build_deprecation_message( +setequation_dep_msg = build_deprecation_message( base, - "setProfile", - "set_profile", + "setEquation", + "set_equation", removal_version, ) -setequation_dep_msg = build_deprecation_message( + +setprofile_dep_msg = build_deprecation_message( base, - "setEquation", - "set_equation", + "setProfile", + "set_profile", removal_version, ) From a6a7316ae476bc0a808590fcff3ea688459fa3a4 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 8 Feb 2026 13:54:18 -0500 Subject: [PATCH 013/193] one final setEquation switch in tests --- tests/test_fitrecipe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index ec5ab72b..60ed9e1f 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -311,7 +311,7 @@ def test_add_contribution(capturestdout): # Set up the FitContribution fitcontribution = FitContribution("cont") fitcontribution.set_profile(profile) - fitcontribution.setEquation("A*sin(k*x + c)") + fitcontribution.set_equation("A*sin(k*x + c)") fitcontribution.A.setValue(1) fitcontribution.k.setValue(1) fitcontribution.c.setValue(0) From b3446b8639b732668c3d596206f15435062c61cf Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 8 Feb 2026 14:31:52 -0500 Subject: [PATCH 014/193] pushFitHook deprecation --- docs/examples/coreshellnp.py | 2 +- docs/source/extending.rst | 2 +- src/diffpy/srfit/fitbase/fithook.py | 8 ++++---- src/diffpy/srfit/fitbase/fitrecipe.py | 16 +++++++++++++++- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/docs/examples/coreshellnp.py b/docs/examples/coreshellnp.py index 3f8d5b06..6e8e7af8 100644 --- a/docs/examples/coreshellnp.py +++ b/docs/examples/coreshellnp.py @@ -169,7 +169,7 @@ def main(): recipe = makeRecipe(stru1, stru2, data) from diffpy.srfit.fitbase.fithook import PlotFitHook - recipe.pushFitHook(PlotFitHook()) + recipe.push_fit_hook(PlotFitHook()) recipe.fithooks[0].verbose = 3 # Optimize - we do this in steps to help convergence diff --git a/docs/source/extending.rst b/docs/source/extending.rst index 6e3563de..a7a10be8 100644 --- a/docs/source/extending.rst +++ b/docs/source/extending.rst @@ -263,5 +263,5 @@ overload. * .. automethod:: FitHook.postcall To use a custom ``FitHook``, assign an instance to a ``FitRecipe`` using the -``pushFitHook`` method. All ``FitHook`` instances held by a ``FitRecipe`` will +``push_fit_hook`` method. All ``FitHook`` instances held by a ``FitRecipe`` will be used in sequence during a call to ``FitRecipe.residual``. diff --git a/src/diffpy/srfit/fitbase/fithook.py b/src/diffpy/srfit/fitbase/fithook.py index 14c5811c..be8cdf7c 100644 --- a/src/diffpy/srfit/fitbase/fithook.py +++ b/src/diffpy/srfit/fitbase/fithook.py @@ -37,10 +37,10 @@ class FitHook(object): """Base class for inspecting the progress of a FitRecipe refinement. Can serve as a fithook for the FitRecipe class (see - FitRecipe.pushFitHook method.) The methods in this class are called - during the preparation of the FitRecipe for refinement, and during - the residual call. See the class methods for a description of their - purpose. + FitRecipe.push_fit_hook method.) The methods in this class are + called during the preparation of the FitRecipe for refinement, and + during the residual call. See the class methods for a description of + their purpose. """ def reset(self, recipe): diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 4568f7a7..5ff73ef4 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -55,6 +55,10 @@ base, "addContribution", "add_contribution", removal_version ) +pushfithook_dep_msg = build_deprecation_message( + base, "pushFitHook", "push_fit_hook", removal_version +) + class FitRecipe(_fitrecipe_interface, RecipeOrganizer): """FitRecipe class. @@ -191,7 +195,7 @@ def __init__(self, name="fit"): } return - def pushFitHook(self, fithook, index=None): + def push_fit_hook(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, @@ -214,6 +218,16 @@ def pushFitHook(self, fithook, index=None): self._update_configuration() return + @deprecated(pushfithook_dep_msg) + def pushFitHook(self, fithook, index=None): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.push_fit_hook instead. + """ + self.push_fit_hook(fithook, index) + return + def popFitHook(self, fithook=None, index=-1): """Remove a FitHook by index or reference. From 520e94bce7d13cafef3812d9b55d7402f8366177 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 8 Feb 2026 14:33:31 -0500 Subject: [PATCH 015/193] popFitHook deprecation --- src/diffpy/srfit/fitbase/fitrecipe.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 5ff73ef4..4b709fa8 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -59,6 +59,10 @@ base, "pushFitHook", "push_fit_hook", removal_version ) +popfithook_dep_msg = build_deprecation_message( + base, "popFitHook", "pop_fit_hook", removal_version +) + class FitRecipe(_fitrecipe_interface, RecipeOrganizer): """FitRecipe class. @@ -228,7 +232,7 @@ def pushFitHook(self, fithook, index=None): self.push_fit_hook(fithook, index) return - def popFitHook(self, fithook=None, index=-1): + def pop_fit_hook(self, fithook=None, index=-1): """Remove a FitHook by index or reference. Attributes @@ -250,6 +254,15 @@ def popFitHook(self, fithook=None, index=-1): self.fithook.remove(index) return + def popFitHook(self, fithook=None, index=-1): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.pop_fit_hook instead. + """ + self.pop_fit_hook(fithook, index) + return + def getFitHooks(self): """Get the sequence of FitHook instances.""" return self.fithooks[:] From 61195e3fdd4ee1bae23af12844185c430151b04b Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 8 Feb 2026 14:33:52 -0500 Subject: [PATCH 016/193] popFitHook dep message --- src/diffpy/srfit/fitbase/fitrecipe.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 4b709fa8..f1741caa 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -254,6 +254,7 @@ def pop_fit_hook(self, fithook=None, index=-1): self.fithook.remove(index) return + @deprecated(popfithook_dep_msg) def popFitHook(self, fithook=None, index=-1): """This function has been deprecated and will be removed in version 4.0.0. From ca3d83e8e52fbae78d7e6a21f1d1cb739882889f Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 8 Feb 2026 14:39:17 -0500 Subject: [PATCH 017/193] getFitHooks and clearFitHooks deprecation --- src/diffpy/srfit/fitbase/fitrecipe.py | 29 +++++++++++++++++++++++++-- tests/test_fitrecipe.py | 2 +- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index f1741caa..b6a10194 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -63,6 +63,14 @@ base, "popFitHook", "pop_fit_hook", removal_version ) +getfithooks_dep_msg = build_deprecation_message( + base, "getFitHooks", "get_fit_hooks", removal_version +) + +clearfithooks_dep_msg = build_deprecation_message( + base, "clearFitHooks", "clear_fit_hooks", removal_version +) + class FitRecipe(_fitrecipe_interface, RecipeOrganizer): """FitRecipe class. @@ -264,15 +272,32 @@ def popFitHook(self, fithook=None, index=-1): self.pop_fit_hook(fithook, index) return - def getFitHooks(self): + def get_fit_hooks(self): """Get the sequence of FitHook instances.""" return self.fithooks[:] - def clearFitHooks(self): + @deprecated(getfithooks_dep_msg) + def getFitHooks(self): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.get_fit_hooks instead.""" + return self.get_fit_hooks() + + def clear_fit_hooks(self): """Clear the FitHook sequence.""" del self.fithooks[:] return + @deprecated(clearfithooks_dep_msg) + def clearFitHooks(self): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.clear_fit_hooks instead.""" + self.clear_fit_hooks() + return + def add_contribution(self, con, weight=1.0): """Add a FitContribution to the FitRecipe. diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 0f8761ac..39345fb6 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -320,7 +320,7 @@ def test_add_contribution(capturestdout): recipe.addVar(fitcontribution.c) recipe.restrain("c", lb=5) - (pfh,) = recipe.getFitHooks() + (pfh,) = recipe.get_fit_hooks() out = capturestdout(recipe.scalarResidual) assert "" == out pfh.verbose = 1 From 9296fc6786d7e82245d3409090671c5fd704c1da Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 8 Feb 2026 14:42:17 -0500 Subject: [PATCH 018/193] setWeight deprecation --- docs/examples/npintensityII.py | 8 ++++---- docs/examples/nppdfsas.py | 10 +++++----- src/diffpy/srfit/fitbase/fitrecipe.py | 15 ++++++++++++++- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/docs/examples/npintensityII.py b/docs/examples/npintensityII.py index d3bd4ef5..e27ef3cb 100644 --- a/docs/examples/npintensityII.py +++ b/docs/examples/npintensityII.py @@ -248,17 +248,17 @@ def main(): # fit. recipe.fix("all") recipe.free("bcoeffs1") - recipe.setWeight(recipe.bucky2, 0) + recipe.set_weight(recipe.bucky2, 0) scipyOptimize(recipe) # Now do the same for the second background recipe.fix("all") recipe.free("bcoeffs1") - recipe.setWeight(recipe.bucky2, 1) - recipe.setWeight(recipe.bucky1, 0) + recipe.set_weight(recipe.bucky2, 1) + recipe.set_weight(recipe.bucky1, 0) scipyOptimize(recipe) # Now refine everything with the structure parameters included recipe.free("all") - recipe.setWeight(recipe.bucky1, 1) + recipe.set_weight(recipe.bucky1, 1) scipyOptimize(recipe) # Generate and print the FitResults diff --git a/docs/examples/nppdfsas.py b/docs/examples/nppdfsas.py index acd6fac7..8e0aa2b1 100644 --- a/docs/examples/nppdfsas.py +++ b/docs/examples/nppdfsas.py @@ -122,7 +122,7 @@ def fitRecipe(recipe): """We refine in stages to help the refinement converge.""" # Tune SAS. - recipe.setWeight(recipe.pdf, 0) + recipe.set_weight(recipe.pdf, 0) recipe.fix("all") recipe.free("radius_a", "radius_b", iqscale=1e8) recipe.constrain("radius_b", "radius_a") @@ -130,15 +130,15 @@ def fitRecipe(recipe): recipe.unconstrain("radius_b") # Tune PDF - recipe.setWeight(recipe.pdf, 1) - recipe.setWeight(recipe.sas, 0) + recipe.set_weight(recipe.pdf, 1) + recipe.set_weight(recipe.sas, 0) recipe.fix("all") recipe.free("a", "Biso_0", "scale", "delta2") scipyOptimize(recipe) # Tune all - recipe.setWeight(recipe.pdf, 1) - recipe.setWeight(recipe.sas, 1) + recipe.set_weight(recipe.pdf, 1) + recipe.set_weight(recipe.sas, 1) recipe.free("all") scipyOptimize(recipe) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index b6a10194..7bb29b8e 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -71,6 +71,10 @@ base, "clearFitHooks", "clear_fit_hooks", removal_version ) +setweight_dep_msg = build_deprecation_message( + base, "setWeight", "set_weight", removal_version +) + class FitRecipe(_fitrecipe_interface, RecipeOrganizer): """FitRecipe class. @@ -326,12 +330,21 @@ def addContribution(self, con, weight=1.0): self.add_contribution(con, weight) return - def setWeight(self, con, weight): + def set_weight(self, con, weight): """Set the weight of a FitContribution.""" idx = list(self._contributions.values()).index(con) self._weights[idx] = weight return + @deprecated(setweight_dep_msg) + def setWeight(self, con, weight): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.set_weight instead.""" + self.set_weight(con, weight) + return + def addParameterSet(self, parset): """Add a ParameterSet to the hierarchy. From 2af8782ac7f3c8b7fea4a88dbed58ce27421fd86 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 8 Feb 2026 14:50:29 -0500 Subject: [PATCH 019/193] news --- news/fithook-and-weights-dep.rst | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 news/fithook-and-weights-dep.rst diff --git a/news/fithook-and-weights-dep.rst b/news/fithook-and-weights-dep.rst new file mode 100644 index 00000000..cc3971b6 --- /dev/null +++ b/news/fithook-and-weights-dep.rst @@ -0,0 +1,27 @@ +**Added:** + +* Added ``set_weight`` method to ``FitRecipe`` to replace ``setWeight``. +* Added ``get_fit_hooks`` method to ``FitRecipe`` to replace ``getFitHooks``. +* Added ``clear_fit_hooks`` method to ``FitRecipe`` to replace ``clearFitHooks``. +* Added ``pop_fit_hook`` method to ``FitRecipe`` to replace ``popFitHook``. +* Added ``push_fit_hook`` method to ``FitRecipe`` to replace ``pushFitHook``. + +**Changed:** + +* + +**Deprecated:** + +* Deprecate ``setWeight``, ``getFitHooks``, ``clearFitHooks``, ``popFitHook``, and ``pushFitHook`` in ``FitRecipe`` for removal in 4.0.0. + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 69ecbb5e493e286e2b43745c9087f83dea3420f5 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 8 Feb 2026 14:53:27 -0500 Subject: [PATCH 020/193] news pt2 --- news/fithook-and-weights-dep.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/news/fithook-and-weights-dep.rst b/news/fithook-and-weights-dep.rst index cc3971b6..43157e5a 100644 --- a/news/fithook-and-weights-dep.rst +++ b/news/fithook-and-weights-dep.rst @@ -12,7 +12,11 @@ **Deprecated:** -* Deprecate ``setWeight``, ``getFitHooks``, ``clearFitHooks``, ``popFitHook``, and ``pushFitHook`` in ``FitRecipe`` for removal in 4.0.0. +* Deprecated ``setWeight`` in ``FitRecipe`` for removal in 4.0.0. +* Deprecated ``getFitHooks`` in ``FitRecipe`` for removal in 4.0.0. +* Deprecated ``clearFitHooks`` in ``FitRecipe`` for removal in 4.0.0. +* Deprecated ``popFitHook`` in ``FitRecipe`` for removal in 4.0.0. +* Deprecated ``pushFitHook`` in ``FitRecipe`` for removal in 4.0.0. **Removed:** From 3d8da329471ce4000ebf10ca01acab8e4732a8d5 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 9 Feb 2026 10:56:52 -0500 Subject: [PATCH 021/193] addParameterSet deprecation --- docs/examples/npintensity.py | 6 ++--- docs/examples/npintensityII.py | 5 ++-- src/diffpy/srfit/fitbase/fitrecipe.py | 16 ++++++++++++- src/diffpy/srfit/fitbase/parameterset.py | 22 ++++++++++++++++- src/diffpy/srfit/pdf/basepdfgenerator.py | 2 +- src/diffpy/srfit/structure/cctbxparset.py | 4 ++-- src/diffpy/srfit/structure/diffpyparset.py | 4 ++-- src/diffpy/srfit/structure/objcrystparset.py | 4 ++-- tests/test_parameterset.py | 25 ++++++++++++++++++-- 9 files changed, 72 insertions(+), 16 deletions(-) diff --git a/docs/examples/npintensity.py b/docs/examples/npintensity.py index e5a50c87..a1c6ffc2 100644 --- a/docs/examples/npintensity.py +++ b/docs/examples/npintensity.py @@ -32,9 +32,9 @@ Extensions -- The IntensityGenerator class uses the 'addParameterSet' method to associate +- The IntensityGenerator class uses the 'add_parameter_set' method to associate the structure adapter (DiffpyStructureParSet) with the generator. Most SrFit - classes have an 'addParameterSet' class and can store ParameterSet objects. + classes have an 'add_parameter_set' class and can store ParameterSet objects. Grab the phase object from the IntensityGenerator and try to add it to other objects used in the fit recipe. Create variables from the moved Parameters rather than from the 'phase' that lives in the IntensityGenerator and see if @@ -153,7 +153,7 @@ def setStructure(self, strufile): parset = DiffpyStructureParSet("phase", stru) # Put this ParameterSet in the ProfileGenerator. - self.addParameterSet(parset) + self.add_parameter_set(parset) return diff --git a/docs/examples/npintensityII.py b/docs/examples/npintensityII.py index a9ce06d9..8364a113 100644 --- a/docs/examples/npintensityII.py +++ b/docs/examples/npintensityII.py @@ -83,7 +83,7 @@ def makeRecipe(strufile, datname1, datname2): generator1 = IntensityGenerator("I") generator1.setStructure(strufile) generator2 = IntensityGenerator("I") - generator2.addParameterSet(generator1.phase) + generator2.add_parameter_set(generator1.phase) # The FitContributions # Create the FitContributions. @@ -99,7 +99,8 @@ def makeRecipe(strufile, datname1, datname2): # the same form and use the same Parameter names. By default, Parameters # in different contributions are different Parameters even if they have the # same names. FitContributions are isolated namespaces than only share - # information if you tell them to by using addParameter or addParameterSet. + # information if you tell them to by using addParameter or + # add_parameter_set. bkgdstr = "b0 + b1*q + b2*q**2 + b3*q**3 + b4*q**4 + b5*q**5 + b6*q**6 +\ b7*q**7 +b8*q**8 + b9*q**9" diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 7bb29b8e..7065968e 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -75,6 +75,10 @@ base, "setWeight", "set_weight", removal_version ) +addparset_dep_msg = build_deprecation_message( + base, "addParameterSet", "add_parameter_set", removal_version +) + class FitRecipe(_fitrecipe_interface, RecipeOrganizer): """FitRecipe class. @@ -345,7 +349,7 @@ def setWeight(self, con, weight): self.set_weight(con, weight) return - def addParameterSet(self, parset): + def add_parameter_set(self, parset): """Add a ParameterSet to the hierarchy. Attributes @@ -361,6 +365,16 @@ def addParameterSet(self, parset): self._add_object(parset, self._parsets, True) return + @deprecated(addparset_dep_msg) + def addParameterSet(self, parset): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.add_parameter_set instead. + """ + self.add_parameter_set(parset) + return + def removeParameterSet(self, parset): """Remove a ParameterSet from the hierarchy. diff --git a/src/diffpy/srfit/fitbase/parameterset.py b/src/diffpy/srfit/fitbase/parameterset.py index ce89326f..918951da 100644 --- a/src/diffpy/srfit/fitbase/parameterset.py +++ b/src/diffpy/srfit/fitbase/parameterset.py @@ -25,6 +25,14 @@ from collections import OrderedDict from diffpy.srfit.fitbase.recipeorganizer import RecipeOrganizer +from diffpy.utils._deprecator import build_deprecation_message, deprecated + +base = "diffpy.srfit.fitbase.parameterset.ParameterSet" +removal_version = "4.0.0" + +addparset_dep_msg = build_deprecation_message( + base, "addParameterSet", "add_parameter_set", removal_version +) class ParameterSet(RecipeOrganizer): @@ -87,7 +95,7 @@ def __init__(self, name): newParameter = RecipeOrganizer._new_parameter removeParameter = RecipeOrganizer._remove_parameter - def addParameterSet(self, parset): + def add_parameter_set(self, parset): """Add a ParameterSet to the hierarchy. Attributes @@ -103,6 +111,18 @@ def addParameterSet(self, parset): self._add_object(parset, self._parsets, True) return + @deprecated(addparset_dep_msg) + def addParameterSet(self, parset): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use + diffpy.srfit.fitbase.parameterset.ParameterSet.add_parameter_set + instead. + """ + self.add_parameter_set(parset) + return + def removeParameterSet(self, parset): """Remove a ParameterSet from the hierarchy. diff --git a/src/diffpy/srfit/pdf/basepdfgenerator.py b/src/diffpy/srfit/pdf/basepdfgenerator.py index e91023e8..9b915be7 100644 --- a/src/diffpy/srfit/pdf/basepdfgenerator.py +++ b/src/diffpy/srfit/pdf/basepdfgenerator.py @@ -277,7 +277,7 @@ def setPhase(self, parset, periodic=True): self.stru = self._phase.stru # Put this ParameterSet in the ProfileGenerator. - self.addParameterSet(parset) + self.add_parameter_set(parset) # Set periodicity self._phase.useSymmetry(periodic) diff --git a/src/diffpy/srfit/structure/cctbxparset.py b/src/diffpy/srfit/structure/cctbxparset.py index 2bb05c7d..e546e61d 100644 --- a/src/diffpy/srfit/structure/cctbxparset.py +++ b/src/diffpy/srfit/structure/cctbxparset.py @@ -237,7 +237,7 @@ def __init__(self, name, stru): """ ParameterSet.__init__(self, name) self.stru = stru - self.addParameterSet(CCTBXUnitCellParSet(self)) + self.add_parameter_set(CCTBXUnitCellParSet(self)) self.scatterers = [] self._update = False @@ -249,7 +249,7 @@ def __init__(self, name, stru): sname = "%s%i" % (el, i) cdict[el] = i + 1 scatterer = CCTBXScattererParSet(sname, self, i) - self.addParameterSet(scatterer) + self.add_parameter_set(scatterer) self.scatterers.append(scatterer) # Constrain the lattice diff --git a/src/diffpy/srfit/structure/diffpyparset.py b/src/diffpy/srfit/structure/diffpyparset.py index 6ed3beef..0a22685f 100644 --- a/src/diffpy/srfit/structure/diffpyparset.py +++ b/src/diffpy/srfit/structure/diffpyparset.py @@ -284,7 +284,7 @@ def __init__(self, name, stru): """ SrRealParSet.__init__(self, name) self.stru = stru - self.addParameterSet(DiffpyLatticeParSet(stru.lattice)) + self.add_parameter_set(DiffpyLatticeParSet(stru.lattice)) self.atoms = [] cdict = {} @@ -297,7 +297,7 @@ def __init__(self, name, stru): aname = "%s%i" % (el, i) cdict[el] = i + 1 atom = DiffpyAtomParSet(aname, a) - self.addParameterSet(atom) + self.add_parameter_set(atom) self.atoms.append(atom) return diff --git a/src/diffpy/srfit/structure/objcrystparset.py b/src/diffpy/srfit/structure/objcrystparset.py index 19213b43..8cb427b9 100644 --- a/src/diffpy/srfit/structure/objcrystparset.py +++ b/src/diffpy/srfit/structure/objcrystparset.py @@ -252,7 +252,7 @@ def __init__(self, name, molecule, parent=None): atom = ObjCrystMolAtomParSet(name, a, self) atom.molecule = self - self.addParameterSet(atom) + self.add_parameter_set(atom) self.atoms.append(atom) anames.append(name) @@ -1760,7 +1760,7 @@ def __init__(self, name, cryst): else: raise TypeError("Unrecognized scatterer '%s'" % cname) - self.addParameterSet(parset) + self.add_parameter_set(parset) self.scatterers.append(parset) snames.append(name) diff --git a/tests/test_parameterset.py b/tests/test_parameterset.py index 51ffa14c..97c98b51 100644 --- a/tests/test_parameterset.py +++ b/tests/test_parameterset.py @@ -27,14 +27,35 @@ def setUp(self): return def testAddParameterSet(self): - """Test the addParameterSet method.""" + """Test the deprecated addParameterSet method. + + Remove this test after the addParameterSet is removed. in + version 4.0.0. + """ parset2 = ParameterSet("parset2") p1 = Parameter("parset2", 1) self.parset.addParameterSet(parset2) self.assertTrue(self.parset.parset2 is parset2) - self.assertRaises(ValueError, self.parset.addParameterSet, p1) + self.assertRaises(ValueError, self.parset.add_parameter_set, p1) + + p1.name = "p1" + parset2.addParameter(p1) + + self.assertTrue(self.parset.parset2.p1 is p1) + + return + + def test_add_parameter_set(self): + """Test the add_parameter_set method.""" + parset2 = ParameterSet("parset2") + p1 = Parameter("parset2", 1) + + self.parset.add_parameter_set(parset2) + self.assertTrue(self.parset.parset2 is parset2) + + self.assertRaises(ValueError, self.parset.add_parameter_set, p1) p1.name = "p1" parset2.addParameter(p1) From 5564a1aec3fb11c4c51cd904c00fc09ff80619d2 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 9 Feb 2026 11:07:26 -0500 Subject: [PATCH 022/193] news --- news/addparameterset-dep.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 news/addparameterset-dep.rst diff --git a/news/addparameterset-dep.rst b/news/addparameterset-dep.rst new file mode 100644 index 00000000..f69da3c2 --- /dev/null +++ b/news/addparameterset-dep.rst @@ -0,0 +1,25 @@ +**Added:** + +* Added ``add_parameter_set`` method to replace deprecated ``FitRecipe.addParameterSet``. +* Added ``add_parameter_set`` method to replace deprecated ``ParameterSet.addParameterSet``. + +**Changed:** + +* + +**Deprecated:** + +* Deprecated ``addParameterSet`` method in ``FitRecipe``. +* Deprecate ``addParameterSet`` method in ``ParameterSet``. + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 46cf86254cafdd8616acd570a59b598d723f19a3 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 9 Feb 2026 11:09:03 -0500 Subject: [PATCH 023/193] docstring typo --- tests/test_parameterset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_parameterset.py b/tests/test_parameterset.py index 97c98b51..1a954c8d 100644 --- a/tests/test_parameterset.py +++ b/tests/test_parameterset.py @@ -29,8 +29,8 @@ def setUp(self): def testAddParameterSet(self): """Test the deprecated addParameterSet method. - Remove this test after the addParameterSet is removed. in - version 4.0.0. + Remove this test after the addParameterSet is removed in version + 4.0.0. """ parset2 = ParameterSet("parset2") p1 = Parameter("parset2", 1) From b336d062e3de590c4c35859281827a0c6cb6d729 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sat, 14 Feb 2026 18:41:49 -0500 Subject: [PATCH 024/193] deprecate getEquation in fitcontribution.py --- src/diffpy/srfit/fitbase/fitcontribution.py | 19 ++++++++++++++++++- tests/test_contribution.py | 12 +++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitcontribution.py b/src/diffpy/srfit/fitbase/fitcontribution.py index 9a4402ae..3672f697 100644 --- a/src/diffpy/srfit/fitbase/fitcontribution.py +++ b/src/diffpy/srfit/fitbase/fitcontribution.py @@ -56,6 +56,13 @@ removal_version, ) +getequation_dep_msg = build_deprecation_message( + base, + "getEquation", + "get_equation", + removal_version, +) + class FitContribution(ParameterSet): """FitContribution class. @@ -304,7 +311,7 @@ def setEquation(self, eqstr, ns={}): self.set_equation(eqstr, ns=ns) return - def getEquation(self): + def get_equation(self): """Get math expression string for the active profile equation. Return normalized math expression or an empty string if profile @@ -317,6 +324,16 @@ def getEquation(self): rv = getExpression(self._eq) return rv + @deprecated(getequation_dep_msg) + def getEquation(self): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitContribution.get_equation + instead. + """ + return self.get_equation() + def setResidualEquation(self, eqstr): """Set the residual equation for the FitContribution. diff --git a/tests/test_contribution.py b/tests/test_contribution.py index 7c167634..2863ac62 100644 --- a/tests/test_contribution.py +++ b/tests/test_contribution.py @@ -313,12 +313,22 @@ def test_set_equation(noObserversInGlobalBuilders): def test_getEquation(noObserversInGlobalBuilders): """Check getting the current profile simulation formula.""" fc = FitContribution("test") - assert "" == fc.getEquation() + assert "" == fc.get_equation() fc.set_equation("A * sin(x + 5)") assert "(A * sin((x + 5)))" == fc.getEquation() assert noObserversInGlobalBuilders return +def test_get_equation(noObserversInGlobalBuilders): + """Check getting the current profile simulation formula.""" + fc = FitContribution("test") + assert "" == fc.get_equation() + fc.set_equation("A * sin(x + 5)") + assert "(A * sin((x + 5)))" == fc.get_equation() + assert noObserversInGlobalBuilders + return + + if __name__ == "__main__": unittest.main() From b6e8c96f8abe2b025154644cfad7a003acb00e77 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sat, 14 Feb 2026 18:50:20 -0500 Subject: [PATCH 025/193] deprecate getEquation from builder.BaseBuilder --- src/diffpy/srfit/equation/builder.py | 29 ++++++++++++++++++++++++---- tests/test_builder.py | 12 ++++++------ 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/diffpy/srfit/equation/builder.py b/src/diffpy/srfit/equation/builder.py index 4485087f..c33e0ff6 100644 --- a/src/diffpy/srfit/equation/builder.py +++ b/src/diffpy/srfit/equation/builder.py @@ -53,12 +53,12 @@ > # sin is defined in this module as an OperatorBuilder > sin = getBuilder("sin") > beq = A*sin(a*x) -> eq = beq.getEquation() +> eq = beq.get_equation() The equation builder can also handle scalar constants. Staring with the above setup: > beq2 = A*sin(a*x) + 3 -> eq2 = beq2.getEquation() +> eq2 = beq2.get_equation() Here, we didn't have to wrap '3' in an ArgumentBuilder. Non scalars, constant or otherwise, must be wrapped as ArgumentBuilders in order to be used in this way. @@ -86,6 +86,7 @@ import diffpy.srfit.equation.literals as literals from diffpy.srfit.equation.equationmod import Equation from diffpy.srfit.equation.literals.literal import Literal +from diffpy.utils._deprecator import build_deprecation_message, deprecated __all__ = [ "EquationFactory", @@ -172,7 +173,7 @@ def makeEquation( lit = literals.Argument(value=beq, const=True) eq = Equation(name="", root=lit) else: - eq = beq.getEquation() + eq = beq.get_equation() self.equations.add(eq) return eq @@ -404,6 +405,16 @@ def _get_undefined_args(self, eqstr): # End class EquationFactory +base_basebuilder = "diffpy.srfit.equation.builder.BaseBuilder" +removal_version = "4.0.0" + +getequation_dep_msg = build_deprecation_message( + base_basebuilder, + "getEquation", + "get_equation", + removal_version, +) + class BaseBuilder(object): """Class for building equations. @@ -430,7 +441,7 @@ def __call__(self, *args): ) raise TypeError(m) - def getEquation(self): + def get_equation(self): """Get the equation built by this object. The equation will given the name "_eq_" where "" is @@ -441,6 +452,16 @@ def getEquation(self): eq = Equation(name, self.literal) return eq + @deprecated(getequation_dep_msg) + def getEquation(self): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.equation.builder.BaseBuilder.get_equation + instead. + """ + return self.get_equation() + def __eval_binary(self, other, OperatorClass, onleft=True): """Evaluate a binary function. diff --git a/tests/test_builder.py b/tests/test_builder.py index 4045dd6d..da1f56f6 100644 --- a/tests/test_builder.py +++ b/tests/test_builder.py @@ -214,7 +214,7 @@ def testBuildEquation(noObserversInGlobalBuilders): x = numpy.arange(0, numpy.pi, 0.1) beq = A * sin(a * x) - eq = beq.getEquation() + eq = beq.get_equation() assert "a" in eq.argdict assert "A" in eq.argdict @@ -235,7 +235,7 @@ def _f(a, b): b = builder.ArgumentBuilder(name="b", value=1) beq = sin(f(a, b)) - eq = beq.getEquation() + eq = beq.get_equation() assert eq() == numpy.sin(_f(2, 1)) # complex function @@ -245,23 +245,23 @@ def _f(a, b): 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() + eq = beq.get_equation() assert numpy.allclose(eq(), numpy.sqrt(numpy.exp(-0.5 * (_x / 0.1) ** 2))) # Equation with Equation A = builder.ArgumentBuilder(name="A", value=2) B = builder.ArgumentBuilder(name="B", value=4) beq = A + B - eq = beq.getEquation() + eq = beq.get_equation() E = builder.wrapOperator("eq", eq) - eq2 = (2 * E).getEquation() + eq2 = (2 * E).get_equation() # Make sure these evaluate to the same thing assert eq.args == [A.literal, B.literal] assert 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() + eq3 = (E(C, D) + 1).get_equation() assert 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 From 9fb32bd31eddffcb665f3567735084382dcc9eb7 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 11:25:54 -0500 Subject: [PATCH 026/193] news --- news/fitcontrib-dep.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 news/fitcontrib-dep.rst diff --git a/news/fitcontrib-dep.rst b/news/fitcontrib-dep.rst new file mode 100644 index 00000000..7df7b22c --- /dev/null +++ b/news/fitcontrib-dep.rst @@ -0,0 +1,25 @@ +**Added:** + +* Added ``get_equation`` method to ``BaseBuilder``. +* Added ``get_equation`` method to ``FitContribution``. + +**Changed:** + +* + +**Deprecated:** + +* Deprecated ``BaseBuilder.get_equation`` method for removal in 4.0.0. +* Deprecated ``FitContributution.get_equation`` method for removal in 4.0.0. + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 12f4ea8c06cd84aeee1197a9f48ad7c930243969 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 11:27:49 -0500 Subject: [PATCH 027/193] news typo --- news/fitcontrib-dep.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/news/fitcontrib-dep.rst b/news/fitcontrib-dep.rst index 7df7b22c..cedaa94e 100644 --- a/news/fitcontrib-dep.rst +++ b/news/fitcontrib-dep.rst @@ -9,8 +9,8 @@ **Deprecated:** -* Deprecated ``BaseBuilder.get_equation`` method for removal in 4.0.0. -* Deprecated ``FitContributution.get_equation`` method for removal in 4.0.0. +* Deprecated ``BaseBuilder.getEquation`` method for removal in 4.0.0. +* Deprecated ``FitContributution.getEquation`` method for removal in 4.0.0. **Removed:** From 0adb573aac2975c291909764f0f79ab2ebc64768 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 19 Feb 2026 12:47:00 -0500 Subject: [PATCH 028/193] deprecate SimpleRecipe.loadParsedData --- src/diffpy/srfit/fitbase/simplerecipe.py | 26 ++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/diffpy/srfit/fitbase/simplerecipe.py b/src/diffpy/srfit/fitbase/simplerecipe.py index f4b3347c..10bec267 100644 --- a/src/diffpy/srfit/fitbase/simplerecipe.py +++ b/src/diffpy/srfit/fitbase/simplerecipe.py @@ -18,6 +18,17 @@ from diffpy.srfit.fitbase.fitrecipe import FitRecipe from diffpy.srfit.fitbase.fitresults import FitResults from diffpy.srfit.fitbase.profile import Profile +from diffpy.utils._deprecator import build_deprecation_message, deprecated + +base = "diffpy.srfit.fitbase.simplerecipe.SimpleRecipe" +removal_version = "4.0.0" + +loadParsedData_dep_msg = build_deprecation_message( + base, + "loadParsedData", + "load_parsed_data", + removal_version, +) class SimpleRecipe(FitRecipe): @@ -109,12 +120,23 @@ def __init__(self, name="fit", conclass=FitContribution): return # Profile methods - def loadParsedData(self, parser): + def load_parsed_data(self, parser): """Load parsed data from a ProfileParser. This sets the xobs, yobs, dyobs arrays as well as the metadata. """ - return self.profile.loadParsedData(parser) + return self.profile.load_parsed_data(parser) + + @deprecated(loadParsedData_dep_msg) + def loadParsedData(self, parser): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use + diffpy.srfit.fitbase.simplerecipe.SimpleRecipe.load_parsed_data + instead. + """ + return self.load_parsed_data(parser) def setObservedProfile(self, xobs, yobs, dyobs=None): """Set the observed profile. From a8fb4889281d5944ef68937a56c1d5ebee390e60 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 19 Feb 2026 12:54:24 -0500 Subject: [PATCH 029/193] deprecate Profile.loadParsedData --- docs/examples/coreshellnp.py | 2 +- docs/examples/crystalpdf.py | 2 +- docs/examples/crystalpdfall.py | 2 +- docs/examples/crystalpdfobjcryst.py | 2 +- docs/examples/crystalpdftwodata.py | 4 +-- docs/examples/crystalpdftwophase.py | 2 +- docs/examples/ellipsoidsas.py | 2 +- docs/examples/nppdfcrystal.py | 2 +- docs/examples/nppdfsas.py | 4 +-- src/diffpy/srfit/fitbase/profile.py | 23 ++++++++++++++- src/diffpy/srfit/pdf/pdfcontribution.py | 4 +-- tests/test_fitrecipe.py | 38 +++++++++++++++++++++++++ 12 files changed, 73 insertions(+), 14 deletions(-) diff --git a/docs/examples/coreshellnp.py b/docs/examples/coreshellnp.py index 84d4f62f..51860f3e 100644 --- a/docs/examples/coreshellnp.py +++ b/docs/examples/coreshellnp.py @@ -44,7 +44,7 @@ def makeRecipe(stru1, stru2, datname): # Load data and add it to the profile parser = PDFParser() parser.parseFile(datname) - profile.loadParsedData(parser) + profile.load_parsed_data(parser) profile.setCalculationRange(xmin=1.5, xmax=45, dx=0.1) # The ProfileGenerator diff --git a/docs/examples/crystalpdf.py b/docs/examples/crystalpdf.py index 2a011e87..3fd9666e 100644 --- a/docs/examples/crystalpdf.py +++ b/docs/examples/crystalpdf.py @@ -55,7 +55,7 @@ def makeRecipe(ciffile, datname): # configuration steps. parser = PDFParser() parser.parseFile(datname) - profile.loadParsedData(parser) + profile.load_parsed_data(parser) profile.setCalculationRange(xmax=20) # The ProfileGenerator diff --git a/docs/examples/crystalpdfall.py b/docs/examples/crystalpdfall.py index f13545c0..8946dfe0 100644 --- a/docs/examples/crystalpdfall.py +++ b/docs/examples/crystalpdfall.py @@ -39,7 +39,7 @@ def makeProfile(datafile): profile = Profile() parser = PDFParser() parser.parseFile(datafile) - profile.loadParsedData(parser) + profile.load_parsed_data(parser) profile.setCalculationRange(xmax=20) return profile diff --git a/docs/examples/crystalpdfobjcryst.py b/docs/examples/crystalpdfobjcryst.py index 6f4d6fef..70ef78d7 100644 --- a/docs/examples/crystalpdfobjcryst.py +++ b/docs/examples/crystalpdfobjcryst.py @@ -48,7 +48,7 @@ def makeRecipe(ciffile, datname): # structure being refined. parser = PDFParser() parser.parseFile(datname) - profile.loadParsedData(parser) + profile.load_parsed_data(parser) profile.setCalculationRange(xmax=20) # The ProfileGenerator diff --git a/docs/examples/crystalpdftwodata.py b/docs/examples/crystalpdftwodata.py index f44beb1c..679dc693 100644 --- a/docs/examples/crystalpdftwodata.py +++ b/docs/examples/crystalpdftwodata.py @@ -48,12 +48,12 @@ def makeRecipe(ciffile, xdatname, ndatname): # Load data and add it to the proper Profile. parser = PDFParser() parser.parseFile(xdatname) - xprofile.loadParsedData(parser) + xprofile.load_parsed_data(parser) xprofile.setCalculationRange(xmax=20) parser = PDFParser() parser.parseFile(ndatname) - nprofile.loadParsedData(parser) + nprofile.load_parsed_data(parser) nprofile.setCalculationRange(xmax=20) # The ProfileGenerators diff --git a/docs/examples/crystalpdftwophase.py b/docs/examples/crystalpdftwophase.py index b9e638d9..59a85743 100644 --- a/docs/examples/crystalpdftwophase.py +++ b/docs/examples/crystalpdftwophase.py @@ -45,7 +45,7 @@ def makeRecipe(niciffile, siciffile, datname): # Load data and add it to the profile parser = PDFParser() parser.parseFile(datname) - profile.loadParsedData(parser) + profile.load_parsed_data(parser) profile.setCalculationRange(xmax=20) # The ProfileGenerator diff --git a/docs/examples/ellipsoidsas.py b/docs/examples/ellipsoidsas.py index c7fd391b..bac18dde 100644 --- a/docs/examples/ellipsoidsas.py +++ b/docs/examples/ellipsoidsas.py @@ -39,7 +39,7 @@ def makeRecipe(datname): # properly and pass the metadata along. parser = SASParser() parser.parseFile(datname) - profile.loadParsedData(parser) + profile.load_parsed_data(parser) # The ProfileGenerator # The SASGenerator is for configuring and calculating a SAS profile. We use diff --git a/docs/examples/nppdfcrystal.py b/docs/examples/nppdfcrystal.py index 40c14c58..c4bffaa1 100644 --- a/docs/examples/nppdfcrystal.py +++ b/docs/examples/nppdfcrystal.py @@ -44,7 +44,7 @@ def makeRecipe(ciffile, grdata): pdfparser = PDFParser() pdfparser.parseFile(grdata) - pdfprofile.loadParsedData(pdfparser) + pdfprofile.load_parsed_data(pdfparser) pdfprofile.setCalculationRange(xmin=0.1, xmax=20) pdfcontribution = FitContribution("pdf") diff --git a/docs/examples/nppdfsas.py b/docs/examples/nppdfsas.py index c655939d..6eff4b31 100644 --- a/docs/examples/nppdfsas.py +++ b/docs/examples/nppdfsas.py @@ -48,7 +48,7 @@ def makeRecipe(ciffile, grdata, iqdata): pdfprofile = Profile() pdfparser = PDFParser() pdfparser.parseFile(grdata) - pdfprofile.loadParsedData(pdfparser) + pdfprofile.load_parsed_data(pdfparser) pdfprofile.setCalculationRange(xmin=0.1, xmax=20) pdfcontribution = FitContribution("pdf") @@ -66,7 +66,7 @@ def makeRecipe(ciffile, grdata, iqdata): sasprofile = Profile() sasparser = SASParser() sasparser.parseFile(iqdata) - sasprofile.loadParsedData(sasparser) + sasprofile.load_parsed_data(sasparser) if all(sasprofile.dy == 0): sasprofile.dy[:] = 1 diff --git a/src/diffpy/srfit/fitbase/profile.py b/src/diffpy/srfit/fitbase/profile.py index 2600fb8f..98b40b80 100644 --- a/src/diffpy/srfit/fitbase/profile.py +++ b/src/diffpy/srfit/fitbase/profile.py @@ -29,9 +29,19 @@ from diffpy.srfit.fitbase.parameter import Parameter from diffpy.srfit.fitbase.validatable import Validatable from diffpy.srfit.util.observable import Observable +from diffpy.utils._deprecator import build_deprecation_message, deprecated # This is the roundoff tolerance for selecting bounds on arrays. epsilon = 1e-8 +base = "diffpy.srfit.fitbase.profile.Profile" +removal_version = "4.0.0" + +loadParsedData_dep_msg = build_deprecation_message( + base, + "loadParsedData", + "load_parsed_data", + removal_version, +) class Profile(Observable, Validatable): @@ -125,7 +135,7 @@ def __init__(self): yobs = property(lambda self: self._yobs) dyobs = property(lambda self: self._dyobs) - def loadParsedData(self, parser): + def load_parsed_data(self, parser): """Load parsed data from a ProfileParser. This sets the xobs, yobs, dyobs arrays as well as the metadata. @@ -135,6 +145,17 @@ def loadParsedData(self, parser): self.setObservedProfile(x, y, dy) return + @deprecated(loadParsedData_dep_msg) + def loadParsedData(self, parser): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.profile.Profile.load_parsed_data + instead. + """ + self.load_parsed_data(parser) + return + def setObservedProfile(self, xobs, yobs, dyobs=None): """Set the observed profile. diff --git a/src/diffpy/srfit/pdf/pdfcontribution.py b/src/diffpy/srfit/pdf/pdfcontribution.py index 3f487a93..44083452 100644 --- a/src/diffpy/srfit/pdf/pdfcontribution.py +++ b/src/diffpy/srfit/pdf/pdfcontribution.py @@ -109,7 +109,7 @@ def loadData(self, data): """Load the data in various formats. This uses the PDFParser to load the data and then passes it to the - built-in profile with loadParsedData. + built-in profile with load_parsed_data. Attributes ---------- @@ -129,7 +129,7 @@ def loadData(self, data): parser.parseString(datstr) # Pass it to the profile - self.profile.loadParsedData(parser) + self.profile.load_parsed_data(parser) return def setCalculationRange(self, xmin=None, xmax=None, dx=None): diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 571b0dab..5d419494 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -369,6 +369,27 @@ def build_recipe_from_datafile(datafile): profile = Profile() parser = PDFParser() parser.parseFile(str(datafile)) + profile.load_parsed_data(parser) + + contribution = FitContribution("c") + contribution.set_profile(profile) + contribution.set_equation("m*x + b") + recipe = FitRecipe() + recipe.add_contribution(contribution) + recipe.addVar(contribution.m, 1) + recipe.addVar(contribution.b, 0) + return recipe + + +def build_recipe_from_datafile_deprecated(datafile): + """Duplicate of build_recipe_from_datafile to use deprecated loadParsedData + method. + + Remove in version 4.0.0. + """ + profile = Profile() + parser = PDFParser() + parser.parseFile(str(datafile)) profile.loadParsedData(parser) contribution = FitContribution("c") @@ -647,6 +668,23 @@ def test_plot_recipe_labels_from_gr_file_overwrite(temp_data_files): assert actual_ylabel == expected_ylabel +def test_plot_recipe_labels_from_gr_file_overwrite_deprecated(temp_data_files): + "Remove this test with version 4.0.0." + gr_file = temp_data_files / "gr_file.gr" + recipe = build_recipe_from_datafile_deprecated(gr_file) + optimize_recipe(recipe) + plt.close("all") + fig, ax = recipe.plot_recipe( + return_fig=True, show=False, xlabel="My X", ylabel="My Y" + ) + actual_xlabel = ax.get_xlabel() + actual_ylabel = ax.get_ylabel() + expected_xlabel = "My X" + expected_ylabel = "My Y" + assert actual_xlabel == expected_xlabel + assert actual_ylabel == expected_ylabel + + def test_plot_recipe_reset_all_defaults(build_recipe_one_contribution): expected_defaults = { "show_observed": True, From bdd82f12524e1b312e9ee6bfb04084a467e21bcb Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 19 Feb 2026 16:20:16 -0500 Subject: [PATCH 030/193] deprecate Profile.setObservedProfile and SimpleRecipe.setObservedProfile --- docs/examples/debyemodel.py | 2 +- docs/source/extending.rst | 2 +- src/diffpy/srfit/fitbase/profile.py | 27 +++++++++++--- src/diffpy/srfit/fitbase/simplerecipe.py | 22 ++++++++++-- tests/conftest.py | 6 ++-- tests/test_contribution.py | 10 +++--- tests/test_fitrecipe.py | 6 ++-- tests/test_profile.py | 46 +++++++++++++++++++++--- 8 files changed, 97 insertions(+), 24 deletions(-) diff --git a/docs/examples/debyemodel.py b/docs/examples/debyemodel.py index eca6f15b..6a029998 100644 --- a/docs/examples/debyemodel.py +++ b/docs/examples/debyemodel.py @@ -93,7 +93,7 @@ def makeRecipe(): # data into the profile. xydy = numpy.array(data.split(), dtype=float).reshape(-1, 3) x, y, dy = xydy.T - profile.setObservedProfile(x, y, dy) + profile.set_observed_profile(x, y, dy) # The FitContribution # The FitContribution associates the profile with the Debye function. diff --git a/docs/source/extending.rst b/docs/source/extending.rst index a7a10be8..582add1d 100644 --- a/docs/source/extending.rst +++ b/docs/source/extending.rst @@ -185,7 +185,7 @@ customized Profile is the ``SASProfile`` class in the The ``__init__`` method sets the ``xobs``, ``yobs`` and ``dyobs`` attributes of the ``SASProfile`` to the associated arrays within the ``_datainfo`` attribute. -The ``setObservedProfile`` method is overloaded to modify the ``_datainfo`` +The ``set_observed_profile`` method is overloaded to modify the ``_datainfo`` arrays when their corresponding attributes are modified. This keeps the arrays in sync. diff --git a/src/diffpy/srfit/fitbase/profile.py b/src/diffpy/srfit/fitbase/profile.py index 98b40b80..13ed5dab 100644 --- a/src/diffpy/srfit/fitbase/profile.py +++ b/src/diffpy/srfit/fitbase/profile.py @@ -43,6 +43,13 @@ removal_version, ) +setObservedProfile_dep_msg = build_deprecation_message( + base, + "setObservedProfile", + "set_observed_profile", + removal_version, +) + class Profile(Observable, Validatable): """Observed and calculated profile container. @@ -142,7 +149,7 @@ def load_parsed_data(self, parser): """ x, y, junk, dy = parser.getData() self.meta = dict(parser.getMetaData()) - self.setObservedProfile(x, y, dy) + self.set_observed_profile(x, y, dy) return @deprecated(loadParsedData_dep_msg) @@ -156,7 +163,7 @@ def loadParsedData(self, parser): self.load_parsed_data(parser) return - def setObservedProfile(self, xobs, yobs, dyobs=None): + def set_observed_profile(self, xobs, yobs, dyobs=None): """Set the observed profile. Parameters @@ -194,6 +201,18 @@ def setObservedProfile(self, xobs, yobs, dyobs=None): return + @deprecated(setObservedProfile_dep_msg) + def setObservedProfile(self, xobs, yobs, dyobs=None): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use + diffpy.srfit.fitbase.profile.Profile.set_observed_profile + instead. + """ + self.set_observed_profile(xobs, yobs, dyobs) + return + def setCalculationRange(self, xmin=None, xmax=None, dx=None): """Set epsilon-inclusive calculation range. @@ -335,7 +354,7 @@ def loadtxt(self, *args, **kw): enforced. The first two arrays returned by numpy.loadtxt are assumed to be x and y. If there is a third array, it is assumed to by dy. Any other arrays are ignored. These are passed to - setObservedProfile. + set_observed_profile. Raises ValueError if the call to numpy.loadtxt returns fewer than 2 arrays. @@ -366,7 +385,7 @@ def loadtxt(self, *args, **kw): if len(cols) > 2: dy = cols[2] - self.setObservedProfile(x, y, dy) + self.set_observed_profile(x, y, dy) return x, y, dy def savetxt(self, fname, **kwargs): diff --git a/src/diffpy/srfit/fitbase/simplerecipe.py b/src/diffpy/srfit/fitbase/simplerecipe.py index 10bec267..5fc533a3 100644 --- a/src/diffpy/srfit/fitbase/simplerecipe.py +++ b/src/diffpy/srfit/fitbase/simplerecipe.py @@ -30,6 +30,13 @@ removal_version, ) +setObservedProfile_dep_msg = build_deprecation_message( + base, + "setObservedProfile", + "set_observed_profile", + removal_version, +) + class SimpleRecipe(FitRecipe): """SimpleRecipe class. @@ -138,7 +145,7 @@ def loadParsedData(self, parser): """ return self.load_parsed_data(parser) - def setObservedProfile(self, xobs, yobs, dyobs=None): + def set_observed_profile(self, xobs, yobs, dyobs=None): """Set the observed profile. Parameters @@ -158,6 +165,17 @@ def setObservedProfile(self, xobs, yobs, dyobs=None): """ return self.profile.setObservedProfile(xobs, yobs, dyobs) + @deprecated(setObservedProfile_dep_msg) + def setObservedProfile(self, xobs, yobs, dyobs=None): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use + diffpy.srfit.fitbase.simplerecipe.SimpleRecipe.set_observed_profile + instead. + """ + return self.set_observed_profile(xobs, yobs, dyobs) + def setCalculationRange(self, xmin=None, xmax=None, dx=None): """Set epsilon-inclusive calculation range. @@ -213,7 +231,7 @@ def loadtxt(self, *args, **kw): enforced. The first two arrays returned by numpy.loadtxt are assumed to be x and y. If there is a third array, it is assumed to by dy. Any other arrays are ignored. These are passed to - setObservedProfile. + set_observed_profile. Raises ValueError if the call to numpy.loadtxt returns fewer than 2 arrays. diff --git a/tests/conftest.py b/tests/conftest.py index d60e870e..5aec22ec 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -152,7 +152,7 @@ def build_recipe_one_contribution(): profile = Profile() x = linspace(0, pi, 10) y = sin(x) - profile.setObservedProfile(x, y) + profile.set_observed_profile(x, y) contribution = FitContribution("c1") contribution.set_profile(profile) contribution.set_equation("A*sin(k*x + c)") @@ -170,14 +170,14 @@ def build_recipe_two_contributions(): profile1 = Profile() x = linspace(0, pi, 10) y1 = sin(x) - profile1.setObservedProfile(x, y1) + profile1.set_observed_profile(x, y1) contribution1 = FitContribution("c1") contribution1.set_profile(profile1) contribution1.set_equation("A*sin(k*x + c)") profile2 = Profile() y2 = 0.5 * sin(2 * x) - profile2.setObservedProfile(x, y2) + profile2.set_observed_profile(x, y2) contribution2 = FitContribution("c2") contribution2.set_profile(profile2) contribution2.set_equation("B*sin(m*x + d)") diff --git a/tests/test_contribution.py b/tests/test_contribution.py index 2863ac62..1e7cabd2 100644 --- a/tests/test_contribution.py +++ b/tests/test_contribution.py @@ -101,7 +101,7 @@ def testInteraction(self): # create some data xobs = arange(0, 10, 0.5) yobs = xobs - profile.setObservedProfile(xobs, yobs) + profile.set_observed_profile(xobs, yobs) # Make sure this is where it's supposed to be self.assertTrue(gen.profile.xobs is xobs) @@ -123,11 +123,11 @@ def testReplacements(self): xobs = arange(0, 10, 0.5) yobs = xobs profile = self.profile - profile.setObservedProfile(xobs, yobs) + profile.set_observed_profile(xobs, yobs) xobs2 = arange(0, 10, 0.8) yobs2 = 0.5 * xobs2 profile2 = Profile() - profile2.setObservedProfile(xobs2, yobs2) + profile2.set_observed_profile(xobs2, yobs2) gen = self.gen # Validate equations @@ -217,7 +217,7 @@ def testResidual(noObserversInGlobalBuilders): # Let's create some data) xobs = arange(0, 10, 0.5) yobs = xobs - profile.setObservedProfile(xobs, yobs) + profile.set_observed_profile(xobs, yobs) # Check our fitting equation. assert np.array_equal(fc._eq(), gen(xobs)) @@ -249,7 +249,7 @@ def testResidual(noObserversInGlobalBuilders): assert fc._reseq._value is None xobs = arange(0, 10, 0.5) yobs = 9 * sin(xobs) - profile.setObservedProfile(xobs, yobs) + profile.set_observed_profile(xobs, yobs) assert fc._eq._value is None assert fc._reseq._value is None diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 5d419494..2b0d1e1c 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -41,7 +41,7 @@ def setUp(self): self.profile = Profile() x = linspace(0, pi, 10) y = sin(x) - self.profile.setObservedProfile(x, y) + self.profile.set_observed_profile(x, y) # Set up the FitContribution self.fitcontribution = FitContribution("cont") @@ -258,7 +258,7 @@ def testPrintFitHook(capturestdout): profile = Profile() x = linspace(0, pi, 10) y = sin(x) - profile.setObservedProfile(x, y) + profile.set_observed_profile(x, y) # Set up the FitContribution fitcontribution = FitContribution("cont") @@ -306,7 +306,7 @@ def test_add_contribution(capturestdout): profile = Profile() x = linspace(0, pi, 10) y = sin(x) - profile.setObservedProfile(x, y) + profile.set_observed_profile(x, y) # Set up the FitContribution fitcontribution = FitContribution("cont") diff --git a/tests/test_profile.py b/tests/test_profile.py index 29da2162..30c95c53 100644 --- a/tests/test_profile.py +++ b/tests/test_profile.py @@ -43,8 +43,44 @@ def testInit(self): self.assertEqual(profile.meta, {}) return + def test_set_observed_profile(self): + """Test the set_observed_profile method.""" + # Make a profile with defined dy + + x = arange(0, 10, 0.1) + y = x + dy = x + + prof = self.profile + prof.set_observed_profile(x, y, dy) + + 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) + y = x + dy = None + + self.profile.set_observed_profile(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)) + + # 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)) + + return + def testSetObservedProfile(self): - """Test the setObservedProfile method.""" + """Test the deprecated setObservedProfile method. + + Remove this test when setObservedProfile is removed in 4.0.0. + """ # Make a profile with defined dy x = arange(0, 10, 0.1) @@ -52,7 +88,7 @@ def testSetObservedProfile(self): dy = x prof = self.profile - prof.setObservedProfile(x, y, dy) + prof.set_observed_profile(x, y, dy) self.assertTrue(array_equal(x, prof.xobs)) self.assertTrue(array_equal(y, prof.yobs)) @@ -88,7 +124,7 @@ def testSetCalculationRange(self): self.assertRaises(AttributeError, prof.setCalculationRange, 0, 5) self.assertRaises(AttributeError, prof.setCalculationRange, 0, 5, 0.2) # assign data - prof.setObservedProfile(x, y, dy) + prof.set_observed_profile(x, y, dy) # Test normal execution w/o arguments self.assertTrue(array_equal(x, prof.x)) self.assertTrue(array_equal(y, prof.y)) @@ -172,7 +208,7 @@ def testSetCalculationPoints(self): self.assertTrue(array_equal(xcalc, prof.x)) # Add the data. This should change the bounds of the calculation array. - prof.setObservedProfile(x, y, dy) + prof.set_observed_profile(x, y, dy) self.assertTrue(array_equal(arange(3, 10.1, 0.2), prof.x)) return @@ -183,7 +219,7 @@ def test_savetxt(self): self.assertRaises(SrFitError, prof.savetxt, "foo") xobs = arange(-2, 3.01, 0.25) yobs = xobs**2 - prof.setObservedProfile(xobs, yobs) + prof.set_observed_profile(xobs, yobs) prof.ycalc = yobs.copy() fp = io.BytesIO() prof.savetxt(fp) From 64ba047e343485739b42a765ba123f647302eb3f Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 19 Feb 2026 16:23:19 -0500 Subject: [PATCH 031/193] news --- news/profile-dep.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 news/profile-dep.rst diff --git a/news/profile-dep.rst b/news/profile-dep.rst new file mode 100644 index 00000000..d915194c --- /dev/null +++ b/news/profile-dep.rst @@ -0,0 +1,25 @@ +**Added:** + +* Added ``load_parsed_data`` in replace of ``loadParsedData`` in ``Profile`` and ``SimpleRecipe``. +* Added ``set_observed_profile`` in replace of ``setObservedProfile`` in ``Profile`` and ``SimpleRecipe``. + +**Changed:** + +* + +**Deprecated:** + +* Deprecated ``loadParsedData`` in ``Profile`` and ``SimpleRecipe`` for removal in 4.0.0. +* Deprecated ``setObservedProfile`` in ``Profile`` and ``SimpleRecipe`` for removal in 4.0.0. + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From eef57415ab147112f695acbcf5a164211769ceca Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 19 Feb 2026 16:49:58 -0500 Subject: [PATCH 032/193] setCalculationRange --- docs/examples/coreshellnp.py | 2 +- docs/examples/crystalpdf.py | 2 +- docs/examples/crystalpdfall.py | 2 +- docs/examples/crystalpdfobjcryst.py | 2 +- docs/examples/crystalpdftwodata.py | 4 +- docs/examples/crystalpdftwophase.py | 2 +- docs/examples/debyemodelII.py | 8 +-- docs/examples/nppdfcrystal.py | 2 +- docs/examples/nppdfobjcryst.py | 2 +- docs/examples/nppdfsas.py | 2 +- docs/examples/simplepdf.py | 2 +- docs/examples/simplepdftwophase.py | 2 +- src/diffpy/srfit/fitbase/profile.py | 21 ++++++- src/diffpy/srfit/fitbase/simplerecipe.py | 23 +++++++- tests/test_profile.py | 73 ++++++++++++++++-------- 15 files changed, 104 insertions(+), 45 deletions(-) diff --git a/docs/examples/coreshellnp.py b/docs/examples/coreshellnp.py index 51860f3e..0ab04609 100644 --- a/docs/examples/coreshellnp.py +++ b/docs/examples/coreshellnp.py @@ -45,7 +45,7 @@ def makeRecipe(stru1, stru2, datname): parser = PDFParser() parser.parseFile(datname) profile.load_parsed_data(parser) - profile.setCalculationRange(xmin=1.5, xmax=45, dx=0.1) + profile.set_calculation_range(xmin=1.5, xmax=45, dx=0.1) # The ProfileGenerator # In order to fit the core and shell phases simultaneously, we must use two diff --git a/docs/examples/crystalpdf.py b/docs/examples/crystalpdf.py index 3fd9666e..4fbc50e4 100644 --- a/docs/examples/crystalpdf.py +++ b/docs/examples/crystalpdf.py @@ -56,7 +56,7 @@ def makeRecipe(ciffile, datname): parser = PDFParser() parser.parseFile(datname) profile.load_parsed_data(parser) - profile.setCalculationRange(xmax=20) + profile.set_calculation_range(xmax=20) # The ProfileGenerator # The PDFGenerator is for configuring and calculating a PDF profile. Here, diff --git a/docs/examples/crystalpdfall.py b/docs/examples/crystalpdfall.py index 8946dfe0..de325719 100644 --- a/docs/examples/crystalpdfall.py +++ b/docs/examples/crystalpdfall.py @@ -40,7 +40,7 @@ def makeProfile(datafile): parser = PDFParser() parser.parseFile(datafile) profile.load_parsed_data(parser) - profile.setCalculationRange(xmax=20) + profile.set_calculation_range(xmax=20) return profile diff --git a/docs/examples/crystalpdfobjcryst.py b/docs/examples/crystalpdfobjcryst.py index 70ef78d7..a4fdf23c 100644 --- a/docs/examples/crystalpdfobjcryst.py +++ b/docs/examples/crystalpdfobjcryst.py @@ -49,7 +49,7 @@ def makeRecipe(ciffile, datname): parser = PDFParser() parser.parseFile(datname) profile.load_parsed_data(parser) - profile.setCalculationRange(xmax=20) + profile.set_calculation_range(xmax=20) # The ProfileGenerator # This time we use the CreateCrystalFromCIF method of pyobjcryst.crystal to diff --git a/docs/examples/crystalpdftwodata.py b/docs/examples/crystalpdftwodata.py index 679dc693..eef737f0 100644 --- a/docs/examples/crystalpdftwodata.py +++ b/docs/examples/crystalpdftwodata.py @@ -49,12 +49,12 @@ def makeRecipe(ciffile, xdatname, ndatname): parser = PDFParser() parser.parseFile(xdatname) xprofile.load_parsed_data(parser) - xprofile.setCalculationRange(xmax=20) + xprofile.set_calculation_range(xmax=20) parser = PDFParser() parser.parseFile(ndatname) nprofile.load_parsed_data(parser) - nprofile.setCalculationRange(xmax=20) + nprofile.set_calculation_range(xmax=20) # The ProfileGenerators # We need one of these for the x-ray data. diff --git a/docs/examples/crystalpdftwophase.py b/docs/examples/crystalpdftwophase.py index 59a85743..7087a4db 100644 --- a/docs/examples/crystalpdftwophase.py +++ b/docs/examples/crystalpdftwophase.py @@ -46,7 +46,7 @@ def makeRecipe(niciffile, siciffile, datname): parser = PDFParser() parser.parseFile(datname) profile.load_parsed_data(parser) - profile.setCalculationRange(xmax=20) + profile.set_calculation_range(xmax=20) # The ProfileGenerator # In order to fit two phases simultaneously, we must use two PDFGenerators. diff --git a/docs/examples/debyemodelII.py b/docs/examples/debyemodelII.py index bc50fe54..fe686f0b 100644 --- a/docs/examples/debyemodelII.py +++ b/docs/examples/debyemodelII.py @@ -77,8 +77,8 @@ def makeRecipeII(): # Change the fit ranges of the Profiles embedded within the # FitContributions. We want to fit one of the contributions at low # temperature, and one at high. - lowT.profile.setCalculationRange(0, 150) - highT.profile.setCalculationRange(400, 500) + lowT.profile.set_calculation_range(0, 150) + highT.profile.set_calculation_range(400, 500) # Vary the offset from each FitContribution separately, while keeping the # Debye temperatures the same. We give each offset variable a different @@ -102,8 +102,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.set_calculation_range(xmin="obs", xmax="obs") + recipe.highT.profile.set_calculation_range(xmin="obs", xmax="obs") T = recipe.lowT.profile.x U = recipe.lowT.profile.y # We can use a FitContribution's 'evaluateEquation' method to evaluate diff --git a/docs/examples/nppdfcrystal.py b/docs/examples/nppdfcrystal.py index c4bffaa1..df64c109 100644 --- a/docs/examples/nppdfcrystal.py +++ b/docs/examples/nppdfcrystal.py @@ -45,7 +45,7 @@ def makeRecipe(ciffile, grdata): pdfparser = PDFParser() pdfparser.parseFile(grdata) pdfprofile.load_parsed_data(pdfparser) - pdfprofile.setCalculationRange(xmin=0.1, xmax=20) + pdfprofile.set_calculation_range(xmin=0.1, xmax=20) pdfcontribution = FitContribution("pdf") pdfcontribution.set_profile(pdfprofile, xname="r") diff --git a/docs/examples/nppdfobjcryst.py b/docs/examples/nppdfobjcryst.py index e77a5a95..45ac1be6 100644 --- a/docs/examples/nppdfobjcryst.py +++ b/docs/examples/nppdfobjcryst.py @@ -40,7 +40,7 @@ def makeRecipe(molecule, datname): # Load data and add it to the profile profile.loadtxt(datname) - profile.setCalculationRange(xmin=1.2, xmax=8) + profile.set_calculation_range(xmin=1.2, xmax=8) # The ProfileGenerator # Create a DebyePDFGenerator named "G". diff --git a/docs/examples/nppdfsas.py b/docs/examples/nppdfsas.py index 6eff4b31..77688709 100644 --- a/docs/examples/nppdfsas.py +++ b/docs/examples/nppdfsas.py @@ -49,7 +49,7 @@ def makeRecipe(ciffile, grdata, iqdata): pdfparser = PDFParser() pdfparser.parseFile(grdata) pdfprofile.load_parsed_data(pdfparser) - pdfprofile.setCalculationRange(xmin=0.1, xmax=20) + pdfprofile.set_calculation_range(xmin=0.1, xmax=20) pdfcontribution = FitContribution("pdf") pdfcontribution.set_profile(pdfprofile, xname="r") diff --git a/docs/examples/simplepdf.py b/docs/examples/simplepdf.py index 4574a5d7..ffe69dd4 100644 --- a/docs/examples/simplepdf.py +++ b/docs/examples/simplepdf.py @@ -35,7 +35,7 @@ def makeRecipe(ciffile, datname): # 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.set_calculation_range(xmin=1, xmax=20, dx=0.1) # and the phase stru = Structure() diff --git a/docs/examples/simplepdftwophase.py b/docs/examples/simplepdftwophase.py index e00ae302..134d8855 100644 --- a/docs/examples/simplepdftwophase.py +++ b/docs/examples/simplepdftwophase.py @@ -31,7 +31,7 @@ def makeRecipe(niciffile, siciffile, datname): # Load data and add it to the profile contribution = PDFContribution("nisi") contribution.loadData(datname) - contribution.setCalculationRange(xmax=20) + contribution.set_calculation_range(xmax=20) stru = loadCrystal(niciffile) contribution.addStructure("ni", stru) diff --git a/src/diffpy/srfit/fitbase/profile.py b/src/diffpy/srfit/fitbase/profile.py index 13ed5dab..aaf13a44 100644 --- a/src/diffpy/srfit/fitbase/profile.py +++ b/src/diffpy/srfit/fitbase/profile.py @@ -50,6 +50,13 @@ removal_version, ) +setCalculationRange_dep_msg = build_deprecation_message( + base, + "setCalculationRange", + "set_calculation_range", + removal_version, +) + class Profile(Observable, Validatable): """Observed and calculated profile container. @@ -213,7 +220,7 @@ def setObservedProfile(self, xobs, yobs, dyobs=None): self.set_observed_profile(xobs, yobs, dyobs) return - def setCalculationRange(self, xmin=None, xmax=None, dx=None): + def set_calculation_range(self, xmin=None, xmax=None, dx=None): """Set epsilon-inclusive calculation range. Adhere to the observed ``xobs`` points when ``dx`` is the same @@ -317,6 +324,18 @@ def _isobs(a): self.setCalculationPoints(x1) return + @deprecated(setCalculationRange_dep_msg) + def setCalculationRange(self, xmin=None, xmax=None, dx=None): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use + diffpy.srfit.fitbase.profile.Profile.set_calculation_range + instead. + """ + self.set_calculation_range(xmin, xmax, dx) + return + def setCalculationPoints(self, x): """Set the calculation points. diff --git a/src/diffpy/srfit/fitbase/simplerecipe.py b/src/diffpy/srfit/fitbase/simplerecipe.py index 5fc533a3..6e9b7919 100644 --- a/src/diffpy/srfit/fitbase/simplerecipe.py +++ b/src/diffpy/srfit/fitbase/simplerecipe.py @@ -37,6 +37,13 @@ removal_version, ) +setCalculationRange_dep_msg = build_deprecation_message( + base, + "setCalculationRange", + "set_calculation_range", + removal_version, +) + class SimpleRecipe(FitRecipe): """SimpleRecipe class. @@ -163,7 +170,7 @@ def set_observed_profile(self, xobs, yobs, dyobs=None): Raises ValueError if len(yobs) != len(xobs) Raises ValueError if dyobs != None and len(dyobs) != len(xobs) """ - return self.profile.setObservedProfile(xobs, yobs, dyobs) + return self.profile.set_observed_profile(xobs, yobs, dyobs) @deprecated(setObservedProfile_dep_msg) def setObservedProfile(self, xobs, yobs, dyobs=None): @@ -176,7 +183,7 @@ def setObservedProfile(self, xobs, yobs, dyobs=None): """ return self.set_observed_profile(xobs, yobs, dyobs) - def setCalculationRange(self, xmin=None, xmax=None, dx=None): + def set_calculation_range(self, xmin=None, xmax=None, dx=None): """Set epsilon-inclusive calculation range. Adhere to the observed ``xobs`` points when ``dx`` is the same @@ -208,7 +215,17 @@ def setCalculationRange(self, xmin=None, xmax=None, dx=None): ValueError When xmin > xmax or if dx <= 0. Also if dx > xmax - xmin. """ - return self.profile.setCalculationRange(xmin, xmax, dx) + return self.profile.set_calculation_range(xmin, xmax, dx) + + def setCalculationRange(self, xmin=None, xmax=None, dx=None): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use + diffpy.srfit.fitbase.simplerecipe.SimpleRecipe.set_calculation_range + instead. + """ + return self.set_calculation_range(xmin, xmax, dx) def setCalculationPoints(self, x): """Set the calculation points. diff --git a/tests/test_profile.py b/tests/test_profile.py index 30c95c53..25722dad 100644 --- a/tests/test_profile.py +++ b/tests/test_profile.py @@ -112,88 +112,111 @@ def testSetObservedProfile(self): return - def testSetCalculationRange(self): - """Test the setCalculationRange method.""" + def test_set_calculation_range(self): + """Test the set_calculation_range method.""" x = arange(2, 9.6, 0.5) y = array(x) dy = array(x) prof = self.profile # Check call before data arrays are present - self.assertRaises(AttributeError, prof.setCalculationRange) - self.assertRaises(AttributeError, prof.setCalculationRange, 0) - self.assertRaises(AttributeError, prof.setCalculationRange, 0, 5) - self.assertRaises(AttributeError, prof.setCalculationRange, 0, 5, 0.2) + self.assertRaises(AttributeError, prof.set_calculation_range) + self.assertRaises(AttributeError, prof.set_calculation_range, 0) + self.assertRaises(AttributeError, prof.set_calculation_range, 0, 5) + self.assertRaises( + AttributeError, prof.set_calculation_range, 0, 5, 0.2 + ) # assign data prof.set_observed_profile(x, y, dy) # Test normal execution w/o arguments self.assertTrue(array_equal(x, prof.x)) self.assertTrue(array_equal(y, prof.y)) self.assertTrue(array_equal(dy, prof.dy)) - prof.setCalculationRange() + prof.set_calculation_range() self.assertTrue(array_equal(x, prof.x)) self.assertTrue(array_equal(y, prof.y)) self.assertTrue(array_equal(dy, prof.dy)) # Test a lower bound < xmin - prof.setCalculationRange(xmin=0) + prof.set_calculation_range(xmin=0) self.assertTrue(array_equal(x, prof.x)) self.assertTrue(array_equal(y, prof.y)) self.assertTrue(array_equal(dy, prof.dy)) # Test an upper bound > xmax - prof.setCalculationRange(xmax=100) + prof.set_calculation_range(xmax=100) self.assertTrue(array_equal(x, prof.x)) 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 + ValueError, prof.set_calculation_range, xmin=10, xmax=3 ) # Test xmax - xmin < dx self.assertRaises( - ValueError, prof.setCalculationRange, xmin=3, xmax=3.9, dx=1.0 + ValueError, prof.set_calculation_range, 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) + self.assertRaises(ValueError, prof.set_calculation_range, dx=0) + self.assertRaises(ValueError, prof.set_calculation_range, 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.set_calculation_range, xmin="oobs") + self.assertRaises(ValueError, prof.set_calculation_range, xmax="oobs") + self.assertRaises(ValueError, prof.set_calculation_range, dx="oobs") # This should be alright - prof.setCalculationRange(3, 5) - prof.setCalculationRange(xmin="obs", xmax=7, dx=0.001) + prof.set_calculation_range(3, 5) + prof.set_calculation_range(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.set_calculation_range(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))) # test setting only one of the bounds - prof.setCalculationRange(xmin=3) + prof.set_calculation_range(xmin=3) self.assertTrue(array_equal(prof.x, arange(3, 7.1, 0.5))) self.assertTrue(array_equal(prof.x, prof.y)) self.assertTrue(array_equal(prof.x, prof.dy)) - prof.setCalculationRange(xmax=5.1) + prof.set_calculation_range(xmax=5.1) self.assertTrue(array_equal(prof.x, arange(3, 5.1, 0.5))) self.assertTrue(array_equal(prof.x, prof.y)) self.assertTrue(array_equal(prof.x, prof.dy)) - prof.setCalculationRange(dx=1) + prof.set_calculation_range(dx=1) self.assertTrue(array_equal(prof.x, arange(3, 5.1))) self.assertTrue(array_equal(prof.x, prof.y)) self.assertTrue(array_equal(prof.x, prof.dy)) # Test a new grid - prof.setCalculationRange(4.2, 7, 0.3) + prof.set_calculation_range(4.2, 7, 0.3) self.assertTrue(array_equal(prof.x, arange(4.2, 6.901, 0.3))) self.assertTrue(allclose(prof.x, prof.y)) self.assertTrue(allclose(prof.x, prof.dy)) - prof.setCalculationRange(xmin=4.2, xmax=6.001) + prof.set_calculation_range(xmin=4.2, xmax=6.001) self.assertTrue(array_equal(prof.x, arange(4.2, 6.001, 0.3))) # resample on a clipped grid - prof.setCalculationRange(dx=0.5) + prof.set_calculation_range(dx=0.5) self.assertTrue(array_equal(prof.x, arange(4.5, 6.1, 0.5))) return + def testSetCalculationRange(self): + """Test the deprecated setCalculationRange method. + + Remove this test when setCalculationRange is removed in 4.0.0. + """ + x = arange(2, 9.6, 0.5) + y = array(x) + dy = array(x) + prof = self.profile + prof.set_observed_profile(x, y, dy) + prof.setCalculationRange() + # Test normal execution w/o arguments + self.assertTrue(array_equal(x, prof.x)) + self.assertTrue(array_equal(y, prof.y)) + self.assertTrue(array_equal(dy, prof.dy)) + prof.setCalculationRange() + self.assertTrue(array_equal(x, prof.x)) + self.assertTrue(array_equal(y, prof.y)) + self.assertTrue(array_equal(dy, prof.dy)) + return + def testSetCalculationPoints(self): """Test the setCalculationPoints method.""" prof = self.profile From 80d0f4b11f9f271a740652c24e8c78901001b771 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 19 Feb 2026 17:06:25 -0500 Subject: [PATCH 033/193] setCalculationPoints --- news/profile-dep.rst | 2 ++ src/diffpy/srfit/fitbase/profile.py | 31 +++++++++++++++++++++--- src/diffpy/srfit/fitbase/simplerecipe.py | 22 +++++++++++++++-- src/diffpy/srfit/pdf/pdfcontribution.py | 2 +- tests/test_profile.py | 25 +++++++++++++++++-- tests/test_profilegenerator.py | 6 ++--- 6 files changed, 76 insertions(+), 12 deletions(-) diff --git a/news/profile-dep.rst b/news/profile-dep.rst index d915194c..cd0f322e 100644 --- a/news/profile-dep.rst +++ b/news/profile-dep.rst @@ -2,6 +2,7 @@ * Added ``load_parsed_data`` in replace of ``loadParsedData`` in ``Profile`` and ``SimpleRecipe``. * Added ``set_observed_profile`` in replace of ``setObservedProfile`` in ``Profile`` and ``SimpleRecipe``. +* Added ``set_calculation_range`` in replace of ``setCalculationRange`` in ``Profile`` and ``SimpleRecipe``. **Changed:** @@ -11,6 +12,7 @@ * Deprecated ``loadParsedData`` in ``Profile`` and ``SimpleRecipe`` for removal in 4.0.0. * Deprecated ``setObservedProfile`` in ``Profile`` and ``SimpleRecipe`` for removal in 4.0.0. +* Deprecated ``setCalculationRange`` in ``Profile`` and ``SimpleRecipe`` for removal in 4.0.0. **Removed:** diff --git a/src/diffpy/srfit/fitbase/profile.py b/src/diffpy/srfit/fitbase/profile.py index aaf13a44..f00f2712 100644 --- a/src/diffpy/srfit/fitbase/profile.py +++ b/src/diffpy/srfit/fitbase/profile.py @@ -57,6 +57,13 @@ removal_version, ) +setCalculationPoints_dep_msg = build_deprecation_message( + base, + "setCalculationPoints", + "set_calculation_points", + removal_version, +) + class Profile(Observable, Validatable): """Observed and calculated profile container. @@ -202,9 +209,9 @@ def set_observed_profile(self, xobs, yobs, dyobs=None): # Set the default calculation points if self.x is None: - self.setCalculationPoints(self._xobs) + self.set_calculation_points(self._xobs) else: - self.setCalculationPoints(self.x) + self.set_calculation_points(self.x) return @@ -321,7 +328,7 @@ def _isobs(a): self.dy = self.dyobs[indices] else: x1 = numpy.arange(lo, hi + epshi, step) - self.setCalculationPoints(x1) + self.set_calculation_points(x1) return @deprecated(setCalculationRange_dep_msg) @@ -336,7 +343,7 @@ def setCalculationRange(self, xmin=None, xmax=None, dx=None): self.set_calculation_range(xmin, xmax, dx) return - def setCalculationPoints(self, x): + def set_calculation_points(self, x): """Set the calculation points. Parameters @@ -366,6 +373,22 @@ def setCalculationPoints(self, x): return + @deprecated(setCalculationPoints_dep_msg) + def setCalculationPoints(self, x): + """Set the calculation points. + + Parameters + ---------- + x + A non-empty numpy array containing the calculation points. If + xobs exists, the bounds of x will be limited to its bounds. + + This will create y and dy on the specified grid if xobs, yobs and + dyobs exist. + """ + self.set_calculation_points(x) + return + def loadtxt(self, *args, **kw): """Use numpy.loadtxt to load data. diff --git a/src/diffpy/srfit/fitbase/simplerecipe.py b/src/diffpy/srfit/fitbase/simplerecipe.py index 6e9b7919..da4aadd8 100644 --- a/src/diffpy/srfit/fitbase/simplerecipe.py +++ b/src/diffpy/srfit/fitbase/simplerecipe.py @@ -44,6 +44,13 @@ removal_version, ) +setCalculationPoints_dep_msg = build_deprecation_message( + base, + "setCalculationPoints", + "set_calculation_points", + removal_version, +) + class SimpleRecipe(FitRecipe): """SimpleRecipe class. @@ -227,7 +234,7 @@ def setCalculationRange(self, xmin=None, xmax=None, dx=None): """ return self.set_calculation_range(xmin, xmax, dx) - def setCalculationPoints(self, x): + def set_calculation_points(self, x): """Set the calculation points. Parameters @@ -239,7 +246,18 @@ def setCalculationPoints(self, x): This will create y and dy on the specified grid if xobs, yobs and dyobs exist. """ - return self.profile.setCalculationPoints(x) + return self.profile.set_calculation_points(x) + + @deprecated(setCalculationPoints_dep_msg) + def setCalculationPoints(self, x): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use + diffpy.srfit.fitbase.simplerecipe.SimpleRecipe.set_calculation_points + instead. + """ + return self.set_calculation_points(x) def loadtxt(self, *args, **kw): """Use numpy.loadtxt to load data. diff --git a/src/diffpy/srfit/pdf/pdfcontribution.py b/src/diffpy/srfit/pdf/pdfcontribution.py index 44083452..9b2bdd93 100644 --- a/src/diffpy/srfit/pdf/pdfcontribution.py +++ b/src/diffpy/srfit/pdf/pdfcontribution.py @@ -164,7 +164,7 @@ def setCalculationRange(self, xmin=None, xmax=None, dx=None): ValueError When xmin > xmax or if dx <= 0. Also if dx > xmax - xmin. """ - return self.profile.setCalculationRange(xmin, xmax, dx) + return self.profile.set_calculation_range(xmin, xmax, dx) def savetxt(self, fname, **kwargs): """Call numpy.savetxt with x, ycalc, y, dy. diff --git a/tests/test_profile.py b/tests/test_profile.py index 25722dad..f8c186b4 100644 --- a/tests/test_profile.py +++ b/tests/test_profile.py @@ -206,7 +206,6 @@ def testSetCalculationRange(self): dy = array(x) prof = self.profile prof.set_observed_profile(x, y, dy) - prof.setCalculationRange() # Test normal execution w/o arguments self.assertTrue(array_equal(x, prof.x)) self.assertTrue(array_equal(y, prof.y)) @@ -217,8 +216,30 @@ def testSetCalculationRange(self): self.assertTrue(array_equal(dy, prof.dy)) return + def test_set_calculation_points(self): + """Test the set_calculation_points method.""" + prof = self.profile + + x = arange(2, 10.5, 0.5) + y = array(x) + dy = array(x) + + # Test without data + xcalc = arange(3, 12.2, 0.2) + prof.set_calculation_points(xcalc) + self.assertTrue(array_equal(xcalc, prof.x)) + + # Add the data. This should change the bounds of the calculation array. + prof.set_observed_profile(x, y, dy) + self.assertTrue(array_equal(arange(3, 10.1, 0.2), prof.x)) + + return + def testSetCalculationPoints(self): - """Test the setCalculationPoints method.""" + """Test the deprecated setCalculationPoints method. + + Remove this test when setCalculationPoints is removed in 4.0.0. + """ prof = self.profile x = arange(2, 10.5, 0.5) diff --git a/tests/test_profilegenerator.py b/tests/test_profilegenerator.py index 14612a93..aeacf690 100644 --- a/tests/test_profilegenerator.py +++ b/tests/test_profilegenerator.py @@ -29,7 +29,7 @@ def setUp(self): self.gen = ProfileGenerator("test") self.profile = Profile() x = arange(0, 10, 0.1) - self.profile.setCalculationPoints(x) + self.profile.set_calculation_points(x) self.gen.set_profile(self.profile) return @@ -55,7 +55,7 @@ def testUpdate(self): # Make sure attributes get updated with a change in the calculation # points. x = arange(0, 9, 0.1) - prof.setCalculationPoints(x) + prof.set_calculation_points(x) self.assertTrue(gen._value is None) val = gen.value self.assertTrue(array_equal(x, val)) @@ -68,7 +68,7 @@ def testUpdate(self): # Make sure attributes get updated with a new profile. x = arange(0, 8, 0.1) prof = Profile() - prof.setCalculationPoints(x) + prof.set_calculation_points(x) gen.set_profile(prof) self.assertTrue(gen._value is None) self.assertTrue(array_equal(x, gen.value)) From 36957e024a01a0cf0540144ff1b66bd445bb0087 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 19 Feb 2026 17:08:00 -0500 Subject: [PATCH 034/193] change rebinArray to rebin_array --- news/profile-dep.rst | 2 ++ src/diffpy/srfit/fitbase/profile.py | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/news/profile-dep.rst b/news/profile-dep.rst index cd0f322e..48424bcd 100644 --- a/news/profile-dep.rst +++ b/news/profile-dep.rst @@ -3,6 +3,7 @@ * Added ``load_parsed_data`` in replace of ``loadParsedData`` in ``Profile`` and ``SimpleRecipe``. * Added ``set_observed_profile`` in replace of ``setObservedProfile`` in ``Profile`` and ``SimpleRecipe``. * Added ``set_calculation_range`` in replace of ``setCalculationRange`` in ``Profile`` and ``SimpleRecipe``. +* Added ``set_calculation_points`` in replace of ``setCalculationPoints`` in ``Profile`` and ``SimpleRecipe``. **Changed:** @@ -13,6 +14,7 @@ * Deprecated ``loadParsedData`` in ``Profile`` and ``SimpleRecipe`` for removal in 4.0.0. * Deprecated ``setObservedProfile`` in ``Profile`` and ``SimpleRecipe`` for removal in 4.0.0. * Deprecated ``setCalculationRange`` in ``Profile`` and ``SimpleRecipe`` for removal in 4.0.0. +* Deprecated ``setCalculationPoints`` in ``Profile`` and ``SimpleRecipe`` for removal in 4.0.0. **Removed:** diff --git a/src/diffpy/srfit/fitbase/profile.py b/src/diffpy/srfit/fitbase/profile.py index f00f2712..c7f94ee7 100644 --- a/src/diffpy/srfit/fitbase/profile.py +++ b/src/diffpy/srfit/fitbase/profile.py @@ -361,7 +361,7 @@ def set_calculation_points(self, x): 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) + self.y = rebin_array(self.yobs, self.xobs, self.x) if self.dyobs is not None: # work around for interpolation issue making some of these non-1 if (self.dyobs == 1).all(): @@ -369,7 +369,7 @@ def set_calculation_points(self, x): else: # FIXME - This does not follow error propagation rules and it # introduces (more) correlation between the data points. - self.dy = rebinArray(self.dyobs, self.xobs, self.x) + self.dy = rebin_array(self.dyobs, self.xobs, self.x) return @@ -500,7 +500,7 @@ def _validate(self): # End class Profile -def rebinArray(A, xold, xnew): +def rebin_array(A, xold, xnew): """Rebin the an array by interpolating over the new x range. Parameters From 7443c6a8bd882b925cb7588f384f978655e331a7 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 19 Feb 2026 17:24:27 -0500 Subject: [PATCH 035/193] make _rebin_array private --- src/diffpy/srfit/fitbase/profile.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/diffpy/srfit/fitbase/profile.py b/src/diffpy/srfit/fitbase/profile.py index c7f94ee7..ae4e896b 100644 --- a/src/diffpy/srfit/fitbase/profile.py +++ b/src/diffpy/srfit/fitbase/profile.py @@ -361,7 +361,7 @@ def set_calculation_points(self, x): x = x[x <= self.xobs[-1] + epsilon] self.x = x if self.yobs is not None: - self.y = rebin_array(self.yobs, self.xobs, self.x) + self.y = _rebin_array(self.yobs, self.xobs, self.x) if self.dyobs is not None: # work around for interpolation issue making some of these non-1 if (self.dyobs == 1).all(): @@ -369,7 +369,7 @@ def set_calculation_points(self, x): else: # FIXME - This does not follow error propagation rules and it # introduces (more) correlation between the data points. - self.dy = rebin_array(self.dyobs, self.xobs, self.x) + self.dy = _rebin_array(self.dyobs, self.xobs, self.x) return @@ -500,7 +500,7 @@ def _validate(self): # End class Profile -def rebin_array(A, xold, xnew): +def _rebin_array(A, xold, xnew): """Rebin the an array by interpolating over the new x range. Parameters From 1befd1174c0c36ca7b5254cfe1fe092979d54436 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 20 Feb 2026 09:52:47 -0500 Subject: [PATCH 036/193] missed deprecation tag in SimpleRecipe --- src/diffpy/srfit/fitbase/simplerecipe.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/diffpy/srfit/fitbase/simplerecipe.py b/src/diffpy/srfit/fitbase/simplerecipe.py index da4aadd8..e5a89e44 100644 --- a/src/diffpy/srfit/fitbase/simplerecipe.py +++ b/src/diffpy/srfit/fitbase/simplerecipe.py @@ -51,6 +51,13 @@ removal_version, ) +setEquation_dep_msg = build_deprecation_message( + base, + "setEquation", + "set_equation", + removal_version, +) + class SimpleRecipe(FitRecipe): """SimpleRecipe class. @@ -224,6 +231,7 @@ def set_calculation_range(self, xmin=None, xmax=None, dx=None): """ return self.profile.set_calculation_range(xmin, xmax, dx) + @deprecated(setCalculationRange_dep_msg) def setCalculationRange(self, xmin=None, xmax=None, dx=None): """This function has been deprecated and will be removed in version 4.0.0. @@ -309,6 +317,18 @@ def set_equation(self, eqstr, ns={}): self.addVar(par) return + @deprecated(setEquation_dep_msg) + def setEquation(self, eqstr, ns={}): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use + diffpy.srfit.fitbase.simplerecipe.SimpleRecipe.set_equation + instead. + """ + self.set_equation(eqstr, ns) + return + def __call__(self): """Evaluate the contribution equation.""" return self.contribution.evaluate() From ca4e85c321d3629a8a33b8b757d3ef0d6f58cbd9 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 20 Feb 2026 09:57:32 -0500 Subject: [PATCH 037/193] setResidualEquation deprecation --- docs/examples/crystalpdfall.py | 8 +++--- docs/examples/crystalpdftwodata.py | 4 +-- docs/examples/ellipsoidsas.py | 2 +- docs/examples/nppdfsas.py | 4 +-- src/diffpy/srfit/fitbase/fitcontribution.py | 29 +++++++++++++++++---- src/diffpy/srfit/fitbase/simplerecipe.py | 4 +-- tests/test_contribution.py | 23 +++++++++++----- 7 files changed, 52 insertions(+), 22 deletions(-) diff --git a/docs/examples/crystalpdfall.py b/docs/examples/crystalpdfall.py index de325719..570c6a27 100644 --- a/docs/examples/crystalpdfall.py +++ b/docs/examples/crystalpdfall.py @@ -97,10 +97,10 @@ def makeRecipe( xcontribution_sini.set_equation("scale * (xG_sini_ni + xG_sini_si)") # As explained in another example, we want to minimize using Rw^2. - xcontribution_ni.setResidualEquation("resv") - xcontribution_si.setResidualEquation("resv") - ncontribution_ni.setResidualEquation("resv") - xcontribution_sini.setResidualEquation("resv") + xcontribution_ni.set_residual_equation("resv") + xcontribution_si.set_residual_equation("resv") + ncontribution_ni.set_residual_equation("resv") + xcontribution_sini.set_residual_equation("resv") # Make the FitRecipe and add the FitContributions. recipe = FitRecipe() diff --git a/docs/examples/crystalpdftwodata.py b/docs/examples/crystalpdftwodata.py index eef737f0..b9293a9e 100644 --- a/docs/examples/crystalpdftwodata.py +++ b/docs/examples/crystalpdftwodata.py @@ -105,8 +105,8 @@ def makeRecipe(ciffile, xdatname, ndatname): # The contribution's residual can be either chi^2, Rw^2, or custom crafted. # In this case, we should minimize Rw^2 of each contribution so that each # one can contribute roughly equally to the fit. - xcontribution.setResidualEquation("resv") - ncontribution.setResidualEquation("resv") + xcontribution.set_residual_equation("resv") + ncontribution.set_residual_equation("resv") # Make the FitRecipe and add the FitContributions. recipe = FitRecipe() diff --git a/docs/examples/ellipsoidsas.py b/docs/examples/ellipsoidsas.py index bac18dde..4fbd6ef8 100644 --- a/docs/examples/ellipsoidsas.py +++ b/docs/examples/ellipsoidsas.py @@ -64,7 +64,7 @@ def makeRecipe(datname): # higher-Q information remains significant. There are no I(Q) uncertainty # values with the data, so we do not need to worry about the effect this # will have on the estimated parameter uncertainties. - contribution.setResidualEquation("log(eq) - log(y)") + contribution.set_residual_equation("log(eq) - log(y)") # Make the FitRecipe and add the FitContribution. recipe = FitRecipe() diff --git a/docs/examples/nppdfsas.py b/docs/examples/nppdfsas.py index 77688709..0df85c56 100644 --- a/docs/examples/nppdfsas.py +++ b/docs/examples/nppdfsas.py @@ -59,7 +59,7 @@ def makeRecipe(ciffile, grdata, iqdata): stru = loadCrystal(ciffile) pdfgenerator.setStructure(stru) pdfcontribution.add_profile_generator(pdfgenerator) - pdfcontribution.setResidualEquation("resv") + pdfcontribution.set_residual_equation("resv") # Create a SAS contribution as well. We assume the nanoparticle is roughly # elliptical. @@ -78,7 +78,7 @@ def makeRecipe(ciffile, grdata, iqdata): model = EllipsoidModel() sasgenerator = SASGenerator("generator", model) sascontribution.add_profile_generator(sasgenerator) - sascontribution.setResidualEquation("resv") + sascontribution.set_residual_equation("resv") # Now we set up a characteristic function calculator that depends on the # sas model. diff --git a/src/diffpy/srfit/fitbase/fitcontribution.py b/src/diffpy/srfit/fitbase/fitcontribution.py index 3672f697..afcb2886 100644 --- a/src/diffpy/srfit/fitbase/fitcontribution.py +++ b/src/diffpy/srfit/fitbase/fitcontribution.py @@ -63,6 +63,13 @@ removal_version, ) +setresidualequation_dep_msg = build_deprecation_message( + base, + "setResidualEquation", + "set_residual_equation", + removal_version, +) + class FitContribution(ParameterSet): """FitContribution class. @@ -186,7 +193,7 @@ def set_profile(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.set_residual_equation("chiv") return @@ -262,7 +269,7 @@ def set_equation(self, eqstr, ns={}): This sets the equation that will be used when generating the residual for this FitContribution. The equation will be usable within - setResidualEquation as "eq", and it takes no arguments. + set_residual_equation as "eq", and it takes no arguments. Attributes ---------- @@ -296,7 +303,7 @@ def set_equation(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.set_residual_equation("chiv") return @@ -334,7 +341,7 @@ def getEquation(self): """ return self.get_equation() - def setResidualEquation(self, eqstr): + def set_residual_equation(self, eqstr): """Set the residual equation for the FitContribution. Attributes @@ -378,6 +385,18 @@ def setResidualEquation(self, eqstr): return + @deprecated(setresidualequation_dep_msg) + def setResidualEquation(self, eqstr): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use + diffpy.srfit.fitbase.FitContribution.set_residual_equation + instead. + """ + self.set_residual_equation(eqstr) + return + def getResidualEquation(self): """Get math expression string for the active residual equation. @@ -402,7 +421,7 @@ def residual(self): chiv = (eq() - self.profile.y) / self.profile.dy The value that is optimized is dot(chiv, chiv). - The residual equation can be changed with the setResidualEquation + The residual equation can be changed with the set_residual_equation method. """ # Assign the calculated profile diff --git a/src/diffpy/srfit/fitbase/simplerecipe.py b/src/diffpy/srfit/fitbase/simplerecipe.py index e5a89e44..c97c2281 100644 --- a/src/diffpy/srfit/fitbase/simplerecipe.py +++ b/src/diffpy/srfit/fitbase/simplerecipe.py @@ -288,8 +288,8 @@ def set_equation(self, eqstr, ns={}): """Set the profile equation for the FitContribution. This sets the equation that will be used when generating the residual. - The equation will be usable within setResidualEquation as "eq", and it - takes no arguments. + The equation will be usable within set_residual_equation as "eq", and + it takes no arguments. Attributes ---------- diff --git a/tests/test_contribution.py b/tests/test_contribution.py index 1e7cabd2..287b7b22 100644 --- a/tests/test_contribution.py +++ b/tests/test_contribution.py @@ -155,6 +155,17 @@ def testReplacements(self): self.assertEqual(len(xobs2), len(fc.residual())) return + def test_get_residual_equation(self): + """Check getting the current formula for residual equation.""" + fc = self.fitcontribution + self.assertEqual("", fc.getResidualEquation()) + fc.set_profile(self.profile) + fc.set_equation("A * x + B") + self.assertEqual("((eq - y) / dy)", fc.getResidualEquation()) + fc.set_residual_equation("2 * (eq - y)") + self.assertEqual("(2 * (eq - y))", fc.getResidualEquation()) + return + def test_getResidualEquation(self): """Check getting the current formula for residual equation.""" fc = self.fitcontribution @@ -175,7 +186,7 @@ def test_releaseOldEquations(self): self.assertEqual(1, len(fc._eqfactory.equations)) fc.set_profile(self.profile) for i in range(5): - fc.setResidualEquation("chiv") + fc.set_residual_equation("chiv") self.assertEqual(2, len(fc._eqfactory.equations)) return @@ -258,26 +269,26 @@ def testResidual(noObserversInGlobalBuilders): # Choose a new residual. fc.set_equation("2*I") - fc.setResidualEquation("resv") + fc.set_residual_equation("resv") chiv = fc.residual() assert dot(chiv, chiv) == pytest.approx( sum((2 * xobs - yobs) ** 2) / sum(yobs**2) ) # Make a custom residual. - fc.setResidualEquation("abs(eq-y)**0.5") + fc.set_residual_equation("abs(eq-y)**0.5") chiv = fc.residual() assert dot(chiv, chiv) == pytest.approx(sum(abs(2 * xobs - yobs))) # Test configuration checks fc1 = FitContribution("test1") with pytest.raises(SrFitError): - fc1.setResidualEquation("chiv") + fc1.set_residual_equation("chiv") fc1.set_profile(profile) with pytest.raises(SrFitError): - fc1.setResidualEquation("chiv") + fc1.set_residual_equation("chiv") fc1.set_equation("A * x") - fc1.setResidualEquation("chiv") + fc1.set_residual_equation("chiv") assert noObserversInGlobalBuilders return From 1a185a66c5b11d78012f7ca491aef56a8f6d84f7 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 20 Feb 2026 10:03:03 -0500 Subject: [PATCH 038/193] getResidualEquation deprecation --- src/diffpy/srfit/fitbase/fitcontribution.py | 21 ++++++++++++++++++++- tests/test_contribution.py | 10 +++++----- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitcontribution.py b/src/diffpy/srfit/fitbase/fitcontribution.py index afcb2886..c9e3df9c 100644 --- a/src/diffpy/srfit/fitbase/fitcontribution.py +++ b/src/diffpy/srfit/fitbase/fitcontribution.py @@ -70,6 +70,13 @@ removal_version, ) +getresidualequation_dep_msg = build_deprecation_message( + base, + "getResidualEquation", + "get_residual_equation", + removal_version, +) + class FitContribution(ParameterSet): """FitContribution class. @@ -397,7 +404,7 @@ def setResidualEquation(self, eqstr): self.set_residual_equation(eqstr) return - def getResidualEquation(self): + def get_residual_equation(self): """Get math expression string for the active residual equation. Return normalized math formula or an empty string if residual @@ -410,6 +417,18 @@ def getResidualEquation(self): rv = getExpression(self._reseq, eqskip="eq$") return rv + @deprecated(getresidualequation_dep_msg) + def getResidualEquation(self): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use + diffpy.srfit.fitbase.FitContribution.get_residual_equation + instead. + """ + + return self.get_residual_equation() + def residual(self): """Calculate the residual for this fitcontribution. diff --git a/tests/test_contribution.py b/tests/test_contribution.py index 287b7b22..001eee42 100644 --- a/tests/test_contribution.py +++ b/tests/test_contribution.py @@ -158,23 +158,23 @@ def testReplacements(self): def test_get_residual_equation(self): """Check getting the current formula for residual equation.""" fc = self.fitcontribution - self.assertEqual("", fc.getResidualEquation()) + self.assertEqual("", fc.get_residual_equation()) fc.set_profile(self.profile) fc.set_equation("A * x + B") - self.assertEqual("((eq - y) / dy)", fc.getResidualEquation()) + self.assertEqual("((eq - y) / dy)", fc.get_residual_equation()) fc.set_residual_equation("2 * (eq - y)") - self.assertEqual("(2 * (eq - y))", fc.getResidualEquation()) + self.assertEqual("(2 * (eq - y))", fc.get_residual_equation()) return def test_getResidualEquation(self): """Check getting the current formula for residual equation.""" fc = self.fitcontribution - self.assertEqual("", fc.getResidualEquation()) + self.assertEqual("", fc.get_residual_equation()) fc.set_profile(self.profile) fc.set_equation("A * x + B") self.assertEqual("((eq - y) / dy)", fc.getResidualEquation()) fc.setResidualEquation("2 * (eq - y)") - self.assertEqual("(2 * (eq - y))", fc.getResidualEquation()) + self.assertEqual("(2 * (eq - y))", fc.get_residual_equation()) return def test_releaseOldEquations(self): From 7673a968ae0b42b2fb6b6853725fc3a89c161b5b Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 20 Feb 2026 10:05:16 -0500 Subject: [PATCH 039/193] news --- news/fitcontrib-dep-final.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 news/fitcontrib-dep-final.rst diff --git a/news/fitcontrib-dep-final.rst b/news/fitcontrib-dep-final.rst new file mode 100644 index 00000000..6be8aff6 --- /dev/null +++ b/news/fitcontrib-dep-final.rst @@ -0,0 +1,24 @@ +**Added:** + +* Added ``get_residual_equation`` method to ``FitContribution``. +* Added ``set_residual_equation`` method to ``FitContribution``. + +**Changed:** + +* + +**Deprecated:** + +* Deprecated ``getResidualEquation`` method of ``FitContribution``. + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 1a3aa786f6e287fecc148dc4d14726dc7c5756e2 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 20 Feb 2026 10:05:58 -0500 Subject: [PATCH 040/193] news again --- news/fitcontrib-dep-final.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/news/fitcontrib-dep-final.rst b/news/fitcontrib-dep-final.rst index 6be8aff6..44a3b787 100644 --- a/news/fitcontrib-dep-final.rst +++ b/news/fitcontrib-dep-final.rst @@ -9,7 +9,8 @@ **Deprecated:** -* Deprecated ``getResidualEquation`` method of ``FitContribution``. +* Deprecated ``getResidualEquation`` method of ``FitContribution`` for removal in 4.0.0. +* Deprecated ``setResidualEquation`` method of ``FitContribution`` for removal in 4.0.0. **Removed:** From ae8f503b2b7b417ab9d22e66f35e13e1a0d7efad Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 20 Feb 2026 13:21:57 -0500 Subject: [PATCH 041/193] add test for remove and add param_set --- tests/test_fitrecipe.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 2b0d1e1c..4a2b3199 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -291,6 +291,34 @@ def testPrintFitHook(capturestdout): return +def test_add_and_remove_ParameterSet(): + # add a parset + recipe = FitRecipe("recipe") + parameter_to_add = Parameter("added_param", 1) + recipe.addParameterSet(parameter_to_add) + # check that the parameter is added + assert recipe.added_param == parameter_to_add + assert recipe.added_param.value == 1 + # remove the added parameter + recipe.removeParameterSet(parameter_to_add) + # check that the parameter is removed + assert not hasattr(recipe, "added_param") + + +def test_add_and_remove_parameter_set(): + recipe = FitRecipe("recipe") + parameter_to_add = Parameter("added_param", 1) + # add a parset + recipe.add_parameter_set(parameter_to_add) + # check that the parameter is added + assert recipe.added_param == parameter_to_add + assert recipe.added_param.value == 1 + # remove the added parameter + recipe.remove_parameter_set(parameter_to_add) + # check that the parameter is removed + assert not hasattr(recipe, "added_param") + + def test_add_contribution(capturestdout): """Duplicated test of PrintFitHooks except addContribution method has changed to the new add_contribution method. This is because addContribution From d67ac9e7953ea20d4b33c21fec0139c4e07152ac Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 20 Feb 2026 13:24:09 -0500 Subject: [PATCH 042/193] removeParameterSet deprecation --- src/diffpy/srfit/fitbase/fitrecipe.py | 16 +++++++++++++++- src/diffpy/srfit/fitbase/parameterset.py | 18 +++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 7065968e..d1c744ee 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -79,6 +79,10 @@ base, "addParameterSet", "add_parameter_set", removal_version ) +removeParameterSet_dep_msg = build_deprecation_message( + base, "removeParameterSet", "remove_parameter_set", removal_version +) + class FitRecipe(_fitrecipe_interface, RecipeOrganizer): """FitRecipe class. @@ -375,7 +379,7 @@ def addParameterSet(self, parset): self.add_parameter_set(parset) return - def removeParameterSet(self, parset): + def remove_parameter_set(self, parset): """Remove a ParameterSet from the hierarchy. Raises ValueError if parset is not managed by this object. @@ -383,6 +387,16 @@ def removeParameterSet(self, parset): self._remove_object(parset, self._parsets) return + @deprecated(removeParameterSet_dep_msg) + def removeParameterSet(self, parset): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.remove_parameter_set instead. + """ + self.remove_parameter_set(parset) + return + def residual(self, p=[]): """Calculate the vector residual to be optimized. diff --git a/src/diffpy/srfit/fitbase/parameterset.py b/src/diffpy/srfit/fitbase/parameterset.py index 918951da..6d200ca9 100644 --- a/src/diffpy/srfit/fitbase/parameterset.py +++ b/src/diffpy/srfit/fitbase/parameterset.py @@ -34,6 +34,10 @@ base, "addParameterSet", "add_parameter_set", removal_version ) +removeParameterSet_dep_msg = build_deprecation_message( + base, "removeParameterSet", "remove_parameter_set", removal_version +) + class ParameterSet(RecipeOrganizer): """Class for organizing Parameters and other ParameterSets. @@ -123,7 +127,7 @@ def addParameterSet(self, parset): self.add_parameter_set(parset) return - def removeParameterSet(self, parset): + def remove_parameter_set(self, parset): """Remove a ParameterSet from the hierarchy. Raises ValueError if parset is not managed by this object. @@ -131,6 +135,18 @@ def removeParameterSet(self, parset): self._remove_object(parset, self._parsets) return + @deprecated(removeParameterSet_dep_msg) + def removeParameterSet(self, parset): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use + diffpy.srfit.fitbase.parameterset.ParameterSet.remove_parameter_set + instead. + """ + self.remove_parameter_set(parset) + return + def setConst(self, const=True): """Set every parameter within the set to a constant. From b106f5c9b6fc65f9ca6455e4ee65e43d48c83a6a Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 20 Feb 2026 13:30:17 -0500 Subject: [PATCH 043/193] scalarResidual deprecation --- src/diffpy/srfit/fitbase/fitrecipe.py | 20 +++++++++++++++++--- tests/test_fitrecipe.py | 14 +++++++------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index d1c744ee..22964503 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -83,6 +83,10 @@ base, "removeParameterSet", "remove_parameter_set", removal_version ) +scalarResidual_dep_msg = build_deprecation_message( + base, "scalarResidual", "scalar_residual", removal_version +) + class FitRecipe(_fitrecipe_interface, RecipeOrganizer): """FitRecipe class. @@ -448,7 +452,7 @@ def residual(self, p=[]): return chiv - def scalarResidual(self, p=[]): + def scalar_residual(self, p=[]): """Calculate the scalar residual to be optimized. Parameters @@ -468,9 +472,19 @@ def scalarResidual(self, p=[]): chiv = self.residual(p) return dot(chiv, chiv) + @deprecated(scalarResidual_dep_msg) + def scalarResidual(self, p=[]): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.scalar_residual + instead. + """ + return self.scalar_residual(p) + def __call__(self, p=[]): - """Same as scalarResidual method.""" - return self.scalarResidual(p) + """Same as scalar_residual method.""" + return self.scalar_residual(p) def _prepare(self): """Prepare for the residual calculation, if necessary. diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 4a2b3199..9008d359 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -273,14 +273,14 @@ def testPrintFitHook(capturestdout): recipe.addVar(fitcontribution.c) recipe.restrain("c", lb=5) (pfh,) = recipe.getFitHooks() - out = capturestdout(recipe.scalarResidual) + out = capturestdout(recipe.scalar_residual) assert "" == out pfh.verbose = 1 - out = capturestdout(recipe.scalarResidual) + out = capturestdout(recipe.scalar_residual) assert out.strip().isdigit() assert "\nRestraints:" not in out pfh.verbose = 2 - out = capturestdout(recipe.scalarResidual) + out = capturestdout(recipe.scalar_residual) assert "\nResidual:" in out assert "\nRestraints:" in out assert "\nVariables" not in out @@ -349,19 +349,19 @@ def test_add_contribution(capturestdout): recipe.addVar(fitcontribution.c) recipe.restrain("c", lb=5) (pfh,) = recipe.get_fit_hooks() - out = capturestdout(recipe.scalarResidual) + out = capturestdout(recipe.scalar_residual) assert "" == out pfh.verbose = 1 - out = capturestdout(recipe.scalarResidual) + out = capturestdout(recipe.scalar_residual) assert out.strip().isdigit() assert "\nRestraints:" not in out pfh.verbose = 2 - out = capturestdout(recipe.scalarResidual) + out = capturestdout(recipe.scalar_residual) assert "\nResidual:" in out assert "\nRestraints:" in out assert "\nVariables" not in out pfh.verbose = 3 - out = capturestdout(recipe.scalarResidual) + out = capturestdout(recipe.scalar_residual) assert "\nVariables" in out assert "c = " in out return From 36e8f445ac7c4e9dd5939e7a63bd5a6e98527a0a Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 20 Feb 2026 13:38:48 -0500 Subject: [PATCH 044/193] addVar deprecation --- docs/examples/coreshellnp.py | 26 +++++---- docs/examples/crystalpdf.py | 10 ++-- docs/examples/crystalpdfall.py | 12 ++-- docs/examples/crystalpdfobjcryst.py | 8 +-- docs/examples/crystalpdftwodata.py | 10 ++-- docs/examples/crystalpdftwophase.py | 10 ++-- docs/examples/debyemodel.py | 4 +- docs/examples/debyemodelII.py | 4 +- docs/examples/ellipsoidsas.py | 8 +-- docs/examples/gaussiangenerator.py | 6 +- docs/examples/gaussianrecipe.py | 6 +- docs/examples/interface.py | 2 +- docs/examples/npintensity.py | 26 ++++----- docs/examples/npintensityII.py | 50 ++++++++--------- docs/examples/nppdfcrystal.py | 8 +-- docs/examples/nppdfobjcryst.py | 4 +- docs/examples/nppdfsas.py | 12 ++-- docs/examples/simplepdf.py | 10 ++-- docs/examples/simplepdftwophase.py | 12 ++-- docs/examples/threedoublepeaks.py | 26 ++++----- src/diffpy/srfit/fitbase/fitrecipe.py | 23 +++++--- src/diffpy/srfit/fitbase/simplerecipe.py | 2 +- src/diffpy/srfit/interface/interface.py | 4 +- tests/conftest.py | 18 +++--- tests/test_fitrecipe.py | 70 ++++++++++++++++++++---- tests/test_sgconstraints.py | 2 +- 26 files changed, 217 insertions(+), 156 deletions(-) diff --git a/docs/examples/coreshellnp.py b/docs/examples/coreshellnp.py index 0ab04609..927980bc 100644 --- a/docs/examples/coreshellnp.py +++ b/docs/examples/coreshellnp.py @@ -89,8 +89,8 @@ def makeRecipe(stru1, stru2, datname): # Vary the inner radius and thickness of the shell. Constrain the core # diameter to twice the shell radius. - recipe.addVar(contribution.radius, 15) - recipe.addVar(contribution.thickness, 11) + recipe.add_variable(contribution.radius, 15) + recipe.add_variable(contribution.thickness, 11) recipe.constrain(contribution.psize, "2 * radius") # Configure the fit variables @@ -102,30 +102,34 @@ def makeRecipe(stru1, stru2, datname): # We also want the resolution factor to be the same on each. # Vary the global scale as well. - recipe.addVar(contribution.scale, 0.3) + recipe.add_variable(contribution.scale, 0.3) # Now we can configure the structural parameters. We tag the different # structural variables so we can easily turn them on and off in the # subsequent refinement. phase_cds = generator_cds.phase for par in phase_cds.sgpars.latpars: - recipe.addVar(par, name=par.name + "_cds", tag="lat") + recipe.add_variable(par, name=par.name + "_cds", tag="lat") for par in phase_cds.sgpars.adppars: - recipe.addVar(par, 1, name=par.name + "_cds", tag="adp") - recipe.addVar(phase_cds.sgpars.xyzpars.z_1, name="z_1_cds", tag="xyz") + recipe.add_variable(par, 1, name=par.name + "_cds", tag="adp") + recipe.add_variable( + phase_cds.sgpars.xyzpars.z_1, name="z_1_cds", tag="xyz" + ) # Since we know these have stacking disorder, constrain the B33 adps for # each atom type. recipe.constrain("B33_1_cds", "B33_0_cds") - recipe.addVar(generator_cds.delta2, name="delta2_cds", value=5) + recipe.add_variable(generator_cds.delta2, name="delta2_cds", value=5) phase_zns = generator_zns.phase for par in phase_zns.sgpars.latpars: - recipe.addVar(par, name=par.name + "_zns", tag="lat") + recipe.add_variable(par, name=par.name + "_zns", tag="lat") for par in phase_zns.sgpars.adppars: - recipe.addVar(par, 1, name=par.name + "_zns", tag="adp") - recipe.addVar(phase_zns.sgpars.xyzpars.z_1, name="z_1_zns", tag="xyz") + recipe.add_variable(par, 1, name=par.name + "_zns", tag="adp") + recipe.add_variable( + phase_zns.sgpars.xyzpars.z_1, name="z_1_zns", tag="xyz" + ) recipe.constrain("B33_1_zns", "B33_0_zns") - recipe.addVar(generator_zns.delta2, name="delta2_zns", value=2.5) + recipe.add_variable(generator_zns.delta2, name="delta2_zns", value=2.5) # Give the recipe away so it can be used! return recipe diff --git a/docs/examples/crystalpdf.py b/docs/examples/crystalpdf.py index 4fbc50e4..9fd7dd9e 100644 --- a/docs/examples/crystalpdf.py +++ b/docs/examples/crystalpdf.py @@ -113,17 +113,17 @@ def makeRecipe(ciffile, datname): # the xyzpars, latpars, and adppars members of the SpaceGroupParameters # object. for par in sgpars.latpars: - recipe.addVar(par) + recipe.add_variable(par) for par in sgpars.adppars: - recipe.addVar(par, 0.005) + recipe.add_variable(par, 0.005) # We now select non-structural parameters to refine. # This controls the scaling of the PDF. - recipe.addVar(generator.scale, 1) + recipe.add_variable(generator.scale, 1) # This is a peak-damping resolution term. - recipe.addVar(generator.qdamp, 0.01) + recipe.add_variable(generator.qdamp, 0.01) # This is a vibrational correlation term that sharpens peaks at low-r. - recipe.addVar(generator.delta2, 5) + recipe.add_variable(generator.delta2, 5) # Give the recipe away so it can be used! return recipe diff --git a/docs/examples/crystalpdfall.py b/docs/examples/crystalpdfall.py index 570c6a27..5eee276a 100644 --- a/docs/examples/crystalpdfall.py +++ b/docs/examples/crystalpdfall.py @@ -111,23 +111,23 @@ def makeRecipe( # Now we vary and constrain Parameters as before. for par in phase_ni.sgpars: - recipe.addVar(par, name=par.name + "_ni") + recipe.add_variable(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.add_variable(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(xcontribution_sini.scale, 1.0, "xscale_sini") + recipe.add_variable(xgenerator_ni.scale, name="xscale_ni") + recipe.add_variable(xgenerator_si.scale, name="xscale_si") + recipe.add_variable(ngenerator_ni.scale, name="nscale_ni") + recipe.add_variable(xcontribution_sini.scale, 1.0, "xscale_sini") recipe.newVar("pscale_sini_ni", 0.8) recipe.constrain(xgenerator_sini_ni.scale, "pscale_sini_ni") recipe.constrain(xgenerator_sini_si.scale, "1 - pscale_sini_ni") diff --git a/docs/examples/crystalpdfobjcryst.py b/docs/examples/crystalpdfobjcryst.py index a4fdf23c..a5796d01 100644 --- a/docs/examples/crystalpdfobjcryst.py +++ b/docs/examples/crystalpdfobjcryst.py @@ -90,18 +90,18 @@ def makeRecipe(ciffile, datname): # As before, we have one free lattice parameter ('a'). We can simplify # things by iterating through all the sgpars. for par in phase.sgpars: - recipe.addVar(par) + recipe.add_variable(par) # set the initial thermal factor to a non-zero value assert hasattr(recipe, "B11_0") recipe.B11_0 = 0.1 # We now select non-structural parameters to refine. # This controls the scaling of the PDF. - recipe.addVar(generator.scale, 1) + recipe.add_variable(generator.scale, 1) # This is a peak-damping resolution term. - recipe.addVar(generator.qdamp, 0.01) + recipe.add_variable(generator.qdamp, 0.01) # This is a vibrational correlation term that sharpens peaks at low-r. - recipe.addVar(generator.delta2, 5) + recipe.add_variable(generator.delta2, 5) # Give the recipe away so it can be used! return recipe diff --git a/docs/examples/crystalpdftwodata.py b/docs/examples/crystalpdftwodata.py index b9293a9e..ddd41f29 100644 --- a/docs/examples/crystalpdftwodata.py +++ b/docs/examples/crystalpdftwodata.py @@ -114,10 +114,10 @@ def makeRecipe(ciffile, xdatname, ndatname): recipe.add_contribution(ncontribution) # Now we vary and constrain Parameters as before. - recipe.addVar(xgenerator.scale, 1, "xscale") - recipe.addVar(ngenerator.scale, 1, "nscale") - recipe.addVar(xgenerator.qdamp, 0.01, "xqdamp") - recipe.addVar(ngenerator.qdamp, 0.01, "nqdamp") + recipe.add_variable(xgenerator.scale, 1, "xscale") + recipe.add_variable(ngenerator.scale, 1, "nscale") + recipe.add_variable(xgenerator.qdamp, 0.01, "xqdamp") + recipe.add_variable(ngenerator.qdamp, 0.01, "nqdamp") # delta2 is a non-structual material property. Thus, we constrain together # delta2 Parameter from each PDFGenerator. delta2 = recipe.newVar("delta2", 2) @@ -128,7 +128,7 @@ def makeRecipe(ciffile, xdatname, ndatname): # ObjCrystCrystalParSet for the Crystal. phase = xgenerator.phase for par in phase.sgpars: - recipe.addVar(par) + recipe.add_variable(par) recipe.B11_0 = 0.1 # Give the recipe away so it can be used! diff --git a/docs/examples/crystalpdftwophase.py b/docs/examples/crystalpdftwophase.py index 7087a4db..fb601433 100644 --- a/docs/examples/crystalpdftwophase.py +++ b/docs/examples/crystalpdftwophase.py @@ -98,7 +98,7 @@ def makeRecipe(niciffile, siciffile, datname): recipe.constrain(generator_si.qdamp, "qdamp") # Vary the global scale as well. - recipe.addVar(contribution.scale, 1) + recipe.add_variable(contribution.scale, 1) # Now we can configure the structural parameters. Since we're using # ObjCrystCrystalParSets, the space group constraints are automatically @@ -107,13 +107,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.add_variable(par, name=par.name + "_ni") + recipe.add_variable(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.add_variable(par, name=par.name + "_si") + recipe.add_variable(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. diff --git a/docs/examples/debyemodel.py b/docs/examples/debyemodel.py index 6a029998..1332e462 100644 --- a/docs/examples/debyemodel.py +++ b/docs/examples/debyemodel.py @@ -139,9 +139,9 @@ def makeRecipe(): # Specify which Parameters we want to refine. # Vary the offset - recipe.addVar(contribution.offset, 0) + recipe.add_variable(contribution.offset, 0) # We also vary the Debye temperature. - recipe.addVar(contribution.thetaD, 100) + recipe.add_variable(contribution.thetaD, 100) # We would like to 'suggest' that the offset should remain positive. This # is somethine that we know about the system that might help the refinement diff --git a/docs/examples/debyemodelII.py b/docs/examples/debyemodelII.py index fe686f0b..4a815437 100644 --- a/docs/examples/debyemodelII.py +++ b/docs/examples/debyemodelII.py @@ -83,8 +83,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.add_variable(recipe.lowT.offset, name="lowToffset") + recipe.add_variable(recipe.highT.offset, name="highToffset") # We create a new Variable and use the recipe's "constrain" method to # associate the Debye temperature parameters with that variable. recipe.newVar("thetaD", 100) diff --git a/docs/examples/ellipsoidsas.py b/docs/examples/ellipsoidsas.py index 4fbd6ef8..dda9cd5f 100644 --- a/docs/examples/ellipsoidsas.py +++ b/docs/examples/ellipsoidsas.py @@ -78,10 +78,10 @@ def makeRecipe(datname): # SASGenerator these are named like "radius_width". # # We want to fit the scale factor, radii and background factors. - recipe.addVar(generator.scale, 1) - recipe.addVar(generator.radius_a, 50) - recipe.addVar(generator.radius_b, 500) - recipe.addVar(generator.background, 0) + recipe.add_variable(generator.scale, 1) + recipe.add_variable(generator.radius_a, 50) + recipe.add_variable(generator.radius_b, 500) + recipe.add_variable(generator.background, 0) # Give the recipe away so it can be used! return recipe diff --git a/docs/examples/gaussiangenerator.py b/docs/examples/gaussiangenerator.py index 4756474e..69c1507c 100644 --- a/docs/examples/gaussiangenerator.py +++ b/docs/examples/gaussiangenerator.py @@ -161,9 +161,9 @@ def makeRecipe(): # that the Parameters belong to the GaussianGenerator, not the # FitContribution as in gaussianrecipe.py. We initialize parameters as in # 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.add_variable(generator.A, 1) + recipe.add_variable(generator.x0, 5) + recipe.add_variable(generator.sigma, name="sig") recipe.sig.value = 1 # Give the recipe away so it can be used! diff --git a/docs/examples/gaussianrecipe.py b/docs/examples/gaussianrecipe.py index f03c9d6d..7bf85355 100644 --- a/docs/examples/gaussianrecipe.py +++ b/docs/examples/gaussianrecipe.py @@ -149,13 +149,13 @@ def makeRecipe(): # Here we create a Variable for the 'A' Parameter from our fit equation. # The resulting Variable will be named 'A' as well, but it will be accessed # via the FitRecipe. - recipe.addVar(contribution.A) + recipe.add_variable(contribution.A) # Here we create the Variable for 'x0' and give it an initial value of 5. - recipe.addVar(contribution.x0, 5) + recipe.add_variable(contribution.x0, 5) # Here we create a Variable named 'sig', which is tied to the 'sigma' # Parameter of our FitContribution. We give it an initial value through the # FitRecipe instance. - recipe.addVar(contribution.sigma, name="sig") + recipe.add_variable(contribution.sigma, name="sig") recipe.sig.value = 1 return recipe diff --git a/docs/examples/interface.py b/docs/examples/interface.py index 640aebc0..bb77b552 100644 --- a/docs/examples/interface.py +++ b/docs/examples/interface.py @@ -46,7 +46,7 @@ def main(): # FitRecipe operations # "|=" - Union of necessary components. # "+=" - Add Parameter or create a new one. Each tuple is a set of - # arguments for either setVar or addVar. + # arguments for either setVar or add_variable. # "*=" - Constrain a parameter. Think of "*" as a push-pin holding one # parameter's value to that of another. # "%=" - Restrain a parameter or equation. Think of "%" as a rope diff --git a/docs/examples/npintensity.py b/docs/examples/npintensity.py index a1c6ffc2..cd54adb9 100644 --- a/docs/examples/npintensity.py +++ b/docs/examples/npintensity.py @@ -263,20 +263,20 @@ def gaussian(q, q0, width): recipe.add_contribution(contribution) # Specify which parameters we want to refine. - recipe.addVar(contribution.b0, 0) - recipe.addVar(contribution.b1, 0) - recipe.addVar(contribution.b2, 0) - recipe.addVar(contribution.b3, 0) - recipe.addVar(contribution.b4, 0) - recipe.addVar(contribution.b5, 0) - recipe.addVar(contribution.b6, 0) - recipe.addVar(contribution.b7, 0) - recipe.addVar(contribution.b8, 0) - recipe.addVar(contribution.b9, 0) + recipe.add_variable(contribution.b0, 0) + recipe.add_variable(contribution.b1, 0) + recipe.add_variable(contribution.b2, 0) + recipe.add_variable(contribution.b3, 0) + recipe.add_variable(contribution.b4, 0) + recipe.add_variable(contribution.b5, 0) + recipe.add_variable(contribution.b6, 0) + recipe.add_variable(contribution.b7, 0) + recipe.add_variable(contribution.b8, 0) + recipe.add_variable(contribution.b9, 0) # We also want to adjust the scale and the convolution width - recipe.addVar(contribution.scale, 1) - recipe.addVar(contribution.width, 0.1) + recipe.add_variable(contribution.scale, 1) + recipe.add_variable(contribution.width, 0.1) # We can also refine structural parameters. Here we extract the # DiffpyStructureParSet from the intensity generator and use the parameters @@ -289,7 +289,7 @@ def gaussian(q, q0, width): # constrained to a Variable by name. This has the same effect. lattice = phase.getLattice() a = lattice.a - recipe.addVar(a) + recipe.add_variable(a) recipe.constrain(lattice.b, a) recipe.constrain(lattice.c, a) # We want to refine the thermal parameters as well. We will add a new diff --git a/docs/examples/npintensityII.py b/docs/examples/npintensityII.py index 8364a113..6956af46 100644 --- a/docs/examples/npintensityII.py +++ b/docs/examples/npintensityII.py @@ -138,38 +138,38 @@ 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.add_variable(contribution1.b0, 0, name="b1_0", tag="bcoeffs1") + recipe.add_variable(contribution1.b1, 0, name="b1_1", tag="bcoeffs1") + recipe.add_variable(contribution1.b2, 0, name="b1_2", tag="bcoeffs1") + recipe.add_variable(contribution1.b3, 0, name="b1_3", tag="bcoeffs1") + recipe.add_variable(contribution1.b4, 0, name="b1_4", tag="bcoeffs1") + recipe.add_variable(contribution1.b5, 0, name="b1_5", tag="bcoeffs1") + recipe.add_variable(contribution1.b6, 0, name="b1_6", tag="bcoeffs1") + recipe.add_variable(contribution1.b7, 0, name="b1_7", tag="bcoeffs1") + recipe.add_variable(contribution1.b8, 0, name="b1_8", tag="bcoeffs1") + recipe.add_variable(contribution1.b9, 0, name="b1_9", tag="bcoeffs1") + recipe.add_variable(contribution2.b0, 0, name="b2_0", tag="bcoeffs2") + recipe.add_variable(contribution2.b1, 0, name="b2_1", tag="bcoeffs2") + recipe.add_variable(contribution2.b2, 0, name="b2_2", tag="bcoeffs2") + recipe.add_variable(contribution2.b3, 0, name="b2_3", tag="bcoeffs2") + recipe.add_variable(contribution2.b4, 0, name="b2_4", tag="bcoeffs2") + recipe.add_variable(contribution2.b5, 0, name="b2_5", tag="bcoeffs2") + recipe.add_variable(contribution2.b6, 0, name="b2_6", tag="bcoeffs2") + recipe.add_variable(contribution2.b7, 0, name="b2_7", tag="bcoeffs2") + recipe.add_variable(contribution2.b8, 0, name="b2_8", tag="bcoeffs2") + recipe.add_variable(contribution2.b9, 0, name="b2_9", tag="bcoeffs2") # We also want to adjust the scale and the convolution width - recipe.addVar(contribution1.scale, 1, name="scale1") - recipe.addVar(contribution1.width, 0.1, name="width1") - recipe.addVar(contribution2.scale, 1, name="scale2") - recipe.addVar(contribution2.width, 0.1, name="width2") + recipe.add_variable(contribution1.scale, 1, name="scale1") + recipe.add_variable(contribution1.width, 0.1, name="width1") + recipe.add_variable(contribution2.scale, 1, name="scale2") + recipe.add_variable(contribution2.width, 0.1, name="width2") # We can also refine structural parameters. We only have to do this once, # since each generator holds the same DiffpyStructureParSet. phase = generator1.phase lattice = phase.getLattice() - a = recipe.addVar(lattice.a) + a = recipe.add_variable(lattice.a) # We want to allow for isotropic expansion, so we'll make constraints for # that. recipe.constrain(lattice.b, a) diff --git a/docs/examples/nppdfcrystal.py b/docs/examples/nppdfcrystal.py index df64c109..457a9571 100644 --- a/docs/examples/nppdfcrystal.py +++ b/docs/examples/nppdfcrystal.py @@ -71,11 +71,11 @@ def makeRecipe(ciffile, grdata): phase = pdfgenerator.phase for par in phase.sgpars: - recipe.addVar(par) + recipe.add_variable(par) - recipe.addVar(pdfcontribution.psize, 20) - recipe.addVar(pdfgenerator.scale, 1) - recipe.addVar(pdfgenerator.delta2, 0) + recipe.add_variable(pdfcontribution.psize, 20) + recipe.add_variable(pdfgenerator.scale, 1) + recipe.add_variable(pdfgenerator.delta2, 0) recipe.B11_0 = 0.1 return recipe diff --git a/docs/examples/nppdfobjcryst.py b/docs/examples/nppdfobjcryst.py index 45ac1be6..3b0127aa 100644 --- a/docs/examples/nppdfobjcryst.py +++ b/docs/examples/nppdfobjcryst.py @@ -101,8 +101,8 @@ def makeRecipe(molecule, datname): # Add the correlation term, scale. The scale is too short to effectively # determine qdamp. - recipe.addVar(generator.delta2, 2) - recipe.addVar(generator.scale, 1.3e4) + recipe.add_variable(generator.delta2, 2) + recipe.add_variable(generator.scale, 1.3e4) # Give the recipe away so it can be used! return recipe diff --git a/docs/examples/nppdfsas.py b/docs/examples/nppdfsas.py index 0df85c56..441f0873 100644 --- a/docs/examples/nppdfsas.py +++ b/docs/examples/nppdfsas.py @@ -99,15 +99,15 @@ def makeRecipe(ciffile, grdata, iqdata): # PDF phase = pdfgenerator.phase for par in phase.sgpars: - recipe.addVar(par) + recipe.add_variable(par) - recipe.addVar(pdfgenerator.scale, 1) - recipe.addVar(pdfgenerator.delta2, 0) + recipe.add_variable(pdfgenerator.scale, 1) + recipe.add_variable(pdfgenerator.delta2, 0) # SAS - recipe.addVar(sasgenerator.scale, 1, name="iqscale") - recipe.addVar(sasgenerator.radius_a, 10) - recipe.addVar(sasgenerator.radius_b, 10) + recipe.add_variable(sasgenerator.scale, 1, name="iqscale") + recipe.add_variable(sasgenerator.radius_a, 10) + recipe.add_variable(sasgenerator.radius_b, 10) # Even though the cfcalculator and sasgenerator depend on the same sas # model, we must still constrain the cfcalculator Parameters so that it is diff --git a/docs/examples/simplepdf.py b/docs/examples/simplepdf.py index ffe69dd4..cb04b539 100644 --- a/docs/examples/simplepdf.py +++ b/docs/examples/simplepdf.py @@ -54,13 +54,13 @@ def makeRecipe(ciffile, datname): sgpars = constrainAsSpaceGroup(phase, "Fm-3m") for par in sgpars.latpars: - recipe.addVar(par) + recipe.add_variable(par) for par in sgpars.adppars: - recipe.addVar(par, 0.005) + recipe.add_variable(par, 0.005) - recipe.addVar(contribution.scale, 1) - recipe.addVar(contribution.qdamp, 0.03, fixed=True) - recipe.addVar(contribution.nickel.delta2, 5) + recipe.add_variable(contribution.scale, 1) + recipe.add_variable(contribution.qdamp, 0.03, fixed=True) + recipe.add_variable(contribution.nickel.delta2, 5) # Give the recipe away so it can be used! return recipe diff --git a/docs/examples/simplepdftwophase.py b/docs/examples/simplepdftwophase.py index 134d8855..fdb9ab2d 100644 --- a/docs/examples/simplepdftwophase.py +++ b/docs/examples/simplepdftwophase.py @@ -51,10 +51,10 @@ def makeRecipe(niciffile, siciffile, datname): recipe.constrain(contribution.si.scale, "1 - scale_ni") # We also want the resolution factor to be the same on each. This is done # for free by the PDFContribution. We simply need to add it to the recipe. - recipe.addVar(contribution.qdamp, 0.03) + recipe.add_variable(contribution.qdamp, 0.03) # Vary the global scale as well. - recipe.addVar(contribution.scale, 1) + recipe.add_variable(contribution.scale, 1) # Now we can configure the structural parameters. Since we're using # ObjCrystCrystalParSets, the space group constraints are automatically @@ -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.add_variable(par, name=par.name + "_ni") + recipe.add_variable(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.add_variable(par, name=par.name + "_si") + recipe.add_variable(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. diff --git a/docs/examples/threedoublepeaks.py b/docs/examples/threedoublepeaks.py index d54428da..951ead5a 100644 --- a/docs/examples/threedoublepeaks.py +++ b/docs/examples/threedoublepeaks.py @@ -101,14 +101,14 @@ def delta(t, mu): recipe.add_contribution(contribution) # Vary the amplitudes for each double peak - recipe.addVar(contribution.A1, 100) - recipe.addVar(contribution.A2, 100) - recipe.addVar(contribution.A3, 100) + recipe.add_variable(contribution.A1, 100) + recipe.add_variable(contribution.A2, 100) + recipe.add_variable(contribution.A3, 100) # Vary the position of the first of the double peaks - recipe.addVar(contribution.mu11, 13.0) - recipe.addVar(contribution.mu21, 24.0) - recipe.addVar(contribution.mu31, 33.0) + recipe.add_variable(contribution.mu11, 13.0) + recipe.add_variable(contribution.mu21, 24.0) + recipe.add_variable(contribution.mu31, 33.0) # Constrain the position of the second double peak from numpy import arcsin, sin @@ -158,13 +158,13 @@ def sig(sig0, dsig, mu): ) # 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.add_variable(contribution.b0, 0, tag="bkgd") + recipe.add_variable(contribution.b1, 0, tag="bkgd") + recipe.add_variable(contribution.b2, 0, tag="bkgd") + recipe.add_variable(contribution.b3, 0, tag="bkgd") + recipe.add_variable(contribution.b4, 0, tag="bkgd") + recipe.add_variable(contribution.b5, 0, tag="bkgd") + recipe.add_variable(contribution.b6, 0, tag="bkgd") return recipe diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 22964503..e31721e3 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -87,6 +87,10 @@ base, "scalarResidual", "scalar_residual", removal_version ) +addVar_dep_msg = build_deprecation_message( + base, "addVar", "add_variable", removal_version +) + class FitRecipe(_fitrecipe_interface, RecipeOrganizer): """FitRecipe class. @@ -641,7 +645,7 @@ def cmp(x, y): # Variable manipulation - def addVar( + def add_variable( self, par, value=None, name=None, fixed=False, tag=None, tags=[] ): """Add a variable to be refined. @@ -679,22 +683,16 @@ def addVar( Raises ValueError if par is constrained. """ name = name or par.name - if par.const: raise ValueError("The parameter '%s' is constant" % par) - if par.constrained: raise ValueError("The parameter '%s' is constrained" % par) - var = ParameterProxy(name, par) if value is not None: var.setValue(value) - self._add_parameter(var) - if fixed: self.fix(var) - # Tag with passed tags and by name self._tagmanager.tag(var, var.name) self._tagmanager.tag(var, "all") @@ -703,6 +701,17 @@ def addVar( self._tagmanager.tag(var, tag) return var + @deprecated(addVar_dep_msg) + def addVar( + self, par, value=None, name=None, fixed=False, tag=None, tags=[] + ): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.add_variable instead. + """ + return self.add_variable(par, value, name, fixed, tag, tags) + def delVar(self, var): """Remove a variable. diff --git a/src/diffpy/srfit/fitbase/simplerecipe.py b/src/diffpy/srfit/fitbase/simplerecipe.py index c97c2281..36391e86 100644 --- a/src/diffpy/srfit/fitbase/simplerecipe.py +++ b/src/diffpy/srfit/fitbase/simplerecipe.py @@ -314,7 +314,7 @@ def set_equation(self, eqstr, ns={}): if par.value is None: par.value = 0 if par.name not in self._parameters: - self.addVar(par) + self.add_variable(par) return @deprecated(setEquation_dep_msg) diff --git a/src/diffpy/srfit/interface/interface.py b/src/diffpy/srfit/interface/interface.py index f2b3ea17..6dee58ab 100644 --- a/src/diffpy/srfit/interface/interface.py +++ b/src/diffpy/srfit/interface/interface.py @@ -127,12 +127,12 @@ def __iadd__(self, args): arguments or argument tuples. """ - # Want to detect addVar or newVar + # Want to detect add_variable or newVar def f(*args): if isinstance(args[0], six.string_types): self.newVar(*args) else: - self.addVar(*args) + self.add_variable(*args) return _applymanyargs(args, f) diff --git a/tests/conftest.py b/tests/conftest.py index 5aec22ec..910564fc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -158,9 +158,9 @@ def build_recipe_one_contribution(): contribution.set_equation("A*sin(k*x + c)") recipe = FitRecipe() recipe.add_contribution(contribution) - recipe.addVar(contribution.A, 1) - recipe.addVar(contribution.k, 1) - recipe.addVar(contribution.c, 1) + recipe.add_variable(contribution.A, 1) + recipe.add_variable(contribution.k, 1) + recipe.add_variable(contribution.c, 1) return recipe @@ -184,12 +184,12 @@ def build_recipe_two_contributions(): recipe = FitRecipe() recipe.add_contribution(contribution1) recipe.add_contribution(contribution2) - recipe.addVar(contribution1.A, 1) - recipe.addVar(contribution1.k, 1) - recipe.addVar(contribution1.c, 1) - recipe.addVar(contribution2.B, 0.5) - recipe.addVar(contribution2.m, 2) - recipe.addVar(contribution2.d, 0) + recipe.add_variable(contribution1.A, 1) + recipe.add_variable(contribution1.k, 1) + recipe.add_variable(contribution1.c, 1) + recipe.add_variable(contribution2.B, 0.5) + recipe.add_variable(contribution2.m, 2) + recipe.add_variable(contribution2.d, 0) return recipe diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 9008d359..19d3d4f9 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -58,9 +58,9 @@ 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.c, 0) + recipe.add_variable(con.A, 2, tag="tagA") + recipe.add_variable(con.k, 1, tag="tagk") + recipe.add_variable(con.c, 0) recipe.newVar("B", 0) self.assertTrue(recipe.isFree(recipe.A)) @@ -100,13 +100,61 @@ def testFixFree(self): self.assertRaises(ValueError, recipe.fix, "junk") return + def test_variables(self): + """Test to see if variables are added and removed properly.""" + recipe = self.recipe + con = self.fitcontribution + + recipe.add_variable(con.A, 2) + recipe.add_variable(con.k, 1) + recipe.add_variable(con.c, 0) + recipe.newVar("B", 0) + + names = recipe.getNames() + self.assertEqual(names, ["A", "k", "c", "B"]) + values = recipe.getValues() + self.assertTrue((values == [2, 1, 0, 0]).all()) + + # Constrain a parameter to the B-variable to give it a value + p = Parameter("Bpar", -1) + recipe.constrain(recipe.B, p) + values = recipe.getValues() + self.assertTrue((values == [2, 1, 0]).all()) + recipe.delVar(recipe.B) + + recipe.fix(recipe.k) + + names = recipe.getNames() + self.assertEqual(names, ["A", "c"]) + values = recipe.getValues() + self.assertTrue((values == [2, 0]).all()) + + recipe.fix("all") + names = recipe.getNames() + self.assertEqual(names, []) + values = recipe.getValues() + self.assertTrue((values == []).all()) + + recipe.free("all") + names = recipe.getNames() + self.assertEqual(3, len(names)) + self.assertTrue("A" in names) + self.assertTrue("k" in names) + self.assertTrue("c" in names) + values = recipe.getValues() + self.assertEqual(3, len(values)) + self.assertTrue(0 in values) + self.assertTrue(1 in values) + self.assertTrue(2 in values) + return + def testVars(self): """Test to see if variables are added and removed properly.""" recipe = self.recipe con = self.fitcontribution - recipe.addVar(con.A, 2) - recipe.addVar(con.k, 1) + recipe.add_variable(con.A, 2) + recipe.add_variable(con.k, 1) recipe.addVar(con.c, 0) recipe.newVar("B", 0) @@ -270,7 +318,7 @@ def testPrintFitHook(capturestdout): recipe.addContribution(fitcontribution) - recipe.addVar(fitcontribution.c) + recipe.add_variable(fitcontribution.c) recipe.restrain("c", lb=5) (pfh,) = recipe.getFitHooks() out = capturestdout(recipe.scalar_residual) @@ -346,7 +394,7 @@ def test_add_contribution(capturestdout): recipe.add_contribution(fitcontribution) - recipe.addVar(fitcontribution.c) + recipe.add_variable(fitcontribution.c) recipe.restrain("c", lb=5) (pfh,) = recipe.get_fit_hooks() out = capturestdout(recipe.scalar_residual) @@ -404,8 +452,8 @@ def build_recipe_from_datafile(datafile): contribution.set_equation("m*x + b") recipe = FitRecipe() recipe.add_contribution(contribution) - recipe.addVar(contribution.m, 1) - recipe.addVar(contribution.b, 0) + recipe.add_variable(contribution.m, 1) + recipe.add_variable(contribution.b, 0) return recipe @@ -425,8 +473,8 @@ def build_recipe_from_datafile_deprecated(datafile): contribution.set_equation("m*x + b") recipe = FitRecipe() recipe.add_contribution(contribution) - recipe.addVar(contribution.m, 1) - recipe.addVar(contribution.b, 0) + recipe.add_variable(contribution.m, 1) + recipe.add_variable(contribution.b, 0) return recipe diff --git a/tests/test_sgconstraints.py b/tests/test_sgconstraints.py index 32d6afe4..4288e530 100644 --- a/tests/test_sgconstraints.py +++ b/tests/test_sgconstraints.py @@ -100,7 +100,7 @@ def test_ObjCryst_constrain_space_group(pyobjcryst_available): f = FitRecipe() with pytest.raises(ValueError): - f.addVar(mn.x) + f.add_variable(mn.x) return From ca94e894bf670e572f17e15158d2d9b9962f5d24 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 20 Feb 2026 13:43:11 -0500 Subject: [PATCH 045/193] delVar deprecation --- src/diffpy/srfit/fitbase/fitrecipe.py | 18 ++++++++++++++++-- tests/test_fitrecipe.py | 4 ++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index e31721e3..046c0610 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -91,6 +91,10 @@ base, "addVar", "add_variable", removal_version ) +delVar_dep_msg = build_deprecation_message( + base, "delVar", "delete_variable", removal_version +) + class FitRecipe(_fitrecipe_interface, RecipeOrganizer): """FitRecipe class. @@ -712,7 +716,7 @@ def addVar( """ return self.add_variable(par, value, name, fixed, tag, tags) - def delVar(self, var): + def delete_variable(self, var): """Remove a variable. Note that constraints and restraints involving the variable are not @@ -731,9 +735,19 @@ def delVar(self, var): self._tagmanager.untag(var) return + @deprecated(delVar_dep_msg) + def delVar(self, var): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.delete_variable instead. + """ + self.delete_variable(var) + return + def __delattr__(self, name): if name in self._parameters: - self.delVar(self._parameters[name]) + self.delete_variable(self._parameters[name]) return super(FitRecipe, self).__delattr__(name) return diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 19d3d4f9..42f42469 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -120,7 +120,7 @@ def test_variables(self): recipe.constrain(recipe.B, p) values = recipe.getValues() self.assertTrue((values == [2, 1, 0]).all()) - recipe.delVar(recipe.B) + recipe.delete_variable(recipe.B) recipe.fix(recipe.k) @@ -246,7 +246,7 @@ def testResidual(self): # Remove the restraint and variable self.recipe.unrestrain(r1) - self.recipe.delVar(self.recipe.Avar) + self.recipe.delete_variable(self.recipe.Avar) self.recipe._ready = False res = self.recipe.residual() chi2 = 0 From 474afb4553177d1445b9ec6fb640c5d710e6a6b0 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 20 Feb 2026 13:49:01 -0500 Subject: [PATCH 046/193] newVar deprecation --- docs/examples/coreshellnp.py | 2 +- docs/examples/crystalpdfall.py | 6 +++--- docs/examples/crystalpdftwodata.py | 2 +- docs/examples/crystalpdftwophase.py | 4 ++-- docs/examples/debyemodelII.py | 2 +- docs/examples/npintensity.py | 2 +- docs/examples/npintensityII.py | 2 +- docs/examples/nppdfobjcryst.py | 4 ++-- docs/examples/simplepdftwophase.py | 2 +- docs/examples/threedoublepeaks.py | 4 ++-- src/diffpy/srfit/fitbase/fitrecipe.py | 19 ++++++++++++++++--- src/diffpy/srfit/interface/interface.py | 6 +++--- tests/test_fitrecipe.py | 6 +++--- tests/test_fitresults.py | 18 +++++++++--------- 14 files changed, 46 insertions(+), 33 deletions(-) diff --git a/docs/examples/coreshellnp.py b/docs/examples/coreshellnp.py index 927980bc..7083ace4 100644 --- a/docs/examples/coreshellnp.py +++ b/docs/examples/coreshellnp.py @@ -96,7 +96,7 @@ def makeRecipe(stru1, stru2, datname): # Configure the fit variables # Start by configuring the scale factor and resolution factors. # We want the sum of the phase scale factors to be 1. - recipe.newVar("scale_CdS", 0.7) + recipe.create_new_variable("scale_CdS", 0.7) recipe.constrain(generator_cds.scale, "scale_CdS") recipe.constrain(generator_zns.scale, "1 - scale_CdS") # We also want the resolution factor to be the same on each. diff --git a/docs/examples/crystalpdfall.py b/docs/examples/crystalpdfall.py index 5eee276a..2e0ac7f5 100644 --- a/docs/examples/crystalpdfall.py +++ b/docs/examples/crystalpdfall.py @@ -112,14 +112,14 @@ def makeRecipe( # Now we vary and constrain Parameters as before. for par in phase_ni.sgpars: recipe.add_variable(par, name=par.name + "_ni") - delta2_ni = recipe.newVar("delta2_ni", 2.5) + delta2_ni = recipe.create_new_variable("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.add_variable(par, name=par.name + "_si") - delta2_si = recipe.newVar("delta2_si", 2.5) + delta2_si = recipe.create_new_variable("delta2_si", 2.5) recipe.constrain(xgenerator_si.delta2, delta2_si) recipe.constrain(xgenerator_sini_si.delta2, delta2_si) @@ -128,7 +128,7 @@ def makeRecipe( recipe.add_variable(xgenerator_si.scale, name="xscale_si") recipe.add_variable(ngenerator_ni.scale, name="nscale_ni") recipe.add_variable(xcontribution_sini.scale, 1.0, "xscale_sini") - recipe.newVar("pscale_sini_ni", 0.8) + recipe.create_new_variable("pscale_sini_ni", 0.8) recipe.constrain(xgenerator_sini_ni.scale, "pscale_sini_ni") recipe.constrain(xgenerator_sini_si.scale, "1 - pscale_sini_ni") diff --git a/docs/examples/crystalpdftwodata.py b/docs/examples/crystalpdftwodata.py index ddd41f29..baef831d 100644 --- a/docs/examples/crystalpdftwodata.py +++ b/docs/examples/crystalpdftwodata.py @@ -120,7 +120,7 @@ def makeRecipe(ciffile, xdatname, ndatname): recipe.add_variable(ngenerator.qdamp, 0.01, "nqdamp") # delta2 is a non-structual material property. Thus, we constrain together # delta2 Parameter from each PDFGenerator. - delta2 = recipe.newVar("delta2", 2) + delta2 = recipe.create_new_variable("delta2", 2) recipe.constrain(xgenerator.delta2, delta2) recipe.constrain(ngenerator.delta2, delta2) diff --git a/docs/examples/crystalpdftwophase.py b/docs/examples/crystalpdftwophase.py index fb601433..3c36c0cc 100644 --- a/docs/examples/crystalpdftwophase.py +++ b/docs/examples/crystalpdftwophase.py @@ -89,11 +89,11 @@ def makeRecipe(niciffile, siciffile, datname): # Configure the fit variables # Start by configuring the scale factor and resolution factors. # We want the sum of the phase scale factors to be 1. - recipe.newVar("scale_ni", 0.1) + recipe.create_new_variable("scale_ni", 0.1) recipe.constrain(generator_ni.scale, "scale_ni") recipe.constrain(generator_si.scale, "1 - scale_ni") # We also want the resolution factor to be the same on each. - recipe.newVar("qdamp", 0.03) + recipe.create_new_variable("qdamp", 0.03) recipe.constrain(generator_ni.qdamp, "qdamp") recipe.constrain(generator_si.qdamp, "qdamp") diff --git a/docs/examples/debyemodelII.py b/docs/examples/debyemodelII.py index 4a815437..631c4143 100644 --- a/docs/examples/debyemodelII.py +++ b/docs/examples/debyemodelII.py @@ -87,7 +87,7 @@ def makeRecipeII(): recipe.add_variable(recipe.highT.offset, name="highToffset") # We create a new Variable and use the recipe's "constrain" method to # associate the Debye temperature parameters with that variable. - recipe.newVar("thetaD", 100) + recipe.create_new_variable("thetaD", 100) recipe.constrain(recipe.lowT.thetaD, "thetaD") recipe.constrain(recipe.highT.thetaD, "thetaD") return recipe diff --git a/docs/examples/npintensity.py b/docs/examples/npintensity.py index cd54adb9..18cd19a1 100644 --- a/docs/examples/npintensity.py +++ b/docs/examples/npintensity.py @@ -296,7 +296,7 @@ def gaussian(q, q0, width): # Variable that we call "Uiso" and constrain the atomic Uiso values to # this. Note that we don't give Uiso an initial value. The initial value # will be inferred from the following constraints. - Uiso = recipe.newVar("Uiso") + Uiso = recipe.create_new_variable("Uiso") for atom in phase.getScatterers(): recipe.constrain(atom.Uiso, Uiso) diff --git a/docs/examples/npintensityII.py b/docs/examples/npintensityII.py index 6956af46..0c7293a1 100644 --- a/docs/examples/npintensityII.py +++ b/docs/examples/npintensityII.py @@ -178,7 +178,7 @@ def gaussian(q, q0, width): # variable that we call "Uiso" and constrain the atomic Uiso values to # this. Note that we don't give Uiso an initial value. The initial value # will be inferred from the subsequent constraints. - Uiso = recipe.newVar("Uiso") + Uiso = recipe.create_new_variable("Uiso") for atom in phase.getScatterers(): recipe.constrain(atom.Uiso, Uiso) diff --git a/docs/examples/nppdfobjcryst.py b/docs/examples/nppdfobjcryst.py index 3b0127aa..50dd9f79 100644 --- a/docs/examples/nppdfobjcryst.py +++ b/docs/examples/nppdfobjcryst.py @@ -66,7 +66,7 @@ def makeRecipe(molecule, datname): c60 = generator.phase # First, the isotropic thermal displacement factor. - Biso = recipe.newVar("Biso") + Biso = recipe.create_new_variable("Biso") for atom in c60.getScatterers(): # We have defined a 'center' atom that is a dummy, which means that it @@ -88,7 +88,7 @@ def makeRecipe(molecule, datname): # that we don't give it an initial value. Since the variable is being # directly constrained to further below, its initial value will be inferred # from the constraint. - radius = recipe.newVar("radius") + radius = recipe.create_new_variable("radius") for i, atom in enumerate(c60.getScatterers()): if atom.isDummy(): diff --git a/docs/examples/simplepdftwophase.py b/docs/examples/simplepdftwophase.py index fdb9ab2d..1e92a329 100644 --- a/docs/examples/simplepdftwophase.py +++ b/docs/examples/simplepdftwophase.py @@ -46,7 +46,7 @@ def makeRecipe(niciffile, siciffile, datname): # Configure the fit variables # Start by configuring the scale factor and resolution factors. # We want the sum of the phase scale factors to be 1. - recipe.newVar("scale_ni", 0.1) + recipe.create_new_variable("scale_ni", 0.1) recipe.constrain(contribution.ni.scale, "scale_ni") recipe.constrain(contribution.si.scale, "1 - scale_ni") # We also want the resolution factor to be the same on each. This is done diff --git a/docs/examples/threedoublepeaks.py b/docs/examples/threedoublepeaks.py index 951ead5a..99eb4e92 100644 --- a/docs/examples/threedoublepeaks.py +++ b/docs/examples/threedoublepeaks.py @@ -126,8 +126,8 @@ def peakloc(mu): # Vary the width of the peaks. We know the functional form of the peak # broadening. - recipe.newVar("sig0", 0.001) - recipe.newVar("dsig", 4) + recipe.create_new_variable("sig0", 0.001) + recipe.create_new_variable("dsig", 4) def sig(sig0, dsig, mu): """Calculate the peak broadening with respect to position.""" diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 046c0610..5c9ef5f1 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -95,6 +95,10 @@ base, "delVar", "delete_variable", removal_version ) +newVar_dep_msg = build_deprecation_message( + base, "newVar", "create_new_variable", removal_version +) + class FitRecipe(_fitrecipe_interface, RecipeOrganizer): """FitRecipe class. @@ -752,7 +756,9 @@ def __delattr__(self, name): super(FitRecipe, self).__delattr__(name) return - def newVar(self, name, value=None, fixed=False, tag=None, tags=[]): + def create_new_variable( + 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 @@ -786,11 +792,9 @@ def newVar(self, name, value=None, fixed=False, tag=None, tags=[]): """ # This will fix the Parameter var = self._new_parameter(name, value) - # We may explicitly free it if not fixed: self.free(var) - # Tag with passed tags self._tagmanager.tag(var, *tags) if tag is not None: @@ -798,6 +802,15 @@ def newVar(self, name, value=None, fixed=False, tag=None, tags=[]): return var + @deprecated(newVar_dep_msg) + def newVar(self, name, value=None, fixed=False, tag=None, tags=[]): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.create_new_variable instead. + """ + return self.create_new_variable(name, value, fixed, tag, tags) + def _new_parameter(self, name, value, check=True): """Overloaded to tag variables. diff --git a/src/diffpy/srfit/interface/interface.py b/src/diffpy/srfit/interface/interface.py index 6dee58ab..71e1b20e 100644 --- a/src/diffpy/srfit/interface/interface.py +++ b/src/diffpy/srfit/interface/interface.py @@ -119,7 +119,7 @@ def __ior__(self, args): return self def __iadd__(self, args): - """AddVar or newVar with += + """add_variable or create_new_variable with += Think of "+" as addition of a variable. @@ -127,10 +127,10 @@ def __iadd__(self, args): arguments or argument tuples. """ - # Want to detect add_variable or newVar + # Want to detect add_variable or create_new_variable def f(*args): if isinstance(args[0], six.string_types): - self.newVar(*args) + self.create_new_variable(*args) else: self.add_variable(*args) return diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 42f42469..0391c991 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -61,7 +61,7 @@ def testFixFree(self): recipe.add_variable(con.A, 2, tag="tagA") recipe.add_variable(con.k, 1, tag="tagk") recipe.add_variable(con.c, 0) - recipe.newVar("B", 0) + recipe.create_new_variable("B", 0) self.assertTrue(recipe.isFree(recipe.A)) recipe.fix("tagA") @@ -108,7 +108,7 @@ def test_variables(self): recipe.add_variable(con.A, 2) recipe.add_variable(con.k, 1) recipe.add_variable(con.c, 0) - recipe.newVar("B", 0) + recipe.create_new_variable("B", 0) names = recipe.getNames() self.assertEqual(names, ["A", "k", "c", "B"]) @@ -212,7 +212,7 @@ def testResidual(self): # Try some constraints # Make c = 2*A, A = Avar - var = self.recipe.newVar("Avar") + var = self.recipe.create_new_variable("Avar") self.recipe.constrain( self.fitcontribution.c, "2*A", {"A": self.fitcontribution.A} ) diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index 5702b03f..84f6a355 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -24,9 +24,9 @@ def testInitializeFromFileName(datafile): recipe = FitRecipe("recipe") - recipe.newVar("A", 0) - recipe.newVar("sig", 0) - recipe.newVar("x0", 0) + recipe.create_new_variable("A", 0) + recipe.create_new_variable("sig", 0) + recipe.create_new_variable("x0", 0) filename = datafile("results.res") Aval = 5.77619823e-01 sigval = -9.22758690e-01 @@ -44,9 +44,9 @@ def testInitializeFromFileName(datafile): def testInitializeFromFileObj(datafile): recipe = FitRecipe("recipe") - recipe.newVar("A", 0) - recipe.newVar("sig", 0) - recipe.newVar("x0", 0) + recipe.create_new_variable("A", 0) + recipe.create_new_variable("sig", 0) + recipe.create_new_variable("x0", 0) filename = datafile("results.res") Aval = 5.77619823e-01 sigval = -9.22758690e-01 @@ -67,9 +67,9 @@ def testInitializeFromFileObj(datafile): def testInitializeFromString(datafile): recipe = FitRecipe("recipe") - recipe.newVar("A", 0) - recipe.newVar("sig", 0) - recipe.newVar("x0", 0) + recipe.create_new_variable("A", 0) + recipe.create_new_variable("sig", 0) + recipe.create_new_variable("x0", 0) filename = datafile("results.res") Aval = 5.77619823e-01 sigval = -9.22758690e-01 From 9c18dcc15319eea23a4beed56da917738a1cde86 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 20 Feb 2026 13:53:00 -0500 Subject: [PATCH 047/193] news --- news/fitrecipe-dep.rst | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 news/fitrecipe-dep.rst diff --git a/news/fitrecipe-dep.rst b/news/fitrecipe-dep.rst new file mode 100644 index 00000000..e9275eb8 --- /dev/null +++ b/news/fitrecipe-dep.rst @@ -0,0 +1,32 @@ +**Added:** + +* Added ``create_new_variable`` method to ``FitRecipe``. +* Added ``delete_variable`` method to ``FitRecipe``. +* Added ``add_variable`` method to ``FitRecipe``. +* Added ``scalar_residual`` method to ``FitRecipe``. +* Added ``remove_parameter_set`` method to ``FitRecipe``. +* Added test for ``remove_parameter_set`` and ``add_parameter_set`` method in ``FitRecipe``. + +**Changed:** + +* + +**Deprecated:** + +* Deprecated ``newVar`` method for removal in 4.0.0. +* Deprecated ``delVar`` method for removal in 4.0.0. +* Deprecated ``addVar`` method for removal in 4.0.0. +* Deprecated ``scalarResidual`` method for removal in 4.0.0. +* Deprecated ``removeParameterSet`` method for removal in 4.0.0. + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 644cc970419f8e6b8666d1c49ed00a28bb3cbfcc Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 20 Feb 2026 13:54:46 -0500 Subject: [PATCH 048/193] news 2 --- news/fitrecipe-dep.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/news/fitrecipe-dep.rst b/news/fitrecipe-dep.rst index e9275eb8..fbf04526 100644 --- a/news/fitrecipe-dep.rst +++ b/news/fitrecipe-dep.rst @@ -5,7 +5,7 @@ * Added ``add_variable`` method to ``FitRecipe``. * Added ``scalar_residual`` method to ``FitRecipe``. * Added ``remove_parameter_set`` method to ``FitRecipe``. -* Added test for ``remove_parameter_set`` and ``add_parameter_set`` method in ``FitRecipe``. +* Added test for ``remove_parameter_set`` method in ``FitRecipe``. **Changed:** From 1ce94dd2482faf6e67ea4f184733d768358e4298 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 22 Feb 2026 14:27:25 -0500 Subject: [PATCH 049/193] isFree deprecation --- src/diffpy/srfit/fitbase/fitrecipe.py | 27 +++++++++++++----- tests/test_fitrecipe.py | 40 +++++++++++++-------------- 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 5c9ef5f1..91039657 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -99,6 +99,10 @@ base, "newVar", "create_new_variable", removal_version ) +isFree_dep_msg = build_deprecation_message( + base, "isFree", "is_free", removal_version +) + class FitRecipe(_fitrecipe_interface, RecipeOrganizer): """FitRecipe class. @@ -169,7 +173,7 @@ class FitRecipe(_fitrecipe_interface, RecipeOrganizer): lambda self: [ v.name for v in self._parameters.values() - if not (self.isFree(v) or self.isConstrained(v)) + if not (self.is_free(v) or self.isConstrained(v)) ], doc="names of the fixed refinable variables", ) @@ -178,7 +182,7 @@ class FitRecipe(_fitrecipe_interface, RecipeOrganizer): [ v.value for v in self._parameters.values() - if not (self.isFree(v) or self.isConstrained(v)) + if not (self.is_free(v) or self.isConstrained(v)) ] ), doc="values of the fixed refinable variables", @@ -935,10 +939,19 @@ def free(self, *args, **kw): return - def isFree(self, var): + def is_free(self, var): """Check if a variable is fixed.""" return not self._tagmanager.hasTags(var, self._fixedtag) + @deprecated(isFree_dep_msg) + def isFree(self, var): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.is_free instead. + """ + return self.is_free(var) + def unconstrain(self, *pars): """Unconstrain a Parameter. @@ -1037,12 +1050,12 @@ def constrain(self, par, con, ns={}): 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)] + [v.value for v in self._parameters.values() if self.is_free(v)] ) def getNames(self): """Get the names of the variables in a list.""" - return [v.name for v in self._parameters.values() if self.isFree(v)] + return [v.name for v in self._parameters.values() if self.is_free(v)] def getBounds(self): """Get the bounds on variables in a list. @@ -1050,7 +1063,7 @@ def getBounds(self): Returns a list of (lb, ub) pairs, where lb is the lower bound and ub is the upper bound. """ - return [v.bounds for v in self._parameters.values() if self.isFree(v)] + return [v.bounds for v in self._parameters.values() if self.is_free(v)] def getBounds2(self): """Get the bounds on variables in two lists. @@ -1372,7 +1385,7 @@ def _apply_values(self, p): """Apply variable values to the variables.""" if len(p) == 0: return - vargen = (v for v in self._parameters.values() if self.isFree(v)) + vargen = (v for v in self._parameters.values() if self.is_free(v)) for var, pval in zip(vargen, p): var.setValue(pval) return diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 0391c991..7230032d 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -54,7 +54,7 @@ def setUp(self): self.recipe.add_contribution(self.fitcontribution) return - def testFixFree(self): + def test_fix_free(self): recipe = self.recipe con = self.fitcontribution @@ -63,36 +63,36 @@ def testFixFree(self): recipe.add_variable(con.c, 0) recipe.create_new_variable("B", 0) - self.assertTrue(recipe.isFree(recipe.A)) + self.assertTrue(recipe.is_free(recipe.A)) recipe.fix("tagA") - self.assertFalse(recipe.isFree(recipe.A)) + self.assertFalse(recipe.is_free(recipe.A)) recipe.free("tagA") - self.assertTrue(recipe.isFree(recipe.A)) + self.assertTrue(recipe.is_free(recipe.A)) recipe.fix("A") - self.assertFalse(recipe.isFree(recipe.A)) + self.assertFalse(recipe.is_free(recipe.A)) recipe.free("A") - self.assertTrue(recipe.isFree(recipe.A)) + self.assertTrue(recipe.is_free(recipe.A)) recipe.fix(recipe.A) - self.assertFalse(recipe.isFree(recipe.A)) + self.assertFalse(recipe.is_free(recipe.A)) recipe.free(recipe.A) - self.assertTrue(recipe.isFree(recipe.A)) + self.assertTrue(recipe.is_free(recipe.A)) recipe.fix(recipe.A) - self.assertFalse(recipe.isFree(recipe.A)) + self.assertFalse(recipe.is_free(recipe.A)) recipe.free("all") - self.assertTrue(recipe.isFree(recipe.A)) - self.assertTrue(recipe.isFree(recipe.k)) - self.assertTrue(recipe.isFree(recipe.c)) - self.assertTrue(recipe.isFree(recipe.B)) + self.assertTrue(recipe.is_free(recipe.A)) + self.assertTrue(recipe.is_free(recipe.k)) + self.assertTrue(recipe.is_free(recipe.c)) + self.assertTrue(recipe.is_free(recipe.B)) 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)) - self.assertTrue(recipe.isFree(recipe.B)) + self.assertFalse(recipe.is_free(recipe.A)) + self.assertFalse(recipe.is_free(recipe.k)) + self.assertFalse(recipe.is_free(recipe.c)) + self.assertTrue(recipe.is_free(recipe.B)) self.assertEqual(3, recipe.c.value) recipe.fix("all") - self.assertFalse(recipe.isFree(recipe.A)) - self.assertFalse(recipe.isFree(recipe.k)) - self.assertFalse(recipe.isFree(recipe.c)) + self.assertFalse(recipe.is_free(recipe.A)) + self.assertFalse(recipe.is_free(recipe.k)) + self.assertFalse(recipe.is_free(recipe.c)) self.assertFalse(recipe.isFree(recipe.B)) self.assertRaises(ValueError, recipe.free, "junk") From eef890c52381bb841f24bd790fb2c01f75ba94ce Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 22 Feb 2026 14:37:23 -0500 Subject: [PATCH 050/193] getValues deprecation --- docs/examples/debyemodelII.py | 2 +- docs/examples/gaussianrecipe.py | 4 +-- docs/examples/nppdfobjcryst.py | 2 +- docs/examples/threedoublepeaks.py | 4 +-- src/diffpy/srfit/fitbase/calculator.py | 2 +- src/diffpy/srfit/fitbase/fitcontribution.py | 2 +- src/diffpy/srfit/fitbase/fithook.py | 2 +- src/diffpy/srfit/fitbase/fitrecipe.py | 16 +++++++++-- src/diffpy/srfit/fitbase/fitresults.py | 2 +- src/diffpy/srfit/fitbase/parameterset.py | 2 +- src/diffpy/srfit/fitbase/profilegenerator.py | 2 +- src/diffpy/srfit/fitbase/recipeorganizer.py | 30 +++++++++++++++++--- src/diffpy/srfit/fitbase/simplerecipe.py | 2 +- tests/test_fitrecipe.py | 18 ++++++------ 14 files changed, 62 insertions(+), 28 deletions(-) diff --git a/docs/examples/debyemodelII.py b/docs/examples/debyemodelII.py index 631c4143..a7c896cb 100644 --- a/docs/examples/debyemodelII.py +++ b/docs/examples/debyemodelII.py @@ -98,7 +98,7 @@ def plotResults(recipe): # The variable values are returned in the order in which the variables were # added to the FitRecipe. - lowToffset, highToffset, thetaD = recipe.getValues() + lowToffset, highToffset, thetaD = recipe.get_values() # We want to extend the fitting range to its full extent so we can get a # nice full plot. diff --git a/docs/examples/gaussianrecipe.py b/docs/examples/gaussianrecipe.py index 7bf85355..fde45cc5 100644 --- a/docs/examples/gaussianrecipe.py +++ b/docs/examples/gaussianrecipe.py @@ -172,11 +172,11 @@ def scipyOptimize(recipe): # We're going to use the least-squares (Levenberg-Marquardt) optimizer from # scipy. We simply have to give it the function to minimize # (recipe.residual) and the starting values of the Variables - # (recipe.getValues()). + # (recipe.get_values()). from scipy.optimize.minpack import leastsq print("Fit using scipy's LM optimizer") - leastsq(recipe.residual, recipe.getValues()) + leastsq(recipe.residual, recipe.get_values()) return diff --git a/docs/examples/nppdfobjcryst.py b/docs/examples/nppdfobjcryst.py index 50dd9f79..70426101 100644 --- a/docs/examples/nppdfobjcryst.py +++ b/docs/examples/nppdfobjcryst.py @@ -143,7 +143,7 @@ def main(): # Optimize from scipy.optimize import leastsq - leastsq(recipe.residual, recipe.getValues()) + leastsq(recipe.residual, recipe.get_values()) # Print results res = FitResults(recipe) diff --git a/docs/examples/threedoublepeaks.py b/docs/examples/threedoublepeaks.py index 99eb4e92..8ad75304 100644 --- a/docs/examples/threedoublepeaks.py +++ b/docs/examples/threedoublepeaks.py @@ -179,11 +179,11 @@ def scipyOptimize(recipe): # We're going to use the least-squares (Levenberg-Marquardt) optimizer from # scipy. We simply have to give it the function to minimize # (recipe.residual) and the starting values of the Variables - # (recipe.getValues()). + # (recipe.get_values()). from scipy.optimize.minpack import leastsq print("Fit using scipy's LM optimizer") - leastsq(recipe.residual, recipe.getValues()) + leastsq(recipe.residual, recipe.get_values()) return diff --git a/src/diffpy/srfit/fitbase/calculator.py b/src/diffpy/srfit/fitbase/calculator.py index 75083b4e..d8762fad 100644 --- a/src/diffpy/srfit/fitbase/calculator.py +++ b/src/diffpy/srfit/fitbase/calculator.py @@ -79,7 +79,7 @@ class Calculator(Operator, ParameterSet): names Variable names (read only). See getNames. values - Variable values (read only). See getValues. + Variable values (read only). See get_values. """ # define abstract attributes from the Operator base. diff --git a/src/diffpy/srfit/fitbase/fitcontribution.py b/src/diffpy/srfit/fitbase/fitcontribution.py index c9e3df9c..ec84db7a 100644 --- a/src/diffpy/srfit/fitbase/fitcontribution.py +++ b/src/diffpy/srfit/fitbase/fitcontribution.py @@ -127,7 +127,7 @@ class FitContribution(ParameterSet): names Variable names (read only). See getNames. values - Variable values (read only). See getValues. + Variable values (read only). See get_values. """ def __init__(self, name): diff --git a/src/diffpy/srfit/fitbase/fithook.py b/src/diffpy/srfit/fitbase/fithook.py index be8cdf7c..438bbfd4 100644 --- a/src/diffpy/srfit/fitbase/fithook.py +++ b/src/diffpy/srfit/fitbase/fithook.py @@ -165,7 +165,7 @@ def postcall(self, recipe, chiv): if self.verbose >= 3: print("Variables") vnames = recipe.getNames() - vals = recipe.getValues() + vals = recipe.get_values() # byname = _byname() items = sorted(zip(vnames, vals), key=_byname) for name, val in items: diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 91039657..da262d3c 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -103,6 +103,10 @@ base, "isFree", "is_free", removal_version ) +getValues_dep_msg = build_deprecation_message( + base, "getValues", "get_values", removal_version +) + class FitRecipe(_fitrecipe_interface, RecipeOrganizer): """FitRecipe class. @@ -158,7 +162,7 @@ class FitRecipe(_fitrecipe_interface, RecipeOrganizer): names Variable names (read only). See getNames. values - Variable values (read only). See getValues. + Variable values (read only). See get_values. fixednames Names of the fixed refinable variables (read only). fixedvalues @@ -1047,12 +1051,20 @@ def constrain(self, par, con, ns={}): RecipeOrganizer.constrain(self, par, con, ns) return - def getValues(self): + def get_values(self): """Get the current values of the variables in a list.""" return array( [v.value for v in self._parameters.values() if self.is_free(v)] ) + @deprecated(getValues_dep_msg) + def getValues(self): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.get_values instead.""" + return self.get_values() + def getNames(self): """Get the names of the variables in a list.""" return [v.name for v in self._parameters.values() if self.is_free(v)] diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index 1949526a..4a05acfb 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -153,7 +153,7 @@ def update(self): # Store the variable names and values self.varnames = recipe.getNames() - self.varvals = recipe.getValues() + self.varvals = recipe.get_values() fixedpars = recipe._tagmanager.union(recipe._fixedtag) fixedpars = [p for p in fixedpars if not p.constrained] self.fixednames = [p.name for p in fixedpars] diff --git a/src/diffpy/srfit/fitbase/parameterset.py b/src/diffpy/srfit/fitbase/parameterset.py index 6d200ca9..5c689583 100644 --- a/src/diffpy/srfit/fitbase/parameterset.py +++ b/src/diffpy/srfit/fitbase/parameterset.py @@ -77,7 +77,7 @@ class ParameterSet(RecipeOrganizer): names Variable names (read only). See getNames. values - Variable values (read only). See getValues. + Variable values (read only). See get_values. """ def __init__(self, name): diff --git a/src/diffpy/srfit/fitbase/profilegenerator.py b/src/diffpy/srfit/fitbase/profilegenerator.py index c6adabbc..64636d98 100644 --- a/src/diffpy/srfit/fitbase/profilegenerator.py +++ b/src/diffpy/srfit/fitbase/profilegenerator.py @@ -112,7 +112,7 @@ class ProfileGenerator(Operator, ParameterSet): names Variable names (read only). See getNames. values - Variable values (read only). See getValues. + Variable values (read only). See get_values. """ # define abstract attributes from the Operator base. diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 3b95a216..96ca668e 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -42,6 +42,17 @@ from diffpy.srfit.util import sortKeyForNumericString as numstr from diffpy.srfit.util.nameutils import validateName from diffpy.srfit.util.observable import Observable +from diffpy.utils._deprecator import build_deprecation_message, deprecated + +base = "diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer" +removal_version = "4.0.0" + +getValues_deprecation_msg = build_deprecation_message( + base, + "getValues", + "get_values", + removal_version, +) class RecipeContainer(Observable, Configurable, Validatable): @@ -85,11 +96,11 @@ class RecipeContainer(Observable, Configurable, Validatable): names Variable names (read only). See getNames. values - Variable values (read only). See getValues. + Variable values (read only). See get_values. """ names = property(lambda self: self.getNames()) - values = property(lambda self: self.getValues()) + values = property(lambda self: self.get_values()) def __init__(self, name): Observable.__init__(self) @@ -233,10 +244,21 @@ def getNames(self): """Get the names of managed parameters.""" return [p.name for p in self._parameters.values()] - def getValues(self): + def get_values(self): """Get the values of managed parameters.""" return [p.value for p in self._parameters.values()] + @deprecated(getValues_deprecation_msg) + def getValues(self): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use + diffpy.srfit.fitbase.recipeorganizer.RecipeContainer.get_values + instead. + """ + return self.get_values() + def _add_object(self, obj, d, check=True): """Add an object to a managed dictionary. @@ -402,7 +424,7 @@ class RecipeOrganizer(_recipeorganizer_interface, RecipeContainer): names Variable names (read only). See getNames. values - Variable values (read only). See getValues. + Variable values (read only). See get_values. Raises ValueError if the name is not a valid attribute identifier diff --git a/src/diffpy/srfit/fitbase/simplerecipe.py b/src/diffpy/srfit/fitbase/simplerecipe.py index 36391e86..8f2edd70 100644 --- a/src/diffpy/srfit/fitbase/simplerecipe.py +++ b/src/diffpy/srfit/fitbase/simplerecipe.py @@ -123,7 +123,7 @@ class SimpleRecipe(FitRecipe): names Variable names (read only). See getNames. values - Variable values (read only). See getValues. + Variable values (read only). See get_values. """ def __init__(self, name="fit", conclass=FitContribution): diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 7230032d..a3ab9f0a 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -112,13 +112,13 @@ def test_variables(self): names = recipe.getNames() self.assertEqual(names, ["A", "k", "c", "B"]) - values = recipe.getValues() + values = recipe.get_values() self.assertTrue((values == [2, 1, 0, 0]).all()) # Constrain a parameter to the B-variable to give it a value p = Parameter("Bpar", -1) recipe.constrain(recipe.B, p) - values = recipe.getValues() + values = recipe.get_values() self.assertTrue((values == [2, 1, 0]).all()) recipe.delete_variable(recipe.B) @@ -126,13 +126,13 @@ def test_variables(self): names = recipe.getNames() self.assertEqual(names, ["A", "c"]) - values = recipe.getValues() + values = recipe.get_values() self.assertTrue((values == [2, 0]).all()) recipe.fix("all") names = recipe.getNames() self.assertEqual(names, []) - values = recipe.getValues() + values = recipe.get_values() self.assertTrue((values == []).all()) recipe.free("all") @@ -141,7 +141,7 @@ def test_variables(self): self.assertTrue("A" in names) self.assertTrue("k" in names) self.assertTrue("c" in names) - values = recipe.getValues() + values = recipe.get_values() self.assertEqual(3, len(values)) self.assertTrue(0 in values) self.assertTrue(1 in values) @@ -160,13 +160,13 @@ def testVars(self): names = recipe.getNames() self.assertEqual(names, ["A", "k", "c", "B"]) - values = recipe.getValues() + values = recipe.get_values() self.assertTrue((values == [2, 1, 0, 0]).all()) # Constrain a parameter to the B-variable to give it a value p = Parameter("Bpar", -1) recipe.constrain(recipe.B, p) - values = recipe.getValues() + values = recipe.get_values() self.assertTrue((values == [2, 1, 0]).all()) recipe.delVar(recipe.B) @@ -174,13 +174,13 @@ def testVars(self): names = recipe.getNames() self.assertEqual(names, ["A", "c"]) - values = recipe.getValues() + values = recipe.get_values() self.assertTrue((values == [2, 0]).all()) recipe.fix("all") names = recipe.getNames() self.assertEqual(names, []) - values = recipe.getValues() + values = recipe.get_values() self.assertTrue((values == []).all()) recipe.free("all") From f26302f720c14396734320610332f21a7f94862a Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 22 Feb 2026 14:39:03 -0500 Subject: [PATCH 051/193] fix typo in base name --- src/diffpy/srfit/fitbase/recipeorganizer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 96ca668e..1a4466ff 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -44,7 +44,7 @@ from diffpy.srfit.util.observable import Observable from diffpy.utils._deprecator import build_deprecation_message, deprecated -base = "diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer" +base = "diffpy.srfit.fitbase.recipeorganizer.RecipeContainer" removal_version = "4.0.0" getValues_deprecation_msg = build_deprecation_message( From fd6bc73f16f7b6de715f6092e76c5511323c3b16 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 22 Feb 2026 14:44:28 -0500 Subject: [PATCH 052/193] getNames deprecation --- src/diffpy/srfit/fitbase/calculator.py | 2 +- src/diffpy/srfit/fitbase/fitcontribution.py | 2 +- src/diffpy/srfit/fitbase/fithook.py | 2 +- src/diffpy/srfit/fitbase/fitrecipe.py | 16 +++++++++-- src/diffpy/srfit/fitbase/fitresults.py | 2 +- src/diffpy/srfit/fitbase/parameterset.py | 2 +- src/diffpy/srfit/fitbase/profilegenerator.py | 2 +- src/diffpy/srfit/fitbase/recipeorganizer.py | 30 ++++++++++++++++---- src/diffpy/srfit/fitbase/simplerecipe.py | 2 +- tests/test_fitrecipe.py | 14 ++++----- 10 files changed, 52 insertions(+), 22 deletions(-) diff --git a/src/diffpy/srfit/fitbase/calculator.py b/src/diffpy/srfit/fitbase/calculator.py index d8762fad..22e96540 100644 --- a/src/diffpy/srfit/fitbase/calculator.py +++ b/src/diffpy/srfit/fitbase/calculator.py @@ -77,7 +77,7 @@ class Calculator(Operator, ParameterSet): Properties ---------- names - Variable names (read only). See getNames. + Variable names (read only). See get_names. values Variable values (read only). See get_values. """ diff --git a/src/diffpy/srfit/fitbase/fitcontribution.py b/src/diffpy/srfit/fitbase/fitcontribution.py index ec84db7a..d6ff6ed0 100644 --- a/src/diffpy/srfit/fitbase/fitcontribution.py +++ b/src/diffpy/srfit/fitbase/fitcontribution.py @@ -125,7 +125,7 @@ class FitContribution(ParameterSet): Properties ---------- names - Variable names (read only). See getNames. + Variable names (read only). See get_names. values Variable values (read only). See get_values. """ diff --git a/src/diffpy/srfit/fitbase/fithook.py b/src/diffpy/srfit/fitbase/fithook.py index 438bbfd4..b5b284c5 100644 --- a/src/diffpy/srfit/fitbase/fithook.py +++ b/src/diffpy/srfit/fitbase/fithook.py @@ -164,7 +164,7 @@ def postcall(self, recipe, chiv): if self.verbose >= 3: print("Variables") - vnames = recipe.getNames() + vnames = recipe.get_names() vals = recipe.get_values() # byname = _byname() items = sorted(zip(vnames, vals), key=_byname) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index da262d3c..a13b2fe0 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -107,6 +107,10 @@ base, "getValues", "get_values", removal_version ) +getNames_dep_msg = build_deprecation_message( + base, "getNames", "get_names", removal_version +) + class FitRecipe(_fitrecipe_interface, RecipeOrganizer): """FitRecipe class. @@ -160,7 +164,7 @@ class FitRecipe(_fitrecipe_interface, RecipeOrganizer): Properties ---------- names - Variable names (read only). See getNames. + Variable names (read only). See get_names. values Variable values (read only). See get_values. fixednames @@ -1065,10 +1069,18 @@ def getValues(self): Please use diffpy.srfit.fitbase.FitRecipe.get_values instead.""" return self.get_values() - def getNames(self): + def get_names(self): """Get the names of the variables in a list.""" return [v.name for v in self._parameters.values() if self.is_free(v)] + @deprecated(getNames_dep_msg) + def getNames(self): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.get_names instead.""" + return self.get_names() + def getBounds(self): """Get the bounds on variables in a list. diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index 4a05acfb..c79c2a17 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -152,7 +152,7 @@ def update(self): recipe._prepare() # Store the variable names and values - self.varnames = recipe.getNames() + self.varnames = recipe.get_names() self.varvals = recipe.get_values() fixedpars = recipe._tagmanager.union(recipe._fixedtag) fixedpars = [p for p in fixedpars if not p.constrained] diff --git a/src/diffpy/srfit/fitbase/parameterset.py b/src/diffpy/srfit/fitbase/parameterset.py index 5c689583..e5e51e39 100644 --- a/src/diffpy/srfit/fitbase/parameterset.py +++ b/src/diffpy/srfit/fitbase/parameterset.py @@ -75,7 +75,7 @@ class ParameterSet(RecipeOrganizer): Properties ---------- names - Variable names (read only). See getNames. + Variable names (read only). See get_names. values Variable values (read only). See get_values. """ diff --git a/src/diffpy/srfit/fitbase/profilegenerator.py b/src/diffpy/srfit/fitbase/profilegenerator.py index 64636d98..c45e93aa 100644 --- a/src/diffpy/srfit/fitbase/profilegenerator.py +++ b/src/diffpy/srfit/fitbase/profilegenerator.py @@ -110,7 +110,7 @@ class ProfileGenerator(Operator, ParameterSet): Properties ---------- names - Variable names (read only). See getNames. + Variable names (read only). See get_names. values Variable values (read only). See get_values. """ diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 1a4466ff..ca7b273b 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -44,16 +44,23 @@ from diffpy.srfit.util.observable import Observable from diffpy.utils._deprecator import build_deprecation_message, deprecated -base = "diffpy.srfit.fitbase.recipeorganizer.RecipeContainer" +recipecontainer_base = "diffpy.srfit.fitbase.recipeorganizer.RecipeContainer" removal_version = "4.0.0" getValues_deprecation_msg = build_deprecation_message( - base, + recipecontainer_base, "getValues", "get_values", removal_version, ) +getNames_deprecation_msg = build_deprecation_message( + recipecontainer_base, + "getNames", + "get_names", + removal_version, +) + class RecipeContainer(Observable, Configurable, Validatable): """Base class for organizing pieces of a FitRecipe. @@ -94,12 +101,12 @@ class RecipeContainer(Observable, Configurable, Validatable): Properties ---------- names - Variable names (read only). See getNames. + Variable names (read only). See get_names. values Variable values (read only). See get_values. """ - names = property(lambda self: self.getNames()) + names = property(lambda self: self.get_names()) values = property(lambda self: self.get_values()) def __init__(self, name): @@ -240,10 +247,21 @@ def get(self, name, default=None): return default - def getNames(self): + def get_names(self): """Get the names of managed parameters.""" return [p.name for p in self._parameters.values()] + @deprecated(getNames_deprecation_msg) + def getNames(self): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use + diffpy.srfit.fitbase.recipeorganizer.RecipeContainer.get_names + instead. + """ + return self.get_names() + def get_values(self): """Get the values of managed parameters.""" return [p.value for p in self._parameters.values()] @@ -422,7 +440,7 @@ class RecipeOrganizer(_recipeorganizer_interface, RecipeContainer): Properties ---------- names - Variable names (read only). See getNames. + Variable names (read only). See get_names. values Variable values (read only). See get_values. diff --git a/src/diffpy/srfit/fitbase/simplerecipe.py b/src/diffpy/srfit/fitbase/simplerecipe.py index 8f2edd70..048520af 100644 --- a/src/diffpy/srfit/fitbase/simplerecipe.py +++ b/src/diffpy/srfit/fitbase/simplerecipe.py @@ -121,7 +121,7 @@ class SimpleRecipe(FitRecipe): Properties ---------- names - Variable names (read only). See getNames. + Variable names (read only). See get_names. values Variable values (read only). See get_values. """ diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index a3ab9f0a..ae466c96 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -110,7 +110,7 @@ def test_variables(self): recipe.add_variable(con.c, 0) recipe.create_new_variable("B", 0) - names = recipe.getNames() + names = recipe.get_names() self.assertEqual(names, ["A", "k", "c", "B"]) values = recipe.get_values() self.assertTrue((values == [2, 1, 0, 0]).all()) @@ -124,19 +124,19 @@ def test_variables(self): recipe.fix(recipe.k) - names = recipe.getNames() + names = recipe.get_names() self.assertEqual(names, ["A", "c"]) values = recipe.get_values() self.assertTrue((values == [2, 0]).all()) recipe.fix("all") - names = recipe.getNames() + names = recipe.get_names() self.assertEqual(names, []) values = recipe.get_values() self.assertTrue((values == []).all()) recipe.free("all") - names = recipe.getNames() + names = recipe.get_names() self.assertEqual(3, len(names)) self.assertTrue("A" in names) self.assertTrue("k" in names) @@ -158,7 +158,7 @@ def testVars(self): recipe.addVar(con.c, 0) recipe.newVar("B", 0) - names = recipe.getNames() + names = recipe.get_names() self.assertEqual(names, ["A", "k", "c", "B"]) values = recipe.get_values() self.assertTrue((values == [2, 1, 0, 0]).all()) @@ -172,13 +172,13 @@ def testVars(self): recipe.fix(recipe.k) - names = recipe.getNames() + names = recipe.get_names() self.assertEqual(names, ["A", "c"]) values = recipe.get_values() self.assertTrue((values == [2, 0]).all()) recipe.fix("all") - names = recipe.getNames() + names = recipe.get_names() self.assertEqual(names, []) values = recipe.get_values() self.assertTrue((values == []).all()) From ba3bc20ffb993ddd705136cd333f393625846450 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 22 Feb 2026 15:39:47 -0500 Subject: [PATCH 053/193] getBounds deprecation --- src/diffpy/srfit/fitbase/fitrecipe.py | 29 +++++++++++++++++++++------ src/diffpy/srfit/fitbase/parameter.py | 4 ++-- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index a13b2fe0..70050983 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -111,6 +111,10 @@ base, "getNames", "get_names", removal_version ) +getBounds_dep_msg = build_deprecation_message( + base, "getBounds", "get_bounds_pairs", removal_version +) + class FitRecipe(_fitrecipe_interface, RecipeOrganizer): """FitRecipe class. @@ -172,7 +176,7 @@ class FitRecipe(_fitrecipe_interface, RecipeOrganizer): fixedvalues Values of the fixed refinable variables (read only). bounds - Bounds on parameters (read only). See getBounds. + Bounds on parameters (read only). See get_bounds_pairs. bounds2 Bounds on parameters (read only). See getBounds2. """ @@ -195,7 +199,7 @@ class FitRecipe(_fitrecipe_interface, RecipeOrganizer): ), doc="values of the fixed refinable variables", ) - bounds = property(lambda self: self.getBounds()) + bounds = property(lambda self: self.get_bounds_pairs()) bounds2 = property(lambda self: self.getBounds2()) def __init__(self, name="fit"): @@ -1081,20 +1085,33 @@ def getNames(self): Please use diffpy.srfit.fitbase.FitRecipe.get_names instead.""" return self.get_names() - def getBounds(self): + def get_bounds_pairs(self): """Get the bounds on variables in a list. - Returns a list of (lb, ub) pairs, where lb is the lower bound - and ub is the upper bound. + Returns + ------- + bounds_pair_list : list of tuple of float + A list of ``(lower, upper)`` bounds on the variables, in the same + order as ``get_names`` and ``get_values``. """ return [v.bounds for v in self._parameters.values() if self.is_free(v)] + @deprecated(getBounds_dep_msg) + def getBounds(self): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.get_bounds_pairs + instead. + """ + return self.get_bounds_pairs() + def getBounds2(self): """Get the bounds on variables in two lists. Returns lower- and upper-bound lists of variable bounds. """ - bounds = self.getBounds() + bounds = self.get_bounds_pairs() lb = array([b[0] for b in bounds]) ub = array([b[1] for b in bounds]) return lb, ub diff --git a/src/diffpy/srfit/fitbase/parameter.py b/src/diffpy/srfit/fitbase/parameter.py index 90691e55..067ab8ae 100644 --- a/src/diffpy/srfit/fitbase/parameter.py +++ b/src/diffpy/srfit/fitbase/parameter.py @@ -55,7 +55,7 @@ class Parameter(_parameter_interface, Argument, Validatable): bounds A 2-list defining the bounds on the Parameter. This can be used by some optimizers when the Parameter is varied. See - FitRecipe.getBounds and FitRecipe.boundsToRestraints. + FitRecipe.get_bounds_pairs and FitRecipe.boundsToRestraints. """ def __init__(self, name, value=None, const=False): @@ -238,7 +238,7 @@ def bounds(self): """List of lower and upper bounds of the proxied Parameter. This can be used by some optimizers when the Parameter is - varied. See FitRecipe.getBounds and + varied. See FitRecipe.get_bounds_pairs and FitRecipe.boundsToRestraints. """ return self.par.bounds From 71b8b4f90ac440e9fc2490952160a14ecf7cc687 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 22 Feb 2026 15:44:53 -0500 Subject: [PATCH 054/193] getBounds2 deprecation --- src/diffpy/srfit/fitbase/fitrecipe.py | 36 +++++++++++++++++++++------ 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 70050983..3bc26e2c 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -115,6 +115,10 @@ base, "getBounds", "get_bounds_pairs", removal_version ) +getBounds2_dep_msg = build_deprecation_message( + base, "getBounds2", "get_bounds_array", removal_version +) + class FitRecipe(_fitrecipe_interface, RecipeOrganizer): """FitRecipe class. @@ -178,7 +182,7 @@ class FitRecipe(_fitrecipe_interface, RecipeOrganizer): bounds Bounds on parameters (read only). See get_bounds_pairs. bounds2 - Bounds on parameters (read only). See getBounds2. + Bounds on parameters (read only). See get_bounds_array. """ fixednames = property( @@ -200,7 +204,7 @@ class FitRecipe(_fitrecipe_interface, RecipeOrganizer): doc="values of the fixed refinable variables", ) bounds = property(lambda self: self.get_bounds_pairs()) - bounds2 = property(lambda self: self.getBounds2()) + bounds2 = property(lambda self: self.get_bounds_array()) def __init__(self, name="fit"): """Initialization.""" @@ -1106,15 +1110,31 @@ def getBounds(self): """ return self.get_bounds_pairs() - def getBounds2(self): - """Get the bounds on variables in two lists. + def get_bounds_array(self): + """Get the bounds on variables in two numpy arrays. - Returns lower- and upper-bound lists of variable bounds. + Returns + ------- + lower_bounds : numpy.ndarray + A numpy array of lower bounds on the variables, in the same order + as ``get_names`` and ``get_values``. + upper_bounds : numpy.ndarray + A numpy array of upper bounds on the variables, in the same order + as ``get_names`` and ``get_values``. """ bounds = self.get_bounds_pairs() - lb = array([b[0] for b in bounds]) - ub = array([b[1] for b in bounds]) - return lb, ub + lower_bounds = array([b[0] for b in bounds]) + upper_bounds = array([b[1] for b in bounds]) + return lower_bounds, upper_bounds + + @deprecated(getBounds2_dep_msg) + def getBounds2(self): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.get_bounds_array instead. + """ + return self.get_bounds_array() def set_plot_defaults(self, **kwargs): """Set default plotting options for all future plots. From 2985fbde3c82a0097bb8ff58dde4e769a872c6ed Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 22 Feb 2026 16:02:25 -0500 Subject: [PATCH 055/193] add test for boundsToRestraints --- tests/test_fitrecipe.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index ae466c96..b7fbe0d3 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -297,6 +297,40 @@ def testResidual(self): # ---------------------------------------------------------------------------- +def test_boundsToRestraints(): + recipe = FitRecipe("recipe") + + # create a bounded variable + recipe.create_new_variable("var1", 1) + recipe.var1.bounds = (-1, 1) + + # apply restraints from bounds + recipe.boundsToRestraints(sig=2, scaled=True) + restraints = list(recipe._restraints) + assert len(restraints) == 1 + r = restraints[0] + assert r.lb == -1 + assert r.ub == 1 + assert r.sig == 2 + assert r.scaled is True + + +def test_convert_bounds_to_restraints(): + recipe = FitRecipe("recipe") + # create a bounded variable + recipe.create_new_variable("var1", 1) + recipe.var1.bounds = (-1, 1) + # apply restraints from bounds + recipe.convert_bounds_to_restraints(sig=2, scaled=True) + restraints = list(recipe._restraints) + assert len(restraints) == 1 + r = restraints[0] + assert r.lb == -1 + assert r.ub == 1 + assert r.sig == 2 + assert r.scaled is True + + def testPrintFitHook(capturestdout): "check output from default PrintFitHook." recipe = FitRecipe("recipe") From 91a2ef4e28effcfae5ab7b0bb6e1665e3150d0f7 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 22 Feb 2026 16:02:50 -0500 Subject: [PATCH 056/193] boundsToRestraints deprecation --- src/diffpy/srfit/fitbase/fitrecipe.py | 17 ++++++++++++++++- src/diffpy/srfit/fitbase/parameter.py | 4 ++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 3bc26e2c..d9ed9427 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -119,6 +119,10 @@ base, "getBounds2", "get_bounds_array", removal_version ) +boundsToRestraints_dep_msg = build_deprecation_message( + base, "boundsToRestraints", "convert_bounds_to_restraints", removal_version +) + class FitRecipe(_fitrecipe_interface, RecipeOrganizer): """FitRecipe class. @@ -1420,7 +1424,7 @@ def plot_recipe(self, ax=None, return_fig=False, **kwargs): else: return figures, axes_list - def boundsToRestraints(self, sig=1, scaled=False): + def convert_bounds_to_restraints(self, sig=1, scaled=False): """Turn all bounded parameters into restraints. The bounds become limits on the restraint. @@ -1442,6 +1446,17 @@ def boundsToRestraints(self, sig=1, scaled=False): ) return + @deprecated(boundsToRestraints_dep_msg) + def boundsToRestraints(self, sig=1, scaled=False): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.convert_bounds_to_restraints + instead. + """ + self.convert_bounds_to_restraints(sig, scaled) + return + def _apply_values(self, p): """Apply variable values to the variables.""" if len(p) == 0: diff --git a/src/diffpy/srfit/fitbase/parameter.py b/src/diffpy/srfit/fitbase/parameter.py index 067ab8ae..d7887f7d 100644 --- a/src/diffpy/srfit/fitbase/parameter.py +++ b/src/diffpy/srfit/fitbase/parameter.py @@ -55,7 +55,7 @@ class Parameter(_parameter_interface, Argument, Validatable): bounds A 2-list defining the bounds on the Parameter. This can be used by some optimizers when the Parameter is varied. See - FitRecipe.get_bounds_pairs and FitRecipe.boundsToRestraints. + FitRecipe.get_bounds_pairs and FitRecipe.convert_bounds_to_restraints. """ def __init__(self, name, value=None, const=False): @@ -239,7 +239,7 @@ def bounds(self): This can be used by some optimizers when the Parameter is varied. See FitRecipe.get_bounds_pairs and - FitRecipe.boundsToRestraints. + FitRecipe.convert_bounds_to_restraints. """ return self.par.bounds From 346d1b2561368ad75a8e715a270bd14f42c804dd Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 22 Feb 2026 16:06:57 -0500 Subject: [PATCH 057/193] make bounds to restraints docstring better --- src/diffpy/srfit/fitbase/fitrecipe.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index d9ed9427..c28acc3e 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -1429,13 +1429,18 @@ def convert_bounds_to_restraints(self, sig=1, scaled=False): The bounds become limits on the restraint. - Attributes + Parameters ---------- - sig - The uncertainty on the bounds (scalar or iterable, - default 1). - scaled - Scale the restraints, see restrain. + sig : float or iterable of float, optional + The number of standard deviations associated with each bound. + Smaller values produce stronger restraints. If a scalar is given, + the same value is applied to all parameters. If an iterable is + provided, it must match the number of parameters. Default is 1. + + scaled : bool, optional + If True, scale each restraint by the magnitude of the corresponding + parameter, consistent with the behavior of :meth:`restrain`. + Default is False. """ pars = self._parameters.values() if not hasattr(sig, "__iter__"): From 64640a5b4f468e536e5af7b46974986de5b2aaea Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 22 Feb 2026 16:10:40 -0500 Subject: [PATCH 058/193] news --- news/fitrecipe2-dep.rst | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 news/fitrecipe2-dep.rst diff --git a/news/fitrecipe2-dep.rst b/news/fitrecipe2-dep.rst new file mode 100644 index 00000000..8ce1d4aa --- /dev/null +++ b/news/fitrecipe2-dep.rst @@ -0,0 +1,33 @@ +**Added:** + +* Added ``convert_bounds_to_restraints`` method to ``FitRecipe``. +* Added ``get_bounds_pairs`` method to ``FitRecipe``. +* Added ``get_bounds_array`` method to ``FitRecipe``. +* Added ``get_names`` method to ``FitRecipe``. +* Added ``get_values`` method to ``FitRecipe``. +* Added ``is_free`` method to ``FitRecipe``. + +**Changed:** + +* + +**Deprecated:** + +* Deprecated ``boundsToRestraints`` method for removal in 4.0.0. +* Deprecated ``getBounds`` method for removal in 4.0.0. +* Deprecated ``getBounds2`` method for removal in 4.0.0. +* Deprecated ``getNames`` method for removal in 4.0.0. +* Deprecated ``getValues`` method for removal in 4.0.0. +* Deprecated ``isFree`` method for removal in 4.0.0. + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From a840d5b60d325c56dcb564c0c986f6e255c067fd Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 22 Feb 2026 16:16:17 -0500 Subject: [PATCH 059/193] news 2 --- news/fitrecipe2-dep.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/news/fitrecipe2-dep.rst b/news/fitrecipe2-dep.rst index 8ce1d4aa..0b7d9e3a 100644 --- a/news/fitrecipe2-dep.rst +++ b/news/fitrecipe2-dep.rst @@ -3,8 +3,8 @@ * Added ``convert_bounds_to_restraints`` method to ``FitRecipe``. * Added ``get_bounds_pairs`` method to ``FitRecipe``. * Added ``get_bounds_array`` method to ``FitRecipe``. -* Added ``get_names`` method to ``FitRecipe``. -* Added ``get_values`` method to ``FitRecipe``. +* Added ``get_names`` method to ``FitRecipe`` and ``RecipeContainer``. +* Added ``get_values`` method to ``FitRecipe`` and ``RecipeContainer``. * Added ``is_free`` method to ``FitRecipe``. **Changed:** From deb7303e08f5f80d8231988207349e8a898984c5 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 22 Feb 2026 16:18:37 -0500 Subject: [PATCH 060/193] make new test cleaner --- tests/test_fitrecipe.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index b7fbe0d3..ec3f4802 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -302,16 +302,22 @@ def test_boundsToRestraints(): # create a bounded variable recipe.create_new_variable("var1", 1) - recipe.var1.bounds = (-1, 1) + expected_lower_bound = -1 + expected_upper_bound = 1 + expected_sigma = 2 + recipe.var1.bounds = (-expected_lower_bound, expected_upper_bound) # apply restraints from bounds - recipe.boundsToRestraints(sig=2, scaled=True) + recipe.boundsToRestraints(sig=expected_sigma, scaled=True) restraints = list(recipe._restraints) assert len(restraints) == 1 r = restraints[0] - assert r.lb == -1 - assert r.ub == 1 - assert r.sig == 2 + actual_lower_bound = r.lb + actual_upper_bound = r.ub + actual_sigma = r.sig + assert actual_lower_bound == expected_lower_bound + assert actual_upper_bound == expected_upper_bound + assert actual_sigma == expected_sigma assert r.scaled is True From 526034db41b8ca82246333b7a5832d253c31c17e Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 23 Feb 2026 09:04:15 -0500 Subject: [PATCH 061/193] remove minus sign typo causing tests to fail --- tests/test_fitrecipe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index ec3f4802..48e0bf15 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -305,7 +305,7 @@ def test_boundsToRestraints(): expected_lower_bound = -1 expected_upper_bound = 1 expected_sigma = 2 - recipe.var1.bounds = (-expected_lower_bound, expected_upper_bound) + recipe.var1.bounds = (expected_lower_bound, expected_upper_bound) # apply restraints from bounds recipe.boundsToRestraints(sig=expected_sigma, scaled=True) From de7f59e9e3dbc2b7f1c86e951fdc00e92b4c5232 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 23 Feb 2026 15:57:21 -0500 Subject: [PATCH 062/193] formatResults deprecation --- src/diffpy/srfit/fitbase/fitresults.py | 45 +++++++++++++++++++------- tests/test_fitresults.py | 19 ++++++++++- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index c79c2a17..60fb9193 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -31,6 +31,17 @@ from diffpy.srfit.util import _DASHEDLINE from diffpy.srfit.util import sortKeyForNumericString as numstr from diffpy.srfit.util.inpututils import inputToString +from diffpy.utils._deprecator import build_deprecation_message, deprecated + +fitresults_base = "diffpy.srfit.fitbase.FitResults" +removal_version = "4.0.0" + +formatResults_dep_msg = build_deprecation_message( + fitresults_base, + "formatResults", + "get_results_string", + removal_version, +) class FitResults(object): @@ -324,24 +335,24 @@ def _calculate_constraint_uncertainties(self): self.conunc.append(sig2c**0.5) return - def formatResults(self, header="", footer="", update=False): + def get_results_string(self, header="", footer="", update=False): """Format the results and return them in a string. This function is called by printResults and saveResults. Overloading the formatting here will change all three functions. - Attributes + Parameters ---------- - header - A header to add to the output (default "") - footer - A footer to add to the output (default "") - update - Flag indicating whether to call update() (default False). + header : str + The header to add to the output (default "") + footer : str + The footer to add to the output (default "") + update : bool + The flag indicating whether to call update() (default False). Returns ------- - out + out : str a string containing the formatted results. """ if update: @@ -516,6 +527,16 @@ def formatResults(self, header="", footer="", update=False): out = "\n".join(lines) + "\n" return out + @deprecated(formatResults_dep_msg) + def formatResults(self, header="", footer="", update=False): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitResults.get_results_string + instead. + """ + return self.get_results_string(header, footer, update) + def printResults(self, header="", footer="", update=False): """Format and print the results. @@ -528,11 +549,11 @@ def printResults(self, header="", footer="", update=False): update Flag indicating whether to call update() (default False). """ - print(self.formatResults(header, footer, update).rstrip()) + print(self.get_results_string(header, footer, update).rstrip()) return def __str__(self): - return self.formatResults() + return self.get_results_string() def saveResults(self, filename, header="", footer="", update=False): """Format and save the results. @@ -556,7 +577,7 @@ def saveResults(self, filename, header="", footer="", update=False): myheader += "produced by " + getuser() + "\n" header = myheader + header - res = self.formatResults(header, footer, update) + res = self.get_results_string(header, footer, update) f = open(filename, "w") f.write(res) f.close() diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index 84f6a355..b373e0db 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -17,9 +17,26 @@ import unittest import pytest +from scipy.optimize import leastsq from diffpy.srfit.fitbase.fitrecipe import FitRecipe -from diffpy.srfit.fitbase.fitresults import initializeRecipe +from diffpy.srfit.fitbase.fitresults import FitResults, initializeRecipe + + +def optimize_recipe(recipe): + recipe.fithooks[0].verbose = 0 + residuals = recipe.residual + values = recipe.values + leastsq(residuals, values) + + +def test_compare_old_formatResults_with_new(build_recipe_one_contribution): + recipe = build_recipe_one_contribution + optimize_recipe(recipe) + results = FitResults(recipe) + results_dep = results.formatResults() + results_new = results.get_results_string() + assert results_dep == results_new def testInitializeFromFileName(datafile): From 32719c007b2030a5f5372139dc7410c11a577692 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 24 Feb 2026 10:11:27 -0500 Subject: [PATCH 063/193] printResults deprecation --- docs/examples/coreshellnp.py | 2 +- docs/examples/crystalpdf.py | 2 +- docs/examples/crystalpdfall.py | 2 +- docs/examples/crystalpdfobjcryst.py | 2 +- docs/examples/crystalpdftwodata.py | 2 +- docs/examples/crystalpdftwophase.py | 2 +- docs/examples/debyemodel.py | 2 +- docs/examples/debyemodelII.py | 2 +- docs/examples/ellipsoidsas.py | 2 +- docs/examples/gaussianrecipe.py | 2 +- docs/examples/interface.py | 2 +- docs/examples/npintensity.py | 2 +- docs/examples/npintensityII.py | 2 +- docs/examples/nppdfcrystal.py | 2 +- docs/examples/nppdfobjcryst.py | 2 +- docs/examples/nppdfsas.py | 2 +- docs/examples/simplepdf.py | 2 +- docs/examples/simplepdftwophase.py | 2 +- docs/examples/simplerecipe.py | 2 +- docs/examples/threedoublepeaks.py | 2 +- src/diffpy/srfit/fitbase/fitresults.py | 22 +++++++++++++-- src/diffpy/srfit/fitbase/simplerecipe.py | 36 ++++++++++++++++++------ 22 files changed, 67 insertions(+), 31 deletions(-) diff --git a/docs/examples/coreshellnp.py b/docs/examples/coreshellnp.py index 7083ace4..afb2a339 100644 --- a/docs/examples/coreshellnp.py +++ b/docs/examples/coreshellnp.py @@ -206,7 +206,7 @@ def main(): # Generate and print the FitResults res = FitResults(recipe) - res.printResults() + res.print_results() # Plot! plotResults(recipe) diff --git a/docs/examples/crystalpdf.py b/docs/examples/crystalpdf.py index 9fd7dd9e..fcfbded3 100644 --- a/docs/examples/crystalpdf.py +++ b/docs/examples/crystalpdf.py @@ -168,7 +168,7 @@ def plotResults(recipe): # Generate and print the FitResults res = FitResults(recipe) - res.printResults() + res.print_results() # Plot! plotResults(recipe) diff --git a/docs/examples/crystalpdfall.py b/docs/examples/crystalpdfall.py index 2e0ac7f5..db5fefa3 100644 --- a/docs/examples/crystalpdfall.py +++ b/docs/examples/crystalpdfall.py @@ -232,7 +232,7 @@ def plotResults(recipe): # Generate and print the FitResults res = FitResults(recipe) - res.printResults() + res.print_results() # Plot! plotResults(recipe) diff --git a/docs/examples/crystalpdfobjcryst.py b/docs/examples/crystalpdfobjcryst.py index a5796d01..672a2267 100644 --- a/docs/examples/crystalpdfobjcryst.py +++ b/docs/examples/crystalpdfobjcryst.py @@ -121,7 +121,7 @@ def makeRecipe(ciffile, datname): # Generate and print the FitResults res = FitResults(recipe) - res.printResults() + res.print_results() # Plot! plotResults(recipe) diff --git a/docs/examples/crystalpdftwodata.py b/docs/examples/crystalpdftwodata.py index baef831d..601cb01b 100644 --- a/docs/examples/crystalpdftwodata.py +++ b/docs/examples/crystalpdftwodata.py @@ -188,7 +188,7 @@ def plotResults(recipe): # Generate and print the FitResults res = FitResults(recipe) - res.printResults() + res.print_results() # Plot! plotResults(recipe) diff --git a/docs/examples/crystalpdftwophase.py b/docs/examples/crystalpdftwophase.py index 3c36c0cc..de9cd965 100644 --- a/docs/examples/crystalpdftwophase.py +++ b/docs/examples/crystalpdftwophase.py @@ -179,7 +179,7 @@ def plotResults(recipe): # Generate and print the FitResults res = FitResults(recipe) - res.printResults() + res.print_results() # Plot! plotResults(recipe) diff --git a/docs/examples/debyemodel.py b/docs/examples/debyemodel.py index 1332e462..758c05ef 100644 --- a/docs/examples/debyemodel.py +++ b/docs/examples/debyemodel.py @@ -193,7 +193,7 @@ def main(): res = FitResults(recipe) # Print the results - res.printResults() + res.print_results() # Plot the results plotResults(recipe) diff --git a/docs/examples/debyemodelII.py b/docs/examples/debyemodelII.py index a7c896cb..2c5602f4 100644 --- a/docs/examples/debyemodelII.py +++ b/docs/examples/debyemodelII.py @@ -146,7 +146,7 @@ def main(): res = FitResults(recipe) # Print the results - res.printResults() + res.print_results() # Plot the results plotResults(recipe) diff --git a/docs/examples/ellipsoidsas.py b/docs/examples/ellipsoidsas.py index dda9cd5f..08586701 100644 --- a/docs/examples/ellipsoidsas.py +++ b/docs/examples/ellipsoidsas.py @@ -122,7 +122,7 @@ def plotResults(recipe): # Generate and print the FitResults res = FitResults(recipe) - res.printResults() + res.print_results() # Plot! plotResults(recipe) diff --git a/docs/examples/gaussianrecipe.py b/docs/examples/gaussianrecipe.py index fde45cc5..d0745660 100644 --- a/docs/examples/gaussianrecipe.py +++ b/docs/examples/gaussianrecipe.py @@ -73,7 +73,7 @@ def main(): res = FitResults(recipe) # Print the results. - res.printResults() + res.print_results() # Plot the results. plotResults(recipe) diff --git a/docs/examples/interface.py b/docs/examples/interface.py index bb77b552..03bb498a 100644 --- a/docs/examples/interface.py +++ b/docs/examples/interface.py @@ -63,7 +63,7 @@ def main(): res = FitResults(r) # Print the results. - res.printResults() + res.print_results() # Plot the results. from gaussianrecipe import plotResults diff --git a/docs/examples/npintensity.py b/docs/examples/npintensity.py index 18cd19a1..fce0e7bd 100644 --- a/docs/examples/npintensity.py +++ b/docs/examples/npintensity.py @@ -326,7 +326,7 @@ def main(): rescount = recipe.fithooks[0].count calcount = recipe.bucky.I.count footer = "iofq called %i%% of the time" % int(100.0 * calcount / rescount) - res.printResults(footer=footer) + res.print_results(footer=footer) # Plot! plotResults(recipe) diff --git a/docs/examples/npintensityII.py b/docs/examples/npintensityII.py index 0c7293a1..44e88506 100644 --- a/docs/examples/npintensityII.py +++ b/docs/examples/npintensityII.py @@ -264,7 +264,7 @@ def main(): # Generate and print the FitResults res = FitResults(recipe) - res.printResults() + res.print_results() # Plot! plotResults(recipe) diff --git a/docs/examples/nppdfcrystal.py b/docs/examples/nppdfcrystal.py index 457a9571..a8e0dc9d 100644 --- a/docs/examples/nppdfcrystal.py +++ b/docs/examples/nppdfcrystal.py @@ -122,7 +122,7 @@ def plotResults(recipe): scipyOptimize(recipe) res = FitResults(recipe) - res.printResults() + res.print_results() plotResults(recipe) diff --git a/docs/examples/nppdfobjcryst.py b/docs/examples/nppdfobjcryst.py index 70426101..cce39962 100644 --- a/docs/examples/nppdfobjcryst.py +++ b/docs/examples/nppdfobjcryst.py @@ -147,7 +147,7 @@ def main(): # Print results res = FitResults(recipe) - res.printResults() + res.print_results() # Plot results plotResults(recipe) diff --git a/docs/examples/nppdfsas.py b/docs/examples/nppdfsas.py index 441f0873..0679e771 100644 --- a/docs/examples/nppdfsas.py +++ b/docs/examples/nppdfsas.py @@ -188,7 +188,7 @@ def plotResults(recipe): fitRecipe(recipe) res = FitResults(recipe) - res.printResults() + res.print_results() plotResults(recipe) diff --git a/docs/examples/simplepdf.py b/docs/examples/simplepdf.py index cb04b539..ea7ff783 100644 --- a/docs/examples/simplepdf.py +++ b/docs/examples/simplepdf.py @@ -82,7 +82,7 @@ def makeRecipe(ciffile, datname): # Generate, print and save the FitResults res = FitResults(recipe) - res.printResults() + res.print_results() res.saveResults("nickel_example.res") # Plot! diff --git a/docs/examples/simplepdftwophase.py b/docs/examples/simplepdftwophase.py index 1e92a329..7b252baf 100644 --- a/docs/examples/simplepdftwophase.py +++ b/docs/examples/simplepdftwophase.py @@ -114,7 +114,7 @@ def makeRecipe(niciffile, siciffile, datname): # Generate and print the FitResults res = FitResults(recipe) - res.printResults() + res.print_results() # Plot! plotResults(recipe) diff --git a/docs/examples/simplerecipe.py b/docs/examples/simplerecipe.py index ef1f9a5e..cb7d7b69 100644 --- a/docs/examples/simplerecipe.py +++ b/docs/examples/simplerecipe.py @@ -51,7 +51,7 @@ def main(): leastsq(recipe.residual, recipe.values) # Print the results - recipe.printResults() + recipe.print_results() return diff --git a/docs/examples/threedoublepeaks.py b/docs/examples/threedoublepeaks.py index 8ad75304..6a5b7a42 100644 --- a/docs/examples/threedoublepeaks.py +++ b/docs/examples/threedoublepeaks.py @@ -251,7 +251,7 @@ def steerFit(recipe): res = FitResults(recipe) # Print the results - res.printResults() + res.print_results() # Plot the results plotResults(recipe) diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index 60fb9193..3005ca68 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -43,6 +43,13 @@ removal_version, ) +printResults_dep_msg = build_deprecation_message( + fitresults_base, + "printResults", + "print_results", + removal_version, +) + class FitResults(object): """Class for processing, presenting and storing results of a fit. @@ -338,7 +345,7 @@ def _calculate_constraint_uncertainties(self): def get_results_string(self, header="", footer="", update=False): """Format the results and return them in a string. - This function is called by printResults and saveResults. Overloading + This function is called by print_results and saveResults. Overloading the formatting here will change all three functions. Parameters @@ -537,7 +544,7 @@ def formatResults(self, header="", footer="", update=False): """ return self.get_results_string(header, footer, update) - def printResults(self, header="", footer="", update=False): + def print_results(self, header="", footer="", update=False): """Format and print the results. Parameters @@ -552,6 +559,17 @@ def printResults(self, header="", footer="", update=False): print(self.get_results_string(header, footer, update).rstrip()) return + @deprecated(printResults_dep_msg) + def printResults(self, header="", footer="", update=False): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitResults.print_results + instead. + """ + self.print_results(header, footer, update) + return + def __str__(self): return self.get_results_string() diff --git a/src/diffpy/srfit/fitbase/simplerecipe.py b/src/diffpy/srfit/fitbase/simplerecipe.py index 048520af..699e9a75 100644 --- a/src/diffpy/srfit/fitbase/simplerecipe.py +++ b/src/diffpy/srfit/fitbase/simplerecipe.py @@ -20,7 +20,7 @@ from diffpy.srfit.fitbase.profile import Profile from diffpy.utils._deprecator import build_deprecation_message, deprecated -base = "diffpy.srfit.fitbase.simplerecipe.SimpleRecipe" +base = "diffpy.srfit.fitbase.SimpleRecipe" removal_version = "4.0.0" loadParsedData_dep_msg = build_deprecation_message( @@ -58,6 +58,13 @@ removal_version, ) +printResults_dep_msg = build_deprecation_message( + base, + "printResults", + "print_results", + removal_version, +) + class SimpleRecipe(FitRecipe): """SimpleRecipe class. @@ -161,7 +168,7 @@ def loadParsedData(self, parser): 4.0.0. Please use - diffpy.srfit.fitbase.simplerecipe.SimpleRecipe.load_parsed_data + diffpy.srfit.fitbase.SimpleRecipe.load_parsed_data instead. """ return self.load_parsed_data(parser) @@ -192,7 +199,7 @@ def setObservedProfile(self, xobs, yobs, dyobs=None): 4.0.0. Please use - diffpy.srfit.fitbase.simplerecipe.SimpleRecipe.set_observed_profile + diffpy.srfit.fitbase.SimpleRecipe.set_observed_profile instead. """ return self.set_observed_profile(xobs, yobs, dyobs) @@ -237,7 +244,7 @@ def setCalculationRange(self, xmin=None, xmax=None, dx=None): 4.0.0. Please use - diffpy.srfit.fitbase.simplerecipe.SimpleRecipe.set_calculation_range + diffpy.srfit.fitbase.SimpleRecipe.set_calculation_range instead. """ return self.set_calculation_range(xmin, xmax, dx) @@ -262,7 +269,7 @@ def setCalculationPoints(self, x): 4.0.0. Please use - diffpy.srfit.fitbase.simplerecipe.SimpleRecipe.set_calculation_points + diffpy.srfit.fitbase.SimpleRecipe.set_calculation_points instead. """ return self.set_calculation_points(x) @@ -323,7 +330,7 @@ def setEquation(self, eqstr, ns={}): 4.0.0. Please use - diffpy.srfit.fitbase.simplerecipe.SimpleRecipe.set_equation + diffpy.srfit.fitbase.SimpleRecipe.set_equation instead. """ self.set_equation(eqstr, ns) @@ -334,8 +341,7 @@ def __call__(self): return self.contribution.evaluate() # FitResults methods - - def printResults(self, header="", footer=""): + def print_results(self, header="", footer=""): """Format and print the results. Attributes @@ -345,7 +351,19 @@ def printResults(self, header="", footer=""): footer A footer to add to the output (default "") """ - self.results.printResults(header, footer, True) + self.results.print_results(header, footer, True) + return + + @deprecated(printResults_dep_msg) + def printResults(self, header="", footer=""): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use + diffpy.srfit.fitbase.SimpleRecipe.print_results + instead. + """ + self.print_results(header, footer) return def saveResults(self, filename, header="", footer=""): From 6839b057070c24ca3e78684b11d5075ba89a030d Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 24 Feb 2026 10:34:58 -0500 Subject: [PATCH 064/193] add tests for printResults and formatResults --- tests/conftest.py | 8 ++--- tests/test_fitresults.py | 70 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 70 insertions(+), 8 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 910564fc..9e5332bd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -155,12 +155,12 @@ def build_recipe_one_contribution(): profile.set_observed_profile(x, y) contribution = FitContribution("c1") contribution.set_profile(profile) - contribution.set_equation("A*sin(k*x + c)") + contribution.set_equation("amplitude*sin(wave_number*x + phase_shift)") recipe = FitRecipe() recipe.add_contribution(contribution) - recipe.add_variable(contribution.A, 1) - recipe.add_variable(contribution.k, 1) - recipe.add_variable(contribution.c, 1) + recipe.add_variable(contribution.amplitude, 1) + recipe.add_variable(contribution.wave_number, 1) + recipe.add_variable(contribution.phase_shift, 1) return recipe diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index b373e0db..c46b9a94 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -22,6 +22,23 @@ from diffpy.srfit.fitbase.fitrecipe import FitRecipe from diffpy.srfit.fitbase.fitresults import FitResults, initializeRecipe +# The fit results from the recipe fixture in conftest.py +expected_fitresults = """\ +Some quantities invalid due to missing profile uncertainty +Overall (Chi2 and Reduced Chi2 invalid) +------------------------------------------------------------------------------ +Residual 0.00000000 +Contributions 0.00000000 +Restraints 0.00000000 +Chi2 0.00000000 +Reduced Chi2 0.00000000 +Rw 0.00000000 + +Variables (Uncertainties invalid) +------------------------------------------------------------------------------ +""" +expected_refined_variables = ["amplitude", "wave_number", "phase_shift"] + def optimize_recipe(recipe): recipe.fithooks[0].verbose = 0 @@ -30,13 +47,58 @@ def optimize_recipe(recipe): leastsq(residuals, values) -def test_compare_old_formatResults_with_new(build_recipe_one_contribution): +def test_formatResults(build_recipe_one_contribution): + recipe = build_recipe_one_contribution + optimize_recipe(recipe) + results = FitResults(recipe) + actual_results_string = results.formatResults() + # Because slight variations in refinement, just check + # that the header of the results are the same. + assert expected_fitresults.strip() in actual_results_string.strip() + # check if the refined variables are in the results + for expected_var in expected_refined_variables: + assert expected_var in actual_results_string.strip() + + +def test_get_results_string(build_recipe_one_contribution): + recipe = build_recipe_one_contribution + optimize_recipe(recipe) + results = FitResults(recipe) + actual_results_string = results.get_results_string() + # Because slight variations in refinement, just check + # that the header of the results are the same. + assert expected_fitresults.strip() in actual_results_string.strip() + # check if the refined variables are in the results + for expected_var in expected_refined_variables: + assert expected_var in actual_results_string.strip() + + +def test_printResults(build_recipe_one_contribution, capsys): + recipe = build_recipe_one_contribution + optimize_recipe(recipe) + results = FitResults(recipe) + results.printResults() + actual_results = capsys.readouterr().out + # Because slight variations in refinement, just check + # that the header of the results are the same. + assert expected_fitresults.strip() in actual_results.strip() + # check if the refined variables are in the results + for expected_var in expected_refined_variables: + assert expected_var in actual_results.strip() + + +def test_print_results(build_recipe_one_contribution, capsys): recipe = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) - results_dep = results.formatResults() - results_new = results.get_results_string() - assert results_dep == results_new + results.print_results() + actual_results = capsys.readouterr().out + # Because slight variations in refinement, just check + # that the header of the results are the same. + assert expected_fitresults.strip() in actual_results.strip() + # check if the refined variables are in the results + for expected_var in expected_refined_variables: + assert expected_var in actual_results.strip() def testInitializeFromFileName(datafile): From 96025a0d72166f0d3c94018ebab5a3657807d4cf Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 24 Feb 2026 10:38:29 -0500 Subject: [PATCH 065/193] write test for saveResults --- tests/test_fitresults.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index c46b9a94..153e2e2a 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -101,6 +101,23 @@ def test_print_results(build_recipe_one_contribution, capsys): assert expected_var in actual_results.strip() +def test_saveResults(build_recipe_one_contribution, tmp_path): + recipe = build_recipe_one_contribution + optimize_recipe(recipe) + results = FitResults(recipe) + actual_results_file = tmp_path / "fit_results.txt" + results.saveResults(actual_results_file) + assert actual_results_file.exists() + with open(actual_results_file, "r") as res_file: + actual_results = res_file.read() + # Because slight variations in refinement, just check + # that the header of the results are the same. + assert expected_fitresults.strip() in actual_results.strip() + # check if the refined variables are in the results + for expected_var in expected_refined_variables: + assert expected_var in actual_results.strip() + + def testInitializeFromFileName(datafile): recipe = FitRecipe("recipe") recipe.create_new_variable("A", 0) From a37469258b9754352ffa08ff7c4f21766c750480 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 24 Feb 2026 10:43:44 -0500 Subject: [PATCH 066/193] test for the addition of a header to results --- tests/test_fitresults.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index 153e2e2a..636fb931 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -24,6 +24,7 @@ # The fit results from the recipe fixture in conftest.py expected_fitresults = """\ +My Custom header Some quantities invalid due to missing profile uncertainty Overall (Chi2 and Reduced Chi2 invalid) ------------------------------------------------------------------------------ @@ -51,7 +52,7 @@ def test_formatResults(build_recipe_one_contribution): recipe = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) - actual_results_string = results.formatResults() + actual_results_string = results.formatResults(header="My Custom header") # Because slight variations in refinement, just check # that the header of the results are the same. assert expected_fitresults.strip() in actual_results_string.strip() @@ -64,7 +65,9 @@ def test_get_results_string(build_recipe_one_contribution): recipe = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) - actual_results_string = results.get_results_string() + actual_results_string = results.get_results_string( + header="My Custom header" + ) # Because slight variations in refinement, just check # that the header of the results are the same. assert expected_fitresults.strip() in actual_results_string.strip() @@ -77,7 +80,7 @@ def test_printResults(build_recipe_one_contribution, capsys): recipe = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) - results.printResults() + results.printResults(header="My Custom header") actual_results = capsys.readouterr().out # Because slight variations in refinement, just check # that the header of the results are the same. @@ -91,7 +94,7 @@ def test_print_results(build_recipe_one_contribution, capsys): recipe = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) - results.print_results() + results.print_results(header="My Custom header") actual_results = capsys.readouterr().out # Because slight variations in refinement, just check # that the header of the results are the same. @@ -106,7 +109,7 @@ def test_saveResults(build_recipe_one_contribution, tmp_path): optimize_recipe(recipe) results = FitResults(recipe) actual_results_file = tmp_path / "fit_results.txt" - results.saveResults(actual_results_file) + results.saveResults(actual_results_file, header="My Custom header") assert actual_results_file.exists() with open(actual_results_file, "r") as res_file: actual_results = res_file.read() From 7ed1ec508317f81f6140669f073630f9158e06f4 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 24 Feb 2026 10:46:44 -0500 Subject: [PATCH 067/193] saveResults deprecation --- docs/examples/simplepdf.py | 2 +- src/diffpy/srfit/fitbase/fitresults.py | 22 ++++++++++++++++++++-- src/diffpy/srfit/fitbase/simplerecipe.py | 22 ++++++++++++++++++++-- tests/test_fitresults.py | 17 +++++++++++++++++ 4 files changed, 58 insertions(+), 5 deletions(-) diff --git a/docs/examples/simplepdf.py b/docs/examples/simplepdf.py index ea7ff783..a81bd83d 100644 --- a/docs/examples/simplepdf.py +++ b/docs/examples/simplepdf.py @@ -83,7 +83,7 @@ def makeRecipe(ciffile, datname): # Generate, print and save the FitResults res = FitResults(recipe) res.print_results() - res.saveResults("nickel_example.res") + res.save_results("nickel_example.res") # Plot! plotResults(recipe) diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index 3005ca68..dabebded 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -50,6 +50,13 @@ removal_version, ) +saveResults_dep_msg = build_deprecation_message( + fitresults_base, + "saveResults", + "save_results", + removal_version, +) + class FitResults(object): """Class for processing, presenting and storing results of a fit. @@ -345,7 +352,7 @@ def _calculate_constraint_uncertainties(self): def get_results_string(self, header="", footer="", update=False): """Format the results and return them in a string. - This function is called by print_results and saveResults. Overloading + This function is called by print_results and save_results. Overloading the formatting here will change all three functions. Parameters @@ -573,7 +580,7 @@ def printResults(self, header="", footer="", update=False): def __str__(self): return self.get_results_string() - def saveResults(self, filename, header="", footer="", update=False): + def save_results(self, filename, header="", footer="", update=False): """Format and save the results. Parameters @@ -601,6 +608,17 @@ def saveResults(self, filename, header="", footer="", update=False): f.close() return + @deprecated(saveResults_dep_msg) + def saveResults(self, filename, header="", footer="", update=False): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.FitResults.save_results + instead. + """ + self.save_results(filename, header, footer, update) + return + # End class FitResults diff --git a/src/diffpy/srfit/fitbase/simplerecipe.py b/src/diffpy/srfit/fitbase/simplerecipe.py index 699e9a75..f3789a3a 100644 --- a/src/diffpy/srfit/fitbase/simplerecipe.py +++ b/src/diffpy/srfit/fitbase/simplerecipe.py @@ -65,6 +65,13 @@ removal_version, ) +saveResults_dep_msg = build_deprecation_message( + base, + "saveResults", + "save_results", + removal_version, +) + class SimpleRecipe(FitRecipe): """SimpleRecipe class. @@ -366,7 +373,7 @@ def printResults(self, header="", footer=""): self.print_results(header, footer) return - def saveResults(self, filename, header="", footer=""): + def save_results(self, filename, header="", footer=""): """Format and save the results. Parameters @@ -378,7 +385,18 @@ def saveResults(self, filename, header="", footer=""): footer A footer to add to the output (default "") """ - self.results.saveResults(filename, header, footer, True) + self.results.save_results(filename, header, footer, True) + + @deprecated(saveResults_dep_msg) + def saveResults(self, filename, header="", footer=""): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use + diffpy.srfit.fitbase.SimpleRecipe.save_results + instead. + """ + self.save_results(filename, header, footer) # End class SimpleRecipe diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index 636fb931..761a30ff 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -121,6 +121,23 @@ def test_saveResults(build_recipe_one_contribution, tmp_path): assert expected_var in actual_results.strip() +def test_save_results(build_recipe_one_contribution, tmp_path): + recipe = build_recipe_one_contribution + optimize_recipe(recipe) + results = FitResults(recipe) + actual_results_file = tmp_path / "fit_results.txt" + results.save_results(actual_results_file, header="My Custom header") + assert actual_results_file.exists() + with open(actual_results_file, "r") as res_file: + actual_results = res_file.read() + # Because slight variations in refinement, just check + # that the header of the results are the same. + assert expected_fitresults.strip() in actual_results.strip() + # check if the refined variables are in the results + for expected_var in expected_refined_variables: + assert expected_var in actual_results.strip() + + def testInitializeFromFileName(datafile): recipe = FitRecipe("recipe") recipe.create_new_variable("A", 0) From a08850f3824f4c943a842e28be451a2089cf4275 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 24 Feb 2026 10:50:27 -0500 Subject: [PATCH 068/193] news --- news/fitresults-dep.rst | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 news/fitresults-dep.rst diff --git a/news/fitresults-dep.rst b/news/fitresults-dep.rst new file mode 100644 index 00000000..2ee8a8a3 --- /dev/null +++ b/news/fitresults-dep.rst @@ -0,0 +1,27 @@ +**Added:** + +* Added ``save_results`` method to ``FitResults``. +* Added ``print_results`` method to ``FitResults``. +* Added ``get_results_string`` method to ``FitResults``. + +**Changed:** + +* + +**Deprecated:** + +* Deprecated ``saveResults`` method for removal in 4.0.0. +* Deprecated ``printResults`` method for removal in 4.0.0. +* Deprecated ``formatResults`` method for removal in 4.0.0. + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From bc39b5ace58c0989cf6b74f6023be9e7a2e6a267 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 10:12:50 -0500 Subject: [PATCH 069/193] set fixtures to scope=function --- tests/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 9e5332bd..6c396963 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -146,7 +146,7 @@ def _capturestdout(f, *args, **kwargs): return _capturestdout -@pytest.fixture(scope="session") +@pytest.fixture() def build_recipe_one_contribution(): "helper to build a simple recipe" profile = Profile() @@ -164,7 +164,7 @@ def build_recipe_one_contribution(): return recipe -@pytest.fixture(scope="session") +@pytest.fixture() def build_recipe_two_contributions(): "helper to build a recipe with two contributions" profile1 = Profile() From 1bb14ecd9ab933701fa835fadfddea43e68ae517 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 11:47:23 -0500 Subject: [PATCH 070/193] add constraints and restraints for more strict testing --- tests/conftest.py | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 6c396963..0417ad17 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -166,30 +166,43 @@ def build_recipe_one_contribution(): @pytest.fixture() def build_recipe_two_contributions(): - "helper to build a recipe with two contributions" + """Helper to build a recipe with two physically related contributions.""" profile1 = Profile() - x = linspace(0, pi, 10) - y1 = sin(x) + x = linspace(0, pi, 50) + y1 = sin(x) # amplitude=1, freq=1 profile1.set_observed_profile(x, y1) + contribution1 = FitContribution("c1") contribution1.set_profile(profile1) contribution1.set_equation("A*sin(k*x + c)") profile2 = Profile() - y2 = 0.5 * sin(2 * x) + y2 = 0.5 * sin(2 * x) # amplitude=0.5, freq=2 profile2.set_observed_profile(x, y2) + contribution2 = FitContribution("c2") contribution2.set_profile(profile2) contribution2.set_equation("B*sin(m*x + d)") + recipe = FitRecipe() recipe.add_contribution(contribution1) recipe.add_contribution(contribution2) - recipe.add_variable(contribution1.A, 1) - recipe.add_variable(contribution1.k, 1) - recipe.add_variable(contribution1.c, 1) - recipe.add_variable(contribution2.B, 0.5) - recipe.add_variable(contribution2.m, 2) - recipe.add_variable(contribution2.d, 0) + + # Add variables with reasonable initial guesses + recipe.add_variable(contribution1.A, 0.8) + recipe.add_variable(contribution1.k, 1.0) + recipe.add_variable(contribution1.c, 0.1) + + recipe.add_variable(contribution2.B, 0.4) + recipe.add_variable(contribution2.m, 2.0) + recipe.add_variable(contribution2.d, 0.1) + + # ---- Meaningful constraints ---- + recipe.constrain(contribution2.m, "2*k") + recipe.constrain(contribution2.d, contribution1.c) + recipe.constrain(contribution2.B, "0.5*A") + recipe.restrain(contribution1.A, 0.5, 1.5) + recipe.restrain(contribution1.k, 0.8, 1.2) return recipe From acfb6741deaefb5eb3362689151d193eeebdb9c7 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 11:49:03 -0500 Subject: [PATCH 071/193] add initialization test and method --- src/diffpy/srfit/fitbase/fitrecipe.py | 44 +++++++++++++++++++ src/diffpy/srfit/fitbase/fitresults.py | 7 +++ tests/test_fitrecipe.py | 59 ++++++++++++++++++++++++++ 3 files changed, 110 insertions(+) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index c28acc3e..894dbc18 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -1140,6 +1140,50 @@ def getBounds2(self): """ return self.get_bounds_array() + def initialize_recipe_with_recipe(self, recipe_object): + """Initialize a FitRecipe with another FitRecipe. + + This is used to initialize a FitRecipe with the contribution(s), + parameters, constraints and restraints of another FitRecipe. + If a duplicate contribution, parameter, constraint, or restraint + is added to the FitRecipe you are initializing, the value from the + added object will be used. + + Parameters + ---------- + recipe_object : FitRecipe + The FitRecipe to initialize with. + + Raises + ------ + ValueError + If the object passed is not a FitRecipe. + """ + if not isinstance(recipe_object, FitRecipe): + raise ValueError( + "The input recipe_object must be a FitRecipe, " + f"but got {type(recipe_object)}" + ) + + for contrib_object in recipe_object._contributions.values(): + if contrib_object not in self._contributions.values(): + self.add_contribution(contrib_object) + + for param_name, param_object in recipe_object._parameters.items(): + if param_name not in self._parameters: + self._parameters.update({param_name: param_object}) + + for ( + parameter_object, + constraint_object, + ) in recipe_object._constraints.items(): + if parameter_object not in self._constraints: + self._constraints.update({parameter_object: constraint_object}) + + for restraint in recipe_object._restraints: + if restraint not in self._restraints: + self._restraints.add(restraint) + def set_plot_defaults(self, **kwargs): """Set default plotting options for all future plots. diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index dabebded..163bb18b 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -57,6 +57,13 @@ removal_version, ) +saveResults_dep_msg = build_deprecation_message( + fitresults_base, + "saveResults", + "save_results", + removal_version, +) + class FitResults(object): """Class for processing, presenting and storing results of a fit. diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 48e0bf15..eeb70e34 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -18,10 +18,12 @@ import matplotlib import matplotlib.pyplot as plt +import numpy as np import pytest from numpy import array_equal, dot, linspace, pi, sin from scipy.optimize import leastsq +from diffpy.srfit.fitbase import FitResults from diffpy.srfit.fitbase.fitcontribution import FitContribution from diffpy.srfit.fitbase.fitrecipe import FitRecipe from diffpy.srfit.fitbase.parameter import Parameter @@ -462,6 +464,63 @@ def optimize_recipe(recipe): leastsq(residuals, values) +def test_initialize_recipe_from_recipe(build_recipe_two_contributions): + # Case: User initializes a FitRecipe from a previously optimized fit + # expected: recipe is initialized with everything: + # contributions, profiles (contained in contributions), + # variables, restraints, and constraints + recipe1 = build_recipe_two_contributions + optimize_recipe(recipe1) + expected_parameters_dict = recipe1._parameters + expected_constraints_dict = recipe1._constraints + expected_restraints_set = recipe1._restraints + expected_contributions_dict = recipe1._contributions + expected_profiles_list = [] + for con_name, contribution in expected_contributions_dict.items(): + expected_profile = contribution.profile + expected_profiles_list.append(expected_profile) + + recipe2 = FitRecipe() + recipe2.initialize_recipe_with_recipe(recipe1) + actual_parameters_dict = recipe2._parameters + actual_constraints_dict = recipe2._constraints + actual_restraints_set = recipe2._restraints + actual_contributions_dict = recipe2._contributions + actual_profiles_list = [] + for con_name, contribution in actual_contributions_dict.items(): + actual_profile = contribution.profile + actual_profiles_list.append(actual_profile) + + assert expected_parameters_dict == actual_parameters_dict + assert expected_constraints_dict == actual_constraints_dict + assert expected_restraints_set == actual_restraints_set + assert expected_contributions_dict == actual_contributions_dict + assert expected_profiles_list == actual_profiles_list + + # Check to see if the refined values and variable names are + # the same in the results objects for each recipe + results1 = FitResults(recipe1) + # round to account for small numerical differences + expected_values = np.round(results1.varvals, 7) + expected_names = results1.varnames + + optimize_recipe(recipe2) + results2 = FitResults(recipe2) + # round to account for small numerical differences + actual_values = np.round(results2.varvals, 7) + actual_names = results2.varnames + + assert sorted(expected_names) == sorted(actual_names) + assert sorted(list(expected_values)) == sorted(list(actual_values)) + + +# def test_initialize_recipe_from_results(build_recipe_one_contribution): +# # Case: User initializes a FitRecipe from a FitResults object or +# # results file +# # expected: recipe is initialized with variables from previous fit +# assert False + + def get_labels_and_linecount(ax): """Helper to get line labels and count from a matplotlib Axes.""" labels = [ From a934f424b1c5db0afd398649dfecff5968877d20 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 11:50:10 -0500 Subject: [PATCH 072/193] news --- news/init-w-recipe.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/init-w-recipe.rst diff --git a/news/init-w-recipe.rst b/news/init-w-recipe.rst new file mode 100644 index 00000000..073926e7 --- /dev/null +++ b/news/init-w-recipe.rst @@ -0,0 +1,23 @@ +**Added:** + +* Added initialize_recipe_from_recipe to ``FitRecipe``. + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 9c9fdc343fab0560e408250e040e7e73b43c4df4 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 11:51:46 -0500 Subject: [PATCH 073/193] remove accidental commit --- src/diffpy/srfit/fitbase/fitresults.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index 163bb18b..dabebded 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -57,13 +57,6 @@ removal_version, ) -saveResults_dep_msg = build_deprecation_message( - fitresults_base, - "saveResults", - "save_results", - removal_version, -) - class FitResults(object): """Class for processing, presenting and storing results of a fit. From 4b60d8a4a46ef7511e44d0bc9c4ae78818f8c3c8 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 11:57:35 -0500 Subject: [PATCH 074/193] add test for ValueError --- src/diffpy/srfit/fitbase/fitrecipe.py | 2 +- tests/test_fitrecipe.py | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 894dbc18..72946e40 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -1162,7 +1162,7 @@ def initialize_recipe_with_recipe(self, recipe_object): if not isinstance(recipe_object, FitRecipe): raise ValueError( "The input recipe_object must be a FitRecipe, " - f"but got {type(recipe_object)}" + f"but got {type(recipe_object)}." ) for contrib_object in recipe_object._contributions.values(): diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index eeb70e34..39af10e8 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -514,6 +514,19 @@ def test_initialize_recipe_from_recipe(build_recipe_two_contributions): assert sorted(list(expected_values)) == sorted(list(actual_values)) +def test_initialize_recipe_from_recipe_bad(build_recipe_two_contributions): + # Case: User tries to initialize a FitRecipe from a non recipe object + # expected: raised ValueError with message + recipe_bad = 12345 # not a FitRecipe object + recipe2 = FitRecipe() + msg = ( + "The input recipe_object must be a FitRecipe, " + "but got ." + ) + with pytest.raises(ValueError, match=msg): + recipe2.initialize_recipe_with_recipe(recipe_bad) + + # def test_initialize_recipe_from_results(build_recipe_one_contribution): # # Case: User initializes a FitRecipe from a FitResults object or # # results file From 2426eb32ef4654b6eb08240d2a47854a7ebb2d2c Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:17:34 -0500 Subject: [PATCH 075/193] AUTHORS.rst --- AUTHORS.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS.rst b/AUTHORS.rst index b2335043..68e2f2d8 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -1,7 +1,7 @@ Authors ======= -Christopher Farrow, Pavol Juhas, Simon J. L. Billinge, and members of the Billinge Group +Christopher Farrow, Pavol Juhas, Caden Myers, Simon J. L. Billinge, and members of the Billinge Group Contributors ------------ From 380a0c1d257d1bf74a5c4f24f2d851bb8b76e9d7 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:18:19 -0500 Subject: [PATCH 076/193] CODE-OF-CONDUCT.rst --- CODE-OF-CONDUCT.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODE-OF-CONDUCT.rst b/CODE-OF-CONDUCT.rst index e8199ca5..9352c6ec 100644 --- a/CODE-OF-CONDUCT.rst +++ b/CODE-OF-CONDUCT.rst @@ -67,7 +67,7 @@ Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at -sb2896@columbia.edu. All complaints will be reviewed and investigated promptly and fairly. +cjm2304@columbia.edu and sbillinge@ucsb.edu. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. From 441f669aeabca345de5500c87fe339911a41c827 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:18:42 -0500 Subject: [PATCH 077/193] cookiecutter.json --- cookiecutter.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 cookiecutter.json diff --git a/cookiecutter.json b/cookiecutter.json new file mode 100644 index 00000000..46da0e2e --- /dev/null +++ b/cookiecutter.json @@ -0,0 +1,20 @@ +{ + "author_names": "Christopher Farrow, Pavol Juhas, Caden Myers, Simon J. L. Billinge", + "author_emails": "farrowch@gmail.com, pavol.juhas@gmail.com, cjm2304@columbia.edu, sbillinge@ucsb.edu", + "maintainer_names": "Caden Myers, Simon J. L. Billinge", + "maintainer_emails": "cjm2304@columbia.edu, sbillinge@ucsb.edu", + "maintainer_github_usernames": "cadenmyers13, sbillinge", + "contributors": "Christopher Farrow, Pavol Juhas, Caden Myers, Simon J. L. Billinge, and members of the DiffPy community.", + "license_holders": "The DiffPy Team", + "project_name": "diffpy.srfit", + "github_username_or_orgname": "diffpy", + "github_repo_name": "diffpy.srfit", + "conda_pypi_package_dist_name": "diffpy.srfit", + "package_dir_name": "diffpy.srfit", + "project_short_description": "Generalized code base for modeling problems.", + "project_keywords": "regression, modeling, fitting, diffraction, PDF", + "minimum_supported_python_version": "3.11", + "maximum_supported_python_version": "3.13", + "project_needs_c_code_compiled": "No", + "project_has_gui_tests": "No" +} From cd8f96eeab64163784f6078b0058ce11010be3ad Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:19:47 -0500 Subject: [PATCH 078/193] LICENSE.rst --- LICENSE.rst | 89 +++++++++-------------------------------------------- 1 file changed, 15 insertions(+), 74 deletions(-) diff --git a/LICENSE.rst b/LICENSE.rst index acbe6078..85dc311f 100644 --- a/LICENSE.rst +++ b/LICENSE.rst @@ -9,7 +9,7 @@ OPEN SOURCE LICENSE AGREEMENT - Copyright (c) 2008-2012, The Trustees of Columbia University in the City of New York - Copyright (c) 2014-2019, Brookhaven Science Associates, Brookhaven National Laboratory - Copyright (c) 2020-2025, The Trustees of Columbia University in the City of New York - +- Copyright (c) 2026-present, The DiffPy Team. The "DiffPy-CMI" is distributed subject to the following license conditions: @@ -59,76 +59,17 @@ outside your organization, if you meet all of the following conditions: (c) Modified copies and works based on the Software must carry prominent notices stating that you changed specified portions of the Software. - (d) Neither the name of Brookhaven Science Associates or Brookhaven - National Laboratory nor the names of its contributors may be used to - endorse or promote products derived from this software without specific - written permission. - - -(5) Portions of the Software resulted from work developed under a U.S. -Government contract and are subject to the following license: -The Government is granted for itself and others acting on its behalf a -paid-up, nonexclusive, irrevocable worldwide license in this computer software -to reproduce, prepare derivative works, and perform publicly and display -publicly. - - -(6) WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT -WARRANTY OF ANY KIND. THE COPYRIGHT HOLDERS, THEIR THIRD PARTY -LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND -THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, INCLUDING -BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL -LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR USEFULNESS OF -THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF THE SOFTWARE WOULD NOT INFRINGE -PRIVATELY OWNED RIGHTS, (4) DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION -UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL BE CORRECTED. - - -(7) LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT HOLDERS, THEIR -THIRD PARTY LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF -ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF ANY KIND OR NATURE, INCLUDING -BUT NOT LIMITED TO LOSS OF PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, -WHETHER SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT (INCLUDING -NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE, EVEN IF ANY OF SAID PARTIES HAS -BEEN WARNED OF THE POSSIBILITY OF SUCH LOSS OR DAMAGES. - - -Brookhaven National Laboratory Notice -===================================== - -Acknowledgment of sponsorship ------------------------------ - -This software was produced by the Brookhaven National Laboratory, under -Contract DE-AC02-98CH10886 with the Department of Energy. - - -Government disclaimer of liability ----------------------------------- - -Neither the United States nor the United States Department of Energy, nor -any of their employees, makes any warranty, express or implied, or assumes -any legal liability or responsibility for the accuracy, completeness, or -usefulness of any data, apparatus, product, or process disclosed, or -represents that its use would not infringe privately owned rights. - - -Brookhaven disclaimer of liability ----------------------------------- - -Brookhaven National Laboratory makes no representations or warranties, -express or implied, nor assumes any liability for the use of this software. - - -Maintenance of notice ---------------------- - -In the interest of clarity regarding the origin and status of this -software, Brookhaven National Laboratory requests that any recipient of it -maintain this notice affixed to any distribution by the recipient that -contains a copy or derivative of this software. - - -END OF LICENSE +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From 4cebd7b61ac610fbf11d0df39439b40c0615428c Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:20:48 -0500 Subject: [PATCH 079/193] LICENSE.rst pt2 --- LICENSE.rst | 87 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 73 insertions(+), 14 deletions(-) diff --git a/LICENSE.rst b/LICENSE.rst index 85dc311f..6d222385 100644 --- a/LICENSE.rst +++ b/LICENSE.rst @@ -59,17 +59,76 @@ outside your organization, if you meet all of the following conditions: (c) Modified copies and works based on the Software must carry prominent notices stating that you changed specified portions of the Software. -3. Neither the name of the copyright holder nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + (d) Neither the name of Brookhaven Science Associates or Brookhaven + National Laboratory nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + written permission. + + +(5) Portions of the Software resulted from work developed under a U.S. +Government contract and are subject to the following license: +The Government is granted for itself and others acting on its behalf a +paid-up, nonexclusive, irrevocable worldwide license in this computer software +to reproduce, prepare derivative works, and perform publicly and display +publicly. + + +(6) WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT +WARRANTY OF ANY KIND. THE COPYRIGHT HOLDERS, THEIR THIRD PARTY +LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND +THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL +LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR USEFULNESS OF +THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF THE SOFTWARE WOULD NOT INFRINGE +PRIVATELY OWNED RIGHTS, (4) DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION +UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL BE CORRECTED. + + +(7) LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT HOLDERS, THEIR +THIRD PARTY LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF +ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, INCIDENTAL, +CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF ANY KIND OR NATURE, INCLUDING +BUT NOT LIMITED TO LOSS OF PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, +WHETHER SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT (INCLUDING +NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE, EVEN IF ANY OF SAID PARTIES HAS +BEEN WARNED OF THE POSSIBILITY OF SUCH LOSS OR DAMAGES. + + +Brookhaven National Laboratory Notice +===================================== + +Acknowledgment of sponsorship +----------------------------- + +This software was produced by the Brookhaven National Laboratory, under +Contract DE-AC02-98CH10886 with the Department of Energy. + + +Government disclaimer of liability +---------------------------------- + +Neither the United States nor the United States Department of Energy, nor +any of their employees, makes any warranty, express or implied, or assumes +any legal liability or responsibility for the accuracy, completeness, or +usefulness of any data, apparatus, product, or process disclosed, or +represents that its use would not infringe privately owned rights. + + +Brookhaven disclaimer of liability +---------------------------------- + +Brookhaven National Laboratory makes no representations or warranties, +express or implied, nor assumes any liability for the use of this software. + + +Maintenance of notice +--------------------- + +In the interest of clarity regarding the origin and status of this +software, Brookhaven National Laboratory requests that any recipient of it +maintain this notice affixed to any distribution by the recipient that +contains a copy or derivative of this software. + + +END OF LICENSE From 5da77d6082d3a2ffe3826a210719a7b246abd01f Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:22:24 -0500 Subject: [PATCH 080/193] MANIFEST.in --- MANIFEST.in | 1 - 1 file changed, 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index b31fb162..c1ccccac 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -11,4 +11,3 @@ global-exclude __pycache__ # Exclude Python cache directories. global-exclude .git* # Exclude git files and directories. global-exclude .idea # Exclude PyCharm project settings. exclude .codecov.yml -exclude .coveragerc From 00f5fbac4c510328a51b772cd3473bc9b4cddc63 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:23:27 -0500 Subject: [PATCH 081/193] pyproject.toml --- pyproject.toml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index fbbe0c3e..677cc175 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,13 +6,17 @@ build-backend = "setuptools.build_meta" name = "diffpy.srfit" dynamic=['version', 'dependencies'] authors = [ - { name="Simon Billinge", email="sb2896@columbia.edu" }, + {name='Christopher Farrow', email='farrowch@gmail.com'}, + {name='Pavol Juhas', email='pavol.juhas@gmail.com'}, + {name='Caden Myers', email='cjm2304@columbia.edu'}, + {name='Simon J. L. Billinge', email='sbillinge@ucsb.edu'}, ] maintainers = [ - { name="Simon Billinge", email="sb2896@columbia.edu" }, + {name='Caden Myers', email='cjm2304@columbia.edu'}, + {name='Simon J. L. Billinge', email='sbillinge@ucsb.edu'}, ] -description = "Configurable code for solving atomic structures." -keywords = ['regression', 'modelling', 'fitting', 'diffraction', 'PDF'] +description = "Generalized code base for modeling problems." +keywords = ['regression', 'modeling', 'fitting', 'diffraction', 'PDF'] readme = "README.rst" requires-python = ">=3.11, <3.14" classifiers = [ @@ -48,6 +52,9 @@ include = ["*"] # package names should match these glob patterns (["*"] by defa exclude = [] # exclude packages matching these glob patterns (empty by default) namespaces = false # to disable scanning PEP 420 namespaces (true by default) +[project.scripts] +diffpy-srfit = "diffpy.srfit.app:main" + [tool.setuptools.dynamic] dependencies = {file = ["requirements/pip.txt"]} @@ -56,6 +63,11 @@ exclude-file = ".codespell/ignore_lines.txt" ignore-words = ".codespell/ignore_words.txt" skip = "*.cif,*.dat" +[tool.docformatter] +recursive = true +wrap-summaries = 72 +wrap-descriptions = 72 + [tool.black] line-length = 79 include = '\.pyi?$' From 6bcccf3286697f258ee541abfe09c0e5fe9397ba Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:25:55 -0500 Subject: [PATCH 082/193] README.rst --- README.rst | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 2d4040ec..fbf4e193 100644 --- a/README.rst +++ b/README.rst @@ -25,6 +25,7 @@ :target: https://anaconda.org/conda-forge/diffpy.srfit .. |PR| image:: https://img.shields.io/badge/PR-Welcome-29ab47ff + :target: https://github.com/diffpy/diffpy.srfit/pulls .. |PyPI| image:: https://img.shields.io/pypi/v/diffpy.srfit :target: https://pypi.org/project/diffpy.srfit/ @@ -94,10 +95,6 @@ The following creates and activates a new environment named ``diffpy.srfit_env`` conda create -n diffpy.srfit_env diffpy.srfit conda activate diffpy.srfit_env -To confirm that the installation was successful, type :: - - python -c "import diffpy.srfit; print(diffpy.srfit.__version__)" - The output should print the latest version displayed on the badges above. This will install the minimal `diffpy.srfit` installation. It will often be used @@ -136,6 +133,19 @@ and run the following :: pip install . +This package also provides command-line utilities. To check the software has been installed correctly, type :: + + diffpy.srfit --version + +You can also type the following command to verify the installation. :: + + python -c "import diffpy.srfit; print(diffpy.srfit.__version__)" + + +To view the basic usage and available commands, type :: + + diffpy.srfit -h + Getting Started --------------- @@ -167,12 +177,12 @@ trying to commit again. Improvements and fixes are always appreciated. -Before contributing, please read our `Code of Conduct `_. +Before contributing, please read our `Code of Conduct `_. Contact ------- -For more information on diffpy.srfit please visit the project `web-page `_ or email Simon Billinge at sb2896@columbia.edu. +For more information on diffpy.srfit please visit the project `web-page `_ or email the maintainers ``Caden Myers (cjm2304@columbia.edu) and Simon J. L. Billinge (sbillinge@ucsb.edu)``. Acknowledgements ---------------- From 11167cb804808299c41f71dd2b242d3e83c5cbef Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:26:25 -0500 Subject: [PATCH 083/193] release_checklist.md --- .github/ISSUE_TEMPLATE/release_checklist.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/release_checklist.md b/.github/ISSUE_TEMPLATE/release_checklist.md index 6107962c..56c5fca3 100644 --- a/.github/ISSUE_TEMPLATE/release_checklist.md +++ b/.github/ISSUE_TEMPLATE/release_checklist.md @@ -11,12 +11,13 @@ assignees: "" - [ ] All PRs/issues attached to the release are merged. - [ ] All the badges on the README are passing. - [ ] License information is verified as correct. If you are unsure, please comment below. -- [ ] Locally rendered documentation contains all appropriate pages, including API references (check no modules are - missing), tutorials, and other human-written text is up-to-date with any changes in the code. +- [ ] Locally rendered documentation contains all appropriate pages, tutorials, and other human-written text is up-to-date with any changes in the code. +- [ ] All API references are included. To check this, run `conda install scikit-package` and then `package build api-doc`. Review any edits made by rerendering the docs locally. - [ ] Installation instructions in the README, documentation, and the website are updated. - [ ] Successfully run any tutorial examples or do functional testing with the latest Python version. - [ ] Grammar and writing quality are checked (no typos). - [ ] Install `pip install build twine`, run `python -m build` and `twine check dist/*` to ensure that the package can be built and is correctly formatted for PyPI release. +- [ ] Dispatch matrix testing to test the release on all Python versions and systems. If you do not have permission to run this workflow, tag the maintainer and say `@maintainer, please dispatch matrix testing workflow`. Please tag the maintainer (e.g., @username) in the comment here when you are ready for the PyPI/GitHub release. Include any additional comments necessary, such as version information and details about the pre-release here: @@ -34,7 +35,7 @@ Please let the maintainer know that all checks are done and the package is ready - [ ] Ensure that the full release has appeared on PyPI successfully. -- [ ] New package dependencies listed in `conda.txt` and `test.txt` are added to `meta.yaml` in the feedstock. +- [ ] New package dependencies listed in `conda.txt` and `tests.txt` are added to `meta.yaml` in the feedstock. - [ ] Close any open issues on the feedstock. Reach out to the maintainer if you have questions. - [ ] Tag the maintainer for conda-forge release. From 7104cf1d78a12c04d18d32bdaeb7cb813c20c33a Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:26:59 -0500 Subject: [PATCH 084/193] build-and-publish-docs-on-dispatch.yml --- .../build-and-publish-docs-on-dispatch.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/build-and-publish-docs-on-dispatch.yml diff --git a/.github/workflows/build-and-publish-docs-on-dispatch.yml b/.github/workflows/build-and-publish-docs-on-dispatch.yml new file mode 100644 index 00000000..3d7394d0 --- /dev/null +++ b/.github/workflows/build-and-publish-docs-on-dispatch.yml @@ -0,0 +1,18 @@ +name: Build and Publish Docs on Dispatch + +on: + workflow_dispatch: + +jobs: + get-python-version: + uses: scikit-package/release-scripts/.github/workflows/_get-python-version-latest.yml@v0 + with: + python_version: 0 + + docs: + uses: scikit-package/release-scripts/.github/workflows/_release-docs.yml@v0 + with: + project: diffpy.srfit + c_extension: false + headless: false + python_version: ${{ fromJSON(needs.get-python-version.outputs.latest_python_version) }} From 6510ca44aa403d66ac97ff03afe894d309814760 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:27:31 -0500 Subject: [PATCH 085/193] build-wheel-release-upload.yml --- .github/workflows/build-wheel-release-upload.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-wheel-release-upload.yml b/.github/workflows/build-wheel-release-upload.yml index 4d66f1b5..c5e92258 100644 --- a/.github/workflows/build-wheel-release-upload.yml +++ b/.github/workflows/build-wheel-release-upload.yml @@ -1,4 +1,4 @@ -name: Release (GitHub/PyPI) and Deploy Docs +name: Build Wheel, Release on GitHub/PyPI, and Deploy Docs on: workflow_dispatch: @@ -7,12 +7,12 @@ on: - "*" # Trigger on all tags initially, but tag and release privilege are verified in _build-wheel-release-upload.yml jobs: - release: + build-release: uses: scikit-package/release-scripts/.github/workflows/_build-wheel-release-upload.yml@v0 with: project: diffpy.srfit c_extension: false - maintainer_GITHUB_username: sbillinge + maintainer_GITHUB_username: cadenmyers13, sbillinge secrets: PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} PAT_TOKEN: ${{ secrets.PAT_TOKEN }} From b506e1676b1aefc299d6b4014afdccf8488b5b6b Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:27:53 -0500 Subject: [PATCH 086/193] matrix-and-codecov.yml --- .github/workflows/matrix-and-codecov.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/matrix-and-codecov.yml diff --git a/.github/workflows/matrix-and-codecov.yml b/.github/workflows/matrix-and-codecov.yml new file mode 100644 index 00000000..b9a73c69 --- /dev/null +++ b/.github/workflows/matrix-and-codecov.yml @@ -0,0 +1,21 @@ +name: Matrix and Codecov + +on: + # push: + # branches: + # - main + release: + types: + - prereleased + - published + workflow_dispatch: + +jobs: + matrix-coverage: + uses: scikit-package/release-scripts/.github/workflows/_matrix-and-codecov-on-merge-to-main.yml@v0 + with: + project: diffpy.srfit + c_extension: false + headless: false + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From cd28445445e6fddb61855e837944301896110b92 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:30:23 -0500 Subject: [PATCH 087/193] README.rst pt2 --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index fbf4e193..00bd1dd2 100644 --- a/README.rst +++ b/README.rst @@ -39,7 +39,7 @@ diffpy.srfit ============ -Configurable code for solving atomic structures. +Generalized code base for modeling problems. The diffpy.srfit package provides the framework for building a global optimizer on the fly from components such as function calculators (that calculate From f71e1dad2a71b895e48e936384ec5852dab804cd Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:30:57 -0500 Subject: [PATCH 088/193] conf.py --- docs/source/conf.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 6f33a1b7..99dc93f6 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -32,9 +32,7 @@ sys.path.insert(0, str(Path("../../src").resolve())) # abbreviations -ab_authors = ( - "Christopher Farrow, Pavol Juhas, and members of the Billinge Group" -) +ab_authors = "Christopher Farrow, Pavol Juhas, Caden Myers, Simon J. L. Billinge, and members of the Billinge Group." # -- General configuration ------------------------------------------------ @@ -86,7 +84,7 @@ # General information about the project. project = "diffpy.srfit" -copyright = "%Y, The Trustees of Columbia University in the City of New York" +copyright = "%Y, The DiffPy Team" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -317,7 +315,7 @@ "diffpy.srfit Documentation", ab_authors, "diffpy.srfit", - "Configurable code for solving atomic structures.", + "Generalized code base for modeling problems.", "Miscellaneous", ), ] From c079ecee05209a14b74fa2c559a50de8a32a7797 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:34:49 -0500 Subject: [PATCH 089/193] index.rst --- docs/source/index.rst | 47 ++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index ea21479d..b40360f6 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,14 +1,20 @@ -.. _developers-guide-index: +####### +|title| +####### -#################################################### -diffpy.srfit documentation -#################################################### +.. |title| replace:: diffpy.srfit documentation -diffpy.srfit - configurable code for solving atomic structures. +``diffpy.srfit`` - Generalized code base for modeling problems. -| Software version |release|. +| Software version |release| | Last updated |today|. +=============== +Getting started +=============== + +Welcome to the ``diffpy.srfit`` documentation! + The diffpy.srfit package provides the framework for building a global optimizer on the fly from components such as function calculators (that calculate different data spectra), regression algorithms and structure models. The @@ -31,9 +37,9 @@ obtain the total cost function. Additionally, diffpy.srfit is designed to be extensible, allowing the user to integrate external calculators to perform co-refinements with other techniques. -======================================== +======= Authors -======================================== +======= diffpy.srfit is developed by members of the Billinge Group at Columbia University and at Brookhaven National Laboratory including @@ -41,17 +47,23 @@ Christopher L. Farrow, Pavol Juhás, Simon J.L. Billinge. The source code in *observable.py* was derived from the 1.0 version of the Caltech "Pyre" project. - -For a detailed list of contributors see +``diffpy.srfit`` is developed by Christopher Farrow, Pavol Juhas, Caden Myers, Simon J. L. Billinge, and members of the DiffPy community. +This project is maintained by Caden Myers and Simon J. L. Billinge. For a detailed list of contributors see https://github.com/diffpy/diffpy.srfit/graphs/contributors. -====================================== +============ Installation -====================================== +============ -See the `README `_ +See the `README `_ file included with the distribution. +================ +Acknowledgements +================ + +``diffpy.srfit`` is built and maintained with `scikit-package `_. + ====================================== Where next? ====================================== @@ -62,10 +74,9 @@ Where next? examples.rst extending.rst -====================================== +================= Table of contents -====================================== - +================= .. toctree:: :titlesonly: @@ -75,9 +86,9 @@ Table of contents .. faq.rst -====================================== +======= Indices -====================================== +======= * :ref:`genindex` * :ref:`modindex` From 14790774f8b77a500761c4903b6642a44dab759a Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:36:20 -0500 Subject: [PATCH 090/193] license.rst --- docs/source/license.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/source/license.rst b/docs/source/license.rst index 7d78e94f..748b63bf 100644 --- a/docs/source/license.rst +++ b/docs/source/license.rst @@ -1,3 +1,5 @@ +:tocdepth: -1 + .. index:: license License @@ -12,10 +14,11 @@ OPEN SOURCE LICENSE AGREEMENT Lawrence Berkeley National Laboratory | Copyright (c) 2014, Australian Synchrotron Research Program Inc., ("ASRP") | Copyright (c) 2006-2007, Board of Trustees of Michigan State University -| Copyright (c) 2008-2012, The Trustees of Columbia University in - the City of New York | Copyright (c) 2014-2019, Brookhaven Science Associates, Brookhaven National Laboratory +| Copyright (c) 2008-2025, The Trustees of Columbia University in + the City of New York +| Copyright (c) 2026-present, The DiffPy Team. The "DiffPy-CMI" is distributed subject to the following license conditions: From 1ef6b748e60ea3f30f2d0af72b2821ffbb868843 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:37:43 -0500 Subject: [PATCH 091/193] diffpy.srfit.rst --- docs/source/api/diffpy.srfit.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/source/api/diffpy.srfit.rst b/docs/source/api/diffpy.srfit.rst index 8f840d0c..1e2925bf 100644 --- a/docs/source/api/diffpy.srfit.rst +++ b/docs/source/api/diffpy.srfit.rst @@ -1,7 +1,9 @@ :tocdepth: -1 -diffpy.srfit package -==================== +|title| +======= + +.. |title| replace:: diffpy.srfit package .. automodule:: diffpy.srfit :members: @@ -25,8 +27,10 @@ Subpackages Submodules ---------- -diffpy.srfit.exceptions module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +|module| +-------- + +.. |module| replace:: diffpy.srfit.exceptions module .. automodule:: diffpy.srfit.exceptions :members: From 99c7aac0c49f209942772b20b2c6b93d24e93c5e Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:40:21 -0500 Subject: [PATCH 092/193] __init__.py --- src/diffpy/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/diffpy/__init__.py b/src/diffpy/__init__.py index 3254c0a6..54f1f125 100644 --- a/src/diffpy/__init__.py +++ b/src/diffpy/__init__.py @@ -4,8 +4,10 @@ # (c) 2008-2025 The Trustees of Columbia University in the City of New York. # All rights reserved. # -# File coded by: Chris Farrow and Billinge Group members and community -# contributors. +# (c) 2025-present The DiffPy Team. +# +# File coded by: Chris Farrow, Caden Myers, Billinge Group members and +# community contributors. # # See GitHub contributions for a more detailed list of contributors. # https://github.com/diffpy/diffpy.srfit/graphs/contributors From 8d4945a86b3f031163df84c6bd35a948ed8c66df Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:41:40 -0500 Subject: [PATCH 093/193] __init__.py --- src/diffpy/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/diffpy/__init__.py b/src/diffpy/__init__.py index 54f1f125..22cbdcc6 100644 --- a/src/diffpy/__init__.py +++ b/src/diffpy/__init__.py @@ -6,8 +6,8 @@ # # (c) 2025-present The DiffPy Team. # -# File coded by: Chris Farrow, Caden Myers, Billinge Group members and -# community contributors. +# File coded by: Christopher Farrow, Pavol Juhas, Caden Myers, +# Simon J. L. Billinge, and members of the DiffPy community. # # See GitHub contributions for a more detailed list of contributors. # https://github.com/diffpy/diffpy.srfit/graphs/contributors From 935f5e5ff1a3fe012cba0b92452d1bfc16b59c1c Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:42:44 -0500 Subject: [PATCH 094/193] __init__.py --- src/diffpy/srfit/__init__.py | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/src/diffpy/srfit/__init__.py b/src/diffpy/srfit/__init__.py index 0374fdcf..d8b19522 100644 --- a/src/diffpy/srfit/__init__.py +++ b/src/diffpy/srfit/__init__.py @@ -3,9 +3,10 @@ # # (c) 2008-2025 The Trustees of Columbia University in the City of New York. # All rights reserved. +# (c) 2026-present The DiffPy Team. All rights reserved. # -# File coded by: Christopher Farrow, Pavol Juhas, and members of the -# Billinge Group. +# File coded by: Christopher Farrow, Pavol Juhas, Caden Myers, +# Simon J. L. Billinge, and members of the DiffPy community. # # See GitHub contributions for a more detailed list of contributors. # https://github.com/diffpy/diffpy.srfit/graphs/contributors @@ -13,27 +14,10 @@ # See LICENSE.rst for license information. # ############################################################################## -"""Complex modeling framework for structure refinement and solution. - -SrFit is a tool for coherently combining known information about a -material to derive other properties, in particular material structure. -SrFit allows the customization and creation of structure -representations, profile calculators, constraints, restraints and file -input parsers. The customized pieces can be glued together within SrFit -to optimize a structure, or other physically relevant information from -one or more experimental profiles. Other known information about the -system of interest can be included with arbitrarily complex constraints -and restraints. In this way, the end user creates a customized fitting -application that suits the problem to the available information. - -The subpackages herein define various pieces of the SrFit framework. -Developers are encouraged to work through the examples described in the -documentation to learn how to use and customize the various parts of -SrFit. -""" +"""Generalized code base for modeling problems.""" # package version -from diffpy.srfit.version import __version__ +from diffpy.srfit.version import __version__ # noqa # silence the pyflakes syntax checker assert __version__ or True From 21f688b2d355177648d7674bdc056d79ffe92c5c Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:43:10 -0500 Subject: [PATCH 095/193] srfit_app.py --- src/diffpy/srfit/srfit_app.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/diffpy/srfit/srfit_app.py diff --git a/src/diffpy/srfit/srfit_app.py b/src/diffpy/srfit/srfit_app.py new file mode 100644 index 00000000..65b92262 --- /dev/null +++ b/src/diffpy/srfit/srfit_app.py @@ -0,0 +1,33 @@ +import argparse + +from diffpy.srfit.version import __version__ + + +def main(): + parser = argparse.ArgumentParser( + prog="diffpy.srfit", + description=( + "Generalized code base for modeling problems.\n\n" + "For more information, visit: " + "https://github.com/diffpy/diffpy.srfit/" + ), + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + + parser.add_argument( + "--version", + action="store_true", + help="Show the program's version number and exit", + ) + + args = parser.parse_args() + + if args.version: + print(f"diffpy.srfit {__version__}") + else: + # Default behavior when no arguments are given + parser.print_help() + + +if __name__ == "__main__": + main() From af72c5ce26477d2c478f5168a6d13c53cb0603f6 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:43:52 -0500 Subject: [PATCH 096/193] version.py --- src/diffpy/srfit/version.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/diffpy/srfit/version.py b/src/diffpy/srfit/version.py index f0833049..c62be11e 100644 --- a/src/diffpy/srfit/version.py +++ b/src/diffpy/srfit/version.py @@ -3,9 +3,10 @@ # # (c) 2008-2025 The Trustees of Columbia University in the City of New York. # All rights reserved. +# (c) 2026-present The DiffPy Team. All rights reserved. # -# File coded by: Christopher Farrow, Pavol Juhas, and members of the -# Billinge Group. +# File coded by: Christopher Farrow, Pavol Juhas, Caden Myers, +# Simon J. L. Billinge, and members of the DiffPy community. # # See GitHub contributions for a more detailed list of contributors. # https://github.com/diffpy/diffpy.srfit/graphs/contributors @@ -19,8 +20,9 @@ # __all__ = ["__date__", "__git_commit__", "__timestamp__", "__version__"] # obtain version information -from importlib.metadata import version +from importlib.metadata import PackageNotFoundError, version -__version__ = version("diffpy.srfit") - -# End of file +try: + __version__ = version("diffpy.srfit") +except PackageNotFoundError: + __version__ = "unknown" From 87294870cf032685cb82c94cc43e44a2dee2f2cd Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:46:24 -0500 Subject: [PATCH 097/193] news --- news/update030.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/update030.rst diff --git a/news/update030.rst b/news/update030.rst new file mode 100644 index 00000000..3ce80500 --- /dev/null +++ b/news/update030.rst @@ -0,0 +1,23 @@ +**Added:** + +* + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* Update codebase to scikit-package 0.3.0 standards. + +**Security:** + +* From 36216d84740cd7bfabaa42ccdbfb49b73ff77613 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 25 Feb 2026 19:47:16 +0000 Subject: [PATCH 098/193] [pre-commit.ci] auto fixes from pre-commit hooks --- docs/examples/debyemodel.py | 6 ++++-- docs/examples/debyemodelII.py | 3 ++- docs/examples/npintensityII.py | 3 ++- docs/examples/nppdfsas.py | 3 ++- docs/examples/threedoublepeaks.py | 3 ++- src/diffpy/srfit/equation/builder.py | 13 ++++++++----- src/diffpy/srfit/equation/literals/literal.py | 3 ++- .../srfit/equation/literals/operators.py | 9 ++++++--- src/diffpy/srfit/equation/visitors/printer.py | 3 ++- src/diffpy/srfit/equation/visitors/swapper.py | 6 ++++-- src/diffpy/srfit/fitbase/fitcontribution.py | 3 ++- src/diffpy/srfit/fitbase/fithook.py | 18 ++++++++++++------ src/diffpy/srfit/fitbase/fitrecipe.py | 11 ++++++----- src/diffpy/srfit/fitbase/fitresults.py | 9 ++++++--- src/diffpy/srfit/fitbase/profileparser.py | 6 ++++-- src/diffpy/srfit/fitbase/recipeorganizer.py | 9 ++++++--- src/diffpy/srfit/fitbase/simplerecipe.py | 3 ++- .../srfit/pdf/characteristicfunctions.py | 11 ++++++----- src/diffpy/srfit/pdf/pdfparser.py | 3 ++- src/diffpy/srfit/sas/prcalculator.py | 3 ++- src/diffpy/srfit/sas/sasparser.py | 6 ++++-- src/diffpy/srfit/sas/sasprofile.py | 3 ++- src/diffpy/srfit/structure/__init__.py | 6 +++--- src/diffpy/srfit/structure/objcrystparset.py | 9 ++++++--- src/diffpy/srfit/structure/sgconstraints.py | 3 ++- src/diffpy/srfit/util/__init__.py | 4 ++-- src/diffpy/srfit/util/argbinders.py | 3 ++- src/diffpy/srfit/util/weakrefcallable.py | 6 ++++-- tests/conftest.py | 6 ++++-- tests/test_contribution.py | 9 ++++++--- tests/test_fitrecipe.py | 10 +++++----- tests/test_objcrystparset.py | 3 ++- tests/test_profilegenerator.py | 3 ++- tests/test_sgconstraints.py | 3 ++- 34 files changed, 128 insertions(+), 74 deletions(-) diff --git a/docs/examples/debyemodel.py b/docs/examples/debyemodel.py index 758c05ef..3ec7002d 100644 --- a/docs/examples/debyemodel.py +++ b/docs/examples/debyemodel.py @@ -12,7 +12,8 @@ # See LICENSE_DANSE.txt for license information. # ######################################################################## -"""Example of fitting the Debye model to experimental Debye-Waller factors. +"""Example of fitting the Debye model to experimental Debye-Waller +factors. In this example, we build a fit recipe that uses an external function that can simulate a atomic displacement parameters using the Debye model. This serves as @@ -207,7 +208,8 @@ def main(): def debye(T, m, thetaD): - """A wrapped version of 'adps' that can handle an array of T-values.""" + """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 diff --git a/docs/examples/debyemodelII.py b/docs/examples/debyemodelII.py index 2c5602f4..5e82aaee 100644 --- a/docs/examples/debyemodelII.py +++ b/docs/examples/debyemodelII.py @@ -12,7 +12,8 @@ # See LICENSE_DANSE.txt for license information. # ######################################################################## -"""Example of fitting the Debye recipe to experimental Debye-Waller factors. +"""Example of fitting the Debye recipe to experimental Debye-Waller +factors. This is an extension of example in debyemodel.py. The recipe we create will simultaneously fit the low and high temperature parts of the experimental data diff --git a/docs/examples/npintensityII.py b/docs/examples/npintensityII.py index 44e88506..2791a1b3 100644 --- a/docs/examples/npintensityII.py +++ b/docs/examples/npintensityII.py @@ -12,7 +12,8 @@ # See LICENSE_DANSE.txt for license information. # ######################################################################## -"""Example of extracting information from multiple data sets simultaneously. +"""Example of extracting information from multiple data sets +simultaneously. This example builds on npintensitygenerator.py, and uses IntensityGenerator from that example to build a recipe that simultaneously refines two data sets diff --git a/docs/examples/nppdfsas.py b/docs/examples/nppdfsas.py index 0679e771..6626c603 100644 --- a/docs/examples/nppdfsas.py +++ b/docs/examples/nppdfsas.py @@ -38,7 +38,8 @@ def makeRecipe(ciffile, grdata, iqdata): - """Make complex-modeling recipe where I(q) and G(r) are fit simultaneously. + """Make complex-modeling recipe where I(q) and G(r) are fit + simultaneously. The fit I(q) is fed into the calculation of G(r), which provides feedback for the fit parameters of both. diff --git a/docs/examples/threedoublepeaks.py b/docs/examples/threedoublepeaks.py index 6a5b7a42..d6c70202 100644 --- a/docs/examples/threedoublepeaks.py +++ b/docs/examples/threedoublepeaks.py @@ -30,7 +30,8 @@ def makeRecipe(): - """Make a FitRecipe for fitting three double-gaussian curves to data. + """Make a FitRecipe for fitting three double-gaussian curves to + data. The separation and amplitude ratio of the double peaks follows a specific relationship. The peaks are broadend according to their diff --git a/src/diffpy/srfit/equation/builder.py b/src/diffpy/srfit/equation/builder.py index c33e0ff6..87a56b63 100644 --- a/src/diffpy/srfit/equation/builder.py +++ b/src/diffpy/srfit/equation/builder.py @@ -238,7 +238,8 @@ def registerFunction(self, name, func, argnames): return self.registerBuilder(name, opbuilder) def registerBuilder(self, name, builder): - """Register builder in this module so it can be used in makeEquation. + """Register builder in this module so it can be used in + makeEquation. If an extant builder with the given name is already registered, this will replace all instances of the old builder's literal in @@ -282,7 +283,8 @@ def deRegisterBuilder(self, name): return def wipeout(self, eq): - """Invalidate the specified equation and remove it from the factory. + """Invalidate the specified equation and remove it from the + factory. This will remove the equation from the purview of the factory and also change its formula to return NaN. This ensures that eq @@ -576,7 +578,8 @@ class ArgumentBuilder(BaseBuilder): """ def __init__(self, value=None, name=None, const=False, arg=None): - """Create an ArgumentBuilder instance, containing a new Argument. + """Create an ArgumentBuilder instance, containing a new + Argument. Parameters ---------- @@ -732,8 +735,8 @@ def getBuilder(name): def __wrap_numpy_operators(): - """Export all numpy operators as OperatorBuilder instances in the module - namespace.""" + """Export all numpy operators as OperatorBuilder instances in the + module namespace.""" for name in dir(numpy): op = getattr(numpy, name) if isinstance(op, numpy.ufunc): diff --git a/src/diffpy/srfit/equation/literals/literal.py b/src/diffpy/srfit/equation/literals/literal.py index ebdc17a9..48c48eaa 100644 --- a/src/diffpy/srfit/equation/literals/literal.py +++ b/src/diffpy/srfit/equation/literals/literal.py @@ -26,7 +26,8 @@ class Literal(Observable, LiteralABC): - """Abstract class for equation pieces, such as operators and arguments. + """Abstract class for equation pieces, such as operators and + arguments. Literal derives from Observable. See diffpy.srfit.util.observable. diff --git a/src/diffpy/srfit/equation/literals/operators.py b/src/diffpy/srfit/equation/literals/operators.py index a7863808..9b78b77c 100644 --- a/src/diffpy/srfit/equation/literals/operators.py +++ b/src/diffpy/srfit/equation/literals/operators.py @@ -141,7 +141,8 @@ def _loop_check(self, literal): class UnaryOperator(Operator): - """Abstract class for an unary operator with one input and one result. + """Abstract class for an unary operator with one input and one + result. This base class defines the `nin` and `nout` attributes. The derived concrete operator must provide the remaining abstract attributes @@ -154,7 +155,8 @@ class UnaryOperator(Operator): class BinaryOperator(Operator): - """Abstract class for a binary operator with two inputs and one result. + """Abstract class for a binary operator with two inputs and one + result. This base class defines the `nin` and `nout` attributes. The derived concrete operator must define the remaining abstract attributes @@ -359,7 +361,8 @@ def __init__(self, op): class ArrayOperator(Operator): - """Operator that will take parameters and turn them into an array.""" + """Operator that will take parameters and turn them into an + array.""" name = "array" symbol = "array" diff --git a/src/diffpy/srfit/equation/visitors/printer.py b/src/diffpy/srfit/equation/visitors/printer.py index 98cfab6a..d3aa5ee7 100644 --- a/src/diffpy/srfit/equation/visitors/printer.py +++ b/src/diffpy/srfit/equation/visitors/printer.py @@ -12,7 +12,8 @@ # See LICENSE_DANSE.txt for license information. # ############################################################################## -"""Printer visitor for printing the equation represented by a Literal tree. +"""Printer visitor for printing the equation represented by a Literal +tree. The Printer visitor creates a one-line representation of the Literal tree, which is valid as a string equivalent of the equation. diff --git a/src/diffpy/srfit/equation/visitors/swapper.py b/src/diffpy/srfit/equation/visitors/swapper.py index a6135750..c27cf85e 100644 --- a/src/diffpy/srfit/equation/visitors/swapper.py +++ b/src/diffpy/srfit/equation/visitors/swapper.py @@ -12,7 +12,8 @@ # See LICENSE_DANSE.txt for license information. # ############################################################################## -"""Swapper for replacing a Literal in an equation with another Literals.""" +"""Swapper for replacing a Literal in an equation with another +Literals.""" __all__ = ["Swapper"] @@ -20,7 +21,8 @@ class Swapper(Visitor): - """Swapper for swapping out one literal for another in a literal tree. + """Swapper for swapping out one literal for another in a literal + tree. Note that this cannot swap out a root node of a literal tree. This case must be tested for explicitly. diff --git a/src/diffpy/srfit/fitbase/fitcontribution.py b/src/diffpy/srfit/fitbase/fitcontribution.py index d6ff6ed0..21a7aed9 100644 --- a/src/diffpy/srfit/fitbase/fitcontribution.py +++ b/src/diffpy/srfit/fitbase/fitcontribution.py @@ -450,7 +450,8 @@ def residual(self): 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 diff --git a/src/diffpy/srfit/fitbase/fithook.py b/src/diffpy/srfit/fitbase/fithook.py index b5b284c5..3afa90d9 100644 --- a/src/diffpy/srfit/fitbase/fithook.py +++ b/src/diffpy/srfit/fitbase/fithook.py @@ -12,7 +12,8 @@ # See LICENSE_DANSE.txt for license information. # ############################################################################## -"""The FitHook class for inspecting the progress of a FitRecipe refinement. +"""The FitHook class for inspecting the progress of a FitRecipe +refinement. FitHooks are called by a FitRecipe during various times of the residual is evaluation. The default FitHook simply counts the number of times the @@ -54,7 +55,8 @@ def reset(self, recipe): return def precall(self, recipe): - """This is called within FitRecipe.residual, before the calculation. + """This is called within FitRecipe.residual, before the + calculation. Attributes ---------- @@ -64,7 +66,8 @@ def precall(self, recipe): return def postcall(self, recipe, chiv): - """This is called within FitRecipe.residual, after the calculation. + """This is called within FitRecipe.residual, after the + calculation. Attributes ---------- @@ -121,7 +124,8 @@ def reset(self, recipe): return def precall(self, recipe): - """This is called within FitRecipe.residual, before the calculation. + """This is called within FitRecipe.residual, before the + calculation. Attributes ---------- @@ -134,7 +138,8 @@ def precall(self, recipe): return def postcall(self, recipe, chiv): - """This is called within FitRecipe.residual, after the calculation. + """This is called within FitRecipe.residual, after the + calculation. Attributes ---------- @@ -227,7 +232,8 @@ def reset(self, recipe): return def postcall(self, recipe, chiv): - """This is called within FitRecipe.residual, after the calculation. + """This is called within FitRecipe.residual, after the + calculation. Find data and plot it. diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 72946e40..c44eb6d9 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -1278,8 +1278,8 @@ def set_plot_defaults(self, **kwargs): self.plot_options.update(kwargs) def _set_axes_labels_from_metadata(self, meta, plot_params): - """Set axes labels based on filename suffix in profile metadata if not - already set.""" + """Set axes labels based on filename suffix in profile metadata + if not already set.""" if isinstance(meta, dict): filename = meta.get("filename") if filename: @@ -1292,8 +1292,8 @@ def _set_axes_labels_from_metadata(self, meta, plot_params): return def plot_recipe(self, ax=None, return_fig=False, **kwargs): - """Plot the observed, fit, and difference curves for each contribution - of the fit recipe. + """Plot the observed, fit, and difference curves for each + contribution of the fit recipe. If the recipe has multiple contributions, a separate plot is created for each contribution. @@ -1516,7 +1516,8 @@ def _apply_values(self, p): return def _update_configuration(self): - """Notify RecipeContainers in hierarchy of configuration change.""" + """Notify RecipeContainers in hierarchy of configuration + change.""" self._ready = False return diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index dabebded..e2f2a20a 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -12,7 +12,8 @@ # See LICENSE_DANSE.txt for license information. # ############################################################################## -"""The FitResults and ContributionResults classes for storing results of a fit. +"""The FitResults and ContributionResults classes for storing results of +a fit. The FitResults class is used to display the current state of a FitRecipe. It stores the state, and uses it to calculate useful @@ -164,7 +165,8 @@ def __init__(self, recipe, update=True, showfixed=True, showcon=False): return def update(self): - """Update the results according to the current state of the recipe.""" + """Update the results according to the current state of the + recipe.""" # Note that the order of these operations are chosen to reduce # computation time. @@ -302,7 +304,8 @@ def _calculate_jacobian(self): return jac def _calculate_metrics(self): - """Calculate chi2, cumchi2, rchi2, rw and cumrw for the recipe.""" + """Calculate chi2, cumchi2, rchi2, rw and cumrw for the + recipe.""" cumchi2 = numpy.array([], dtype=float) # total weighed denominator for the ratio in the Rw formula yw2tot = 0.0 diff --git a/src/diffpy/srfit/fitbase/profileparser.py b/src/diffpy/srfit/fitbase/profileparser.py index 32cb9669..b152164b 100644 --- a/src/diffpy/srfit/fitbase/profileparser.py +++ b/src/diffpy/srfit/fitbase/profileparser.py @@ -93,7 +93,8 @@ def getFormat(self): return self._format def parseString(self, patstring): - """Parse a string and set the _x, _y, _dx, _dy and _meta variables. + """Parse a string and set the _x, _y, _dx, _dy and _meta + variables. When _dx or _dy cannot be obtained in the data format it is set to None. @@ -110,7 +111,8 @@ def parseString(self, patstring): raise NotImplementedError() def parseFile(self, filename): - """Parse a file and set the _x, _y, _dx, _dy and _meta variables. + """Parse a file and set the _x, _y, _dx, _dy and _meta + variables. This wipes out the currently loaded data and selected bank number. diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index ca7b273b..3daf5674 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -514,7 +514,8 @@ def _remove_parameter(self, par): return def registerCalculator(self, f, argnames=None): - """Register a Calculator so it can be used within equation strings. + """Register a Calculator so it can be used within equation + strings. A Calculator is an elaborate function that can organize Parameters. This creates a function with this class that can be used within string @@ -551,7 +552,8 @@ def registerCalculator(self, f, argnames=None): return eq def registerFunction(self, f, name=None, argnames=None): - """Register a function so it can be used within equation strings. + """Register a function so it can be used within equation + strings. This creates a function with this class that can be used within string equations. The resulting equation does not require the arguments to be @@ -962,7 +964,8 @@ def clearRestraints(self, recurse=False): return def _get_constraints(self, recurse=True): - """Get the constrained Parameters for this and managed sub-objects.""" + """Get the constrained Parameters for this and managed sub- + objects.""" constraints = {} if recurse: for m in filter(_has_get_constraints, self._iter_managed()): diff --git a/src/diffpy/srfit/fitbase/simplerecipe.py b/src/diffpy/srfit/fitbase/simplerecipe.py index f3789a3a..e9da1f2c 100644 --- a/src/diffpy/srfit/fitbase/simplerecipe.py +++ b/src/diffpy/srfit/fitbase/simplerecipe.py @@ -12,7 +12,8 @@ # See LICENSE_DANSE.txt for license information. # ############################################################################## -"""Simple FitRecipe class that includes a FitContribution and Profile.""" +"""Simple FitRecipe class that includes a FitContribution and +Profile.""" from diffpy.srfit.fitbase.fitcontribution import FitContribution from diffpy.srfit.fitbase.fitrecipe import FitRecipe diff --git a/src/diffpy/srfit/pdf/characteristicfunctions.py b/src/diffpy/srfit/pdf/characteristicfunctions.py index 5d2bf15e..9846e131 100644 --- a/src/diffpy/srfit/pdf/characteristicfunctions.py +++ b/src/diffpy/srfit/pdf/characteristicfunctions.py @@ -12,7 +12,8 @@ # See LICENSE_DANSE.txt for license information. # ############################################################################## -"""Form factors (characteristic functions) used in PDF nanoshape fitting. +"""Form factors (characteristic functions) used in PDF nanoshape +fitting. These are used to calculate the attenuation of the PDF due to a finite size. For a crystal-like nanoparticle, one can calculate the PDF via @@ -202,8 +203,8 @@ def spheroidalCF2(r, psize, axrat): def lognormalSphericalCF(r, psize, psig): - """Spherical nanoparticle characteristic function with lognormal size - distribution. + """Spherical nanoparticle characteristic function with lognormal + size distribution. Attributes ---------- @@ -405,8 +406,8 @@ def __init__(self, name, model): return def __call__(self, r): - """Calculate the characteristic function from the transform of the - BaseModel.""" + """Calculate the characteristic function from the transform of + the BaseModel.""" # Determine q-values. # We want very fine r-spacing so we can properly normalize f(r). This diff --git a/src/diffpy/srfit/pdf/pdfparser.py b/src/diffpy/srfit/pdf/pdfparser.py index 445835f7..f2d32ccd 100644 --- a/src/diffpy/srfit/pdf/pdfparser.py +++ b/src/diffpy/srfit/pdf/pdfparser.py @@ -109,7 +109,8 @@ class PDFParser(ProfileParser): _format = "PDF" def parseString(self, patstring): - """Parse a string and set the _x, _y, _dx, _dy and _meta variables. + """Parse a string and set the _x, _y, _dx, _dy and _meta + variables. When _dx or _dy cannot be obtained in the data format it is set to 0. diff --git a/src/diffpy/srfit/sas/prcalculator.py b/src/diffpy/srfit/sas/prcalculator.py index 17c63de6..4030aa94 100644 --- a/src/diffpy/srfit/sas/prcalculator.py +++ b/src/diffpy/srfit/sas/prcalculator.py @@ -116,7 +116,8 @@ def _inverted(self, x, c): class CFCalculator(PrCalculator): - """A class for calculating the characteristic function (CF) from data. + """A class for calculating the characteristic function (CF) from + data. This calculator produces f(r) = P(r) / 4 pi r**2 diff --git a/src/diffpy/srfit/sas/sasparser.py b/src/diffpy/srfit/sas/sasparser.py index 1ddd48b3..12583d6b 100644 --- a/src/diffpy/srfit/sas/sasparser.py +++ b/src/diffpy/srfit/sas/sasparser.py @@ -91,7 +91,8 @@ class SASParser(ProfileParser): _format = "SAS" def parseFile(self, filename): - """Parse a file and set the _x, _y, _dx, _dy and _meta variables. + """Parse a file and set the _x, _y, _dx, _dy and _meta + variables. This wipes out the currently loaded data and selected bank number. @@ -131,7 +132,8 @@ def parseFile(self, filename): return def parseString(self, patstring): - """Parse a string and set the _x, _y, _dx, _dy and _meta variables. + """Parse a string and set the _x, _y, _dx, _dy and _meta + variables. When _dx or _dy cannot be obtained in the data format it is set to 0. diff --git a/src/diffpy/srfit/sas/sasprofile.py b/src/diffpy/srfit/sas/sasprofile.py index a5ad4225..a4b313f7 100644 --- a/src/diffpy/srfit/sas/sasprofile.py +++ b/src/diffpy/srfit/sas/sasprofile.py @@ -12,7 +12,8 @@ # See LICENSE_DANSE.txt for license information. # ############################################################################## -"""Class for adapting a sas DataInfo objects to the Profile interface.""" +"""Class for adapting a sas DataInfo objects to the Profile +interface.""" __all__ = ["SASProfile"] diff --git a/src/diffpy/srfit/structure/__init__.py b/src/diffpy/srfit/structure/__init__.py index 2a34680e..f479cf50 100644 --- a/src/diffpy/srfit/structure/__init__.py +++ b/src/diffpy/srfit/structure/__init__.py @@ -12,9 +12,9 @@ # See LICENSE_DANSE.txt for license information. # ############################################################################## -"""Modules and classes that adapt structure representations to the ParameterSet -interface and automatic structure constraint generation from space group -information.""" +"""Modules and classes that adapt structure representations to the +ParameterSet interface and automatic structure constraint generation +from space group information.""" from diffpy.srfit.structure.sgconstraints import constrainAsSpaceGroup diff --git a/src/diffpy/srfit/structure/objcrystparset.py b/src/diffpy/srfit/structure/objcrystparset.py index 8cb427b9..62995ee6 100644 --- a/src/diffpy/srfit/structure/objcrystparset.py +++ b/src/diffpy/srfit/structure/objcrystparset.py @@ -12,7 +12,8 @@ # See LICENSE_DANSE.txt for license information. # ############################################################################## -"""Wrappers for adapting pyobjcryst.crystal.Crystal to a srfit ParameterSet. +"""Wrappers for adapting pyobjcryst.crystal.Crystal to a srfit +ParameterSet. This will adapt a Crystal or Molecule object from pyobjcryst into the ParameterSet interface. The following classes are adapted. @@ -335,7 +336,8 @@ def wrapRestraints(self): return def wrapStretchModeParameters(self): - """Wrap the stretch modes implicit to the Molecule as Parameters. + """Wrap the stretch modes implicit to the Molecule as + Parameters. This will wrap StretchModeBondLengths and StretchModeBondAngles of the Molecule as Parameters. Note that this requires that the MolBondAtoms @@ -1516,7 +1518,8 @@ def getValue(self): class ObjCrystDihedralAngleParameter(StretchModeParameter): - """Class for abstracting a dihedral angle in a Molecule to a Parameter. + """Class for abstracting a dihedral angle in a Molecule to a + Parameter. This wraps up a pyobjcryst.molecule.StretchModeTorsion object so that the angle defined by four MolAtoms ([a1-a2].[a3-a4]) in a Molecule can be used diff --git a/src/diffpy/srfit/structure/sgconstraints.py b/src/diffpy/srfit/structure/sgconstraints.py index c9dbc5b9..81c71de9 100644 --- a/src/diffpy/srfit/structure/sgconstraints.py +++ b/src/diffpy/srfit/structure/sgconstraints.py @@ -814,7 +814,8 @@ def _makeconstraint(parname, formula, scatterer, idx, ns={}): def _get_float(formula): - """Get a float from a formula string, or None if this is not possible.""" + """Get a float from a formula string, or None if this is not + possible.""" try: return eval(formula) except NameError: diff --git a/src/diffpy/srfit/util/__init__.py b/src/diffpy/srfit/util/__init__.py index 023b4256..c8c9b830 100644 --- a/src/diffpy/srfit/util/__init__.py +++ b/src/diffpy/srfit/util/__init__.py @@ -18,8 +18,8 @@ def sortKeyForNumericString(s): - """Compute key for sorting strings according to their integer numeric - value. + """Compute key for sorting strings according to their integer + numeric value. Each string gets split to string and integer segments to create keys for comparison. Signs, decimal points and exponents are ignored. diff --git a/src/diffpy/srfit/util/argbinders.py b/src/diffpy/srfit/util/argbinders.py index 28cd5144..71db89b4 100644 --- a/src/diffpy/srfit/util/argbinders.py +++ b/src/diffpy/srfit/util/argbinders.py @@ -16,7 +16,8 @@ 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.""" diff --git a/src/diffpy/srfit/util/weakrefcallable.py b/src/diffpy/srfit/util/weakrefcallable.py index 287d2e47..042e1812 100644 --- a/src/diffpy/srfit/util/weakrefcallable.py +++ b/src/diffpy/srfit/util/weakrefcallable.py @@ -69,7 +69,8 @@ def __init__(self, f, fallback=None): return def __call__(self, *args, **kwargs): - """Call the wrapped method if the weak-referenced object is alive. + """Call the wrapped method if the weak-referenced object is + alive. If that object does not exist and the fallback function is defined, call the fallback function instead. @@ -122,7 +123,8 @@ def __getstate__(self): 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: diff --git a/tests/conftest.py b/tests/conftest.py index 0417ad17..62a4d0e7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -90,7 +90,8 @@ def pyobjcryst_available(): @pytest.fixture(scope="session") def datafile(): - """Fixture to load a test data file from the testdata package directory.""" + """Fixture to load a test data file from the testdata package + directory.""" def _datafile(filename): return importlib.resources.files("tests.testdata").joinpath(filename) @@ -166,7 +167,8 @@ def build_recipe_one_contribution(): @pytest.fixture() def build_recipe_two_contributions(): - """Helper to build a recipe with two physically related contributions.""" + """Helper to build a recipe with two physically related + contributions.""" profile1 = Profile() x = linspace(0, pi, 50) y1 = sin(x) # amplitude=1, freq=1 diff --git a/tests/test_contribution.py b/tests/test_contribution.py index 001eee42..ef388b6b 100644 --- a/tests/test_contribution.py +++ b/tests/test_contribution.py @@ -80,7 +80,8 @@ def test_add_profile_generator(self): return def testInteraction(self): - """Test the interaction between the profile and profile generator.""" + """Test the interaction between the profile and profile + generator.""" fc = self.fitcontribution profile = self.profile gen = self.gen @@ -178,7 +179,8 @@ def test_getResidualEquation(self): 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): @@ -191,7 +193,8 @@ def test_releaseOldEquations(self): return def test_registerFunction(self): - """Ensure registered function works after second set_equation call.""" + """Ensure registered function works after second set_equation + call.""" fc = self.fitcontribution fc.registerFunction(_fsquare, name="fsquare") fc.set_equation("fsquare") diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 39af10e8..6deb1cad 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -410,9 +410,9 @@ def test_add_and_remove_parameter_set(): def test_add_contribution(capturestdout): - """Duplicated test of PrintFitHooks except addContribution method has - changed to the new add_contribution method. This is because addContribution - is deprecated. + """Duplicated test of PrintFitHooks except addContribution method + has changed to the new add_contribution method. This is because + addContribution is deprecated. Remove this test after addContribution is removed and update testPrintFitHook to use add_contribution instead of addContribution. @@ -570,8 +570,8 @@ def build_recipe_from_datafile(datafile): def build_recipe_from_datafile_deprecated(datafile): - """Duplicate of build_recipe_from_datafile to use deprecated loadParsedData - method. + """Duplicate of build_recipe_from_datafile to use deprecated + loadParsedData method. Remove in version 4.0.0. """ diff --git a/tests/test_objcrystparset.py b/tests/test_objcrystparset.py index 5150ae54..10c96ee9 100644 --- a/tests/test_objcrystparset.py +++ b/tests/test_objcrystparset.py @@ -650,7 +650,8 @@ def sgsEquivalent(self, sg1, sg2): # FIXME: only about 50% of the spacegroups pass the assertion # test disabled even if cctbx is installed def xtestCreateSpaceGroup(self): - """Check all sgtbx space groups for proper conversion to SpaceGroup.""" + """Check all sgtbx space groups for proper conversion to + SpaceGroup.""" try: from cctbx import sgtbx diff --git a/tests/test_profilegenerator.py b/tests/test_profilegenerator.py index aeacf690..e4ea0fa3 100644 --- a/tests/test_profilegenerator.py +++ b/tests/test_profilegenerator.py @@ -48,7 +48,8 @@ def testOperation(self): return def testUpdate(self): - """Update and change the profile to make sure generator is flushed.""" + """Update and change the profile to make sure generator is + flushed.""" gen = self.gen prof = self.profile diff --git a/tests/test_sgconstraints.py b/tests/test_sgconstraints.py index 4288e530..11859a9f 100644 --- a/tests/test_sgconstraints.py +++ b/tests/test_sgconstraints.py @@ -179,7 +179,8 @@ def _alltests(par): def test_constrain_as_space_group_args(pyobjcryst_available, datafile): - """Test the arguments processing of constrainAsSpaceGroup function.""" + """Test the arguments processing of constrainAsSpaceGroup + function.""" if not pyobjcryst_available: pytest.skip("pyobjcrysta package not available") From 3233b7324cb93e57fc8f15c2c7e9b61b38dcab80 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 14:59:13 -0500 Subject: [PATCH 099/193] resultsDictionary deprecation, added to FitResults --- src/diffpy/srfit/fitbase/fitresults.py | 42 +++++++++++++++++++++++++- tests/test_fitresults.py | 19 ++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index dabebded..d1627fa3 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -57,6 +57,14 @@ removal_version, ) +resultsDictionary_dep_msg = build_deprecation_message( + "diffpy.srfit.fitbase", + "resultsDictionary", + "get_results_dictionary", + removal_version, + new_base="diffpy.srfit.fitbase.FitResults", +) + class FitResults(object): """Class for processing, presenting and storing results of a fit. @@ -619,6 +627,31 @@ def saveResults(self, filename, header="", footer="", update=False): self.save_results(filename, header, footer, update) return + def get_results_dictionary(self): + """Get a dictionary of results, with variable names and values, and + overall metrics. + + Returns + ------- + results_dict : dict + A dictionary containing the variable names and values, and overall + metrics, from the FitResults. + """ + parameter_names = self.varnames + parameter_values = self.varvals + results_dict = dict(zip(parameter_names, parameter_values)) + results_dict.update( + { + "Residual": self.residual, + "Contributions": self.residual - self.penalty, + "Restraints": self.penalty, + "Chi2": self.chi2, + "Reduced Chi2": self.rchi2, + "Rw": self.rw, + } + ) + return results_dict + # End class FitResults @@ -750,8 +783,15 @@ def _calculate_metrics(self): # End class ContributionResults +@deprecated(resultsDictionary_dep_msg) def resultsDictionary(results): - """Get dictionary of results from file. + """**This function has been deprecated and will be** **removed in version + 4.0.0.** + + **Please use** + **diffpy.srfit.fitbase.FitResults.get_results_dictionary instead.** + + Get dictionary of results from file. This reads the results from file and stores them in a dictionary to be returned to the caller. The dictionary may contain non-result entries. diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index 761a30ff..98ae1869 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -138,6 +138,25 @@ def test_save_results(build_recipe_one_contribution, tmp_path): assert expected_var in actual_results.strip() +def test_get_results_dictionary(build_recipe_one_contribution): + recipe = build_recipe_one_contribution + optimize_recipe(recipe) + results = FitResults(recipe) + actual_results_dict = results.get_results_dictionary() + expected_metrics = [ + "Residual", + "Contributions", + "Restraints", + "Chi2", + "Reduced Chi2", + "Rw", + ] + for expected_metric in expected_metrics: + assert expected_metric in actual_results_dict + for expected_var in expected_refined_variables: + assert expected_var in actual_results_dict + + def testInitializeFromFileName(datafile): recipe = FitRecipe("recipe") recipe.create_new_variable("A", 0) From 7f6555745568841402905ef43b134fa14a82779d Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 15:00:53 -0500 Subject: [PATCH 100/193] news --- news/res-dict.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/res-dict.rst diff --git a/news/res-dict.rst b/news/res-dict.rst new file mode 100644 index 00000000..6ebe11fc --- /dev/null +++ b/news/res-dict.rst @@ -0,0 +1,23 @@ +**Added:** + +* Added ``FitResults.get_results_dictionary`` in replace of ``resultsDictionary``. + +**Changed:** + +* + +**Deprecated:** + +* Deprecated ``resultsDictionary`` for removal in 4.0.0. + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From ca47352b32cee7430d7825fc03ae081e28dc1518 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 15:20:02 -0500 Subject: [PATCH 101/193] test for resultsDictionary --- tests/conftest.py | 28 ++++++++++++++++++++++++++++ tests/test_fitresults.py | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 0417ad17..61bfa490 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -223,4 +223,32 @@ def temp_data_files(tmp_path): cgr_file = tmp_path / "cgr_file.cgr" cgr_file.write_text("1.0 2.0\n" "1.1 2.1\n" "1.2 2.2\n") + + results_file = tmp_path / "fit_results.res" + results_file.write_text( + """ +Results written: Wed Feb 25 15:14:58 2026 +produced by cadenmyers + +Some quantities invalid due to missing profile uncertainty +Overall (Chi2 and Reduced Chi2 invalid) +------------------------------------------------------------------------------ +Residual 0.00000000 +Contributions 0.00000000 +Restraints 0.00000000 +Chi2 0.00000000 +Reduced Chi2 0.00000000 +Rw 0.00000000 + +Variables (Uncertainties invalid) +------------------------------------------------------------------------------ +amplitude 1.00000000e+00 +/- 4.82804000e-01 +phase_shift -1.61291146e-18 +/- 1.00000000e+00 +wave_number 1.00000000e+00 +/- 2.17496687e-01 + +Variable Correlations greater than 25% (Correlations invalid) +------------------------------------------------------------------------------ +No correlations greater than 25% +""" + ) yield tmp_path diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index 98ae1869..354b66f7 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -16,11 +16,16 @@ import unittest +import numpy as np import pytest from scipy.optimize import leastsq from diffpy.srfit.fitbase.fitrecipe import FitRecipe -from diffpy.srfit.fitbase.fitresults import FitResults, initializeRecipe +from diffpy.srfit.fitbase.fitresults import ( + FitResults, + initializeRecipe, + resultsDictionary, +) # The fit results from the recipe fixture in conftest.py expected_fitresults = """\ @@ -157,6 +162,39 @@ def test_get_results_dictionary(build_recipe_one_contribution): assert expected_var in actual_results_dict +def test_resultsDictionary(temp_data_files): + actual_results_dict = resultsDictionary( + temp_data_files / "fit_results.res" + ) + # bad behavior: values are stored as strings + expected_results_dict = { + "than": "25", # bad behavior: shouldn't be here + "wave_number": "1.00000000e+00", + "phase_shift": "-1.61291146e-18", + "amplitude": "1.00000000e+00", + "Rw": "0.00000000", + "Chi2": "0.00000000", + "Restraints": "0.00000000", + "Contributions": "0.00000000", + "Residual": "0.00000000", + "Feb": "25", # bad behavior: shouldn't be here + } + # convert values to float for comparison (with rounding) + for key in expected_results_dict: + expected_results_dict[key] = float(expected_results_dict[key]) + for key in actual_results_dict: + actual_results_dict[key] = float(actual_results_dict[key]) + + actual_keys = set(actual_results_dict.keys()) + actual_values = np.round(np.array(list(actual_results_dict.values())), 5) + expected_keys = set(expected_results_dict.keys()) + expected_values = np.round( + np.array(list(expected_results_dict.values())), 5 + ) + assert expected_keys == actual_keys + assert list(expected_values == list(actual_values)) + + def testInitializeFromFileName(datafile): recipe = FitRecipe("recipe") recipe.create_new_variable("A", 0) From 1dad4560ea937877ae4698f4058a2654d59203bd Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 15:27:02 -0500 Subject: [PATCH 102/193] improve test --- tests/test_fitresults.py | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index 354b66f7..45ac9a63 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -147,19 +147,27 @@ def test_get_results_dictionary(build_recipe_one_contribution): recipe = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) + results.print_results() actual_results_dict = results.get_results_dictionary() - expected_metrics = [ - "Residual", - "Contributions", - "Restraints", - "Chi2", - "Reduced Chi2", - "Rw", - ] - for expected_metric in expected_metrics: - assert expected_metric in actual_results_dict - for expected_var in expected_refined_variables: - assert expected_var in actual_results_dict + expected_results_dict = { + "amplitude": 1.000000000060171, + "wave_number": 1.00000000012548, + "phase_shift": -1.6129114631049646e-18, + "Residual": 3.3284672708760557e-19, + "Contributions": 3.3284672708760557e-19, + "Restraints": 0, + "Chi2": 3.3284672708760557e-19, + "Reduced Chi2": 4.7549532441086507e-20, + "Rw": 2.7196679825449506e-10, + } + actual_values = np.round(np.array(list(actual_results_dict.values())), 5) + actual_keys = set(actual_results_dict.keys()) + expected_values = np.round( + np.array(list(expected_results_dict.values())), 5 + ) + expected_keys = set(expected_results_dict.keys()) + assert expected_keys == actual_keys + assert list(expected_values == list(actual_values)) def test_resultsDictionary(temp_data_files): From fc672df34cc7894b78166c72b7e8349252640e11 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 15:30:59 -0500 Subject: [PATCH 103/193] add comments describing tests --- tests/test_fitresults.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index 45ac9a63..b9fb7492 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -144,10 +144,11 @@ def test_save_results(build_recipe_one_contribution, tmp_path): def test_get_results_dictionary(build_recipe_one_contribution): + # Case: user gets results dictionary after optimization + # expected: results dictionary contains expected keys and values recipe = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) - results.print_results() actual_results_dict = results.get_results_dictionary() expected_results_dict = { "amplitude": 1.000000000060171, @@ -171,6 +172,8 @@ def test_get_results_dictionary(build_recipe_one_contribution): def test_resultsDictionary(temp_data_files): + # Case: user gets results dictionary from a results file + # expected: results dictionary contains expected keys and values actual_results_dict = resultsDictionary( temp_data_files / "fit_results.res" ) From e46399686741815b6816c23f70e147169e91c81e Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 15:38:18 -0500 Subject: [PATCH 104/193] rm merge-to-main duplicate workflow --- .../matrix-and-codecov-on-merge-to-main.yml | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 .github/workflows/matrix-and-codecov-on-merge-to-main.yml diff --git a/.github/workflows/matrix-and-codecov-on-merge-to-main.yml b/.github/workflows/matrix-and-codecov-on-merge-to-main.yml deleted file mode 100644 index 2bd09ede..00000000 --- a/.github/workflows/matrix-and-codecov-on-merge-to-main.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: CI - -on: - release: - types: - - prereleased - - published - workflow_dispatch: - -jobs: - matrix-coverage: - uses: scikit-package/release-scripts/.github/workflows/_matrix-and-codecov-on-merge-to-main.yml@v0 - with: - project: diffpy.srfit - c_extension: false - headless: false - secrets: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From a8334332e1c9be33ef4267f7bbbbacda71514f04 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 15:39:42 -0500 Subject: [PATCH 105/193] add __init__ header to README --- README.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.rst b/README.rst index 00bd1dd2..be8a91e4 100644 --- a/README.rst +++ b/README.rst @@ -63,6 +63,23 @@ obtain the total cost function. Additionally, diffpy.srfit is designed to be extensible, allowing the user to integrate external calculators to perform co-refinements with other techniques. + +SrFit has tools for coherently combining known information about a +material to derive other properties, in particular material structure. +SrFit allows the customization and creation of structure +representations, profile calculators, constraints, restraints and file +input parsers. The customized pieces can be glued together within SrFit +to optimize a structure, or other physically relevant information from +one or more experimental profiles. Other known information about the +system of interest can be included with arbitrarily complex constraints +and restraints. In this way, the end user creates a customized fitting +application that suits the problem to the available information. + +The subpackages herein define various pieces of the SrFit framework. +Developers are encouraged to work through the examples described in the +documentation to learn how to use and customize the various parts of +SrFit. + For more information about the diffpy.srfit library, please consult our `online documentation `_. Citation From dd9fca8fe736dfd0c674694b3747f856d4cd4009 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 25 Feb 2026 15:53:11 -0500 Subject: [PATCH 106/193] pull PR to list branch to fix docformatter failure --- news/res-dict.rst | 23 +++++++++ src/diffpy/srfit/fitbase/fitresults.py | 42 +++++++++++++++- tests/conftest.py | 28 +++++++++++ tests/test_fitresults.py | 70 +++++++++++++++++++++++++- 4 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 news/res-dict.rst diff --git a/news/res-dict.rst b/news/res-dict.rst new file mode 100644 index 00000000..6ebe11fc --- /dev/null +++ b/news/res-dict.rst @@ -0,0 +1,23 @@ +**Added:** + +* Added ``FitResults.get_results_dictionary`` in replace of ``resultsDictionary``. + +**Changed:** + +* + +**Deprecated:** + +* Deprecated ``resultsDictionary`` for removal in 4.0.0. + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index e2f2a20a..c154d018 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -58,6 +58,14 @@ removal_version, ) +resultsDictionary_dep_msg = build_deprecation_message( + "diffpy.srfit.fitbase", + "resultsDictionary", + "get_results_dictionary", + removal_version, + new_base="diffpy.srfit.fitbase.FitResults", +) + class FitResults(object): """Class for processing, presenting and storing results of a fit. @@ -622,6 +630,31 @@ def saveResults(self, filename, header="", footer="", update=False): self.save_results(filename, header, footer, update) return + def get_results_dictionary(self): + """Get a dictionary of results, with variable names and values, + and overall metrics. + + Returns + ------- + results_dict : dict + A dictionary containing the variable names and values, and overall + metrics, from the FitResults. + """ + parameter_names = self.varnames + parameter_values = self.varvals + results_dict = dict(zip(parameter_names, parameter_values)) + results_dict.update( + { + "Residual": self.residual, + "Contributions": self.residual - self.penalty, + "Restraints": self.penalty, + "Chi2": self.chi2, + "Reduced Chi2": self.rchi2, + "Rw": self.rw, + } + ) + return results_dict + # End class FitResults @@ -753,8 +786,15 @@ def _calculate_metrics(self): # End class ContributionResults +@deprecated(resultsDictionary_dep_msg) def resultsDictionary(results): - """Get dictionary of results from file. + """**This function has been deprecated and will be** **removed in version + 4.0.0.** + + **Please use** + **diffpy.srfit.fitbase.FitResults.get_results_dictionary instead.** + + Get dictionary of results from file. This reads the results from file and stores them in a dictionary to be returned to the caller. The dictionary may contain non-result entries. diff --git a/tests/conftest.py b/tests/conftest.py index 62a4d0e7..45c6308a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -225,4 +225,32 @@ def temp_data_files(tmp_path): cgr_file = tmp_path / "cgr_file.cgr" cgr_file.write_text("1.0 2.0\n" "1.1 2.1\n" "1.2 2.2\n") + + results_file = tmp_path / "fit_results.res" + results_file.write_text( + """ +Results written: Wed Feb 25 15:14:58 2026 +produced by cadenmyers + +Some quantities invalid due to missing profile uncertainty +Overall (Chi2 and Reduced Chi2 invalid) +------------------------------------------------------------------------------ +Residual 0.00000000 +Contributions 0.00000000 +Restraints 0.00000000 +Chi2 0.00000000 +Reduced Chi2 0.00000000 +Rw 0.00000000 + +Variables (Uncertainties invalid) +------------------------------------------------------------------------------ +amplitude 1.00000000e+00 +/- 4.82804000e-01 +phase_shift -1.61291146e-18 +/- 1.00000000e+00 +wave_number 1.00000000e+00 +/- 2.17496687e-01 + +Variable Correlations greater than 25% (Correlations invalid) +------------------------------------------------------------------------------ +No correlations greater than 25% +""" + ) yield tmp_path diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index 761a30ff..b9fb7492 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -16,11 +16,16 @@ import unittest +import numpy as np import pytest from scipy.optimize import leastsq from diffpy.srfit.fitbase.fitrecipe import FitRecipe -from diffpy.srfit.fitbase.fitresults import FitResults, initializeRecipe +from diffpy.srfit.fitbase.fitresults import ( + FitResults, + initializeRecipe, + resultsDictionary, +) # The fit results from the recipe fixture in conftest.py expected_fitresults = """\ @@ -138,6 +143,69 @@ def test_save_results(build_recipe_one_contribution, tmp_path): assert expected_var in actual_results.strip() +def test_get_results_dictionary(build_recipe_one_contribution): + # Case: user gets results dictionary after optimization + # expected: results dictionary contains expected keys and values + recipe = build_recipe_one_contribution + optimize_recipe(recipe) + results = FitResults(recipe) + actual_results_dict = results.get_results_dictionary() + expected_results_dict = { + "amplitude": 1.000000000060171, + "wave_number": 1.00000000012548, + "phase_shift": -1.6129114631049646e-18, + "Residual": 3.3284672708760557e-19, + "Contributions": 3.3284672708760557e-19, + "Restraints": 0, + "Chi2": 3.3284672708760557e-19, + "Reduced Chi2": 4.7549532441086507e-20, + "Rw": 2.7196679825449506e-10, + } + actual_values = np.round(np.array(list(actual_results_dict.values())), 5) + actual_keys = set(actual_results_dict.keys()) + expected_values = np.round( + np.array(list(expected_results_dict.values())), 5 + ) + expected_keys = set(expected_results_dict.keys()) + assert expected_keys == actual_keys + assert list(expected_values == list(actual_values)) + + +def test_resultsDictionary(temp_data_files): + # Case: user gets results dictionary from a results file + # expected: results dictionary contains expected keys and values + actual_results_dict = resultsDictionary( + temp_data_files / "fit_results.res" + ) + # bad behavior: values are stored as strings + expected_results_dict = { + "than": "25", # bad behavior: shouldn't be here + "wave_number": "1.00000000e+00", + "phase_shift": "-1.61291146e-18", + "amplitude": "1.00000000e+00", + "Rw": "0.00000000", + "Chi2": "0.00000000", + "Restraints": "0.00000000", + "Contributions": "0.00000000", + "Residual": "0.00000000", + "Feb": "25", # bad behavior: shouldn't be here + } + # convert values to float for comparison (with rounding) + for key in expected_results_dict: + expected_results_dict[key] = float(expected_results_dict[key]) + for key in actual_results_dict: + actual_results_dict[key] = float(actual_results_dict[key]) + + actual_keys = set(actual_results_dict.keys()) + actual_values = np.round(np.array(list(actual_results_dict.values())), 5) + expected_keys = set(expected_results_dict.keys()) + expected_values = np.round( + np.array(list(expected_results_dict.values())), 5 + ) + assert expected_keys == actual_keys + assert list(expected_values == list(actual_values)) + + def testInitializeFromFileName(datafile): recipe = FitRecipe("recipe") recipe.create_new_variable("A", 0) From cee67de0e4fa061e1e35449e54f458ef3fbe830f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 25 Feb 2026 20:56:14 +0000 Subject: [PATCH 107/193] [pre-commit.ci] auto fixes from pre-commit hooks --- src/diffpy/srfit/fitbase/fitresults.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index 9812112c..c154d018 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -631,8 +631,8 @@ def saveResults(self, filename, header="", footer="", update=False): return def get_results_dictionary(self): - """Get a dictionary of results, with variable names and values, and - overall metrics. + """Get a dictionary of results, with variable names and values, + and overall metrics. Returns ------- From 698842eadb04d7a9c8381542a640906f69141c3b Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 14:35:31 -0500 Subject: [PATCH 108/193] fix conftest fixture so it creates new recipe object on each call --- tests/conftest.py | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 45c6308a..411f70dc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -150,19 +150,23 @@ def _capturestdout(f, *args, **kwargs): @pytest.fixture() def build_recipe_one_contribution(): "helper to build a simple recipe" - profile = Profile() - x = linspace(0, pi, 10) - y = sin(x) - profile.set_observed_profile(x, y) - contribution = FitContribution("c1") - contribution.set_profile(profile) - contribution.set_equation("amplitude*sin(wave_number*x + phase_shift)") - recipe = FitRecipe() - recipe.add_contribution(contribution) - recipe.add_variable(contribution.amplitude, 1) - recipe.add_variable(contribution.wave_number, 1) - recipe.add_variable(contribution.phase_shift, 1) - return recipe + + def _build_recipe(): + profile = Profile() + x = linspace(0, pi, 10) + y = sin(x) + profile.set_observed_profile(x, y) + contribution = FitContribution("c1") + contribution.set_profile(profile) + contribution.set_equation("amplitude*sin(wave_number*x + phase_shift)") + recipe = FitRecipe() + recipe.add_contribution(contribution) + recipe.add_variable(contribution.amplitude, 1) + recipe.add_variable(contribution.wave_number, 1) + recipe.add_variable(contribution.phase_shift, 1) + return recipe + + return _build_recipe @pytest.fixture() From 12ee91c51cc0de38f63e5376754693bfbf7b4a7c Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 14:43:43 -0500 Subject: [PATCH 109/193] update fixture initial values to be more different --- tests/conftest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 411f70dc..6b5b39c7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -161,9 +161,9 @@ def _build_recipe(): contribution.set_equation("amplitude*sin(wave_number*x + phase_shift)") recipe = FitRecipe() recipe.add_contribution(contribution) - recipe.add_variable(contribution.amplitude, 1) - recipe.add_variable(contribution.wave_number, 1) - recipe.add_variable(contribution.phase_shift, 1) + recipe.add_variable(contribution.amplitude, 4) + recipe.add_variable(contribution.wave_number, 3) + recipe.add_variable(contribution.phase_shift, 2) return recipe return _build_recipe From 0d6e1beedc9a21ad138b408b2c772d582a81207f Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 14:48:46 -0500 Subject: [PATCH 110/193] update expected to accound for the slight difference now --- tests/test_fitresults.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index b9fb7492..4a2fde67 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -38,10 +38,7 @@ Restraints 0.00000000 Chi2 0.00000000 Reduced Chi2 0.00000000 -Rw 0.00000000 - -Variables (Uncertainties invalid) ------------------------------------------------------------------------------- +Rw 0.00000007 """ expected_refined_variables = ["amplitude", "wave_number", "phase_shift"] @@ -54,9 +51,10 @@ def optimize_recipe(recipe): def test_formatResults(build_recipe_one_contribution): - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) results = FitResults(recipe) + results.save_results("res.res") actual_results_string = results.formatResults(header="My Custom header") # Because slight variations in refinement, just check # that the header of the results are the same. @@ -67,7 +65,7 @@ def test_formatResults(build_recipe_one_contribution): def test_get_results_string(build_recipe_one_contribution): - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) results = FitResults(recipe) actual_results_string = results.get_results_string( @@ -82,7 +80,7 @@ def test_get_results_string(build_recipe_one_contribution): def test_printResults(build_recipe_one_contribution, capsys): - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) results = FitResults(recipe) results.printResults(header="My Custom header") @@ -96,7 +94,7 @@ def test_printResults(build_recipe_one_contribution, capsys): def test_print_results(build_recipe_one_contribution, capsys): - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) results = FitResults(recipe) results.print_results(header="My Custom header") @@ -110,7 +108,7 @@ def test_print_results(build_recipe_one_contribution, capsys): def test_saveResults(build_recipe_one_contribution, tmp_path): - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) results = FitResults(recipe) actual_results_file = tmp_path / "fit_results.txt" @@ -127,7 +125,7 @@ def test_saveResults(build_recipe_one_contribution, tmp_path): def test_save_results(build_recipe_one_contribution, tmp_path): - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) results = FitResults(recipe) actual_results_file = tmp_path / "fit_results.txt" @@ -146,7 +144,7 @@ def test_save_results(build_recipe_one_contribution, tmp_path): def test_get_results_dictionary(build_recipe_one_contribution): # Case: user gets results dictionary after optimization # expected: results dictionary contains expected keys and values - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) results = FitResults(recipe) actual_results_dict = results.get_results_dictionary() From 474b32e6169c3fcc40e004483dffe0f2e9fab3d4 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 15:23:33 -0500 Subject: [PATCH 111/193] feat: initialize FitRecipe from a results file or object --- src/diffpy/srfit/fitbase/fitrecipe.py | 70 +++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index c44eb6d9..ca3d34a8 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -35,11 +35,13 @@ __all__ = ["FitRecipe"] from collections import OrderedDict +from pathlib import Path import matplotlib.pyplot as plt from bg_mpl_stylesheets.styles import all_styles from numpy import array, concatenate, dot, sqrt +import diffpy.srfit.util.inpututils as utils from diffpy.srfit.fitbase.fithook import PrintFitHook from diffpy.srfit.fitbase.parameter import ParameterProxy from diffpy.srfit.fitbase.recipeorganizer import RecipeOrganizer @@ -1184,6 +1186,74 @@ def initialize_recipe_with_recipe(self, recipe_object): if restraint not in self._restraints: self._restraints.add(restraint) + def _pretty_print_results_dict(self, params_dict): + """Pretty print a dictionary of parameter names and values.""" + sorted_params = sorted(params_dict.items()) + width = max(len(name) for name, _ in sorted_params) + for name, value in sorted_params: + if isinstance(value, float): + value_str = f"{value:.6g}" + else: + value_str = str(value) + print(f" {name:<{width}} = {value_str}") + + def _set_parameters_from_dict(self, params_dict): + """Set the parameters of the FitRecipe from a dictionary of + parameter names and values.""" + for param_name, param_value in params_dict.items(): + if param_name in self._parameters: + self._parameters[param_name].setValue(param_value) + else: + print( + f"Warning: Parameter '{param_name}' from results " + "not found in FitRecipe and will be ignored." + ) + + def initialize_recipe_with_results(self, results, verbose=True): + """Initialize a FitRecipe with a FitResults object or a results + file. + + Note that at least one FitContribution must already exist in + the FitRecipe. + + Parameters + ---------- + results : FitResults, pathlib.Path, or str + The FitResults object or path to results file to initialize with. + verbose : bool, optional + If True, print warnings for any parameters in the results that are + not in the FitRecipe. Default is True. + + Raises + ------ + ValueError + If the input results is not a FitResults object or a path to a + results file. + """ + if hasattr(results, "print_results"): + params_dict = utils.get_dict_from_results_object(results) + elif isinstance(results, (str, Path)): + params_dict = utils.get_dict_from_results_file(results) + else: + raise ValueError( + "The input results must be a FitResults object or a path to a " + f"results file, but got {type(results)}." + ) + self._set_parameters_from_dict(params_dict) + if verbose: + print() + print("Parameters found in Results:") + print("=" * 30) + self._pretty_print_results_dict(params_dict) + print() + print("Parameters set in FitRecipe:") + print("=" * 30) + set_parameters_dict = { + param.name: param.getValue() + for param in self._parameters.values() + } + self._pretty_print_results_dict(set_parameters_dict) + def set_plot_defaults(self, **kwargs): """Set default plotting options for all future plots. From 96ac076387ed6a0253460e204e7c90199fec627d Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 15:24:22 -0500 Subject: [PATCH 112/193] test: tests for the new feature --- tests/test_fitrecipe.py | 132 +++++++++++++++++++++++++++++++++++----- 1 file changed, 118 insertions(+), 14 deletions(-) diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 6deb1cad..21ce1113 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -527,11 +527,115 @@ def test_initialize_recipe_from_recipe_bad(build_recipe_two_contributions): recipe2.initialize_recipe_with_recipe(recipe_bad) -# def test_initialize_recipe_from_results(build_recipe_one_contribution): -# # Case: User initializes a FitRecipe from a FitResults object or -# # results file -# # expected: recipe is initialized with variables from previous fit -# assert False +def test_initialize_recipe_from_results_object(build_recipe_one_contribution): + # Case: User initializes a FitRecipe from a FitResults object + # expected: recipe is initialized with variables from previous fit + recipe1 = build_recipe_one_contribution() + optimize_recipe(recipe1) + results1 = FitResults(recipe1) + expected_values = np.round(results1.varvals, 5) + expected_names = results1.varnames + + recipe2 = build_recipe_one_contribution() + recipe2.create_new_variable( + "extra_var", 5 + ) # should be included in the initialized recipe + actual_values_before_init = [val for val in recipe2.get_values()] + actual_names_before_init = recipe2.get_names() + expected_names_before_init = [ + "amplitude", + "extra_var", + "phase_shift", + "wave_number", + ] + expected_values_before_init = [ + 4, + 3, + 2, + 5, + ] # the three variables + the extra_var + + assert actual_values_before_init == expected_values_before_init + assert sorted(actual_names_before_init) == sorted( + expected_names_before_init + ) + + recipe2.initialize_recipe_with_results(results1) + optimize_recipe(recipe2) + results2 = FitResults(recipe2) + actual_values = np.round(results2.varvals, 5) + actual_names = results2.varnames + + expected_names = expected_names + [ + "extra_var" + ] # add the new variable name to expected names + expected_values = list(expected_values) + [ + 5 + ] # add the value of the new variable to expected values + assert sorted(expected_names) == sorted(actual_names) + assert sorted(expected_values) == sorted(list(actual_values)) + + +def test_initialize_recipe_from_results_file( + build_recipe_one_contribution, temp_data_files +): + # Case: User initializes a FitRecipe from a FitResults file + # expected: recipe is initialized with variables from previous fit + results_file = temp_data_files / "fit_results.res" + expected_names = ["amplitude", "phase_shift", "wave_number"] + expected_values = [1, 1, 0] + + recipe = build_recipe_one_contribution() + recipe.initialize_recipe_with_results(results_file) + results = FitResults(recipe) + actual_values = np.round(results.varvals, 5) + actual_names = results.varnames + + assert sorted(expected_names) == sorted(actual_names) + assert list(expected_values) == list(actual_values) + + +def test_initialize_recipe_from_results_file_bad( + build_recipe_one_contribution, +): + # Case: User tries to initialize a recipe with something that + # isn't a path, str, or FitResults object + # Expected: raised ValueError with message + recipe = build_recipe_one_contribution() + bad_input = 12345 # not a valid input type + msg = ( + "The input results must be a FitResults object or a path to a " + "results file, but got ." + ) + with pytest.raises(ValueError, match=msg): + recipe.initialize_recipe_with_results(bad_input) + + +def test_initialize_recipe_from_results_file_wrong( + build_recipe_two_contributions, temp_data_files, capsys +): + # Case: User tries to initialize a FitRecipe from a results file + # that does not match params in the recipe + # expected: Warning message is printed and things proceed as + # usual with the variables in the recipe + + results_file_from_single_contrib = temp_data_files / "fit_results.res" + recipe = build_recipe_two_contributions + recipe.initialize_recipe_with_results(results_file_from_single_contrib) + captured = capsys.readouterr() + actual_print_msg = captured.out # .strip() + + results_file_param_names = ["amplitude", "phase_shift", "wave_number"] + expected_print_messages = [] + for param_name in results_file_param_names: + msg = ( + f"Warning: Parameter '{param_name}' from results not found " + "in FitRecipe and will be ignored." + ) + expected_print_messages.append(msg) + + for expected_print_msg in expected_print_messages: + assert expected_print_msg in actual_print_msg def get_labels_and_linecount(ax): @@ -591,7 +695,7 @@ def build_recipe_from_datafile_deprecated(datafile): def test_plot_recipe_bad_display(build_recipe_one_contribution): - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() # Case: All plots are disabled # expected: raised ValueError with message plt.close("all") @@ -621,7 +725,7 @@ def test_plot_recipe_before_refinement(capsys, build_recipe_one_contribution): # Case: User tries to plot recipe before refinement # expected: Data plotted without fit line or difference curve # and warning message printed - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() plt.close("all") before = set(plt.get_fignums()) # include fit_label="nothing" to make sure fit line is not plotted @@ -649,7 +753,7 @@ def test_plot_recipe_before_refinement(capsys, build_recipe_one_contribution): def test_plot_recipe_after_refinement(build_recipe_one_contribution): # Case: User refines recipe and then plots # expected: Plot generates with no problem - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) plt.close("all") before = set(plt.get_fignums()) @@ -686,7 +790,7 @@ def test_plot_recipe_two_contributions(build_recipe_two_contributions): def test_plot_recipe_on_existing_plot(build_recipe_one_contribution): # Case: User passes axes to plot_recipe to plot on existing figure # expected: User modifications are present in the final figure - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) plt.close("all") fig, ax = plt.subplots() @@ -706,7 +810,7 @@ def test_plot_recipe_on_existing_plot(build_recipe_one_contribution): def test_plot_recipe_add_new_data(build_recipe_one_contribution): # Case: User wants to add data to figure generated by plot_recipe # Expected: New data is added to existing figure (check with labels) - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) plt.close("all") before = set(plt.get_fignums()) @@ -750,7 +854,7 @@ def test_plot_recipe_add_new_data_two_figs(build_recipe_two_contributions): def test_plot_recipe_set_title(build_recipe_one_contribution): # Case: User sets title via plot_recipe # Expected: Title is set correctly - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) plt.close("all") expected_title = "Custom Recipe Title" @@ -764,7 +868,7 @@ def test_plot_recipe_set_title(build_recipe_one_contribution): def test_plot_recipe_set_defaults(build_recipe_one_contribution): # Case: user sets default plot options with set_plot_defaults # Expected: plot_recipe uses the default options for all calls - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) plt.close("all") # set new defaults @@ -792,7 +896,7 @@ def test_plot_recipe_set_defaults(build_recipe_one_contribution): def test_plot_recipe_set_defaults_bad(capsys, build_recipe_one_contribution): # Case: user tries to set kwargs that are not valid plot_recipe options # Expected: Plot is shown and warning is printed - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) plt.close("all") recipe.set_plot_defaults( @@ -902,7 +1006,7 @@ def test_plot_recipe_reset_all_defaults(build_recipe_one_contribution): "show": True, } - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) plt.close("all") From 66a658d4255a39d8090d91284976e1f7adddbf33 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 15:24:57 -0500 Subject: [PATCH 113/193] add utils objects to get dict from results object or file --- src/diffpy/srfit/util/inpututils.py | 62 +++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/diffpy/srfit/util/inpututils.py b/src/diffpy/srfit/util/inpututils.py index b5dfa2ac..9eb2e067 100644 --- a/src/diffpy/srfit/util/inpututils.py +++ b/src/diffpy/srfit/util/inpututils.py @@ -17,6 +17,7 @@ __all__ = ["inputToString"] import os.path +from pathlib import Path def inputToString(input): @@ -51,4 +52,65 @@ def inputToString(input): return inptstr +def get_dict_from_results_file( + results_filepath: Path | str, +) -> dict[str, float]: + """Get a dictionary of parameter names and values from a results + file. + + The file should have lines in the format: + "parameter_name value +/- uncertainty". Lines that do not match this + format will be ignored. + + Parameters + ---------- + results_filepath : pathlib.Path or str + The path to the results file. + + Returns + ------- + parsed_results_dict : dict + The dictionary where keys are parameter names and values are the + corresponding parameter values as floats. + """ + with open(results_filepath, "r") as f: + results_string = f.read() + parsed_results_dict = {} + for raw_line in results_string.splitlines(): + line = raw_line.strip() + # skip blank lines and lines that are just dashes + if not line or set(line) == {"-"}: + continue + line_items = line.split() + if len(line_items) < 2: + continue + if len(line_items) >= 4 and line_items[2] == "+/-": + try: + parsed_results_dict[line_items[0]] = float(line_items[1]) + except ValueError: + pass + return parsed_results_dict + + +def get_dict_from_results_object(results_object) -> dict[str, float]: + """Get a dictionary of parameter names and values from a FitResults + object. + + Parameters + ---------- + results_object : FitResults + The FitResults object containing the parameter names and values. + + Returns + ------- + params_dict : dict + The dictionary where keys are parameter names and values are the + corresponding parameter values as floats. + """ + param_names = results_object.varnames + param_vals = results_object.varvals + params_dict = dict(zip(param_names, param_vals)) + return params_dict + + # End of file From 83fd535aab39e29efaf156d7a531335104977c28 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 15:26:18 -0500 Subject: [PATCH 114/193] news --- news/init-w-results.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/init-w-results.rst diff --git a/news/init-w-results.rst b/news/init-w-results.rst new file mode 100644 index 00000000..ae63a94a --- /dev/null +++ b/news/init-w-results.rst @@ -0,0 +1,23 @@ +**Added:** + +* Added ``initialize_recipe_with_results`` to ``FitRecipe``. + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 0c25030f992c33c11d23443e2eb9d2b5885ce046 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 15:28:49 -0500 Subject: [PATCH 115/193] fix accident in test_fitresults --- tests/test_fitresults.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index 4a2fde67..90bb1552 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -39,6 +39,9 @@ Chi2 0.00000000 Reduced Chi2 0.00000000 Rw 0.00000007 + +Variables (Uncertainties invalid) +------------------------------------------------------------------------------ """ expected_refined_variables = ["amplitude", "wave_number", "phase_shift"] From 0625461e63416df2497ca3e028c16248c1aed251 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 15:49:22 -0500 Subject: [PATCH 116/193] use get_results_dictionary method to get params_dict --- src/diffpy/srfit/fitbase/fitrecipe.py | 14 ++++++++++++-- src/diffpy/srfit/fitbase/fitresults.py | 9 +++++++++ src/diffpy/srfit/util/inpututils.py | 21 --------------------- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index ca3d34a8..28822043 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -1230,8 +1230,18 @@ def initialize_recipe_with_results(self, results, verbose=True): If the input results is not a FitResults object or a path to a results file. """ - if hasattr(results, "print_results"): - params_dict = utils.get_dict_from_results_object(results) + if hasattr(results, "get_results_dictionary"): + params_dict = results.get_results_dictionary() + metrics_in_dict = [ + "Residual", + "Contributions", + "Restraints", + "Chi2", + "Reduced Chi2", + "Rw", + ] + for metric in metrics_in_dict: + params_dict.pop(metric, None) elif isinstance(results, (str, Path)): params_dict = utils.get_dict_from_results_file(results) else: diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index c154d018..a83d6a9c 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -66,6 +66,14 @@ new_base="diffpy.srfit.fitbase.FitResults", ) +initializeRecipe_dep_msg = build_deprecation_message( + "diffpy.srfit.fitbase", + "initializeRecipe", + "FitRecipe.in", + removal_version, + new_base="diffpy.srfit.fitbase.FitResults", +) + class FitResults(object): """Class for processing, presenting and storing results of a fit. @@ -820,6 +828,7 @@ def resultsDictionary(results): return mpairs +@deprecated(initializeRecipe_dep_msg) def initializeRecipe(recipe, results): """Initialize the variables of a recipe from a results file. diff --git a/src/diffpy/srfit/util/inpututils.py b/src/diffpy/srfit/util/inpututils.py index 9eb2e067..f2e0a9df 100644 --- a/src/diffpy/srfit/util/inpututils.py +++ b/src/diffpy/srfit/util/inpututils.py @@ -92,25 +92,4 @@ def get_dict_from_results_file( return parsed_results_dict -def get_dict_from_results_object(results_object) -> dict[str, float]: - """Get a dictionary of parameter names and values from a FitResults - object. - - Parameters - ---------- - results_object : FitResults - The FitResults object containing the parameter names and values. - - Returns - ------- - params_dict : dict - The dictionary where keys are parameter names and values are the - corresponding parameter values as floats. - """ - param_names = results_object.varnames - param_vals = results_object.varvals - params_dict = dict(zip(param_names, param_vals)) - return params_dict - - # End of file From 17f2b10c0363fc6335fdb14e1d987144c7203672 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 15:52:43 -0500 Subject: [PATCH 117/193] initializeRecipe deprecation --- src/diffpy/srfit/fitbase/fitresults.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index a83d6a9c..4f91b6d5 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -69,9 +69,9 @@ initializeRecipe_dep_msg = build_deprecation_message( "diffpy.srfit.fitbase", "initializeRecipe", - "FitRecipe.in", + "initialize_recipe_with_results", removal_version, - new_base="diffpy.srfit.fitbase.FitResults", + new_base="diffpy.srfit.fitbase.FitRecipe", ) @@ -830,7 +830,14 @@ def resultsDictionary(results): @deprecated(initializeRecipe_dep_msg) def initializeRecipe(recipe, results): - """Initialize the variables of a recipe from a results file. + """**This function has been deprecated and will be** **removed in + version 4.0.0.** + + **Please use** + **diffpy.srfit.fitbase.FitRecipe.initialize_recipe_with_results** + **instead.** + + Initialize the variables of a recipe from a results file. This reads the results from file and initializes any variables (fixed or free) in the recipe to the results values. Note that the recipe has to be From 9e205d73b19be203db941a17a3a604db34931871 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 16:20:18 -0500 Subject: [PATCH 118/193] add better docstrings to fitrecipe and fitresults --- src/diffpy/srfit/fitbase/fitrecipe.py | 378 +++++++++++++++++-------- src/diffpy/srfit/fitbase/fitresults.py | 163 ++++++----- 2 files changed, 356 insertions(+), 185 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 28822043..a88e4487 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -131,63 +131,63 @@ class FitRecipe(_fitrecipe_interface, RecipeOrganizer): Attributes ---------- - name + name : str A name for this FitRecipe. - fithooks + fithooks : list List of FitHook instances that can pass information out - of the system during a refinement. By default, the is + of the system during a refinement. By default, this is populated by a PrintFitHook instance. - _constraints + _constraints : dict A dictionary of Constraints, indexed by the constrained Parameter. Constraints can be added using the 'constrain' method. - _oconstraints + _oconstraints : list An ordered list of the constraints from this and all sub-components. - _calculators + _calculators : dict A managed dictionary of Calculators. - _contributions + _contributions : OrderedDict A managed OrderedDict of FitContributions. - _parameters + _parameters : OrderedDict A managed OrderedDict of parameters (in this case the parameters are varied). - _parsets + _parsets : dict A managed dictionary of ParameterSets. - _eqfactory + _eqfactory : diffpy.srfit.equation.builder.EquationFactory A diffpy.srfit.equation.builder.EquationFactory instance that is used to create constraints and - restraints from string - _restraintlist + restraints from strings. + _restraintlist : list A list of restraints from this and all sub-components. - _restraints + _restraints : set A set of Restraints. Restraints can be added using the 'restrain' or 'confine' methods. - _ready + _ready : bool A flag indicating if all attributes are ready for the calculation. - _tagmanager + _tagmanager : TagManager A TagManager instance for managing tags on Parameters. - _weights + _weights : list List of weighing factors for each FitContribution. The weights are multiplied by the residual of the FitContribution when determining the overall residual. - _fixedtag + _fixedtag : str "__fixed", used for tagging variables as fixed. Don't use this tag unless you want issues. Properties ---------- - names + names : list Variable names (read only). See get_names. - values + values : numpy.ndarray Variable values (read only). See get_values. - fixednames + fixednames : list Names of the fixed refinable variables (read only). - fixedvalues + fixedvalues : numpy.ndarray Values of the fixed refinable variables (read only). - bounds + bounds : list of tuple Bounds on parameters (read only). See get_bounds_pairs. - bounds2 + bounds2 : tuple of numpy.ndarray Bounds on parameters (read only). See get_bounds_array. """ @@ -269,12 +269,12 @@ def push_fit_hook(self, fithook, index=None): diffpy.srfit.fitbase.fithook.FitHook class for the required interface. Added FitHooks will be called sequentially during refinement. - Attributes + Parameters ---------- - fithook - FitHook instance to add to the sequence - index - Index for inserting fithook into the list of fit hooks. If + fithook : diffpy.srfit.fitbase.fithook.FitHook + FitHook instance to add to the sequence. + index : int or None, optional + Index for inserting fithook into the list of fit hooks. If this is None (default), the fithook is added to the end. """ if index is None: @@ -297,18 +297,20 @@ def pushFitHook(self, fithook, index=None): def pop_fit_hook(self, fithook=None, index=-1): """Remove a FitHook by index or reference. - Attributes + Parameters ---------- - fithook + fithook : diffpy.srfit.fitbase.fithook.FitHook or None, optional FitHook instance to remove from the sequence. If this is None (default), default to index. - index + index : int, optional Index of FitHook instance to remove (default -1). - - Raises ValueError if fithook is not None, but is not present in the - sequence. - Raises IndexError if the sequence is empty or index is out of range. + Raises + ------ + ValueError + If fithook is not None, but is not present in the sequence. + IndexError + If the sequence is empty or index is out of range. """ if fithook is not None: self.fithooks.remove(fithook) @@ -355,15 +357,18 @@ def clearFitHooks(self): def add_contribution(self, con, weight=1.0): """Add a FitContribution to the FitRecipe. - Attributes + Parameters ---------- - con + con : FitContribution The FitContribution to be stored. + weight : float, optional + The weight of the FitContribution. Default is 1.0. - - Raises ValueError if the FitContribution has no name - Raises ValueError if the FitContribution has the same name as some - other managed object. + Raises + ------ + ValueError + If the FitContribution has no name or if the FitContribution has + the same name as some other managed object. """ self._add_object(con, self._contributions, True) self._weights.append(weight) @@ -381,7 +386,19 @@ def addContribution(self, con, weight=1.0): return def set_weight(self, con, weight): - """Set the weight of a FitContribution.""" + """Set the weight of a FitContribution. + + Parameters + ---------- + con : FitContribution + The FitContribution object whose weight is to be set. + weight : float + The weight value to assign to the specified FitContribution. + + Returns + ------- + None + """ idx = list(self._contributions.values()).index(con) self._weights[idx] = weight return @@ -398,15 +415,16 @@ def setWeight(self, con, weight): def add_parameter_set(self, parset): """Add a ParameterSet to the hierarchy. - Attributes + Parameters ---------- - parset + parset : ParameterSet The ParameterSet to be stored. - - Raises ValueError if the ParameterSet has no name. - Raises ValueError if the ParameterSet has the same name as some other - managed object. + Raises + ------ + ValueError + If the ParameterSet has no name or if the ParameterSet has the same + name as some other managed object. """ self._add_object(parset, self._parsets, True) return @@ -424,7 +442,19 @@ def addParameterSet(self, parset): def remove_parameter_set(self, parset): """Remove a ParameterSet from the hierarchy. - Raises ValueError if parset is not managed by this object. + This method removes the specified ParameterSet object from the internal + hierarchy of managed ParameterSets. If the provided ParameterSet is not + currently managed by this object, a ValueError will be raised. + + Parameters: + ----------- + parset : ParameterSet + The ParameterSet instance to be removed from the hierarchy. + + Raises: + ------- + ValueError + If the provided ParameterSet is not managed by this object. """ self._remove_object(parset, self._parsets) return @@ -444,7 +474,7 @@ def residual(self, p=[]): Parameters ---------- - p + p : list or numpy.ndarray The list of current variable values, provided in the same order as the '_parameters' list. If p is an empty iterable (default), then it is assumed that the parameters have already been @@ -495,7 +525,7 @@ def scalar_residual(self, p=[]): Parameters ---------- - p + p : list or numpy.ndarray The list of current variable values, provided in the same order as the '_parameters' list. If p is an empty iterable (default), then it is assumed that the parameters have already been @@ -533,7 +563,10 @@ def _prepare(self): This updates the local restraints with those of the contributions. - Raises AttributeError if there are variables without a value. + Raises + ------ + AttributeError + If there are variables without a value. """ # Only prepare if the configuration has changed within the recipe @@ -684,37 +717,40 @@ def add_variable( ): """Add a variable to be refined. - Attributes + Parameters ---------- - par + par : diffpy.srfit.fitbase.Parameter A Parameter that will be varied during a fit. - value + value : float or None, optional An initial value for the variable. If this is None (default), then the current value of par will be used. - name + name : str or None, optional A name for this variable. If name is None (default), then the name of the parameter will be used. - fixed + fixed : bool, optional Fix the variable so that it does not vary (default False). - tag + tag : str or None, optional A tag for the variable. This can be used to retrieve, fix or free variables by tag (default None). Note that a variable is automatically tagged with its name and "all". - tags + tags : list of str, optional A list of tags (default []). Both tag and tags can be applied. - Returns ------- - vars + ParameterProxy ParameterProxy (variable) for the passed Parameter. - - Raises ValueError if the name of the variable is already taken by - another managed object. - Raises ValueError if par is constant. - Raises ValueError if par is constrained. + Raises + ------ + ValueError + If the name of the variable is already taken by + another managed object. + ValueError + If par is constant. + ValueError + If par is constrained. """ name = name or par.name if par.const: @@ -752,13 +788,15 @@ def delete_variable(self, var): Note that constraints and restraints involving the variable are not modified. - Attributes + Parameters ---------- - var + var : ParameterProxy A variable of the FitRecipe. - - Raises ValueError if var is not part of the FitRecipe. + Raises + ------ + ValueError + If var is not part of the FitRecipe. """ self._remove_parameter(var) @@ -792,29 +830,31 @@ def create_new_variable( optimization routine, and therefore should only be created to be used in constraint or restraint equations. - Attributes + Parameters ---------- - name + name : str The name of the variable. The variable will be able to be used by this name in restraint and constraint equations. - value + value : float or None, optional An initial value for the variable. If this is None (default), then the variable will be given the value of the first non-None-valued Parameter constrained to it. If this fails, an error will be thrown when 'residual' is called. - fixed + fixed : bool, optional Fix the variable so that it does not vary (default False). The variable will still be managed by the FitRecipe. - tag + tag : str or None, optional A tag for the variable. This can be used to fix and free variables by tag (default None). Note that a variable is automatically tagged with its name and "all". - tags + tags : list of str, optional A list of tags (default []). Both tag and tags can be applied. - - Returns the new variable (Parameter instance). + Returns + ------- + Parameter + The new variable (Parameter instance). """ # This will fix the Parameter var = self._new_parameter(name, value) @@ -910,16 +950,51 @@ def __get_vars_from_args(self, *args, **kw): return varargs def fix(self, *args, **kw): - """Fix a parameter by reference, name or tag. + """Fix one or more parameters by reference, name, or tag. - A fixed variable is not refined. Variables are free by default. + This method marks specified parameters as fixed, meaning they will not + be refined during the fitting process. By default, all parameters are + free (not fixed). Parameters can be specified using their references, + names, or tags. Additionally, keyword arguments can be used to assign + specific values to the fixed parameters. - This method accepts string or variable arguments. An argument of - "all" selects all variables. Keyword arguments must be parameter - names, followed by a value to assign to the fixed variable. + Parameters + ---------- + *args: + Positional arguments specifying the parameters to fix. These + can be parameter objects, their names as strings, or tags. + The special string "all" can be used to select all + parameters. + **kw: + Keyword arguments where the keys are parameter names and the + values are the values to assign to the corresponding + fixed parameters. + + Raises + ------ + ValueError: + If an unknown parameter, name, or tag is passed, or if a + tag is passed as a keyword argument. + + Example + ------- + + :: + + # Fix a parameter by reference + recipe.fix(param1) - Raises ValueError if an unknown Parameter, name or tag is - passed, or if a tag is passed in a keyword. + # Fix a parameter by name + recipe.fix("param2") + + # Fix all parameters + recipe.fix("all") + + # Fix parameters by tag + recipe.fix(tag="group1") + + # Fix a parameter and assign it a value + recipe.fix(param3=10.0) """ # Check the inputs and get the variables from them varargs = self.__get_vars_from_args(*args, **kw) @@ -935,17 +1010,44 @@ def fix(self, *args, **kw): return def free(self, *args, **kw): - """Free a parameter by reference, name or tag. + """Free one or more parameters by reference, name, or tag. - A free variable is refined. Variables are free by default. - Constrained variables are not free. + This method marks specified parameters as free, allowing them to be + refined during the fitting process. By default, variables + are free unless they are constrained. Constrained variables + cannot be freed. - This method accepts string or variable arguments. An argument of - "all" selects all variables. Keyword arguments must be parameter - names, followed by a value to assign to the fixed variable. + Parameters + ---------- + *args : str or Parameter + Positional arguments specifying the parameters to free. + These can be: + - Parameter objects + - Names of parameters (as strings) + - Tags associated with parameters (as strings) + - The string "all" to select all parameters. + **kw : dict + Keyword arguments specifying parameter names as keys and + their values to assign after freeing. This is useful + for setting the value of a parameter while marking it as free. - Raises ValueError if an unknown Parameter, name or tag is - passed, or if a tag is passed in a keyword. + Raises + ------ + ValueError + If an unknown parameter, name, or tag is passed, or if a + tag is passed as a keyword argument. + + Notes + ----- + - Parameters that are already free will remain free. + - Tags associated with fixed parameters will be removed when they + are freed. + - If keyword arguments are provided, the corresponding parameter values + will be updated after freeing. + + Returns + ------- + None """ # Check the inputs and get the variables from them varargs = self.__get_vars_from_args(*args, **kw) @@ -962,7 +1064,24 @@ def free(self, *args, **kw): return def is_free(self, var): - """Check if a variable is fixed.""" + """Determine if a variable is free (not fixed) in the fit + recipe. + + This method checks whether the specified variable does not have the + fixed tag associated with it, indicating that it is free to vary + during the fitting process. + + Parameters + ---------- + var : object + The variable to check. This is typically an instance of a parameter + or variable object used in the fit recipe. + + Returns + ------- + bool + True if the variable is free (not fixed), False otherwise. + """ return not self._tagmanager.hasTags(var, self._fixedtag) @deprecated(isFree_dep_msg) @@ -980,13 +1099,15 @@ def unconstrain(self, *pars): This removes any constraints on a Parameter. If the Parameter is also a variable of the recipe, it will be freed as well. - Attributes + Parameters ---------- - *pars - The names of Parameters or Parameters to unconstrain. - + *pars : str or Parameter + The names of Parameters or Parameter objects to unconstrain. - Raises ValueError if the Parameter is not constrained. + Raises + ------ + ValueError + If the Parameter is not constrained. """ update = False for par in pars: @@ -1020,26 +1141,29 @@ def constrain(self, par, con, ns={}): and its current value is None. A constrained variable will be set as fixed. - Attributes + Parameters ---------- - par + par : Parameter The Parameter to constrain. - con + con : str or Parameter A string representation of the constraint equation or a - Parameter to constrain to. A constraint equation must + Parameter to constrain to. A constraint equation must consist of numpy operators and "known" Parameters. Parameters are known if they are in the ns argument, or if they are managed by this object. - ns + ns : dict, optional A dictionary of Parameters, indexed by name, that are used in the eqstr, but not part of this object (default {}). - - Raises ValueError if ns uses a name that is already used for a - variable. - Raises ValueError if eqstr depends on a Parameter that is not part of - the FitRecipe and that is not defined in ns. - Raises ValueError if par is marked as constant. + Raises + ------ + ValueError + If ns uses a name that is already used for a variable. + ValueError + If eqstr depends on a Parameter that is not part of the FitRecipe + and that is not defined in ns. + ValueError + If par is marked as constant. """ if isinstance(par, str): name = par @@ -1070,10 +1194,24 @@ def constrain(self, par, con, ns={}): return def get_values(self): - """Get the current values of the variables in a list.""" - return array( + """Retrieve the current values of all free variables in the fit + recipe. + + This method collects the values of all parameters that are marked as + free (i.e., adjustable during the fitting process) and returns them + as a NumPy array. + + Returns + ------- + + values_array : numpy.ndarray + An array containing the current values of all free + variables in the fit recipe. + """ + values_array = array( [v.value for v in self._parameters.values() if self.is_free(v)] ) + return values_array @deprecated(getValues_dep_msg) def getValues(self): @@ -1084,8 +1222,20 @@ def getValues(self): return self.get_values() def get_names(self): - """Get the names of the variables in a list.""" - return [v.name for v in self._parameters.values() if self.is_free(v)] + """Retrieve the names of all free variables in the fit recipe. + + This method iterates through the parameters in the fit recipe and + returns a list of names for those variables that are marked as free. + + Returns + ------- + parameter_names :list of str + A list containing the names of free variables. + """ + parameter_names = [ + v.name for v in self._parameters.values() if self.is_free(v) + ] + return parameter_names @deprecated(getNames_dep_msg) def getNames(self): diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index 4f91b6d5..bf286a3b 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -80,58 +80,80 @@ class FitResults(object): Attributes ---------- - recipe - The recipe containing the results. - cov - The covariance matrix from the recipe. - conresults - An ordered dictionary of ContributionResults for each - FitContribution, indexed by the FitContribution name. - derivstep - The fractional step size for calculating numeric - derivatives. Default 1e-8. - varnames - Names of the variables in the recipe. - varvals - Values of the variables in the recipe. - varunc - Uncertainties in the variable values. - showfixed - Show fixed variables (default True). - fixednames - Names of the fixed variables of the recipe. - fixedvals - Values of the fixed variables of the recipe. - showcon - Show constraint values in the output (default False). - connames - Names of the constrained parameters. - convals - Values of the constrained parameters. - conunc - Uncertainties in the constraint values. - residual - The scalar residual of the recipe. - penalty - The penalty to residual from the restraints. - chi2 - The chi2 of the recipe. - cumchi2 - The cumulative chi2 of the recipe. - rchi2 - The reduced chi2 of the recipe. - rw - The Rw of the recipe. - cumrw - The cumulative Rw of the recipe. - messages - A list of messages about the results. - precision - The precision of numeric output (default 8). - _dcon - The derivatives of the constraint equations with respect to - the variables. This is used internally. + recipe : FitRecipe + The recipe from which the results were generated. + + cov : numpy.ndarray or None + Covariance matrix of the refined variables. None if unavailable. + + conresults : collections.OrderedDict[str, ContributionResults] + Ordered mapping of FitContribution name → ContributionResults. + + derivstep : float + Fractional step size used for numerical derivatives (default 1e-8). + + varnames : list[str] + Names of refined variables in the recipe. + + varvals : numpy.ndarray + Optimized values of the refined variables. + + varunc : numpy.ndarray or None + Estimated standard uncertainties of the variables. None if invalid. + + showfixed : bool + Whether fixed variables are included in formatted output + (default True). + + fixednames : list[str] + Names of variables held fixed during refinement. + + fixedvals : numpy.ndarray + Values of the fixed variables. + + showcon : bool + Whether constrained parameters are included in formatted output + (default False). + + connames : list[str] + Names of constrained parameters. + convals : numpy.ndarray + Values of constrained parameters. + + conunc : numpy.ndarray or None + Uncertainties of constrained parameters. None if unavailable. + + residual : float + Scalar residual value of the recipe. + + penalty : float + Penalty contribution to the residual from restraints. + + chi2 : float + Chi-squared value of the fit. + + cumchi2 : numpy.ndarray + Cumulative chi-squared as a function of data index. + + rchi2 : float + Reduced chi-squared of the fit. + + rw : float + Weighted R-factor of the fit. + + cumrw : numpy.ndarray + Cumulative weighted R-factor as a function of data index. + + messages : list[str] + Informational or warning messages associated with the results. + + precision : int + Number of digits used when formatting numeric output (default 8). + + _dcon : numpy.ndarray + Jacobian of constraint equations with respect to variables. + Used internally for uncertainty propagation. Each of these attributes, except the recipe, are created or updated when the update method is called. @@ -142,14 +164,13 @@ def __init__(self, recipe, update=True, showfixed=True, showcon=False): Attributes ---------- - recipe - The recipe containing the results - update - Flag indicating whether to do an immediate update (default - True). - showcon + recipe : FitRecipe + The recipe containing the results. + update : bool + Flag indicating whether to do an immediate update (default True). + showfixed : bool Show fixed variables in the output (default True). - showcon + showcon : bool Show constraint values in the output (default False). """ self.recipe = recipe @@ -674,37 +695,37 @@ class ContributionResults(object): Attributes ---------- - y + y : numpy.ndarray or None The FitContribution's profile over the calculation range (default None). - dy + dy : numpy.ndarray or None The uncertainty in the FitContribution's profile over the calculation range (default None). - x + x : numpy.ndarray or None A numpy array of the calculated independent variable for the FitContribution (default None). - ycalc + ycalc : numpy.ndarray or None A numpy array of the calculated signal for the FitContribution (default None). - residual + residual : float The scalar residual of the FitContribution. - chi2 + chi2 : float The chi2 of the FitContribution. - cumchi2 + cumchi2 : numpy.ndarray The cumulative chi2 of the FitContribution. - rw + rw : float The Rw of the FitContribution. - cumrw + cumrw : numpy.ndarray The cumulative Rw of the FitContribution. - weight + weight : float The weight of the FitContribution in the recipe. - conlocs + conlocs : list The location of the constrained parameters in the FitContribution (see the RecipeContainer._locate_managed_object method). - convals + convals : list Values of the constrained parameters. - conunc + conunc : list Uncertainties in the constraint values. """ From 39178a67d24eee1de4907eed1e5f2ee360ad7c9f Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 17:59:52 -0500 Subject: [PATCH 119/193] add 'The' to docstrings --- src/diffpy/srfit/fitbase/fitrecipe.py | 94 +++++++++++++------------- src/diffpy/srfit/fitbase/fitresults.py | 75 ++++++++++---------- 2 files changed, 85 insertions(+), 84 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index a88e4487..0aff6ecd 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -134,41 +134,41 @@ class FitRecipe(_fitrecipe_interface, RecipeOrganizer): name : str A name for this FitRecipe. fithooks : list - List of FitHook instances that can pass information out + The list of FitHook instances that can pass information out of the system during a refinement. By default, this is populated by a PrintFitHook instance. _constraints : dict - A dictionary of Constraints, indexed by the constrained + The dictionary of Constraints, indexed by the constrained Parameter. Constraints can be added using the 'constrain' method. _oconstraints : list - An ordered list of the constraints from this and all + The ordered list of the constraints from this and all sub-components. _calculators : dict - A managed dictionary of Calculators. + The managed dictionary of Calculators. _contributions : OrderedDict - A managed OrderedDict of FitContributions. + The managed OrderedDict of FitContributions. _parameters : OrderedDict - A managed OrderedDict of parameters (in this case the + The managed OrderedDict of parameters (in this case the parameters are varied). _parsets : dict - A managed dictionary of ParameterSets. + The managed dictionary of ParameterSets. _eqfactory : diffpy.srfit.equation.builder.EquationFactory - A diffpy.srfit.equation.builder.EquationFactory + The diffpy.srfit.equation.builder.EquationFactory instance that is used to create constraints and restraints from strings. _restraintlist : list - A list of restraints from this and all sub-components. + The list of restraints from this and all sub-components. _restraints : set - A set of Restraints. Restraints can be added using the + The set of Restraints. Restraints can be added using the 'restrain' or 'confine' methods. _ready : bool - A flag indicating if all attributes are ready for the + The flag indicating if all attributes are ready for the calculation. _tagmanager : TagManager - A TagManager instance for managing tags on Parameters. + The TagManager instance for managing tags on Parameters. _weights : list - List of weighing factors for each FitContribution. The + The list of weighing factors for each FitContribution. The weights are multiplied by the residual of the FitContribution when determining the overall residual. _fixedtag : str @@ -178,17 +178,17 @@ class FitRecipe(_fitrecipe_interface, RecipeOrganizer): Properties ---------- names : list - Variable names (read only). See get_names. + The variable names (read only). See get_names. values : numpy.ndarray - Variable values (read only). See get_values. + The variable values (read only). See get_values. fixednames : list - Names of the fixed refinable variables (read only). + The names of the fixed refinable variables (read only). fixedvalues : numpy.ndarray - Values of the fixed refinable variables (read only). + The values of the fixed refinable variables (read only). bounds : list of tuple - Bounds on parameters (read only). See get_bounds_pairs. + The bounds on parameters (read only). See get_bounds_pairs. bounds2 : tuple of numpy.ndarray - Bounds on parameters (read only). See get_bounds_array. + The bounds on parameters (read only). See get_bounds_array. """ fixednames = property( @@ -272,9 +272,9 @@ def push_fit_hook(self, fithook, index=None): Parameters ---------- fithook : diffpy.srfit.fitbase.fithook.FitHook - FitHook instance to add to the sequence. + The FitHook instance to add to the sequence. index : int or None, optional - Index for inserting fithook into the list of fit hooks. If + The index for inserting fithook into the list of fit hooks. If this is None (default), the fithook is added to the end. """ if index is None: @@ -300,10 +300,10 @@ def pop_fit_hook(self, fithook=None, index=-1): Parameters ---------- fithook : diffpy.srfit.fitbase.fithook.FitHook or None, optional - FitHook instance to remove from the sequence. If this is + The FitHook instance to remove from the sequence. If this is None (default), default to index. index : int, optional - Index of FitHook instance to remove (default -1). + The index of FitHook instance to remove (default -1). Raises ------ @@ -720,21 +720,21 @@ def add_variable( Parameters ---------- par : diffpy.srfit.fitbase.Parameter - A Parameter that will be varied during a fit. + The Parameter that will be varied during a fit. value : float or None, optional - An initial value for the variable. If this is None + The initial value for the variable. If this is None (default), then the current value of par will be used. name : str or None, optional - A name for this variable. If name is None (default), then + The name for this variable. If name is None (default), then the name of the parameter will be used. fixed : bool, optional Fix the variable so that it does not vary (default False). tag : str or None, optional - A tag for the variable. This can be used to retrieve, fix + The tag for the variable. This can be used to retrieve, fix or free variables by tag (default None). Note that a variable is automatically tagged with its name and "all". tags : list of str, optional - A list of tags (default []). Both tag and tags can be + The list of tags (default []). Both tag and tags can be applied. Returns @@ -836,7 +836,7 @@ def create_new_variable( The name of the variable. The variable will be able to be used by this name in restraint and constraint equations. value : float or None, optional - An initial value for the variable. If this is None + The initial value for the variable. If this is None (default), then the variable will be given the value of the first non-None-valued Parameter constrained to it. If this fails, an error will be thrown when 'residual' is called. @@ -844,11 +844,11 @@ def create_new_variable( Fix the variable so that it does not vary (default False). The variable will still be managed by the FitRecipe. tag : str or None, optional - A tag for the variable. This can be used to fix and free + The tag for the variable. This can be used to fix and free variables by tag (default None). Note that a variable is automatically tagged with its name and "all". tags : list of str, optional - A list of tags (default []). Both tag and tags can be + The list of tags (default []). Both tag and tags can be applied. Returns @@ -960,14 +960,14 @@ def fix(self, *args, **kw): Parameters ---------- - *args: - Positional arguments specifying the parameters to fix. These - can be parameter objects, their names as strings, or tags. - The special string "all" can be used to select all + *args : str or Parameter + The positional arguments specifying the parameters to fix. + These can be parameter objects, their names as strings, or + tags. The special string "all" can be used to select all parameters. - **kw: - Keyword arguments where the keys are parameter names and the - values are the values to assign to the corresponding + **kw : dict + The keyword arguments where the keys are parameter names and + the values are the values to assign to the corresponding fixed parameters. Raises @@ -1020,14 +1020,14 @@ def free(self, *args, **kw): Parameters ---------- *args : str or Parameter - Positional arguments specifying the parameters to free. + The positional arguments specifying the parameters to free. These can be: - Parameter objects - Names of parameters (as strings) - Tags associated with parameters (as strings) - The string "all" to select all parameters. **kw : dict - Keyword arguments specifying parameter names as keys and + The keyword arguments specifying parameter names as keys and their values to assign after freeing. This is useful for setting the value of a parameter while marking it as free. @@ -1146,13 +1146,13 @@ def constrain(self, par, con, ns={}): par : Parameter The Parameter to constrain. con : str or Parameter - A string representation of the constraint equation or a + The string representation of the constraint equation or a Parameter to constrain to. A constraint equation must consist of numpy operators and "known" Parameters. Parameters are known if they are in the ns argument, or if they are managed by this object. ns : dict, optional - A dictionary of Parameters, indexed by name, that are used + The dictionary of Parameters, indexed by name, that are used in the eqstr, but not part of this object (default {}). Raises @@ -1205,7 +1205,7 @@ def get_values(self): ------- values_array : numpy.ndarray - An array containing the current values of all free + The array containing the current values of all free variables in the fit recipe. """ values_array = array( @@ -1230,7 +1230,7 @@ def get_names(self): Returns ------- parameter_names :list of str - A list containing the names of free variables. + The list containing the names of free variables. """ parameter_names = [ v.name for v in self._parameters.values() if self.is_free(v) @@ -1251,7 +1251,7 @@ def get_bounds_pairs(self): Returns ------- bounds_pair_list : list of tuple of float - A list of ``(lower, upper)`` bounds on the variables, in the same + The list of ``(lower, upper)`` bounds on the variables, in the same order as ``get_names`` and ``get_values``. """ return [v.bounds for v in self._parameters.values() if self.is_free(v)] @@ -1272,10 +1272,10 @@ def get_bounds_array(self): Returns ------- lower_bounds : numpy.ndarray - A numpy array of lower bounds on the variables, in the same order + The numpy array of lower bounds on the variables, in the same order as ``get_names`` and ``get_values``. upper_bounds : numpy.ndarray - A numpy array of upper bounds on the variables, in the same order + The numpy array of upper bounds on the variables, in the same order as ``get_names`` and ``get_values``. """ bounds = self.get_bounds_pairs() diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index bf286a3b..d8310109 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -84,75 +84,75 @@ class FitResults(object): The recipe from which the results were generated. cov : numpy.ndarray or None - Covariance matrix of the refined variables. None if unavailable. + The covariance matrix of the refined variables. None if unavailable. conresults : collections.OrderedDict[str, ContributionResults] - Ordered mapping of FitContribution name → ContributionResults. + The ordered mapping of FitContribution name → ContributionResults. derivstep : float - Fractional step size used for numerical derivatives (default 1e-8). + The fractional step size used for numerical derivatives (default 1e-8). varnames : list[str] - Names of refined variables in the recipe. + The names of refined variables in the recipe. varvals : numpy.ndarray - Optimized values of the refined variables. + The optimized values of the refined variables. varunc : numpy.ndarray or None - Estimated standard uncertainties of the variables. None if invalid. + The estimated standard uncertainties of the variables. None if invalid. showfixed : bool - Whether fixed variables are included in formatted output + Show the fixed variables in the formatted output (default True). fixednames : list[str] - Names of variables held fixed during refinement. + The names of variables held fixed during refinement. fixedvals : numpy.ndarray - Values of the fixed variables. + The values of the fixed variables. showcon : bool - Whether constrained parameters are included in formatted output + show the constrained parameters in the formatted output (default False). connames : list[str] - Names of constrained parameters. + The names of constrained parameters. convals : numpy.ndarray - Values of constrained parameters. + The values of constrained parameters. conunc : numpy.ndarray or None - Uncertainties of constrained parameters. None if unavailable. + The uncertainties of constrained parameters. None if unavailable. residual : float - Scalar residual value of the recipe. + The scalar residual value of the recipe. penalty : float - Penalty contribution to the residual from restraints. + The penalty contribution to the residual from restraints. chi2 : float - Chi-squared value of the fit. + The chi-squared value of the fit. cumchi2 : numpy.ndarray - Cumulative chi-squared as a function of data index. + The cumulative chi-squared as a function of data index. rchi2 : float - Reduced chi-squared of the fit. + The reduced chi-squared of the fit. rw : float - Weighted R-factor of the fit. + The weighted R-factor of the fit. cumrw : numpy.ndarray - Cumulative weighted R-factor as a function of data index. + The cumulative weighted R-factor as a function of data index. messages : list[str] - Informational or warning messages associated with the results. + The informational or warning messages associated with the results. precision : int - Number of digits used when formatting numeric output (default 8). + The number of digits used when formatting numeric output (default 8). _dcon : numpy.ndarray - Jacobian of constraint equations with respect to variables. + The jacobian of constraint equations with respect to variables. Used internally for uncertainty propagation. Each of these attributes, except the recipe, are created or updated when @@ -167,7 +167,8 @@ def __init__(self, recipe, update=True, showfixed=True, showcon=False): recipe : FitRecipe The recipe containing the results. update : bool - Flag indicating whether to do an immediate update (default True). + The flag indicating whether to do an immediate update + (default True). showfixed : bool Show fixed variables in the output (default True). showcon : bool @@ -597,11 +598,11 @@ def print_results(self, header="", footer="", update=False): Parameters ---------- header - A header to add to the output (default "") + The header to add to the output (default "") footer - A footer to add to the output (default "") + The footer to add to the output (default "") update - Flag indicating whether to call update() (default False). + The flag indicating whether to call update() (default False). """ print(self.get_results_string(header, footer, update).rstrip()) return @@ -626,13 +627,13 @@ def save_results(self, filename, header="", footer="", update=False): Parameters ---------------------------------- filename - Name of the save file. + The name of the save file. header - A header to add to the output (default "") + The header to add to the output (default "") footer - A footer to add to the output (default "") + The footer to add to the output (default "") update - Flag indicating whether to call update() (default False). + The flag indicating whether to call update() (default False). """ # Save the time and user from getpass import getuser @@ -666,8 +667,8 @@ def get_results_dictionary(self): Returns ------- results_dict : dict - A dictionary containing the variable names and values, and overall - metrics, from the FitResults. + The dictionary containing the variable names and values, + and overall metrics, from the FitResults. """ parameter_names = self.varnames parameter_values = self.varvals @@ -702,10 +703,10 @@ class ContributionResults(object): The uncertainty in the FitContribution's profile over the calculation range (default None). x : numpy.ndarray or None - A numpy array of the calculated independent variable for the + The numpy array of the calculated independent variable for the FitContribution (default None). ycalc : numpy.ndarray or None - A numpy array of the calculated signal for the FitContribution + The numpy array of the calculated signal for the FitContribution (default None). residual : float The scalar residual of the FitContribution. @@ -724,9 +725,9 @@ class ContributionResults(object): FitContribution (see the RecipeContainer._locate_managed_object method). convals : list - Values of the constrained parameters. + The values of the constrained parameters. conunc : list - Uncertainties in the constraint values. + The uncertainties in the constraint values. """ def __init__(self, con, weight, fitres): From 73704f41ad84c64e5cb73dc4968095077ecb0f8e Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 27 Feb 2026 15:47:52 -0500 Subject: [PATCH 120/193] do linspace with odd number of points --- tests/conftest.py | 4 ++-- tests/test_fitresults.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 6b5b39c7..9b7a99fc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -153,7 +153,7 @@ def build_recipe_one_contribution(): def _build_recipe(): profile = Profile() - x = linspace(0, pi, 10) + x = linspace(0, pi, 11) y = sin(x) profile.set_observed_profile(x, y) contribution = FitContribution("c1") @@ -174,7 +174,7 @@ def build_recipe_two_contributions(): """Helper to build a recipe with two physically related contributions.""" profile1 = Profile() - x = linspace(0, pi, 50) + x = linspace(0, pi, 51) y1 = sin(x) # amplitude=1, freq=1 profile1.set_observed_profile(x, y1) diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index 90bb1552..c8797233 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -38,7 +38,7 @@ Restraints 0.00000000 Chi2 0.00000000 Reduced Chi2 0.00000000 -Rw 0.00000007 +Rw 0.00000010 Variables (Uncertainties invalid) ------------------------------------------------------------------------------ From aae48e070d8f7277eccc8c167a5273e6872cfeda Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 2 Mar 2026 14:20:12 -0500 Subject: [PATCH 121/193] revert recipe fixture back, explicitly set scope to 'function', and add a new helper function that builds recipe for init testing --- tests/conftest.py | 40 ++++++++-------- tests/test_fitrecipe.py | 99 ++++++++++++++++++++++++---------------- tests/test_fitresults.py | 15 +++--- 3 files changed, 84 insertions(+), 70 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 9b7a99fc..bd8efd7c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -147,29 +147,25 @@ def _capturestdout(f, *args, **kwargs): return _capturestdout -@pytest.fixture() +@pytest.fixture(scope="function") def build_recipe_one_contribution(): - "helper to build a simple recipe" - - def _build_recipe(): - profile = Profile() - x = linspace(0, pi, 11) - y = sin(x) - profile.set_observed_profile(x, y) - contribution = FitContribution("c1") - contribution.set_profile(profile) - contribution.set_equation("amplitude*sin(wave_number*x + phase_shift)") - recipe = FitRecipe() - recipe.add_contribution(contribution) - recipe.add_variable(contribution.amplitude, 4) - recipe.add_variable(contribution.wave_number, 3) - recipe.add_variable(contribution.phase_shift, 2) - return recipe - - return _build_recipe - - -@pytest.fixture() + """Helper to build a simple recipe.""" + profile = Profile() + x = linspace(0, pi, 11) + y = sin(x) + profile.set_observed_profile(x, y) + contribution = FitContribution("c1") + contribution.set_profile(profile) + contribution.set_equation("amplitude*sin(wave_number*x + phase_shift)") + recipe = FitRecipe() + recipe.add_contribution(contribution) + recipe.add_variable(contribution.amplitude, 4) + recipe.add_variable(contribution.wave_number, 3) + recipe.add_variable(contribution.phase_shift, 2) + return recipe + + +@pytest.fixture(scope="function") def build_recipe_two_contributions(): """Helper to build a recipe with two physically related contributions.""" diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 21ce1113..b19702c7 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -33,6 +33,29 @@ matplotlib.use("Agg") +def build_recipe_for_init_testing(): + """A helper to build a FitRecipe with one contribution and three + variables. + + This is identical to the build_recipe_one_contribution fixture, but + is a function instead of a fixture so we can call it to get unique + recipe objects in a singular test. + """ + profile = Profile() + x = linspace(0, pi, 11) + y = sin(x) + profile.set_observed_profile(x, y) + contribution = FitContribution("c1") + contribution.set_profile(profile) + contribution.set_equation("amplitude*sin(wave_number*x + phase_shift)") + recipe = FitRecipe() + recipe.add_contribution(contribution) + recipe.add_variable(contribution.amplitude, 4) + recipe.add_variable(contribution.wave_number, 3) + recipe.add_variable(contribution.phase_shift, 2) + return recipe + + class TestFitRecipe(unittest.TestCase): def setUp(self): @@ -530,48 +553,44 @@ def test_initialize_recipe_from_recipe_bad(build_recipe_two_contributions): def test_initialize_recipe_from_results_object(build_recipe_one_contribution): # Case: User initializes a FitRecipe from a FitResults object # expected: recipe is initialized with variables from previous fit - recipe1 = build_recipe_one_contribution() + + # create unique recipe1 + recipe1 = build_recipe_for_init_testing() optimize_recipe(recipe1) results1 = FitResults(recipe1) expected_values = np.round(results1.varvals, 5) expected_names = results1.varnames - recipe2 = build_recipe_one_contribution() - recipe2.create_new_variable( - "extra_var", 5 - ) # should be included in the initialized recipe + # create unique recipe2 with same contributions + # and variables as recipe1 but not optimized yet + recipe2 = build_recipe_for_init_testing() + assert recipe1 != recipe2 + # create a new var that should be include in the initialized recipe + recipe2.create_new_variable("extra_var", 5) actual_values_before_init = [val for val in recipe2.get_values()] - actual_names_before_init = recipe2.get_names() - expected_names_before_init = [ - "amplitude", - "extra_var", - "phase_shift", - "wave_number", - ] - expected_values_before_init = [ - 4, - 3, - 2, - 5, - ] # the three variables + the extra_var - - assert actual_values_before_init == expected_values_before_init - assert sorted(actual_names_before_init) == sorted( - expected_names_before_init + actual_names_before_init = sorted(recipe2.get_names()) + # the three variables + the extra_var + expected_names_before_init = sorted( + [ + "amplitude", + "extra_var", + "phase_shift", + "wave_number", + ] ) - + expected_values_before_init = [4, 3, 2, 5] + assert actual_values_before_init == expected_values_before_init + assert actual_names_before_init == expected_names_before_init recipe2.initialize_recipe_with_results(results1) optimize_recipe(recipe2) results2 = FitResults(recipe2) actual_values = np.round(results2.varvals, 5) actual_names = results2.varnames - expected_names = expected_names + [ - "extra_var" - ] # add the new variable name to expected names - expected_values = list(expected_values) + [ - 5 - ] # add the value of the new variable to expected values + # add the new variable name to expected names + expected_names = expected_names + ["extra_var"] + # add the value of the new variable to expected values + expected_values = list(expected_values) + [5] assert sorted(expected_names) == sorted(actual_names) assert sorted(expected_values) == sorted(list(actual_values)) @@ -585,7 +604,7 @@ def test_initialize_recipe_from_results_file( expected_names = ["amplitude", "phase_shift", "wave_number"] expected_values = [1, 1, 0] - recipe = build_recipe_one_contribution() + recipe = build_recipe_one_contribution recipe.initialize_recipe_with_results(results_file) results = FitResults(recipe) actual_values = np.round(results.varvals, 5) @@ -601,7 +620,7 @@ def test_initialize_recipe_from_results_file_bad( # Case: User tries to initialize a recipe with something that # isn't a path, str, or FitResults object # Expected: raised ValueError with message - recipe = build_recipe_one_contribution() + recipe = build_recipe_one_contribution bad_input = 12345 # not a valid input type msg = ( "The input results must be a FitResults object or a path to a " @@ -695,7 +714,7 @@ def build_recipe_from_datafile_deprecated(datafile): def test_plot_recipe_bad_display(build_recipe_one_contribution): - recipe = build_recipe_one_contribution() + recipe = build_recipe_one_contribution # Case: All plots are disabled # expected: raised ValueError with message plt.close("all") @@ -725,7 +744,7 @@ def test_plot_recipe_before_refinement(capsys, build_recipe_one_contribution): # Case: User tries to plot recipe before refinement # expected: Data plotted without fit line or difference curve # and warning message printed - recipe = build_recipe_one_contribution() + recipe = build_recipe_one_contribution plt.close("all") before = set(plt.get_fignums()) # include fit_label="nothing" to make sure fit line is not plotted @@ -753,7 +772,7 @@ def test_plot_recipe_before_refinement(capsys, build_recipe_one_contribution): def test_plot_recipe_after_refinement(build_recipe_one_contribution): # Case: User refines recipe and then plots # expected: Plot generates with no problem - recipe = build_recipe_one_contribution() + recipe = build_recipe_one_contribution optimize_recipe(recipe) plt.close("all") before = set(plt.get_fignums()) @@ -790,7 +809,7 @@ def test_plot_recipe_two_contributions(build_recipe_two_contributions): def test_plot_recipe_on_existing_plot(build_recipe_one_contribution): # Case: User passes axes to plot_recipe to plot on existing figure # expected: User modifications are present in the final figure - recipe = build_recipe_one_contribution() + recipe = build_recipe_one_contribution optimize_recipe(recipe) plt.close("all") fig, ax = plt.subplots() @@ -810,7 +829,7 @@ def test_plot_recipe_on_existing_plot(build_recipe_one_contribution): def test_plot_recipe_add_new_data(build_recipe_one_contribution): # Case: User wants to add data to figure generated by plot_recipe # Expected: New data is added to existing figure (check with labels) - recipe = build_recipe_one_contribution() + recipe = build_recipe_one_contribution optimize_recipe(recipe) plt.close("all") before = set(plt.get_fignums()) @@ -854,7 +873,7 @@ def test_plot_recipe_add_new_data_two_figs(build_recipe_two_contributions): def test_plot_recipe_set_title(build_recipe_one_contribution): # Case: User sets title via plot_recipe # Expected: Title is set correctly - recipe = build_recipe_one_contribution() + recipe = build_recipe_one_contribution optimize_recipe(recipe) plt.close("all") expected_title = "Custom Recipe Title" @@ -868,7 +887,7 @@ def test_plot_recipe_set_title(build_recipe_one_contribution): def test_plot_recipe_set_defaults(build_recipe_one_contribution): # Case: user sets default plot options with set_plot_defaults # Expected: plot_recipe uses the default options for all calls - recipe = build_recipe_one_contribution() + recipe = build_recipe_one_contribution optimize_recipe(recipe) plt.close("all") # set new defaults @@ -896,7 +915,7 @@ def test_plot_recipe_set_defaults(build_recipe_one_contribution): def test_plot_recipe_set_defaults_bad(capsys, build_recipe_one_contribution): # Case: user tries to set kwargs that are not valid plot_recipe options # Expected: Plot is shown and warning is printed - recipe = build_recipe_one_contribution() + recipe = build_recipe_one_contribution optimize_recipe(recipe) plt.close("all") recipe.set_plot_defaults( @@ -1006,7 +1025,7 @@ def test_plot_recipe_reset_all_defaults(build_recipe_one_contribution): "show": True, } - recipe = build_recipe_one_contribution() + recipe = build_recipe_one_contribution optimize_recipe(recipe) plt.close("all") diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index c8797233..d91a51ad 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -54,10 +54,9 @@ def optimize_recipe(recipe): def test_formatResults(build_recipe_one_contribution): - recipe = build_recipe_one_contribution() + recipe = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) - results.save_results("res.res") actual_results_string = results.formatResults(header="My Custom header") # Because slight variations in refinement, just check # that the header of the results are the same. @@ -68,7 +67,7 @@ def test_formatResults(build_recipe_one_contribution): def test_get_results_string(build_recipe_one_contribution): - recipe = build_recipe_one_contribution() + recipe = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) actual_results_string = results.get_results_string( @@ -83,7 +82,7 @@ def test_get_results_string(build_recipe_one_contribution): def test_printResults(build_recipe_one_contribution, capsys): - recipe = build_recipe_one_contribution() + recipe = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) results.printResults(header="My Custom header") @@ -97,7 +96,7 @@ def test_printResults(build_recipe_one_contribution, capsys): def test_print_results(build_recipe_one_contribution, capsys): - recipe = build_recipe_one_contribution() + recipe = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) results.print_results(header="My Custom header") @@ -111,7 +110,7 @@ def test_print_results(build_recipe_one_contribution, capsys): def test_saveResults(build_recipe_one_contribution, tmp_path): - recipe = build_recipe_one_contribution() + recipe = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) actual_results_file = tmp_path / "fit_results.txt" @@ -128,7 +127,7 @@ def test_saveResults(build_recipe_one_contribution, tmp_path): def test_save_results(build_recipe_one_contribution, tmp_path): - recipe = build_recipe_one_contribution() + recipe = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) actual_results_file = tmp_path / "fit_results.txt" @@ -147,7 +146,7 @@ def test_save_results(build_recipe_one_contribution, tmp_path): def test_get_results_dictionary(build_recipe_one_contribution): # Case: user gets results dictionary after optimization # expected: results dictionary contains expected keys and values - recipe = build_recipe_one_contribution() + recipe = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) actual_results_dict = results.get_results_dictionary() From 02b04430b8a267fbe48417fc78cd664458662996 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 2 Mar 2026 14:28:47 -0500 Subject: [PATCH 122/193] add assert recipes arent equal --- tests/test_fitrecipe.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index b19702c7..be3d2d2f 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -487,12 +487,12 @@ def optimize_recipe(recipe): leastsq(residuals, values) -def test_initialize_recipe_from_recipe(build_recipe_two_contributions): +def test_initialize_recipe_from_recipe(): # Case: User initializes a FitRecipe from a previously optimized fit # expected: recipe is initialized with everything: # contributions, profiles (contained in contributions), # variables, restraints, and constraints - recipe1 = build_recipe_two_contributions + recipe1 = build_recipe_for_init_testing() optimize_recipe(recipe1) expected_parameters_dict = recipe1._parameters expected_constraints_dict = recipe1._constraints @@ -504,6 +504,7 @@ def test_initialize_recipe_from_recipe(build_recipe_two_contributions): expected_profiles_list.append(expected_profile) recipe2 = FitRecipe() + assert recipe1 != recipe2 recipe2.initialize_recipe_with_recipe(recipe1) actual_parameters_dict = recipe2._parameters actual_constraints_dict = recipe2._constraints From 4c4b066fc7603c03190562d7f8b524211b3038da Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 2 Mar 2026 20:34:50 -0500 Subject: [PATCH 123/193] add fixture that returns two identical recipes --- tests/conftest.py | 29 +++++++++++++++++++++++++++++ tests/test_fitrecipe.py | 34 ++++------------------------------ 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index bd8efd7c..d2c499cb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -209,6 +209,35 @@ def build_recipe_two_contributions(): return recipe +@pytest.fixture(scope="function") +def build_two_recipes(): + x = linspace(0, pi, 11) + y = sin(x) + + profile1 = Profile() + profile1.set_observed_profile(x, y) + contribution1 = FitContribution("c1") + contribution1.set_profile(profile1) + contribution1.set_equation("amplitude*sin(wave_number*x + phase_shift)") + recipe1 = FitRecipe() + recipe1.add_contribution(contribution1) + recipe1.add_variable(contribution1.amplitude, 4) + recipe1.add_variable(contribution1.wave_number, 3) + recipe1.add_variable(contribution1.phase_shift, 2) + + profile2 = Profile() + profile2.set_observed_profile(x, y) + contribution2 = FitContribution("c2") + contribution2.set_profile(profile2) + contribution2.set_equation("amplitude*sin(wave_number*x + phase_shift)") + recipe2 = FitRecipe() + recipe2.add_contribution(contribution2) + recipe2.add_variable(contribution2.amplitude, 4) + recipe2.add_variable(contribution2.wave_number, 3) + recipe2.add_variable(contribution2.phase_shift, 2) + return recipe1, recipe2 + + @pytest.fixture def temp_data_files(tmp_path): """ diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index be3d2d2f..4cdc91ff 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -33,29 +33,6 @@ matplotlib.use("Agg") -def build_recipe_for_init_testing(): - """A helper to build a FitRecipe with one contribution and three - variables. - - This is identical to the build_recipe_one_contribution fixture, but - is a function instead of a fixture so we can call it to get unique - recipe objects in a singular test. - """ - profile = Profile() - x = linspace(0, pi, 11) - y = sin(x) - profile.set_observed_profile(x, y) - contribution = FitContribution("c1") - contribution.set_profile(profile) - contribution.set_equation("amplitude*sin(wave_number*x + phase_shift)") - recipe = FitRecipe() - recipe.add_contribution(contribution) - recipe.add_variable(contribution.amplitude, 4) - recipe.add_variable(contribution.wave_number, 3) - recipe.add_variable(contribution.phase_shift, 2) - return recipe - - class TestFitRecipe(unittest.TestCase): def setUp(self): @@ -487,12 +464,12 @@ def optimize_recipe(recipe): leastsq(residuals, values) -def test_initialize_recipe_from_recipe(): +def test_initialize_recipe_from_recipe(build_recipe_one_contribution): # Case: User initializes a FitRecipe from a previously optimized fit # expected: recipe is initialized with everything: # contributions, profiles (contained in contributions), # variables, restraints, and constraints - recipe1 = build_recipe_for_init_testing() + recipe1 = build_recipe_one_contribution optimize_recipe(recipe1) expected_parameters_dict = recipe1._parameters expected_constraints_dict = recipe1._constraints @@ -551,20 +528,17 @@ def test_initialize_recipe_from_recipe_bad(build_recipe_two_contributions): recipe2.initialize_recipe_with_recipe(recipe_bad) -def test_initialize_recipe_from_results_object(build_recipe_one_contribution): +def test_initialize_recipe_from_results_object(build_two_recipes): # Case: User initializes a FitRecipe from a FitResults object # expected: recipe is initialized with variables from previous fit # create unique recipe1 - recipe1 = build_recipe_for_init_testing() + recipe1, recipe2 = build_two_recipes optimize_recipe(recipe1) results1 = FitResults(recipe1) expected_values = np.round(results1.varvals, 5) expected_names = results1.varnames - # create unique recipe2 with same contributions - # and variables as recipe1 but not optimized yet - recipe2 = build_recipe_for_init_testing() assert recipe1 != recipe2 # create a new var that should be include in the initialized recipe recipe2.create_new_variable("extra_var", 5) From 70dbe784509a41b74556068727ec127c301d9158 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 3 Mar 2026 11:13:55 -0500 Subject: [PATCH 124/193] add second recipe to fixture build_recipe_one_contribution --- tests/conftest.py | 68 ++++++++++++++++------------------------ tests/test_fitrecipe.py | 28 ++++++++--------- tests/test_fitresults.py | 14 ++++----- 3 files changed, 48 insertions(+), 62 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index d2c499cb..37a1bfa4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -149,20 +149,35 @@ def _capturestdout(f, *args, **kwargs): @pytest.fixture(scope="function") def build_recipe_one_contribution(): - """Helper to build a simple recipe.""" - profile = Profile() + """Helper to build a simple recipe. + + Two identical recipes are returned if needed. + """ x = linspace(0, pi, 11) y = sin(x) - profile.set_observed_profile(x, y) - contribution = FitContribution("c1") - contribution.set_profile(profile) - contribution.set_equation("amplitude*sin(wave_number*x + phase_shift)") - recipe = FitRecipe() - recipe.add_contribution(contribution) - recipe.add_variable(contribution.amplitude, 4) - recipe.add_variable(contribution.wave_number, 3) - recipe.add_variable(contribution.phase_shift, 2) - return recipe + + profile1 = Profile() + profile1.set_observed_profile(x, y) + contribution1 = FitContribution("c1") + contribution1.set_profile(profile1) + contribution1.set_equation("amplitude*sin(wave_number*x + phase_shift)") + recipe1 = FitRecipe() + recipe1.add_contribution(contribution1) + recipe1.add_variable(contribution1.amplitude, 4) + recipe1.add_variable(contribution1.wave_number, 3) + recipe1.add_variable(contribution1.phase_shift, 2) + + profile2 = Profile() + profile2.set_observed_profile(x, y) + contribution2 = FitContribution("c2") + contribution2.set_profile(profile2) + contribution2.set_equation("amplitude*sin(wave_number*x + phase_shift)") + recipe2 = FitRecipe() + recipe2.add_contribution(contribution2) + recipe2.add_variable(contribution2.amplitude, 4) + recipe2.add_variable(contribution2.wave_number, 3) + recipe2.add_variable(contribution2.phase_shift, 2) + return recipe1, recipe2 @pytest.fixture(scope="function") @@ -209,35 +224,6 @@ def build_recipe_two_contributions(): return recipe -@pytest.fixture(scope="function") -def build_two_recipes(): - x = linspace(0, pi, 11) - y = sin(x) - - profile1 = Profile() - profile1.set_observed_profile(x, y) - contribution1 = FitContribution("c1") - contribution1.set_profile(profile1) - contribution1.set_equation("amplitude*sin(wave_number*x + phase_shift)") - recipe1 = FitRecipe() - recipe1.add_contribution(contribution1) - recipe1.add_variable(contribution1.amplitude, 4) - recipe1.add_variable(contribution1.wave_number, 3) - recipe1.add_variable(contribution1.phase_shift, 2) - - profile2 = Profile() - profile2.set_observed_profile(x, y) - contribution2 = FitContribution("c2") - contribution2.set_profile(profile2) - contribution2.set_equation("amplitude*sin(wave_number*x + phase_shift)") - recipe2 = FitRecipe() - recipe2.add_contribution(contribution2) - recipe2.add_variable(contribution2.amplitude, 4) - recipe2.add_variable(contribution2.wave_number, 3) - recipe2.add_variable(contribution2.phase_shift, 2) - return recipe1, recipe2 - - @pytest.fixture def temp_data_files(tmp_path): """ diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 4cdc91ff..46905030 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -469,7 +469,7 @@ def test_initialize_recipe_from_recipe(build_recipe_one_contribution): # expected: recipe is initialized with everything: # contributions, profiles (contained in contributions), # variables, restraints, and constraints - recipe1 = build_recipe_one_contribution + recipe1, _ = build_recipe_one_contribution optimize_recipe(recipe1) expected_parameters_dict = recipe1._parameters expected_constraints_dict = recipe1._constraints @@ -528,12 +528,12 @@ def test_initialize_recipe_from_recipe_bad(build_recipe_two_contributions): recipe2.initialize_recipe_with_recipe(recipe_bad) -def test_initialize_recipe_from_results_object(build_two_recipes): +def test_initialize_recipe_from_results_object(build_recipe_one_contribution): # Case: User initializes a FitRecipe from a FitResults object # expected: recipe is initialized with variables from previous fit # create unique recipe1 - recipe1, recipe2 = build_two_recipes + recipe1, recipe2 = build_recipe_one_contribution optimize_recipe(recipe1) results1 = FitResults(recipe1) expected_values = np.round(results1.varvals, 5) @@ -579,7 +579,7 @@ def test_initialize_recipe_from_results_file( expected_names = ["amplitude", "phase_shift", "wave_number"] expected_values = [1, 1, 0] - recipe = build_recipe_one_contribution + recipe, _ = build_recipe_one_contribution recipe.initialize_recipe_with_results(results_file) results = FitResults(recipe) actual_values = np.round(results.varvals, 5) @@ -595,7 +595,7 @@ def test_initialize_recipe_from_results_file_bad( # Case: User tries to initialize a recipe with something that # isn't a path, str, or FitResults object # Expected: raised ValueError with message - recipe = build_recipe_one_contribution + recipe, _ = build_recipe_one_contribution bad_input = 12345 # not a valid input type msg = ( "The input results must be a FitResults object or a path to a " @@ -689,7 +689,7 @@ def build_recipe_from_datafile_deprecated(datafile): def test_plot_recipe_bad_display(build_recipe_one_contribution): - recipe = build_recipe_one_contribution + recipe, _ = build_recipe_one_contribution # Case: All plots are disabled # expected: raised ValueError with message plt.close("all") @@ -719,7 +719,7 @@ def test_plot_recipe_before_refinement(capsys, build_recipe_one_contribution): # Case: User tries to plot recipe before refinement # expected: Data plotted without fit line or difference curve # and warning message printed - recipe = build_recipe_one_contribution + recipe, _ = build_recipe_one_contribution plt.close("all") before = set(plt.get_fignums()) # include fit_label="nothing" to make sure fit line is not plotted @@ -747,7 +747,7 @@ def test_plot_recipe_before_refinement(capsys, build_recipe_one_contribution): def test_plot_recipe_after_refinement(build_recipe_one_contribution): # Case: User refines recipe and then plots # expected: Plot generates with no problem - recipe = build_recipe_one_contribution + recipe, _ = build_recipe_one_contribution optimize_recipe(recipe) plt.close("all") before = set(plt.get_fignums()) @@ -784,7 +784,7 @@ def test_plot_recipe_two_contributions(build_recipe_two_contributions): def test_plot_recipe_on_existing_plot(build_recipe_one_contribution): # Case: User passes axes to plot_recipe to plot on existing figure # expected: User modifications are present in the final figure - recipe = build_recipe_one_contribution + recipe, _ = build_recipe_one_contribution optimize_recipe(recipe) plt.close("all") fig, ax = plt.subplots() @@ -804,7 +804,7 @@ def test_plot_recipe_on_existing_plot(build_recipe_one_contribution): def test_plot_recipe_add_new_data(build_recipe_one_contribution): # Case: User wants to add data to figure generated by plot_recipe # Expected: New data is added to existing figure (check with labels) - recipe = build_recipe_one_contribution + recipe, _ = build_recipe_one_contribution optimize_recipe(recipe) plt.close("all") before = set(plt.get_fignums()) @@ -848,7 +848,7 @@ def test_plot_recipe_add_new_data_two_figs(build_recipe_two_contributions): def test_plot_recipe_set_title(build_recipe_one_contribution): # Case: User sets title via plot_recipe # Expected: Title is set correctly - recipe = build_recipe_one_contribution + recipe, _ = build_recipe_one_contribution optimize_recipe(recipe) plt.close("all") expected_title = "Custom Recipe Title" @@ -862,7 +862,7 @@ def test_plot_recipe_set_title(build_recipe_one_contribution): def test_plot_recipe_set_defaults(build_recipe_one_contribution): # Case: user sets default plot options with set_plot_defaults # Expected: plot_recipe uses the default options for all calls - recipe = build_recipe_one_contribution + recipe, _ = build_recipe_one_contribution optimize_recipe(recipe) plt.close("all") # set new defaults @@ -890,7 +890,7 @@ def test_plot_recipe_set_defaults(build_recipe_one_contribution): def test_plot_recipe_set_defaults_bad(capsys, build_recipe_one_contribution): # Case: user tries to set kwargs that are not valid plot_recipe options # Expected: Plot is shown and warning is printed - recipe = build_recipe_one_contribution + recipe, _ = build_recipe_one_contribution optimize_recipe(recipe) plt.close("all") recipe.set_plot_defaults( @@ -1000,7 +1000,7 @@ def test_plot_recipe_reset_all_defaults(build_recipe_one_contribution): "show": True, } - recipe = build_recipe_one_contribution + recipe, _ = build_recipe_one_contribution optimize_recipe(recipe) plt.close("all") diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index d91a51ad..b5f18bc4 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -54,7 +54,7 @@ def optimize_recipe(recipe): def test_formatResults(build_recipe_one_contribution): - recipe = build_recipe_one_contribution + recipe, _ = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) actual_results_string = results.formatResults(header="My Custom header") @@ -67,7 +67,7 @@ def test_formatResults(build_recipe_one_contribution): def test_get_results_string(build_recipe_one_contribution): - recipe = build_recipe_one_contribution + recipe, _ = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) actual_results_string = results.get_results_string( @@ -82,7 +82,7 @@ def test_get_results_string(build_recipe_one_contribution): def test_printResults(build_recipe_one_contribution, capsys): - recipe = build_recipe_one_contribution + recipe, _ = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) results.printResults(header="My Custom header") @@ -96,7 +96,7 @@ def test_printResults(build_recipe_one_contribution, capsys): def test_print_results(build_recipe_one_contribution, capsys): - recipe = build_recipe_one_contribution + recipe, _ = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) results.print_results(header="My Custom header") @@ -110,7 +110,7 @@ def test_print_results(build_recipe_one_contribution, capsys): def test_saveResults(build_recipe_one_contribution, tmp_path): - recipe = build_recipe_one_contribution + recipe, _ = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) actual_results_file = tmp_path / "fit_results.txt" @@ -127,7 +127,7 @@ def test_saveResults(build_recipe_one_contribution, tmp_path): def test_save_results(build_recipe_one_contribution, tmp_path): - recipe = build_recipe_one_contribution + recipe, _ = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) actual_results_file = tmp_path / "fit_results.txt" @@ -146,7 +146,7 @@ def test_save_results(build_recipe_one_contribution, tmp_path): def test_get_results_dictionary(build_recipe_one_contribution): # Case: user gets results dictionary after optimization # expected: results dictionary contains expected keys and values - recipe = build_recipe_one_contribution + recipe, _ = build_recipe_one_contribution optimize_recipe(recipe) results = FitResults(recipe) actual_results_dict = results.get_results_dictionary() From 08478d4249aff58ee0561b9687171a1cad7e5f43 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 3 Mar 2026 15:50:07 -0500 Subject: [PATCH 125/193] change fixture name to be plural (build_recipes_one_contribution) --- tests/conftest.py | 2 +- tests/test_fitrecipe.py | 52 ++++++++++++++++++++-------------------- tests/test_fitresults.py | 28 +++++++++++----------- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 37a1bfa4..f6e58e7e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -148,7 +148,7 @@ def _capturestdout(f, *args, **kwargs): @pytest.fixture(scope="function") -def build_recipe_one_contribution(): +def build_recipes_one_contribution(): """Helper to build a simple recipe. Two identical recipes are returned if needed. diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 46905030..bc5cff21 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -464,12 +464,12 @@ def optimize_recipe(recipe): leastsq(residuals, values) -def test_initialize_recipe_from_recipe(build_recipe_one_contribution): +def test_initialize_recipe_from_recipe(build_recipes_one_contribution): # Case: User initializes a FitRecipe from a previously optimized fit # expected: recipe is initialized with everything: # contributions, profiles (contained in contributions), # variables, restraints, and constraints - recipe1, _ = build_recipe_one_contribution + recipe1, _ = build_recipes_one_contribution optimize_recipe(recipe1) expected_parameters_dict = recipe1._parameters expected_constraints_dict = recipe1._constraints @@ -528,12 +528,12 @@ def test_initialize_recipe_from_recipe_bad(build_recipe_two_contributions): recipe2.initialize_recipe_with_recipe(recipe_bad) -def test_initialize_recipe_from_results_object(build_recipe_one_contribution): +def test_initialize_recipe_from_results_object(build_recipes_one_contribution): # Case: User initializes a FitRecipe from a FitResults object # expected: recipe is initialized with variables from previous fit # create unique recipe1 - recipe1, recipe2 = build_recipe_one_contribution + recipe1, recipe2 = build_recipes_one_contribution optimize_recipe(recipe1) results1 = FitResults(recipe1) expected_values = np.round(results1.varvals, 5) @@ -571,7 +571,7 @@ def test_initialize_recipe_from_results_object(build_recipe_one_contribution): def test_initialize_recipe_from_results_file( - build_recipe_one_contribution, temp_data_files + build_recipes_one_contribution, temp_data_files ): # Case: User initializes a FitRecipe from a FitResults file # expected: recipe is initialized with variables from previous fit @@ -579,7 +579,7 @@ def test_initialize_recipe_from_results_file( expected_names = ["amplitude", "phase_shift", "wave_number"] expected_values = [1, 1, 0] - recipe, _ = build_recipe_one_contribution + recipe, _ = build_recipes_one_contribution recipe.initialize_recipe_with_results(results_file) results = FitResults(recipe) actual_values = np.round(results.varvals, 5) @@ -590,12 +590,12 @@ def test_initialize_recipe_from_results_file( def test_initialize_recipe_from_results_file_bad( - build_recipe_one_contribution, + build_recipes_one_contribution, ): # Case: User tries to initialize a recipe with something that # isn't a path, str, or FitResults object # Expected: raised ValueError with message - recipe, _ = build_recipe_one_contribution + recipe, _ = build_recipes_one_contribution bad_input = 12345 # not a valid input type msg = ( "The input results must be a FitResults object or a path to a " @@ -688,8 +688,8 @@ def build_recipe_from_datafile_deprecated(datafile): return recipe -def test_plot_recipe_bad_display(build_recipe_one_contribution): - recipe, _ = build_recipe_one_contribution +def test_plot_recipe_bad_display(build_recipes_one_contribution): + recipe, _ = build_recipes_one_contribution # Case: All plots are disabled # expected: raised ValueError with message plt.close("all") @@ -715,11 +715,11 @@ def test_plot_recipe_no_contribution(): recipe.plot_recipe() -def test_plot_recipe_before_refinement(capsys, build_recipe_one_contribution): +def test_plot_recipe_before_refinement(capsys, build_recipes_one_contribution): # Case: User tries to plot recipe before refinement # expected: Data plotted without fit line or difference curve # and warning message printed - recipe, _ = build_recipe_one_contribution + recipe, _ = build_recipes_one_contribution plt.close("all") before = set(plt.get_fignums()) # include fit_label="nothing" to make sure fit line is not plotted @@ -744,10 +744,10 @@ def test_plot_recipe_before_refinement(capsys, build_recipe_one_contribution): assert actual == expected -def test_plot_recipe_after_refinement(build_recipe_one_contribution): +def test_plot_recipe_after_refinement(build_recipes_one_contribution): # Case: User refines recipe and then plots # expected: Plot generates with no problem - recipe, _ = build_recipe_one_contribution + recipe, _ = build_recipes_one_contribution optimize_recipe(recipe) plt.close("all") before = set(plt.get_fignums()) @@ -781,10 +781,10 @@ def test_plot_recipe_two_contributions(build_recipe_two_contributions): assert len(new_figs) == 2 -def test_plot_recipe_on_existing_plot(build_recipe_one_contribution): +def test_plot_recipe_on_existing_plot(build_recipes_one_contribution): # Case: User passes axes to plot_recipe to plot on existing figure # expected: User modifications are present in the final figure - recipe, _ = build_recipe_one_contribution + recipe, _ = build_recipes_one_contribution optimize_recipe(recipe) plt.close("all") fig, ax = plt.subplots() @@ -801,10 +801,10 @@ def test_plot_recipe_on_existing_plot(build_recipe_one_contribution): assert actual_title == expected_title -def test_plot_recipe_add_new_data(build_recipe_one_contribution): +def test_plot_recipe_add_new_data(build_recipes_one_contribution): # Case: User wants to add data to figure generated by plot_recipe # Expected: New data is added to existing figure (check with labels) - recipe, _ = build_recipe_one_contribution + recipe, _ = build_recipes_one_contribution optimize_recipe(recipe) plt.close("all") before = set(plt.get_fignums()) @@ -845,10 +845,10 @@ def test_plot_recipe_add_new_data_two_figs(build_recipe_two_contributions): assert len(new_figs) == 2 -def test_plot_recipe_set_title(build_recipe_one_contribution): +def test_plot_recipe_set_title(build_recipes_one_contribution): # Case: User sets title via plot_recipe # Expected: Title is set correctly - recipe, _ = build_recipe_one_contribution + recipe, _ = build_recipes_one_contribution optimize_recipe(recipe) plt.close("all") expected_title = "Custom Recipe Title" @@ -859,10 +859,10 @@ def test_plot_recipe_set_title(build_recipe_one_contribution): assert actual_title == expected_title -def test_plot_recipe_set_defaults(build_recipe_one_contribution): +def test_plot_recipe_set_defaults(build_recipes_one_contribution): # Case: user sets default plot options with set_plot_defaults # Expected: plot_recipe uses the default options for all calls - recipe, _ = build_recipe_one_contribution + recipe, _ = build_recipes_one_contribution optimize_recipe(recipe) plt.close("all") # set new defaults @@ -887,10 +887,10 @@ def test_plot_recipe_set_defaults(build_recipe_one_contribution): assert actual_labels == expected_labels -def test_plot_recipe_set_defaults_bad(capsys, build_recipe_one_contribution): +def test_plot_recipe_set_defaults_bad(capsys, build_recipes_one_contribution): # Case: user tries to set kwargs that are not valid plot_recipe options # Expected: Plot is shown and warning is printed - recipe, _ = build_recipe_one_contribution + recipe, _ = build_recipes_one_contribution optimize_recipe(recipe) plt.close("all") recipe.set_plot_defaults( @@ -971,7 +971,7 @@ def test_plot_recipe_labels_from_gr_file_overwrite_deprecated(temp_data_files): assert actual_ylabel == expected_ylabel -def test_plot_recipe_reset_all_defaults(build_recipe_one_contribution): +def test_plot_recipe_reset_all_defaults(build_recipes_one_contribution): expected_defaults = { "show_observed": True, "show_fit": True, @@ -1000,7 +1000,7 @@ def test_plot_recipe_reset_all_defaults(build_recipe_one_contribution): "show": True, } - recipe, _ = build_recipe_one_contribution + recipe, _ = build_recipes_one_contribution optimize_recipe(recipe) plt.close("all") diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index b5f18bc4..d9be7317 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -53,8 +53,8 @@ def optimize_recipe(recipe): leastsq(residuals, values) -def test_formatResults(build_recipe_one_contribution): - recipe, _ = build_recipe_one_contribution +def test_formatResults(build_recipes_one_contribution): + recipe, _ = build_recipes_one_contribution optimize_recipe(recipe) results = FitResults(recipe) actual_results_string = results.formatResults(header="My Custom header") @@ -66,8 +66,8 @@ def test_formatResults(build_recipe_one_contribution): assert expected_var in actual_results_string.strip() -def test_get_results_string(build_recipe_one_contribution): - recipe, _ = build_recipe_one_contribution +def test_get_results_string(build_recipes_one_contribution): + recipe, _ = build_recipes_one_contribution optimize_recipe(recipe) results = FitResults(recipe) actual_results_string = results.get_results_string( @@ -81,8 +81,8 @@ def test_get_results_string(build_recipe_one_contribution): assert expected_var in actual_results_string.strip() -def test_printResults(build_recipe_one_contribution, capsys): - recipe, _ = build_recipe_one_contribution +def test_printResults(build_recipes_one_contribution, capsys): + recipe, _ = build_recipes_one_contribution optimize_recipe(recipe) results = FitResults(recipe) results.printResults(header="My Custom header") @@ -95,8 +95,8 @@ def test_printResults(build_recipe_one_contribution, capsys): assert expected_var in actual_results.strip() -def test_print_results(build_recipe_one_contribution, capsys): - recipe, _ = build_recipe_one_contribution +def test_print_results(build_recipes_one_contribution, capsys): + recipe, _ = build_recipes_one_contribution optimize_recipe(recipe) results = FitResults(recipe) results.print_results(header="My Custom header") @@ -109,8 +109,8 @@ def test_print_results(build_recipe_one_contribution, capsys): assert expected_var in actual_results.strip() -def test_saveResults(build_recipe_one_contribution, tmp_path): - recipe, _ = build_recipe_one_contribution +def test_saveResults(build_recipes_one_contribution, tmp_path): + recipe, _ = build_recipes_one_contribution optimize_recipe(recipe) results = FitResults(recipe) actual_results_file = tmp_path / "fit_results.txt" @@ -126,8 +126,8 @@ def test_saveResults(build_recipe_one_contribution, tmp_path): assert expected_var in actual_results.strip() -def test_save_results(build_recipe_one_contribution, tmp_path): - recipe, _ = build_recipe_one_contribution +def test_save_results(build_recipes_one_contribution, tmp_path): + recipe, _ = build_recipes_one_contribution optimize_recipe(recipe) results = FitResults(recipe) actual_results_file = tmp_path / "fit_results.txt" @@ -143,10 +143,10 @@ def test_save_results(build_recipe_one_contribution, tmp_path): assert expected_var in actual_results.strip() -def test_get_results_dictionary(build_recipe_one_contribution): +def test_get_results_dictionary(build_recipes_one_contribution): # Case: user gets results dictionary after optimization # expected: results dictionary contains expected keys and values - recipe, _ = build_recipe_one_contribution + recipe, _ = build_recipes_one_contribution optimize_recipe(recipe) results = FitResults(recipe) actual_results_dict = results.get_results_dictionary() From 2453e1abb7d7d7e50f112833e71e7e58bb9553b3 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 5 Mar 2026 09:47:23 -0500 Subject: [PATCH 126/193] rm deprecated six and other deprecated python2 objects --- src/diffpy/srfit/equation/literals/abcs.py | 72 +++++++++++++++++----- 1 file changed, 57 insertions(+), 15 deletions(-) diff --git a/src/diffpy/srfit/equation/literals/abcs.py b/src/diffpy/srfit/equation/literals/abcs.py index 605bc53e..8468f419 100644 --- a/src/diffpy/srfit/equation/literals/abcs.py +++ b/src/diffpy/srfit/equation/literals/abcs.py @@ -16,14 +16,10 @@ __all__ = ["LiteralABC", "ArgumentABC", "OperatorABC"] +from abc import ABC, abstractmethod -from abc import ABCMeta, abstractmethod, abstractproperty -import six - - -@six.add_metaclass(ABCMeta) -class LiteralABC(object): +class LiteralABC(ABC): """Abstract Base Class for Literal. See Literal for usage. @@ -31,13 +27,19 @@ class LiteralABC(object): @abstractmethod def identify(self, visitor): + """Identify this literal using a visitor.""" pass @abstractmethod def getValue(self): + """Return the value of the literal.""" pass - name = abstractproperty(None, None) + @property + @abstractmethod + def name(self): + """Name of the literal.""" + pass # End class LiteralABC @@ -51,10 +53,20 @@ class ArgumentABC(LiteralABC): @abstractmethod def setValue(self, value): + """Set the value of the argument.""" pass - const = abstractproperty(None, None) - value = abstractproperty(None, None) + @property + @abstractmethod + def const(self): + """Whether the argument is constant.""" + pass + + @property + @abstractmethod + def value(self): + """Value of the argument.""" + pass # End class ArgumentABC @@ -68,14 +80,44 @@ class OperatorABC(LiteralABC): @abstractmethod def addLiteral(self, literal): + """Add a literal argument to the operator.""" + pass + + @property + @abstractmethod + def args(self): + """Arguments of the operator.""" + pass + + @property + @abstractmethod + def nin(self): + """Number of input arguments.""" pass - args = abstractproperty(None, None) - nin = abstractproperty(None, None) - nout = abstractproperty(None, None) - operation = abstractproperty(None, None) - symbol = abstractproperty(None, None) - value = abstractproperty(None, None) + @property + @abstractmethod + def nout(self): + """Number of outputs.""" + pass + + @property + @abstractmethod + def operation(self): + """Callable implementing the operator.""" + pass + + @property + @abstractmethod + def symbol(self): + """Symbol representing the operator.""" + pass + + @property + @abstractmethod + def value(self): + """Value produced by the operator.""" + pass # End class OperatorABC From c4c0b104a38571a4a397c2a0776fdd2907cabc51 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 5 Mar 2026 10:56:35 -0500 Subject: [PATCH 127/193] setValue deprecation --- docs/source/extending.rst | 2 +- src/diffpy/srfit/equation/equationmod.py | 8 +- src/diffpy/srfit/equation/literals/abcs.py | 2 +- .../srfit/equation/literals/argument.py | 8 +- src/diffpy/srfit/fitbase/constraint.py | 4 +- src/diffpy/srfit/fitbase/fitrecipe.py | 8 +- src/diffpy/srfit/fitbase/parameter.py | 38 ++++--- src/diffpy/srfit/fitbase/profile.py | 8 +- src/diffpy/srfit/interface/interface.py | 2 +- src/diffpy/srfit/pdf/basepdfgenerator.py | 2 +- src/diffpy/srfit/sas/sasparameter.py | 6 +- src/diffpy/srfit/structure/objcrystparset.py | 22 ++--- tests/test_builder.py | 12 +-- tests/test_constraint.py | 4 +- tests/test_contribution.py | 8 +- tests/test_diffpyparset.py | 10 +- tests/test_equation.py | 20 ++-- tests/test_fitrecipe.py | 24 ++--- tests/test_literals.py | 12 +-- tests/test_objcrystparset.py | 16 +-- tests/test_parameter.py | 14 +-- tests/test_pdf.py | 4 +- tests/test_recipeorganizer.py | 24 ++--- tests/test_restraint.py | 14 +-- tests/test_sas.py | 4 +- tests/test_speed.py | 98 +++++++++---------- tests/test_visitors.py | 18 ++-- tests/test_weakrefcallable.py | 4 +- 28 files changed, 206 insertions(+), 190 deletions(-) diff --git a/docs/source/extending.rst b/docs/source/extending.rst index 582add1d..164ef187 100644 --- a/docs/source/extending.rst +++ b/docs/source/extending.rst @@ -108,7 +108,7 @@ can be adapted as:: setter = SimpleAtom.set, attr = "x") Thus, when ``xpar.getValue()`` is called, it in turn calls -``SimpleAtom.get(atom, "x")``. ``xpar.setValue(value)`` calls +``SimpleAtom.get(atom, "x")``. ``xpar.set_value(value)`` calls ``SimpleAtom.set(atom, "x", value)``. If the attributes of an object cannot be accessed in one of these three ways, diff --git a/src/diffpy/srfit/equation/equationmod.py b/src/diffpy/srfit/equation/equationmod.py index dd8293ec..4a40aeb7 100644 --- a/src/diffpy/srfit/equation/equationmod.py +++ b/src/diffpy/srfit/equation/equationmod.py @@ -25,8 +25,8 @@ these! > b = Argument(name="b") > add.addLiteral(a) > add.addLiteral(b) > # make an Equation instance and pass the root > eq = Equation(root = add) > eq(a=3, b=4) # returns 7 > eq(a=2) # remembers b=4, returns 6 > -eq.a.setValue(-3) > eq.b.setValue(3) > eq() # uses last assignment of a -and b, returns 0 +eq.a.set_value(-3) > eq.b.set_value(3) > eq() # uses last assignment of +a and b, returns 0 See the class documentation for more information. """ @@ -193,14 +193,14 @@ def __call__(self, *args, **kw): if idx >= len(self.argdict): raise ValueError("Too many arguments") arg = self.args[idx] - arg.setValue(val) + arg.set_value(val) # Process kw for name, val in kw.items(): arg = self.argdict.get(name) if arg is None: raise ValueError("No argument named '%s' here" % name) - arg.setValue(val) + arg.set_value(val) self._value = self.root.getValue() return self._value diff --git a/src/diffpy/srfit/equation/literals/abcs.py b/src/diffpy/srfit/equation/literals/abcs.py index 8468f419..82c633cc 100644 --- a/src/diffpy/srfit/equation/literals/abcs.py +++ b/src/diffpy/srfit/equation/literals/abcs.py @@ -52,7 +52,7 @@ class ArgumentABC(LiteralABC): """ @abstractmethod - def setValue(self, value): + def set_value(self, value): """Set the value of the argument.""" pass diff --git a/src/diffpy/srfit/equation/literals/argument.py b/src/diffpy/srfit/equation/literals/argument.py index 60d639f2..a99fb7f1 100644 --- a/src/diffpy/srfit/equation/literals/argument.py +++ b/src/diffpy/srfit/equation/literals/argument.py @@ -37,9 +37,9 @@ class Argument(Literal, ArgumentABC): A flag indicating whether this is considered a constant. Constants may be given special treatment by the Visitors. _value - The value of the Argument. Modified with 'setValue'. + The value of the Argument. Modified with 'set_value'. value - Property for 'getValue' and 'setValue'. + Property for 'getValue' and 'set_value'. """ const = None @@ -59,7 +59,7 @@ def getValue(self): """Get the value of this Literal.""" return self._value - def setValue(self, val): + def set_value(self, val): """Set the value of the Literal. Attributes @@ -77,7 +77,7 @@ def setValue(self, val): return value = property( - lambda self: self.getValue(), lambda self, val: self.setValue(val) + lambda self: self.getValue(), lambda self, val: self.set_value(val) ) diff --git a/src/diffpy/srfit/fitbase/constraint.py b/src/diffpy/srfit/fitbase/constraint.py index 68171548..b0a89d19 100644 --- a/src/diffpy/srfit/fitbase/constraint.py +++ b/src/diffpy/srfit/fitbase/constraint.py @@ -82,7 +82,7 @@ def update(self): val = self.eq() # This will only change the Parameter if val is different from the # currently stored value. - self.par.setValue(val) + self.par.set_value(val) return def _validate(self): @@ -107,7 +107,7 @@ def _validate(self): # Try to get the value of eq. try: val = self.eq() - self.par.setValue(val) + self.par.set_value(val) except TypeError: raise SrFitError("eq cannot be evaluated") finally: diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 0aff6ecd..2ebaa777 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -759,7 +759,7 @@ def add_variable( raise ValueError("The parameter '%s' is constrained" % par) var = ParameterProxy(name, par) if value is not None: - var.setValue(value) + var.set_value(value) self._add_parameter(var) if fixed: self.fix(var) @@ -1185,7 +1185,7 @@ def constrain(self, par, con, ns={}): val = con.getValue() if val is None: val = par.getValue() - con.setValue(val) + con.set_value(val) if par in self._parameters.values(): self.fix(par) @@ -1352,7 +1352,7 @@ def _set_parameters_from_dict(self, params_dict): parameter names and values.""" for param_name, param_value in params_dict.items(): if param_name in self._parameters: - self._parameters[param_name].setValue(param_value) + self._parameters[param_name].set_value(param_value) else: print( f"Warning: Parameter '{param_name}' from results " @@ -1742,7 +1742,7 @@ def _apply_values(self, p): return vargen = (v for v in self._parameters.values() if self.is_free(v)) for var, pval in zip(vargen, p): - var.setValue(pval) + var.set_value(pval) return def _update_configuration(self): diff --git a/src/diffpy/srfit/fitbase/parameter.py b/src/diffpy/srfit/fitbase/parameter.py index d7887f7d..1c7450d7 100644 --- a/src/diffpy/srfit/fitbase/parameter.py +++ b/src/diffpy/srfit/fitbase/parameter.py @@ -34,6 +34,13 @@ from diffpy.srfit.interface import _parameter_interface from diffpy.srfit.util.argbinders import bind2nd from diffpy.srfit.util.nameutils import validateName +from diffpy.utils._deprecator import build_deprecation_message, deprecated + +parameter_base = "diffpy.srfit.fitbase.Parameter" +removal_version = "4.0.0" +setValue_dep_msg = build_deprecation_message( + parameter_base, "setValue", "set_value", removal_version +) class Parameter(_parameter_interface, Argument, Validatable): @@ -46,9 +53,9 @@ class Parameter(_parameter_interface, Argument, Validatable): const A flag indicating whether this is considered a constant. _value - The value of the Parameter. Modified with 'setValue'. + The value of the Parameter. Modified with 'set_value'. value - Property for 'getValue' and 'setValue'. + Property for 'getValue' and 'set_value'. constrained A flag indicating if the Parameter is constrained (default False). @@ -81,7 +88,7 @@ def __init__(self, name, value=None, const=False): Argument.__init__(self, name, value, const) return - def setValue(self, val): + def set_value(self, val): """Set the value of the Parameter and the bounds. Attributes @@ -100,9 +107,18 @@ def setValue(self, val): self Returns self so that mutators can be chained. """ - Argument.setValue(self, val) + Argument.set_value(self, val) return self + @deprecated(setValue_dep_msg) + def setValue(self, val): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use diffpy.srfit.fitbase.Parameter.set_value instead. + """ + return self.set_value(val) + def setConst(self, const=True, value=None): """Toggle the Parameter as constant. @@ -123,7 +139,7 @@ def setConst(self, const=True, value=None): """ self.const = bool(const) if value is not None: - self.setValue(value) + self.set_value(value) return self def boundRange(self, lb=None, ub=None): @@ -254,9 +270,9 @@ def _observers(self): # wrap Parameter methods to use the target object ------------------------ - @wraps(Parameter.setValue) - def setValue(self, val): - return self.par.setValue(val) + @wraps(Parameter.set_value) + def set_value(self, val): + return self.par.set_value(val) @wraps(Parameter.getValue) def getValue(self): @@ -293,8 +309,8 @@ def _validate(self): class ParameterAdapter(Parameter): """An adapter for parameter-like objects. - This class wraps an object as a Parameter. The getValue and setValue - methods defer to the data of the wrapped object. + This class wraps an object as a Parameter. The getValue and + set_value methods defer to the data of the wrapped object. """ def __init__(self, name, obj, getter=None, setter=None, attr=None): @@ -359,7 +375,7 @@ def getValue(self): """Get the value of the Parameter.""" return self.getter(self.obj) - def setValue(self, value): + def set_value(self, value): """Set the value of the Parameter.""" if value != self.getValue(): self.setter(self.obj, value) diff --git a/src/diffpy/srfit/fitbase/profile.py b/src/diffpy/srfit/fitbase/profile.py index ae4e896b..684a0313 100644 --- a/src/diffpy/srfit/fitbase/profile.py +++ b/src/diffpy/srfit/fitbase/profile.py @@ -136,19 +136,19 @@ def __init__(self): # 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), + lambda self, val: self.xpar.set_value(val), ) y = property( lambda self: self.ypar.getValue(), - lambda self, val: self.ypar.setValue(val), + lambda self, val: self.ypar.set_value(val), ) dy = property( lambda self: self.dypar.getValue(), - lambda self, val: self.dypar.setValue(val), + lambda self, val: self.dypar.set_value(val), ) ycalc = property( lambda self: self.ycpar.getValue(), - lambda self, val: self.ycpar.setValue(val), + lambda self, val: self.ycpar.set_value(val), ) # We want xobs, yobs and dyobs to be read-only diff --git a/src/diffpy/srfit/interface/interface.py b/src/diffpy/srfit/interface/interface.py index 71e1b20e..308e0471 100644 --- a/src/diffpy/srfit/interface/interface.py +++ b/src/diffpy/srfit/interface/interface.py @@ -36,7 +36,7 @@ class ParameterInterface(object): """Mix-in class for enhancing the Parameter interface.""" def __lshift__(self, v): - """SetValue with << + """set_value with << Think of '<<' as injecting a value diff --git a/src/diffpy/srfit/pdf/basepdfgenerator.py b/src/diffpy/srfit/pdf/basepdfgenerator.py index 9b915be7..d19005cf 100644 --- a/src/diffpy/srfit/pdf/basepdfgenerator.py +++ b/src/diffpy/srfit/pdf/basepdfgenerator.py @@ -174,7 +174,7 @@ def processMetaData(self): val = self.meta.get(name) if val is not None: par = self.get(name) - par.setValue(val) + par.set_value(val) return diff --git a/src/diffpy/srfit/sas/sasparameter.py b/src/diffpy/srfit/sas/sasparameter.py index ad3d9895..28ae4834 100644 --- a/src/diffpy/srfit/sas/sasparameter.py +++ b/src/diffpy/srfit/sas/sasparameter.py @@ -33,9 +33,9 @@ class SASParameter(Parameter): const A flag indicating whether this is considered a constant. _value - The value of the Parameter. Modified with 'setValue'. + The value of the Parameter. Modified with 'set_value'. value - Property for 'getValue' and 'setValue'. + Property for 'getValue' and 'set_value'. constrained A flag indicating if the Parameter is constrained (default False). @@ -73,7 +73,7 @@ def getValue(self): value = self._model.getParam(self._parname) return value - def setValue(self, value): + def set_value(self, value): """Set the value of the Parameter.""" if value != self.getValue(): self._model.setParam(self._parname, value) diff --git a/src/diffpy/srfit/structure/objcrystparset.py b/src/diffpy/srfit/structure/objcrystparset.py index 62995ee6..f50650b6 100644 --- a/src/diffpy/srfit/structure/objcrystparset.py +++ b/src/diffpy/srfit/structure/objcrystparset.py @@ -1153,7 +1153,7 @@ def __init__(self, name, value=None, const=False): Parameter.__init__(self, name, value, const) self.keepcenter = True - def setValue(self, val): + def set_value(self, val): """Change the value of the Parameter.""" curval = self.getValue() val = float(val) @@ -1166,7 +1166,7 @@ def setValue(self, val): self.mode.Stretch(delta, self.keepcenter) # Let Parameter take care of the general details - Parameter.setValue(self, val) + Parameter.set_value(self, val) return self @@ -1268,9 +1268,9 @@ class ObjCrystBondLengthParameter(StretchModeParameter): const A flag indicating whether this is considered a constant. _value - The value of the Parameter. Modified with 'setValue'. + The value of the Parameter. Modified with 'set_value'. value - Property for 'getValue' and 'setValue'. + Property for 'getValue' and 'set_value'. constraint A callable that calculates the value of this Parameter. If this is None (None), the the Parameter is responsible for its @@ -1363,7 +1363,7 @@ def getValue(self): """ if self._value is None: val = GetBondLength(self.atom1.scat, self.atom2.scat) - Parameter.setValue(self, val) + Parameter.set_value(self, val) return self._value @@ -1406,9 +1406,9 @@ class ObjCrystBondAngleParameter(StretchModeParameter): const A flag indicating whether this is considered a constant. _value - The value of the Parameter. Modified with 'setValue'. + The value of the Parameter. Modified with 'set_value'. value - Property for 'getValue' and 'setValue'. + Property for 'getValue' and 'set_value'. constraint A callable that calculates the value of this Parameter. If this is None (None), the the Parameter is responsible for its @@ -1509,7 +1509,7 @@ def getValue(self): val = GetBondAngle( self.atom1.scat, self.atom2.scat, self.atom3.scat ) - Parameter.setValue(self, val) + Parameter.set_value(self, val) return self._value @@ -1557,9 +1557,9 @@ class ObjCrystDihedralAngleParameter(StretchModeParameter): const A flag indicating whether this is considered a constant. _value - The value of the Parameter. Modified with 'setValue'. + The value of the Parameter. Modified with 'set_value'. value - Property for 'getValue' and 'setValue'. + Property for 'getValue' and 'set_value'. constraint A callable that calculates the value of this Parameter. If this is None (None), the the Parameter is responsible for its @@ -1676,7 +1676,7 @@ def getValue(self): self.atom3.scat, self.atom4.scat, ) - Parameter.setValue(self, val) + Parameter.set_value(self, val) return self._value diff --git a/tests/test_builder.py b/tests/test_builder.py index da1f56f6..0cdf6d20 100644 --- a/tests/test_builder.py +++ b/tests/test_builder.py @@ -153,10 +153,10 @@ def testParseEquation(noObserversInGlobalBuilders): x = numpy.pi B = 4.0 C = 2.0 - eq.A.setValue(A) - eq.x.setValue(x) - eq.B.setValue(B) - eq.C.setValue(C) + eq.A.set_value(A) + eq.x.set_value(x) + eq.B.set_value(B) + eq.C.set_value(C) assert numpy.array_equal(eq(), f_equation(A, x, B, C)) # Make sure that the arguments of eq are listed in the order in which @@ -167,8 +167,8 @@ def testParseEquation(noObserversInGlobalBuilders): eq = factory.makeEquation("sqrt(e**(-0.5*(x/sigma)**2))") x = numpy.arange(0, 1, 0.05) sigma = 0.1 - eq.x.setValue(x) - eq.sigma.setValue(sigma) + eq.x.set_value(x) + eq.sigma.set_value(sigma) assert numpy.allclose(eq(), gaussian_test(x, sigma)) assert eq.args == [eq.x, eq.sigma] diff --git a/tests/test_constraint.py b/tests/test_constraint.py index 5c41689f..00da5b14 100644 --- a/tests/test_constraint.py +++ b/tests/test_constraint.py @@ -50,11 +50,11 @@ def testConstraint(self): eq3 = equationFromString("p1", factory) self.assertRaises(ValueError, c2.constrain, p2, eq3) - p2.setValue(2.5) + p2.set_value(2.5) c.update() self.assertEqual(5.0, p1.getValue()) - p2.setValue(8.1) + p2.set_value(8.1) self.assertEqual(5.0, p1.getValue()) c.update() self.assertEqual(16.2, p1.getValue()) diff --git a/tests/test_contribution.py b/tests/test_contribution.py index ef388b6b..e30bf7c4 100644 --- a/tests/test_contribution.py +++ b/tests/test_contribution.py @@ -198,7 +198,7 @@ def test_registerFunction(self): fc = self.fitcontribution fc.registerFunction(_fsquare, name="fsquare") fc.set_equation("fsquare") - fc.x.setValue(5) + fc.x.set_value(5) self.assertEqual(25, fc.evaluate()) fc.x << 6 self.assertEqual(36, fc.evaluate()) @@ -257,7 +257,7 @@ def testResidual(noObserversInGlobalBuilders): assert dot(chiv, chiv) == pytest.approx(dot(yobs, yobs)) # Try something more complex - c.setValue(3) + c.set_value(3) fc.set_equation("c**2*sin(I)") assert fc._eq._value is None assert fc._reseq._value is None @@ -300,7 +300,7 @@ def test_setEquation(noObserversInGlobalBuilders): """Check replacement of removed parameters.""" fc = FitContribution("test") fc.setEquation("x + 5") - fc.x.setValue(2) + fc.x.set_value(2) assert 7 == fc.evaluate() fc.removeParameter(fc.x) x = arange(0, 10, 0.5) @@ -314,7 +314,7 @@ def test_set_equation(noObserversInGlobalBuilders): """Check replacement of removed parameters.""" fc = FitContribution("test") fc.set_equation("x + 5") - fc.x.setValue(2) + fc.x.set_value(2) assert 7 == fc.evaluate() fc.removeParameter(fc.x) x = arange(0, 10, 0.5) diff --git a/tests/test_diffpyparset.py b/tests/test_diffpyparset.py index 8463d80d..2e523d35 100644 --- a/tests/test_diffpyparset.py +++ b/tests/test_diffpyparset.py @@ -90,12 +90,12 @@ def _testLattice(): _testLattice() # Now change values from the srfit DiffpyStructureParSet - s.Cu0.x.setValue(0.456) - s.Cu0.U22.setValue(0.441) - s.Cu0.B13.setValue(0.550) + s.Cu0.x.set_value(0.456) + s.Cu0.U22.set_value(0.441) + s.Cu0.B13.set_value(0.550) d = dsstru.lattice.dist(a1.xyz, a2.xyz) - s.lattice.b.setValue(4.6) - s.lattice.alpha.setValue(91.3) + s.lattice.b.set_value(4.6) + s.lattice.alpha.set_value(91.3) _testAtoms() _testLattice() # Make sure the distance changed diff --git a/tests/test_equation.py b/tests/test_equation.py index ff44a3d8..c4bc7cd8 100644 --- a/tests/test_equation.py +++ b/tests/test_equation.py @@ -46,11 +46,11 @@ def testSimpleFunction(make_args, noObserversInGlobalBuilders): # Set the values of the variables. # The equation should evaluate to 2.5*(1+3)*(4-2) = 20 - v1.setValue(1) - v2.setValue(2) - v3.setValue(3) - v4.setValue(4) - c.setValue(2.5) + v1.set_value(1) + v2.set_value(2) + v3.set_value(3) + v4.set_value(4) + c.set_value(2.5) # Make an equation and test eq = Equation("eq", mult2) @@ -135,11 +135,11 @@ def testEmbeddedEquation(make_args, noObserversInGlobalBuilders): # Set the values of the variables. # The equation should evaluate to 2.5*(1+3)*(4-2) = 20 - v1.setValue(1) - v2.setValue(2) - v3.setValue(3) - v4.setValue(4) - c.setValue(2.5) + v1.set_value(1) + v2.set_value(2) + v3.set_value(3) + v4.set_value(4) + c.set_value(2.5) # Make an equation and test root = Equation("root", mult2) diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index bc5cff21..4c928431 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -49,9 +49,9 @@ def setUp(self): self.fitcontribution = FitContribution("cont") self.fitcontribution.set_profile(self.profile) self.fitcontribution.set_equation("A*sin(k*x + c)") - self.fitcontribution.A.setValue(1) - self.fitcontribution.k.setValue(1) - self.fitcontribution.c.setValue(0) + self.fitcontribution.A.set_value(1) + self.fitcontribution.k.set_value(1) + self.fitcontribution.c.set_value(0) self.recipe.add_contribution(self.fitcontribution) return @@ -208,7 +208,7 @@ 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) - self.recipe.cont.c.setValue(1) + self.recipe.cont.c.set_value(1) res = self.recipe.residual() self.assertTrue(array_equal(y - self.profile.y, res)) @@ -241,7 +241,7 @@ def testResidual(self): # Clear the constraint and restore the value of c to 0. This should # give us chi2 = 0 again. self.recipe.unconstrain(self.fitcontribution.c) - self.fitcontribution.c.setValue(0) + self.fitcontribution.c.set_value(0) res = self.recipe.residual([self.recipe.cont.A.getValue()]) chi2 = 0 self.assertAlmostEqual(chi2, dot(res, res)) @@ -276,7 +276,7 @@ def testResidual(self): self.fitcontribution.unrestrain(r1) self.recipe._ready = False self.fitcontribution.unconstrain(self.fitcontribution.c) - self.fitcontribution.c.setValue(0) + self.fitcontribution.c.set_value(0) res = self.recipe.residual() chi2 = 0 self.assertAlmostEqual(chi2, dot(res, res)) @@ -354,9 +354,9 @@ def testPrintFitHook(capturestdout): fitcontribution = FitContribution("cont") fitcontribution.set_profile(profile) fitcontribution.set_equation("A*sin(k*x + c)") - fitcontribution.A.setValue(1) - fitcontribution.k.setValue(1) - fitcontribution.c.setValue(0) + fitcontribution.A.set_value(1) + fitcontribution.k.set_value(1) + fitcontribution.c.set_value(0) recipe.addContribution(fitcontribution) @@ -430,9 +430,9 @@ def test_add_contribution(capturestdout): fitcontribution = FitContribution("cont") fitcontribution.set_profile(profile) fitcontribution.set_equation("A*sin(k*x + c)") - fitcontribution.A.setValue(1) - fitcontribution.k.setValue(1) - fitcontribution.c.setValue(0) + fitcontribution.A.set_value(1) + fitcontribution.k.set_value(1) + fitcontribution.c.set_value(0) recipe.add_contribution(fitcontribution) diff --git a/tests/test_literals.py b/tests/test_literals.py index 8155d64a..970a2702 100644 --- a/tests/test_literals.py +++ b/tests/test_literals.py @@ -49,10 +49,10 @@ def testValue(self): self.assertEqual(None, a.getValue()) # Test setting value - a.setValue(3.14) + a.set_value(3.14) self.assertAlmostEqual(3.14, a._value) - a.setValue(3.14) + a.set_value(3.14) self.assertAlmostEqual(3.14, a.value) self.assertAlmostEqual(3.14, a.getValue()) return @@ -100,7 +100,7 @@ def testValue(self): self.assertAlmostEqual(0, op.value) # Test update from the nodes - a.setValue(4) + a.set_value(4) self.assertTrue(op._value is None) self.assertAlmostEqual(4, op.value) self.assertAlmostEqual(4, op.getValue()) @@ -129,11 +129,11 @@ def testAddLiteral(self): op.addLiteral(b) self.assertAlmostEqual(0, op.value) - a.setValue(1) - b.setValue(2) + a.set_value(1) + b.set_value(2) self.assertAlmostEqual(3, op.value) - a.setValue(None) + a.set_value(None) # Test for self-references # Try to add self diff --git a/tests/test_objcrystparset.py b/tests/test_objcrystparset.py index 10c96ee9..f905a9eb 100644 --- a/tests/test_objcrystparset.py +++ b/tests/test_objcrystparset.py @@ -223,11 +223,11 @@ 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.a.setValue(1.1) + cryst.c60.C44.x.set_value(1.1) + cryst.c60.C44.occ.set_value(1.1) + cryst.c60.C44.Biso.set_value(1.1) + cryst.c60.q3.set_value(1.1) + cryst.a.set_value(1.1) _testCrystal() _testMolecule() @@ -411,7 +411,7 @@ def testExplicitBondLengthParameter(self): # Change the value scale = 1.05 - p1.setValue(scale * d0) + p1.set_value(scale * d0) # Verify that it has changed. assert scale * d0 == pytest.approx(p1.getValue(), abs=1e-6) @@ -483,7 +483,7 @@ def testExplicitBondAngleParameter(self): # Change the value scale = 1.05 - p1.setValue(scale * angle0) + p1.set_value(scale * angle0) # Verify that it has changed. assert scale * angle0 == pytest.approx(p1.getValue(), abs=1e-6) @@ -564,7 +564,7 @@ def testExplicitDihedralAngleParameter(self): # Change the value scale = 1.05 - p1.setValue(scale * angle0) + p1.set_value(scale * angle0) # Verify that it has changed. assert scale * angle0 == pytest.approx(p1.getValue(), abs=1e-6) diff --git a/tests/test_parameter.py b/tests/test_parameter.py index 04ecd4c7..90606179 100644 --- a/tests/test_parameter.py +++ b/tests/test_parameter.py @@ -29,7 +29,7 @@ def testSetValue(self): """Test initialization.""" par_l = Parameter("l") - par_l.setValue(3.14) + par_l.set_value(3.14) self.assertAlmostEqual(3.14, par_l.getValue()) # Try array @@ -47,7 +47,7 @@ def testSetValue(self): self.assertTrue(par_l.value is y) # Back to scalar - par_l.setValue(1.01) + par_l.set_value(1.01) self.assertAlmostEqual(1.01, par_l.getValue()) self.assertAlmostEqual(1.01, par_l.value) return @@ -89,18 +89,18 @@ def testWrapper(self): # Try Accessor adaptation la = ParameterAdapter( - "l", par_l, getter=Parameter.getValue, setter=Parameter.setValue + "l", par_l, getter=Parameter.getValue, setter=Parameter.set_value ) self.assertEqual(par_l.name, la.name) self.assertEqual(par_l.getValue(), la.getValue()) # Change the parameter - par_l.setValue(2.3) + par_l.set_value(2.3) self.assertEqual(par_l.getValue(), la.getValue()) # Change the adapter - la.setValue(3.2) + la.set_value(3.2) self.assertEqual(par_l.getValue(), la.getValue()) # Try Attribute adaptation @@ -111,11 +111,11 @@ def testWrapper(self): self.assertEqual(par_l.getValue(), la.getValue()) # Change the parameter - par_l.setValue(2.3) + par_l.set_value(2.3) self.assertEqual(par_l.getValue(), la.getValue()) # Change the adapter - la.setValue(3.2) + la.set_value(3.2) self.assertEqual(par_l.getValue(), la.getValue()) return diff --git a/tests/test_pdf.py b/tests/test_pdf.py index b46fa2a6..37839b01 100644 --- a/tests/test_pdf.py +++ b/tests/test_pdf.py @@ -173,9 +173,9 @@ def testGenerator( defval = calc._getDoubleAttr(pname) assert defval == par.getValue() # Test setting values - par.setValue(1.0) + par.set_value(1.0) assert 1.0 == par.getValue() - par.setValue(defval) + par.set_value(defval) assert defval == par.getValue() r = numpy.arange(0, 10, 0.1) diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index a5db1e1b..15a284af 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -275,7 +275,7 @@ def testConstrain(self): self.assertEqual(1, len(self.m._constraints)) self.assertTrue(self.m.isConstrained(p1)) - p2.setValue(10) + p2.set_value(10) self.m._constraints[p1].update() self.assertEqual(20, p1.getValue()) @@ -291,7 +291,7 @@ def testConstrain(self): # Try an straight constraint self.m.constrain(p1, p2) - p2.setValue(7) + p2.set_value(7) self.m._constraints[p1].update() self.assertEqual(7, p1.getValue()) return @@ -308,14 +308,14 @@ def testRestrain(self): self.assertEqual(0, len(self.m._restraints)) r = self.m.restrain("p1+p2", ub=10) self.assertEqual(1, len(self.m._restraints)) - p2.setValue(10) + p2.set_value(10) self.assertEqual(1, r.penalty()) self.m.unrestrain(r) self.assertEqual(0, len(self.m._restraints)) r = self.m.restrain(p1, ub=10) self.assertEqual(1, len(self.m._restraints)) - p1.setValue(11) + p1.set_value(11) self.assertEqual(1, r.penalty()) # Check errors on unregistered parameters @@ -401,15 +401,15 @@ def __call__(self, x): self.m.registerCalculator(g) x = numpy.arange(0.5, 10, 0.5) - self.m.x.setValue(x) + self.m.x.set_value(x) - self.m.g.center.setValue(3.0) + self.m.g.center.set_value(3.0) 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.m.g.center.set_value(5.0) self.assertTrue( numpy.array_equal(numpy.exp(-0.5 * ((x - 5.0) / 0.1) ** 2), g(x)) @@ -437,10 +437,10 @@ def g2(A): self.assertTrue(p in self.m._parameters.values()) x = numpy.arange(0.5, 10, 0.5) - self.m.x.setValue(x) - self.m.A.setValue(1.0) - self.m.c.setValue(3.0) - self.m.w.setValue(0.1) + self.m.x.set_value(x) + self.m.A.set_value(1.0) + self.m.c.set_value(3.0) + self.m.w.set_value(0.1) self.assertTrue( numpy.array_equal(numpy.exp(-0.5 * ((x - 3.0) / 0.1) ** 2), eq()) @@ -477,7 +477,7 @@ def testRegisterStringFunction(self): # Make an equation. eq1 = self.m.registerStringFunction("x**2 + 3", "eq1") - eq1.x.setValue(0) + eq1.x.set_value(0) for p in eq1.args: self.assertTrue(p in self.m._parameters.values()) diff --git a/tests/test_restraint.py b/tests/test_restraint.py index 68673679..c5ef55c7 100644 --- a/tests/test_restraint.py +++ b/tests/test_restraint.py @@ -40,20 +40,20 @@ def testRestraint(self): r = Restraint(eq, 1, 5) # This should have no penalty - p1.setValue(1) - p2.setValue(1) + p1.set_value(1) + p2.set_value(1) self.assertEqual(0, r.penalty()) # Make p1 + p2 = 0 # This should have a penalty of 1*(1 - 0)**2 = 1 - p1.setValue(-1) - p2.setValue(1) + p1.set_value(-1) + p2.set_value(1) self.assertEqual(1, r.penalty()) # Make p1 + p2 = 8 # This should have a penalty of 1*(8 - 5)**2 = 9 - p1.setValue(4) - p2.setValue(4) + p1.set_value(4) + p2.set_value(4) self.assertEqual(9, r.penalty()) # Set the chi^2 to get a dynamic penalty @@ -64,7 +64,7 @@ def testRestraint(self): import numpy r.ub = numpy.inf - p1.setValue(1e100) + p1.set_value(1e100) self.assertEqual(0, r.penalty()) return diff --git a/tests/test_sas.py b/tests/test_sas.py index 59cb14c0..db856942 100644 --- a/tests/test_sas.py +++ b/tests/test_sas.py @@ -123,10 +123,10 @@ def test_generator(sas_available): par = gen.get(pname) assert defval == par.getValue() # Test setting values - par.setValue(1.0) + par.set_value(1.0) assert 1.0 == par.getValue() assert 1.0 == model.getParam(pname) - par.setValue(defval) + par.set_value(defval) assert defval == par.getValue() assert defval == model.getParam(pname) diff --git a/tests/test_speed.py b/tests/test_speed.py index 6bc75014..5c2d7f3a 100644 --- a/tests/test_speed.py +++ b/tests/test_speed.py @@ -52,19 +52,19 @@ def makeLazyEquation(make_args): mult2.addLiteral(pow) mult2.addLiteral(exp) - v2.setValue(x) - v3.setValue(50 * x) - v5.setValue(2.11) - v6.setValue(numpy.e) + v2.set_value(x) + v3.set_value(50 * x) + v5.set_value(2.11) + v6.set_value(numpy.e) evaluator = visitors.Evaluator() def _f(a, b, c, d, e): - v1.setValue(a) - v4.setValue(b) - v5.setValue(c) - v6.setValue(d) - v7.setValue(e) + v1.set_value(a) + v4.set_value(b) + v5.set_value(c) + v6.set_value(d) + v7.set_value(e) mult2.identify(evaluator) evaluator.clicker.click() return evaluator.value @@ -133,18 +133,18 @@ def speedTest2(mutate=2): """ factory.registerConstant("x", x) eq = factory.makeEquation(eqstr) - eq.qsig.setValue(qsig) - eq.sigma1.setValue(sigma) - eq.sigma2.setValue(sigma) - eq.A0.setValue(1.0) - eq.b1.setValue(0) - eq.b2.setValue(1) - eq.b3.setValue(2.0) - eq.b4.setValue(2.0) - eq.b5.setValue(2.0) - eq.b6.setValue(2.0) - eq.b7.setValue(2.0) - eq.b8.setValue(2.0) + eq.qsig.set_value(qsig) + eq.sigma1.set_value(sigma) + eq.sigma2.set_value(sigma) + eq.A0.set_value(1.0) + eq.b1.set_value(0) + eq.b2.set_value(1) + eq.b3.set_value(2.0) + eq.b4.set_value(2.0) + eq.b5.set_value(2.0) + eq.b6.set_value(2.0) + eq.b7.set_value(2.0) + eq.b8.set_value(2.0) from numpy import exp, polyval @@ -211,18 +211,18 @@ def speedTest3(mutate=2): """ factory.registerConstant("x", x) eq = factory.makeEquation(eqstr) - eq.qsig.setValue(qsig) - eq.sigma1.setValue(sigma) - eq.sigma2.setValue(sigma) - eq.A0.setValue(1.0) - eq.b1.setValue(0) - eq.b2.setValue(1) - eq.b3.setValue(2.0) - eq.b4.setValue(2.0) - eq.b5.setValue(2.0) - eq.b6.setValue(2.0) - eq.b7.setValue(2.0) - eq.b8.setValue(2.0) + eq.qsig.set_value(qsig) + eq.sigma1.set_value(sigma) + eq.sigma2.set_value(sigma) + eq.A0.set_value(1.0) + eq.b1.set_value(0) + eq.b2.set_value(1) + eq.b3.set_value(2.0) + eq.b4.set_value(2.0) + eq.b5.set_value(2.0) + eq.b6.set_value(2.0) + eq.b7.set_value(2.0) + eq.b8.set_value(2.0) from numpy import polyval from sympy import exp, lambdify, var @@ -357,14 +357,14 @@ def weightedTest(mutate=2): factory.registerConstant("x", x) eq = factory.makeEquation(eqstr) - eq.b1.setValue(0) - eq.b2.setValue(1) - eq.b3.setValue(2.0) - eq.b4.setValue(2.0) - eq.b5.setValue(2.0) - eq.b6.setValue(2.0) - eq.b7.setValue(2.0) - eq.b8.setValue(2.0) + eq.b1.set_value(0) + eq.b2.set_value(1) + eq.b3.set_value(2.0) + eq.b4.set_value(2.0) + eq.b5.set_value(2.0) + eq.b6.set_value(2.0) + eq.b7.set_value(2.0) + eq.b8.set_value(2.0) # scale = visitors.NodeWeigher() # eq.root.identify(scale) @@ -426,14 +426,14 @@ def profileTest(): factory.registerConstant("x", x) eq = factory.makeEquation(eqstr) - eq.b1.setValue(0) - eq.b2.setValue(1) - eq.b3.setValue(2.0) - eq.b4.setValue(2.0) - eq.b5.setValue(2.0) - eq.b6.setValue(2.0) - eq.b7.setValue(2.0) - eq.b8.setValue(2.0) + eq.b1.set_value(0) + eq.b2.set_value(1) + eq.b3.set_value(2.0) + eq.b4.set_value(2.0) + eq.b5.set_value(2.0) + eq.b6.set_value(2.0) + eq.b7.set_value(2.0) + eq.b8.set_value(2.0) mutate = 8 numargs = len(eq.args) diff --git a/tests/test_visitors.py b/tests/test_visitors.py index 546edaaa..9ae8698d 100644 --- a/tests/test_visitors.py +++ b/tests/test_visitors.py @@ -117,10 +117,10 @@ def testSimpleFunction(self): # Set the values of the variables. # The equation should evaluate to (1+3)*(4-2) = 8 - v1.setValue(1) - v2.setValue(2) - v3.setValue(3) - v4.setValue(4) + v1.set_value(1) + v2.set_value(2) + v3.set_value(3) + v4.set_value(4) # now get the args args = visitors.getArgs(mult) @@ -170,11 +170,11 @@ def testSimpleFunction(self): # Set the values of the variables. # The equation should evaluate to (1+3)*(4-2) = 8 - v1.setValue(1) - v2.setValue(2) - v3.setValue(3) - v4.setValue(4) - v5.setValue(5) + v1.set_value(1) + v2.set_value(2) + v3.set_value(3) + v4.set_value(4) + v5.set_value(5) # Evaluate assert 8 == mult.value diff --git a/tests/test_weakrefcallable.py b/tests/test_weakrefcallable.py index fd3488ac..1e8ca092 100644 --- a/tests/test_weakrefcallable.py +++ b/tests/test_weakrefcallable.py @@ -119,7 +119,7 @@ def test_observable_deregistration(self): xof = next(iter(x._observers)) self.assertTrue(isinstance(xof, WeakBoundMethod)) # changing value of x should reset f._eq - x.setValue(x.value + 1) + x.set_value(x.value + 1) self.assertTrue(None is f._eq._value) self.assertEqual(18, f.evaluate()) # deallocate f now @@ -127,7 +127,7 @@ def test_observable_deregistration(self): self.assertTrue(xof in x._observers) # since f does not exist anymore, the next notification call # should drop the associated observer. - x.setValue(x.value + 1) + x.set_value(x.value + 1) self.assertEqual(0, len(x._observers)) return From 6d0de2732ba722bdc7c998d41395dd5f0961b3c6 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 5 Mar 2026 10:57:53 -0500 Subject: [PATCH 128/193] news --- news/setvalue-dep.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/setvalue-dep.rst diff --git a/news/setvalue-dep.rst b/news/setvalue-dep.rst new file mode 100644 index 00000000..83121f06 --- /dev/null +++ b/news/setvalue-dep.rst @@ -0,0 +1,23 @@ +**Added:** + +* Added ``set_value`` method to ``diffpy.srfit.fitbase.Parameter``. + +**Changed:** + +* + +**Deprecated:** + +* Deprecated ``setValue`` method in ``diffpy.srfit.fitbase.Parameter`` for removal in 4.0.0. + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 314b155e4ebf580e25b29669670f650f25e8136b Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Mar 2026 11:15:26 -0500 Subject: [PATCH 129/193] skip test_speed.py --- tests/test_speed.py | 59 ++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/tests/test_speed.py b/tests/test_speed.py index 5c2d7f3a..e859e4e0 100644 --- a/tests/test_speed.py +++ b/tests/test_speed.py @@ -17,14 +17,23 @@ import random import numpy +import pytest import diffpy.srfit.equation.literals as literals import diffpy.srfit.equation.visitors as visitors +pytestmark = pytest.mark.skip( + reason=( + "This is a performance benchmark test, " + "not a unit test. Comment out this line " + "to run performance testing." + ) +) + x = numpy.arange(0, 20, 0.05) -def makeLazyEquation(make_args): +def make_lazy_equation(make_args): """Make a lazy equation and see how fast it is.""" # Make some variables @@ -72,7 +81,7 @@ def _f(a, b, c, d, e): return _f -def makeEquation1(): +def make_equation1(): """Make the same equation as the lazy one.""" y = 50 * x @@ -83,7 +92,7 @@ def _f(a, b, c, d, e): return _f -def timeFunction(f, *args, **kw): +def time_function(f, *args, **kw): """Time a function in ms.""" import time @@ -93,9 +102,9 @@ def timeFunction(f, *args, **kw): return (t2 - t1) * 1000 -def speedTest1(): - f1 = makeLazyEquation() - f2 = makeEquation1() +def test_speed1(): + f1 = make_lazy_equation() + f2 = make_equation1() args = [3.1, 8.19973123410, 2.1, numpy.e, numpy.pi] @@ -104,8 +113,8 @@ def speedTest1(): for i in range(len(args)): args[i] = 10 * random.random() print("Changing argument %i" % (i + 1)) - t1 = timeFunction(f1, *args) - t2 = timeFunction(f2, *args) + t1 = time_function(f1, *args) + t2 = time_function(f2, *args) total1 += t1 total2 += t2 print("lazy", t1) @@ -117,7 +126,7 @@ def speedTest1(): print("Ratio (lazy/regular)", total1 / total2) -def speedTest2(mutate=2): +def test_speed2(mutate=2): from diffpy.srfit.equation.builder import EquationFactory @@ -176,8 +185,8 @@ def f(A0, qsig, sigma1, sigma2, b1, b2, b3, b4, b5, b6, b7, b8): args[idx] = random.random() # Time the different functions with these arguments - tnpy += timeFunction(f, *args) - teq += timeFunction(eq, *args) + tnpy += time_function(f, *args) + teq += time_function(eq, *args) print( "Average call time (%i calls, %i mutations/call):" % (numcalls, mutate) @@ -189,7 +198,7 @@ def f(A0, qsig, sigma1, sigma2, b1, b2, b3, b4, b5, b6, b7, b8): return -def speedTest3(mutate=2): +def test_speed3(mutate=2): """Test wrt sympy. Results - sympy is 10 to 24 times faster without using arrays (ouch!). @@ -265,8 +274,8 @@ def speedTest3(mutate=2): args[idx] = random.random() # Time the different functions with these arguments - teq += timeFunction(eq, *(args[:-1])) - tnpy += timeFunction(f, *args) + teq += time_function(eq, *(args[:-1])) + tnpy += time_function(f, *args) print( "Average call time (%i calls, %i mutations/call):" % (numcalls, mutate) @@ -278,7 +287,7 @@ def speedTest3(mutate=2): return -def speedTest4(mutate=2): +def test_speed4(mutate=2): """Test wrt sympy. Results - sympy is 10 to 24 times faster without using arrays (ouch!). @@ -310,7 +319,7 @@ def speedTest4(mutate=2): teq = 0 # Randomly change variables numargs = len(eq.args) - choices = range(numargs) + choices = list(range(numargs)) args = [1.0] * (len(eq.args)) args.append(x) @@ -329,8 +338,8 @@ def speedTest4(mutate=2): args[idx] = random.random() # Time the different functions with these arguments - teq += timeFunction(eq, *(args[:-1])) - tnpy += timeFunction(f, *args) + teq += time_function(eq, *(args[:-1])) + tnpy += time_function(f, *args) print( "Average call time (%i calls, %i mutations/call):" % (numcalls, mutate) @@ -342,7 +351,7 @@ def speedTest4(mutate=2): return -def weightedTest(mutate=2): +def test_weighted(mutate=2): """Show the benefits of a properly balanced equation tree.""" from diffpy.srfit.equation.builder import EquationFactory @@ -379,7 +388,7 @@ def f(b1, b2, b3, b4, b5, b6, b7, b8): teq = 0 # Randomly change variables numargs = len(eq.args) - choices = range(numargs) + choices = list(range(numargs)) args = [0.1] * numargs # The call-loop @@ -399,8 +408,8 @@ def f(b1, b2, b3, b4, b5, b6, b7, b8): # print(args) # Time the different functions with these arguments - teq += timeFunction(eq, *args) - tnpy += timeFunction(f, *args) + teq += time_function(eq, *args) + tnpy += time_function(f, *args) print( "Average call time (%i calls, %i mutations/call):" % (numcalls, mutate) @@ -412,9 +421,9 @@ def f(b1, b2, b3, b4, b5, b6, b7, b8): return -def profileTest(): +def test_profile(): - from diffpy.srfit.builder import EquationFactory + from diffpy.srfit.equation.builder import EquationFactory factory = EquationFactory() @@ -437,7 +446,7 @@ def profileTest(): mutate = 8 numargs = len(eq.args) - choices = range(numargs) + choices = list(range(numargs)) args = [0.1] * numargs # The call-loop From bb99611056bc4a1de5275accef688ad1fa5784fa Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Mar 2026 12:38:01 -0500 Subject: [PATCH 130/193] ignore test_speed.py in codecov --- .codecov.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.codecov.yml b/.codecov.yml index 4af5eb24..1cdcf2e9 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -5,6 +5,9 @@ coverage: target: auto # use the coverage from the base commit, fail if coverage is lower threshold: 0% # allow the coverage to drop by + ignore: + - "tests/test_speed.py" # ignore performance testing in test coverage. + comment: layout: " diff, flags, files" behavior: default From d6e29b7b95555b3d857d49dc663494149bfc2838 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Mar 2026 14:51:43 -0500 Subject: [PATCH 131/193] iterPars deprecation --- src/diffpy/srfit/fitbase/fitrecipe.py | 2 +- src/diffpy/srfit/fitbase/parameterset.py | 2 +- src/diffpy/srfit/fitbase/recipeorganizer.py | 48 +++++++++++++++++---- tests/test_pdf.py | 4 +- 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 0aff6ecd..3000aae4 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -622,7 +622,7 @@ def __verify_parameters(self): # Get all parameters with a value of None badpars = [] - for par in self.iterPars(): + for par in self.iterate_over_parameters(): try: par.getValue() except ValueError: diff --git a/src/diffpy/srfit/fitbase/parameterset.py b/src/diffpy/srfit/fitbase/parameterset.py index e5e51e39..6ebc4fc7 100644 --- a/src/diffpy/srfit/fitbase/parameterset.py +++ b/src/diffpy/srfit/fitbase/parameterset.py @@ -156,7 +156,7 @@ def setConst(self, const=True): Flag indicating if the parameter is constant (default True). """ - for par in self.iterPars(): + for par in self.iterate_over_parameters(): par.setConst(const) return diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 3daf5674..6d0878e1 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -61,6 +61,13 @@ removal_version, ) +iterPars_deprecation_msg = build_deprecation_message( + recipecontainer_base, + "iterPars", + "iterate_over_parameters", + removal_version, +) + class RecipeContainer(Observable, Configurable, Validatable): """Base class for organizing pieces of a FitRecipe. @@ -134,16 +141,30 @@ def _iter_managed(self): """Get iterator over managed objects.""" return chain(*(d.values() for d in self.__managed)) - def iterPars(self, pattern="", recurse=True): + def iterate_over_parameters(self, pattern="", recurse=True): """Iterate over the Parameters contained in this object. Parameters ---------- - pattern : str - Iterate over parameters with names matching this regular - expression (all parameters by default). - recurse : bool - Recurse into managed objects when True (default). + pattern : str, optional + The regular expression pattern to match parameter + names against. Only parameters with names matching + this pattern will be returned. Default is an empty + string, which matches all parameter names. + recurse : bool, optional + The flag indicating whether to recurse into managed + objects when iterating over parameters. If True + (default), the method will also iterate over + parameters in managed sub-objects. If False, only + top-level parameters will be iterated over. + + Example + ------- + + .. + for param in recipe.iterate_over_parameters(pattern="scale_"): + # print the name and value of parameters containing "scale_" + print(f"{param.name}={param.value}") """ regexp = re.compile(pattern) for par in list(self._parameters.values()): @@ -156,11 +177,22 @@ def iterPars(self, pattern="", recurse=True): managed.remove(self._parameters) for m in managed: for obj in m.values(): - if hasattr(obj, "iterPars"): - for par in obj.iterPars(pattern=pattern): + if hasattr(obj, "iterate_over_parameters"): + for par in obj.iterate_over_parameters(pattern=pattern): yield par return + @deprecated(iterPars_deprecation_msg) + def iterPars(self, pattern="", recurse=True): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use + diffpy.srfit.fitbase.recipeorganizer.RecipeContainer.iterate_over_parameters + instead. + """ + return self.iterate_over_parameters(pattern=pattern, recurse=recurse) + def __iter__(self): """Iterate over top-level parameters.""" return iter(self._parameters.values()) diff --git a/tests/test_pdf.py b/tests/test_pdf.py index b46fa2a6..9b528f5d 100644 --- a/tests/test_pdf.py +++ b/tests/test_pdf.py @@ -308,7 +308,9 @@ def test_pickling( pc2 = pickle.loads(pickle.dumps(pc)) res0 = pc.residual() assert numpy.array_equal(res0, pc2.residual()) - for p in chain(pc.iterPars("Uiso"), pc2.iterPars("Uiso")): + for p in chain( + pc.iterate_over_parameters("Uiso"), pc2.iterate_over_parameters("Uiso") + ): p.value = 0.004 res1 = pc.residual() assert not numpy.allclose(res0, res1) From ffe76bf28e15cff1ecc2759e1de8610ddf0f0f95 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Mar 2026 15:00:07 -0500 Subject: [PATCH 132/193] registerCalculator deprecation --- docs/examples/nppdfsas.py | 2 +- src/diffpy/srfit/fitbase/calculator.py | 2 +- src/diffpy/srfit/fitbase/recipeorganizer.py | 38 ++++++++++++----- tests/test_recipeorganizer.py | 45 +++++++++++++++++++++ 4 files changed, 76 insertions(+), 11 deletions(-) diff --git a/docs/examples/nppdfsas.py b/docs/examples/nppdfsas.py index 6626c603..2117ac58 100644 --- a/docs/examples/nppdfsas.py +++ b/docs/examples/nppdfsas.py @@ -87,7 +87,7 @@ def makeRecipe(ciffile, grdata, iqdata): # Register the calculator with the pdf contribution and define the fitting # equation. - pdfcontribution.registerCalculator(cfcalculator) + pdfcontribution.register_calculator(cfcalculator) # The PDF for a nanoscale crystalline is approximated by # Gnano = f * Gcryst pdfcontribution.set_equation("f * G") diff --git a/src/diffpy/srfit/fitbase/calculator.py b/src/diffpy/srfit/fitbase/calculator.py index 22e96540..41ebde60 100644 --- a/src/diffpy/srfit/fitbase/calculator.py +++ b/src/diffpy/srfit/fitbase/calculator.py @@ -20,7 +20,7 @@ overloaded to accept external arguments. Calculators are used to wrap registered functions so that the function's Parameters are contained in an object specific to the function. A custom Calculator can be added to -another RecipeOrganizer with the 'registerCalculator' method. +another RecipeOrganizer with the 'register_calculator' method. """ __all__ = ["Calculator"] diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 6d0878e1..c68e02ef 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -68,6 +68,15 @@ removal_version, ) +recipeorganizer_base = "diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer" + +registerCalculator_deprecation_msg = build_deprecation_message( + recipeorganizer_base, + "registerCalculator", + "register_calculator", + removal_version, +) + class RecipeContainer(Observable, Configurable, Validatable): """Base class for organizing pieces of a FitRecipe. @@ -545,7 +554,7 @@ def _remove_parameter(self, par): self._eqfactory.deRegisterBuilder(par.name) return - def registerCalculator(self, f, argnames=None): + def register_calculator(self, calculator, argnames=None): """Register a Calculator so it can be used within equation strings. @@ -557,18 +566,18 @@ def registerCalculator(self, f, argnames=None): Attributes ---------- - f + calculator : Calculator object The Calculator to register. - argnames - The names of the arguments to f (list or None). + argnames : list or None, optional + The names of the arguments to calculator (list or None). If this is None, then the argument names will be extracted from the function. """ - self._eqfactory.registerOperator(f.name, f) - self._add_object(f, self._calculators) + self._eqfactory.registerOperator(calculator.name, calculator) + self._add_object(calculator, self._calculators) # Register arguments of the calculator if argnames is None: - fncode = f.__call__.__func__.__code__ + fncode = calculator.__call__.__func__.__code__ argnames = list(fncode.co_varnames) argnames = argnames[1 : fncode.co_argcount] @@ -577,12 +586,23 @@ def registerCalculator(self, f, argnames=None): par = self._new_parameter(pname, 0) else: par = self.get(pname) - f.addLiteral(par) + calculator.addLiteral(par) # Now return an equation object - eq = self._eqfactory.makeEquation(f.name) + eq = self._eqfactory.makeEquation(calculator.name) return eq + @deprecated(registerCalculator_deprecation_msg) + def registerCalculator(self, f, argnames=None): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.register_calculator + instead. + """ + return self.register_calculator(f, argnames=argnames) + def registerFunction(self, f, name=None, argnames=None): """Register a function so it can be used within equation strings. diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index a5db1e1b..cd55ccd4 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -377,6 +377,51 @@ def testGetRestraints(self): self.assertEqual(2, len(res)) return + def test_register_calculator(self): + + class GCalc(Calculator): + + def __init__(self, name): + Calculator.__init__(self, name) + self.newParameter("A", 1.0) + self.newParameter("center", 0.0) + self.newParameter("width", 0.1) + return + + 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) + + # End class GCalc + + g = GCalc("g") + + self.m.register_calculator(g) + + x = numpy.arange(0.5, 10, 0.5) + self.m.x.setValue(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.m.g.center.setValue(5.0) + + 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())) + + return + def testRegisterCalculator(self): class GCalc(Calculator): From ecec4b198b19ed3acf08dd690a9d38996a469cc0 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Mar 2026 15:20:37 -0500 Subject: [PATCH 133/193] registerFunction deprecation in EquationFactory and RecipeOrganizer --- docs/examples/coreshellnp.py | 4 +- docs/examples/debyemodel.py | 6 +- docs/examples/npintensity.py | 2 +- docs/examples/npintensityII.py | 4 +- docs/examples/nppdfcrystal.py | 2 +- docs/examples/threedoublepeaks.py | 8 +- src/diffpy/srfit/equation/builder.py | 40 ++++++-- src/diffpy/srfit/fitbase/fitcontribution.py | 2 +- src/diffpy/srfit/fitbase/recipeorganizer.py | 96 ++++++++++++------- .../srfit/pdf/characteristicfunctions.py | 2 +- tests/test_builder.py | 6 +- tests/test_contribution.py | 4 +- tests/test_recipeorganizer.py | 6 +- 13 files changed, 118 insertions(+), 64 deletions(-) diff --git a/docs/examples/coreshellnp.py b/docs/examples/coreshellnp.py index afb2a339..430726b1 100644 --- a/docs/examples/coreshellnp.py +++ b/docs/examples/coreshellnp.py @@ -76,8 +76,8 @@ def makeRecipe(stru1, stru2, datname): # very little to the PDF. from diffpy.srfit.pdf.characteristicfunctions import shellCF, sphericalCF - contribution.registerFunction(sphericalCF, name="f_CdS") - contribution.registerFunction(shellCF, name="f_ZnS") + contribution.register_function(sphericalCF, name="f_CdS") + contribution.register_function(shellCF, name="f_ZnS") # Write the fitting equation. We want to sum the PDFs from each phase and # multiply it by a scaling factor. diff --git a/docs/examples/debyemodel.py b/docs/examples/debyemodel.py index 3ec7002d..cd2dcbbd 100644 --- a/docs/examples/debyemodel.py +++ b/docs/examples/debyemodel.py @@ -106,14 +106,14 @@ def makeRecipe(): contribution.set_profile(profile, xname="T") # We now need to create the fitting equation. We tell the FitContribution - # to use the 'debye' function defined below. The 'registerFunction' method + # to use the 'debye' function defined below. The 'register_function' method # will let us do this. Since we haven't told it otherwise, - # 'registerFunction' will extract the name of the function ('debye') and + # 'register_function' will extract the name of the function ('debye') and # the names of the arguments ('T', 'm', 'thetaD'). These arguments will # become Parameters of the FitContribution. Since we named the x-variable # 'T' above, the 'T' in the 'debye' equation will refer to this x-variable # whenever it is used. - contribution.registerFunction(debye) + contribution.register_function(debye) # Now we can create the fitting equation. We want to extend the 'debye' # equation by adding a vertical offset. We could wrap 'debye' in a new diff --git a/docs/examples/npintensity.py b/docs/examples/npintensity.py index fce0e7bd..23c23ffa 100644 --- a/docs/examples/npintensity.py +++ b/docs/examples/npintensity.py @@ -247,7 +247,7 @@ def gaussian(q, q0, width): # This registers the python function and extracts the name and creates # Parameters from the arguments. - contribution.registerFunction(gaussian) + contribution.register_function(gaussian) # Center the Gaussian so it is not truncated. contribution.q0.value = x[len(x) // 2] diff --git a/docs/examples/npintensityII.py b/docs/examples/npintensityII.py index 2791a1b3..c5683338 100644 --- a/docs/examples/npintensityII.py +++ b/docs/examples/npintensityII.py @@ -119,8 +119,8 @@ def gaussian(q, q0, width): * exp(-0.5 * ((q - q0) / width) ** 2) ) - contribution1.registerFunction(gaussian) - contribution2.registerFunction(gaussian) + contribution1.register_function(gaussian) + contribution2.register_function(gaussian) # Center the gaussian contribution1.q0.value = x[len(x) // 2] contribution2.q0.value = x[len(x) // 2] diff --git a/docs/examples/nppdfcrystal.py b/docs/examples/nppdfcrystal.py index a8e0dc9d..496a1104 100644 --- a/docs/examples/nppdfcrystal.py +++ b/docs/examples/nppdfcrystal.py @@ -59,7 +59,7 @@ def makeRecipe(ciffile, grdata): # Register the nanoparticle shape factor. from diffpy.srfit.pdf.characteristicfunctions import sphericalCF - pdfcontribution.registerFunction(sphericalCF, name="f") + pdfcontribution.register_function(sphericalCF, name="f") # Now we set up the fitting equation. pdfcontribution.set_equation("f * G") diff --git a/docs/examples/threedoublepeaks.py b/docs/examples/threedoublepeaks.py index d6c70202..960820c4 100644 --- a/docs/examples/threedoublepeaks.py +++ b/docs/examples/threedoublepeaks.py @@ -59,7 +59,7 @@ def makeRecipe(): def gaussian(t, mu, sig): return 1 / (2 * pi * sig**2) ** 0.5 * exp(-0.5 * ((t - mu) / sig) ** 2) - contribution.registerFunction(gaussian, name="peakshape") + contribution.register_function(gaussian, name="peakshape") def delta(t, mu): """Calculate a delta-function. @@ -70,7 +70,7 @@ def delta(t, mu): sig = t[1] - t[0] return gaussian(t, mu, sig) - contribution.registerFunction(delta) + contribution.register_function(delta) # Here is another one bkgdstr = "b0 + b1*t + b2*t**2 + b3*t**3 + b4*t**4 + b5*t**5 + b6*t**6" @@ -120,7 +120,7 @@ def peakloc(mu): l2 = 1.0 return 180 / pi * arcsin(pi / 180 * l2 * sin(mu) / l1) - recipe.registerFunction(peakloc) + recipe.register_function(peakloc) recipe.constrain(contribution.mu12, "peakloc(mu11)") recipe.constrain(contribution.mu22, "peakloc(mu21)") recipe.constrain(contribution.mu32, "peakloc(mu31)") @@ -134,7 +134,7 @@ def sig(sig0, dsig, mu): """Calculate the peak broadening with respect to position.""" return sig0 * (1 - dsig * mu**2) - recipe.registerFunction(sig) + recipe.register_function(sig) recipe.fix("mu") # Now constrain the peak widths to this recipe.sig0.value = 0.001 diff --git a/src/diffpy/srfit/equation/builder.py b/src/diffpy/srfit/equation/builder.py index 87a56b63..0c9ffafb 100644 --- a/src/diffpy/srfit/equation/builder.py +++ b/src/diffpy/srfit/equation/builder.py @@ -106,6 +106,16 @@ _builders = {} +EquationFactory_base = "diffpy.srfit.equation.builder.EquationFactory" +removal_version = "4.0.0" + +registerFunction_dep_msg = build_deprecation_message( + EquationFactory_base, + "registerFunction", + "register_function", + removal_version, +) + class EquationFactory(object): """A Factory for equations. @@ -208,23 +218,26 @@ def registerOperator(self, name, op): opbuilder = wrapOperator(name, op) return self.registerBuilder(name, opbuilder) - def registerFunction(self, name, func, argnames): + def register_function(self, name, func, argnames): """Register a named function with the factory. This will register a builder for the function. - Attributes + Parameters ---------- - name + name : str The name of the function - func - A callable python object - argnames + func : callable + The callable python object + argnames : list of str The argument names for func. If these names do not correspond to builders, then new constants with value 0 will be created for each name. - Returns the registered builder. + Returns + ------- + registered_builder : OperatorBuilder + The registered builder. """ for n in argnames: if n not in self.builders: @@ -234,8 +247,19 @@ def registerFunction(self, name, func, argnames): builder = self.builders[argname] argliteral = builder.literal opbuilder.literal.addLiteral(argliteral) + registered_builder = self.registerBuilder(name, opbuilder) + return registered_builder - return self.registerBuilder(name, opbuilder) + @deprecated(registerFunction_dep_msg) + def registerFunction(self, name, func, argnames): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use + diffpy.srfit.equation.builder.EquationFactory.register_function + instead. + """ + return self.register_function(name, func, argnames) def registerBuilder(self, name, builder): """Register builder in this module so it can be used in diff --git a/src/diffpy/srfit/fitbase/fitcontribution.py b/src/diffpy/srfit/fitbase/fitcontribution.py index 21a7aed9..cdb39862 100644 --- a/src/diffpy/srfit/fitbase/fitcontribution.py +++ b/src/diffpy/srfit/fitbase/fitcontribution.py @@ -283,7 +283,7 @@ def set_equation(self, eqstr, ns={}): eqstr A string representation of the equation. Any Parameter registered by addParameter or setProfile, or function - registered by setCalculator, registerFunction or + registered by setCalculator, register_function or registerStringFunction can be can be used in the equation by name. Other names will be turned into Parameters of this FitContribution. diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index c68e02ef..f3c27d57 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -77,6 +77,13 @@ removal_version, ) +registerFunction_deprecation_msg = build_deprecation_message( + recipeorganizer_base, + "registerFunction", + "register_function", + removal_version, +) + class RecipeContainer(Observable, Configurable, Validatable): """Base class for organizing pieces of a FitRecipe. @@ -603,52 +610,62 @@ def registerCalculator(self, f, argnames=None): """ return self.register_calculator(f, argnames=argnames) - def registerFunction(self, f, name=None, argnames=None): + def register_function(self, function, 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 - equations. The resulting equation does not require the arguments to be + equations. The resulting equation does not require the arguments to be passed in the equation string, as this will be handled automatically. - Attributes + Parameters ---------- - f + function : callable The callable to register. If this is an Equation instance, then all that needs to be provided is a name. - name + name : str or None, optional The name of the function to be used in equations. If this is None (default), the method will try to determine the name of the function automatically. - argnames - The names of the arguments to f (list or None). + argnames : list or None, optional + The names of the arguments to 'function' (list or None). If this is None (default), then the argument names will be extracted from the function. - - Note that name and argnames can be extracted from regular python - functions (of type 'function'), bound class methods and callable + Note + ---- + name and argnames can be extracted from regular Python + functions (of type ), bound class methods, and callable classes. + Raises + ------ + TypeError + If name or argnames cannot be automatically extracted. + TypeError + If an automatically extracted name is ''. + ValueError + If function is an Equation object and name is None. - Raises TypeError if name or argnames cannot be automatically - extracted. - Raises TypeError if an automatically extracted name is ''. - Raises ValueError if f is an Equation object and name is None. - - Returns the callable Equation object. + Returns + ------- + equation_object : Equation + The callable Equation object. """ # If the function is an equation, we treat it specially. This is # required so that the objects observed by the root get observed if the # Equation is used within another equation. It is assumed that a plain # function is not observable. - if isinstance(f, Equation): + if isinstance(function, Equation): if name is None: - m = "Equation must be given a name" + m = ( + "The equation must be given a name. " + "Specify a name with the 'name' argument." + ) raise ValueError(m) - self._eqfactory.registerOperator(name, f) - return f + self._eqfactory.registerOperator(name, function) + return function # Introspection code if name is None or argnames is None: @@ -661,15 +678,17 @@ def registerFunction(self, f, name=None, argnames=None): offset = 0 # check regular functions - if inspect.isfunction(f): - fncode = f.__code__ + if inspect.isfunction(function): + fncode = function.__code__ # check class method - elif inspect.ismethod(f): - fncode = f.__func__.__code__ + elif inspect.ismethod(function): + fncode = function.__func__.__code__ offset = 1 # check functor - elif hasattr(f, "__call__") and hasattr(f.__call__, "__func__"): - fncode = f.__call__.__func__.__code__ + elif hasattr(function, "__call__") and hasattr( + function.__call__, "__func__" + ): + fncode = function.__call__.__func__.__code__ offset = 1 else: m = "Cannot extract name or argnames" @@ -697,18 +716,29 @@ def registerFunction(self, f, name=None, argnames=None): # Initialize and register from diffpy.srfit.fitbase.calculator import Calculator - if isinstance(f, Calculator): + if isinstance(function, Calculator): for pname in argnames: par = self.get(pname) - f.addLiteral(par) - self._eqfactory.registerOperator(name, f) + function.addLiteral(par) + self._eqfactory.registerOperator(name, function) else: - self._eqfactory.registerFunction(name, f, argnames) + self._eqfactory.register_function(name, function, argnames) # Now we can create the Equation and return it to the user. - eq = self._eqfactory.makeEquation(name) + equation_object = self._eqfactory.makeEquation(name) - return eq + return equation_object + + @deprecated(registerFunction_deprecation_msg) + def registerFunction(self, f, name=None, argnames=None): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.register_function + instead. + """ + return self.register_function(f, name=name, argnames=argnames) def registerStringFunction(self, fstr, name, ns={}): """Register a string function. @@ -747,7 +777,7 @@ def registerStringFunction(self, fstr, name, ns={}): # Register the equation as a callable function. argnames = eq.argdict.keys() - return self.registerFunction(eq, name, argnames) + return self.register_function(eq, name, argnames) def evaluateEquation(self, eqstr, ns={}): """Evaluate a string equation. diff --git a/src/diffpy/srfit/pdf/characteristicfunctions.py b/src/diffpy/srfit/pdf/characteristicfunctions.py index 9846e131..ca24dfc1 100644 --- a/src/diffpy/srfit/pdf/characteristicfunctions.py +++ b/src/diffpy/srfit/pdf/characteristicfunctions.py @@ -21,7 +21,7 @@ function and Gcryst(f) is the crystal PDF. These functions are meant to be imported and added to a FitContribution -using the 'registerFunction' method of that class. +using the 'register_function' method of that class. """ __all__ = [ diff --git a/tests/test_builder.py b/tests/test_builder.py index da1f56f6..2ac09fb4 100644 --- a/tests/test_builder.py +++ b/tests/test_builder.py @@ -97,7 +97,7 @@ def g2(v1): factory.registerArgument("v2", v2) factory.registerArgument("v3", v3) factory.registerArgument("v4", v4) - b = factory.registerFunction("g", g1, ["v1", "v2", "v3", "v4"]) + b = factory.register_function("g", g1, ["v1", "v2", "v3", "v4"]) # Now associate args with the wrapped function op = b.literal @@ -121,7 +121,7 @@ def g2(v1): assert round(abs(24 - eq1()), 7) == 0 # Now swap out the function - b = factory.registerFunction("g", g2, ["v1"]) + b = factory.register_function("g", g2, ["v1"]) op = b.literal assert op.operation == g2 assert v1 in op.args @@ -181,7 +181,7 @@ def testParseEquation(noObserversInGlobalBuilders): assert eq.args == [eq.sigma] # Equation with user-defined functions - factory.registerFunction("myfunc", eq, ["sigma"]) + factory.register_function("myfunc", eq, ["sigma"]) eq2 = factory.makeEquation("c*myfunc(sigma)") assert numpy.allclose(eq2(c=2, sigma=sigma), 2 * gaussian_test(x, sigma)) assert "sigma" in eq2.argdict diff --git a/tests/test_contribution.py b/tests/test_contribution.py index ef388b6b..58571655 100644 --- a/tests/test_contribution.py +++ b/tests/test_contribution.py @@ -192,11 +192,11 @@ def test_releaseOldEquations(self): self.assertEqual(2, len(fc._eqfactory.equations)) return - def test_registerFunction(self): + def test_register_function(self): """Ensure registered function works after second set_equation call.""" fc = self.fitcontribution - fc.registerFunction(_fsquare, name="fsquare") + fc.register_function(_fsquare, name="fsquare") fc.set_equation("fsquare") fc.x.setValue(5) self.assertEqual(25, fc.evaluate()) diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index cd55ccd4..c5bb29d9 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -476,7 +476,7 @@ def g1(A, c, w, x): def g2(A): return A + 1 - eq = self.m.registerFunction(g1, "g") + eq = self.m.register_function(g1, "g") for p in eq.args: self.assertTrue(p in self.m._parameters.values()) @@ -496,7 +496,7 @@ def g2(A): self.assertTrue(numpy.array_equal(eq() / x - 1, eq2())) # Make sure we can swap out "g". - self.m.registerFunction(g2, "g") + self.m.register_function(g2, "g") self.assertAlmostEqual(2.0, eq()) # Try a bound method @@ -508,7 +508,7 @@ def __call__(self): return 4.56 t = temp() - eq = self.m.registerFunction(t.eval, "eval") + eq = self.m.register_function(t.eval, "eval") self.assertAlmostEqual(1.23, eq()) # Now the callable From b0a714b0e785af1fc3e4066f8034fbff8f0f8720 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Mar 2026 15:31:17 -0500 Subject: [PATCH 134/193] registerStringFunction deprecation --- docs/examples/npintensity.py | 2 +- docs/examples/npintensityII.py | 4 +- docs/examples/threedoublepeaks.py | 2 +- src/diffpy/srfit/fitbase/fitcontribution.py | 2 +- src/diffpy/srfit/fitbase/recipeorganizer.py | 59 +++++++++++++++------ tests/test_recipeorganizer.py | 14 ++--- 6 files changed, 55 insertions(+), 28 deletions(-) diff --git a/docs/examples/npintensity.py b/docs/examples/npintensity.py index 23c23ffa..e05d3fec 100644 --- a/docs/examples/npintensity.py +++ b/docs/examples/npintensity.py @@ -231,7 +231,7 @@ def makeRecipe(strufile, datname): # This creates a callable equation named "bkgd" within the FitContribution, # and turns the polynomial coefficients into Parameters. - contribution.registerStringFunction(bkgdstr, "bkgd") + contribution.register_string_function(bkgdstr, "bkgd") # We will create the broadening function that we need by creating a python # function and registering it with the FitContribution. diff --git a/docs/examples/npintensityII.py b/docs/examples/npintensityII.py index c5683338..19c9c8c7 100644 --- a/docs/examples/npintensityII.py +++ b/docs/examples/npintensityII.py @@ -105,8 +105,8 @@ def makeRecipe(strufile, datname1, datname2): bkgdstr = "b0 + b1*q + b2*q**2 + b3*q**3 + b4*q**4 + b5*q**5 + b6*q**6 +\ b7*q**7 +b8*q**8 + b9*q**9" - contribution1.registerStringFunction(bkgdstr, "bkgd") - contribution2.registerStringFunction(bkgdstr, "bkgd") + contribution1.register_string_function(bkgdstr, "bkgd") + contribution2.register_string_function(bkgdstr, "bkgd") # We will create the broadening function by registering a python function. pi = numpy.pi diff --git a/docs/examples/threedoublepeaks.py b/docs/examples/threedoublepeaks.py index 960820c4..4a3d7eb6 100644 --- a/docs/examples/threedoublepeaks.py +++ b/docs/examples/threedoublepeaks.py @@ -75,7 +75,7 @@ def delta(t, mu): # Here is another one bkgdstr = "b0 + b1*t + b2*t**2 + b3*t**3 + b4*t**4 + b5*t**5 + b6*t**6" - contribution.registerStringFunction(bkgdstr, "bkgd") + contribution.register_string_function(bkgdstr, "bkgd") # Now define our fitting equation. We will hardcode the peak ratios. contribution.set_equation( diff --git a/src/diffpy/srfit/fitbase/fitcontribution.py b/src/diffpy/srfit/fitbase/fitcontribution.py index cdb39862..d5af4709 100644 --- a/src/diffpy/srfit/fitbase/fitcontribution.py +++ b/src/diffpy/srfit/fitbase/fitcontribution.py @@ -284,7 +284,7 @@ def set_equation(self, eqstr, ns={}): A string representation of the equation. Any Parameter registered by addParameter or setProfile, or function registered by setCalculator, register_function or - registerStringFunction can be can be used in the equation + register_string_function can be can be used in the equation by name. Other names will be turned into Parameters of this FitContribution. ns diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index f3c27d57..6ebfd5d1 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -84,6 +84,13 @@ removal_version, ) +registerStringFunction_deprecation_msg = build_deprecation_message( + recipeorganizer_base, + "registerStringFunction", + "register_string_function", + removal_version, +) + class RecipeContainer(Observable, Configurable, Validatable): """Base class for organizing pieces of a FitRecipe. @@ -740,35 +747,41 @@ def registerFunction(self, f, name=None, argnames=None): """ return self.register_function(f, name=name, argnames=argnames) - def registerStringFunction(self, fstr, name, ns={}): + def register_string_function(self, function_str, name, func_params={}): """Register a string function. This creates a function with this class that can be used within string - equations. The resulting equation does not require the arguments to be + equations. The resulting equation does not require the arguments to be passed in the function string, as this will be handled automatically. - Attributes + Parameters ---------- - fstr + function_str : str A string equation to register. - name + name : str The name of the function to be used in equations. - ns + func_params : dict, optional A dictionary of Parameters, indexed by name, that are - used in fstr, but not part of the FitRecipe (default - {}). + used in function_str, but not part of the FitRecipe (default {}). + Raises + ------ + ValueError + If func_params uses a name that is already used for another + managed object. + ValueError + If the function name is the name of another managed object. - Raises ValueError if ns uses a name that is already used for another - managed object. - Raises ValueError if the function name is the name of another managed - object. - - Returns the callable Equation object. + Returns + ------- + equation_object : Equation + The callable Equation object. """ # Build the equation instance. - eq = equationFromString(fstr, self._eqfactory, ns=ns, buildargs=True) + eq = equationFromString( + function_str, self._eqfactory, ns=func_params, buildargs=True + ) eq.name = name # Register any new Parameters. @@ -777,7 +790,21 @@ def registerStringFunction(self, fstr, name, ns={}): # Register the equation as a callable function. argnames = eq.argdict.keys() - return self.register_function(eq, name, argnames) + equation_object = self.register_function( + eq, name=name, argnames=argnames + ) + return equation_object + + @deprecated(registerStringFunction_deprecation_msg) + def registerStringFunction(self, fstr, name, ns={}): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.register_string_function + instead. + """ + return self.register_string_function(fstr, name, func_params=ns) def evaluateEquation(self, eqstr, ns={}): """Evaluate a string equation. diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index c5bb29d9..a2821a9d 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -417,7 +417,7 @@ def __call__(self, x): # Use this in another equation - eq = self.m.registerStringFunction("g/x - 1", "pdf") + eq = self.m.register_string_function("g/x - 1", "pdf") self.assertTrue(numpy.array_equal(g(x) / x - 1, eq())) return @@ -462,7 +462,7 @@ def __call__(self, x): # Use this in another equation - eq = self.m.registerStringFunction("g/x - 1", "pdf") + eq = self.m.register_string_function("g/x - 1", "pdf") self.assertTrue(numpy.array_equal(g(x) / x - 1, eq())) return @@ -492,7 +492,7 @@ def g2(A): ) # Use this in another equation - eq2 = self.m.registerStringFunction("g/x - 1", "pdf") + eq2 = self.m.register_string_function("g/x - 1", "pdf") self.assertTrue(numpy.array_equal(eq() / x - 1, eq2())) # Make sure we can swap out "g". @@ -517,11 +517,11 @@ def __call__(self): return - def testRegisterStringFunction(self): + def test_register_string_function(self): """Test registering string functions in various ways.""" # Make an equation. - eq1 = self.m.registerStringFunction("x**2 + 3", "eq1") + eq1 = self.m.register_string_function("x**2 + 3", "eq1") eq1.x.setValue(0) for p in eq1.args: @@ -537,9 +537,9 @@ def testRegisterStringFunction(self): # Use eq1 in some equations # x**2 (x**2 + 3 - 3) - eq2 = self.m.registerStringFunction("eq1 - 3", "eq2") + eq2 = self.m.register_string_function("eq1 - 3", "eq2") # y**2 - eq3 = self.m.registerStringFunction("eq1(y) - 3", "eq3") + eq3 = self.m.register_string_function("eq1(y) - 3", "eq3") # Test these equations. self.assertEqual(0, eq2()) From 1d91a580455419904341179af8c5deaa9be2be5b Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Mar 2026 16:34:03 -0500 Subject: [PATCH 135/193] evaluateEquation deprecation --- docs/examples/debyemodelII.py | 6 +-- docs/examples/npintensity.py | 2 +- docs/examples/npintensityII.py | 4 +- docs/examples/nppdfcrystal.py | 4 +- docs/examples/nppdfsas.py | 4 +- src/diffpy/srfit/fitbase/recipeorganizer.py | 55 ++++++++++++++++++--- tests/test_recipeorganizer.py | 7 +++ 7 files changed, 64 insertions(+), 18 deletions(-) diff --git a/docs/examples/debyemodelII.py b/docs/examples/debyemodelII.py index 5e82aaee..4817d11d 100644 --- a/docs/examples/debyemodelII.py +++ b/docs/examples/debyemodelII.py @@ -107,14 +107,14 @@ def plotResults(recipe): recipe.highT.profile.set_calculation_range(xmin="obs", xmax="obs") T = recipe.lowT.profile.x U = recipe.lowT.profile.y - # We can use a FitContribution's 'evaluateEquation' method to evaluate + # We can use a FitContribution's 'evaluate_equation' method to evaluate # expressions involving the Parameters and other aspects of the # FitContribution. Here we evaluate the fitting equation, which is always # accessed using the name "eq". We access it this way (rather than through # the Profile's ycalc attribute) because we changed the calculation range # above, and we therefore need to recalculate the profile. - lowU = recipe.lowT.evaluateEquation("eq") - highU = recipe.highT.evaluateEquation("eq") + lowU = recipe.lowT.evaluate_equation("eq") + highU = recipe.highT.evaluate_equation("eq") # Now we can plot this. import pylab diff --git a/docs/examples/npintensity.py b/docs/examples/npintensity.py index e05d3fec..b9d33075 100644 --- a/docs/examples/npintensity.py +++ b/docs/examples/npintensity.py @@ -342,7 +342,7 @@ def plotResults(recipe): Imeas = recipe.bucky.profile.y Icalc = recipe.bucky.profile.ycalc - bkgd = recipe.bucky.evaluateEquation("bkgd") + bkgd = recipe.bucky.evaluate_equation("bkgd") diff = Imeas - Icalc import pylab diff --git a/docs/examples/npintensityII.py b/docs/examples/npintensityII.py index 19c9c8c7..92e5e899 100644 --- a/docs/examples/npintensityII.py +++ b/docs/examples/npintensityII.py @@ -196,11 +196,11 @@ def plotResults(recipe): # Plot this for fun. I1 = recipe.bucky1.profile.y Icalc1 = recipe.bucky1.profile.ycalc - bkgd1 = recipe.bucky1.evaluateEquation("bkgd") + bkgd1 = recipe.bucky1.evaluate_equation("bkgd") diff1 = I1 - Icalc1 I2 = recipe.bucky2.profile.y Icalc2 = recipe.bucky2.profile.ycalc - bkgd2 = recipe.bucky2.evaluateEquation("bkgd") + bkgd2 = recipe.bucky2.evaluate_equation("bkgd") diff2 = I2 - Icalc2 offset = 1.2 * max(I2) * numpy.ones_like(I2) I1 += offset diff --git a/docs/examples/nppdfcrystal.py b/docs/examples/nppdfcrystal.py index 496a1104..95cca7e3 100644 --- a/docs/examples/nppdfcrystal.py +++ b/docs/examples/nppdfcrystal.py @@ -91,10 +91,10 @@ def plotResults(recipe): diffzero = -0.8 * max(g) * numpy.ones_like(g) diff = g - gcalc + diffzero - gcryst = recipe.pdf.evaluateEquation("G") + gcryst = recipe.pdf.evaluate_equation("G") gcryst /= recipe.scale.value - fr = recipe.pdf.evaluateEquation("f") + fr = recipe.pdf.evaluate_equation("f") fr *= max(g) / fr[0] import pylab diff --git a/docs/examples/nppdfsas.py b/docs/examples/nppdfsas.py index 2117ac58..69386a8b 100644 --- a/docs/examples/nppdfsas.py +++ b/docs/examples/nppdfsas.py @@ -156,10 +156,10 @@ def plotResults(recipe): diffzero = -0.8 * max(g) * numpy.ones_like(g) diff = g - gcalc + diffzero - gcryst = recipe.pdf.evaluateEquation("G") + gcryst = recipe.pdf.evaluate_equation("G") gcryst /= recipe.scale.value - fr = recipe.pdf.evaluateEquation("f") + fr = recipe.pdf.evaluate_equation("f") fr *= max(g) / fr[0] import pylab diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 6ebfd5d1..8f322334 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -91,6 +91,13 @@ removal_version, ) +evaluateEquation_deprecation_msg = build_deprecation_message( + recipeorganizer_base, + "evaluateEquation", + "evaluate_equation", + removal_version, +) + class RecipeContainer(Observable, Configurable, Validatable): """Base class for organizing pieces of a FitRecipe. @@ -762,12 +769,12 @@ def register_string_function(self, function_str, name, func_params={}): The name of the function to be used in equations. func_params : dict, optional A dictionary of Parameters, indexed by name, that are - used in function_str, but not part of the FitRecipe (default {}). + used in `function_str`, but not part of the FitRecipe (default {}). Raises ------ ValueError - If func_params uses a name that is already used for another + If `func_params` uses a name that is already used for another managed object. ValueError If the function name is the name of another managed object. @@ -806,6 +813,43 @@ def registerStringFunction(self, fstr, name, ns={}): """ return self.register_string_function(fstr, name, func_params=ns) + def evaluate_equation(self, equation_str, func_params={}): + """Evaluate a string equation. + + This method takes a string representation of a mathematical equation + and evaluates it using the current values of the registered Parameters + in the FitRecipe. Additional parameters not part of the FitRecipe can + also be provided via the `func_params` dictionary. + + Parameters + ---------- + equation_str + The string equation to evaluate. The equation is evaluated at + the current value of the registered Parameters. + func_params : dict, optional + The dictionary of Parameters, indexed by name, that are + used in `equation_str`, but not part of the FitRecipe + (default `{}`). + + Returns + ------- + returned_value : float + The value of the evaluated equation. + + Raises + ------ + ValueError + If `func_params` uses a name that is already used for a + variable. + """ + eq = equationFromString(equation_str, self._eqfactory, func_params) + try: + returned_value = eq() + finally: + self._eqfactory.wipeout(eq) + return returned_value + + @deprecated(evaluateEquation_deprecation_msg) def evaluateEquation(self, eqstr, ns={}): """Evaluate a string equation. @@ -822,12 +866,7 @@ def evaluateEquation(self, eqstr, ns={}): Raises ValueError if ns uses a name that is already used for a variable. """ - eq = equationFromString(eqstr, self._eqfactory, ns) - try: - rv = eq() - finally: - self._eqfactory.wipeout(eq) - return rv + return self.evaluate_equation(eqstr, func_params=ns) def constrain(self, par, con, ns={}): """Constrain a parameter to an equation. diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index a2821a9d..46eabb1b 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -555,6 +555,13 @@ def test_register_string_function(self): return + def test_release_old_equations(self): + """Verify EquationFactory does not hold temporary equations.""" + self.m._new_parameter("x", 12) + self.assertEqual(36, self.m.evaluate_equation("3 * x")) + self.assertEqual(0, len(self.m._eqfactory.equations)) + return + def test_releaseOldEquations(self): """Verify EquationFactory does not hold temporary equations.""" self.m._new_parameter("x", 12) From 4ea52ec12262981654d91cac083c353cc328c52f Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Mar 2026 16:41:48 -0500 Subject: [PATCH 136/193] isConstrained deprecation --- src/diffpy/srfit/fitbase/fitrecipe.py | 4 +- src/diffpy/srfit/fitbase/recipeorganizer.py | 65 +++++++++++++-------- src/diffpy/srfit/structure/sgconstraints.py | 8 +-- tests/test_recipeorganizer.py | 4 +- 4 files changed, 48 insertions(+), 33 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 3000aae4..b91b3bb8 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -195,7 +195,7 @@ class FitRecipe(_fitrecipe_interface, RecipeOrganizer): lambda self: [ v.name for v in self._parameters.values() - if not (self.is_free(v) or self.isConstrained(v)) + if not (self.is_free(v) or self.is_constrained(v)) ], doc="names of the fixed refinable variables", ) @@ -204,7 +204,7 @@ class FitRecipe(_fitrecipe_interface, RecipeOrganizer): [ v.value for v in self._parameters.values() - if not (self.is_free(v) or self.isConstrained(v)) + if not (self.is_free(v) or self.is_constrained(v)) ] ), doc="values of the fixed refinable variables", diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 8f322334..a80d03ae 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -27,7 +27,6 @@ from functools import partial from itertools import chain, groupby -import six from numpy import inf from diffpy.srfit.equation import Equation @@ -98,6 +97,13 @@ removal_version, ) +isConstrained_deprecation_msg = build_deprecation_message( + recipeorganizer_base, + "isConstrained", + "is_constrained", + removal_version, +) + class RecipeContainer(Observable, Configurable, Validatable): """Base class for organizing pieces of a FitRecipe. @@ -851,20 +857,12 @@ def evaluate_equation(self, equation_str, func_params={}): @deprecated(evaluateEquation_deprecation_msg) def evaluateEquation(self, eqstr, ns={}): - """Evaluate a string equation. - - Attributes - ---------- - eqstr - A string equation to evaluate. The equation is evaluated at - the current value of the registered Parameters. - ns - A dictionary of Parameters, indexed by name, that are - used in fstr, but not part of the FitRecipe (default {}). - + """This function has been deprecated and will be removed in + version 4.0.0. - Raises ValueError if ns uses a name that is already used for a - variable. + Please use + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.evaluate_equation + instead. """ return self.evaluate_equation(eqstr, func_params=ns) @@ -894,7 +892,7 @@ def constrain(self, par, con, ns={}): ns. Raises ValueError if par is marked as constant. """ - if isinstance(par, six.string_types): + if isinstance(par, str): name = par par = self.get(name) if par is None: @@ -906,7 +904,7 @@ def constrain(self, par, con, ns={}): if par.const: raise ValueError("The parameter '%s' is constant" % par) - if isinstance(con, six.string_types): + if isinstance(con, str): eqstr = con eq = equationFromString(con, self._eqfactory, ns) else: @@ -927,19 +925,36 @@ def constrain(self, par, con, ns={}): return - def isConstrained(self, par): + def is_constrained(self, parameter): """Determine if a Parameter is constrained in this object. - Attributes + Parameters ---------- - par + parameter : str or Parameter The name of a Parameter or a Parameter to check. + + Returns + ------- + bool + True if the Parameter is constrained in this object, False + otherwise. """ - if isinstance(par, six.string_types): - name = par - par = self.get(name) + if isinstance(parameter, str): + name = parameter + parameter = self.get(name) - return par in self._constraints + return parameter in self._constraints + + @deprecated(isConstrained_deprecation_msg) + def isConstrained(self, par): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.is_constrained + instead. + """ + return self.is_constrained(par) def unconstrain(self, *pars): """Unconstrain a Parameter. @@ -956,7 +971,7 @@ def unconstrain(self, *pars): """ update = False for par in pars: - if isinstance(par, six.string_types): + if isinstance(par, str): name = par par = self.get(name) @@ -1048,7 +1063,7 @@ def restrain(self, res, lb=-inf, ub=inf, sig=1, scaled=False, ns={}): Returns the Restraint object for use with the 'unrestrain' method. """ - if isinstance(res, six.string_types): + if isinstance(res, str): eqstr = res eq = equationFromString(res, self._eqfactory, ns) else: diff --git a/src/diffpy/srfit/structure/sgconstraints.py b/src/diffpy/srfit/structure/sgconstraints.py index 81c71de9..291bb33a 100644 --- a/src/diffpy/srfit/structure/sgconstraints.py +++ b/src/diffpy/srfit/structure/sgconstraints.py @@ -390,7 +390,7 @@ def _clear_constraints(self): for scatterer in scatterers: for par in [scatterer.x, scatterer.y, scatterer.z]: - if scatterer.isConstrained(par): + if scatterer.is_constrained(par): scatterer.unconstrain(par) par.setConst(False) @@ -407,7 +407,7 @@ def _clear_constraints(self): lattice.gamma, ] for par in latpars: - if lattice.isConstrained(par): + if lattice.is_constrained(par): lattice.unconstrain(par) par.setConst(False) @@ -417,14 +417,14 @@ def _clear_constraints(self): if isosymbol: par = scatterer.get(isosymbol) if par is not None: - if scatterer.isConstrained(par): + if scatterer.is_constrained(par): scatterer.unconstrain(par) par.setConst(False) for pname in adpsymbols: par = scatterer.get(pname) if par is not None: - if scatterer.isConstrained(par): + if scatterer.is_constrained(par): scatterer.unconstrain(par) par.setConst(False) diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index 46eabb1b..f7200557 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -259,7 +259,7 @@ def testRemoveParameter(self): self.assertRaises(ValueError, m._remove_parameter, c) return - def testConstrain(self): + def test_constrain(self): """Test the constrain method.""" p1 = self.m._new_parameter("p1", 1) @@ -273,7 +273,7 @@ def testConstrain(self): self.assertTrue(p1.constrained) self.assertTrue(p1 in self.m._constraints) self.assertEqual(1, len(self.m._constraints)) - self.assertTrue(self.m.isConstrained(p1)) + self.assertTrue(self.m.is_constrained(p1)) p2.setValue(10) self.m._constraints[p1].update() From 1ed19da67a6fca608e228ac58fcbf0215b65c6e9 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Mar 2026 16:44:09 -0500 Subject: [PATCH 137/193] replace par with parameter --- src/diffpy/srfit/fitbase/recipeorganizer.py | 107 ++++++++++---------- 1 file changed, 55 insertions(+), 52 deletions(-) diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index a80d03ae..fd71a512 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -203,9 +203,9 @@ def iterate_over_parameters(self, pattern="", recurse=True): print(f"{param.name}={param.value}") """ regexp = re.compile(pattern) - for par in list(self._parameters.values()): - if regexp.search(par.name): - yield par + for parameter in list(self._parameters.values()): + if regexp.search(parameter.name): + yield parameter if not recurse: return # Iterate over objects within the managed dictionaries. @@ -214,8 +214,10 @@ def iterate_over_parameters(self, pattern="", recurse=True): for m in managed: for obj in m.values(): if hasattr(obj, "iterate_over_parameters"): - for par in obj.iterate_over_parameters(pattern=pattern): - yield par + for parameter in obj.iterate_over_parameters( + pattern=pattern + ): + yield parameter return @deprecated(iterPars_deprecation_msg) @@ -274,11 +276,11 @@ def __dir__(self): def __setattr__(self, name, value): """Parameter access and object checking.""" if name in self._parameters: - par = self._parameters[name] + parameter = self._parameters[name] if isinstance(value, Parameter): - par.value = value.value + parameter.value = value.value else: - par.value = value + parameter.value = value return m = self.get(name) @@ -540,14 +542,14 @@ def _new_parameter(self, name, value, check=True): self._add_parameter(p, check) return p - def _add_parameter(self, par, check=True): + def _add_parameter(self, parameter, check=True): """Store a Parameter. Parameters added in this way are registered with the _eqfactory. Attributes ---------- - par + parameter The Parameter to be stored. check If True (default), a ValueError is raised a Parameter of @@ -560,13 +562,13 @@ def _add_parameter(self, par, check=True): """ # Store the Parameter - RecipeContainer._add_object(self, par, self._parameters, check) + RecipeContainer._add_object(self, parameter, self._parameters, check) # Register the Parameter - self._eqfactory.registerArgument(par.name, par) + self._eqfactory.registerArgument(parameter.name, parameter) return - def _remove_parameter(self, par): + def _remove_parameter(self, parameter): """Remove a parameter. This de-registers the Parameter with the _eqfactory. The @@ -575,10 +577,11 @@ def _remove_parameter(self, par): Note that constraints and restraints involving the Parameter are not modified. - Raises ValueError if par is not part of the RecipeOrganizer. + Raises ValueError if parameter is not part of the + RecipeOrganizer. """ - self._remove_object(par, self._parameters) - self._eqfactory.deRegisterBuilder(par.name) + self._remove_object(parameter, self._parameters) + self._eqfactory.deRegisterBuilder(parameter.name) return def register_calculator(self, calculator, argnames=None): @@ -610,10 +613,10 @@ def register_calculator(self, calculator, argnames=None): for pname in argnames: if pname not in self._eqfactory.builders: - par = self._new_parameter(pname, 0) + parameter = self._new_parameter(pname, 0) else: - par = self.get(pname) - calculator.addLiteral(par) + parameter = self.get(pname) + calculator.addLiteral(parameter) # Now return an equation object eq = self._eqfactory.makeEquation(calculator.name) @@ -738,8 +741,8 @@ def register_function(self, function, name=None, argnames=None): if isinstance(function, Calculator): for pname in argnames: - par = self.get(pname) - function.addLiteral(par) + parameter = self.get(pname) + function.addLiteral(parameter) self._eqfactory.registerOperator(name, function) else: self._eqfactory.register_function(name, function, argnames) @@ -798,8 +801,8 @@ def register_string_function(self, function_str, name, func_params={}): eq.name = name # Register any new Parameters. - for par in self._eqfactory.newargs: - self._add_parameter(par) + for parameter in self._eqfactory.newargs: + self._add_parameter(parameter) # Register the equation as a callable function. argnames = eq.argdict.keys() @@ -866,14 +869,14 @@ def evaluateEquation(self, eqstr, ns={}): """ return self.evaluate_equation(eqstr, func_params=ns) - def constrain(self, par, con, ns={}): + def constrain(self, parameter, con, ns={}): """Constrain a parameter to an equation. Note that only one constraint can exist on a Parameter at a time. Attributes ---------- - par + parameter The name of a Parameter or a Parameter to constrain. con A string representation of the constraint equation or a @@ -888,21 +891,21 @@ def constrain(self, par, con, ns={}): Raises ValueError if ns uses a name that is already used for a variable. - Raises ValueError if par is a string but not part of this object or in - ns. - Raises ValueError if par is marked as constant. + Raises ValueError if parameter is a string but not part of this + object or in ns. + Raises ValueError if parameter is marked as constant. """ - if isinstance(par, str): - name = par - par = self.get(name) - if par is None: - par = ns.get(name) + if isinstance(parameter, str): + name = parameter + parameter = self.get(name) + if parameter is None: + parameter = ns.get(name) - if par is None: + if parameter is None: raise ValueError("The parameter cannot be found") - if par.const: - raise ValueError("The parameter '%s' is constant" % par) + if parameter.const: + raise ValueError("The parameter '%s' is constant" % parameter) if isinstance(con, str): eqstr = con @@ -911,14 +914,14 @@ def constrain(self, par, con, ns={}): eq = Equation(root=con) eqstr = con.name - eq.name = "_constraint_%s" % par.name + eq.name = "_constraint_%s" % parameter.name # Make and store the constraint con = Constraint() - con.constrain(par, eq) + con.constrain(parameter, eq) # Store the equation string so it can be shown later. con.eqstr = eqstr - self._constraints[par] = con + self._constraints[parameter] = con # Our configuration changed self._update_configuration() @@ -946,7 +949,7 @@ def is_constrained(self, parameter): return parameter in self._constraints @deprecated(isConstrained_deprecation_msg) - def isConstrained(self, par): + def isConstrained(self, parameter): """This function has been deprecated and will be removed in version 4.0.0. @@ -954,7 +957,7 @@ def isConstrained(self, par): diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.is_constrained instead. """ - return self.is_constrained(par) + return self.is_constrained(parameter) def unconstrain(self, *pars): """Unconstrain a Parameter. @@ -970,17 +973,17 @@ def unconstrain(self, *pars): Raises ValueError if the Parameter is not constrained. """ update = False - for par in pars: - if isinstance(par, str): - name = par - par = self.get(name) + for parameter in pars: + if isinstance(parameter, str): + name = parameter + parameter = self.get(name) - if par is None: + if parameter is None: raise ValueError("The parameter cannot be found") - if par in self._constraints: - self._constraints[par].unconstrain() - del self._constraints[par] + if parameter in self._constraints: + self._constraints[parameter].unconstrain() + del self._constraints[parameter] update = True if update: @@ -1213,13 +1216,13 @@ def _format_constraints(self): cdict = self._get_constraints() # Find each constraint and format the equation clines = [] - for par, con in cdict.items(): - loc = self._locate_managed_object(par) + for parameter, con in cdict.items(): + loc = self._locate_managed_object(parameter) if loc: locstr = ".".join(o.name for o in loc[1:]) clines.append("%s <-- %s" % (locstr, con.eqstr)) else: - clines.append("%s <-- %s" % (par.name, con.eqstr)) + clines.append("%s <-- %s" % (parameter.name, con.eqstr)) clines.sort(key=numstr) return clines From 99f4e143ed3da9deb667b498e6a7d7cf6f6a8baa Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Mar 2026 16:54:37 -0500 Subject: [PATCH 138/193] getConstrainedPars deprecation, and write a test for it :) --- src/diffpy/srfit/fitbase/recipeorganizer.py | 30 +++++++++++++++++++-- tests/test_recipeorganizer.py | 12 +++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index fd71a512..b02d75cb 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -104,6 +104,13 @@ removal_version, ) +getConstrainedPars_deprecation_msg = build_deprecation_message( + recipeorganizer_base, + "getConstrainedPars", + "get_constrained_parmeters", + removal_version, +) + class RecipeContainer(Observable, Configurable, Validatable): """Base class for organizing pieces of a FitRecipe. @@ -996,6 +1003,26 @@ def unconstrain(self, *pars): return + def get_constrained_parmeters(self, recurse=False): + """Get a list of constrained managed Parameters in this object. + + Parameters + ---------- + recurse : bool, optional + If False (default), only constrained Parameters in + this object are returned. If True, constrained + Parameters in managed sub-objects are also included. + + Return + ------ + constrained_params : list + A list of constrained managed Parameters in this object. + """ + const = self._get_constraints(recurse) + constrained_params = list(const.keys()) + return constrained_params + + @deprecated(getConstrainedPars_deprecation_msg) def getConstrainedPars(self, recurse=False): """Get a list of constrained managed Parameters in this object. @@ -1005,8 +1032,7 @@ def getConstrainedPars(self, recurse=False): Recurse into managed objects and retrieve their constrained Parameters as well (default False). """ - const = self._get_constraints(recurse) - return const.keys() + return self.get_constrained_parmeters(recurse=recurse) def clearConstraints(self, recurse=False): """Clear all constraints managed by this organizer. diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index f7200557..e7366c48 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -270,6 +270,18 @@ def test_constrain(self): self.assertEqual(0, len(self.m._constraints)) self.m.constrain(p1, "2*p2") + actual_constrained_params = self.m.getConstrainedPars() + actual_constrained_params = [p.name for p in actual_constrained_params] + expected_constrained_params = [p1.name] + + assert actual_constrained_params == expected_constrained_params + + actual_constrained_params = self.m.get_constrained_parmeters() + actual_constrained_params = [p.name for p in actual_constrained_params] + expected_constrained_params = [p1.name] + + assert actual_constrained_params == expected_constrained_params + self.assertTrue(p1.constrained) self.assertTrue(p1 in self.m._constraints) self.assertEqual(1, len(self.m._constraints)) From 6aa1e73067178ec39c44caabaf364e8fe6843783 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Mar 2026 16:56:47 -0500 Subject: [PATCH 139/193] small fix --- src/diffpy/srfit/fitbase/recipeorganizer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index b02d75cb..a46e77f0 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -1015,11 +1015,11 @@ def get_constrained_parmeters(self, recurse=False): Return ------ - constrained_params : list + constrained_params : list of Parameter A list of constrained managed Parameters in this object. """ const = self._get_constraints(recurse) - constrained_params = list(const.keys()) + constrained_params = const.keys() return constrained_params @deprecated(getConstrainedPars_deprecation_msg) From 29671add6929effabea46089cbe709458f2fac17 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Mar 2026 17:09:00 -0500 Subject: [PATCH 140/193] clearConstraints deprecation, and write small test --- src/diffpy/srfit/fitbase/recipeorganizer.py | 38 +++++++++++++++------ tests/test_recipeorganizer.py | 20 +++++++++++ 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index a46e77f0..90a8b492 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -111,6 +111,13 @@ removal_version, ) +clearConstraints_deprecation_msg = build_deprecation_message( + recipeorganizer_base, + "clearConstraints", + "clear_all_constraints", + removal_version, +) + class RecipeContainer(Observable, Configurable, Validatable): """Base class for organizing pieces of a FitRecipe. @@ -1034,27 +1041,38 @@ def getConstrainedPars(self, recurse=False): """ return self.get_constrained_parmeters(recurse=recurse) - def clearConstraints(self, recurse=False): + def clear_all_constraints(self, recurse=False): """Clear all constraints managed by this organizer. - Attributes - ---------- - recurse - Recurse into managed objects and clear all constraints - found there as well. - - This removes constraints that are held in this organizer, no matter where the constrained parameters are from. + + Parameters + ---------- + recurse : bool, optional + If False (default), only constraints in this object + are cleared. If True, constraints in managed + sub-objects are also cleared. """ if self._constraints: self.unconstrain(*self._constraints) if recurse: for m in filter(_has_clear_constraints, self._iter_managed()): - m.clearConstraints(recurse) + m.clear_all_constraints(recurse) return + @deprecated(clearConstraints_deprecation_msg) + def clearConstraints(self, recurse=False): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.clear_all_constraints + instead. + """ + return self.clear_all_constraints(recurse=recurse) + def restrain(self, res, lb=-inf, ub=inf, sig=1, scaled=False, ns={}): """Restrain an expression to specified bounds. @@ -1392,7 +1410,7 @@ def equationFromString( def _has_clear_constraints(msg): - return hasattr(msg, "clearConstraints") + return hasattr(msg, "clear_all_constraints") def _has_clear_restraints(msg): diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index e7366c48..43846a13 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -306,6 +306,26 @@ def test_constrain(self): p2.setValue(7) self.m._constraints[p1].update() self.assertEqual(7, p1.getValue()) + + self.m.clear_all_constraints() + actual_constrained_params = self.m.get_constrained_parmeters() + actual_constrained_params = [p.name for p in actual_constrained_params] + expected_constrained_params = [] + assert actual_constrained_params == expected_constrained_params + + # add constraint back and test the old function name `clearConstraints` + self.m.constrain(p1, p2) + actual_constrained_params = self.m.get_constrained_parmeters() + actual_constrained_params = [p.name for p in actual_constrained_params] + expected_constrained_params = [p1.name] + assert actual_constrained_params == expected_constrained_params + + self.m.clearConstraints() + actual_constrained_params = self.m.get_constrained_parmeters() + actual_constrained_params = [p.name for p in actual_constrained_params] + expected_constrained_params = [] + assert actual_constrained_params == expected_constrained_params + return def testRestrain(self): From 6d6673c39590f5d61e64faef232c5771efcd4b1b Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Mar 2026 17:29:42 -0500 Subject: [PATCH 141/193] clean up and fix variable names in restrain and constrain methods --- src/diffpy/srfit/fitbase/recipeorganizer.py | 140 +++++++++++--------- src/diffpy/srfit/structure/sgconstraints.py | 6 +- tests/test_recipeorganizer.py | 4 +- 3 files changed, 85 insertions(+), 65 deletions(-) diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 90a8b492..9faef40f 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -883,37 +883,41 @@ def evaluateEquation(self, eqstr, ns={}): """ return self.evaluate_equation(eqstr, func_params=ns) - def constrain(self, parameter, con, ns={}): + def constrain(self, parameter, constraint_eq, params={}): """Constrain a parameter to an equation. Note that only one constraint can exist on a Parameter at a time. - Attributes + Parameters ---------- - parameter + parameter : str or Parameter The name of a Parameter or a Parameter to constrain. - con + constraint_eq : str or Equation A string representation of the constraint equation or a - Parameter to constrain to. A constraint equation must + Parameter to constrain to. A constraint equation must consist of numpy operators and "known" Parameters. - Parameters are known if they are in the ns argument, or if - they are managed by this object. - ns + Parameters are known if they are in the `params` + argument, or if they are managed by this object. + params : dict, optional A dictionary of Parameters, indexed by name, that are used - in the parameter, but not part of this object (default {}). - + in `parameter`, but not part of this object (default {}). - Raises ValueError if ns uses a name that is already used for a - variable. - Raises ValueError if parameter is a string but not part of this - object or in ns. - Raises ValueError if parameter is marked as constant. + Raises + ------ + ValueError + If `params` uses a name that is already used for a + variable. + ValueError + If `parameter` is a string but not part of this object or + in `params`. + ValueError + If `parameter` is marked as constant. """ if isinstance(parameter, str): name = parameter parameter = self.get(name) if parameter is None: - parameter = ns.get(name) + parameter = params.get(name) if parameter is None: raise ValueError("The parameter cannot be found") @@ -921,21 +925,21 @@ def constrain(self, parameter, con, ns={}): if parameter.const: raise ValueError("The parameter '%s' is constant" % parameter) - if isinstance(con, str): - eqstr = con - eq = equationFromString(con, self._eqfactory, ns) + if isinstance(constraint_eq, str): + eqstr = constraint_eq + eq = equationFromString(constraint_eq, self._eqfactory, params) else: - eq = Equation(root=con) - eqstr = con.name + eq = Equation(root=constraint_eq) + eqstr = constraint_eq.name eq.name = "_constraint_%s" % parameter.name # Make and store the constraint - con = Constraint() - con.constrain(parameter, eq) + constraint_eq = Constraint() + constraint_eq.constrain(parameter, eq) # Store the equation string so it can be shown later. - con.eqstr = eqstr - self._constraints[parameter] = con + constraint_eq.eqstr = eqstr + self._constraints[parameter] = constraint_eq # Our configuration changed self._update_configuration() @@ -1073,55 +1077,67 @@ def clearConstraints(self, recurse=False): """ return self.clear_all_constraints(recurse=recurse) - def restrain(self, res, lb=-inf, ub=inf, sig=1, scaled=False, ns={}): + def restrain( + self, param_or_eq, lb=-inf, ub=inf, sig=1, scaled=False, params={} + ): """Restrain an expression to specified bounds. - Attributes + Parameters ---------- - res - An equation string or Parameter to restrain. - lb - The lower bound on the restraint evaluation (default -inf). - ub - The lower bound on the restraint evaluation (default inf). - sig - The uncertainty on the bounds (default 1). - scaled - A flag indicating if the restraint is scaled (multiplied) - by the unrestrained point-average chi^2 (chi^2/numpoints) - (default False). - ns - A dictionary of Parameters, indexed by name, that are used - in the equation string, but not part of the RecipeOrganizer - (default {}). + param_or_eq : str or Parameter + The equation string or a Parameter object to restrain. + lb : float, optional + The lower bound for the restraint evaluation (default is -inf). + ub : float, optional + The upper bound for the restraint evaluation (default is inf). + sig : float, optional + The uncertainty associated with the bounds (default is 1). + scaled : bool, optional + If True, the restraint penalty is scaled by the unrestrained + point-average chi^2 (chi^2/numpoints) (default is False). + params : dict, optional + The dictionary of Parameters, indexed by name, that are used in the + equation string but are not part of the RecipeOrganizer + (default is {}). + Returns + ------- + Restraint + The created Restraint object, which can be used with the + 'unrestrain' method. - The penalty is calculated as - (max(0, lb - val, val - ub)/sig)**2 - and val is the value of the calculated equation. This is multiplied by - the average chi^2 if scaled is True. + Notes + ----- + The penalty is calculated as: + .. + (max(0, lb - val, val - ub) / sig) ** 2 - Raises ValueError if ns uses a name that is already used for a - Parameter. - Raises ValueError if res depends on a Parameter that is not part of - the RecipeOrganizer and that is not defined in ns. + where `val` is the value of the evaluated equation. + If `scaled` is True, this penalty is multiplied by + the average chi^2. - Returns the Restraint object for use with the 'unrestrain' method. + Raises + ------ + ValueError + If `func_params` contains a name that is already used + for a Parameter. + ValueError + If `param_or_eq` depends on a Parameter that is not part of the + RecipeOrganizer and is not defined in `func_params`. """ - - if isinstance(res, str): - eqstr = res - eq = equationFromString(res, self._eqfactory, ns) + if isinstance(param_or_eq, str): + eqstr = param_or_eq + eq = equationFromString(param_or_eq, self._eqfactory, params) else: - eq = Equation(root=res) - eqstr = res.name + eq = Equation(root=param_or_eq) + eqstr = param_or_eq.name # Make and store the restraint - res = Restraint(eq, lb, ub, sig, scaled) - res.eqstr = eqstr - self.addRestraint(res) - return res + param_or_eq = Restraint(eq, lb, ub, sig, scaled) + param_or_eq.eqstr = eqstr + self.addRestraint(param_or_eq) + return param_or_eq def addRestraint(self, res): """Add a Restraint instance to the RecipeOrganizer. diff --git a/src/diffpy/srfit/structure/sgconstraints.py b/src/diffpy/srfit/structure/sgconstraints.py index 291bb33a..8e1e198d 100644 --- a/src/diffpy/srfit/structure/sgconstraints.py +++ b/src/diffpy/srfit/structure/sgconstraints.py @@ -596,7 +596,9 @@ def _constrain_adps(self, positions): continue isoidx.append(j) scatterer = scatterers[j] - scatterer.constrain(isosymbol, isoname, ns=self._parameters) + scatterer.constrain( + isosymbol, isoname, params=self._parameters + ) fadp = g.UFormulas(adpnames) @@ -809,7 +811,7 @@ 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, params=ns) return diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index 43846a13..17b6a758 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -352,7 +352,9 @@ def testRestrain(self): # 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", params={"p2": p3} + ) return def testGetConstraints(self): From 6a299836780d6451886fb704cd20cf9fb3aecc3c Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Mar 2026 17:58:10 -0500 Subject: [PATCH 142/193] minor docstring typos --- src/diffpy/srfit/fitbase/recipeorganizer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 9faef40f..495b3706 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -613,7 +613,7 @@ def register_calculator(self, calculator, argnames=None): calculator : Calculator object The Calculator to register. argnames : list or None, optional - The names of the arguments to calculator (list or None). + The names of the arguments to `calculator` (list or None). If this is None, then the argument names will be extracted from the function. """ @@ -665,13 +665,13 @@ def register_function(self, function, name=None, argnames=None): this is None (default), the method will try to determine the name of the function automatically. argnames : list or None, optional - The names of the arguments to 'function' (list or None). + The names of the arguments to `function` (list or None). If this is None (default), then the argument names will be extracted from the function. Note ---- - name and argnames can be extracted from regular Python + The `name` and `argnames` args can be extracted from regular Python functions (of type ), bound class methods, and callable classes. From 1c11b3196e3028103666c5083a9b53d6db9c60fe Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 6 Mar 2026 18:01:38 -0500 Subject: [PATCH 143/193] news --- news/recipeorg-dep1.rst | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 news/recipeorg-dep1.rst diff --git a/news/recipeorg-dep1.rst b/news/recipeorg-dep1.rst new file mode 100644 index 00000000..aff30369 --- /dev/null +++ b/news/recipeorg-dep1.rst @@ -0,0 +1,37 @@ +**Added:** + +* Added ``iterate_over_parameters`` method. +* Added ``register_calculator`` method. +* Added ``register_function`` method. +* Added ``register_string_function`` method. +* Added ``evaluate_equation`` method. +* Added ``is_constrained`` method. +* Added ``get_constrained_parameters`` method. +* Added ``clear_all_constraints`` method. + +**Changed:** + +* + +**Deprecated:** + +* Deprecated ``iterPars`` method. Use ``iterate_over_parameters`` instead. +* Deprecated ``registerCalculator`` method. Use ``register_calculator`` instead. +* Deprecated ``registerFunction`` method. Use ``register_function`` instead. +* Deprecated ``registerStringFunction`` method. Use ``register_string_function`` instead. +* Deprecated ``evaluateEquation`` method. Use ``evaluate_equation`` instead. +* Deprecated ``isConstrained`` method. Use ``is_constrained`` instead. +* Deprecated ``getConstrainedPars`` method. Use ``get_constrained_parameters`` instead. +* Deprecated ``clearConstraints`` method. Use ``clear_all_constraints`` instead. + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 3b9b2573a88d6a5495bd1bffcbb05a43bbe55aee Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 9 Mar 2026 14:17:36 -0400 Subject: [PATCH 144/193] constrain and unconstrain deprecation --- docs/examples/coreshellnp.py | 10 +-- docs/examples/crystalpdfall.py | 14 ++-- docs/examples/crystalpdftwodata.py | 4 +- docs/examples/crystalpdftwophase.py | 8 +-- docs/examples/debyemodelII.py | 4 +- docs/examples/npintensity.py | 6 +- docs/examples/npintensityII.py | 6 +- docs/examples/nppdfobjcryst.py | 4 +- docs/examples/nppdfsas.py | 8 +-- docs/examples/simplepdftwophase.py | 4 +- docs/examples/threedoublepeaks.py | 18 ++--- src/diffpy/srfit/fitbase/constraint.py | 60 ++++++++++++++-- src/diffpy/srfit/fitbase/fitrecipe.py | 52 +++++++++++--- src/diffpy/srfit/fitbase/recipeorganizer.py | 79 ++++++++++++++++++--- src/diffpy/srfit/pdf/pdfcontribution.py | 4 +- src/diffpy/srfit/structure/sgconstraints.py | 30 ++++---- tests/conftest.py | 6 +- tests/test_constraint.py | 39 ++++++++++ tests/test_fitrecipe.py | 10 +-- tests/test_recipeorganizer.py | 16 ++--- tests/test_sgconstraints.py | 6 +- 21 files changed, 286 insertions(+), 102 deletions(-) diff --git a/docs/examples/coreshellnp.py b/docs/examples/coreshellnp.py index 430726b1..4a413a70 100644 --- a/docs/examples/coreshellnp.py +++ b/docs/examples/coreshellnp.py @@ -91,14 +91,14 @@ def makeRecipe(stru1, stru2, datname): # diameter to twice the shell radius. recipe.add_variable(contribution.radius, 15) recipe.add_variable(contribution.thickness, 11) - recipe.constrain(contribution.psize, "2 * radius") + recipe.constrain_parameter(contribution.psize, "2 * radius") # Configure the fit variables # Start by configuring the scale factor and resolution factors. # We want the sum of the phase scale factors to be 1. recipe.create_new_variable("scale_CdS", 0.7) - recipe.constrain(generator_cds.scale, "scale_CdS") - recipe.constrain(generator_zns.scale, "1 - scale_CdS") + recipe.constrain_parameter(generator_cds.scale, "scale_CdS") + recipe.constrain_parameter(generator_zns.scale, "1 - scale_CdS") # We also want the resolution factor to be the same on each. # Vary the global scale as well. @@ -117,7 +117,7 @@ def makeRecipe(stru1, stru2, datname): ) # Since we know these have stacking disorder, constrain the B33 adps for # each atom type. - recipe.constrain("B33_1_cds", "B33_0_cds") + recipe.constrain_parameter("B33_1_cds", "B33_0_cds") recipe.add_variable(generator_cds.delta2, name="delta2_cds", value=5) phase_zns = generator_zns.phase @@ -128,7 +128,7 @@ def makeRecipe(stru1, stru2, datname): recipe.add_variable( phase_zns.sgpars.xyzpars.z_1, name="z_1_zns", tag="xyz" ) - recipe.constrain("B33_1_zns", "B33_0_zns") + recipe.constrain_parameter("B33_1_zns", "B33_0_zns") recipe.add_variable(generator_zns.delta2, name="delta2_zns", value=2.5) # Give the recipe away so it can be used! diff --git a/docs/examples/crystalpdfall.py b/docs/examples/crystalpdfall.py index db5fefa3..32e573f0 100644 --- a/docs/examples/crystalpdfall.py +++ b/docs/examples/crystalpdfall.py @@ -113,15 +113,15 @@ def makeRecipe( for par in phase_ni.sgpars: recipe.add_variable(par, name=par.name + "_ni") delta2_ni = recipe.create_new_variable("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) + recipe.constrain_parameter(xgenerator_ni.delta2, delta2_ni) + recipe.constrain_parameter(ngenerator_ni.delta2, delta2_ni) + recipe.constrain_parameter(xgenerator_sini_ni.delta2, delta2_ni) for par in phase_si.sgpars: recipe.add_variable(par, name=par.name + "_si") delta2_si = recipe.create_new_variable("delta2_si", 2.5) - recipe.constrain(xgenerator_si.delta2, delta2_si) - recipe.constrain(xgenerator_sini_si.delta2, delta2_si) + recipe.constrain_parameter(xgenerator_si.delta2, delta2_si) + recipe.constrain_parameter(xgenerator_sini_si.delta2, delta2_si) # Now the experimental parameters recipe.add_variable(xgenerator_ni.scale, name="xscale_ni") @@ -129,8 +129,8 @@ def makeRecipe( recipe.add_variable(ngenerator_ni.scale, name="nscale_ni") recipe.add_variable(xcontribution_sini.scale, 1.0, "xscale_sini") recipe.create_new_variable("pscale_sini_ni", 0.8) - recipe.constrain(xgenerator_sini_ni.scale, "pscale_sini_ni") - recipe.constrain(xgenerator_sini_si.scale, "1 - pscale_sini_ni") + recipe.constrain_parameter(xgenerator_sini_ni.scale, "pscale_sini_ni") + recipe.constrain_parameter(xgenerator_sini_si.scale, "1 - pscale_sini_ni") # The qdamp parameters are too correlated to vary so we fix them based on # previous measurements. diff --git a/docs/examples/crystalpdftwodata.py b/docs/examples/crystalpdftwodata.py index 601cb01b..e82374b2 100644 --- a/docs/examples/crystalpdftwodata.py +++ b/docs/examples/crystalpdftwodata.py @@ -121,8 +121,8 @@ def makeRecipe(ciffile, xdatname, ndatname): # delta2 is a non-structual material property. Thus, we constrain together # delta2 Parameter from each PDFGenerator. delta2 = recipe.create_new_variable("delta2", 2) - recipe.constrain(xgenerator.delta2, delta2) - recipe.constrain(ngenerator.delta2, delta2) + recipe.constrain_parameter(xgenerator.delta2, delta2) + recipe.constrain_parameter(ngenerator.delta2, delta2) # We only need to constrain phase properties once since there is a single # ObjCrystCrystalParSet for the Crystal. diff --git a/docs/examples/crystalpdftwophase.py b/docs/examples/crystalpdftwophase.py index de9cd965..37feaad5 100644 --- a/docs/examples/crystalpdftwophase.py +++ b/docs/examples/crystalpdftwophase.py @@ -90,12 +90,12 @@ def makeRecipe(niciffile, siciffile, datname): # Start by configuring the scale factor and resolution factors. # We want the sum of the phase scale factors to be 1. recipe.create_new_variable("scale_ni", 0.1) - recipe.constrain(generator_ni.scale, "scale_ni") - recipe.constrain(generator_si.scale, "1 - scale_ni") + recipe.constrain_parameter(generator_ni.scale, "scale_ni") + recipe.constrain_parameter(generator_si.scale, "1 - scale_ni") # We also want the resolution factor to be the same on each. recipe.create_new_variable("qdamp", 0.03) - recipe.constrain(generator_ni.qdamp, "qdamp") - recipe.constrain(generator_si.qdamp, "qdamp") + recipe.constrain_parameter(generator_ni.qdamp, "qdamp") + recipe.constrain_parameter(generator_si.qdamp, "qdamp") # Vary the global scale as well. recipe.add_variable(contribution.scale, 1) diff --git a/docs/examples/debyemodelII.py b/docs/examples/debyemodelII.py index 4817d11d..4115179f 100644 --- a/docs/examples/debyemodelII.py +++ b/docs/examples/debyemodelII.py @@ -89,8 +89,8 @@ def makeRecipeII(): # We create a new Variable and use the recipe's "constrain" method to # associate the Debye temperature parameters with that variable. recipe.create_new_variable("thetaD", 100) - recipe.constrain(recipe.lowT.thetaD, "thetaD") - recipe.constrain(recipe.highT.thetaD, "thetaD") + recipe.constrain_parameter(recipe.lowT.thetaD, "thetaD") + recipe.constrain_parameter(recipe.highT.thetaD, "thetaD") return recipe diff --git a/docs/examples/npintensity.py b/docs/examples/npintensity.py index b9d33075..54843d9f 100644 --- a/docs/examples/npintensity.py +++ b/docs/examples/npintensity.py @@ -290,15 +290,15 @@ def gaussian(q, q0, width): lattice = phase.getLattice() a = lattice.a recipe.add_variable(a) - recipe.constrain(lattice.b, a) - recipe.constrain(lattice.c, a) + recipe.constrain_parameter(lattice.b, a) + recipe.constrain_parameter(lattice.c, a) # We want to refine the thermal parameters as well. We will add a new # Variable that we call "Uiso" and constrain the atomic Uiso values to # this. Note that we don't give Uiso an initial value. The initial value # will be inferred from the following constraints. Uiso = recipe.create_new_variable("Uiso") for atom in phase.getScatterers(): - recipe.constrain(atom.Uiso, Uiso) + recipe.constrain_parameter(atom.Uiso, Uiso) # Give the recipe away so it can be used! return recipe diff --git a/docs/examples/npintensityII.py b/docs/examples/npintensityII.py index 92e5e899..69b54efc 100644 --- a/docs/examples/npintensityII.py +++ b/docs/examples/npintensityII.py @@ -173,15 +173,15 @@ def gaussian(q, q0, width): a = recipe.add_variable(lattice.a) # We want to allow for isotropic expansion, so we'll make constraints for # that. - recipe.constrain(lattice.b, a) - recipe.constrain(lattice.c, a) + recipe.constrain_parameter(lattice.b, a) + recipe.constrain_parameter(lattice.c, a) # We want to refine the thermal parameters as well. We will add a new # variable that we call "Uiso" and constrain the atomic Uiso values to # this. Note that we don't give Uiso an initial value. The initial value # will be inferred from the subsequent constraints. Uiso = recipe.create_new_variable("Uiso") for atom in phase.getScatterers(): - recipe.constrain(atom.Uiso, Uiso) + recipe.constrain_parameter(atom.Uiso, Uiso) # Give the recipe away so it can be used! return recipe diff --git a/docs/examples/nppdfobjcryst.py b/docs/examples/nppdfobjcryst.py index cce39962..33a387ab 100644 --- a/docs/examples/nppdfobjcryst.py +++ b/docs/examples/nppdfobjcryst.py @@ -73,7 +73,7 @@ def makeRecipe(molecule, datname): # has no scattering power. It is only used as a reference point for # our bond length. We don't want to constrain it. if not atom.isDummy(): - recipe.constrain(atom.Biso, Biso) + recipe.constrain_parameter(atom.Biso, Biso) # We need to let the molecule expand. If we were modeling it as a crystal, # we could let the unit cell expand. For instruction purposes, we use a @@ -97,7 +97,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) - recipe.constrain(par, radius) + recipe.constrain_parameter(par, radius) # Add the correlation term, scale. The scale is too short to effectively # determine qdamp. diff --git a/docs/examples/nppdfsas.py b/docs/examples/nppdfsas.py index 69386a8b..adaae5bc 100644 --- a/docs/examples/nppdfsas.py +++ b/docs/examples/nppdfsas.py @@ -113,8 +113,8 @@ def makeRecipe(ciffile, grdata, iqdata): # Even though the cfcalculator and sasgenerator depend on the same sas # model, we must still constrain the cfcalculator Parameters so that it is # informed of changes in the refined parameters. - recipe.constrain(cfcalculator.radius_a, "radius_a") - recipe.constrain(cfcalculator.radius_b, "radius_b") + recipe.constrain_parameter(cfcalculator.radius_a, "radius_a") + recipe.constrain_parameter(cfcalculator.radius_b, "radius_b") return recipe @@ -126,9 +126,9 @@ def fitRecipe(recipe): recipe.set_weight(recipe.pdf, 0) recipe.fix("all") recipe.free("radius_a", "radius_b", iqscale=1e8) - recipe.constrain("radius_b", "radius_a") + recipe.constrain_parameter("radius_b", "radius_a") scipyOptimize(recipe) - recipe.unconstrain("radius_b") + recipe.unconstrain_parameter("radius_b") # Tune PDF recipe.set_weight(recipe.pdf, 1) diff --git a/docs/examples/simplepdftwophase.py b/docs/examples/simplepdftwophase.py index 7b252baf..209abcf0 100644 --- a/docs/examples/simplepdftwophase.py +++ b/docs/examples/simplepdftwophase.py @@ -47,8 +47,8 @@ def makeRecipe(niciffile, siciffile, datname): # Start by configuring the scale factor and resolution factors. # We want the sum of the phase scale factors to be 1. recipe.create_new_variable("scale_ni", 0.1) - recipe.constrain(contribution.ni.scale, "scale_ni") - recipe.constrain(contribution.si.scale, "1 - scale_ni") + recipe.constrain_parameter(contribution.ni.scale, "scale_ni") + recipe.constrain_parameter(contribution.si.scale, "1 - scale_ni") # We also want the resolution factor to be the same on each. This is done # for free by the PDFContribution. We simply need to add it to the recipe. recipe.add_variable(contribution.qdamp, 0.03) diff --git a/docs/examples/threedoublepeaks.py b/docs/examples/threedoublepeaks.py index 4a3d7eb6..17d23ed1 100644 --- a/docs/examples/threedoublepeaks.py +++ b/docs/examples/threedoublepeaks.py @@ -121,9 +121,9 @@ def peakloc(mu): return 180 / pi * arcsin(pi / 180 * l2 * sin(mu) / l1) recipe.register_function(peakloc) - recipe.constrain(contribution.mu12, "peakloc(mu11)") - recipe.constrain(contribution.mu22, "peakloc(mu21)") - recipe.constrain(contribution.mu32, "peakloc(mu31)") + recipe.constrain_parameter(contribution.mu12, "peakloc(mu11)") + recipe.constrain_parameter(contribution.mu22, "peakloc(mu21)") + recipe.constrain_parameter(contribution.mu32, "peakloc(mu31)") # Vary the width of the peaks. We know the functional form of the peak # broadening. @@ -139,20 +139,20 @@ def sig(sig0, dsig, mu): # Now constrain the peak widths to this recipe.sig0.value = 0.001 recipe.dsig.value = 4.0 - recipe.constrain(contribution.sig11, "sig(sig0, dsig, mu11)") - recipe.constrain( + recipe.constrain_parameter(contribution.sig11, "sig(sig0, dsig, mu11)") + recipe.constrain_parameter( contribution.sig12, "sig(sig0, dsig, mu12)", ns={"mu12": contribution.mu12}, ) - recipe.constrain(contribution.sig21, "sig(sig0, dsig, mu21)") - recipe.constrain( + recipe.constrain_parameter(contribution.sig21, "sig(sig0, dsig, mu21)") + recipe.constrain_parameter( contribution.sig22, "sig(sig0, dsig, mu22)", ns={"mu22": contribution.mu22}, ) - recipe.constrain(contribution.sig31, "sig(sig0, dsig, mu31)") - recipe.constrain( + recipe.constrain_parameter(contribution.sig31, "sig(sig0, dsig, mu31)") + recipe.constrain_parameter( contribution.sig32, "sig(sig0, dsig, mu32)", ns={"mu32": contribution.mu32}, diff --git a/src/diffpy/srfit/fitbase/constraint.py b/src/diffpy/srfit/fitbase/constraint.py index b0a89d19..c24eaf35 100644 --- a/src/diffpy/srfit/fitbase/constraint.py +++ b/src/diffpy/srfit/fitbase/constraint.py @@ -24,6 +24,24 @@ from diffpy.srfit.exceptions import SrFitError from diffpy.srfit.fitbase.validatable import Validatable +from diffpy.utils._deprecator import build_deprecation_message, deprecated + +base = "diffpy.srfit.fitbase.constraint.Constraint" +removal_version = "4.0.0" + +constrain_deprecation_msg = build_deprecation_message( + base, + "constrain", + "constrain_parameter", + removal_version, +) + +unconstrain_deprecation_msg = build_deprecation_message( + base, + "unconstrain", + "unconstrain_parameter", + removal_version, +) class Constraint(Validatable): @@ -47,13 +65,23 @@ def __init__(self): self.eq = None return - def constrain(self, par, eq): + def constrain_parameter(self, par, eq): """Constrain a Parameter according to an Equation. The parameter will be set constant once it is constrained. This will keep it from being constrained multiple times. - Raises a ValueError if par is const. + Parameters + ---------- + par : Parameter + The Parameter to constrain. + eq : Equation + The Equation to use to constrain the Parameter. + + Raises + ------ + ValueError + If par is constant or already constrained. """ if par.const: @@ -69,13 +97,37 @@ def constrain(self, par, eq): self.update() return - def unconstrain(self): - """Clear the constraint.""" + @deprecated(constrain_deprecation_msg) + def constrain(self, par, eq): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use + diffpy.srfit.fitbase.constraint.Constraint.constrain_parameter + instead. + """ + self.constrain_parameter(par, eq) + return + + def unconstrain_parameter(self): + """Clear the constraint from a Parameter.""" self.par.constrained = False self.par = None self.eq = None return + @deprecated(unconstrain_deprecation_msg) + def unconstrain(self): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use + diffpy.srfit.fitbase.constraint.Constraint.unconstrain_parameter + instead. + """ + self.unconstrain_parameter() + return + def update(self): """Update the parameter according to the equation.""" # This will be evaluated quickly thanks to the Equation class. diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 95021384..7cc56b21 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -125,6 +125,14 @@ base, "boundsToRestraints", "convert_bounds_to_restraints", removal_version ) +constrain_dep_msg = build_deprecation_message( + base, "constrain", "constrain_parameter", removal_version +) + +unconstrain_dep_msg = build_deprecation_message( + base, "unconstrain", "unconstrain_parameter", removal_version +) + class FitRecipe(_fitrecipe_interface, RecipeOrganizer): """FitRecipe class. @@ -472,6 +480,11 @@ def removeParameterSet(self, parset): def residual(self, p=[]): """Calculate the vector residual to be optimized. + The residual is by default the weighted concatenation of each + FitContribution's residual, plus the value of each restraint. The array + returned, denoted chiv, is such that + dot(chiv, chiv) = chi^2 + restraints. + Parameters ---------- p : list or numpy.ndarray @@ -481,10 +494,11 @@ def residual(self, p=[]): updated in some other way, and the explicit update within this function is skipped. - The residual is by default the weighted concatenation of each - FitContribution's residual, plus the value of each restraint. The array - returned, denoted chiv, is such that - dot(chiv, chiv) = chi^2 + restraints. + Return + ------ + chiv : numpy.ndarray + The array of residuals to be optimized. The array is such that + dot(chiv, chiv) = chi^2 + restraints. """ # Prepare, if necessary @@ -1093,7 +1107,7 @@ def isFree(self, var): """ return self.is_free(var) - def unconstrain(self, *pars): + def unconstrain_parameter(self, *pars): """Unconstrain a Parameter. This removes any constraints on a Parameter. If the Parameter is also a @@ -1119,7 +1133,7 @@ def unconstrain(self, *pars): raise ValueError("The parameter cannot be found") if par in self._constraints: - self._constraints[par].unconstrain() + self._constraints[par].unconstrain_parameter() del self._constraints[par] update = True @@ -1132,7 +1146,18 @@ def unconstrain(self, *pars): return - def constrain(self, par, con, ns={}): + @deprecated(unconstrain_dep_msg) + def unconstrain(self, *pars): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.unconstrain_parameter + instead. + """ + self.unconstrain_parameter(*pars) + return + + def constrain_parameter(self, par, con, ns={}): """Constrain a parameter to an equation. Note that only one constraint can exist on a Parameter at a time. @@ -1190,7 +1215,18 @@ def constrain(self, par, con, ns={}): if par in self._parameters.values(): self.fix(par) - RecipeOrganizer.constrain(self, par, con, ns) + RecipeOrganizer.constrain_parameter(self, par, con, ns) + return + + @deprecated(constrain_dep_msg) + def constrain(self, par, con, ns={}): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use diffpy.srfit.fitbase.FitRecipe.constrain_parameter + instead. + """ + self.constrain_parameter(par, con, ns) return def get_values(self): diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 495b3706..1b63030d 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -118,6 +118,27 @@ removal_version, ) +addRestraint_deprecation_msg = build_deprecation_message( + recipeorganizer_base, + "addRestraint", + "add_restraint", + removal_version, +) + +constrain_deprecation_msg = build_deprecation_message( + recipeorganizer_base, + "constrain", + "constrain_parameter", + removal_version, +) + +unconstrain_deprecation_msg = build_deprecation_message( + recipeorganizer_base, + "unconstrain", + "unconstrain_parameter", + removal_version, +) + class RecipeContainer(Observable, Configurable, Validatable): """Base class for organizing pieces of a FitRecipe. @@ -883,7 +904,7 @@ def evaluateEquation(self, eqstr, ns={}): """ return self.evaluate_equation(eqstr, func_params=ns) - def constrain(self, parameter, constraint_eq, params={}): + def constrain_parameter(self, parameter, constraint_eq, params={}): """Constrain a parameter to an equation. Note that only one constraint can exist on a Parameter at a time. @@ -936,7 +957,7 @@ def constrain(self, parameter, constraint_eq, params={}): # Make and store the constraint constraint_eq = Constraint() - constraint_eq.constrain(parameter, eq) + constraint_eq.constrain_parameter(parameter, eq) # Store the equation string so it can be shown later. constraint_eq.eqstr = eqstr self._constraints[parameter] = constraint_eq @@ -946,6 +967,18 @@ def constrain(self, parameter, constraint_eq, params={}): return + @deprecated(constrain_deprecation_msg) + def constrain(self, parameter, constraint_eq, params={}): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.constrain_parameter + instead. + """ + self.constrain_parameter(parameter, constraint_eq, params=params) + return + def is_constrained(self, parameter): """Determine if a Parameter is constrained in this object. @@ -977,14 +1010,14 @@ def isConstrained(self, parameter): """ return self.is_constrained(parameter) - def unconstrain(self, *pars): + def unconstrain_parameter(self, *pars): """Unconstrain a Parameter. This removes any constraints on a Parameter. Attributes ---------- - *pars + *pars : str or Parameter The names of Parameters or Parameters to unconstrain. @@ -1000,7 +1033,7 @@ def unconstrain(self, *pars): raise ValueError("The parameter cannot be found") if parameter in self._constraints: - self._constraints[parameter].unconstrain() + self._constraints[parameter].unconstrain_parameter() del self._constraints[parameter] update = True @@ -1014,6 +1047,18 @@ def unconstrain(self, *pars): return + @deprecated(unconstrain_deprecation_msg) + def unconstrain(self, *pars): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.unconstrain_parameter + instead. + """ + self.unconstrain_parameter(*pars) + return + def get_constrained_parmeters(self, recurse=False): """Get a list of constrained managed Parameters in this object. @@ -1059,7 +1104,7 @@ def clear_all_constraints(self, recurse=False): sub-objects are also cleared. """ if self._constraints: - self.unconstrain(*self._constraints) + self.unconstrain_parameter(*self._constraints) if recurse: for m in filter(_has_clear_constraints, self._iter_managed()): @@ -1136,15 +1181,15 @@ def restrain( # Make and store the restraint param_or_eq = Restraint(eq, lb, ub, sig, scaled) param_or_eq.eqstr = eqstr - self.addRestraint(param_or_eq) + self.add_restraint(param_or_eq) return param_or_eq - def addRestraint(self, res): + def add_restraint(self, res): """Add a Restraint instance to the RecipeOrganizer. - Attributes + Parameters ---------- - res + res : Restraint A Restraint instance. """ self._restraints.add(res) @@ -1152,6 +1197,18 @@ def addRestraint(self, res): self._update_configuration() return + @deprecated(addRestraint_deprecation_msg) + def addRestraint(self, res): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.add_restraint + instead. + """ + self.add_restraint(res) + return + def unrestrain(self, *ress): """Remove a Restraint from the RecipeOrganizer. @@ -1159,7 +1216,7 @@ def unrestrain(self, *ress): ---------- *ress Restraints returned from the 'restrain' method or added - with the 'addRestraint' method. + with the 'add_restraint' method. """ update = False restuple = tuple(self._restraints) diff --git a/src/diffpy/srfit/pdf/pdfcontribution.py b/src/diffpy/srfit/pdf/pdfcontribution.py index 9b2bdd93..8ef1578b 100644 --- a/src/diffpy/srfit/pdf/pdfcontribution.py +++ b/src/diffpy/srfit/pdf/pdfcontribution.py @@ -287,8 +287,8 @@ def _setup_generator(self, gen): gen.processMetaData() # Constrain the shared parameters - self.constrain(gen.qdamp, self.qdamp) - self.constrain(gen.qbroad, self.qbroad) + self.constrain_parameter(gen.qdamp, self.qdamp) + self.constrain_parameter(gen.qbroad, self.qbroad) return # Calculation setup methods diff --git a/src/diffpy/srfit/structure/sgconstraints.py b/src/diffpy/srfit/structure/sgconstraints.py index 8e1e198d..681bad1b 100644 --- a/src/diffpy/srfit/structure/sgconstraints.py +++ b/src/diffpy/srfit/structure/sgconstraints.py @@ -391,7 +391,7 @@ def _clear_constraints(self): for par in [scatterer.x, scatterer.y, scatterer.z]: if scatterer.is_constrained(par): - scatterer.unconstrain(par) + scatterer.unconstrain_parameter(par) par.setConst(False) # Clear the lattice @@ -408,7 +408,7 @@ def _clear_constraints(self): ] for par in latpars: if lattice.is_constrained(par): - lattice.unconstrain(par) + lattice.unconstrain_parameter(par) par.setConst(False) # Clear ADPs @@ -418,14 +418,14 @@ def _clear_constraints(self): par = scatterer.get(isosymbol) if par is not None: if scatterer.is_constrained(par): - scatterer.unconstrain(par) + scatterer.unconstrain_parameter(par) par.setConst(False) for pname in adpsymbols: par = scatterer.get(pname) if par is not None: if scatterer.is_constrained(par): - scatterer.unconstrain(par) + scatterer.unconstrain_parameter(par) par.setConst(False) return @@ -596,7 +596,7 @@ def _constrain_adps(self, positions): continue isoidx.append(j) scatterer = scatterers[j] - scatterer.constrain( + scatterer.constrain_parameter( isosymbol, isoname, params=self._parameters ) @@ -691,7 +691,7 @@ def _constrain_tetragonal(lattice): lattice.alpha.setConst(True, ang90) lattice.beta.setConst(True, ang90) lattice.gamma.setConst(True, ang90) - lattice.constrain(lattice.b, lattice.a) + lattice.constrain_parameter(lattice.b, lattice.a) return @@ -708,15 +708,15 @@ def _constrain_trigonal(lattice): ang90 = 90.0 * afactor ang120 = 120.0 * afactor if lattice.gamma.getValue() == ang120: - lattice.constrain(lattice.b, lattice.a) + lattice.constrain_parameter(lattice.b, lattice.a) lattice.alpha.setConst(True, ang90) lattice.beta.setConst(True, ang90) lattice.gamma.setConst(True, ang120) else: - lattice.constrain(lattice.b, lattice.a) - lattice.constrain(lattice.c, lattice.a) - lattice.constrain(lattice.beta, lattice.alpha) - lattice.constrain(lattice.gamma, lattice.alpha) + lattice.constrain_parameter(lattice.b, lattice.a) + lattice.constrain_parameter(lattice.c, lattice.a) + lattice.constrain_parameter(lattice.beta, lattice.alpha) + lattice.constrain_parameter(lattice.gamma, lattice.alpha) return @@ -731,7 +731,7 @@ def _constrain_hexagonal(lattice): afactor = deg2rad ang90 = 90.0 * afactor ang120 = 120.0 * afactor - lattice.constrain(lattice.b, lattice.a) + lattice.constrain_parameter(lattice.b, lattice.a) lattice.alpha.setConst(True, ang90) lattice.beta.setConst(True, ang90) lattice.gamma.setConst(True, ang120) @@ -748,8 +748,8 @@ def _constrain_cubic(lattice): if lattice.angunits == "rad": afactor = deg2rad ang90 = 90.0 * afactor - lattice.constrain(lattice.b, lattice.a) - lattice.constrain(lattice.c, lattice.a) + lattice.constrain_parameter(lattice.b, lattice.a) + lattice.constrain_parameter(lattice.c, lattice.a) lattice.alpha.setConst(True, ang90) lattice.beta.setConst(True, ang90) lattice.gamma.setConst(True, ang90) @@ -811,7 +811,7 @@ 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, params=ns) + scatterer.constrain_parameter(par, formula, params=ns) return diff --git a/tests/conftest.py b/tests/conftest.py index f6e58e7e..e053c732 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -215,9 +215,9 @@ def build_recipe_two_contributions(): recipe.add_variable(contribution2.d, 0.1) # ---- Meaningful constraints ---- - recipe.constrain(contribution2.m, "2*k") - recipe.constrain(contribution2.d, contribution1.c) - recipe.constrain(contribution2.B, "0.5*A") + recipe.constrain_parameter(contribution2.m, "2*k") + recipe.constrain_parameter(contribution2.d, contribution1.c) + recipe.constrain_parameter(contribution2.B, "0.5*A") recipe.restrain(contribution1.A, 0.5, 1.5) recipe.restrain(contribution1.k, 0.8, 1.2) diff --git a/tests/test_constraint.py b/tests/test_constraint.py index 00da5b14..a72a69fa 100644 --- a/tests/test_constraint.py +++ b/tests/test_constraint.py @@ -24,6 +24,45 @@ class TestConstraint(unittest.TestCase): + def test_constrain_parameter(self): + """Test the Constraint class.""" + + p1 = Parameter("p1", 1) + p2 = Parameter("p2", 2) + + factory = EquationFactory() + + factory.registerArgument("p1", p1) + factory.registerArgument("p2", p2) + + c = Constraint() + # Constrain p1 = 2*p2 + eq = equationFromString("2*p2", factory) + c.constrain_parameter(p1, eq) + + self.assertTrue(p1.constrained) + self.assertFalse(p2.constrained) + + eq2 = equationFromString("2*p2+1", factory) + c2 = Constraint() + self.assertRaises(ValueError, c2.constrain, p1, eq2) + p2.setConst() + eq3 = equationFromString("p1", factory) + self.assertRaises(ValueError, c2.constrain, p2, eq3) + + p2.set_value(2.5) + c.update() + self.assertEqual(5.0, p1.getValue()) + + p2.set_value(8.1) + self.assertEqual(5.0, p1.getValue()) + c.update() + self.assertEqual(16.2, p1.getValue()) + return + + +class TestConstraint_deprecated(unittest.TestCase): + def testConstraint(self): """Test the Constraint class.""" diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 4c928431..b64b3f99 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -119,7 +119,7 @@ def test_variables(self): # Constrain a parameter to the B-variable to give it a value p = Parameter("Bpar", -1) - recipe.constrain(recipe.B, p) + recipe.constrain_parameter(recipe.B, p) values = recipe.get_values() self.assertTrue((values == [2, 1, 0]).all()) recipe.delete_variable(recipe.B) @@ -215,11 +215,11 @@ def testResidual(self): # Try some constraints # Make c = 2*A, A = Avar var = self.recipe.create_new_variable("Avar") - self.recipe.constrain( + self.recipe.constrain_parameter( self.fitcontribution.c, "2*A", {"A": self.fitcontribution.A} ) self.assertEqual(2, self.fitcontribution.c.value) - self.recipe.constrain(self.fitcontribution.A, var) + self.recipe.constrain_parameter(self.fitcontribution.A, var) self.assertEqual(1, var.getValue()) self.assertEqual(self.recipe.cont.A.getValue(), var.getValue()) # c is constrained to a constrained parameter. @@ -240,7 +240,7 @@ def testResidual(self): # Clear the constraint and restore the value of c to 0. This should # give us chi2 = 0 again. - self.recipe.unconstrain(self.fitcontribution.c) + self.recipe.unconstrain_parameter(self.fitcontribution.c) self.fitcontribution.c.set_value(0) res = self.recipe.residual([self.recipe.cont.A.getValue()]) chi2 = 0 @@ -255,7 +255,7 @@ def testResidual(self): self.assertAlmostEqual(chi2, dot(res, res)) # Add constraints at the fitcontribution level. - self.fitcontribution.constrain(self.fitcontribution.c, "2*A") + self.fitcontribution.constrain_parameter(self.fitcontribution.c, "2*A") # This should evaluate to sin(x+2) x = self.profile.x y = sin(x + 2) diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index bdd38058..c6bc19a7 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -259,7 +259,7 @@ def testRemoveParameter(self): self.assertRaises(ValueError, m._remove_parameter, c) return - def test_constrain(self): + def test_constrain_parameter(self): """Test the constrain method.""" p1 = self.m._new_parameter("p1", 1) @@ -268,7 +268,7 @@ def test_constrain(self): self.assertFalse(p1.constrained) self.assertEqual(0, len(self.m._constraints)) - self.m.constrain(p1, "2*p2") + self.m.constrain_parameter(p1, "2*p2") actual_constrained_params = self.m.getConstrainedPars() actual_constrained_params = [p.name for p in actual_constrained_params] @@ -296,13 +296,13 @@ def test_constrain(self): self.assertRaises(ValueError, self.m.constrain, p1, "2*p2", {"p2": p3}) # Remove the constraint - self.m.unconstrain(p1) + self.m.unconstrain_parameter(p1) self.assertFalse(p1.constrained) self.assertEqual(0, len(self.m._constraints)) self.assertFalse(self.m.isConstrained(p1)) # Try an straight constraint - self.m.constrain(p1, p2) + self.m.constrain_parameter(p1, p2) p2.set_value(7) self.m._constraints[p1].update() self.assertEqual(7, p1.getValue()) @@ -314,7 +314,7 @@ def test_constrain(self): assert actual_constrained_params == expected_constrained_params # add constraint back and test the old function name `clearConstraints` - self.m.constrain(p1, p2) + self.m.constrain_parameter(p1, p2) actual_constrained_params = self.m.get_constrained_parmeters() actual_constrained_params = [p.name for p in actual_constrained_params] expected_constrained_params = [p1.name] @@ -375,8 +375,8 @@ def testGetConstraints(self): m2._add_parameter(p3) m2._add_parameter(p4) - self.m.constrain(p1, "p2") - m2.constrain(p3, "p4") + self.m.constrain_parameter(p1, "p2") + m2.constrain_parameter(p3, "p4") cons = self.m._get_constraints() self.assertTrue(p1 in cons) @@ -625,7 +625,7 @@ def capture_show(*args, **kwargs): assert "Constraints" not in lines1 assert "Restraints" not in lines1 organizer._new_parameter("z", 7) - organizer.constrain("y", "3 * z") + organizer.constrain_parameter("y", "3 * z") out2 = capture_show() lines2 = out2.strip().split("\n") assert 9 == len(lines2) diff --git a/tests/test_sgconstraints.py b/tests/test_sgconstraints.py index 11859a9f..19bb49f2 100644 --- a/tests/test_sgconstraints.py +++ b/tests/test_sgconstraints.py @@ -87,13 +87,13 @@ def test_ObjCryst_constrain_space_group(pyobjcryst_available): # Make sure we can't constrain these with pytest.raises(ValueError): - mn.constrain(mn.x, "y") + mn.constrain_parameter(mn.x, "y") with pytest.raises(ValueError): - mn.constrain(mn.y, "z") + mn.constrain_parameter(mn.y, "z") with pytest.raises(ValueError): - mn.constrain(mn.z, "x") + mn.constrain_parameter(mn.z, "x") # Nor can we make them into variables from diffpy.srfit.fitbase.fitrecipe import FitRecipe From 9993779e94e1701e7653f647ebb8eb61b8512220 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 9 Mar 2026 14:32:29 -0400 Subject: [PATCH 145/193] change name to register_restraint --- src/diffpy/srfit/fitbase/recipeorganizer.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 1b63030d..d1f6a9ba 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -121,7 +121,7 @@ addRestraint_deprecation_msg = build_deprecation_message( recipeorganizer_base, "addRestraint", - "add_restraint", + "register_restraint", removal_version, ) @@ -1181,10 +1181,10 @@ def restrain( # Make and store the restraint param_or_eq = Restraint(eq, lb, ub, sig, scaled) param_or_eq.eqstr = eqstr - self.add_restraint(param_or_eq) + self.register_restraint(param_or_eq) return param_or_eq - def add_restraint(self, res): + def register_restraint(self, res): """Add a Restraint instance to the RecipeOrganizer. Parameters @@ -1203,10 +1203,10 @@ def addRestraint(self, res): version 4.0.0. Please use - diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.add_restraint + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.register_restraint instead. """ - self.add_restraint(res) + self.register_restraint(res) return def unrestrain(self, *ress): @@ -1216,7 +1216,7 @@ def unrestrain(self, *ress): ---------- *ress Restraints returned from the 'restrain' method or added - with the 'add_restraint' method. + with the 'register_restraint' method. """ update = False restuple = tuple(self._restraints) From 1f301a37ef2cadbaec68b9d0bc3442002aec0015 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 9 Mar 2026 14:44:23 -0400 Subject: [PATCH 146/193] restrain deprecation --- docs/examples/crystalpdftwophase.py | 12 +++++------ docs/examples/debyemodel.py | 2 +- docs/examples/simplepdftwophase.py | 12 +++++------ src/diffpy/srfit/fitbase/fitrecipe.py | 2 +- src/diffpy/srfit/fitbase/recipeorganizer.py | 24 ++++++++++++++++++++- tests/conftest.py | 4 ++-- tests/test_fitrecipe.py | 10 +++++---- tests/test_recipeorganizer.py | 10 ++++----- 8 files changed, 50 insertions(+), 26 deletions(-) diff --git a/docs/examples/crystalpdftwophase.py b/docs/examples/crystalpdftwophase.py index 37feaad5..3f0a0194 100644 --- a/docs/examples/crystalpdftwophase.py +++ b/docs/examples/crystalpdftwophase.py @@ -123,18 +123,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.add_restraint("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.add_restraint("delta2_ni", lb=2.22, ub=2.22, scaled=True) + recipe.add_restraint("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.add_restraint("a_si", lb=5.430, ub=5.430, scaled=True) + recipe.add_restraint("delta2_si", lb=3.54, ub=3.54, scaled=True) + recipe.add_restraint("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/docs/examples/debyemodel.py b/docs/examples/debyemodel.py index cd2dcbbd..c49c13b0 100644 --- a/docs/examples/debyemodel.py +++ b/docs/examples/debyemodel.py @@ -152,7 +152,7 @@ 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.add_restraint(recipe.offset, lb=0, scaled=True) # We're done setting up the recipe. We can now do other things with it. return recipe diff --git a/docs/examples/simplepdftwophase.py b/docs/examples/simplepdftwophase.py index 209abcf0..e0735514 100644 --- a/docs/examples/simplepdftwophase.py +++ b/docs/examples/simplepdftwophase.py @@ -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.add_restraint("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.add_restraint("delta2_ni", lb=2.22, ub=2.22, scaled=True) + recipe.add_restraint("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.add_restraint("a_si", lb=5.430, ub=5.430, scaled=True) + recipe.add_restraint("delta2_si", lb=3.54, ub=3.54, scaled=True) + recipe.add_restraint("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/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 7cc56b21..1dc61fbc 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -1756,7 +1756,7 @@ def convert_bounds_to_restraints(self, sig=1, scaled=False): if not hasattr(sig, "__iter__"): sig = [sig] * len(pars) for par, x in zip(pars, sig): - self.restrain( + self.add_restraint( par, par.bounds[0], par.bounds[1], sig=x, scaled=scaled ) return diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index d1f6a9ba..f35037bf 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -139,6 +139,13 @@ removal_version, ) +restrain_deprecation_msg = build_deprecation_message( + recipeorganizer_base, + "restrain", + "add_restraint", + removal_version, +) + class RecipeContainer(Observable, Configurable, Validatable): """Base class for organizing pieces of a FitRecipe. @@ -1122,7 +1129,7 @@ def clearConstraints(self, recurse=False): """ return self.clear_all_constraints(recurse=recurse) - def restrain( + def add_restraint( self, param_or_eq, lb=-inf, ub=inf, sig=1, scaled=False, params={} ): """Restrain an expression to specified bounds. @@ -1184,6 +1191,21 @@ def restrain( self.register_restraint(param_or_eq) return param_or_eq + @deprecated(restrain_deprecation_msg) + def restrain( + self, param_or_eq, lb=-inf, ub=inf, sig=1, scaled=False, params={} + ): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.add_restraint + instead. + """ + return self.add_restraint( + param_or_eq, lb=lb, ub=ub, sig=sig, scaled=scaled, params=params + ) + def register_restraint(self, res): """Add a Restraint instance to the RecipeOrganizer. diff --git a/tests/conftest.py b/tests/conftest.py index e053c732..118f30d4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -218,8 +218,8 @@ def build_recipe_two_contributions(): recipe.constrain_parameter(contribution2.m, "2*k") recipe.constrain_parameter(contribution2.d, contribution1.c) recipe.constrain_parameter(contribution2.B, "0.5*A") - recipe.restrain(contribution1.A, 0.5, 1.5) - recipe.restrain(contribution1.k, 0.8, 1.2) + recipe.add_restraint(contribution1.A, 0.5, 1.5) + recipe.add_restraint(contribution1.k, 0.8, 1.2) return recipe diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index b64b3f99..2fb6f8c2 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -232,7 +232,7 @@ def testResidual(self): # 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 - r1 = self.recipe.restrain(self.fitcontribution.c, 0, 0, 1) + r1 = self.recipe.add_restraint(self.fitcontribution.c, 0, 0, 1) self.recipe._ready = False res = self.recipe.residual() chi2 = 4 + dot(y - self.profile.y, y - self.profile.y) @@ -263,7 +263,9 @@ def testResidual(self): 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) + r1 = self.fitcontribution.add_restraint( + self.fitcontribution.c, 0, 0, 1 + ) self.recipe._ready = False # The chi2 is the same as above, plus 4 res = self.recipe.residual() @@ -361,7 +363,7 @@ def testPrintFitHook(capturestdout): recipe.addContribution(fitcontribution) recipe.add_variable(fitcontribution.c) - recipe.restrain("c", lb=5) + recipe.add_restraint("c", lb=5) (pfh,) = recipe.getFitHooks() out = capturestdout(recipe.scalar_residual) assert "" == out @@ -437,7 +439,7 @@ def test_add_contribution(capturestdout): recipe.add_contribution(fitcontribution) recipe.add_variable(fitcontribution.c) - recipe.restrain("c", lb=5) + recipe.add_restraint("c", lb=5) (pfh,) = recipe.get_fit_hooks() out = capturestdout(recipe.scalar_residual) assert "" == out diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index c6bc19a7..cb93d929 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -328,7 +328,7 @@ def test_constrain_parameter(self): return - def testRestrain(self): + def test_add_restraint(self): """Test the restrain method.""" p1 = Parameter("p1", 1) @@ -338,7 +338,7 @@ 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.add_restraint("p1+p2", ub=10) self.assertEqual(1, len(self.m._restraints)) p2.set_value(10) self.assertEqual(1, r.penalty()) @@ -402,8 +402,8 @@ def testGetRestraints(self): m2._add_parameter(p3) m2._add_parameter(p4) - r1 = self.m.restrain("p1 + p2") - r2 = m2.restrain("2*p3 + p4") + r1 = self.m.add_restraint("p1 + p2") + r2 = m2.add_restraint("2*p3 + p4") res = self.m._get_restraints() self.assertTrue(r1 in res) @@ -632,7 +632,7 @@ def capture_show(*args, **kwargs): assert "Parameters" in lines2 assert "Constraints" in lines2 assert "Restraints" not in lines2 - organizer.restrain("z", lb=2, ub=3, sig=0.001) + organizer.add_restraint("z", lb=2, ub=3, sig=0.001) out3 = capture_show() lines3 = out3.strip().split("\n") assert 13 == len(lines3) From 8184be43f1e8ad70846ec62151a9b9def6e29f9b Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 9 Mar 2026 14:49:05 -0400 Subject: [PATCH 147/193] unrestrain deprecation --- src/diffpy/srfit/fitbase/recipeorganizer.py | 27 ++++++++++++++++++--- tests/test_fitrecipe.py | 4 +-- tests/test_recipeorganizer.py | 2 +- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index f35037bf..f9415df0 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -146,6 +146,13 @@ removal_version, ) +unrestrain_deprecation_msg = build_deprecation_message( + recipeorganizer_base, + "unrestrain", + "remove_restraint", + removal_version, +) + class RecipeContainer(Observable, Configurable, Validatable): """Base class for organizing pieces of a FitRecipe. @@ -1231,13 +1238,13 @@ def addRestraint(self, res): self.register_restraint(res) return - def unrestrain(self, *ress): + def remove_restraint(self, *ress): """Remove a Restraint from the RecipeOrganizer. Attributes ---------- - *ress - Restraints returned from the 'restrain' method or added + *ress : + The Restraints returned from the 'add_restraint' method or added with the 'register_restraint' method. """ update = False @@ -1253,6 +1260,18 @@ def unrestrain(self, *ress): return + @deprecated(unrestrain_deprecation_msg) + def unrestrain(self, *ress): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.remove_restraint + instead. + """ + self.remove_restraint(*ress) + return + def clearRestraints(self, recurse=False): """Clear all restraints. @@ -1262,7 +1281,7 @@ def clearRestraints(self, recurse=False): Recurse into managed objects and clear all restraints found there as well. """ - self.unrestrain(*self._restraints) + self.remove_restraint(*self._restraints) if recurse: for msg in filter(_has_clear_restraints, self._iter_managed()): msg.clearRestraints(recurse) diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 2fb6f8c2..3e165268 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -247,7 +247,7 @@ def testResidual(self): self.assertAlmostEqual(chi2, dot(res, res)) # Remove the restraint and variable - self.recipe.unrestrain(r1) + self.recipe.remove_restraint(r1) self.recipe.delete_variable(self.recipe.Avar) self.recipe._ready = False res = self.recipe.residual() @@ -275,7 +275,7 @@ def testResidual(self): self.assertAlmostEqual(chi2, dot(res, res)) # Remove those - self.fitcontribution.unrestrain(r1) + self.fitcontribution.remove_restraint(r1) self.recipe._ready = False self.fitcontribution.unconstrain(self.fitcontribution.c) self.fitcontribution.c.set_value(0) diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index cb93d929..922cb33f 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -342,7 +342,7 @@ def test_add_restraint(self): self.assertEqual(1, len(self.m._restraints)) p2.set_value(10) self.assertEqual(1, r.penalty()) - self.m.unrestrain(r) + self.m.remove_restraint(r) self.assertEqual(0, len(self.m._restraints)) r = self.m.restrain(p1, ub=10) From 5d958fba4d45465fa96f9d983e79f745130a4748 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 9 Mar 2026 14:55:32 -0400 Subject: [PATCH 148/193] clearRestraints deprecation --- src/diffpy/srfit/fitbase/recipeorganizer.py | 27 ++++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index f9415df0..0522a80f 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -153,6 +153,13 @@ removal_version, ) +clearRestraints_deprecation_msg = build_deprecation_message( + recipeorganizer_base, + "clearRestraints", + "clear_all_restraints", + removal_version, +) + class RecipeContainer(Observable, Configurable, Validatable): """Base class for organizing pieces of a FitRecipe. @@ -1243,7 +1250,7 @@ def remove_restraint(self, *ress): Attributes ---------- - *ress : + *ress : Restraint The Restraints returned from the 'add_restraint' method or added with the 'register_restraint' method. """ @@ -1272,7 +1279,7 @@ def unrestrain(self, *ress): self.remove_restraint(*ress) return - def clearRestraints(self, recurse=False): + def clear_all_restraints(self, recurse=False): """Clear all restraints. Attributes @@ -1284,7 +1291,19 @@ def clearRestraints(self, recurse=False): self.remove_restraint(*self._restraints) if recurse: for msg in filter(_has_clear_restraints, self._iter_managed()): - msg.clearRestraints(recurse) + msg.clear_all_restraints(recurse) + return + + @deprecated(clearRestraints_deprecation_msg) + def clearRestraints(self, recurse=False): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.clear_all_restraints + instead. + """ + self.clear_all_restraints(recurse=recurse) return def _get_constraints(self, recurse=True): @@ -1528,7 +1547,7 @@ def _has_clear_constraints(msg): def _has_clear_restraints(msg): - return hasattr(msg, "clearRestraints") + return hasattr(msg, "clear_all_restraints") def _has_get_restraints(msg): From 7a2e29dc4120d57255509a823cf286c8f8195fda Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 9 Mar 2026 15:09:52 -0400 Subject: [PATCH 149/193] equationFromString deprecation --- src/diffpy/srfit/fitbase/fitcontribution.py | 8 ++- src/diffpy/srfit/fitbase/recipeorganizer.py | 73 ++++++++++++++++----- tests/test_constraint.py | 14 ++-- tests/test_recipeorganizer.py | 19 ++++-- tests/test_restraint.py | 4 +- 5 files changed, 83 insertions(+), 35 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitcontribution.py b/src/diffpy/srfit/fitbase/fitcontribution.py index d5af4709..feda75ba 100644 --- a/src/diffpy/srfit/fitbase/fitcontribution.py +++ b/src/diffpy/srfit/fitbase/fitcontribution.py @@ -28,7 +28,7 @@ from diffpy.srfit.fitbase.parameter import ParameterProxy from diffpy.srfit.fitbase.parameterset import ParameterSet from diffpy.srfit.fitbase.profile import Profile -from diffpy.srfit.fitbase.recipeorganizer import equationFromString +from diffpy.srfit.fitbase.recipeorganizer import get_equation_from_string from diffpy.utils._deprecator import build_deprecation_message, deprecated base = "diffpy.srfit.fitbase.FitContribution" @@ -296,7 +296,9 @@ def set_equation(self, eqstr, ns={}): variable. """ # Build the equation instance. - eq = equationFromString(eqstr, self._eqfactory, buildargs=True, ns=ns) + eq = get_equation_from_string( + eqstr, self._eqfactory, buildargs=True, ns=ns + ) eq.name = "eq" # Register any new Parameters. @@ -386,7 +388,7 @@ def set_residual_equation(self, eqstr): elif eqstr == "resv": eqstr = resvstr - reseq = equationFromString(eqstr, self._eqfactory) + reseq = get_equation_from_string(eqstr, self._eqfactory) self._eqfactory.wipeout(self._reseq) self._reseq = reseq diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 0522a80f..256faa9d 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -17,10 +17,10 @@ RecipeContainer is the base class for organizing Parameters, and other RecipeContainers. RecipeOrganizer is an extended RecipeContainer that incorporates equation building, constraints and Restraints. -equationFromString creates an Equation instance from a string. +get_equation_from_string creates an Equation instance from a string. """ -__all__ = ["RecipeContainer", "RecipeOrganizer", "equationFromString"] +__all__ = ["RecipeContainer", "RecipeOrganizer", "get_equation_from_string"] import re from collections import OrderedDict @@ -160,6 +160,13 @@ removal_version, ) +equationFromString_deprecation_msg = build_deprecation_message( + recipeorganizer_base, + "equationFromString", + "get_equation_from_string", + removal_version, +) + class RecipeContainer(Observable, Configurable, Validatable): """Base class for organizing pieces of a FitRecipe. @@ -851,7 +858,7 @@ def register_string_function(self, function_str, name, func_params={}): """ # Build the equation instance. - eq = equationFromString( + eq = get_equation_from_string( function_str, self._eqfactory, ns=func_params, buildargs=True ) eq.name = name @@ -907,7 +914,9 @@ def evaluate_equation(self, equation_str, func_params={}): If `func_params` uses a name that is already used for a variable. """ - eq = equationFromString(equation_str, self._eqfactory, func_params) + eq = get_equation_from_string( + equation_str, self._eqfactory, func_params + ) try: returned_value = eq() finally: @@ -969,7 +978,9 @@ def constrain_parameter(self, parameter, constraint_eq, params={}): if isinstance(constraint_eq, str): eqstr = constraint_eq - eq = equationFromString(constraint_eq, self._eqfactory, params) + eq = get_equation_from_string( + constraint_eq, self._eqfactory, params + ) else: eq = Equation(root=constraint_eq) eqstr = constraint_eq.name @@ -1194,7 +1205,7 @@ def add_restraint( """ if isinstance(param_or_eq, str): eqstr = param_or_eq - eq = equationFromString(param_or_eq, self._eqfactory, params) + eq = get_equation_from_string(param_or_eq, self._eqfactory, params) else: eq = Equation(root=param_or_eq) eqstr = param_or_eq.name @@ -1489,38 +1500,45 @@ def show(self, pattern="", textwidth=78): # End RecipeOrganizer -def equationFromString( +def get_equation_from_string( eqstr, factory, ns={}, buildargs=False, argclass=Parameter, argkw={} ): - """Make an equation from a string. + """Make an Equation object from a string. Attributes ---------- - eqstr + eqstr : str A string representation of the equation. The equation must consist of numpy operators and "known" Parameters. Parameters are known if they are in ns, or already defined in the factory. - factory + factory : EquationFactory An EquationFactory instance. - ns - A dictionary of Parameters indexed by name that are used + ns : dict, optional + The dictionary of Parameters indexed by name that are used in the eqstr but not already defined in the factory (default {}). - buildargs + buildargs : bool, optional A flag indicating whether missing Parameters can be created by the Factory (default False). If False, then the a ValueError will be raised if there are undefined arguments in the eqstr. - argclass + argclass : Parameter class, optional Class to use when creating new Arguments (default Parameter). The class constructor must accept the 'name' key word. - argkw + argkw : dict, optional Key word dictionary to pass to the argclass constructor (default {}). + Returns + ------- + eq : Equation + An Equation instance representing the equation in eqstr. - Raises ValueError if ns uses a name that is already defined in the factory. - Raises ValueError if the equation has undefined parameters. + Raises + ------ + ValueError + If buildargs is False and there are undefined parameters in eqstr + or if ns uses a name that is already defined in the factory. """ defined = set(factory.builders.keys()) @@ -1542,6 +1560,27 @@ def equationFromString( return eq +@deprecated(equationFromString_deprecation_msg) +def equationFromString( + eqstr, factory, ns={}, buildargs=False, argclass=Parameter, argkw={} +): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use + diffpy.srfit.fitbase.recipeorganizer.get_equation_from_string + instead. + """ + return get_equation_from_string( + eqstr, + factory, + ns=ns, + buildargs=buildargs, + argclass=argclass, + argkw=argkw, + ) + + def _has_clear_constraints(msg): return hasattr(msg, "clear_all_constraints") diff --git a/tests/test_constraint.py b/tests/test_constraint.py index a72a69fa..014e8939 100644 --- a/tests/test_constraint.py +++ b/tests/test_constraint.py @@ -19,7 +19,7 @@ from diffpy.srfit.equation.builder import EquationFactory from diffpy.srfit.fitbase.constraint import Constraint from diffpy.srfit.fitbase.parameter import Parameter -from diffpy.srfit.fitbase.recipeorganizer import equationFromString +from diffpy.srfit.fitbase.recipeorganizer import get_equation_from_string class TestConstraint(unittest.TestCase): @@ -37,17 +37,17 @@ def test_constrain_parameter(self): c = Constraint() # Constrain p1 = 2*p2 - eq = equationFromString("2*p2", factory) + eq = get_equation_from_string("2*p2", factory) c.constrain_parameter(p1, eq) self.assertTrue(p1.constrained) self.assertFalse(p2.constrained) - eq2 = equationFromString("2*p2+1", factory) + eq2 = get_equation_from_string("2*p2+1", factory) c2 = Constraint() self.assertRaises(ValueError, c2.constrain, p1, eq2) p2.setConst() - eq3 = equationFromString("p1", factory) + eq3 = get_equation_from_string("p1", factory) self.assertRaises(ValueError, c2.constrain, p2, eq3) p2.set_value(2.5) @@ -76,17 +76,17 @@ def testConstraint(self): c = Constraint() # Constrain p1 = 2*p2 - eq = equationFromString("2*p2", factory) + eq = get_equation_from_string("2*p2", factory) c.constrain(p1, eq) self.assertTrue(p1.constrained) self.assertFalse(p2.constrained) - eq2 = equationFromString("2*p2+1", factory) + eq2 = get_equation_from_string("2*p2+1", factory) c2 = Constraint() self.assertRaises(ValueError, c2.constrain, p1, eq2) p2.setConst() - eq3 = equationFromString("p1", factory) + eq3 = get_equation_from_string("p1", factory) self.assertRaises(ValueError, c2.constrain, p2, eq3) p2.set_value(2.5) diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index 922cb33f..0302ca6e 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -25,6 +25,7 @@ RecipeContainer, RecipeOrganizer, equationFromString, + get_equation_from_string, ) # ---------------------------------------------------------------------------- @@ -32,8 +33,8 @@ class TestEquationFromString(unittest.TestCase): - def testEquationFromString(self): - """Test the equationFromString method.""" + def test_get_equation_from_string(self): + """Test the get_equation_from_string method.""" p1 = Parameter("p1", 1) p2 = Parameter("p2", 2) @@ -46,7 +47,7 @@ def testEquationFromString(self): factory.registerArgument("p2", p2) # Check usage where all parameters are registered with the factory - eq = equationFromString("p1+p2", factory) + eq = get_equation_from_string("p1+p2", factory) self.assertEqual(2, len(eq.args)) self.assertTrue(p1 in eq.args) @@ -54,7 +55,9 @@ def testEquationFromString(self): self.assertEqual(3, eq()) # Try to use a parameter that is not registered - self.assertRaises(ValueError, equationFromString, "p1+p2+p3", factory) + self.assertRaises( + ValueError, get_equation_from_string, "p1+p2+p3", factory + ) # Pass that argument in the ns dictionary eq = equationFromString("p1+p2+p3", factory, {"p3": p3}) @@ -69,12 +72,16 @@ def testEquationFromString(self): # Pass and use an unregistered parameter self.assertRaises( - ValueError, equationFromString, "p1+p2+p3+p4", factory, {"p3": p3} + ValueError, + get_equation_from_string, + "p1+p2+p3+p4", + factory, + {"p3": p3}, ) # Try to overload a registered parameter self.assertRaises( - ValueError, equationFromString, "p1+p2", factory, {"p2": p4} + ValueError, get_equation_from_string, "p1+p2", factory, {"p2": p4} ) return diff --git a/tests/test_restraint.py b/tests/test_restraint.py index c5ef55c7..09819531 100644 --- a/tests/test_restraint.py +++ b/tests/test_restraint.py @@ -18,7 +18,7 @@ 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.recipeorganizer import get_equation_from_string from diffpy.srfit.fitbase.restraint import Restraint @@ -36,7 +36,7 @@ def testRestraint(self): factory.registerArgument("p2", p2) # Restrain 1 < p1 + p2 < 5 - eq = equationFromString("p1 + p2", factory) + eq = get_equation_from_string("p1 + p2", factory) r = Restraint(eq, 1, 5) # This should have no penalty From a5fb23c05c5e131a320a172fda0a6be3f639903a Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 9 Mar 2026 15:57:17 -0400 Subject: [PATCH 150/193] news --- news/recipeorg-dep2.rst | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 news/recipeorg-dep2.rst diff --git a/news/recipeorg-dep2.rst b/news/recipeorg-dep2.rst new file mode 100644 index 00000000..2bf0d1c5 --- /dev/null +++ b/news/recipeorg-dep2.rst @@ -0,0 +1,35 @@ +**Added:** + +* Added ``constrain_parameter`` method to ``RecipeOrganizer``. +* Added ``unconstrain_parameter`` method to ``RecipeOrganizer``. +* Added ``add_restraint`` method to ``RecipeOrganizer``. +* Added ``remove_restraint`` method to ``RecipeOrganizer``. +* Added ``register_restraint`` method to ``RecipeOrganizer``. +* Added ``clear_all_restraints`` method to ``RecipeOrganizer``. +* Added ``get_equation_from_string`` method to ``RecipeOrganizer``. + +**Changed:** + +* + +**Deprecated:** + +* Deprecated ``constrain`` method of ``RecipeOrganizer``. Use ``constrain_parameter`` instead. +* Deprecated ``unconstrain`` method of ``RecipeOrganizer``. Use ``unconstrain_parameter`` instead. +* Deprecated ``restrain`` method of ``RecipeOrganizer``. Use ``add_restraint`` instead. +* Deprecated ``unrestrain`` methods of ``RecipeOrganizer``. Use ``remove_restraint`` instead. +* Deprecated ``addRestraint`` method of ``RecipeOrganizer``. Use ``register_restraint`` instead. +* Deprecate ``clearRestraints`` method of ``RecipeOrganizer``. Use ``clear_all_restraints`` instead. +* Deprecated ``equationFromString`` method of ``RecipeOrganizer``. Use ``get_equation_from_string`` instead. + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From a79dbec735554d7947b77788127c6bca830de985 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 12 Mar 2026 10:17:30 -0400 Subject: [PATCH 151/193] constrain_parameter --> add_constraint --- docs/examples/coreshellnp.py | 10 +++++----- docs/examples/crystalpdfall.py | 14 ++++++------- docs/examples/crystalpdftwodata.py | 4 ++-- docs/examples/crystalpdftwophase.py | 8 ++++---- docs/examples/debyemodelII.py | 4 ++-- docs/examples/npintensity.py | 6 +++--- docs/examples/npintensityII.py | 6 +++--- docs/examples/nppdfobjcryst.py | 4 ++-- docs/examples/nppdfsas.py | 6 +++--- docs/examples/simplepdftwophase.py | 4 ++-- docs/examples/threedoublepeaks.py | 18 ++++++++--------- news/recipeorg-dep2.rst | 4 ++-- src/diffpy/srfit/fitbase/constraint.py | 8 ++++---- src/diffpy/srfit/fitbase/fitrecipe.py | 10 +++++----- src/diffpy/srfit/fitbase/recipeorganizer.py | 10 +++++----- src/diffpy/srfit/pdf/pdfcontribution.py | 4 ++-- src/diffpy/srfit/structure/sgconstraints.py | 22 ++++++++++----------- tests/conftest.py | 6 +++--- tests/test_constraint.py | 2 +- tests/test_fitrecipe.py | 8 ++++---- tests/test_recipeorganizer.py | 12 +++++------ tests/test_sgconstraints.py | 6 +++--- 22 files changed, 88 insertions(+), 88 deletions(-) diff --git a/docs/examples/coreshellnp.py b/docs/examples/coreshellnp.py index 4a413a70..23871a46 100644 --- a/docs/examples/coreshellnp.py +++ b/docs/examples/coreshellnp.py @@ -91,14 +91,14 @@ def makeRecipe(stru1, stru2, datname): # diameter to twice the shell radius. recipe.add_variable(contribution.radius, 15) recipe.add_variable(contribution.thickness, 11) - recipe.constrain_parameter(contribution.psize, "2 * radius") + recipe.add_constraint(contribution.psize, "2 * radius") # Configure the fit variables # Start by configuring the scale factor and resolution factors. # We want the sum of the phase scale factors to be 1. recipe.create_new_variable("scale_CdS", 0.7) - recipe.constrain_parameter(generator_cds.scale, "scale_CdS") - recipe.constrain_parameter(generator_zns.scale, "1 - scale_CdS") + recipe.add_constraint(generator_cds.scale, "scale_CdS") + recipe.add_constraint(generator_zns.scale, "1 - scale_CdS") # We also want the resolution factor to be the same on each. # Vary the global scale as well. @@ -117,7 +117,7 @@ def makeRecipe(stru1, stru2, datname): ) # Since we know these have stacking disorder, constrain the B33 adps for # each atom type. - recipe.constrain_parameter("B33_1_cds", "B33_0_cds") + recipe.add_constraint("B33_1_cds", "B33_0_cds") recipe.add_variable(generator_cds.delta2, name="delta2_cds", value=5) phase_zns = generator_zns.phase @@ -128,7 +128,7 @@ def makeRecipe(stru1, stru2, datname): recipe.add_variable( phase_zns.sgpars.xyzpars.z_1, name="z_1_zns", tag="xyz" ) - recipe.constrain_parameter("B33_1_zns", "B33_0_zns") + recipe.add_constraint("B33_1_zns", "B33_0_zns") recipe.add_variable(generator_zns.delta2, name="delta2_zns", value=2.5) # Give the recipe away so it can be used! diff --git a/docs/examples/crystalpdfall.py b/docs/examples/crystalpdfall.py index 32e573f0..1ee8903c 100644 --- a/docs/examples/crystalpdfall.py +++ b/docs/examples/crystalpdfall.py @@ -113,15 +113,15 @@ def makeRecipe( for par in phase_ni.sgpars: recipe.add_variable(par, name=par.name + "_ni") delta2_ni = recipe.create_new_variable("delta2_ni", 2.5) - recipe.constrain_parameter(xgenerator_ni.delta2, delta2_ni) - recipe.constrain_parameter(ngenerator_ni.delta2, delta2_ni) - recipe.constrain_parameter(xgenerator_sini_ni.delta2, delta2_ni) + recipe.add_constraint(xgenerator_ni.delta2, delta2_ni) + recipe.add_constraint(ngenerator_ni.delta2, delta2_ni) + recipe.add_constraint(xgenerator_sini_ni.delta2, delta2_ni) for par in phase_si.sgpars: recipe.add_variable(par, name=par.name + "_si") delta2_si = recipe.create_new_variable("delta2_si", 2.5) - recipe.constrain_parameter(xgenerator_si.delta2, delta2_si) - recipe.constrain_parameter(xgenerator_sini_si.delta2, delta2_si) + recipe.add_constraint(xgenerator_si.delta2, delta2_si) + recipe.add_constraint(xgenerator_sini_si.delta2, delta2_si) # Now the experimental parameters recipe.add_variable(xgenerator_ni.scale, name="xscale_ni") @@ -129,8 +129,8 @@ def makeRecipe( recipe.add_variable(ngenerator_ni.scale, name="nscale_ni") recipe.add_variable(xcontribution_sini.scale, 1.0, "xscale_sini") recipe.create_new_variable("pscale_sini_ni", 0.8) - recipe.constrain_parameter(xgenerator_sini_ni.scale, "pscale_sini_ni") - recipe.constrain_parameter(xgenerator_sini_si.scale, "1 - pscale_sini_ni") + recipe.add_constraint(xgenerator_sini_ni.scale, "pscale_sini_ni") + recipe.add_constraint(xgenerator_sini_si.scale, "1 - pscale_sini_ni") # The qdamp parameters are too correlated to vary so we fix them based on # previous measurements. diff --git a/docs/examples/crystalpdftwodata.py b/docs/examples/crystalpdftwodata.py index e82374b2..0b0d6093 100644 --- a/docs/examples/crystalpdftwodata.py +++ b/docs/examples/crystalpdftwodata.py @@ -121,8 +121,8 @@ def makeRecipe(ciffile, xdatname, ndatname): # delta2 is a non-structual material property. Thus, we constrain together # delta2 Parameter from each PDFGenerator. delta2 = recipe.create_new_variable("delta2", 2) - recipe.constrain_parameter(xgenerator.delta2, delta2) - recipe.constrain_parameter(ngenerator.delta2, delta2) + recipe.add_constraint(xgenerator.delta2, delta2) + recipe.add_constraint(ngenerator.delta2, delta2) # We only need to constrain phase properties once since there is a single # ObjCrystCrystalParSet for the Crystal. diff --git a/docs/examples/crystalpdftwophase.py b/docs/examples/crystalpdftwophase.py index 3f0a0194..2071ac7a 100644 --- a/docs/examples/crystalpdftwophase.py +++ b/docs/examples/crystalpdftwophase.py @@ -90,12 +90,12 @@ def makeRecipe(niciffile, siciffile, datname): # Start by configuring the scale factor and resolution factors. # We want the sum of the phase scale factors to be 1. recipe.create_new_variable("scale_ni", 0.1) - recipe.constrain_parameter(generator_ni.scale, "scale_ni") - recipe.constrain_parameter(generator_si.scale, "1 - scale_ni") + recipe.add_constraint(generator_ni.scale, "scale_ni") + recipe.add_constraint(generator_si.scale, "1 - scale_ni") # We also want the resolution factor to be the same on each. recipe.create_new_variable("qdamp", 0.03) - recipe.constrain_parameter(generator_ni.qdamp, "qdamp") - recipe.constrain_parameter(generator_si.qdamp, "qdamp") + recipe.add_constraint(generator_ni.qdamp, "qdamp") + recipe.add_constraint(generator_si.qdamp, "qdamp") # Vary the global scale as well. recipe.add_variable(contribution.scale, 1) diff --git a/docs/examples/debyemodelII.py b/docs/examples/debyemodelII.py index 4115179f..a79df5f6 100644 --- a/docs/examples/debyemodelII.py +++ b/docs/examples/debyemodelII.py @@ -89,8 +89,8 @@ def makeRecipeII(): # We create a new Variable and use the recipe's "constrain" method to # associate the Debye temperature parameters with that variable. recipe.create_new_variable("thetaD", 100) - recipe.constrain_parameter(recipe.lowT.thetaD, "thetaD") - recipe.constrain_parameter(recipe.highT.thetaD, "thetaD") + recipe.add_constraint(recipe.lowT.thetaD, "thetaD") + recipe.add_constraint(recipe.highT.thetaD, "thetaD") return recipe diff --git a/docs/examples/npintensity.py b/docs/examples/npintensity.py index 54843d9f..eaf17012 100644 --- a/docs/examples/npintensity.py +++ b/docs/examples/npintensity.py @@ -290,15 +290,15 @@ def gaussian(q, q0, width): lattice = phase.getLattice() a = lattice.a recipe.add_variable(a) - recipe.constrain_parameter(lattice.b, a) - recipe.constrain_parameter(lattice.c, a) + recipe.add_constraint(lattice.b, a) + recipe.add_constraint(lattice.c, a) # We want to refine the thermal parameters as well. We will add a new # Variable that we call "Uiso" and constrain the atomic Uiso values to # this. Note that we don't give Uiso an initial value. The initial value # will be inferred from the following constraints. Uiso = recipe.create_new_variable("Uiso") for atom in phase.getScatterers(): - recipe.constrain_parameter(atom.Uiso, Uiso) + recipe.add_constraint(atom.Uiso, Uiso) # Give the recipe away so it can be used! return recipe diff --git a/docs/examples/npintensityII.py b/docs/examples/npintensityII.py index 69b54efc..5a6415a6 100644 --- a/docs/examples/npintensityII.py +++ b/docs/examples/npintensityII.py @@ -173,15 +173,15 @@ def gaussian(q, q0, width): a = recipe.add_variable(lattice.a) # We want to allow for isotropic expansion, so we'll make constraints for # that. - recipe.constrain_parameter(lattice.b, a) - recipe.constrain_parameter(lattice.c, a) + recipe.add_constraint(lattice.b, a) + recipe.add_constraint(lattice.c, a) # We want to refine the thermal parameters as well. We will add a new # variable that we call "Uiso" and constrain the atomic Uiso values to # this. Note that we don't give Uiso an initial value. The initial value # will be inferred from the subsequent constraints. Uiso = recipe.create_new_variable("Uiso") for atom in phase.getScatterers(): - recipe.constrain_parameter(atom.Uiso, Uiso) + recipe.add_constraint(atom.Uiso, Uiso) # Give the recipe away so it can be used! return recipe diff --git a/docs/examples/nppdfobjcryst.py b/docs/examples/nppdfobjcryst.py index 33a387ab..03511d19 100644 --- a/docs/examples/nppdfobjcryst.py +++ b/docs/examples/nppdfobjcryst.py @@ -73,7 +73,7 @@ def makeRecipe(molecule, datname): # has no scattering power. It is only used as a reference point for # our bond length. We don't want to constrain it. if not atom.isDummy(): - recipe.constrain_parameter(atom.Biso, Biso) + recipe.add_constraint(atom.Biso, Biso) # We need to let the molecule expand. If we were modeling it as a crystal, # we could let the unit cell expand. For instruction purposes, we use a @@ -97,7 +97,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) - recipe.constrain_parameter(par, radius) + recipe.add_constraint(par, radius) # Add the correlation term, scale. The scale is too short to effectively # determine qdamp. diff --git a/docs/examples/nppdfsas.py b/docs/examples/nppdfsas.py index adaae5bc..c2cdbe84 100644 --- a/docs/examples/nppdfsas.py +++ b/docs/examples/nppdfsas.py @@ -113,8 +113,8 @@ def makeRecipe(ciffile, grdata, iqdata): # Even though the cfcalculator and sasgenerator depend on the same sas # model, we must still constrain the cfcalculator Parameters so that it is # informed of changes in the refined parameters. - recipe.constrain_parameter(cfcalculator.radius_a, "radius_a") - recipe.constrain_parameter(cfcalculator.radius_b, "radius_b") + recipe.add_constraint(cfcalculator.radius_a, "radius_a") + recipe.add_constraint(cfcalculator.radius_b, "radius_b") return recipe @@ -126,7 +126,7 @@ def fitRecipe(recipe): recipe.set_weight(recipe.pdf, 0) recipe.fix("all") recipe.free("radius_a", "radius_b", iqscale=1e8) - recipe.constrain_parameter("radius_b", "radius_a") + recipe.add_constraint("radius_b", "radius_a") scipyOptimize(recipe) recipe.unconstrain_parameter("radius_b") diff --git a/docs/examples/simplepdftwophase.py b/docs/examples/simplepdftwophase.py index e0735514..17ff79a2 100644 --- a/docs/examples/simplepdftwophase.py +++ b/docs/examples/simplepdftwophase.py @@ -47,8 +47,8 @@ def makeRecipe(niciffile, siciffile, datname): # Start by configuring the scale factor and resolution factors. # We want the sum of the phase scale factors to be 1. recipe.create_new_variable("scale_ni", 0.1) - recipe.constrain_parameter(contribution.ni.scale, "scale_ni") - recipe.constrain_parameter(contribution.si.scale, "1 - scale_ni") + recipe.add_constraint(contribution.ni.scale, "scale_ni") + recipe.add_constraint(contribution.si.scale, "1 - scale_ni") # We also want the resolution factor to be the same on each. This is done # for free by the PDFContribution. We simply need to add it to the recipe. recipe.add_variable(contribution.qdamp, 0.03) diff --git a/docs/examples/threedoublepeaks.py b/docs/examples/threedoublepeaks.py index 17d23ed1..ecf01bf4 100644 --- a/docs/examples/threedoublepeaks.py +++ b/docs/examples/threedoublepeaks.py @@ -121,9 +121,9 @@ def peakloc(mu): return 180 / pi * arcsin(pi / 180 * l2 * sin(mu) / l1) recipe.register_function(peakloc) - recipe.constrain_parameter(contribution.mu12, "peakloc(mu11)") - recipe.constrain_parameter(contribution.mu22, "peakloc(mu21)") - recipe.constrain_parameter(contribution.mu32, "peakloc(mu31)") + recipe.add_constraint(contribution.mu12, "peakloc(mu11)") + recipe.add_constraint(contribution.mu22, "peakloc(mu21)") + recipe.add_constraint(contribution.mu32, "peakloc(mu31)") # Vary the width of the peaks. We know the functional form of the peak # broadening. @@ -139,20 +139,20 @@ def sig(sig0, dsig, mu): # Now constrain the peak widths to this recipe.sig0.value = 0.001 recipe.dsig.value = 4.0 - recipe.constrain_parameter(contribution.sig11, "sig(sig0, dsig, mu11)") - recipe.constrain_parameter( + recipe.add_constraint(contribution.sig11, "sig(sig0, dsig, mu11)") + recipe.add_constraint( contribution.sig12, "sig(sig0, dsig, mu12)", ns={"mu12": contribution.mu12}, ) - recipe.constrain_parameter(contribution.sig21, "sig(sig0, dsig, mu21)") - recipe.constrain_parameter( + recipe.add_constraint(contribution.sig21, "sig(sig0, dsig, mu21)") + recipe.add_constraint( contribution.sig22, "sig(sig0, dsig, mu22)", ns={"mu22": contribution.mu22}, ) - recipe.constrain_parameter(contribution.sig31, "sig(sig0, dsig, mu31)") - recipe.constrain_parameter( + recipe.add_constraint(contribution.sig31, "sig(sig0, dsig, mu31)") + recipe.add_constraint( contribution.sig32, "sig(sig0, dsig, mu32)", ns={"mu32": contribution.mu32}, diff --git a/news/recipeorg-dep2.rst b/news/recipeorg-dep2.rst index 2bf0d1c5..b2236f9e 100644 --- a/news/recipeorg-dep2.rst +++ b/news/recipeorg-dep2.rst @@ -1,6 +1,6 @@ **Added:** -* Added ``constrain_parameter`` method to ``RecipeOrganizer``. +* Added ``add_constraint`` method to ``RecipeOrganizer``. * Added ``unconstrain_parameter`` method to ``RecipeOrganizer``. * Added ``add_restraint`` method to ``RecipeOrganizer``. * Added ``remove_restraint`` method to ``RecipeOrganizer``. @@ -14,7 +14,7 @@ **Deprecated:** -* Deprecated ``constrain`` method of ``RecipeOrganizer``. Use ``constrain_parameter`` instead. +* Deprecated ``constrain`` method of ``RecipeOrganizer``. Use ``add_constraint`` instead. * Deprecated ``unconstrain`` method of ``RecipeOrganizer``. Use ``unconstrain_parameter`` instead. * Deprecated ``restrain`` method of ``RecipeOrganizer``. Use ``add_restraint`` instead. * Deprecated ``unrestrain`` methods of ``RecipeOrganizer``. Use ``remove_restraint`` instead. diff --git a/src/diffpy/srfit/fitbase/constraint.py b/src/diffpy/srfit/fitbase/constraint.py index c24eaf35..dba135b4 100644 --- a/src/diffpy/srfit/fitbase/constraint.py +++ b/src/diffpy/srfit/fitbase/constraint.py @@ -32,7 +32,7 @@ constrain_deprecation_msg = build_deprecation_message( base, "constrain", - "constrain_parameter", + "add_constraint", removal_version, ) @@ -65,7 +65,7 @@ def __init__(self): self.eq = None return - def constrain_parameter(self, par, eq): + def add_constraint(self, par, eq): """Constrain a Parameter according to an Equation. The parameter will be set constant once it is constrained. This @@ -103,10 +103,10 @@ def constrain(self, par, eq): version 4.0.0. Please use - diffpy.srfit.fitbase.constraint.Constraint.constrain_parameter + diffpy.srfit.fitbase.constraint.Constraint.add_constraint instead. """ - self.constrain_parameter(par, eq) + self.add_constraint(par, eq) return def unconstrain_parameter(self): diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 1dc61fbc..12ac4428 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -126,7 +126,7 @@ ) constrain_dep_msg = build_deprecation_message( - base, "constrain", "constrain_parameter", removal_version + base, "constrain", "add_constraint", removal_version ) unconstrain_dep_msg = build_deprecation_message( @@ -1157,7 +1157,7 @@ def unconstrain(self, *pars): self.unconstrain_parameter(*pars) return - def constrain_parameter(self, par, con, ns={}): + def add_constraint(self, par, con, ns={}): """Constrain a parameter to an equation. Note that only one constraint can exist on a Parameter at a time. @@ -1215,7 +1215,7 @@ def constrain_parameter(self, par, con, ns={}): if par in self._parameters.values(): self.fix(par) - RecipeOrganizer.constrain_parameter(self, par, con, ns) + RecipeOrganizer.add_constraint(self, par, con, ns) return @deprecated(constrain_dep_msg) @@ -1223,10 +1223,10 @@ def constrain(self, par, con, ns={}): """This function has been deprecated and will be removed in version 4.0.0. - Please use diffpy.srfit.fitbase.FitRecipe.constrain_parameter + Please use diffpy.srfit.fitbase.FitRecipe.add_constraint instead. """ - self.constrain_parameter(par, con, ns) + self.add_constraint(par, con, ns) return def get_values(self): diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 256faa9d..333a9a3c 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -128,7 +128,7 @@ constrain_deprecation_msg = build_deprecation_message( recipeorganizer_base, "constrain", - "constrain_parameter", + "add_constraint", removal_version, ) @@ -934,7 +934,7 @@ def evaluateEquation(self, eqstr, ns={}): """ return self.evaluate_equation(eqstr, func_params=ns) - def constrain_parameter(self, parameter, constraint_eq, params={}): + def add_constraint(self, parameter, constraint_eq, params={}): """Constrain a parameter to an equation. Note that only one constraint can exist on a Parameter at a time. @@ -989,7 +989,7 @@ def constrain_parameter(self, parameter, constraint_eq, params={}): # Make and store the constraint constraint_eq = Constraint() - constraint_eq.constrain_parameter(parameter, eq) + constraint_eq.add_constraint(parameter, eq) # Store the equation string so it can be shown later. constraint_eq.eqstr = eqstr self._constraints[parameter] = constraint_eq @@ -1005,10 +1005,10 @@ def constrain(self, parameter, constraint_eq, params={}): version 4.0.0. Please use - diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.constrain_parameter + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.add_constraint instead. """ - self.constrain_parameter(parameter, constraint_eq, params=params) + self.add_constraint(parameter, constraint_eq, params=params) return def is_constrained(self, parameter): diff --git a/src/diffpy/srfit/pdf/pdfcontribution.py b/src/diffpy/srfit/pdf/pdfcontribution.py index 8ef1578b..07d33c5d 100644 --- a/src/diffpy/srfit/pdf/pdfcontribution.py +++ b/src/diffpy/srfit/pdf/pdfcontribution.py @@ -287,8 +287,8 @@ def _setup_generator(self, gen): gen.processMetaData() # Constrain the shared parameters - self.constrain_parameter(gen.qdamp, self.qdamp) - self.constrain_parameter(gen.qbroad, self.qbroad) + self.add_constraint(gen.qdamp, self.qdamp) + self.add_constraint(gen.qbroad, self.qbroad) return # Calculation setup methods diff --git a/src/diffpy/srfit/structure/sgconstraints.py b/src/diffpy/srfit/structure/sgconstraints.py index 681bad1b..19b6d187 100644 --- a/src/diffpy/srfit/structure/sgconstraints.py +++ b/src/diffpy/srfit/structure/sgconstraints.py @@ -596,7 +596,7 @@ def _constrain_adps(self, positions): continue isoidx.append(j) scatterer = scatterers[j] - scatterer.constrain_parameter( + scatterer.add_constraint( isosymbol, isoname, params=self._parameters ) @@ -691,7 +691,7 @@ def _constrain_tetragonal(lattice): lattice.alpha.setConst(True, ang90) lattice.beta.setConst(True, ang90) lattice.gamma.setConst(True, ang90) - lattice.constrain_parameter(lattice.b, lattice.a) + lattice.add_constraint(lattice.b, lattice.a) return @@ -708,15 +708,15 @@ def _constrain_trigonal(lattice): ang90 = 90.0 * afactor ang120 = 120.0 * afactor if lattice.gamma.getValue() == ang120: - lattice.constrain_parameter(lattice.b, lattice.a) + lattice.add_constraint(lattice.b, lattice.a) lattice.alpha.setConst(True, ang90) lattice.beta.setConst(True, ang90) lattice.gamma.setConst(True, ang120) else: - lattice.constrain_parameter(lattice.b, lattice.a) - lattice.constrain_parameter(lattice.c, lattice.a) - lattice.constrain_parameter(lattice.beta, lattice.alpha) - lattice.constrain_parameter(lattice.gamma, lattice.alpha) + lattice.add_constraint(lattice.b, lattice.a) + lattice.add_constraint(lattice.c, lattice.a) + lattice.add_constraint(lattice.beta, lattice.alpha) + lattice.add_constraint(lattice.gamma, lattice.alpha) return @@ -731,7 +731,7 @@ def _constrain_hexagonal(lattice): afactor = deg2rad ang90 = 90.0 * afactor ang120 = 120.0 * afactor - lattice.constrain_parameter(lattice.b, lattice.a) + lattice.add_constraint(lattice.b, lattice.a) lattice.alpha.setConst(True, ang90) lattice.beta.setConst(True, ang90) lattice.gamma.setConst(True, ang120) @@ -748,8 +748,8 @@ def _constrain_cubic(lattice): if lattice.angunits == "rad": afactor = deg2rad ang90 = 90.0 * afactor - lattice.constrain_parameter(lattice.b, lattice.a) - lattice.constrain_parameter(lattice.c, lattice.a) + lattice.add_constraint(lattice.b, lattice.a) + lattice.add_constraint(lattice.c, lattice.a) lattice.alpha.setConst(True, ang90) lattice.beta.setConst(True, ang90) lattice.gamma.setConst(True, ang90) @@ -811,7 +811,7 @@ 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_parameter(par, formula, params=ns) + scatterer.add_constraint(par, formula, params=ns) return diff --git a/tests/conftest.py b/tests/conftest.py index 118f30d4..8dc38c9a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -215,9 +215,9 @@ def build_recipe_two_contributions(): recipe.add_variable(contribution2.d, 0.1) # ---- Meaningful constraints ---- - recipe.constrain_parameter(contribution2.m, "2*k") - recipe.constrain_parameter(contribution2.d, contribution1.c) - recipe.constrain_parameter(contribution2.B, "0.5*A") + recipe.add_constraint(contribution2.m, "2*k") + recipe.add_constraint(contribution2.d, contribution1.c) + recipe.add_constraint(contribution2.B, "0.5*A") recipe.add_restraint(contribution1.A, 0.5, 1.5) recipe.add_restraint(contribution1.k, 0.8, 1.2) diff --git a/tests/test_constraint.py b/tests/test_constraint.py index 014e8939..d045feb5 100644 --- a/tests/test_constraint.py +++ b/tests/test_constraint.py @@ -38,7 +38,7 @@ def test_constrain_parameter(self): c = Constraint() # Constrain p1 = 2*p2 eq = get_equation_from_string("2*p2", factory) - c.constrain_parameter(p1, eq) + c.add_constraint(p1, eq) self.assertTrue(p1.constrained) self.assertFalse(p2.constrained) diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 3e165268..75066f65 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -119,7 +119,7 @@ def test_variables(self): # Constrain a parameter to the B-variable to give it a value p = Parameter("Bpar", -1) - recipe.constrain_parameter(recipe.B, p) + recipe.add_constraint(recipe.B, p) values = recipe.get_values() self.assertTrue((values == [2, 1, 0]).all()) recipe.delete_variable(recipe.B) @@ -215,11 +215,11 @@ def testResidual(self): # Try some constraints # Make c = 2*A, A = Avar var = self.recipe.create_new_variable("Avar") - self.recipe.constrain_parameter( + self.recipe.add_constraint( self.fitcontribution.c, "2*A", {"A": self.fitcontribution.A} ) self.assertEqual(2, self.fitcontribution.c.value) - self.recipe.constrain_parameter(self.fitcontribution.A, var) + self.recipe.add_constraint(self.fitcontribution.A, var) self.assertEqual(1, var.getValue()) self.assertEqual(self.recipe.cont.A.getValue(), var.getValue()) # c is constrained to a constrained parameter. @@ -255,7 +255,7 @@ def testResidual(self): self.assertAlmostEqual(chi2, dot(res, res)) # Add constraints at the fitcontribution level. - self.fitcontribution.constrain_parameter(self.fitcontribution.c, "2*A") + self.fitcontribution.add_constraint(self.fitcontribution.c, "2*A") # This should evaluate to sin(x+2) x = self.profile.x y = sin(x + 2) diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index 0302ca6e..4af757e0 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -275,7 +275,7 @@ def test_constrain_parameter(self): self.assertFalse(p1.constrained) self.assertEqual(0, len(self.m._constraints)) - self.m.constrain_parameter(p1, "2*p2") + self.m.add_constraint(p1, "2*p2") actual_constrained_params = self.m.getConstrainedPars() actual_constrained_params = [p.name for p in actual_constrained_params] @@ -309,7 +309,7 @@ def test_constrain_parameter(self): self.assertFalse(self.m.isConstrained(p1)) # Try an straight constraint - self.m.constrain_parameter(p1, p2) + self.m.add_constraint(p1, p2) p2.set_value(7) self.m._constraints[p1].update() self.assertEqual(7, p1.getValue()) @@ -321,7 +321,7 @@ def test_constrain_parameter(self): assert actual_constrained_params == expected_constrained_params # add constraint back and test the old function name `clearConstraints` - self.m.constrain_parameter(p1, p2) + self.m.add_constraint(p1, p2) actual_constrained_params = self.m.get_constrained_parmeters() actual_constrained_params = [p.name for p in actual_constrained_params] expected_constrained_params = [p1.name] @@ -382,8 +382,8 @@ def testGetConstraints(self): m2._add_parameter(p3) m2._add_parameter(p4) - self.m.constrain_parameter(p1, "p2") - m2.constrain_parameter(p3, "p4") + self.m.add_constraint(p1, "p2") + m2.add_constraint(p3, "p4") cons = self.m._get_constraints() self.assertTrue(p1 in cons) @@ -632,7 +632,7 @@ def capture_show(*args, **kwargs): assert "Constraints" not in lines1 assert "Restraints" not in lines1 organizer._new_parameter("z", 7) - organizer.constrain_parameter("y", "3 * z") + organizer.add_constraint("y", "3 * z") out2 = capture_show() lines2 = out2.strip().split("\n") assert 9 == len(lines2) diff --git a/tests/test_sgconstraints.py b/tests/test_sgconstraints.py index 19bb49f2..211d61be 100644 --- a/tests/test_sgconstraints.py +++ b/tests/test_sgconstraints.py @@ -87,13 +87,13 @@ def test_ObjCryst_constrain_space_group(pyobjcryst_available): # Make sure we can't constrain these with pytest.raises(ValueError): - mn.constrain_parameter(mn.x, "y") + mn.add_constraint(mn.x, "y") with pytest.raises(ValueError): - mn.constrain_parameter(mn.y, "z") + mn.add_constraint(mn.y, "z") with pytest.raises(ValueError): - mn.constrain_parameter(mn.z, "x") + mn.add_constraint(mn.z, "x") # Nor can we make them into variables from diffpy.srfit.fitbase.fitrecipe import FitRecipe From 80173b60520bff15d3d45322893161194e7a043a Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 12 Mar 2026 10:18:20 -0400 Subject: [PATCH 152/193] unconstrain_parameter --> remove_constraint --- docs/examples/nppdfsas.py | 2 +- news/recipeorg-dep2.rst | 4 ++-- src/diffpy/srfit/fitbase/constraint.py | 8 ++++---- src/diffpy/srfit/fitbase/fitrecipe.py | 10 +++++----- src/diffpy/srfit/fitbase/recipeorganizer.py | 12 ++++++------ src/diffpy/srfit/structure/sgconstraints.py | 8 ++++---- tests/test_fitrecipe.py | 2 +- tests/test_recipeorganizer.py | 2 +- 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/examples/nppdfsas.py b/docs/examples/nppdfsas.py index c2cdbe84..7bea8069 100644 --- a/docs/examples/nppdfsas.py +++ b/docs/examples/nppdfsas.py @@ -128,7 +128,7 @@ def fitRecipe(recipe): recipe.free("radius_a", "radius_b", iqscale=1e8) recipe.add_constraint("radius_b", "radius_a") scipyOptimize(recipe) - recipe.unconstrain_parameter("radius_b") + recipe.remove_constraint("radius_b") # Tune PDF recipe.set_weight(recipe.pdf, 1) diff --git a/news/recipeorg-dep2.rst b/news/recipeorg-dep2.rst index b2236f9e..28018154 100644 --- a/news/recipeorg-dep2.rst +++ b/news/recipeorg-dep2.rst @@ -1,7 +1,7 @@ **Added:** * Added ``add_constraint`` method to ``RecipeOrganizer``. -* Added ``unconstrain_parameter`` method to ``RecipeOrganizer``. +* Added ``remove_constraint`` method to ``RecipeOrganizer``. * Added ``add_restraint`` method to ``RecipeOrganizer``. * Added ``remove_restraint`` method to ``RecipeOrganizer``. * Added ``register_restraint`` method to ``RecipeOrganizer``. @@ -15,7 +15,7 @@ **Deprecated:** * Deprecated ``constrain`` method of ``RecipeOrganizer``. Use ``add_constraint`` instead. -* Deprecated ``unconstrain`` method of ``RecipeOrganizer``. Use ``unconstrain_parameter`` instead. +* Deprecated ``unconstrain`` method of ``RecipeOrganizer``. Use ``remove_constraint`` instead. * Deprecated ``restrain`` method of ``RecipeOrganizer``. Use ``add_restraint`` instead. * Deprecated ``unrestrain`` methods of ``RecipeOrganizer``. Use ``remove_restraint`` instead. * Deprecated ``addRestraint`` method of ``RecipeOrganizer``. Use ``register_restraint`` instead. diff --git a/src/diffpy/srfit/fitbase/constraint.py b/src/diffpy/srfit/fitbase/constraint.py index dba135b4..dab6002b 100644 --- a/src/diffpy/srfit/fitbase/constraint.py +++ b/src/diffpy/srfit/fitbase/constraint.py @@ -39,7 +39,7 @@ unconstrain_deprecation_msg = build_deprecation_message( base, "unconstrain", - "unconstrain_parameter", + "remove_constraint", removal_version, ) @@ -109,7 +109,7 @@ def constrain(self, par, eq): self.add_constraint(par, eq) return - def unconstrain_parameter(self): + def remove_constraint(self): """Clear the constraint from a Parameter.""" self.par.constrained = False self.par = None @@ -122,10 +122,10 @@ def unconstrain(self): version 4.0.0. Please use - diffpy.srfit.fitbase.constraint.Constraint.unconstrain_parameter + diffpy.srfit.fitbase.constraint.Constraint.remove_constraint instead. """ - self.unconstrain_parameter() + self.remove_constraint() return def update(self): diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 12ac4428..416133cb 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -130,7 +130,7 @@ ) unconstrain_dep_msg = build_deprecation_message( - base, "unconstrain", "unconstrain_parameter", removal_version + base, "unconstrain", "remove_constraint", removal_version ) @@ -1107,7 +1107,7 @@ def isFree(self, var): """ return self.is_free(var) - def unconstrain_parameter(self, *pars): + def remove_constraint(self, *pars): """Unconstrain a Parameter. This removes any constraints on a Parameter. If the Parameter is also a @@ -1133,7 +1133,7 @@ def unconstrain_parameter(self, *pars): raise ValueError("The parameter cannot be found") if par in self._constraints: - self._constraints[par].unconstrain_parameter() + self._constraints[par].remove_constraint() del self._constraints[par] update = True @@ -1151,10 +1151,10 @@ def unconstrain(self, *pars): """This function has been deprecated and will be removed in version 4.0.0. - Please use diffpy.srfit.fitbase.FitRecipe.unconstrain_parameter + Please use diffpy.srfit.fitbase.FitRecipe.remove_constraint instead. """ - self.unconstrain_parameter(*pars) + self.remove_constraint(*pars) return def add_constraint(self, par, con, ns={}): diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 333a9a3c..b3a92bfe 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -135,7 +135,7 @@ unconstrain_deprecation_msg = build_deprecation_message( recipeorganizer_base, "unconstrain", - "unconstrain_parameter", + "remove_constraint", removal_version, ) @@ -1042,7 +1042,7 @@ def isConstrained(self, parameter): """ return self.is_constrained(parameter) - def unconstrain_parameter(self, *pars): + def remove_constraint(self, *pars): """Unconstrain a Parameter. This removes any constraints on a Parameter. @@ -1065,7 +1065,7 @@ def unconstrain_parameter(self, *pars): raise ValueError("The parameter cannot be found") if parameter in self._constraints: - self._constraints[parameter].unconstrain_parameter() + self._constraints[parameter].remove_constraint() del self._constraints[parameter] update = True @@ -1085,10 +1085,10 @@ def unconstrain(self, *pars): version 4.0.0. Please use - diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.unconstrain_parameter + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.remove_constraint instead. """ - self.unconstrain_parameter(*pars) + self.remove_constraint(*pars) return def get_constrained_parmeters(self, recurse=False): @@ -1136,7 +1136,7 @@ def clear_all_constraints(self, recurse=False): sub-objects are also cleared. """ if self._constraints: - self.unconstrain_parameter(*self._constraints) + self.remove_constraint(*self._constraints) if recurse: for m in filter(_has_clear_constraints, self._iter_managed()): diff --git a/src/diffpy/srfit/structure/sgconstraints.py b/src/diffpy/srfit/structure/sgconstraints.py index 19b6d187..2b48ec1d 100644 --- a/src/diffpy/srfit/structure/sgconstraints.py +++ b/src/diffpy/srfit/structure/sgconstraints.py @@ -391,7 +391,7 @@ def _clear_constraints(self): for par in [scatterer.x, scatterer.y, scatterer.z]: if scatterer.is_constrained(par): - scatterer.unconstrain_parameter(par) + scatterer.remove_constraint(par) par.setConst(False) # Clear the lattice @@ -408,7 +408,7 @@ def _clear_constraints(self): ] for par in latpars: if lattice.is_constrained(par): - lattice.unconstrain_parameter(par) + lattice.remove_constraint(par) par.setConst(False) # Clear ADPs @@ -418,14 +418,14 @@ def _clear_constraints(self): par = scatterer.get(isosymbol) if par is not None: if scatterer.is_constrained(par): - scatterer.unconstrain_parameter(par) + scatterer.remove_constraint(par) par.setConst(False) for pname in adpsymbols: par = scatterer.get(pname) if par is not None: if scatterer.is_constrained(par): - scatterer.unconstrain_parameter(par) + scatterer.remove_constraint(par) par.setConst(False) return diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 75066f65..885a34a7 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -240,7 +240,7 @@ def testResidual(self): # Clear the constraint and restore the value of c to 0. This should # give us chi2 = 0 again. - self.recipe.unconstrain_parameter(self.fitcontribution.c) + self.recipe.remove_constraint(self.fitcontribution.c) self.fitcontribution.c.set_value(0) res = self.recipe.residual([self.recipe.cont.A.getValue()]) chi2 = 0 diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index 4af757e0..66cff9b4 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -303,7 +303,7 @@ def test_constrain_parameter(self): self.assertRaises(ValueError, self.m.constrain, p1, "2*p2", {"p2": p3}) # Remove the constraint - self.m.unconstrain_parameter(p1) + self.m.remove_constraint(p1) self.assertFalse(p1.constrained) self.assertEqual(0, len(self.m._constraints)) self.assertFalse(self.m.isConstrained(p1)) From 31a57fc22905151629d5feb63bf7bfccbf4dd56f Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 12 Mar 2026 10:19:36 -0400 Subject: [PATCH 153/193] add_restraint --> add_penalty --- docs/examples/crystalpdftwophase.py | 12 ++++++------ docs/examples/debyemodel.py | 2 +- docs/examples/simplepdftwophase.py | 12 ++++++------ news/recipeorg-dep2.rst | 4 ++-- src/diffpy/srfit/fitbase/fitrecipe.py | 2 +- src/diffpy/srfit/fitbase/recipeorganizer.py | 10 +++++----- tests/conftest.py | 4 ++-- tests/test_fitrecipe.py | 10 ++++------ tests/test_recipeorganizer.py | 8 ++++---- 9 files changed, 31 insertions(+), 33 deletions(-) diff --git a/docs/examples/crystalpdftwophase.py b/docs/examples/crystalpdftwophase.py index 2071ac7a..c7354211 100644 --- a/docs/examples/crystalpdftwophase.py +++ b/docs/examples/crystalpdftwophase.py @@ -123,18 +123,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.add_restraint("a_ni", lb=3.527, ub=3.527, scaled=True) + recipe.add_penalty("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.add_restraint("delta2_ni", lb=2.22, ub=2.22, scaled=True) - recipe.add_restraint("Biso_0_ni", lb=0.454, ub=0.454, scaled=True) + recipe.add_penalty("delta2_ni", lb=2.22, ub=2.22, scaled=True) + recipe.add_penalty("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.add_restraint("a_si", lb=5.430, ub=5.430, scaled=True) - recipe.add_restraint("delta2_si", lb=3.54, ub=3.54, scaled=True) - recipe.add_restraint("Biso_0_si", lb=0.645, ub=0.645, scaled=True) + recipe.add_penalty("a_si", lb=5.430, ub=5.430, scaled=True) + recipe.add_penalty("delta2_si", lb=3.54, ub=3.54, scaled=True) + recipe.add_penalty("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/docs/examples/debyemodel.py b/docs/examples/debyemodel.py index c49c13b0..a373f307 100644 --- a/docs/examples/debyemodel.py +++ b/docs/examples/debyemodel.py @@ -152,7 +152,7 @@ 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.add_restraint(recipe.offset, lb=0, scaled=True) + recipe.add_penalty(recipe.offset, lb=0, scaled=True) # We're done setting up the recipe. We can now do other things with it. return recipe diff --git a/docs/examples/simplepdftwophase.py b/docs/examples/simplepdftwophase.py index 17ff79a2..ec496542 100644 --- a/docs/examples/simplepdftwophase.py +++ b/docs/examples/simplepdftwophase.py @@ -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.add_restraint("a_ni", lb=3.527, ub=3.527, scaled=True) + recipe.add_penalty("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.add_restraint("delta2_ni", lb=2.22, ub=2.22, scaled=True) - recipe.add_restraint("Biso_0_ni", lb=0.454, ub=0.454, scaled=True) + recipe.add_penalty("delta2_ni", lb=2.22, ub=2.22, scaled=True) + recipe.add_penalty("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.add_restraint("a_si", lb=5.430, ub=5.430, scaled=True) - recipe.add_restraint("delta2_si", lb=3.54, ub=3.54, scaled=True) - recipe.add_restraint("Biso_0_si", lb=0.645, ub=0.645, scaled=True) + recipe.add_penalty("a_si", lb=5.430, ub=5.430, scaled=True) + recipe.add_penalty("delta2_si", lb=3.54, ub=3.54, scaled=True) + recipe.add_penalty("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/news/recipeorg-dep2.rst b/news/recipeorg-dep2.rst index 28018154..2c707f1d 100644 --- a/news/recipeorg-dep2.rst +++ b/news/recipeorg-dep2.rst @@ -2,7 +2,7 @@ * Added ``add_constraint`` method to ``RecipeOrganizer``. * Added ``remove_constraint`` method to ``RecipeOrganizer``. -* Added ``add_restraint`` method to ``RecipeOrganizer``. +* Added ``add_penalty`` method to ``RecipeOrganizer``. * Added ``remove_restraint`` method to ``RecipeOrganizer``. * Added ``register_restraint`` method to ``RecipeOrganizer``. * Added ``clear_all_restraints`` method to ``RecipeOrganizer``. @@ -16,7 +16,7 @@ * Deprecated ``constrain`` method of ``RecipeOrganizer``. Use ``add_constraint`` instead. * Deprecated ``unconstrain`` method of ``RecipeOrganizer``. Use ``remove_constraint`` instead. -* Deprecated ``restrain`` method of ``RecipeOrganizer``. Use ``add_restraint`` instead. +* Deprecated ``restrain`` method of ``RecipeOrganizer``. Use ``add_penalty`` instead. * Deprecated ``unrestrain`` methods of ``RecipeOrganizer``. Use ``remove_restraint`` instead. * Deprecated ``addRestraint`` method of ``RecipeOrganizer``. Use ``register_restraint`` instead. * Deprecate ``clearRestraints`` method of ``RecipeOrganizer``. Use ``clear_all_restraints`` instead. diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 416133cb..7740a20e 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -1756,7 +1756,7 @@ def convert_bounds_to_restraints(self, sig=1, scaled=False): if not hasattr(sig, "__iter__"): sig = [sig] * len(pars) for par, x in zip(pars, sig): - self.add_restraint( + self.add_penalty( par, par.bounds[0], par.bounds[1], sig=x, scaled=scaled ) return diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index b3a92bfe..c9e72e11 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -142,7 +142,7 @@ restrain_deprecation_msg = build_deprecation_message( recipeorganizer_base, "restrain", - "add_restraint", + "add_penalty", removal_version, ) @@ -1154,7 +1154,7 @@ def clearConstraints(self, recurse=False): """ return self.clear_all_constraints(recurse=recurse) - def add_restraint( + def add_penalty( self, param_or_eq, lb=-inf, ub=inf, sig=1, scaled=False, params={} ): """Restrain an expression to specified bounds. @@ -1224,10 +1224,10 @@ def restrain( version 4.0.0. Please use - diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.add_restraint + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.add_penalty instead. """ - return self.add_restraint( + return self.add_penalty( param_or_eq, lb=lb, ub=ub, sig=sig, scaled=scaled, params=params ) @@ -1262,7 +1262,7 @@ def remove_restraint(self, *ress): Attributes ---------- *ress : Restraint - The Restraints returned from the 'add_restraint' method or added + The Restraints returned from the 'add_penalty' method or added with the 'register_restraint' method. """ update = False diff --git a/tests/conftest.py b/tests/conftest.py index 8dc38c9a..8fb14445 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -218,8 +218,8 @@ def build_recipe_two_contributions(): recipe.add_constraint(contribution2.m, "2*k") recipe.add_constraint(contribution2.d, contribution1.c) recipe.add_constraint(contribution2.B, "0.5*A") - recipe.add_restraint(contribution1.A, 0.5, 1.5) - recipe.add_restraint(contribution1.k, 0.8, 1.2) + recipe.add_penalty(contribution1.A, 0.5, 1.5) + recipe.add_penalty(contribution1.k, 0.8, 1.2) return recipe diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 885a34a7..0982f630 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -232,7 +232,7 @@ def testResidual(self): # 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 - r1 = self.recipe.add_restraint(self.fitcontribution.c, 0, 0, 1) + r1 = self.recipe.add_penalty(self.fitcontribution.c, 0, 0, 1) self.recipe._ready = False res = self.recipe.residual() chi2 = 4 + dot(y - self.profile.y, y - self.profile.y) @@ -263,9 +263,7 @@ def testResidual(self): self.assertTrue(array_equal(y - self.profile.y, res)) # Add a restraint at the fitcontribution level. - r1 = self.fitcontribution.add_restraint( - self.fitcontribution.c, 0, 0, 1 - ) + r1 = self.fitcontribution.add_penalty(self.fitcontribution.c, 0, 0, 1) self.recipe._ready = False # The chi2 is the same as above, plus 4 res = self.recipe.residual() @@ -363,7 +361,7 @@ def testPrintFitHook(capturestdout): recipe.addContribution(fitcontribution) recipe.add_variable(fitcontribution.c) - recipe.add_restraint("c", lb=5) + recipe.add_penalty("c", lb=5) (pfh,) = recipe.getFitHooks() out = capturestdout(recipe.scalar_residual) assert "" == out @@ -439,7 +437,7 @@ def test_add_contribution(capturestdout): recipe.add_contribution(fitcontribution) recipe.add_variable(fitcontribution.c) - recipe.add_restraint("c", lb=5) + recipe.add_penalty("c", lb=5) (pfh,) = recipe.get_fit_hooks() out = capturestdout(recipe.scalar_residual) assert "" == out diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index 66cff9b4..12fbc3c6 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -345,7 +345,7 @@ def test_add_restraint(self): self.m._eqfactory.registerArgument("p2", p2) self.assertEqual(0, len(self.m._restraints)) - r = self.m.add_restraint("p1+p2", ub=10) + r = self.m.add_penalty("p1+p2", ub=10) self.assertEqual(1, len(self.m._restraints)) p2.set_value(10) self.assertEqual(1, r.penalty()) @@ -409,8 +409,8 @@ def testGetRestraints(self): m2._add_parameter(p3) m2._add_parameter(p4) - r1 = self.m.add_restraint("p1 + p2") - r2 = m2.add_restraint("2*p3 + p4") + r1 = self.m.add_penalty("p1 + p2") + r2 = m2.add_penalty("2*p3 + p4") res = self.m._get_restraints() self.assertTrue(r1 in res) @@ -639,7 +639,7 @@ def capture_show(*args, **kwargs): assert "Parameters" in lines2 assert "Constraints" in lines2 assert "Restraints" not in lines2 - organizer.add_restraint("z", lb=2, ub=3, sig=0.001) + organizer.add_penalty("z", lb=2, ub=3, sig=0.001) out3 = capture_show() lines3 = out3.strip().split("\n") assert 13 == len(lines3) From f04475cf7e969c6fa1eac1b7743b0a1334956d98 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 12 Mar 2026 10:20:18 -0400 Subject: [PATCH 154/193] remove_restraint --> remove_penalty --- news/recipeorg-dep2.rst | 4 ++-- src/diffpy/srfit/fitbase/recipeorganizer.py | 10 +++++----- tests/test_fitrecipe.py | 4 ++-- tests/test_recipeorganizer.py | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/news/recipeorg-dep2.rst b/news/recipeorg-dep2.rst index 2c707f1d..3d8f9535 100644 --- a/news/recipeorg-dep2.rst +++ b/news/recipeorg-dep2.rst @@ -3,7 +3,7 @@ * Added ``add_constraint`` method to ``RecipeOrganizer``. * Added ``remove_constraint`` method to ``RecipeOrganizer``. * Added ``add_penalty`` method to ``RecipeOrganizer``. -* Added ``remove_restraint`` method to ``RecipeOrganizer``. +* Added ``remove_penalty`` method to ``RecipeOrganizer``. * Added ``register_restraint`` method to ``RecipeOrganizer``. * Added ``clear_all_restraints`` method to ``RecipeOrganizer``. * Added ``get_equation_from_string`` method to ``RecipeOrganizer``. @@ -17,7 +17,7 @@ * Deprecated ``constrain`` method of ``RecipeOrganizer``. Use ``add_constraint`` instead. * Deprecated ``unconstrain`` method of ``RecipeOrganizer``. Use ``remove_constraint`` instead. * Deprecated ``restrain`` method of ``RecipeOrganizer``. Use ``add_penalty`` instead. -* Deprecated ``unrestrain`` methods of ``RecipeOrganizer``. Use ``remove_restraint`` instead. +* Deprecated ``unrestrain`` methods of ``RecipeOrganizer``. Use ``remove_penalty`` instead. * Deprecated ``addRestraint`` method of ``RecipeOrganizer``. Use ``register_restraint`` instead. * Deprecate ``clearRestraints`` method of ``RecipeOrganizer``. Use ``clear_all_restraints`` instead. * Deprecated ``equationFromString`` method of ``RecipeOrganizer``. Use ``get_equation_from_string`` instead. diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index c9e72e11..16d2a256 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -149,7 +149,7 @@ unrestrain_deprecation_msg = build_deprecation_message( recipeorganizer_base, "unrestrain", - "remove_restraint", + "remove_penalty", removal_version, ) @@ -1256,7 +1256,7 @@ def addRestraint(self, res): self.register_restraint(res) return - def remove_restraint(self, *ress): + def remove_penalty(self, *ress): """Remove a Restraint from the RecipeOrganizer. Attributes @@ -1284,10 +1284,10 @@ def unrestrain(self, *ress): version 4.0.0. Please use - diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.remove_restraint + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.remove_penalty instead. """ - self.remove_restraint(*ress) + self.remove_penalty(*ress) return def clear_all_restraints(self, recurse=False): @@ -1299,7 +1299,7 @@ def clear_all_restraints(self, recurse=False): Recurse into managed objects and clear all restraints found there as well. """ - self.remove_restraint(*self._restraints) + self.remove_penalty(*self._restraints) if recurse: for msg in filter(_has_clear_restraints, self._iter_managed()): msg.clear_all_restraints(recurse) diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 0982f630..515f4fd2 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -247,7 +247,7 @@ def testResidual(self): self.assertAlmostEqual(chi2, dot(res, res)) # Remove the restraint and variable - self.recipe.remove_restraint(r1) + self.recipe.remove_penalty(r1) self.recipe.delete_variable(self.recipe.Avar) self.recipe._ready = False res = self.recipe.residual() @@ -273,7 +273,7 @@ def testResidual(self): self.assertAlmostEqual(chi2, dot(res, res)) # Remove those - self.fitcontribution.remove_restraint(r1) + self.fitcontribution.remove_penalty(r1) self.recipe._ready = False self.fitcontribution.unconstrain(self.fitcontribution.c) self.fitcontribution.c.set_value(0) diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index 12fbc3c6..186f7092 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -349,7 +349,7 @@ def test_add_restraint(self): self.assertEqual(1, len(self.m._restraints)) p2.set_value(10) self.assertEqual(1, r.penalty()) - self.m.remove_restraint(r) + self.m.remove_penalty(r) self.assertEqual(0, len(self.m._restraints)) r = self.m.restrain(p1, ub=10) From a197c76bca3cd6b762e97714774767391b72ae55 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 12 Mar 2026 10:22:19 -0400 Subject: [PATCH 155/193] register_restraint --> register_penalty --- news/recipeorg-dep2.rst | 4 ++-- src/diffpy/srfit/fitbase/recipeorganizer.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/news/recipeorg-dep2.rst b/news/recipeorg-dep2.rst index 3d8f9535..03e2feaf 100644 --- a/news/recipeorg-dep2.rst +++ b/news/recipeorg-dep2.rst @@ -4,7 +4,7 @@ * Added ``remove_constraint`` method to ``RecipeOrganizer``. * Added ``add_penalty`` method to ``RecipeOrganizer``. * Added ``remove_penalty`` method to ``RecipeOrganizer``. -* Added ``register_restraint`` method to ``RecipeOrganizer``. +* Added ``register_penalty`` method to ``RecipeOrganizer``. * Added ``clear_all_restraints`` method to ``RecipeOrganizer``. * Added ``get_equation_from_string`` method to ``RecipeOrganizer``. @@ -18,7 +18,7 @@ * Deprecated ``unconstrain`` method of ``RecipeOrganizer``. Use ``remove_constraint`` instead. * Deprecated ``restrain`` method of ``RecipeOrganizer``. Use ``add_penalty`` instead. * Deprecated ``unrestrain`` methods of ``RecipeOrganizer``. Use ``remove_penalty`` instead. -* Deprecated ``addRestraint`` method of ``RecipeOrganizer``. Use ``register_restraint`` instead. +* Deprecated ``addRestraint`` method of ``RecipeOrganizer``. Use ``register_penalty`` instead. * Deprecate ``clearRestraints`` method of ``RecipeOrganizer``. Use ``clear_all_restraints`` instead. * Deprecated ``equationFromString`` method of ``RecipeOrganizer``. Use ``get_equation_from_string`` instead. diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 16d2a256..239fffab 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -121,7 +121,7 @@ addRestraint_deprecation_msg = build_deprecation_message( recipeorganizer_base, "addRestraint", - "register_restraint", + "register_penalty", removal_version, ) @@ -1213,7 +1213,7 @@ def add_penalty( # Make and store the restraint param_or_eq = Restraint(eq, lb, ub, sig, scaled) param_or_eq.eqstr = eqstr - self.register_restraint(param_or_eq) + self.register_penalty(param_or_eq) return param_or_eq @deprecated(restrain_deprecation_msg) @@ -1231,7 +1231,7 @@ def restrain( param_or_eq, lb=lb, ub=ub, sig=sig, scaled=scaled, params=params ) - def register_restraint(self, res): + def register_penalty(self, res): """Add a Restraint instance to the RecipeOrganizer. Parameters @@ -1250,10 +1250,10 @@ def addRestraint(self, res): version 4.0.0. Please use - diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.register_restraint + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.register_penalty instead. """ - self.register_restraint(res) + self.register_penalty(res) return def remove_penalty(self, *ress): @@ -1263,7 +1263,7 @@ def remove_penalty(self, *ress): ---------- *ress : Restraint The Restraints returned from the 'add_penalty' method or added - with the 'register_restraint' method. + with the 'register_penalty' method. """ update = False restuple = tuple(self._restraints) From d77c6ac69e48738fca82aacbd79c72a8e354a450 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 12 Mar 2026 10:23:04 -0400 Subject: [PATCH 156/193] clear_all_restraints --> clear_all_penalties --- news/recipeorg-dep2.rst | 4 ++-- src/diffpy/srfit/fitbase/recipeorganizer.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/news/recipeorg-dep2.rst b/news/recipeorg-dep2.rst index 03e2feaf..0b75f313 100644 --- a/news/recipeorg-dep2.rst +++ b/news/recipeorg-dep2.rst @@ -5,7 +5,7 @@ * Added ``add_penalty`` method to ``RecipeOrganizer``. * Added ``remove_penalty`` method to ``RecipeOrganizer``. * Added ``register_penalty`` method to ``RecipeOrganizer``. -* Added ``clear_all_restraints`` method to ``RecipeOrganizer``. +* Added ``clear_all_penalties`` method to ``RecipeOrganizer``. * Added ``get_equation_from_string`` method to ``RecipeOrganizer``. **Changed:** @@ -19,7 +19,7 @@ * Deprecated ``restrain`` method of ``RecipeOrganizer``. Use ``add_penalty`` instead. * Deprecated ``unrestrain`` methods of ``RecipeOrganizer``. Use ``remove_penalty`` instead. * Deprecated ``addRestraint`` method of ``RecipeOrganizer``. Use ``register_penalty`` instead. -* Deprecate ``clearRestraints`` method of ``RecipeOrganizer``. Use ``clear_all_restraints`` instead. +* Deprecate ``clearRestraints`` method of ``RecipeOrganizer``. Use ``clear_all_penalties`` instead. * Deprecated ``equationFromString`` method of ``RecipeOrganizer``. Use ``get_equation_from_string`` instead. **Removed:** diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 239fffab..bed024b7 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -156,7 +156,7 @@ clearRestraints_deprecation_msg = build_deprecation_message( recipeorganizer_base, "clearRestraints", - "clear_all_restraints", + "clear_all_penalties", removal_version, ) @@ -1290,7 +1290,7 @@ def unrestrain(self, *ress): self.remove_penalty(*ress) return - def clear_all_restraints(self, recurse=False): + def clear_all_penalties(self, recurse=False): """Clear all restraints. Attributes @@ -1302,7 +1302,7 @@ def clear_all_restraints(self, recurse=False): self.remove_penalty(*self._restraints) if recurse: for msg in filter(_has_clear_restraints, self._iter_managed()): - msg.clear_all_restraints(recurse) + msg.clear_all_penalties(recurse) return @deprecated(clearRestraints_deprecation_msg) @@ -1311,10 +1311,10 @@ def clearRestraints(self, recurse=False): version 4.0.0. Please use - diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.clear_all_restraints + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.clear_all_penalties instead. """ - self.clear_all_restraints(recurse=recurse) + self.clear_all_penalties(recurse=recurse) return def _get_constraints(self, recurse=True): @@ -1586,7 +1586,7 @@ def _has_clear_constraints(msg): def _has_clear_restraints(msg): - return hasattr(msg, "clear_all_restraints") + return hasattr(msg, "clear_all_penalties") def _has_get_restraints(msg): From 0b9e9f78aad6617f0dd42f26866222f6fc0201fd Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 13 Mar 2026 11:34:01 -0400 Subject: [PATCH 157/193] change lb to lower_bound everywhere --- docs/examples/crystalpdftwophase.py | 12 ++++---- docs/examples/debyemodel.py | 2 +- docs/examples/simplepdftwophase.py | 12 ++++---- src/diffpy/srfit/fitbase/parameter.py | 18 +++++------ src/diffpy/srfit/fitbase/recipeorganizer.py | 33 ++++++++++++++++----- src/diffpy/srfit/fitbase/restraint.py | 22 +++++++------- tests/test_fitrecipe.py | 8 ++--- tests/test_recipeorganizer.py | 2 +- 8 files changed, 64 insertions(+), 45 deletions(-) diff --git a/docs/examples/crystalpdftwophase.py b/docs/examples/crystalpdftwophase.py index c7354211..dc5aaadb 100644 --- a/docs/examples/crystalpdftwophase.py +++ b/docs/examples/crystalpdftwophase.py @@ -123,18 +123,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.add_penalty("a_ni", lb=3.527, ub=3.527, scaled=True) + recipe.add_penalty("a_ni", lower_bound=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.add_penalty("delta2_ni", lb=2.22, ub=2.22, scaled=True) - recipe.add_penalty("Biso_0_ni", lb=0.454, ub=0.454, scaled=True) + recipe.add_penalty("delta2_ni", lower_bound=2.22, ub=2.22, scaled=True) + recipe.add_penalty("Biso_0_ni", lower_bound=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.add_penalty("a_si", lb=5.430, ub=5.430, scaled=True) - recipe.add_penalty("delta2_si", lb=3.54, ub=3.54, scaled=True) - recipe.add_penalty("Biso_0_si", lb=0.645, ub=0.645, scaled=True) + recipe.add_penalty("a_si", lower_bound=5.430, ub=5.430, scaled=True) + recipe.add_penalty("delta2_si", lower_bound=3.54, ub=3.54, scaled=True) + recipe.add_penalty("Biso_0_si", lower_bound=0.645, ub=0.645, scaled=True) # Give the recipe away so it can be used! return recipe diff --git a/docs/examples/debyemodel.py b/docs/examples/debyemodel.py index a373f307..5173c376 100644 --- a/docs/examples/debyemodel.py +++ b/docs/examples/debyemodel.py @@ -152,7 +152,7 @@ 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.add_penalty(recipe.offset, lb=0, scaled=True) + recipe.add_penalty(recipe.offset, lower_bound=0, scaled=True) # We're done setting up the recipe. We can now do other things with it. return recipe diff --git a/docs/examples/simplepdftwophase.py b/docs/examples/simplepdftwophase.py index ec496542..0c86ada5 100644 --- a/docs/examples/simplepdftwophase.py +++ b/docs/examples/simplepdftwophase.py @@ -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.add_penalty("a_ni", lb=3.527, ub=3.527, scaled=True) + recipe.add_penalty("a_ni", lower_bound=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.add_penalty("delta2_ni", lb=2.22, ub=2.22, scaled=True) - recipe.add_penalty("Biso_0_ni", lb=0.454, ub=0.454, scaled=True) + recipe.add_penalty("delta2_ni", lower_bound=2.22, ub=2.22, scaled=True) + recipe.add_penalty("Biso_0_ni", lower_bound=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.add_penalty("a_si", lb=5.430, ub=5.430, scaled=True) - recipe.add_penalty("delta2_si", lb=3.54, ub=3.54, scaled=True) - recipe.add_penalty("Biso_0_si", lb=0.645, ub=0.645, scaled=True) + recipe.add_penalty("a_si", lower_bound=5.430, ub=5.430, scaled=True) + recipe.add_penalty("delta2_si", lower_bound=3.54, ub=3.54, scaled=True) + recipe.add_penalty("Biso_0_si", lower_bound=0.645, ub=0.645, scaled=True) # Give the recipe away so it can be used! return recipe diff --git a/src/diffpy/srfit/fitbase/parameter.py b/src/diffpy/srfit/fitbase/parameter.py index 1c7450d7..1f323d62 100644 --- a/src/diffpy/srfit/fitbase/parameter.py +++ b/src/diffpy/srfit/fitbase/parameter.py @@ -95,7 +95,7 @@ def set_value(self, val): ---------- val The value to assign. - lb + lower_bound : float The lower bounds for the bounds list. If this is None (default), then the lower bound will not be alterered. ub @@ -142,12 +142,12 @@ def setConst(self, const=True, value=None): self.set_value(value) return self - def boundRange(self, lb=None, ub=None): + def boundRange(self, lower_bound=None, ub=None): """Set lower and upper bound of the Parameter. Attributes ---------- - lb + lower_bound : float The lower bound for the bounds list. ub The upper bound for the bounds list. @@ -157,8 +157,8 @@ def boundRange(self, lb=None, ub=None): self Returns self so that mutators can be chained. """ - if lb is not None: - self.bounds[0] = lb + if lower_bound is not None: + self.bounds[0] = lower_bound if ub is not None: self.bounds[1] = ub return self @@ -182,11 +182,11 @@ def boundWindow(self, lr=0, ur=None): Returns self so that mutators can be chained. """ val = self.getValue() - lb = val - lr + lower_bound = val - lr if ur is None: ur = lr ub = val + ur - self.bounds = [lb, ub] + self.bounds = [lower_bound, ub] return self def _validate(self): @@ -283,8 +283,8 @@ 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) + def boundRange(self, lower_bound=None, ub=None): + return self.par.boundRange(lower_bound, ub) @wraps(Parameter.boundWindow) def boundWindow(self, lr=0, ur=None): diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index bed024b7..3a3edb86 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -1155,7 +1155,13 @@ def clearConstraints(self, recurse=False): return self.clear_all_constraints(recurse=recurse) def add_penalty( - self, param_or_eq, lb=-inf, ub=inf, sig=1, scaled=False, params={} + self, + param_or_eq, + lower_bound=-inf, + ub=inf, + sig=1, + scaled=False, + params={}, ): """Restrain an expression to specified bounds. @@ -1163,7 +1169,7 @@ def add_penalty( ---------- param_or_eq : str or Parameter The equation string or a Parameter object to restrain. - lb : float, optional + lower_bound : float, optional The lower bound for the restraint evaluation (default is -inf). ub : float, optional The upper bound for the restraint evaluation (default is inf). @@ -1188,7 +1194,7 @@ def add_penalty( The penalty is calculated as: .. - (max(0, lb - val, val - ub) / sig) ** 2 + (max(0, lower_bound - val, val - ub) / sig) ** 2 where `val` is the value of the evaluated equation. If `scaled` is True, this penalty is multiplied by @@ -1211,14 +1217,20 @@ def add_penalty( eqstr = param_or_eq.name # Make and store the restraint - param_or_eq = Restraint(eq, lb, ub, sig, scaled) + param_or_eq = Restraint(eq, lower_bound, ub, sig, scaled) param_or_eq.eqstr = eqstr self.register_penalty(param_or_eq) return param_or_eq @deprecated(restrain_deprecation_msg) def restrain( - self, param_or_eq, lb=-inf, ub=inf, sig=1, scaled=False, params={} + self, + param_or_eq, + lower_bound=-inf, + ub=inf, + sig=1, + scaled=False, + params={}, ): """This function has been deprecated and will be removed in version 4.0.0. @@ -1228,7 +1240,12 @@ def restrain( instead. """ return self.add_penalty( - param_or_eq, lb=lb, ub=ub, sig=sig, scaled=scaled, params=params + param_or_eq, + lower_bound=lower_bound, + ub=ub, + sig=sig, + scaled=scaled, + params=params, ) def register_penalty(self, res): @@ -1429,9 +1446,9 @@ def _format_restraints(self): rset = self._get_restraints() rlines = [] for res in rset: - line = "%s: lb = %f, ub = %f, sig = %f, scaled = %s" % ( + line = "%s: lower_bound = %f, ub = %f, sig = %f, scaled = %s" % ( res.eqstr, - res.lb, + res.lower_bound, res.ub, res.sig, res.scaled, diff --git a/src/diffpy/srfit/fitbase/restraint.py b/src/diffpy/srfit/fitbase/restraint.py index 5630d808..4b0210fc 100644 --- a/src/diffpy/srfit/fitbase/restraint.py +++ b/src/diffpy/srfit/fitbase/restraint.py @@ -33,28 +33,28 @@ class Restraint(Validatable): Attributes ---------- - eq + eq : Equation An equation whose evaluation is compared against the restraint bounds. - lb + lower_bound : float The lower bound on the restraint evaluation (default -inf). - ub + ub : float The lower bound on the restraint evaluation (default inf). - sig + sig : float The uncertainty on the bounds (default 1). - scaled + scaled : bool A flag indicating if the restraint is scaled (multiplied) by the unrestrained point-average chi^2 (chi^2/numpoints) (default False). The penalty is calculated as - (max(0, lb - val, val - ub)/sig)**2 + (max(0, lower_bound - val, val - ub)/sig)**2 and val is the value of the calculated equation. This is multiplied by the average chi^2 if scaled is True. """ - def __init__(self, eq, lb=-inf, ub=inf, sig=1, scaled=False): + def __init__(self, eq, lower_bound=-inf, ub=inf, sig=1, scaled=False): """Restrain an equation to specified bounds. Attributes @@ -62,7 +62,7 @@ def __init__(self, eq, lb=-inf, ub=inf, sig=1, scaled=False): eq An equation whose evaluation is compared against the restraint bounds. - lb + lower_bound The lower bound on the restraint evaluation (float, default -inf). ub @@ -76,7 +76,7 @@ def __init__(self, eq, lb=-inf, ub=inf, sig=1, scaled=False): (bool, default False). """ self.eq = eq - self.lb = float(lb) + self.lower_bound = float(lower_bound) self.ub = float(ub) self.sig = float(sig) self.scaled = bool(scaled) @@ -97,7 +97,9 @@ def penalty(self, w=1.0): Returns the penalty as a float """ val = self.eq() - penalty = (max(0, self.lb - val, val - self.ub) / self.sig) ** 2 + penalty = ( + max(0, self.lower_bound - val, val - self.ub) / self.sig + ) ** 2 if self.scaled: penalty *= w diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 515f4fd2..85842a8c 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -314,7 +314,7 @@ def test_boundsToRestraints(): restraints = list(recipe._restraints) assert len(restraints) == 1 r = restraints[0] - actual_lower_bound = r.lb + actual_lower_bound = r.lower_bound actual_upper_bound = r.ub actual_sigma = r.sig assert actual_lower_bound == expected_lower_bound @@ -333,7 +333,7 @@ def test_convert_bounds_to_restraints(): restraints = list(recipe._restraints) assert len(restraints) == 1 r = restraints[0] - assert r.lb == -1 + assert r.lower_bound == -1 assert r.ub == 1 assert r.sig == 2 assert r.scaled is True @@ -361,7 +361,7 @@ def testPrintFitHook(capturestdout): recipe.addContribution(fitcontribution) recipe.add_variable(fitcontribution.c) - recipe.add_penalty("c", lb=5) + recipe.add_penalty("c", lower_bound=5) (pfh,) = recipe.getFitHooks() out = capturestdout(recipe.scalar_residual) assert "" == out @@ -437,7 +437,7 @@ def test_add_contribution(capturestdout): recipe.add_contribution(fitcontribution) recipe.add_variable(fitcontribution.c) - recipe.add_penalty("c", lb=5) + recipe.add_penalty("c", lower_bound=5) (pfh,) = recipe.get_fit_hooks() out = capturestdout(recipe.scalar_residual) assert "" == out diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index 186f7092..a1d9b69a 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -639,7 +639,7 @@ def capture_show(*args, **kwargs): assert "Parameters" in lines2 assert "Constraints" in lines2 assert "Restraints" not in lines2 - organizer.add_penalty("z", lb=2, ub=3, sig=0.001) + organizer.add_penalty("z", lower_bound=2, ub=3, sig=0.001) out3 = capture_show() lines3 = out3.strip().split("\n") assert 13 == len(lines3) From 273e63a16e999231e02e55bcba98a200ef8e8b6d Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 13 Mar 2026 11:36:05 -0400 Subject: [PATCH 158/193] change ub to upper_bound everywhere --- docs/examples/crystalpdftwophase.py | 24 +++++++++++++----- docs/examples/simplepdftwophase.py | 24 +++++++++++++----- src/diffpy/srfit/fitbase/parameter.py | 18 +++++++------- src/diffpy/srfit/fitbase/recipeorganizer.py | 27 ++++++++++++--------- src/diffpy/srfit/fitbase/restraint.py | 14 ++++++----- tests/test_fitrecipe.py | 4 +-- tests/test_recipeorganizer.py | 6 ++--- tests/test_restraint.py | 2 +- 8 files changed, 74 insertions(+), 45 deletions(-) diff --git a/docs/examples/crystalpdftwophase.py b/docs/examples/crystalpdftwophase.py index dc5aaadb..a39b1b2f 100644 --- a/docs/examples/crystalpdftwophase.py +++ b/docs/examples/crystalpdftwophase.py @@ -123,18 +123,30 @@ 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.add_penalty("a_ni", lower_bound=3.527, ub=3.527, scaled=True) + recipe.add_penalty( + "a_ni", lower_bound=3.527, upper_bound=3.527, scaled=True + ) # Now we do the same with the delta2 and Biso parameters (remember that # Biso = 8*pi**2*Uiso) - recipe.add_penalty("delta2_ni", lower_bound=2.22, ub=2.22, scaled=True) - recipe.add_penalty("Biso_0_ni", lower_bound=0.454, ub=0.454, scaled=True) + recipe.add_penalty( + "delta2_ni", lower_bound=2.22, upper_bound=2.22, scaled=True + ) + recipe.add_penalty( + "Biso_0_ni", lower_bound=0.454, upper_bound=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.add_penalty("a_si", lower_bound=5.430, ub=5.430, scaled=True) - recipe.add_penalty("delta2_si", lower_bound=3.54, ub=3.54, scaled=True) - recipe.add_penalty("Biso_0_si", lower_bound=0.645, ub=0.645, scaled=True) + recipe.add_penalty( + "a_si", lower_bound=5.430, upper_bound=5.430, scaled=True + ) + recipe.add_penalty( + "delta2_si", lower_bound=3.54, upper_bound=3.54, scaled=True + ) + recipe.add_penalty( + "Biso_0_si", lower_bound=0.645, upper_bound=0.645, scaled=True + ) # Give the recipe away so it can be used! return recipe diff --git a/docs/examples/simplepdftwophase.py b/docs/examples/simplepdftwophase.py index 0c86ada5..8a48cd60 100644 --- a/docs/examples/simplepdftwophase.py +++ b/docs/examples/simplepdftwophase.py @@ -82,18 +82,30 @@ 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.add_penalty("a_ni", lower_bound=3.527, ub=3.527, scaled=True) + recipe.add_penalty( + "a_ni", lower_bound=3.527, upper_bound=3.527, scaled=True + ) # Now we do the same with the delta2 and Biso parameters (remember that # Biso = 8*pi**2*Uiso) - recipe.add_penalty("delta2_ni", lower_bound=2.22, ub=2.22, scaled=True) - recipe.add_penalty("Biso_0_ni", lower_bound=0.454, ub=0.454, scaled=True) + recipe.add_penalty( + "delta2_ni", lower_bound=2.22, upper_bound=2.22, scaled=True + ) + recipe.add_penalty( + "Biso_0_ni", lower_bound=0.454, upper_bound=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.add_penalty("a_si", lower_bound=5.430, ub=5.430, scaled=True) - recipe.add_penalty("delta2_si", lower_bound=3.54, ub=3.54, scaled=True) - recipe.add_penalty("Biso_0_si", lower_bound=0.645, ub=0.645, scaled=True) + recipe.add_penalty( + "a_si", lower_bound=5.430, upper_bound=5.430, scaled=True + ) + recipe.add_penalty( + "delta2_si", lower_bound=3.54, upper_bound=3.54, scaled=True + ) + recipe.add_penalty( + "Biso_0_si", lower_bound=0.645, upper_bound=0.645, scaled=True + ) # Give the recipe away so it can be used! return recipe diff --git a/src/diffpy/srfit/fitbase/parameter.py b/src/diffpy/srfit/fitbase/parameter.py index 1f323d62..6bddf43b 100644 --- a/src/diffpy/srfit/fitbase/parameter.py +++ b/src/diffpy/srfit/fitbase/parameter.py @@ -98,7 +98,7 @@ def set_value(self, val): lower_bound : float The lower bounds for the bounds list. If this is None (default), then the lower bound will not be alterered. - ub + upper_bound : float The upper bounds for the bounds list. If this is None (default), then the upper bound will not be alterered. @@ -142,14 +142,14 @@ def setConst(self, const=True, value=None): self.set_value(value) return self - def boundRange(self, lower_bound=None, ub=None): + def boundRange(self, lower_bound=None, upper_bound=None): """Set lower and upper bound of the Parameter. Attributes ---------- lower_bound : float The lower bound for the bounds list. - ub + upper_bound : float The upper bound for the bounds list. Returns @@ -159,8 +159,8 @@ def boundRange(self, lower_bound=None, ub=None): """ if lower_bound is not None: self.bounds[0] = lower_bound - if ub is not None: - self.bounds[1] = ub + if upper_bound is not None: + self.bounds[1] = upper_bound return self def boundWindow(self, lr=0, ur=None): @@ -185,8 +185,8 @@ def boundWindow(self, lr=0, ur=None): lower_bound = val - lr if ur is None: ur = lr - ub = val + ur - self.bounds = [lower_bound, ub] + upper_bound = val + ur + self.bounds = [lower_bound, upper_bound] return self def _validate(self): @@ -283,8 +283,8 @@ def setConst(self, const=True, value=None): return self.par.setConst(const, value) @wraps(Parameter.boundRange) - def boundRange(self, lower_bound=None, ub=None): - return self.par.boundRange(lower_bound, ub) + def boundRange(self, lower_bound=None, upper_bound=None): + return self.par.boundRange(lower_bound, upper_bound) @wraps(Parameter.boundWindow) def boundWindow(self, lr=0, ur=None): diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 3a3edb86..9c0cd3f7 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -1158,7 +1158,7 @@ def add_penalty( self, param_or_eq, lower_bound=-inf, - ub=inf, + upper_bound=inf, sig=1, scaled=False, params={}, @@ -1171,7 +1171,7 @@ def add_penalty( The equation string or a Parameter object to restrain. lower_bound : float, optional The lower bound for the restraint evaluation (default is -inf). - ub : float, optional + upper_bound : float, optional The upper bound for the restraint evaluation (default is inf). sig : float, optional The uncertainty associated with the bounds (default is 1). @@ -1194,7 +1194,7 @@ def add_penalty( The penalty is calculated as: .. - (max(0, lower_bound - val, val - ub) / sig) ** 2 + (max(0, lower_bound - val, val - upper_bound) / sig) ** 2 where `val` is the value of the evaluated equation. If `scaled` is True, this penalty is multiplied by @@ -1217,7 +1217,7 @@ def add_penalty( eqstr = param_or_eq.name # Make and store the restraint - param_or_eq = Restraint(eq, lower_bound, ub, sig, scaled) + param_or_eq = Restraint(eq, lower_bound, upper_bound, sig, scaled) param_or_eq.eqstr = eqstr self.register_penalty(param_or_eq) return param_or_eq @@ -1227,7 +1227,7 @@ def restrain( self, param_or_eq, lower_bound=-inf, - ub=inf, + upper_bound=inf, sig=1, scaled=False, params={}, @@ -1242,7 +1242,7 @@ def restrain( return self.add_penalty( param_or_eq, lower_bound=lower_bound, - ub=ub, + upper_bound=upper_bound, sig=sig, scaled=scaled, params=params, @@ -1446,12 +1446,15 @@ def _format_restraints(self): rset = self._get_restraints() rlines = [] for res in rset: - line = "%s: lower_bound = %f, ub = %f, sig = %f, scaled = %s" % ( - res.eqstr, - res.lower_bound, - res.ub, - res.sig, - res.scaled, + line = ( + "%s: lower_bound = %f, upper_bound = %f, sig = %f, scaled = %s" + % ( + res.eqstr, + res.lower_bound, + res.upper_bound, + res.sig, + res.scaled, + ) ) rlines.append(line) rlines.sort(key=numstr) diff --git a/src/diffpy/srfit/fitbase/restraint.py b/src/diffpy/srfit/fitbase/restraint.py index 4b0210fc..7b6ec747 100644 --- a/src/diffpy/srfit/fitbase/restraint.py +++ b/src/diffpy/srfit/fitbase/restraint.py @@ -38,7 +38,7 @@ class Restraint(Validatable): bounds. lower_bound : float The lower bound on the restraint evaluation (default -inf). - ub : float + upper_bound : float The lower bound on the restraint evaluation (default inf). sig : float The uncertainty on the bounds (default 1). @@ -49,12 +49,14 @@ class Restraint(Validatable): The penalty is calculated as - (max(0, lower_bound - val, val - ub)/sig)**2 + (max(0, lower_bound - val, val - upper_bound)/sig)**2 and val is the value of the calculated equation. This is multiplied by the average chi^2 if scaled is True. """ - def __init__(self, eq, lower_bound=-inf, ub=inf, sig=1, scaled=False): + def __init__( + self, eq, lower_bound=-inf, upper_bound=inf, sig=1, scaled=False + ): """Restrain an equation to specified bounds. Attributes @@ -65,7 +67,7 @@ def __init__(self, eq, lower_bound=-inf, ub=inf, sig=1, scaled=False): lower_bound The lower bound on the restraint evaluation (float, default -inf). - ub + upper_bound The lower bound on the restraint evaluation (float, default inf). sig @@ -77,7 +79,7 @@ def __init__(self, eq, lower_bound=-inf, ub=inf, sig=1, scaled=False): """ self.eq = eq self.lower_bound = float(lower_bound) - self.ub = float(ub) + self.upper_bound = float(upper_bound) self.sig = float(sig) self.scaled = bool(scaled) return @@ -98,7 +100,7 @@ def penalty(self, w=1.0): """ val = self.eq() penalty = ( - max(0, self.lower_bound - val, val - self.ub) / self.sig + max(0, self.lower_bound - val, val - self.upper_bound) / self.sig ) ** 2 if self.scaled: diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 85842a8c..9e09568b 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -315,7 +315,7 @@ def test_boundsToRestraints(): assert len(restraints) == 1 r = restraints[0] actual_lower_bound = r.lower_bound - actual_upper_bound = r.ub + actual_upper_bound = r.upper_bound actual_sigma = r.sig assert actual_lower_bound == expected_lower_bound assert actual_upper_bound == expected_upper_bound @@ -334,7 +334,7 @@ def test_convert_bounds_to_restraints(): assert len(restraints) == 1 r = restraints[0] assert r.lower_bound == -1 - assert r.ub == 1 + assert r.upper_bound == 1 assert r.sig == 2 assert r.scaled is True diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index a1d9b69a..7d4e216f 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -345,14 +345,14 @@ def test_add_restraint(self): self.m._eqfactory.registerArgument("p2", p2) self.assertEqual(0, len(self.m._restraints)) - r = self.m.add_penalty("p1+p2", ub=10) + r = self.m.add_penalty("p1+p2", upper_bound=10) self.assertEqual(1, len(self.m._restraints)) p2.set_value(10) self.assertEqual(1, r.penalty()) self.m.remove_penalty(r) self.assertEqual(0, len(self.m._restraints)) - r = self.m.restrain(p1, ub=10) + r = self.m.restrain(p1, upper_bound=10) self.assertEqual(1, len(self.m._restraints)) p1.set_value(11) self.assertEqual(1, r.penalty()) @@ -639,7 +639,7 @@ def capture_show(*args, **kwargs): assert "Parameters" in lines2 assert "Constraints" in lines2 assert "Restraints" not in lines2 - organizer.add_penalty("z", lower_bound=2, ub=3, sig=0.001) + organizer.add_penalty("z", lower_bound=2, upper_bound=3, sig=0.001) out3 = capture_show() lines3 = out3.strip().split("\n") assert 13 == len(lines3) diff --git a/tests/test_restraint.py b/tests/test_restraint.py index 09819531..befae689 100644 --- a/tests/test_restraint.py +++ b/tests/test_restraint.py @@ -63,7 +63,7 @@ def testRestraint(self): # Make a really large number to check the upper bound import numpy - r.ub = numpy.inf + r.upper_bound = numpy.inf p1.set_value(1e100) self.assertEqual(0, r.penalty()) From 7032d6b54c2eb08fbe1aac0ed71cfe150c391af2 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 13 Mar 2026 11:39:36 -0400 Subject: [PATCH 159/193] add_penalty --> add_soft_bounds --- docs/examples/crystalpdftwophase.py | 12 ++++++------ docs/examples/debyemodel.py | 2 +- docs/examples/simplepdftwophase.py | 12 ++++++------ news/recipeorg-dep2.rst | 4 ++-- src/diffpy/srfit/fitbase/fitrecipe.py | 2 +- src/diffpy/srfit/fitbase/recipeorganizer.py | 10 +++++----- tests/conftest.py | 4 ++-- tests/test_fitrecipe.py | 10 ++++++---- tests/test_recipeorganizer.py | 8 ++++---- 9 files changed, 33 insertions(+), 31 deletions(-) diff --git a/docs/examples/crystalpdftwophase.py b/docs/examples/crystalpdftwophase.py index a39b1b2f..1d6878b2 100644 --- a/docs/examples/crystalpdftwophase.py +++ b/docs/examples/crystalpdftwophase.py @@ -123,28 +123,28 @@ 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.add_penalty( + recipe.add_soft_bounds( "a_ni", lower_bound=3.527, upper_bound=3.527, scaled=True ) # Now we do the same with the delta2 and Biso parameters (remember that # Biso = 8*pi**2*Uiso) - recipe.add_penalty( + recipe.add_soft_bounds( "delta2_ni", lower_bound=2.22, upper_bound=2.22, scaled=True ) - recipe.add_penalty( + recipe.add_soft_bounds( "Biso_0_ni", lower_bound=0.454, upper_bound=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.add_penalty( + recipe.add_soft_bounds( "a_si", lower_bound=5.430, upper_bound=5.430, scaled=True ) - recipe.add_penalty( + recipe.add_soft_bounds( "delta2_si", lower_bound=3.54, upper_bound=3.54, scaled=True ) - recipe.add_penalty( + recipe.add_soft_bounds( "Biso_0_si", lower_bound=0.645, upper_bound=0.645, scaled=True ) diff --git a/docs/examples/debyemodel.py b/docs/examples/debyemodel.py index 5173c376..7813be4e 100644 --- a/docs/examples/debyemodel.py +++ b/docs/examples/debyemodel.py @@ -152,7 +152,7 @@ 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.add_penalty(recipe.offset, lower_bound=0, scaled=True) + recipe.add_soft_bounds(recipe.offset, lower_bound=0, scaled=True) # We're done setting up the recipe. We can now do other things with it. return recipe diff --git a/docs/examples/simplepdftwophase.py b/docs/examples/simplepdftwophase.py index 8a48cd60..0b7ee046 100644 --- a/docs/examples/simplepdftwophase.py +++ b/docs/examples/simplepdftwophase.py @@ -82,28 +82,28 @@ 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.add_penalty( + recipe.add_soft_bounds( "a_ni", lower_bound=3.527, upper_bound=3.527, scaled=True ) # Now we do the same with the delta2 and Biso parameters (remember that # Biso = 8*pi**2*Uiso) - recipe.add_penalty( + recipe.add_soft_bounds( "delta2_ni", lower_bound=2.22, upper_bound=2.22, scaled=True ) - recipe.add_penalty( + recipe.add_soft_bounds( "Biso_0_ni", lower_bound=0.454, upper_bound=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.add_penalty( + recipe.add_soft_bounds( "a_si", lower_bound=5.430, upper_bound=5.430, scaled=True ) - recipe.add_penalty( + recipe.add_soft_bounds( "delta2_si", lower_bound=3.54, upper_bound=3.54, scaled=True ) - recipe.add_penalty( + recipe.add_soft_bounds( "Biso_0_si", lower_bound=0.645, upper_bound=0.645, scaled=True ) diff --git a/news/recipeorg-dep2.rst b/news/recipeorg-dep2.rst index 0b75f313..45e9f19d 100644 --- a/news/recipeorg-dep2.rst +++ b/news/recipeorg-dep2.rst @@ -2,7 +2,7 @@ * Added ``add_constraint`` method to ``RecipeOrganizer``. * Added ``remove_constraint`` method to ``RecipeOrganizer``. -* Added ``add_penalty`` method to ``RecipeOrganizer``. +* Added ``add_soft_bounds`` method to ``RecipeOrganizer``. * Added ``remove_penalty`` method to ``RecipeOrganizer``. * Added ``register_penalty`` method to ``RecipeOrganizer``. * Added ``clear_all_penalties`` method to ``RecipeOrganizer``. @@ -16,7 +16,7 @@ * Deprecated ``constrain`` method of ``RecipeOrganizer``. Use ``add_constraint`` instead. * Deprecated ``unconstrain`` method of ``RecipeOrganizer``. Use ``remove_constraint`` instead. -* Deprecated ``restrain`` method of ``RecipeOrganizer``. Use ``add_penalty`` instead. +* Deprecated ``restrain`` method of ``RecipeOrganizer``. Use ``add_soft_bounds`` instead. * Deprecated ``unrestrain`` methods of ``RecipeOrganizer``. Use ``remove_penalty`` instead. * Deprecated ``addRestraint`` method of ``RecipeOrganizer``. Use ``register_penalty`` instead. * Deprecate ``clearRestraints`` method of ``RecipeOrganizer``. Use ``clear_all_penalties`` instead. diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 7740a20e..0961b504 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -1756,7 +1756,7 @@ def convert_bounds_to_restraints(self, sig=1, scaled=False): if not hasattr(sig, "__iter__"): sig = [sig] * len(pars) for par, x in zip(pars, sig): - self.add_penalty( + self.add_soft_bounds( par, par.bounds[0], par.bounds[1], sig=x, scaled=scaled ) return diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 9c0cd3f7..ca664be4 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -142,7 +142,7 @@ restrain_deprecation_msg = build_deprecation_message( recipeorganizer_base, "restrain", - "add_penalty", + "add_soft_bounds", removal_version, ) @@ -1154,7 +1154,7 @@ def clearConstraints(self, recurse=False): """ return self.clear_all_constraints(recurse=recurse) - def add_penalty( + def add_soft_bounds( self, param_or_eq, lower_bound=-inf, @@ -1236,10 +1236,10 @@ def restrain( version 4.0.0. Please use - diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.add_penalty + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.add_soft_bounds instead. """ - return self.add_penalty( + return self.add_soft_bounds( param_or_eq, lower_bound=lower_bound, upper_bound=upper_bound, @@ -1279,7 +1279,7 @@ def remove_penalty(self, *ress): Attributes ---------- *ress : Restraint - The Restraints returned from the 'add_penalty' method or added + The Restraints returned from the 'add_soft_bounds' method or added with the 'register_penalty' method. """ update = False diff --git a/tests/conftest.py b/tests/conftest.py index 8fb14445..6eb797c3 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -218,8 +218,8 @@ def build_recipe_two_contributions(): recipe.add_constraint(contribution2.m, "2*k") recipe.add_constraint(contribution2.d, contribution1.c) recipe.add_constraint(contribution2.B, "0.5*A") - recipe.add_penalty(contribution1.A, 0.5, 1.5) - recipe.add_penalty(contribution1.k, 0.8, 1.2) + recipe.add_soft_bounds(contribution1.A, 0.5, 1.5) + recipe.add_soft_bounds(contribution1.k, 0.8, 1.2) return recipe diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 9e09568b..fe8f8352 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -232,7 +232,7 @@ def testResidual(self): # 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 - r1 = self.recipe.add_penalty(self.fitcontribution.c, 0, 0, 1) + r1 = self.recipe.add_soft_bounds(self.fitcontribution.c, 0, 0, 1) self.recipe._ready = False res = self.recipe.residual() chi2 = 4 + dot(y - self.profile.y, y - self.profile.y) @@ -263,7 +263,9 @@ def testResidual(self): self.assertTrue(array_equal(y - self.profile.y, res)) # Add a restraint at the fitcontribution level. - r1 = self.fitcontribution.add_penalty(self.fitcontribution.c, 0, 0, 1) + r1 = self.fitcontribution.add_soft_bounds( + self.fitcontribution.c, 0, 0, 1 + ) self.recipe._ready = False # The chi2 is the same as above, plus 4 res = self.recipe.residual() @@ -361,7 +363,7 @@ def testPrintFitHook(capturestdout): recipe.addContribution(fitcontribution) recipe.add_variable(fitcontribution.c) - recipe.add_penalty("c", lower_bound=5) + recipe.add_soft_bounds("c", lower_bound=5) (pfh,) = recipe.getFitHooks() out = capturestdout(recipe.scalar_residual) assert "" == out @@ -437,7 +439,7 @@ def test_add_contribution(capturestdout): recipe.add_contribution(fitcontribution) recipe.add_variable(fitcontribution.c) - recipe.add_penalty("c", lower_bound=5) + recipe.add_soft_bounds("c", lower_bound=5) (pfh,) = recipe.get_fit_hooks() out = capturestdout(recipe.scalar_residual) assert "" == out diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index 7d4e216f..d10441c2 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -345,7 +345,7 @@ def test_add_restraint(self): self.m._eqfactory.registerArgument("p2", p2) self.assertEqual(0, len(self.m._restraints)) - r = self.m.add_penalty("p1+p2", upper_bound=10) + r = self.m.add_soft_bounds("p1+p2", upper_bound=10) self.assertEqual(1, len(self.m._restraints)) p2.set_value(10) self.assertEqual(1, r.penalty()) @@ -409,8 +409,8 @@ def testGetRestraints(self): m2._add_parameter(p3) m2._add_parameter(p4) - r1 = self.m.add_penalty("p1 + p2") - r2 = m2.add_penalty("2*p3 + p4") + r1 = self.m.add_soft_bounds("p1 + p2") + r2 = m2.add_soft_bounds("2*p3 + p4") res = self.m._get_restraints() self.assertTrue(r1 in res) @@ -639,7 +639,7 @@ def capture_show(*args, **kwargs): assert "Parameters" in lines2 assert "Constraints" in lines2 assert "Restraints" not in lines2 - organizer.add_penalty("z", lower_bound=2, upper_bound=3, sig=0.001) + organizer.add_soft_bounds("z", lower_bound=2, upper_bound=3, sig=0.001) out3 = capture_show() lines3 = out3.strip().split("\n") assert 13 == len(lines3) From dab361fd3745d3386dca46971abdf21df359216c Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 13 Mar 2026 11:40:02 -0400 Subject: [PATCH 160/193] remove_penalty --> remove_soft_bounds --- news/recipeorg-dep2.rst | 4 ++-- src/diffpy/srfit/fitbase/recipeorganizer.py | 10 +++++----- tests/test_fitrecipe.py | 4 ++-- tests/test_recipeorganizer.py | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/news/recipeorg-dep2.rst b/news/recipeorg-dep2.rst index 45e9f19d..ee4da736 100644 --- a/news/recipeorg-dep2.rst +++ b/news/recipeorg-dep2.rst @@ -3,7 +3,7 @@ * Added ``add_constraint`` method to ``RecipeOrganizer``. * Added ``remove_constraint`` method to ``RecipeOrganizer``. * Added ``add_soft_bounds`` method to ``RecipeOrganizer``. -* Added ``remove_penalty`` method to ``RecipeOrganizer``. +* Added ``remove_soft_bounds`` method to ``RecipeOrganizer``. * Added ``register_penalty`` method to ``RecipeOrganizer``. * Added ``clear_all_penalties`` method to ``RecipeOrganizer``. * Added ``get_equation_from_string`` method to ``RecipeOrganizer``. @@ -17,7 +17,7 @@ * Deprecated ``constrain`` method of ``RecipeOrganizer``. Use ``add_constraint`` instead. * Deprecated ``unconstrain`` method of ``RecipeOrganizer``. Use ``remove_constraint`` instead. * Deprecated ``restrain`` method of ``RecipeOrganizer``. Use ``add_soft_bounds`` instead. -* Deprecated ``unrestrain`` methods of ``RecipeOrganizer``. Use ``remove_penalty`` instead. +* Deprecated ``unrestrain`` methods of ``RecipeOrganizer``. Use ``remove_soft_bounds`` instead. * Deprecated ``addRestraint`` method of ``RecipeOrganizer``. Use ``register_penalty`` instead. * Deprecate ``clearRestraints`` method of ``RecipeOrganizer``. Use ``clear_all_penalties`` instead. * Deprecated ``equationFromString`` method of ``RecipeOrganizer``. Use ``get_equation_from_string`` instead. diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index ca664be4..32ab497f 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -149,7 +149,7 @@ unrestrain_deprecation_msg = build_deprecation_message( recipeorganizer_base, "unrestrain", - "remove_penalty", + "remove_soft_bounds", removal_version, ) @@ -1273,7 +1273,7 @@ def addRestraint(self, res): self.register_penalty(res) return - def remove_penalty(self, *ress): + def remove_soft_bounds(self, *ress): """Remove a Restraint from the RecipeOrganizer. Attributes @@ -1301,10 +1301,10 @@ def unrestrain(self, *ress): version 4.0.0. Please use - diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.remove_penalty + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.remove_soft_bounds instead. """ - self.remove_penalty(*ress) + self.remove_soft_bounds(*ress) return def clear_all_penalties(self, recurse=False): @@ -1316,7 +1316,7 @@ def clear_all_penalties(self, recurse=False): Recurse into managed objects and clear all restraints found there as well. """ - self.remove_penalty(*self._restraints) + self.remove_soft_bounds(*self._restraints) if recurse: for msg in filter(_has_clear_restraints, self._iter_managed()): msg.clear_all_penalties(recurse) diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index fe8f8352..4da38ab8 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -247,7 +247,7 @@ def testResidual(self): self.assertAlmostEqual(chi2, dot(res, res)) # Remove the restraint and variable - self.recipe.remove_penalty(r1) + self.recipe.remove_soft_bounds(r1) self.recipe.delete_variable(self.recipe.Avar) self.recipe._ready = False res = self.recipe.residual() @@ -275,7 +275,7 @@ def testResidual(self): self.assertAlmostEqual(chi2, dot(res, res)) # Remove those - self.fitcontribution.remove_penalty(r1) + self.fitcontribution.remove_soft_bounds(r1) self.recipe._ready = False self.fitcontribution.unconstrain(self.fitcontribution.c) self.fitcontribution.c.set_value(0) diff --git a/tests/test_recipeorganizer.py b/tests/test_recipeorganizer.py index d10441c2..08d46dec 100644 --- a/tests/test_recipeorganizer.py +++ b/tests/test_recipeorganizer.py @@ -349,7 +349,7 @@ def test_add_restraint(self): self.assertEqual(1, len(self.m._restraints)) p2.set_value(10) self.assertEqual(1, r.penalty()) - self.m.remove_penalty(r) + self.m.remove_soft_bounds(r) self.assertEqual(0, len(self.m._restraints)) r = self.m.restrain(p1, upper_bound=10) From e67595da6bcd3036c6bf16d368cf4827feae5c4d Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 13 Mar 2026 11:41:09 -0400 Subject: [PATCH 161/193] register_penalty --> register_soft_bounds --- news/recipeorg-dep2.rst | 4 ++-- src/diffpy/srfit/fitbase/recipeorganizer.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/news/recipeorg-dep2.rst b/news/recipeorg-dep2.rst index ee4da736..b30655c3 100644 --- a/news/recipeorg-dep2.rst +++ b/news/recipeorg-dep2.rst @@ -4,7 +4,7 @@ * Added ``remove_constraint`` method to ``RecipeOrganizer``. * Added ``add_soft_bounds`` method to ``RecipeOrganizer``. * Added ``remove_soft_bounds`` method to ``RecipeOrganizer``. -* Added ``register_penalty`` method to ``RecipeOrganizer``. +* Added ``register_soft_bounds`` method to ``RecipeOrganizer``. * Added ``clear_all_penalties`` method to ``RecipeOrganizer``. * Added ``get_equation_from_string`` method to ``RecipeOrganizer``. @@ -18,7 +18,7 @@ * Deprecated ``unconstrain`` method of ``RecipeOrganizer``. Use ``remove_constraint`` instead. * Deprecated ``restrain`` method of ``RecipeOrganizer``. Use ``add_soft_bounds`` instead. * Deprecated ``unrestrain`` methods of ``RecipeOrganizer``. Use ``remove_soft_bounds`` instead. -* Deprecated ``addRestraint`` method of ``RecipeOrganizer``. Use ``register_penalty`` instead. +* Deprecated ``addRestraint`` method of ``RecipeOrganizer``. Use ``register_soft_bounds`` instead. * Deprecate ``clearRestraints`` method of ``RecipeOrganizer``. Use ``clear_all_penalties`` instead. * Deprecated ``equationFromString`` method of ``RecipeOrganizer``. Use ``get_equation_from_string`` instead. diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 32ab497f..f00dcbc0 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -121,7 +121,7 @@ addRestraint_deprecation_msg = build_deprecation_message( recipeorganizer_base, "addRestraint", - "register_penalty", + "register_soft_bounds", removal_version, ) @@ -1219,7 +1219,7 @@ def add_soft_bounds( # Make and store the restraint param_or_eq = Restraint(eq, lower_bound, upper_bound, sig, scaled) param_or_eq.eqstr = eqstr - self.register_penalty(param_or_eq) + self.register_soft_bounds(param_or_eq) return param_or_eq @deprecated(restrain_deprecation_msg) @@ -1248,7 +1248,7 @@ def restrain( params=params, ) - def register_penalty(self, res): + def register_soft_bounds(self, res): """Add a Restraint instance to the RecipeOrganizer. Parameters @@ -1267,10 +1267,10 @@ def addRestraint(self, res): version 4.0.0. Please use - diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.register_penalty + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.register_soft_bounds instead. """ - self.register_penalty(res) + self.register_soft_bounds(res) return def remove_soft_bounds(self, *ress): @@ -1280,7 +1280,7 @@ def remove_soft_bounds(self, *ress): ---------- *ress : Restraint The Restraints returned from the 'add_soft_bounds' method or added - with the 'register_penalty' method. + with the 'register_soft_bounds' method. """ update = False restuple = tuple(self._restraints) From 680fee45156e0bfff5a726eadad1f3340ea29cf5 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 13 Mar 2026 11:42:26 -0400 Subject: [PATCH 162/193] clear_all_penalties --> clear_all_soft_bounds --- news/recipeorg-dep2.rst | 4 ++-- src/diffpy/srfit/fitbase/recipeorganizer.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/news/recipeorg-dep2.rst b/news/recipeorg-dep2.rst index b30655c3..bcd8a3b0 100644 --- a/news/recipeorg-dep2.rst +++ b/news/recipeorg-dep2.rst @@ -5,7 +5,7 @@ * Added ``add_soft_bounds`` method to ``RecipeOrganizer``. * Added ``remove_soft_bounds`` method to ``RecipeOrganizer``. * Added ``register_soft_bounds`` method to ``RecipeOrganizer``. -* Added ``clear_all_penalties`` method to ``RecipeOrganizer``. +* Added ``clear_all_soft_bounds`` method to ``RecipeOrganizer``. * Added ``get_equation_from_string`` method to ``RecipeOrganizer``. **Changed:** @@ -19,7 +19,7 @@ * Deprecated ``restrain`` method of ``RecipeOrganizer``. Use ``add_soft_bounds`` instead. * Deprecated ``unrestrain`` methods of ``RecipeOrganizer``. Use ``remove_soft_bounds`` instead. * Deprecated ``addRestraint`` method of ``RecipeOrganizer``. Use ``register_soft_bounds`` instead. -* Deprecate ``clearRestraints`` method of ``RecipeOrganizer``. Use ``clear_all_penalties`` instead. +* Deprecate ``clearRestraints`` method of ``RecipeOrganizer``. Use ``clear_all_soft_bounds`` instead. * Deprecated ``equationFromString`` method of ``RecipeOrganizer``. Use ``get_equation_from_string`` instead. **Removed:** diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index f00dcbc0..36f8c9b2 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -156,7 +156,7 @@ clearRestraints_deprecation_msg = build_deprecation_message( recipeorganizer_base, "clearRestraints", - "clear_all_penalties", + "clear_all_soft_bounds", removal_version, ) @@ -1307,7 +1307,7 @@ def unrestrain(self, *ress): self.remove_soft_bounds(*ress) return - def clear_all_penalties(self, recurse=False): + def clear_all_soft_bounds(self, recurse=False): """Clear all restraints. Attributes @@ -1319,7 +1319,7 @@ def clear_all_penalties(self, recurse=False): self.remove_soft_bounds(*self._restraints) if recurse: for msg in filter(_has_clear_restraints, self._iter_managed()): - msg.clear_all_penalties(recurse) + msg.clear_all_soft_bounds(recurse) return @deprecated(clearRestraints_deprecation_msg) @@ -1328,10 +1328,10 @@ def clearRestraints(self, recurse=False): version 4.0.0. Please use - diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.clear_all_penalties + diffpy.srfit.fitbase.recipeorganizer.RecipeOrganizer.clear_all_soft_bounds instead. """ - self.clear_all_penalties(recurse=recurse) + self.clear_all_soft_bounds(recurse=recurse) return def _get_constraints(self, recurse=True): @@ -1606,7 +1606,7 @@ def _has_clear_constraints(msg): def _has_clear_restraints(msg): - return hasattr(msg, "clear_all_penalties") + return hasattr(msg, "clear_all_soft_bounds") def _has_get_restraints(msg): From 8c3618cc972d85394fdbcfd79c6334f0919655b6 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 13 Mar 2026 12:08:47 -0400 Subject: [PATCH 163/193] add more to add_soft_bounds docstring --- src/diffpy/srfit/fitbase/recipeorganizer.py | 32 +++++++++++++++------ 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index 36f8c9b2..dc7e8543 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -1167,21 +1167,22 @@ def add_soft_bounds( Parameters ---------- - param_or_eq : str or Parameter - The equation string or a Parameter object to restrain. + param_or_eq : str + The equation or parameter to restrain. lower_bound : float, optional The lower bound for the restraint evaluation (default is -inf). upper_bound : float, optional The upper bound for the restraint evaluation (default is inf). sig : float, optional The uncertainty associated with the bounds (default is 1). + Please see Notes for how this is used in the penalty calculation. scaled : bool, optional If True, the restraint penalty is scaled by the unrestrained point-average chi^2 (chi^2/numpoints) (default is False). params : dict, optional - The dictionary of Parameters, indexed by name, that are used in the - equation string but are not part of the RecipeOrganizer - (default is {}). + The dictionary of Parameters, indexed by name, that are used in + `param_or_eq` (if an equation string is used) but are not part + of the RecipeOrganizer (default is {}). Returns ------- @@ -1196,18 +1197,33 @@ def add_soft_bounds( .. (max(0, lower_bound - val, val - upper_bound) / sig) ** 2 - where `val` is the value of the evaluated equation. + where `val` is the value of the evaluated `param_or_eq`. If `scaled` is True, this penalty is multiplied by the average chi^2. + Examples + -------- + Restraining the lattice parameters of an Ni lattice to be + approximately 7.4Å (2x the original lattice param) + can be done with the following code: + .. + recipe.add_soft_bounds( + "a_ni + b_ni", + lower_bound=7.0, + upper_bound=7.5, + sig=0.1, + scaled=True, + params={"b_ni": Parameter("b_ni", 3.473)} + ) + Raises ------ ValueError - If `func_params` contains a name that is already used + If `params` contains a name that is already used for a Parameter. ValueError If `param_or_eq` depends on a Parameter that is not part of the - RecipeOrganizer and is not defined in `func_params`. + RecipeOrganizer and is not defined in `params`. """ if isinstance(param_or_eq, str): eqstr = param_or_eq From c11547896b0cfe46d6bbcfb5e0fba70e6b560ddc Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 13 Mar 2026 12:09:39 -0400 Subject: [PATCH 164/193] more to docstring --- src/diffpy/srfit/fitbase/recipeorganizer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index dc7e8543..a3d442f7 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -1165,6 +1165,8 @@ def add_soft_bounds( ): """Restrain an expression to specified bounds. + See Notes for how the penalty is calculated. + Parameters ---------- param_or_eq : str From c23c5d49ca2edb361ee31f02ff939267023ec486 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 13 Mar 2026 15:10:22 -0400 Subject: [PATCH 165/193] processMetaData --> _process_metadata --- src/diffpy/srfit/fitbase/profilegenerator.py | 4 ++-- src/diffpy/srfit/pdf/basepdfgenerator.py | 6 +++--- src/diffpy/srfit/pdf/pdfcontribution.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/diffpy/srfit/fitbase/profilegenerator.py b/src/diffpy/srfit/fitbase/profilegenerator.py index c45e93aa..34f4ce0b 100644 --- a/src/diffpy/srfit/fitbase/profilegenerator.py +++ b/src/diffpy/srfit/fitbase/profilegenerator.py @@ -171,10 +171,10 @@ def set_profile(self, profile): # Merge the profiles metadata with our own self.meta.update(self.profile.meta) - self.processMetaData() + self._process_metadata() return - def processMetaData(self): + def _process_metadata(self): """Process the metadata. This can be used to configure a ProfileGenerator upon a change diff --git a/src/diffpy/srfit/pdf/basepdfgenerator.py b/src/diffpy/srfit/pdf/basepdfgenerator.py index d19005cf..3ff6e247 100644 --- a/src/diffpy/srfit/pdf/basepdfgenerator.py +++ b/src/diffpy/srfit/pdf/basepdfgenerator.py @@ -117,7 +117,7 @@ def _set_calculator(self, calc): self._calc = calc for pname in self.__class__._parnames: self.addParameter(ParameterAdapter(pname, self._calc, attr=pname)) - self.processMetaData() + self._process_metadata() return def parallel(self, ncpu, mapfunc=None): @@ -154,9 +154,9 @@ def parallel(self, ncpu, mapfunc=None): self._calc = createParallelCalculator(calc_serial, ncpu, mapfunc) return - def processMetaData(self): + def _process_metadata(self): """Process the metadata once it gets set.""" - ProfileGenerator.processMetaData(self) + ProfileGenerator._process_metadata(self) stype = self.meta.get("stype") if stype is not None: diff --git a/src/diffpy/srfit/pdf/pdfcontribution.py b/src/diffpy/srfit/pdf/pdfcontribution.py index 07d33c5d..a06a7574 100644 --- a/src/diffpy/srfit/pdf/pdfcontribution.py +++ b/src/diffpy/srfit/pdf/pdfcontribution.py @@ -284,7 +284,7 @@ def _setup_generator(self, gen): # Update with our metadata gen.meta.update(self._meta) - gen.processMetaData() + gen._process_metadata() # Constrain the shared parameters self.add_constraint(gen.qdamp, self.qdamp) From db25294fc52a34143677fff3681f9348f4647909 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 11:41:03 -0400 Subject: [PATCH 166/193] isConst --> is_constant --- src/diffpy/srfit/fitbase/parameter.py | 36 +++-- src/diffpy/srfit/fitbase/parameterset.py | 23 +++- src/diffpy/srfit/structure/objcrystparset.py | 130 +++++++++++++++---- src/diffpy/srfit/structure/sgconstraints.py | 46 +++---- tests/test_constraint.py | 2 +- 5 files changed, 175 insertions(+), 62 deletions(-) diff --git a/src/diffpy/srfit/fitbase/parameter.py b/src/diffpy/srfit/fitbase/parameter.py index 6bddf43b..3e53d1c3 100644 --- a/src/diffpy/srfit/fitbase/parameter.py +++ b/src/diffpy/srfit/fitbase/parameter.py @@ -42,6 +42,10 @@ parameter_base, "setValue", "set_value", removal_version ) +setConst_dep_msg = build_deprecation_message( + parameter_base, "setConst", "set_constant", removal_version +) + class Parameter(_parameter_interface, Argument, Validatable): """Parameter class. @@ -119,17 +123,17 @@ def setValue(self, val): """ return self.set_value(val) - def setConst(self, const=True, value=None): + def set_constant(self, is_constant=True, value=None): """Toggle the Parameter as constant. - Attributes + Parameters ---------- - const - Flag indicating if the parameter is constant (default + is_constant : bool, optional + The flag indicating if the parameter is constant (default True). - value - An optional value for the parameter (default None). If this - is not None, then the parameter will get a new value, + value : float, optional + The value value for the parameter to be set to (default None). + If this is not None, then the parameter will get a new value, constant or otherwise. Returns @@ -137,11 +141,21 @@ def setConst(self, const=True, value=None): self Returns self so that mutators can be chained. """ - self.const = bool(const) + self.const = bool(is_constant) if value is not None: self.set_value(value) return self + @deprecated(setConst_dep_msg) + def setConst(self, const=True, value=None): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use diffpy.srfit.fitbase.Parameter.set_constant instead. + """ + self.set_constant(const, value) + return self + def boundRange(self, lower_bound=None, upper_bound=None): """Set lower and upper bound of the Parameter. @@ -278,9 +292,9 @@ def set_value(self, val): 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.set_constant) + def set_constant(self, const=True, value=None): + return self.par.set_constant(const, value) @wraps(Parameter.boundRange) def boundRange(self, lower_bound=None, upper_bound=None): diff --git a/src/diffpy/srfit/fitbase/parameterset.py b/src/diffpy/srfit/fitbase/parameterset.py index 6ebc4fc7..afc64906 100644 --- a/src/diffpy/srfit/fitbase/parameterset.py +++ b/src/diffpy/srfit/fitbase/parameterset.py @@ -38,6 +38,10 @@ base, "removeParameterSet", "remove_parameter_set", removal_version ) +setConst_dep_msg = build_deprecation_message( + base, "setConst", "set_constant", removal_version +) + class ParameterSet(RecipeOrganizer): """Class for organizing Parameters and other ParameterSets. @@ -147,18 +151,29 @@ def removeParameterSet(self, parset): self.remove_parameter_set(parset) return - def setConst(self, const=True): + def set_constant(self, is_constant=True): """Set every parameter within the set to a constant. Attributes ---------- - const - Flag indicating if the parameter is constant (default + is_constant : bool, optional + The flag indicating if the parameter is constant (default True). """ for par in self.iterate_over_parameters(): - par.setConst(const) + par.set_constant(is_constant) + return + @deprecated(setConst_dep_msg) + def setConst(self, const=True): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use + diffpy.srfit.fitbase.parameterset.ParameterSet.set_constant + instead. + """ + self.set_constant(const) return diff --git a/src/diffpy/srfit/structure/objcrystparset.py b/src/diffpy/srfit/structure/objcrystparset.py index f50650b6..4264b02d 100644 --- a/src/diffpy/srfit/structure/objcrystparset.py +++ b/src/diffpy/srfit/structure/objcrystparset.py @@ -56,6 +56,37 @@ ) from diffpy.srfit.fitbase.parameterset import ParameterSet from diffpy.srfit.structure.srrealparset import SrRealParSet +from diffpy.utils._deprecator import build_deprecation_message, deprecated + +removal_version = "4.0.0" +bl_base = "diffpy.srfit.structure.objcrystparset.ObjCrystBondLengthParameter" + +bl_setConst_dep_msg = build_deprecation_message( + bl_base, + "setConst", + "set_constant", + removal_version, +) + +ba_base = "diffpy.srfit.structure.objcrystparset.ObjCrystBondAngleParameter" + +ba_setConst_dep_msg = build_deprecation_message( + ba_base, + "setConst", + "set_constant", + removal_version, +) + +da_base = ( + "diffpy.srfit.structure.objcrystparset.ObjCrystDihedralAngleParameter" +) + +da_setConst_dep_msg = build_deprecation_message( + da_base, + "setConst", + "set_constant", + removal_version, +) class ObjCrystScattererParSet(ParameterSet): @@ -1327,31 +1358,49 @@ def __init__(self, name, atom1, atom2, value=None, const=False, mode=None): if value is None: value = GetBondLength(atom1.scat, atom2.scat) StretchModeParameter.__init__(self, name, value, const) - self.setConst(const) + self.set_constant(const) return - def setConst(self, const=True, value=None): + def set_constant(self, is_constant=True, value=None): """Toggle the Parameter as constant. - This sets the underlying ObjCrystMolAtomParSet positions const as well. + This sets the underlying ObjCrystMolAtomParSet positions + constant as well. Attributes ---------- - const + is_constant Flag indicating if the Parameter is constant (default True). value An optional value for the Parameter (default None). If this is not None, then the Parameter will get a new value, constant or otherwise. + + Return + ------ + self + Returns self so that mutators can be chained. """ - StretchModeParameter.setConst(self, const, value) + StretchModeParameter.set_constant(self, is_constant, value) for a in [self.atom1, self.atom2]: - a.x.setConst(const) - a.y.setConst(const) - a.z.setConst(const) + a.x.set_constant(is_constant) + a.y.set_constant(is_constant) + a.z.set_constant(is_constant) + return self + + @deprecated(bl_setConst_dep_msg) + def setConst(self, const=True, value=None): + """This function has been deprecated and will be removed in version + 4.0.0. + + Please use + diffpy.srfit.structure.objcryst.ObjCrystBondLengthParameter.set_constant + instead. + """ + self.set_constant(const, value) return self def getValue(self): @@ -1472,30 +1521,48 @@ def __init__( if value is None: value = GetBondAngle(atom1.scat, atom2.scat, atom3.scat) StretchModeParameter.__init__(self, name, value, const) - self.setConst(const) + self.set_constant(const) return - def setConst(self, const=True, value=None): + def set_constant(self, is_constant=True, value=None): """Toggle the Parameter as constant. - This sets the underlying ObjCrystMolAtomParSet positions const as well. + This sets the underlying ObjCrystMolAtomParSet positions + constant as well. Attributes ---------- - const + is_constant Flag indicating if the Parameter is constant (default True). value An optional value for the Parameter (default None). If this is not None, then the Parameter will get a new value, constant or otherwise. + + Return + ------ + self + Returns self so that mutators can be chained. """ - StretchModeParameter.setConst(self, const, value) + StretchModeParameter.set_constant(self, is_constant, value) for a in [self.atom1, self.atom2, self.atom3]: - a.x.setConst(const) - a.y.setConst(const) - a.z.setConst(const) + a.x.set_constant(is_constant) + a.y.set_constant(is_constant) + a.z.set_constant(is_constant) + return self + + @deprecated(ba_setConst_dep_msg) + def setConst(self, const=True, value=None): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use + diffpy.srfit.structure.objcryst.ObjCrystBondAngleParameter.set_constant + instead. + """ + self.set_constant(const, value) return self def getValue(self): @@ -1636,30 +1703,47 @@ def __init__( atom1.scat, atom2.scat, atom3.scat, atom4.scat ) StretchModeParameter.__init__(self, name, value, const) - self.setConst(const) + self.set_constant(const) return - def setConst(self, const=True, value=None): + def set_constant(self, is_constant=True, value=None): """Toggle the Parameter as constant. This sets the underlying ObjCrystMolAtomParSet positions const as well. Attributes ---------- - const + is_constant Flag indicating if the Parameter is constant (default True). value An optional value for the Parameter (default None). If this is not None, then the Parameter will get a new value, constant or otherwise. + + Return + ------ + self + Returns self so that mutators can be chained. """ - StretchModeParameter.setConst(self, const, value) + StretchModeParameter.set_constant(self, is_constant, value) for a in [self.atom1, self.atom2, self.atom3, self.atom4]: - a.x.setConst(const) - a.y.setConst(const) - a.z.setConst(const) + a.x.set_constant(is_constant) + a.y.set_constant(is_constant) + a.z.set_constant(is_constant) + return self + + @deprecated(da_setConst_dep_msg) + def setConst(self, const=True, value=None): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use + diffpy.srfit.structure.objcryst.ObjCrystDihedralAngleParameter.set_constant + instead. + """ + self.set_constant(const, value) return self def getValue(self): diff --git a/src/diffpy/srfit/structure/sgconstraints.py b/src/diffpy/srfit/structure/sgconstraints.py index 2b48ec1d..2faab6fb 100644 --- a/src/diffpy/srfit/structure/sgconstraints.py +++ b/src/diffpy/srfit/structure/sgconstraints.py @@ -392,7 +392,7 @@ def _clear_constraints(self): for par in [scatterer.x, scatterer.y, scatterer.z]: if scatterer.is_constrained(par): scatterer.remove_constraint(par) - par.setConst(False) + par.set_constant(False) # Clear the lattice if self.constrainlat: @@ -409,7 +409,7 @@ def _clear_constraints(self): for par in latpars: if lattice.is_constrained(par): lattice.remove_constraint(par) - par.setConst(False) + par.set_constant(False) # Clear ADPs if self.constrainadps: @@ -419,14 +419,14 @@ def _clear_constraints(self): if par is not None: if scatterer.is_constrained(par): scatterer.remove_constraint(par) - par.setConst(False) + par.set_constant(False) for pname in adpsymbols: par = scatterer.get(pname) if par is not None: if scatterer.is_constrained(par): scatterer.remove_constraint(par) - par.setConst(False) + par.set_constant(False) return @@ -652,14 +652,14 @@ def _constrain_monoclinic(lattice): if lattice.angunits == "rad": afactor = deg2rad ang90 = 90.0 * afactor - lattice.alpha.setConst(True, ang90) + lattice.alpha.set_constant(True, ang90) beta = lattice.beta.getValue() gamma = lattice.gamma.getValue() if ang90 != beta and ang90 == gamma: - lattice.gamma.setConst(True, ang90) + lattice.gamma.set_constant(True, ang90) else: - lattice.beta.setConst(True, ang90) + lattice.beta.set_constant(True, ang90) return @@ -672,9 +672,9 @@ def _constrain_orthorhombic(lattice): 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) + lattice.alpha.set_constant(True, ang90) + lattice.beta.set_constant(True, ang90) + lattice.gamma.set_constant(True, ang90) return @@ -688,9 +688,9 @@ def _constrain_tetragonal(lattice): 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) + lattice.alpha.set_constant(True, ang90) + lattice.beta.set_constant(True, ang90) + lattice.gamma.set_constant(True, ang90) lattice.add_constraint(lattice.b, lattice.a) return @@ -709,9 +709,9 @@ def _constrain_trigonal(lattice): ang120 = 120.0 * afactor if lattice.gamma.getValue() == ang120: lattice.add_constraint(lattice.b, lattice.a) - lattice.alpha.setConst(True, ang90) - lattice.beta.setConst(True, ang90) - lattice.gamma.setConst(True, ang120) + lattice.alpha.set_constant(True, ang90) + lattice.beta.set_constant(True, ang90) + lattice.gamma.set_constant(True, ang120) else: lattice.add_constraint(lattice.b, lattice.a) lattice.add_constraint(lattice.c, lattice.a) @@ -732,9 +732,9 @@ def _constrain_hexagonal(lattice): ang90 = 90.0 * afactor ang120 = 120.0 * afactor lattice.add_constraint(lattice.b, lattice.a) - lattice.alpha.setConst(True, ang90) - lattice.beta.setConst(True, ang90) - lattice.gamma.setConst(True, ang120) + lattice.alpha.set_constant(True, ang90) + lattice.beta.set_constant(True, ang90) + lattice.gamma.set_constant(True, ang120) return @@ -750,9 +750,9 @@ def _constrain_cubic(lattice): ang90 = 90.0 * afactor lattice.add_constraint(lattice.b, lattice.a) lattice.add_constraint(lattice.c, lattice.a) - lattice.alpha.setConst(True, ang90) - lattice.beta.setConst(True, ang90) - lattice.gamma.setConst(True, ang90) + lattice.alpha.set_constant(True, ang90) + lattice.beta.set_constant(True, ang90) + lattice.gamma.set_constant(True, ang90) return @@ -805,7 +805,7 @@ def _makeconstraint(parname, formula, scatterer, idx, ns={}): # Check to see if it is a constant fval = _get_float(formula) if fval is not None: - par.setConst() + par.set_constant() return # If we got here, then we have a constraint equation diff --git a/tests/test_constraint.py b/tests/test_constraint.py index d045feb5..f173de14 100644 --- a/tests/test_constraint.py +++ b/tests/test_constraint.py @@ -46,7 +46,7 @@ def test_constrain_parameter(self): eq2 = get_equation_from_string("2*p2+1", factory) c2 = Constraint() self.assertRaises(ValueError, c2.constrain, p1, eq2) - p2.setConst() + p2.set_constant() eq3 = get_equation_from_string("p1", factory) self.assertRaises(ValueError, c2.constrain, p2, eq3) From 160519e6ecb47070a2a4d67a7b2e0d72f40ec707 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 11:55:14 -0400 Subject: [PATCH 167/193] change Attributes --> Parameters in all docstrings --- src/diffpy/srfit/equation/builder.py | 6 +-- src/diffpy/srfit/equation/equationmod.py | 2 +- .../srfit/equation/literals/argument.py | 2 +- .../srfit/equation/literals/operators.py | 2 +- .../srfit/equation/visitors/__init__.py | 4 +- src/diffpy/srfit/equation/visitors/printer.py | 2 - src/diffpy/srfit/equation/visitors/swapper.py | 2 +- src/diffpy/srfit/fitbase/fitcontribution.py | 8 +-- src/diffpy/srfit/fitbase/fithook.py | 12 ++--- src/diffpy/srfit/fitbase/fitrecipe.py | 2 +- src/diffpy/srfit/fitbase/fitresults.py | 8 +-- src/diffpy/srfit/fitbase/parameter.py | 12 ++--- src/diffpy/srfit/fitbase/parameterset.py | 6 +-- src/diffpy/srfit/fitbase/profile.py | 2 - src/diffpy/srfit/fitbase/profilegenerator.py | 2 +- src/diffpy/srfit/fitbase/recipeorganizer.py | 18 +++---- src/diffpy/srfit/fitbase/restraint.py | 4 +- src/diffpy/srfit/fitbase/simplerecipe.py | 4 +- src/diffpy/srfit/interface/interface.py | 2 +- src/diffpy/srfit/pdf/basepdfgenerator.py | 8 +-- .../srfit/pdf/characteristicfunctions.py | 16 +++--- src/diffpy/srfit/pdf/debyepdfgenerator.py | 4 +- src/diffpy/srfit/pdf/pdfcontribution.py | 10 ++-- src/diffpy/srfit/pdf/pdfparser.py | 2 - src/diffpy/srfit/sas/prcalculator.py | 2 +- src/diffpy/srfit/sas/sasgenerator.py | 2 +- src/diffpy/srfit/sas/sasimport.py | 2 +- src/diffpy/srfit/sas/sasparameter.py | 2 +- src/diffpy/srfit/sas/sasparser.py | 2 - src/diffpy/srfit/sas/sasprofile.py | 4 +- src/diffpy/srfit/structure/__init__.py | 2 +- src/diffpy/srfit/structure/bvsrestraint.py | 4 +- src/diffpy/srfit/structure/cctbxparset.py | 6 +-- src/diffpy/srfit/structure/diffpyparset.py | 6 +-- src/diffpy/srfit/structure/objcrystparset.py | 54 +++++++++---------- src/diffpy/srfit/structure/sgconstraints.py | 10 ++-- src/diffpy/srfit/structure/srrealparset.py | 2 +- src/diffpy/srfit/util/inpututils.py | 2 +- src/diffpy/srfit/util/tagmanager.py | 4 +- 39 files changed, 116 insertions(+), 128 deletions(-) diff --git a/src/diffpy/srfit/equation/builder.py b/src/diffpy/srfit/equation/builder.py index 0c9ffafb..0bb81350 100644 --- a/src/diffpy/srfit/equation/builder.py +++ b/src/diffpy/srfit/equation/builder.py @@ -493,7 +493,7 @@ def __eval_binary(self, other, OperatorClass, onleft=True): Other can be an BaseBuilder or a constant. - Attributes + Parameters ---------- onleft Indicates that the operator was passed on the left side @@ -666,7 +666,7 @@ def __call__(self, *args): This creates a new builder that encapsulates the operation. - Attributes + Parameters ---------- args Arguments of the operation. @@ -730,7 +730,7 @@ def wrapOperator(name, op): def wrapFunction(name, func, nin=2, nout=1): """Wrap a function in an OperatorBuilder instance. - Attributes + Parameters ---------- name The name of the function diff --git a/src/diffpy/srfit/equation/equationmod.py b/src/diffpy/srfit/equation/equationmod.py index 4a40aeb7..5be7ba0c 100644 --- a/src/diffpy/srfit/equation/equationmod.py +++ b/src/diffpy/srfit/equation/equationmod.py @@ -91,7 +91,7 @@ class Equation(Operator): def __init__(self, name=None, root=None): """Initialize. - Attributes + Parameters ---------- name A name for this Equation. diff --git a/src/diffpy/srfit/equation/literals/argument.py b/src/diffpy/srfit/equation/literals/argument.py index a99fb7f1..c468d516 100644 --- a/src/diffpy/srfit/equation/literals/argument.py +++ b/src/diffpy/srfit/equation/literals/argument.py @@ -62,7 +62,7 @@ def getValue(self): def set_value(self, val): """Set the value of the Literal. - Attributes + Parameters ---------- val The value to assign diff --git a/src/diffpy/srfit/equation/literals/operators.py b/src/diffpy/srfit/equation/literals/operators.py index 9b78b77c..bb830b05 100644 --- a/src/diffpy/srfit/equation/literals/operators.py +++ b/src/diffpy/srfit/equation/literals/operators.py @@ -347,7 +347,7 @@ def __init__(self, op): Arguments - Attributes + Parameters ---------- op A numpy ufunc diff --git a/src/diffpy/srfit/equation/visitors/__init__.py b/src/diffpy/srfit/equation/visitors/__init__.py index ef50ec43..82239eb4 100644 --- a/src/diffpy/srfit/equation/visitors/__init__.py +++ b/src/diffpy/srfit/equation/visitors/__init__.py @@ -35,7 +35,7 @@ def getArgs(literal, getconsts=True): """Get the Arguments of a Literal tree. - Attributes + Parameters ---------- getconsts If True (default), then Arguments designated as constant @@ -50,7 +50,7 @@ def getArgs(literal, getconsts=True): def getExpression(literal, eqskip=None): """Get math expression string from the Literal tree object. - Attributes + Parameters ---------- eqskip regular expression pattern for Equation objects that should diff --git a/src/diffpy/srfit/equation/visitors/printer.py b/src/diffpy/srfit/equation/visitors/printer.py index d3aa5ee7..4fcb717b 100644 --- a/src/diffpy/srfit/equation/visitors/printer.py +++ b/src/diffpy/srfit/equation/visitors/printer.py @@ -29,8 +29,6 @@ class Printer(Visitor): """Printer for printing a Literal tree. - Attributes: - Attributes ---------- eqskip diff --git a/src/diffpy/srfit/equation/visitors/swapper.py b/src/diffpy/srfit/equation/visitors/swapper.py index c27cf85e..ddd49ef6 100644 --- a/src/diffpy/srfit/equation/visitors/swapper.py +++ b/src/diffpy/srfit/equation/visitors/swapper.py @@ -38,7 +38,7 @@ class Swapper(Visitor): def __init__(self, oldlit, newlit): """Initialize. - Attributes + Parameters ---------- oldlit The literal to be replaced. diff --git a/src/diffpy/srfit/fitbase/fitcontribution.py b/src/diffpy/srfit/fitbase/fitcontribution.py index feda75ba..710f492c 100644 --- a/src/diffpy/srfit/fitbase/fitcontribution.py +++ b/src/diffpy/srfit/fitbase/fitcontribution.py @@ -147,7 +147,7 @@ def __init__(self, name): def set_profile(self, profile, xname=None, yname=None, dyname=None): """Assign the Profile for this FitContribution. - Attributes + Parameters ---------- profile A Profile that specifies the calculation points and that @@ -227,7 +227,7 @@ def add_profile_generator(self, gen, name=None): Calling addProfileGenerator sets the profile equation to call the calculator and if there is not a profile equation already. - Attributes + Parameters ---------- gen A ProfileGenerator instance @@ -278,7 +278,7 @@ def set_equation(self, eqstr, ns={}): for this FitContribution. The equation will be usable within set_residual_equation as "eq", and it takes no arguments. - Attributes + Parameters ---------- eqstr A string representation of the equation. Any Parameter @@ -353,7 +353,7 @@ def getEquation(self): def set_residual_equation(self, eqstr): """Set the residual equation for the FitContribution. - Attributes + Parameters ---------- eqstr A string representation of the residual. If eqstr is None diff --git a/src/diffpy/srfit/fitbase/fithook.py b/src/diffpy/srfit/fitbase/fithook.py index 3afa90d9..43e2c84e 100644 --- a/src/diffpy/srfit/fitbase/fithook.py +++ b/src/diffpy/srfit/fitbase/fithook.py @@ -58,7 +58,7 @@ def precall(self, recipe): """This is called within FitRecipe.residual, before the calculation. - Attributes + Parameters ---------- recipe The FitRecipe instance @@ -69,7 +69,7 @@ def postcall(self, recipe, chiv): """This is called within FitRecipe.residual, after the calculation. - Attributes + Parameters ---------- recipe The FitRecipe instance @@ -88,8 +88,6 @@ class PrintFitHook(FitHook): This FitHook prints out a running count of the number of times the residual has been called, or other information, based on the verbosity. - Attributes - Attributes ---------- count @@ -127,7 +125,7 @@ def precall(self, recipe): """This is called within FitRecipe.residual, before the calculation. - Attributes + Parameters ---------- recipe The FitRecipe instance @@ -141,7 +139,7 @@ def postcall(self, recipe, chiv): """This is called within FitRecipe.residual, after the calculation. - Attributes + Parameters ---------- recipe The FitRecipe instance @@ -237,7 +235,7 @@ def postcall(self, recipe, chiv): Find data and plot it. - Attributes + Parameters ---------- recipe The FitRecipe instance diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 0961b504..d4fdf279 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -906,7 +906,7 @@ def _new_parameter(self, name, value, check=True): def __get_var_and_check(self, var): """Get the actual variable from var. - Attributes + Parameters ---------- var A variable of the FitRecipe, or the name of a variable. diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index d8310109..18f0423c 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -162,7 +162,7 @@ class FitResults(object): def __init__(self, recipe, update=True, showfixed=True, showcon=False): """Initialize the attributes. - Attributes + Parameters ---------- recipe : FitRecipe The recipe containing the results. @@ -733,7 +733,7 @@ class ContributionResults(object): def __init__(self, con, weight, fitres): """Initialize the attributes. - Attributes + Parameters ---------- con The FitContribution @@ -829,7 +829,7 @@ def resultsDictionary(results): This reads the results from file and stores them in a dictionary to be returned to the caller. The dictionary may contain non-result entries. - Attributes + Parameters ---------- results An open file-like object, name of a file that contains @@ -865,7 +865,7 @@ def initializeRecipe(recipe, results): free) in the recipe to the results values. Note that the recipe has to be configured, with variables. This does not reconstruct a FitRecipe. - Attributes + Parameters ---------- recipe A configured recipe with variables diff --git a/src/diffpy/srfit/fitbase/parameter.py b/src/diffpy/srfit/fitbase/parameter.py index 3e53d1c3..d9a82b13 100644 --- a/src/diffpy/srfit/fitbase/parameter.py +++ b/src/diffpy/srfit/fitbase/parameter.py @@ -72,7 +72,7 @@ class Parameter(_parameter_interface, Argument, Validatable): def __init__(self, name, value=None, const=False): """Initialization. - Attributes + Parameters ---------- name The name of this Parameter (must be a valid attribute @@ -95,7 +95,7 @@ def __init__(self, name, value=None, const=False): def set_value(self, val): """Set the value of the Parameter and the bounds. - Attributes + Parameters ---------- val The value to assign. @@ -159,7 +159,7 @@ def setConst(self, const=True, value=None): def boundRange(self, lower_bound=None, upper_bound=None): """Set lower and upper bound of the Parameter. - Attributes + Parameters ---------- lower_bound : float The lower bound for the bounds list. @@ -180,7 +180,7 @@ def boundRange(self, lower_bound=None, upper_bound=None): def boundWindow(self, lr=0, ur=None): """Create bounds centered on the current value of the Parameter. - Attributes + Parameters ---------- lr The radius of the lower bound (default 0). The lower bound is @@ -235,7 +235,7 @@ class ParameterProxy(Parameter): def __init__(self, name, par): """Initialization. - Attributes + Parameters ---------- name The name of this ParameterProxy. @@ -330,7 +330,7 @@ class ParameterAdapter(Parameter): def __init__(self, name, obj, getter=None, setter=None, attr=None): """Wrap an object as a Parameter. - Attributes + Parameters ---------- name The name of this Parameter. diff --git a/src/diffpy/srfit/fitbase/parameterset.py b/src/diffpy/srfit/fitbase/parameterset.py index afc64906..edaac6f5 100644 --- a/src/diffpy/srfit/fitbase/parameterset.py +++ b/src/diffpy/srfit/fitbase/parameterset.py @@ -87,7 +87,7 @@ class ParameterSet(RecipeOrganizer): def __init__(self, name): """Initialize. - Attributes + Parameters ---------- name The name of this ParameterSet. @@ -106,7 +106,7 @@ def __init__(self, name): def add_parameter_set(self, parset): """Add a ParameterSet to the hierarchy. - Attributes + Parameters ---------- parset The ParameterSet to be stored. @@ -154,7 +154,7 @@ def removeParameterSet(self, parset): def set_constant(self, is_constant=True): """Set every parameter within the set to a constant. - Attributes + Parameters ---------- is_constant : bool, optional The flag indicating if the parameter is constant (default diff --git a/src/diffpy/srfit/fitbase/profile.py b/src/diffpy/srfit/fitbase/profile.py index 684a0313..bc598d3f 100644 --- a/src/diffpy/srfit/fitbase/profile.py +++ b/src/diffpy/srfit/fitbase/profile.py @@ -71,8 +71,6 @@ class Profile(Observable, Validatable): Profile is an Observable. The xpar, ypar and dypar attributes are observed by the Profile, which can in turn be observed by some other object. - Attributes - Attributes ---------- _xobs diff --git a/src/diffpy/srfit/fitbase/profilegenerator.py b/src/diffpy/srfit/fitbase/profilegenerator.py index 34f4ce0b..e0206084 100644 --- a/src/diffpy/srfit/fitbase/profilegenerator.py +++ b/src/diffpy/srfit/fitbase/profilegenerator.py @@ -156,7 +156,7 @@ def operation(self): def set_profile(self, profile): """Assign the profile. - Attributes + Parameters ---------- profile A Profile that specifies the calculation points and which diff --git a/src/diffpy/srfit/fitbase/recipeorganizer.py b/src/diffpy/srfit/fitbase/recipeorganizer.py index a3d442f7..20d16c49 100644 --- a/src/diffpy/srfit/fitbase/recipeorganizer.py +++ b/src/diffpy/srfit/fitbase/recipeorganizer.py @@ -413,7 +413,7 @@ def getValues(self): def _add_object(self, obj, d, check=True): """Add an object to a managed dictionary. - Attributes + Parameters ---------- obj The object to be stored. @@ -482,7 +482,7 @@ def _remove_object(self, obj, d): def _locate_managed_object(self, obj): """Find the location a managed object within the hierarchy. - Attributes + Parameters ---------- obj The object to find. @@ -610,7 +610,7 @@ def _add_parameter(self, parameter, check=True): Parameters added in this way are registered with the _eqfactory. - Attributes + Parameters ---------- parameter The Parameter to be stored. @@ -657,7 +657,7 @@ def register_calculator(self, calculator, argnames=None): arguments like a function or without, in which case the values of the Parameters created from argnames will be be used to compute the value. - Attributes + Parameters ---------- calculator : Calculator object The Calculator to register. @@ -1047,7 +1047,7 @@ def remove_constraint(self, *pars): This removes any constraints on a Parameter. - Attributes + Parameters ---------- *pars : str or Parameter The names of Parameters or Parameters to unconstrain. @@ -1114,7 +1114,7 @@ def get_constrained_parmeters(self, recurse=False): def getConstrainedPars(self, recurse=False): """Get a list of constrained managed Parameters in this object. - Attributes + Parameters ---------- recurse Recurse into managed objects and retrieve their constrained @@ -1294,7 +1294,7 @@ def addRestraint(self, res): def remove_soft_bounds(self, *ress): """Remove a Restraint from the RecipeOrganizer. - Attributes + Parameters ---------- *ress : Restraint The Restraints returned from the 'add_soft_bounds' method or added @@ -1328,7 +1328,7 @@ def unrestrain(self, *ress): def clear_all_soft_bounds(self, recurse=False): """Clear all restraints. - Attributes + Parameters ---------- recurse Recurse into managed objects and clear all restraints @@ -1543,7 +1543,7 @@ def get_equation_from_string( ): """Make an Equation object from a string. - Attributes + Parameters ---------- eqstr : str 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 7b6ec747..fb0006d2 100644 --- a/src/diffpy/srfit/fitbase/restraint.py +++ b/src/diffpy/srfit/fitbase/restraint.py @@ -59,7 +59,7 @@ def __init__( ): """Restrain an equation to specified bounds. - Attributes + Parameters ---------- eq An equation whose evaluation is compared against the @@ -87,7 +87,7 @@ def __init__( def penalty(self, w=1.0): """Calculate the penalty of the restraint. - Attributes + Parameters ---------- w The point-average chi^2 which is optionally used to scale the diff --git a/src/diffpy/srfit/fitbase/simplerecipe.py b/src/diffpy/srfit/fitbase/simplerecipe.py index e9da1f2c..5f27889b 100644 --- a/src/diffpy/srfit/fitbase/simplerecipe.py +++ b/src/diffpy/srfit/fitbase/simplerecipe.py @@ -306,7 +306,7 @@ def set_equation(self, eqstr, ns={}): The equation will be usable within set_residual_equation as "eq", and it takes no arguments. - Attributes + Parameters ---------- eqstr A string representation of the equation. Variables will be @@ -352,7 +352,7 @@ def __call__(self): def print_results(self, header="", footer=""): """Format and print the results. - Attributes + Parameters ---------- header A header to add to the output (default "") diff --git a/src/diffpy/srfit/interface/interface.py b/src/diffpy/srfit/interface/interface.py index 308e0471..08748728 100644 --- a/src/diffpy/srfit/interface/interface.py +++ b/src/diffpy/srfit/interface/interface.py @@ -40,7 +40,7 @@ def __lshift__(self, v): Think of '<<' as injecting a value - Attributes + Parameters ---------- v value or Argument derivative diff --git a/src/diffpy/srfit/pdf/basepdfgenerator.py b/src/diffpy/srfit/pdf/basepdfgenerator.py index 3ff6e247..e8566b84 100644 --- a/src/diffpy/srfit/pdf/basepdfgenerator.py +++ b/src/diffpy/srfit/pdf/basepdfgenerator.py @@ -123,7 +123,7 @@ def _set_calculator(self, calc): def parallel(self, ncpu, mapfunc=None): """Run calculation in parallel. - Attributes + Parameters ---------- ncpu Number of parallel processes. Revert to serial mode when 1. @@ -181,7 +181,7 @@ def _process_metadata(self): def setScatteringType(self, stype="X"): """Set the scattering type. - Attributes + Parameters ---------- stype "X" for x-ray, "N" for neutron, "E" for electrons, @@ -230,7 +230,7 @@ def setStructure(self, stru, name="phase", periodic=True): See those classes (located in diffpy.srfit.structure) for how they are used. The resulting ParameterSet will be managed by this generator. - Attributes + Parameters ---------- stru diffpy.structure.Structure, pyobjcryst.crystal.Crystal or @@ -260,7 +260,7 @@ def setPhase(self, parset, periodic=True): object (from diffpy or pyobjcryst). The passed ParameterSet will be managed by this generator. - Attributes + Parameters ---------- parset A SrRealParSet that holds the structural information. diff --git a/src/diffpy/srfit/pdf/characteristicfunctions.py b/src/diffpy/srfit/pdf/characteristicfunctions.py index ca24dfc1..19f8364a 100644 --- a/src/diffpy/srfit/pdf/characteristicfunctions.py +++ b/src/diffpy/srfit/pdf/characteristicfunctions.py @@ -48,7 +48,7 @@ def sphericalCF(r, psize): """Spherical nanoparticle characteristic function. - Attributes + Parameters ---------- r distance of interaction @@ -73,7 +73,7 @@ def spheroidalCF(r, erad, prad): Spheroid with radii (erad, erad, prad) - Attributes + Parameters ---------- prad polar radius @@ -95,7 +95,7 @@ def spheroidalCF2(r, psize, axrat): Form factor for ellipsoid with radii (psize/2, psize/2, axrat*psize/2) - Attributes + Parameters ---------- r distance of interaction @@ -206,7 +206,7 @@ def lognormalSphericalCF(r, psize, psig): """Spherical nanoparticle characteristic function with lognormal size distribution. - Attributes + Parameters ---------- r distance of interaction @@ -263,7 +263,7 @@ def lognormalSphericalCF(r, psize, psig): def sheetCF(r, sthick): """Nanosheet characteristic function. - Attributes + Parameters ---------- r distance of interaction @@ -293,7 +293,7 @@ def sheetCF(r, sthick): def shellCF(r, radius, thickness): """Spherical shell characteristic function. - Attributes + Parameters ---------- radius Inner radius @@ -313,7 +313,7 @@ def shellCF(r, radius, thickness): def shellCF2(r, a, delta): """Spherical shell characteristic function. - Attributes + Parameters ---------- a Central radius @@ -378,7 +378,7 @@ class SASCF(Calculator): def __init__(self, name, model): """Initialize the generator. - Attributes + Parameters ---------- name A name for the SASCF diff --git a/src/diffpy/srfit/pdf/debyepdfgenerator.py b/src/diffpy/srfit/pdf/debyepdfgenerator.py index 641c577f..ba84faac 100644 --- a/src/diffpy/srfit/pdf/debyepdfgenerator.py +++ b/src/diffpy/srfit/pdf/debyepdfgenerator.py @@ -92,7 +92,7 @@ def setStructure(self, stru, name="phase", periodic=False): See those classes (located in diffpy.srfit.structure) for how they are used. The resulting ParameterSet will be managed by this generator. - Attributes + Parameters ---------- stru diffpy.structure.Structure, pyobjcryst.crystal.Crystal or @@ -116,7 +116,7 @@ def setPhase(self, parset, periodic=False): object (from diffpy or pyobjcryst). The passed ParameterSet will be managed by this generator. - Attributes + Parameters ---------- parset A SrRealParSet that holds the structural information. diff --git a/src/diffpy/srfit/pdf/pdfcontribution.py b/src/diffpy/srfit/pdf/pdfcontribution.py index a06a7574..c884641b 100644 --- a/src/diffpy/srfit/pdf/pdfcontribution.py +++ b/src/diffpy/srfit/pdf/pdfcontribution.py @@ -84,7 +84,7 @@ class PDFContribution(FitContribution): def __init__(self, name): """Create the PDFContribution. - Attributes + Parameters ---------- name The name of the contribution. @@ -111,7 +111,7 @@ def loadData(self, data): This uses the PDFParser to load the data and then passes it to the built-in profile with load_parsed_data. - Attributes + Parameters ---------- data An open file-like object, name of a file that contains data @@ -180,7 +180,7 @@ def savetxt(self, fname, **kwargs): def addStructure(self, name, stru, periodic=True): """Add a phase that goes into the PDF calculation. - Attributes + Parameters ---------- name A name to give the generator that will manage the PDF @@ -224,7 +224,7 @@ def addStructure(self, name, stru, periodic=True): def addPhase(self, name, parset, periodic=True): """Add a phase that goes into the PDF calculation. - Attributes + Parameters ---------- name A name to give the generator that will manage the PDF @@ -307,7 +307,7 @@ def _get_meta_value(self, kwd): def setScatteringType(self, type="X"): """Set the scattering type. - Attributes + Parameters ---------- type "X" for x-ray or "N" for neutron diff --git a/src/diffpy/srfit/pdf/pdfparser.py b/src/diffpy/srfit/pdf/pdfparser.py index f2d32ccd..75d9c81f 100644 --- a/src/diffpy/srfit/pdf/pdfparser.py +++ b/src/diffpy/srfit/pdf/pdfparser.py @@ -33,8 +33,6 @@ class PDFParser(ProfileParser): """Class for holding a diffraction pattern. - Attributes - Attributes ---------- _format diff --git a/src/diffpy/srfit/sas/prcalculator.py b/src/diffpy/srfit/sas/prcalculator.py index 4030aa94..00d3c8e8 100644 --- a/src/diffpy/srfit/sas/prcalculator.py +++ b/src/diffpy/srfit/sas/prcalculator.py @@ -66,7 +66,7 @@ class PrCalculator(Calculator): def __init__(self, name): """Initialize the generator. - Attributes + Parameters ---------- name A name for the PrCalculator diff --git a/src/diffpy/srfit/sas/sasgenerator.py b/src/diffpy/srfit/sas/sasgenerator.py index 238ae43f..a986e283 100644 --- a/src/diffpy/srfit/sas/sasgenerator.py +++ b/src/diffpy/srfit/sas/sasgenerator.py @@ -43,7 +43,7 @@ class SASGenerator(ProfileGenerator): def __init__(self, name, model): """Initialize the generator. - Attributes + Parameters ---------- name A name for the SASGenerator diff --git a/src/diffpy/srfit/sas/sasimport.py b/src/diffpy/srfit/sas/sasimport.py index 2c15c4ad..cfd10fa8 100644 --- a/src/diffpy/srfit/sas/sasimport.py +++ b/src/diffpy/srfit/sas/sasimport.py @@ -18,7 +18,7 @@ def sasimport(modname): """Import specified module from the SasView sas package. - Attributes + Parameters ---------- modname absolute module name contained in the sas package. diff --git a/src/diffpy/srfit/sas/sasparameter.py b/src/diffpy/srfit/sas/sasparameter.py index 28ae4834..b74a58f1 100644 --- a/src/diffpy/srfit/sas/sasparameter.py +++ b/src/diffpy/srfit/sas/sasparameter.py @@ -52,7 +52,7 @@ class SASParameter(Parameter): def __init__(self, name, model, parname=None): """Create the Parameter. - Attributes + Parameters ---------- name Name of the Parameter diff --git a/src/diffpy/srfit/sas/sasparser.py b/src/diffpy/srfit/sas/sasparser.py index 12583d6b..22da76f8 100644 --- a/src/diffpy/srfit/sas/sasparser.py +++ b/src/diffpy/srfit/sas/sasparser.py @@ -30,8 +30,6 @@ class SASParser(ProfileParser): This uses a sas DataLoader to load the data. The DataInfo object it returns is held in the metadata under the name "datainfo". - Attributes - Attributes ---------- _format diff --git a/src/diffpy/srfit/sas/sasprofile.py b/src/diffpy/srfit/sas/sasprofile.py index a4b313f7..2ac6ab3b 100644 --- a/src/diffpy/srfit/sas/sasprofile.py +++ b/src/diffpy/srfit/sas/sasprofile.py @@ -30,8 +30,6 @@ class SASProfile(Profile): Otherwise, use the SASParser class and load the data into a base Profile object. - Attributes - Attributes ---------- _xobs @@ -78,7 +76,7 @@ class SASProfile(Profile): def __init__(self, datainfo): """Initialize the attributes. - Attributes + Parameters ---------- datainfo The DataInfo object this wraps. diff --git a/src/diffpy/srfit/structure/__init__.py b/src/diffpy/srfit/structure/__init__.py index f479cf50..d09aa5cc 100644 --- a/src/diffpy/srfit/structure/__init__.py +++ b/src/diffpy/srfit/structure/__init__.py @@ -25,7 +25,7 @@ def struToParameterSet(name, stru): This returns a ParameterSet adapted for the structure depending on its type. - Attributes + Parameters ---------- stru a structure object known by this module diff --git a/src/diffpy/srfit/structure/bvsrestraint.py b/src/diffpy/srfit/structure/bvsrestraint.py index f8af1ebe..ec156449 100644 --- a/src/diffpy/srfit/structure/bvsrestraint.py +++ b/src/diffpy/srfit/structure/bvsrestraint.py @@ -47,7 +47,7 @@ class BVSRestraint(Restraint): def __init__(self, parset, sig=1, scaled=False): """Initialize the Restraint. - Attributes + Parameters ---------- parset SrRealParSet that creates this BVSRestraint. @@ -69,7 +69,7 @@ def __init__(self, parset, sig=1, scaled=False): def penalty(self, w=1.0): """Calculate the penalty of the restraint. - Attributes + Parameters ---------- w The point-average chi^2 which is optionally used to scale the diff --git a/src/diffpy/srfit/structure/cctbxparset.py b/src/diffpy/srfit/structure/cctbxparset.py index e546e61d..544d1f3f 100644 --- a/src/diffpy/srfit/structure/cctbxparset.py +++ b/src/diffpy/srfit/structure/cctbxparset.py @@ -56,7 +56,7 @@ class CCTBXScattererParSet(ParameterSet): def __init__(self, name, strups, idx): """Initialize. - Attributes + Parameters ---------- name The name of this scatterer. @@ -153,7 +153,7 @@ class CCTBXUnitCellParSet(ParameterSet): def __init__(self, strups): """Initialize. - Attributes + Parameters ---------- strups The CCTBXCrystalParSet that contains the cctbx structure @@ -228,7 +228,7 @@ class CCTBXCrystalParSet(BaseStructureParSet): def __init__(self, name, stru): """Initialize. - Attributes + Parameters ---------- name A name for this diff --git a/src/diffpy/srfit/structure/diffpyparset.py b/src/diffpy/srfit/structure/diffpyparset.py index 0a22685f..452dd6ed 100644 --- a/src/diffpy/srfit/structure/diffpyparset.py +++ b/src/diffpy/srfit/structure/diffpyparset.py @@ -91,7 +91,7 @@ class DiffpyAtomParSet(ParameterSet): def __init__(self, name, atom): """Initialize. - Attributes + Parameters ---------- atom A diffpy.structure.Atom instance @@ -205,7 +205,7 @@ class DiffpyLatticeParSet(ParameterSet): def __init__(self, lattice): """Initialize. - Attributes + Parameters ---------- lattice A diffpy.structure.Lattice instance @@ -275,7 +275,7 @@ class DiffpyStructureParSet(SrRealParSet): def __init__(self, name, stru): """Initialize. - Attributes + Parameters ---------- name A name for the structure diff --git a/src/diffpy/srfit/structure/objcrystparset.py b/src/diffpy/srfit/structure/objcrystparset.py index 4264b02d..25cd50d8 100644 --- a/src/diffpy/srfit/structure/objcrystparset.py +++ b/src/diffpy/srfit/structure/objcrystparset.py @@ -114,7 +114,7 @@ class ObjCrystScattererParSet(ParameterSet): def __init__(self, name, scat, parent): """Initialize. - Attributes + Parameters ---------- name The name of the scatterer @@ -176,7 +176,7 @@ class ObjCrystAtomParSet(ObjCrystScattererParSet): def __init__(self, name, atom, parent): """Initialize. - Attributes + Parameters ---------- name The name of the scatterer @@ -252,7 +252,7 @@ class ObjCrystMoleculeParSet(ObjCrystScattererParSet): def __init__(self, name, molecule, parent=None): """Initialize. - Attributes + Parameters ---------- name The name of the scatterer @@ -433,7 +433,7 @@ def restrainBondLength( This creates an instance of ObjCrystBondLengthRestraint and adds it to the ObjCrystMoleculeParSet. - Attributes + Parameters ---------- atom1 First atom (ObjCrystMolAtomParSet) in the bond @@ -471,7 +471,7 @@ def restrainBondLengthParameter( This creates an instance of ObjCrystBondLengthRestraint and adds it to the ObjCrystMoleculeParSet. - Attributes + Parameters ---------- par A ObjCrystBondLengthParameter (see addBondLengthParameter) @@ -504,7 +504,7 @@ def restrainBondAngle( This creates an instance of ObjCrystBondAngleRestraint and adds it to the ObjCrystMoleculeParSet. - Attributes + Parameters ---------- atom1 First atom (ObjCrystMolAtomParSet) in the bond angle @@ -545,7 +545,7 @@ def restrainBondAngleParameter( This creates an instance of ObjCrystBondAngleRestraint and adds it to the ObjCrystMoleculeParSet. - Attributes + Parameters ---------- par A ObjCrystBondAngleParameter (see addBondAngleParameter) @@ -578,7 +578,7 @@ def restrainDihedralAngle( This creates an instance of ObjCrystDihedralAngleRestraint and adds it to the ObjCrystMoleculeParSet. - Attributes + Parameters ---------- atom1 First atom (ObjCrystMolAtomParSet) in the angle @@ -620,7 +620,7 @@ def restrainDihedralAngleParameter( This creates an instance of ObjCrystDihedralAngleRestraint and adds it to the ObjCrystMoleculeParSet. - Attributes + Parameters ---------- par A ObjCrystDihedralAngleParameter (see @@ -661,7 +661,7 @@ def addBondLengthParameter( This creates a ObjCrystBondLengthParameter to the ObjCrystMoleculeParSet that can be adjusted during the fit. - Attributes + Parameters ---------- name The name of the ObjCrystBondLengthParameter @@ -696,7 +696,7 @@ def addBondAngleParameter( This creates a ObjCrystBondAngleParameter to the ObjCrystMoleculeParSet that can be adjusted during the fit. - Attributes + Parameters ---------- name The name of the ObjCrystBondAngleParameter @@ -736,7 +736,7 @@ def addDihedralAngleParameter( This creates a ObjCrystDihedralAngleParameter to the ObjCrystMoleculeParSet that can be adjusted during the fit. - Attributes + Parameters ---------- name The name of the ObjCrystDihedralAngleParameter. @@ -809,7 +809,7 @@ class ObjCrystMolAtomParSet(ObjCrystScattererParSet): def __init__(self, name, scat, parent): """Initialize. - Attributes + Parameters ---------- name The name of the scatterer @@ -881,7 +881,7 @@ class ObjCrystMoleculeRestraint(object): def __init__(self, res, scaled=False): """Create a Restraint-like from a pyobjcryst Molecule restraint. - Attributes + Parameters ---------- res The pyobjcryst Molecule restraint. @@ -897,7 +897,7 @@ def __init__(self, res, scaled=False): def penalty(self, w=1.0): """Calculate the penalty of the restraint. - Attributes + Parameters ---------- w The point-average chi^2 which is optionally used to scale the @@ -938,7 +938,7 @@ class ObjCrystBondLengthRestraint(ObjCrystMoleculeRestraint): def __init__(self, atom1, atom2, length, sigma, delta, scaled=False): """Create a bond length restraint. - Attributes + Parameters ---------- atom1 First atom (ObjCrystMolAtomParSet) in the bond @@ -1010,7 +1010,7 @@ class ObjCrystBondAngleRestraint(ObjCrystMoleculeRestraint): def __init__(self, atom1, atom2, atom3, angle, sigma, delta, scaled=False): """Create a bond angle restraint. - Attributes + Parameters ---------- atom1 First atom (ObjCrystMolAtomParSet) in the bond angle @@ -1092,7 +1092,7 @@ def __init__( ): """Create a dihedral angle restraint. - Attributes + Parameters ---------- atom1 First atom (ObjCrystMolAtomParSet) in the angle @@ -1168,7 +1168,7 @@ class StretchModeParameter(Parameter): def __init__(self, name, value=None, const=False): """Initialization. - Attributes + Parameters ---------- name The name of this Parameter (must be a valid attribute @@ -1314,7 +1314,7 @@ class ObjCrystBondLengthParameter(StretchModeParameter): def __init__(self, name, atom1, atom2, value=None, const=False, mode=None): """Create a ObjCrystBondLengthParameter. - Attributes + Parameters ---------- name The name of the ObjCrystBondLengthParameter @@ -1368,7 +1368,7 @@ def set_constant(self, is_constant=True, value=None): This sets the underlying ObjCrystMolAtomParSet positions constant as well. - Attributes + Parameters ---------- is_constant Flag indicating if the Parameter is constant (default @@ -1472,7 +1472,7 @@ def __init__( ): """Create a ObjCrystBondAngleParameter. - Attributes + Parameters ---------- name The name of the ObjCrystBondAngleParameter. @@ -1531,7 +1531,7 @@ def set_constant(self, is_constant=True, value=None): This sets the underlying ObjCrystMolAtomParSet positions constant as well. - Attributes + Parameters ---------- is_constant Flag indicating if the Parameter is constant (default @@ -1649,7 +1649,7 @@ def __init__( ): """Create a ObjCrystDihedralAngleParameter. - Attributes + Parameters ---------- name The name of the ObjCrystDihedralAngleParameter @@ -1712,7 +1712,7 @@ def set_constant(self, is_constant=True, value=None): This sets the underlying ObjCrystMolAtomParSet positions const as well. - Attributes + Parameters ---------- is_constant Flag indicating if the Parameter is constant (default @@ -1806,7 +1806,7 @@ class ObjCrystCrystalParSet(SrRealParSet): def __init__(self, name, cryst): """Initialize. - Attributes + Parameters ---------- name A name for this ParameterSet @@ -1881,7 +1881,7 @@ def _constrain_space_group(self): def _create_space_group(sgobjcryst): """Create a diffpy.structure SpaceGroup object from pyobjcryst. - Attributes + Parameters ---------- sgobjcryst A pyobjcryst.spacegroup.SpaceGroup instance. diff --git a/src/diffpy/srfit/structure/sgconstraints.py b/src/diffpy/srfit/structure/sgconstraints.py index 2faab6fb..666e360d 100644 --- a/src/diffpy/srfit/structure/sgconstraints.py +++ b/src/diffpy/srfit/structure/sgconstraints.py @@ -190,7 +190,7 @@ def __init__(self, name="sgpars"): def addParameter(self, par, check=True): """Store a Parameter. - Attributes + Parameters ---------- par The Parameter to be stored. @@ -470,7 +470,7 @@ def _constrain_lattice(self): def _constrain_xyzs(self, positions): """Constrain the positions. - Attributes + Parameters ---------- positions The coordinates of the scatterers. @@ -513,7 +513,7 @@ def _constrain_xyzs(self, positions): def _constrain_adps(self, positions): """Constrain the ADPs. - Attributes + Parameters ---------- positions The coordinates of the scatterers. @@ -618,7 +618,7 @@ def _constrain_adps(self, positions): def __add_par(self, parname, par): """Constrain a parameter via proxy with a specified name. - Attributes + Parameters ---------- par Parameter to constrain @@ -772,7 +772,7 @@ def _constrain_cubic(lattice): def _makeconstraint(parname, formula, scatterer, idx, ns={}): """Constrain a parameter according to a formula. - Attributes + Parameters ---------- parname Name of parameter diff --git a/src/diffpy/srfit/structure/srrealparset.py b/src/diffpy/srfit/structure/srrealparset.py index 5a5e5028..4ed31ffc 100644 --- a/src/diffpy/srfit/structure/srrealparset.py +++ b/src/diffpy/srfit/structure/srrealparset.py @@ -52,7 +52,7 @@ def restrainBVS(self, sig=1, scaled=False): this is also scaled by the current point-averaged chi^2 value so the restraint is roughly equally weighted in the fit. - Attributes + Parameters ---------- sig The uncertainty on the BVS (default 1). diff --git a/src/diffpy/srfit/util/inpututils.py b/src/diffpy/srfit/util/inpututils.py index f2e0a9df..1e0d83fa 100644 --- a/src/diffpy/srfit/util/inpututils.py +++ b/src/diffpy/srfit/util/inpututils.py @@ -26,7 +26,7 @@ def inputToString(input): This is useful when you want a method to accept a string, open file object or file name. - Attributes + Parameters ---------- input An open file-like object, name of a file diff --git a/src/diffpy/srfit/util/tagmanager.py b/src/diffpy/srfit/util/tagmanager.py index 9e981d64..37c58a3d 100644 --- a/src/diffpy/srfit/util/tagmanager.py +++ b/src/diffpy/srfit/util/tagmanager.py @@ -53,7 +53,7 @@ def tag(self, obj, *tags): Tags are stored as strings. - Attributes + Parameters ---------- obj Any hashable object to be untagged. @@ -71,7 +71,7 @@ def tag(self, obj, *tags): def untag(self, obj, *tags): """Remove tags from an object. - Attributes + Parameters ---------- obj Any hashable object to be untagged. From 35ada985ec9670252816b53c107d62dd89cf8e11 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 11:58:53 -0400 Subject: [PATCH 168/193] boundRange --> bound_range --- src/diffpy/srfit/fitbase/parameter.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/diffpy/srfit/fitbase/parameter.py b/src/diffpy/srfit/fitbase/parameter.py index d9a82b13..b22192e4 100644 --- a/src/diffpy/srfit/fitbase/parameter.py +++ b/src/diffpy/srfit/fitbase/parameter.py @@ -46,6 +46,10 @@ parameter_base, "setConst", "set_constant", removal_version ) +boundRange_dep_msg = build_deprecation_message( + parameter_base, "boundRange", "bound_range", removal_version +) + class Parameter(_parameter_interface, Argument, Validatable): """Parameter class. @@ -156,7 +160,7 @@ def setConst(self, const=True, value=None): self.set_constant(const, value) return self - def boundRange(self, lower_bound=None, upper_bound=None): + def bound_range(self, lower_bound=None, upper_bound=None): """Set lower and upper bound of the Parameter. Parameters @@ -177,6 +181,16 @@ def boundRange(self, lower_bound=None, upper_bound=None): self.bounds[1] = upper_bound return self + @deprecated(boundRange_dep_msg) + def boundRange(self, lower_bound=None, upper_bound=None): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use diffpy.srfit.fitbase.Parameter.bound_range instead. + """ + self.bound_range(lower_bound, upper_bound) + return self + def boundWindow(self, lr=0, ur=None): """Create bounds centered on the current value of the Parameter. @@ -296,9 +310,9 @@ def getValue(self): def set_constant(self, const=True, value=None): return self.par.set_constant(const, value) - @wraps(Parameter.boundRange) - def boundRange(self, lower_bound=None, upper_bound=None): - return self.par.boundRange(lower_bound, upper_bound) + @wraps(Parameter.bound_range) + def bound_range(self, lower_bound=None, upper_bound=None): + return self.par.bound_range(lower_bound, upper_bound) @wraps(Parameter.boundWindow) def boundWindow(self, lr=0, ur=None): From cbbddf58bef7c1e1f673fa6847b280dd37a28e21 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 12:11:26 -0400 Subject: [PATCH 169/193] boundWindow --> bound_window --- src/diffpy/srfit/fitbase/parameter.py | 40 ++++++++++++++++++--------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/diffpy/srfit/fitbase/parameter.py b/src/diffpy/srfit/fitbase/parameter.py index b22192e4..4fa2c2b6 100644 --- a/src/diffpy/srfit/fitbase/parameter.py +++ b/src/diffpy/srfit/fitbase/parameter.py @@ -50,6 +50,10 @@ parameter_base, "boundRange", "bound_range", removal_version ) +boundWindow_dep_msg = build_deprecation_message( + parameter_base, "boundWindow", "bound_window", removal_version +) + class Parameter(_parameter_interface, Argument, Validatable): """Parameter class. @@ -191,18 +195,18 @@ def boundRange(self, lower_bound=None, upper_bound=None): self.bound_range(lower_bound, upper_bound) return self - def boundWindow(self, lr=0, ur=None): + def bound_window(self, lower_radius=0, upper_radius=None): """Create bounds centered on the current value of the Parameter. Parameters ---------- - lr + lower_radius : float, optional The radius of the lower bound (default 0). The lower bound is - computed as value - lr. - ur + computed as value - lower_radius. + upper_radius : float, optional The radius of the upper bound. The upper bound is computed as - value + ur. If this is None (default), then the value of the - lower radius is used. + value + upper_radius. If this is None (default), then the value + of the lower radius is used. Returns ------- @@ -210,13 +214,23 @@ def boundWindow(self, lr=0, ur=None): Returns self so that mutators can be chained. """ val = self.getValue() - lower_bound = val - lr - if ur is None: - ur = lr - upper_bound = val + ur + lower_bound = val - lower_radius + if upper_radius is None: + upper_radius = lower_radius + upper_bound = val + upper_radius self.bounds = [lower_bound, upper_bound] return self + @deprecated(boundWindow_dep_msg) + def boundWindow(self, lr=0, ur=None): + """This function has been deprecated and will be removed in + version 4.0.0. + + Please use diffpy.srfit.fitbase.Parameter.bound_window instead. + """ + self.bound_window(lr, ur) + return self + def _validate(self): """Validate my state. @@ -314,9 +328,9 @@ def set_constant(self, const=True, value=None): def bound_range(self, lower_bound=None, upper_bound=None): return self.par.bound_range(lower_bound, upper_bound) - @wraps(Parameter.boundWindow) - def boundWindow(self, lr=0, ur=None): - return self.par.boundWindow(lr, ur) + @wraps(Parameter.bound_window) + def bound_window(self, lr=0, ur=None): + return self.par.bound_window(lr, ur) def _validate(self): """Validate my state. From 959c6f28f43e5a3b413c7d32b334c7df663056de Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 12:11:47 -0400 Subject: [PATCH 170/193] write tests for bound_window and bound_range --- tests/test_parameter.py | 93 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/tests/test_parameter.py b/tests/test_parameter.py index 90606179..a56d3ddf 100644 --- a/tests/test_parameter.py +++ b/tests/test_parameter.py @@ -16,6 +16,9 @@ import unittest +import numpy as np +import pytest + from diffpy.srfit.fitbase.parameter import ( Parameter, ParameterAdapter, @@ -121,5 +124,95 @@ def testWrapper(self): return +@pytest.mark.parametrize( + "lower, upper, expected", + [ + # User sets both lower and upper bounds explicitly. + (1, 10, [1, 10]), + # User sets only a lower bound. + (2, None, [2, np.inf]), + # User sets only an upper bound. + (None, 8, [-np.inf, 8]), + # User overwrites existing bounds. + (2, 6, [2, 6]), + ], +) +def test_bound_range(lower, upper, expected): + p = Parameter("a", value=5) + # If testing overwrite, pre-set bounds to see overwrite effect + if expected == [2, 6]: + p.bound_range(0, 10) + p.bound_range(lower_bound=lower, upper_bound=upper) + actual = p.bounds + assert actual == expected + + +@pytest.mark.parametrize( + "lower, upper, expected", + [ + # User sets both lower and upper bounds explicitly. + (1, 10, [1, 10]), + # User sets only a lower bound. + (2, None, [2, np.inf]), + # User sets only an upper bound. + (None, 8, [-np.inf, 8]), + # User overwrites existing bounds. + (2, 6, [2, 6]), + ], +) +def test_boundRange(lower, upper, expected): + p = Parameter("a", value=5) + # If testing overwrite, pre-set bounds to see overwrite effect + if expected == [2, 6]: + p.boundRange(0, 10) + p.boundRange(lower_bound=lower, upper_bound=upper) + actual = p.bounds + assert actual == expected + + +@pytest.mark.parametrize( + "value, lower_radius, upper_radius, expected", + [ + # Symmetric radius (upper_radius None, uses lower_radius) + (10, 2, None, [8, 12]), + # Asymmetric radius + (10, 3, 5, [7, 15]), + # Zero radius + (4, 0, None, [4, 4]), + # Current value updated before bounding + (20, 2, None, [18, 22]), + ], +) +def test_bound_window(value, lower_radius, upper_radius, expected): + p = Parameter("a", value=5) + if value != 5: + p.set_value(value) + p.bound_window(lower_radius=lower_radius, upper_radius=upper_radius) + actual = p.bounds + assert actual == expected + + +@pytest.mark.parametrize( + "value, lower_radius, upper_radius, expected", + [ + # Symmetric radius (upper_radius None, uses lower_radius) + (10, 2, None, [8, 12]), + # Asymmetric radius + (10, 3, 5, [7, 15]), + # Zero radius + (4, 0, None, [4, 4]), + # Current value updated before bounding + (20, 2, None, [18, 22]), + ], +) +def test_boundWindow(value, lower_radius, upper_radius, expected): + p = Parameter("a", value=5) + if value != 5: + p.set_value(value) + p.boundWindow(lr=lower_radius, ur=upper_radius) + actual = p.bounds + assert actual == expected + + if __name__ == "__main__": unittest.main() From b9fe12740a0ce046bc4d7b54542fc1977f3a6c17 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 12:13:31 -0400 Subject: [PATCH 171/193] news --- news/param-dep.rst | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 news/param-dep.rst diff --git a/news/param-dep.rst b/news/param-dep.rst new file mode 100644 index 00000000..e0b8eabe --- /dev/null +++ b/news/param-dep.rst @@ -0,0 +1,27 @@ +**Added:** + +* Added ``is_constant`` method to ``Parameter``. +* Added ``bound_range`` method to ``Parameter``. +* Added ``bound_window`` method to ``Parameter``. + +**Changed:** + +* + +**Deprecated:** + +* Deprecated ``isConst`` method of ``Parameter``. Use ``is_constant`` instead. +* Deprecated ``boundRange`` method of ``Parameter``. Use ``bound_range`` instead. +* Deprecated ``boundWindow`` method of ``Parameter``. Use ``bound_window`` instead. + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From ec2b2af015b22d638060f8501e5bbc0bc900b69f Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 12:25:11 -0400 Subject: [PATCH 172/193] minor docstring fix --- src/diffpy/srfit/interface/interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diffpy/srfit/interface/interface.py b/src/diffpy/srfit/interface/interface.py index 08748728..308e0471 100644 --- a/src/diffpy/srfit/interface/interface.py +++ b/src/diffpy/srfit/interface/interface.py @@ -40,7 +40,7 @@ def __lshift__(self, v): Think of '<<' as injecting a value - Parameters + Attributes ---------- v value or Argument derivative From de843cf1e6057c670f24e51396121f3fd59c481a Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 20:14:01 -0400 Subject: [PATCH 173/193] deprecate PDFParser --- src/diffpy/srfit/pdf/pdfparser.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/diffpy/srfit/pdf/pdfparser.py b/src/diffpy/srfit/pdf/pdfparser.py index 75d9c81f..bfb10a15 100644 --- a/src/diffpy/srfit/pdf/pdfparser.py +++ b/src/diffpy/srfit/pdf/pdfparser.py @@ -28,6 +28,19 @@ from diffpy.srfit.exceptions import ParseError from diffpy.srfit.fitbase.profileparser import ProfileParser +from diffpy.utils._deprecator import build_deprecation_message, deprecated + +removal_verison = "4.0.0" +base = "diffpy.srfit.pdf.pdfparser.PDFParser" +new_base = "diffpy.srfit.fitbase.ProfileParser" + +parseFile_dep_msg = build_deprecation_message( + base, + "parseFile", + "parse_file", + removal_version=removal_verison, + new_base=new_base, +) class PDFParser(ProfileParser): @@ -106,6 +119,11 @@ class PDFParser(ProfileParser): _format = "PDF" + # Marking this function as deprecated because PDFParser.parseFile calls it + # so when people use PDFParser.parseFile, they will get a + # warning that it is deprecated and they should use + # ProfileParser.parse_file instead. + @deprecated(parseFile_dep_msg) def parseString(self, patstring): """Parse a string and set the _x, _y, _dx, _dy and _meta variables. @@ -121,6 +139,7 @@ def parseString(self, patstring): Raises ParseError if the string cannot be parsed """ + # useful regex patterns: rx = {"f": r"[-+]?(\d+(\.\d*)?|\d*\.\d+)([eE][-+]?\d+)?"} # find where does the data start From 567c8a1af9185a4793a321cc12130293c1c22f1f Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 20:17:24 -0400 Subject: [PATCH 174/193] build parse_file and deprecate getNumBank, selectBank, getFormat, getData, and getMetaData --- src/diffpy/srfit/fitbase/profileparser.py | 287 +++++++++++++++++++--- 1 file changed, 255 insertions(+), 32 deletions(-) diff --git a/src/diffpy/srfit/fitbase/profileparser.py b/src/diffpy/srfit/fitbase/profileparser.py index b152164b..7260a66d 100644 --- a/src/diffpy/srfit/fitbase/profileparser.py +++ b/src/diffpy/srfit/fitbase/profileparser.py @@ -23,7 +23,56 @@ """ +from pathlib import Path + +import numpy as np + from diffpy.srfit.exceptions import ParseError +from diffpy.utils._deprecator import build_deprecation_message, deprecated +from diffpy.utils.parsers import load_data + +removal_verison = "4.0.0" +pdfparser_base = "diffpy.srfit.pdf.pdfparser.PDFParser" +new_base = "diffpy.srfit.fitbase.ProfileParser" + + +parseFile_dep_msg = build_deprecation_message( + pdfparser_base, + "parseFile", + "parse_file", + removal_verison, + new_base=new_base, +) + +pp_base = "diffpy.srfit.fitbase.profileparser.ProfileParser" + +getNumBanks_dep_msg = build_deprecation_message( + pp_base, + "getNumBanks", + "get_num_banks", + removal_verison, +) + +selectBank_dep_msg = build_deprecation_message( + pp_base, + "selectBank", + "select_bank", + removal_verison, +) + +getData_dep_msg = build_deprecation_message( + pp_base, + "getData", + "get_data", + removal_verison, +) + +getMetaData_dep_msg = build_deprecation_message( + pp_base, + "getMetaData", + "get_metadata", + removal_verison, +) class ProfileParser(object): @@ -31,48 +80,47 @@ class ProfileParser(object): Attributes ---------- - _format - Name of the data format that this parses (string, default - ""). The format string is a unique identifier for the data + _format : str, optional + The name of the data format that this parses (string, default + `""`). The format string is a unique identifier for the data format handled by the parser. - _banks + _banks : list of tuples The data from each bank. Each bank contains a (x, y, dx, dy) tuple: - x - A numpy array containing the independent - variable read from the file. - y - A numpy array containing the profile + x : np.ndarray + The independent variable read from the file. + y : np.ndarray + The dependent variable (profile) read from the file. - dx - A numpy array containing the uncertainty in x - read from the file. This is None if the + dx : np.ndarray + The uncertainties associated with x + read from the file. This is 0 if the + uncertainty cannot be read. + dy : np.ndarray + The uncertainties associated with y + read from the file. This is 0 if the uncertainty cannot be read. - dy - A numpy array containing the uncertainty read - from the file. This is None if the uncertainty - cannot be read. - _x + _x : np.ndarray Independent variable from the chosen bank - _y + _y : np.ndarray Profile from the chosen bank - _dx + _dx : np.ndarray Uncertainty in independent variable from the chosen bank - _dy + _dy : np.ndarray Uncertainty in profile from the chosen bank - _meta + _meta : dict A dictionary containing metadata read from the file. General Metadata ---------------- - filename + filename : str or Path The name of the file from which data was parsed. This key will not exist if data was not read from file. - nbanks + nbanks : int The number of banks parsed. - bank + bank : int The chosen bank number. """ @@ -110,6 +158,8 @@ def parseString(self, patstring): """ raise NotImplementedError() + # remove parseString too when this file is removed. + @deprecated(parseFile_dep_msg) def parseFile(self, filename): """Parse a file and set the _x, _y, _dx, _dy and _meta variables. @@ -135,14 +185,151 @@ def parseFile(self, filename): if len(self._banks) < 1: raise ParseError("There are no data in the banks") - self.selectBank(0) + self.select_bank(0) return - def getNumBanks(self): - """Get the number of banks read by the parser.""" + def parse_file(self, filename, column_format=None): + """Parse a data file and extract data and metadata with + automatic uncertainty detection. + + - For files with 2 columns: assumes (x, y) and sets dx, dy to 0. + - For files with 3 columns: assumes (x, y, dy) and sets dx to 0. + - For files with 4 columns: assumes (x, y, dx, dy). + - For other cases: `column_format` must be explicitly specified. + + Uncertainty columns (dx, dy) are only considered valid if all values + are positive and not NaN/Inf. Otherwise they are set to 0. + + This wipes out the currently loaded data and selected bank number. + + Parameters + ---------- + filename : str or Path + The name of the file to parse. + column_format : tuple of str, optional + The order in which columns appear in the file. + If None, the format is auto-detected based on the + number of columns. + + Valid labels: `"x"`, `"y"`, `"dx"`, `"dy"` + + Examples: + + - `("x", "y")` + - `("x", "y", "dy")` + - `("x", "y", "dx", "dy")` + - `("x", "dx", "y", "dy")` + + Raises + ------ + ParseError + If parsing fails or ambiguity detected. + """ + # Reset internal state + self._banks = [] + if isinstance(filename, Path): + filename = str(filename) + # Load metadata and numeric data + self._meta, data = self._load_file(filename) + column_format = self._detect_column_format(data, column_format) + # Map columns to x, y, dx, dy + columns = self._map_column_labels_to_data(data, column_format) + # Extract required arrays + x = columns["x"] + y = columns["y"] + x_length = len(x) + y_length = len(y) + dx = self._validate_uncertainty(columns.get("dx"), x_length) + dy = self._validate_uncertainty(columns.get("dy"), y_length) + # Store as single bank + self._banks = [(x, y, dx, dy)] + self._meta["nbanks"] = 1 + self.select_bank(0) + + # --- Private helpers --- # + + def _load_file(self, filename): + """Load metadata and numeric data from a file.""" + meta = load_data(filename, headers=True) + meta["filename"] = filename + data = load_data(filename) + if data.size == 0 or (data.ndim == 1): + raise ParseError( + "Data block must have at least two columns (x, y)." + ) + return meta, data + + def _detect_column_format(self, data, column_format): + """Auto-detect or validate column format.""" + num_cols = data.shape[1] + + if column_format is None: + if num_cols == 2: + column_format = ("x", "y") + elif num_cols == 3: + column_format = ("x", "y", "dy") + elif num_cols == 4: + column_format = ("x", "y", "dx", "dy") + else: + raise ParseError( + f"Expected 2 to 4 columns but found {num_cols}." + ) + if len(column_format) != num_cols: + raise ParseError( + f"column_format has {len(column_format)} " + f"labels but file contains {num_cols} columns." + ) + if len(set(column_format)) != len(column_format): + raise ParseError("column_format cannot contain duplicate labels.") + for label in column_format: + if label not in {"x", "y", "dx", "dy"}: + raise ParseError( + f"column_format contains invalid label '{label}'. " + "Valid labels are 'x', 'y', 'dx', and 'dy'." + ) + return column_format + + def _map_column_labels_to_data(self, data, column_format): + """Map numeric data to columns by label.""" + columns = {} + for i, label in enumerate(column_format): + columns[label] = data[:, i] + + if "x" not in columns or "y" not in columns: + raise ParseError( + "Both 'x' and 'y' columns must be present in the data." + ) + + return columns + + @staticmethod + def _validate_uncertainty(data, length): + """Return the uncertainty data if valid, otherwise 0.""" + if data is None or not np.all(np.isfinite(data)) or np.any(data <= 0): + return np.zeros(length) + return data + + def get_num_banks(self): + """Get the number of banks read by the parser. + + Returns + ------- + int + The number of banks read by the parser. + """ return len(self._banks) - def selectBank(self, index): + @deprecated(getNumBanks_dep_msg) + def getNumBanks(self): + """This function is deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.ProfileParser.get_num_banks + instead. + """ + return self.get_num_banks() + + def select_bank(self, index): """Select which bank to use. This method should only be called after the data has been parsed. The @@ -160,7 +347,7 @@ def selectBank(self, index): if index is None: index = self._meta.get("bank", 0) - numbanks = self.getNumBanks() + numbanks = self.get_num_banks() if index > numbanks: raise IndexError("Bank index out of range") @@ -175,7 +362,18 @@ def selectBank(self, index): self._x, self._y, self._dx, self._dy = self._banks[index] return - def getData(self, index=None): + @deprecated(selectBank_dep_msg) + def selectBank(self, index): + """This function is deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.ProfileParser.select_bank + instead. + """ + self.select_bank(index) + return + + def get_data(self, index=None): """Get the data. This method should only be called after the data has been parsed. The @@ -192,12 +390,37 @@ def getData(self, index=None): This returns (x, y, dx, dy) tuple for the bank. dx is 0 if it cannot be determined from the data format. """ - self.selectBank(index) + self.select_bank(index) return self._x, self._y, self._dx, self._dy + @deprecated(getData_dep_msg) + def getData(self, index=None): + """This function is deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.ProfileParser.get_data instead. + """ + return self.get_data(index) + + def get_metadata(self): + """Get the parsed metadata. + + Returns + ------- + dict + A dictionary containing metadata read from the file. + """ + return self._meta + + @deprecated(getMetaData_dep_msg) def getMetaData(self): - """Get the parsed metadata.""" + """This function is deprecated and will be removed in version + 4.0.0. + + Please use diffpy.srfit.fitbase.ProfileParser.get_metadata + instead. + """ return self._meta From 172fced6e50219fe21b3e99652110c9d005eec8d Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 20:17:52 -0400 Subject: [PATCH 175/193] add ProfileParser to __init__ so it can be imported from fitbase --- src/diffpy/srfit/fitbase/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/diffpy/srfit/fitbase/__init__.py b/src/diffpy/srfit/fitbase/__init__.py index bdbcb2d1..ce68fa7d 100644 --- a/src/diffpy/srfit/fitbase/__init__.py +++ b/src/diffpy/srfit/fitbase/__init__.py @@ -39,6 +39,7 @@ "Profile", "ProfileGenerator", "SimpleRecipe", + "ProfileParser", ] from diffpy.srfit.fitbase.calculator import Calculator @@ -48,6 +49,7 @@ 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.profileparser import ProfileParser from diffpy.srfit.fitbase.simplerecipe import SimpleRecipe # End of file From 9680c770be7160ff78dbd6fdd4fa9645243aeb38 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 20:18:23 -0400 Subject: [PATCH 176/193] add test files as conftest fixture --- tests/conftest.py | 99 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index 6eb797c3..25714656 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -269,3 +269,102 @@ def temp_data_files(tmp_path): """ ) yield tmp_path + + +@pytest.fixture +def parser_datafile(tmp_path): + """Create temporary data files with different column layouts and + yield the directory.""" + + METADATA_HEADER = r"""# xPDFsuite Configuration # +[PDF] +wavelength = 0.1 +dataformat = QA +inputfile = input.iq +backgroundfile = backgroundfile.iq +mode = xray +bgscale = 1.0 +composition = TiSe2 +outputtype = gr +qmaxinst = 25.0 +qmin = 0.1 +qmax = 25.0 +rmax = 140.0 +rmin = 0.0 +rstep = 0.01 +rpoly = 0.7 + +[Misc] +inputdir = /my/data/dir +savedir = /my/save/dir +backgroundfilefull = /my/data/dir/backgroundfile.iq + +#### start data +#S 1 +""" + + # Four-column standard + (tmp_path / "four_col.gr").write_text( + METADATA_HEADER + + r"""#L r($\AA$) G($\AA^{-2}$) dr($\AA$) dG($\AA^{-2}$) +1.0 2.0 0.1 0.2 +1.1 2.1 0.3 0.4 +1.2 2.2 0.5 0.6""" + ) + + # Three-column (x, y, dy) + (tmp_path / "three_col.dat").write_text( + METADATA_HEADER + + r"""#L r($\AA$) G($\AA^{-2}$) dG($\AA^{-2}$) +1.0 2.0 0.2 +1.1 2.1 0.4 +1.2 2.2 0.6""" + ) + + # Two-column (x, y) + (tmp_path / "two_col.txt").write_text( + METADATA_HEADER + + r"""#L r($\AA$) G($\AA^{-2}$) +1.0 2.0 +1.1 2.1 +1.2 2.2""" + ) + + # Four-column reordered (x, dx, y, dy) + (tmp_path / "four_col_reordered.txt").write_text( + METADATA_HEADER + + r"""#L r($\AA$) dr($\AA$) G($\AA^{-2}$) dG($\AA^{-2}$) +1.0 0.1 2.0 0.2 +1.1 0.3 2.1 0.4 +1.2 0.5 2.2 0.6""" + ) + + # Four-column with NaN/Inf + (tmp_path / "four_col_nan_inf.gr").write_text( + METADATA_HEADER + + r"""#L r($\AA$) G($\AA^{-2}$) dr($\AA$) dG($\AA^{-2}$) +1.0 2.0 nan inf +1.1 2.1 inf 1 +1.2 2.2 nan nan""" + ) + + # One-column + (tmp_path / "one_col.gr").write_text( + METADATA_HEADER + + r"""#L r($\AA$) +1.0 +1.1 +1.2""" + ) + + # Five-column (extra column) + (tmp_path / "five_col.gr").write_text( + METADATA_HEADER + + r"""#L r($\AA$) G($\AA^{-2}$) dr($\AA$) dG($\AA^{-2}$) extra +1.0 2.0 0.1 0.2 9.9 +1.1 2.1 0.3 0.4 9.8 +1.2 2.2 0.5 0.6 9.7""" + ) + + # Yield the directory + yield tmp_path From 5568579d0b7cd22581b513c421d782ff716b74bd Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 20:19:05 -0400 Subject: [PATCH 177/193] use ProfileParser in PDFContribution, replacing PDFParser --- src/diffpy/srfit/pdf/pdfcontribution.py | 26 +++++++------------------ 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/diffpy/srfit/pdf/pdfcontribution.py b/src/diffpy/srfit/pdf/pdfcontribution.py index c884641b..73e666ea 100644 --- a/src/diffpy/srfit/pdf/pdfcontribution.py +++ b/src/diffpy/srfit/pdf/pdfcontribution.py @@ -20,7 +20,7 @@ __all__ = ["PDFContribution"] -from diffpy.srfit.fitbase import FitContribution, Profile +from diffpy.srfit.fitbase import FitContribution, Profile, ProfileParser class PDFContribution(FitContribution): @@ -105,28 +105,16 @@ def __init__(self, name): # Data methods - def loadData(self, data): - """Load the data in various formats. - - This uses the PDFParser to load the data and then passes it to the - built-in profile with load_parsed_data. + def loadData(self, datafile): + """Load the data from a datafile. Parameters ---------- - data - An open file-like object, name of a file that contains data - or a string containing the data. + data : str or Path + The path to the data file. """ - # 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) + parser = ProfileParser() + parser.parse_file(datafile) # Pass it to the profile self.profile.load_parsed_data(parser) From 937e11f3b3b4415a265f750aa53c60e6f69af035 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 20:21:03 -0400 Subject: [PATCH 178/193] Use ProfileParser instead of PDFParser for fitrecipe testing --- tests/test_fitrecipe.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 4da38ab8..b697f531 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -23,7 +23,7 @@ from numpy import array_equal, dot, linspace, pi, sin from scipy.optimize import leastsq -from diffpy.srfit.fitbase import FitResults +from diffpy.srfit.fitbase import FitResults, ProfileParser from diffpy.srfit.fitbase.fitcontribution import FitContribution from diffpy.srfit.fitbase.fitrecipe import FitRecipe from diffpy.srfit.fitbase.parameter import Parameter @@ -655,8 +655,8 @@ def build_recipe_from_datafile(datafile): """Helper to build a FitRecipe from a datafile using PDFParser and PDFGenerator.""" profile = Profile() - parser = PDFParser() - parser.parseFile(str(datafile)) + parser = ProfileParser() + parser.parse_file(str(datafile)) profile.load_parsed_data(parser) contribution = FitContribution("c") From 97cfc58cae8a7188761d3b227d9372a025d2b1fe Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 20:21:52 -0400 Subject: [PATCH 179/193] getData --> get_data, and getMetaData --> get_metadata in Profile --- src/diffpy/srfit/fitbase/profile.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/diffpy/srfit/fitbase/profile.py b/src/diffpy/srfit/fitbase/profile.py index bc598d3f..0262935d 100644 --- a/src/diffpy/srfit/fitbase/profile.py +++ b/src/diffpy/srfit/fitbase/profile.py @@ -159,8 +159,8 @@ def load_parsed_data(self, parser): This sets the xobs, yobs, dyobs arrays as well as the metadata. """ - x, y, junk, dy = parser.getData() - self.meta = dict(parser.getMetaData()) + x, y, junk, dy = parser.get_data() + self.meta = dict(parser.get_metadata()) self.set_observed_profile(x, y, dy) return From 9544243fab0f02f4dcba71cf41dce89df2ccc60a Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 20:33:16 -0400 Subject: [PATCH 180/193] add set_parsed_profile test with ProfileParser --- src/diffpy/srfit/fitbase/profile.py | 2 +- tests/test_profile.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/diffpy/srfit/fitbase/profile.py b/src/diffpy/srfit/fitbase/profile.py index 0262935d..d66e61f7 100644 --- a/src/diffpy/srfit/fitbase/profile.py +++ b/src/diffpy/srfit/fitbase/profile.py @@ -159,7 +159,7 @@ def load_parsed_data(self, parser): This sets the xobs, yobs, dyobs arrays as well as the metadata. """ - x, y, junk, dy = parser.get_data() + x, y, dx, dy = parser.get_data() self.meta = dict(parser.get_metadata()) self.set_observed_profile(x, y, dy) return diff --git a/tests/test_profile.py b/tests/test_profile.py index f8c186b4..b69f6f7b 100644 --- a/tests/test_profile.py +++ b/tests/test_profile.py @@ -22,6 +22,7 @@ from numpy import allclose, arange, array, array_equal, ones_like from diffpy.srfit.exceptions import SrFitError +from diffpy.srfit.fitbase import ProfileParser from diffpy.srfit.fitbase.profile import Profile @@ -307,5 +308,20 @@ def _test(p): return +def test_load_parsed_data(parser_datafiles): + """Test the load_parsed_data method.""" + prof = Profile() + parser = ProfileParser() + datafile = parser_datafiles / "four_col.gr" + parser.parse_file(datafile) + prof.load_parsed_data(parser) + expected_xobs = [1.0, 1.1, 1.2] + expected_yobs = [2.0, 2.1, 2.2] + expected_dyobs = [0.2, 0.4, 0.6] + assert prof.xobs.tolist() == expected_xobs + assert prof.yobs.tolist() == expected_yobs + assert prof.dyobs.tolist() == expected_dyobs + + if __name__ == "__main__": unittest.main() From a616dc2060335a476ae3de3b8b02fbb1932c7980 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 21:01:34 -0400 Subject: [PATCH 181/193] update examples with new parser --- docs/examples/coreshellnp.py | 5 +++-- docs/examples/crystalpdf.py | 12 +++++++----- docs/examples/crystalpdfall.py | 5 +++-- docs/examples/crystalpdfobjcryst.py | 13 +++++++------ docs/examples/crystalpdftwodata.py | 7 ++++--- docs/examples/crystalpdftwophase.py | 5 +++-- docs/examples/nppdfcrystal.py | 5 +++-- docs/examples/nppdfsas.py | 5 +++-- 8 files changed, 33 insertions(+), 24 deletions(-) diff --git a/docs/examples/coreshellnp.py b/docs/examples/coreshellnp.py index 23871a46..8560221d 100644 --- a/docs/examples/coreshellnp.py +++ b/docs/examples/coreshellnp.py @@ -29,8 +29,9 @@ FitRecipe, FitResults, Profile, + ProfileParser, ) -from diffpy.srfit.pdf import PDFGenerator, PDFParser +from diffpy.srfit.pdf import PDFGenerator # Example Code @@ -42,7 +43,7 @@ def makeRecipe(stru1, stru2, datname): profile = Profile() # Load data and add it to the profile - parser = PDFParser() + parser = ProfileParser() parser.parseFile(datname) profile.load_parsed_data(parser) profile.set_calculation_range(xmin=1.5, xmax=45, dx=0.1) diff --git a/docs/examples/crystalpdf.py b/docs/examples/crystalpdf.py index fcfbded3..cdd3472e 100644 --- a/docs/examples/crystalpdf.py +++ b/docs/examples/crystalpdf.py @@ -32,8 +32,9 @@ FitRecipe, FitResults, Profile, + ProfileParser, ) -from diffpy.srfit.pdf import PDFGenerator, PDFParser +from diffpy.srfit.pdf import PDFGenerator from diffpy.structure import Structure ###### @@ -48,12 +49,12 @@ def makeRecipe(ciffile, datname): profile = Profile() # Load data and add it to the Profile. Unlike in other examples, we use a - # class (PDFParser) to help us load the data. This class will read the data - # and relevant metadata from a two- to four-column data file generated + # class (ProfileParser) to help us load the data. This class will read the + # data and relevant metadata from a two- to four-column data file generated # with PDFGetX2 or PDFGetN. The metadata will be passed to the PDFGenerator # when they are associated in the FitContribution, which saves some # configuration steps. - parser = PDFParser() + parser = ProfileParser() parser.parseFile(datname) profile.load_parsed_data(parser) profile.set_calculation_range(xmax=20) @@ -62,7 +63,8 @@ def makeRecipe(ciffile, datname): # The PDFGenerator is for configuring and calculating a PDF profile. Here, # we want to refine a Structure object from diffpy.structure. We tell the # PDFGenerator that with the 'setStructure' method. All other configuration - # options will be inferred from the metadata that is read by the PDFParser. + # options will be inferred from the metadata that is read by the + # ProfileParser. # In particular, this will set the scattering type (x-ray or neutron), the # Qmax value, as well as initial values for the non-structural Parameters. generator = PDFGenerator("G") diff --git a/docs/examples/crystalpdfall.py b/docs/examples/crystalpdfall.py index 1ee8903c..37a57c78 100644 --- a/docs/examples/crystalpdfall.py +++ b/docs/examples/crystalpdfall.py @@ -27,8 +27,9 @@ FitRecipe, FitResults, Profile, + ProfileParser, ) -from diffpy.srfit.pdf import PDFGenerator, PDFParser +from diffpy.srfit.pdf import PDFGenerator ###### # Example Code @@ -37,7 +38,7 @@ def makeProfile(datafile): """Make an place data within a Profile.""" profile = Profile() - parser = PDFParser() + parser = ProfileParser() parser.parseFile(datafile) profile.load_parsed_data(parser) profile.set_calculation_range(xmax=20) diff --git a/docs/examples/crystalpdfobjcryst.py b/docs/examples/crystalpdfobjcryst.py index 672a2267..43a98e4d 100644 --- a/docs/examples/crystalpdfobjcryst.py +++ b/docs/examples/crystalpdfobjcryst.py @@ -28,8 +28,9 @@ FitRecipe, FitResults, Profile, + ProfileParser, ) -from diffpy.srfit.pdf import PDFGenerator, PDFParser +from diffpy.srfit.pdf import PDFGenerator ###### # Example Code @@ -42,11 +43,11 @@ def makeRecipe(ciffile, datname): # This will be used to store the observed and calculated PDF profile. profile = Profile() - # Load data and add it to the Profile. As before we use a PDFParser. The - # metadata is still passed to the PDFGenerator later on. The interaction - # between the PDFGenerator and the metadata does not depend on type of - # structure being refined. - parser = PDFParser() + # Load data and add it to the Profile. As before we use a ProfileParser. + # The metadata is still passed to the PDFGenerator later on. + # The interaction between the PDFGenerator and the metadata does not + # depend on type of structure being refined. + parser = ProfileParser() parser.parseFile(datname) profile.load_parsed_data(parser) profile.set_calculation_range(xmax=20) diff --git a/docs/examples/crystalpdftwodata.py b/docs/examples/crystalpdftwodata.py index 0b0d6093..03458fa8 100644 --- a/docs/examples/crystalpdftwodata.py +++ b/docs/examples/crystalpdftwodata.py @@ -29,8 +29,9 @@ FitRecipe, FitResults, Profile, + ProfileParser, ) -from diffpy.srfit.pdf import PDFGenerator, PDFParser +from diffpy.srfit.pdf import PDFGenerator ###### # Example Code @@ -46,12 +47,12 @@ def makeRecipe(ciffile, xdatname, ndatname): nprofile = Profile() # Load data and add it to the proper Profile. - parser = PDFParser() + parser = ProfileParser() parser.parseFile(xdatname) xprofile.load_parsed_data(parser) xprofile.set_calculation_range(xmax=20) - parser = PDFParser() + parser = ProfileParser() parser.parseFile(ndatname) nprofile.load_parsed_data(parser) nprofile.set_calculation_range(xmax=20) diff --git a/docs/examples/crystalpdftwophase.py b/docs/examples/crystalpdftwophase.py index 1d6878b2..c2dbcf78 100644 --- a/docs/examples/crystalpdftwophase.py +++ b/docs/examples/crystalpdftwophase.py @@ -29,8 +29,9 @@ FitRecipe, FitResults, Profile, + ProfileParser, ) -from diffpy.srfit.pdf import PDFGenerator, PDFParser +from diffpy.srfit.pdf import PDFGenerator ###### # Example Code @@ -43,7 +44,7 @@ def makeRecipe(niciffile, siciffile, datname): profile = Profile() # Load data and add it to the profile - parser = PDFParser() + parser = ProfileParser() parser.parseFile(datname) profile.load_parsed_data(parser) profile.set_calculation_range(xmax=20) diff --git a/docs/examples/nppdfcrystal.py b/docs/examples/nppdfcrystal.py index 95cca7e3..a568e8b9 100644 --- a/docs/examples/nppdfcrystal.py +++ b/docs/examples/nppdfcrystal.py @@ -32,8 +32,9 @@ FitRecipe, FitResults, Profile, + ProfileParser, ) -from diffpy.srfit.pdf import PDFGenerator, PDFParser +from diffpy.srfit.pdf import PDFGenerator def makeRecipe(ciffile, grdata): @@ -42,7 +43,7 @@ def makeRecipe(ciffile, grdata): # Set up a PDF fit as has been done in other examples. pdfprofile = Profile() - pdfparser = PDFParser() + pdfparser = ProfileParser() pdfparser.parseFile(grdata) pdfprofile.load_parsed_data(pdfparser) pdfprofile.set_calculation_range(xmin=0.1, xmax=20) diff --git a/docs/examples/nppdfsas.py b/docs/examples/nppdfsas.py index 7bea8069..2aac74b4 100644 --- a/docs/examples/nppdfsas.py +++ b/docs/examples/nppdfsas.py @@ -31,8 +31,9 @@ FitRecipe, FitResults, Profile, + ProfileParser, ) -from diffpy.srfit.pdf import PDFGenerator, PDFParser +from diffpy.srfit.pdf import PDFGenerator from diffpy.srfit.pdf.characteristicfunctions import SASCF from diffpy.srfit.sas import SASGenerator, SASParser @@ -47,7 +48,7 @@ def makeRecipe(ciffile, grdata, iqdata): # Create a PDF contribution as before pdfprofile = Profile() - pdfparser = PDFParser() + pdfparser = ProfileParser() pdfparser.parseFile(grdata) pdfprofile.load_parsed_data(pdfparser) pdfprofile.set_calculation_range(xmin=0.1, xmax=20) From 515205cedb267c52247fe6a9c6f4570ee40c0e7a Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 21:02:41 -0400 Subject: [PATCH 182/193] update test_pdf to reflect new parser --- tests/conftest.py | 2 +- tests/test_pdf.py | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 25714656..8d64babf 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -272,7 +272,7 @@ def temp_data_files(tmp_path): @pytest.fixture -def parser_datafile(tmp_path): +def parser_datafiles(tmp_path): """Create temporary data files with different column layouts and yield the directory.""" diff --git a/tests/test_pdf.py b/tests/test_pdf.py index d8e86e54..908d5eb1 100644 --- a/tests/test_pdf.py +++ b/tests/test_pdf.py @@ -23,6 +23,7 @@ import pytest from diffpy.srfit.exceptions import SrFitError +from diffpy.srfit.fitbase import ProfileParser from diffpy.srfit.pdf import PDFContribution, PDFGenerator, PDFParser # ---------------------------------------------------------------------------- @@ -46,7 +47,7 @@ def testParser1(datafile): assert meta.get("scale") is None assert meta.get("doping") is None - x, y, dx, dy = parser.getData() + x, y, dx, dy = parser.get_data() assert dx is None assert dy is None @@ -78,12 +79,12 @@ def testParser1(datafile): def testParser2(datafile): data = datafile("si-q27r60-xray.gr") - parser = PDFParser() - parser.parseFile(data) + parser = ProfileParser() + parser.parse_file(data) meta = parser._meta - assert data == meta["filename"] + assert str(data) == meta["filename"] assert 1 == meta["nbanks"] assert "X" == meta["stype"] assert 27 == meta["qmax"] @@ -94,7 +95,7 @@ def testParser2(datafile): assert meta.get("scale") is None assert meta.get("doping") is None - x, y, dx, dy = parser.getData() + x, y, dx, dy = parser.get_data() testx = numpy.linspace(0.01, 60, 5999, endpoint=False) diff = testx - x res = numpy.dot(diff, diff) @@ -136,7 +137,7 @@ def testParser2(datafile): res = numpy.dot(diff, diff) assert 0 == pytest.approx(res) - assert dx is None + assert dx.tolist() == [0] * len(dx) return From 7eaea4b314a251c772c28d95d15de56396fd9247 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 21:03:26 -0400 Subject: [PATCH 183/193] update old formatted test data to get parser to pass tests --- tests/testdata/si-q27r60-xray.gr | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/testdata/si-q27r60-xray.gr b/tests/testdata/si-q27r60-xray.gr index e25d5795..a0f208ad 100644 --- a/tests/testdata/si-q27r60-xray.gr +++ b/tests/testdata/si-q27r60-xray.gr @@ -9,7 +9,9 @@ sourcedir=C:\Program Files\PDFgetX2\ logfile=.pdfgetx2.log quiet=0 debug=0 autosave_isa=1 savefilenamebase=si325_mesh_300k_nor_4-8 iqfilesurfix=.iq sqfilesurfix=.sq fqfilesurfix=.fq grfilesurfix=.gr - +stype = X +qmax = 27 +temperature = 300 ##### DataFileFormat datatype=1 (0:SPEC, 1:CHI, 2:nxm column, 3:unknown) num_skiplines=3 comment_id=# delimiter= From dd32346514d1a84bb49f3e2e802feae692976382 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 21:06:57 -0400 Subject: [PATCH 184/193] add test for ProfileParser --- tests/test_profileparser.py | 200 ++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 tests/test_profileparser.py diff --git a/tests/test_profileparser.py b/tests/test_profileparser.py new file mode 100644 index 00000000..e1676b15 --- /dev/null +++ b/tests/test_profileparser.py @@ -0,0 +1,200 @@ +import re +from pathlib import Path + +import pytest + +from diffpy.srfit.exceptions import ParseError +from diffpy.srfit.fitbase.profileparser import ProfileParser + +# UC1: User loads file with all x, y, dx, dy columns in that format +# expected: x, y, dx, dy, and metadata are all read correctly +# UC2: User loads file with x, y, dy columns in that format (dx is missing) +# expected: x, y, dy, and metadata are all read correctly +# UC3: User loads file with x, y columns in that format (dx and dy are missing) +# expected: x, y, and metadata are all read correctly +# UC4: User loads file with x, dx, y, dy columns in that format and specifies +# column_format +# expected: x, y, dx, dy, and metadata are all read correctly +# UC5: User loads file with dy and dx values containing NaN and inf values +# expected: x, y, and metadata are all read correctly and dx and dy are set to +# 0 for all values + +# UC6: User loads file with only one column +# expected: ParseError is raised +# UC7: User loads file with 5 columns +# expected: ParseError is raised +# UC8: User loads file with x, y, and dy but specifies column_format with 4 +# columns +# expected: ParseError is raised +# UC9: User loads file with x, y, dx, and dy but specifies column_format with 5 +# columns +# expected: ParseError is raised +# UC10: User loads file with x, y, dx, and dy but specifies column_format with +# 3 columns +# expected: ParseError is raised +# UC11: User loads file with x, y, dx, and dy but specifies column_format with +# duplicate values +# expected: ParseError is raised + +EXPECTED_META = { + "wavelength": 0.1, + "dataformat": "QA", + "inputfile": "input.iq", + "backgroundfile": "backgroundfile.iq", + "mode": "xray", + "bgscale": 1.0, + "composition": "TiSe2", + "outputtype": "gr", + "qmaxinst": 25.0, + "qmin": 0.1, + "qmax": 25.0, + "rmax": 140.0, + "rmin": 0.0, + "rstep": 0.01, + "rpoly": 0.7, + "inputdir": "/my/data/dir", + "savedir": "/my/save/dir", + "backgroundfilefull": "/my/data/dir/backgroundfile.iq", + "nbanks": 1, + "bank": 0, +} + + +@pytest.mark.parametrize( + "input_file, column_order, expected_x, " + "expected_y, expected_dx, expected_dy", + [ + # UC1: 4-column file (x, y, dx, dy) — all columns present + # expected: x, y, dx, dy, and metadata are all read correctly + ( + Path("four_col.gr"), + None, + [1.0, 1.1, 1.2], + [2.0, 2.1, 2.2], + [0.1, 0.3, 0.5], + [0.2, 0.4, 0.6], + ), + # UC2: 3-column file (x, y, dy) — dx is missing + # expected: x, y, dy, and metadata are all read correctly + ( + Path("three_col.dat"), + None, + [1.0, 1.1, 1.2], + [2.0, 2.1, 2.2], + [0.0, 0.0, 0.0], + [0.2, 0.4, 0.6], + ), + # UC3: 2-column file (x, y) — dx and dy are missing + # expected: x, y, and metadata are all read correctly + ( + Path("two_col.txt"), + None, + [1.0, 1.1, 1.2], + [2.0, 2.1, 2.2], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + ), + # UC4: 4-column file in (x, dx, y, dy) order with explicit + # column_format + # expected: x, y, dx, dy, and metadata are all read correctly + ( + Path("four_col_reordered.txt"), + ("x", "dx", "y", "dy"), + [1.0, 1.1, 1.2], + [2.0, 2.1, 2.2], + [0.1, 0.3, 0.5], + [0.2, 0.4, 0.6], + ), + # UC5: 4-column file where dx/dy contain NaN and inf values + # expected: x, y, and metadata are read correctly; dx and dy + # are set to 0 + ( + Path("four_col_nan_inf.gr"), + None, + [1.0, 1.1, 1.2], + [2.0, 2.1, 2.2], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + ), + ], +) +def test_parse_file( + parser_datafiles, + input_file, + column_order, + expected_x, + expected_y, + expected_dx, + expected_dy, +): + parser = ProfileParser() + parser.parse_file(parser_datafiles / input_file, column_order) + actual_x = parser._x.tolist() + actual_y = parser._y.tolist() + actual_dx = parser._dx.tolist() + actual_dy = parser._dy.tolist() + actual_metadata = parser._meta + actual_metadata["filename"] = actual_metadata["filename"].split("/")[-1] + + EXPECTED_META["filename"] = str(input_file).split("/")[-1] + assert actual_x == expected_x + assert actual_y == expected_y + assert actual_dx == expected_dx + assert actual_dy == expected_dy + assert actual_metadata == EXPECTED_META + + +@pytest.mark.parametrize( + "input_file, column_order, msg", + [ + # UC6: Only one column — cannot form x/y pair + # expected: ParseError is raised + ( + "one_col.gr", + None, + "Data block must have at least two columns (x, y).", + ), + # UC7: Five columns — ambiguous, no mapping defined + # expected: ParseError is raised + ("five_col.gr", None, "Expected 2 to 4 columns but found 5."), + # UC8: 3-column file but column_format expects 4 columns + # expected: ParseError is raised + ( + "three_col.dat", + ("x", "y", "dx", "dy"), + "column_format has 4 labels but file contains 3 columns.", + ), + # UC9: 4-column file but column_format expects 5 columns + # expected: ParseError is raised + ( + "four_col.gr", + ("x", "y", "dx", "dy", "extra"), + "column_format has 5 labels but file contains 4 columns.", + ), + # UC10: 4-column file but column_format expects only 3 columns + # expected: ParseError is raised + ( + "four_col.gr", + ("x", "y", "dy"), + "column_format has 3 labels but file contains 4 columns.", + ), + # UC11: column_format contains duplicate column names + # expected: ParseError is raised + ( + "four_col.gr", + ("x", "x", "dx", "dy"), + "column_format cannot contain duplicate labels.", + ), + # UC12: column_format contains invalid column names + ( + "four_col.gr", + ("x", "y", "dx", "invalid"), + "column_format contains invalid label 'invalid'. " + "Valid labels are 'x', 'y', 'dx', and 'dy'.", + ), + ], +) +def test_parse_file_bad(parser_datafiles, input_file, column_order, msg): + parser = ProfileParser() + with pytest.raises(ParseError, match=re.escape(msg)): + parser.parse_file(parser_datafiles / input_file, column_order) From ecead8d84c354935010bcb1d34744cb5db649ba7 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 21:07:35 -0400 Subject: [PATCH 185/193] update sas module and test to reflect new changes --- src/diffpy/srfit/sas/sasparser.py | 2 +- tests/test_sas.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/diffpy/srfit/sas/sasparser.py b/src/diffpy/srfit/sas/sasparser.py index 22da76f8..5503a417 100644 --- a/src/diffpy/srfit/sas/sasparser.py +++ b/src/diffpy/srfit/sas/sasparser.py @@ -126,7 +126,7 @@ def parseFile(self, filename): # FIXME: Revisit when we refactor the SAS characteristic functions. # Why is a list imported but only the first element is taken? # Is this desired behavior? - self.selectBank(0) + self.select_bank(0) return def parseString(self, patstring): diff --git a/tests/test_sas.py b/tests/test_sas.py index db856942..33dab04a 100644 --- a/tests/test_sas.py +++ b/tests/test_sas.py @@ -31,7 +31,7 @@ def testParser(sas_available, datafile): data = datafile("sas_ascii_test_1.txt") parser = SASParser() parser.parseFile(data) - x, y, dx, dy = parser.getData() + x, y, dx, dy = parser.get_data() testx = numpy.array( [ 0.002618, From 51d2a43f27d52a84b7bd672210a9caa313cc831f Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 21:10:42 -0400 Subject: [PATCH 186/193] news --- news/profileparser_dep.rst | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 news/profileparser_dep.rst diff --git a/news/profileparser_dep.rst b/news/profileparser_dep.rst new file mode 100644 index 00000000..9f180049 --- /dev/null +++ b/news/profileparser_dep.rst @@ -0,0 +1,29 @@ +**Added:** + +* Add ``parse_file`` method to ``ProfileParser`` to parse a file directly with ``load_data`` from ``diffpy.utils``. +* Add ``get_num_bank`` method to ``ProfileParser`` to replace ``getNumBank``. +* Add ``select_bank`` method to ``ProfileParser`` to replace ``selectBank``. +* Add ``get_format`` method to ``ProfileParser`` to replace ``getFormat``. +* Add ``get_data`` method to ``ProfileParser`` to replace ``getData``. +* Add ``get_meta_data`` method to ``ProfileParser`` to replace ``getMetaData``. + +**Changed:** + +* + +**Deprecated:** + +* Deprecate ``PDFParser``. Use ``ProfileParser`` instead. +* Deprecate ``getNumBank``, ``selectBank``, ``getFormat``, ``getData``, and ``getMetaData`` in ``ProfileParser``. + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 62b3af5bb96c3ca0783d9c437f8a3dcf436ed33b Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 21:33:48 -0400 Subject: [PATCH 187/193] rm comment --- src/diffpy/srfit/fitbase/profileparser.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/diffpy/srfit/fitbase/profileparser.py b/src/diffpy/srfit/fitbase/profileparser.py index 7260a66d..16c8e014 100644 --- a/src/diffpy/srfit/fitbase/profileparser.py +++ b/src/diffpy/srfit/fitbase/profileparser.py @@ -189,8 +189,8 @@ def parseFile(self, filename): return def parse_file(self, filename, column_format=None): - """Parse a data file and extract data and metadata with - automatic uncertainty detection. + """Parse a data file to extract data and metadata, with + automatic handling of uncertainties. - For files with 2 columns: assumes (x, y) and sets dx, dy to 0. - For files with 3 columns: assumes (x, y, dy) and sets dx to 0. @@ -246,8 +246,6 @@ def parse_file(self, filename, column_format=None): self._meta["nbanks"] = 1 self.select_bank(0) - # --- Private helpers --- # - def _load_file(self, filename): """Load metadata and numeric data from a file.""" meta = load_data(filename, headers=True) From 653c98d30cf4affade639a759cef22f79daa1be6 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 21:36:36 -0400 Subject: [PATCH 188/193] blank commit to fix pre-commit From 63aa9e9769e718f38268515239650c9d80230f1d Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 17 Mar 2026 09:26:56 -0400 Subject: [PATCH 189/193] run pre-commit autoupdate and run pre-commit --- .pre-commit-config.yaml | 20 ++++++++++---------- src/diffpy/srfit/equation/builder.py | 1 + src/diffpy/srfit/fitbase/profileparser.py | 1 - src/diffpy/srfit/interface/__init__.py | 1 - src/diffpy/srfit/structure/sgconstraints.py | 1 - src/diffpy/srfit/util/weakrefcallable.py | 3 +-- tests/conftest.py | 19 ++++++------------- tests/debug.py | 1 - tests/run.py | 1 - tests/test_contribution.py | 1 + tests/test_weakrefcallable.py | 1 - 11 files changed, 19 insertions(+), 31 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0e4a84d1..f189a945 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ ci: submodules: false repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v6.0.0 hooks: - id: check-yaml - id: end-of-file-fixer @@ -21,45 +21,45 @@ repos: - id: check-toml - id: check-added-large-files - repo: https://github.com/psf/black - rev: 24.4.2 + rev: 26.3.1 hooks: - id: black - repo: https://github.com/pycqa/flake8 - rev: 7.0.0 + rev: 7.3.0 hooks: - id: flake8 - repo: https://github.com/pycqa/isort - rev: 5.13.2 + rev: 8.0.1 hooks: - id: isort args: ["--profile", "black"] - repo: https://github.com/kynan/nbstripout - rev: 0.7.1 + rev: 0.9.1 hooks: - id: nbstripout - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v6.0.0 hooks: - id: no-commit-to-branch name: Prevent Commit to Main Branch args: ["--branch", "main"] stages: [pre-commit] - repo: https://github.com/codespell-project/codespell - rev: v2.3.0 + rev: v2.4.2 hooks: - id: codespell additional_dependencies: - tomli # prettier - multi formatter for .json, .yml, and .md files - repo: https://github.com/pre-commit/mirrors-prettier - rev: f12edd9c7be1c20cfa42420fd0e6df71e42b51ea # frozen: v4.0.0-alpha.8 + rev: v4.0.0-alpha.8 hooks: - id: prettier additional_dependencies: - "prettier@^3.2.4" # docformatter - PEP 257 compliant docstring formatter - - repo: https://github.com/s-weigand/docformatter - rev: 5757c5190d95e5449f102ace83df92e7d3b06c6c + - repo: https://github.com/PyCQA/docformatter + rev: v1.7.7 hooks: - id: docformatter additional_dependencies: [tomli] diff --git a/src/diffpy/srfit/equation/builder.py b/src/diffpy/srfit/equation/builder.py index 0bb81350..a41f6bda 100644 --- a/src/diffpy/srfit/equation/builder.py +++ b/src/diffpy/srfit/equation/builder.py @@ -75,6 +75,7 @@ > beq = c*f(a,b) > eq = beq.makeEquation() """ + import inspect import numbers import token diff --git a/src/diffpy/srfit/fitbase/profileparser.py b/src/diffpy/srfit/fitbase/profileparser.py index 16c8e014..7713abc5 100644 --- a/src/diffpy/srfit/fitbase/profileparser.py +++ b/src/diffpy/srfit/fitbase/profileparser.py @@ -22,7 +22,6 @@ See the class documentation for more information. """ - from pathlib import Path import numpy as np diff --git a/src/diffpy/srfit/interface/__init__.py b/src/diffpy/srfit/interface/__init__.py index 3157c1ec..896ae519 100644 --- a/src/diffpy/srfit/interface/__init__.py +++ b/src/diffpy/srfit/interface/__init__.py @@ -19,7 +19,6 @@ for scripting. """ - from diffpy.srfit.interface.interface import ( FitRecipeInterface, ParameterInterface, diff --git a/src/diffpy/srfit/structure/sgconstraints.py b/src/diffpy/srfit/structure/sgconstraints.py index 666e360d..893c90a0 100644 --- a/src/diffpy/srfit/structure/sgconstraints.py +++ b/src/diffpy/srfit/structure/sgconstraints.py @@ -14,7 +14,6 @@ ############################################################################## """Code to set space group constraints for a crystal structure.""" - import re import numpy diff --git a/src/diffpy/srfit/util/weakrefcallable.py b/src/diffpy/srfit/util/weakrefcallable.py index 042e1812..1cbb87aa 100644 --- a/src/diffpy/srfit/util/weakrefcallable.py +++ b/src/diffpy/srfit/util/weakrefcallable.py @@ -14,7 +14,6 @@ ############################################################################## """Picklable storage of callable objects using weak references.""" - import types import weakref @@ -125,7 +124,7 @@ def __getstate__(self): def __setstate__(self, state): """Restore the weak reference in this wrapper upon unpickling.""" - (self._class, nm, self.fallback, mobj) = state + self._class, nm, self.fallback, mobj = state self.function = getattr(self._class, nm) if mobj is None: # use a fake weak reference that mimics deallocated object. diff --git a/tests/conftest.py b/tests/conftest.py index 8d64babf..23b92f6a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -242,8 +242,7 @@ def temp_data_files(tmp_path): cgr_file.write_text("1.0 2.0\n" "1.1 2.1\n" "1.2 2.2\n") results_file = tmp_path / "fit_results.res" - results_file.write_text( - """ + results_file.write_text(""" Results written: Wed Feb 25 15:14:58 2026 produced by cadenmyers @@ -266,8 +265,7 @@ def temp_data_files(tmp_path): Variable Correlations greater than 25% (Correlations invalid) ------------------------------------------------------------------------------ No correlations greater than 25% -""" - ) +""") yield tmp_path @@ -314,8 +312,7 @@ def parser_datafiles(tmp_path): # Three-column (x, y, dy) (tmp_path / "three_col.dat").write_text( - METADATA_HEADER - + r"""#L r($\AA$) G($\AA^{-2}$) dG($\AA^{-2}$) + METADATA_HEADER + r"""#L r($\AA$) G($\AA^{-2}$) dG($\AA^{-2}$) 1.0 2.0 0.2 1.1 2.1 0.4 1.2 2.2 0.6""" @@ -323,8 +320,7 @@ def parser_datafiles(tmp_path): # Two-column (x, y) (tmp_path / "two_col.txt").write_text( - METADATA_HEADER - + r"""#L r($\AA$) G($\AA^{-2}$) + METADATA_HEADER + r"""#L r($\AA$) G($\AA^{-2}$) 1.0 2.0 1.1 2.1 1.2 2.2""" @@ -349,13 +345,10 @@ def parser_datafiles(tmp_path): ) # One-column - (tmp_path / "one_col.gr").write_text( - METADATA_HEADER - + r"""#L r($\AA$) + (tmp_path / "one_col.gr").write_text(METADATA_HEADER + r"""#L r($\AA$) 1.0 1.1 -1.2""" - ) +1.2""") # Five-column (extra column) (tmp_path / "five_col.gr").write_text( diff --git a/tests/debug.py b/tests/debug.py index 8ebfc4ad..64d5c83f 100644 --- a/tests/debug.py +++ b/tests/debug.py @@ -19,7 +19,6 @@ Exceptions raised by failed tests or other errors are not caught. """ - if __name__ == "__main__": import sys diff --git a/tests/run.py b/tests/run.py index a375045e..9ca3054a 100644 --- a/tests/run.py +++ b/tests/run.py @@ -17,7 +17,6 @@ python -m diffpy.srfit.tests.run """ - if __name__ == "__main__": import sys diff --git a/tests/test_contribution.py b/tests/test_contribution.py index 813ef9c8..56975905 100644 --- a/tests/test_contribution.py +++ b/tests/test_contribution.py @@ -13,6 +13,7 @@ # ############################################################################## """Tests for refinableobj module.""" + import unittest import numpy as np diff --git a/tests/test_weakrefcallable.py b/tests/test_weakrefcallable.py index 1e8ca092..688bc563 100644 --- a/tests/test_weakrefcallable.py +++ b/tests/test_weakrefcallable.py @@ -14,7 +14,6 @@ ############################################################################## """Unit tests for the weakrefcallable module.""" - import pickle import unittest From 985e474e7ac07685752e362908198f64d25a340a Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 17 Mar 2026 09:46:38 -0400 Subject: [PATCH 190/193] set python version to 3.13 to pin pre-commit CI --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f189a945..124954e0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,5 @@ default_language_version: - python: python3 + python: python3.13 ci: autofix_commit_msg: | [pre-commit.ci] auto fixes from pre-commit hooks From 17c997179dcebaad5a406ee1785bf24800c771f8 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 17 Mar 2026 09:58:31 -0400 Subject: [PATCH 191/193] pin only docformatter to python3.13 --- .pre-commit-config.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 124954e0..d118bebc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,5 @@ default_language_version: - python: python3.13 + python: python3 ci: autofix_commit_msg: | [pre-commit.ci] auto fixes from pre-commit hooks @@ -62,5 +62,6 @@ repos: rev: v1.7.7 hooks: - id: docformatter + language_version: python3.13 additional_dependencies: [tomli] args: [--in-place, --config, ./pyproject.toml] From ab44228edc1e70a0912ef0d0206b9bb578578fcc Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 17 Mar 2026 10:20:26 -0400 Subject: [PATCH 192/193] rm python3.13 pin on pre-commit-config for now --- .pre-commit-config.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d118bebc..f189a945 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -62,6 +62,5 @@ repos: rev: v1.7.7 hooks: - id: docformatter - language_version: python3.13 additional_dependencies: [tomli] args: [--in-place, --config, ./pyproject.toml] From ce39171ab5323c332f2f576de91deb3f1cad23e2 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 17 Mar 2026 16:39:41 -0400 Subject: [PATCH 193/193] pip pre-commit docformatter to 3.13 --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f189a945..d118bebc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -62,5 +62,6 @@ repos: rev: v1.7.7 hooks: - id: docformatter + language_version: python3.13 additional_dependencies: [tomli] args: [--in-place, --config, ./pyproject.toml]