diff --git a/.codecov.yml b/.codecov.yml index 5a94096..4af5eb2 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,14 +1,14 @@ coverage: status: - project: # more options at https://docs.codecov.com/docs/commit-status + project: # more options at https://docs.codecov.com/docs/commit-status default: target: auto # use the coverage from the base commit, fail if coverage is lower - threshold: 0% # allow the coverage to drop by + threshold: 0% # allow the coverage to drop by comment: layout: " diff, flags, files" behavior: default require_changes: false - require_base: false # [true :: must have a base report to post] - require_head: false # [true :: must have a head report to post] + require_base: false # [true :: must have a base report to post] + require_head: false # [true :: must have a head report to post] hide_project_coverage: false # [true :: only show coverage on the git diff aka patch coverage] diff --git a/.codespell/ignore_words.txt b/.codespell/ignore_words.txt index 9757d7c..04b4fcf 100644 --- a/.codespell/ignore_words.txt +++ b/.codespell/ignore_words.txt @@ -4,8 +4,5 @@ ;; abbreviation for "materials" often used in a journal title mater -;; alternative use of socioeconomic -socio-economic - ;; Frobenius norm used in np.linalg.norm fro diff --git a/.github/ISSUE_TEMPLATE/release_checklist.md b/.github/ISSUE_TEMPLATE/release_checklist.md index 0f56027..6107962 100644 --- a/.github/ISSUE_TEMPLATE/release_checklist.md +++ b/.github/ISSUE_TEMPLATE/release_checklist.md @@ -6,30 +6,41 @@ labels: "release" assignees: "" --- -### PyPI/GitHub release checklist: +### PyPI/GitHub rc-release preparation checklist: - [ ] 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. -- [ ] Installation instructions in the README, documentation and on the website (e.g., diffpy.org) are updated. + missing), tutorials, and other human-written text is up-to-date with any changes in the code. +- [ ] 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. -Please mention @sbillinge here when you are ready for PyPI/GitHub release. Include any additional comments necessary, such as -version information and details about the pre-release here: +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: -### conda-forge release checklist: +### PyPI/GitHub full-release preparation checklist: - +- [ ] Create a new conda environment and install the rc from PyPI (`pip install ==??`) +- [ ] License information on PyPI is correct. +- [ ] Docs are deployed successfully to `https:///`. +- [ ] Successfully run all tests, tutorial examples or do functional testing. +Please let the maintainer know that all checks are done and the package is ready for full release. + +### conda-forge release preparation checklist: + + + +- [ ] 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. -- [ ] All relevant issues in the feedstock are addressed in the release PR. +- [ ] Close any open issues on the feedstock. Reach out to the maintainer if you have questions. +- [ ] Tag the maintainer for conda-forge release. ### Post-release checklist -- [ ] Run tutorial examples and conduct functional testing using the installation guide in the README. Attach screenshots/results as comments. -- [ ] Documentation (README, tutorials, API references, and websites) is deployed without broken links or missing figures. +- [ ] Run tutorial examples and conduct functional testing using the installation guide in the README. Attach screenshots/results as comments. +- [ ] Documentation (README, tutorials, API references, and websites) is deployed without broken links or missing figures. diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md new file mode 100644 index 0000000..1099d86 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md @@ -0,0 +1,15 @@ +### What problem does this PR address? + + + +### What should the reviewer(s) do? + + + + diff --git a/.github/workflows/build-wheel-release-upload.yml b/.github/workflows/build-wheel-release-upload.yml index 8c575c5..00f39f4 100644 --- a/.github/workflows/build-wheel-release-upload.yml +++ b/.github/workflows/build-wheel-release-upload.yml @@ -4,13 +4,15 @@ on: workflow_dispatch: push: tags: - - '*' # Trigger on all tags initially, but tag and release privilege are verified in _build-wheel-release-upload.yml + - "*" # Trigger on all tags initially, but tag and release privilege are verified in _build-wheel-release-upload.yml jobs: release: - uses: Billingegroup/release-scripts/.github/workflows/_build-wheel-release-upload.yml@v0 + uses: scikit-package/release-scripts/.github/workflows/_build-wheel-release-upload.yml@v0 with: project: diffpy.srmise + c_extension: false + maintainer_GITHUB_username: sbillinge secrets: PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} PAT_TOKEN: ${{ secrets.PAT_TOKEN }} diff --git a/.github/workflows/check-news-item.yml b/.github/workflows/check-news-item.yml index 960756f..e6f5a5e 100644 --- a/.github/workflows/check-news-item.yml +++ b/.github/workflows/check-news-item.yml @@ -3,10 +3,10 @@ name: Check for News on: pull_request_target: branches: - - main + - main jobs: - build: - uses: Billingegroup/release-scripts/.github/workflows/_check-news-item.yml@v0 + check-news-item: + uses: scikit-package/release-scripts/.github/workflows/_check-news-item.yml@v0 with: project: diffpy.srmise diff --git a/.github/workflows/matrix-and-codecov-on-merge-to-main.yml b/.github/workflows/matrix-and-codecov-on-merge-to-main.yml index f4ad74a..9f677b4 100644 --- a/.github/workflows/matrix-and-codecov-on-merge-to-main.yml +++ b/.github/workflows/matrix-and-codecov-on-merge-to-main.yml @@ -11,8 +11,8 @@ on: workflow_dispatch: jobs: - coverage: - uses: Billingegroup/release-scripts/.github/workflows/_matrix-and-codecov-on-merge-to-main.yml@v0 + matrix-coverage: + uses: scikit-package/release-scripts/.github/workflows/_matrix-and-codecov-on-merge-to-main.yml@v0 with: project: diffpy.srmise c_extension: false diff --git a/.github/workflows/publish-docs-on-release.yml b/.github/workflows/publish-docs-on-release.yml new file mode 100644 index 0000000..6df1afc --- /dev/null +++ b/.github/workflows/publish-docs-on-release.yml @@ -0,0 +1,12 @@ +name: Deploy Documentation on Release + +on: + workflow_dispatch: + +jobs: + docs: + uses: scikit-package/release-scripts/.github/workflows/_publish-docs-on-release.yml@v0 + with: + project: diffpy.srmise + c_extension: false + headless: false diff --git a/.github/workflows/tests-on-pr.yml b/.github/workflows/tests-on-pr.yml index 201dad7..55091e8 100644 --- a/.github/workflows/tests-on-pr.yml +++ b/.github/workflows/tests-on-pr.yml @@ -1,15 +1,12 @@ name: Tests on PR on: - push: - branches: - - main pull_request: workflow_dispatch: jobs: - validate: - uses: Billingegroup/release-scripts/.github/workflows/_tests-on-pr.yml@v0 + tests-on-pr: + uses: scikit-package/release-scripts/.github/workflows/_tests-on-pr.yml@v0 with: project: diffpy.srmise c_extension: false diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9cf0556..0e4a84d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,14 +1,14 @@ default_language_version: - python: python3 + python: python3 ci: - autofix_commit_msg: | - [pre-commit.ci] auto fixes from pre-commit hooks - autofix_prs: true - autoupdate_branch: 'pre-commit-autoupdate' - autoupdate_commit_msg: '[pre-commit.ci] pre-commit autoupdate' - autoupdate_schedule: monthly - skip: [no-commit-to-branch] - submodules: false + autofix_commit_msg: | + [pre-commit.ci] auto fixes from pre-commit hooks + autofix_prs: true + autoupdate_branch: "pre-commit-autoupdate" + autoupdate_commit_msg: "[pre-commit.ci] pre-commit autoupdate" + autoupdate_schedule: monthly + skip: [no-commit-to-branch] + submodules: false repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.6.0 @@ -47,6 +47,20 @@ repos: - repo: https://github.com/codespell-project/codespell rev: v2.3.0 hooks: - - id: codespell - additional_dependencies: - - tomli + - 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 + hooks: + - id: prettier + additional_dependencies: + - "prettier@^3.2.4" + # docformatter - PEP 257 compliant docstring formatter + - repo: https://github.com/s-weigand/docformatter + rev: 5757c5190d95e5449f102ace83df92e7d3b06c6c + hooks: + - id: docformatter + additional_dependencies: [tomli] + args: [--in-place, --config, ./pyproject.toml] diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..47f7a01 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,13 @@ +version: 2 + +build: + os: "ubuntu-22.04" + tools: + python: "latest" + +python: + install: + - requirements: requirements/docs.txt + +sphinx: + configuration: doc/source/conf.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1466de7..ab00ed6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,5 +1,5 @@ ============= -Release Notes +Release notes ============= .. current developments diff --git a/CODE_OF_CONDUCT.rst b/CODE_OF_CONDUCT.rst index ff9c356..e8199ca 100644 --- a/CODE_OF_CONDUCT.rst +++ b/CODE_OF_CONDUCT.rst @@ -8,7 +8,7 @@ Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, +identity and expression, level of experience, education, socioeconomic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. diff --git a/doc/examples/fit_initial.py b/doc/examples/fit_initial.py index fa9961c..57af2d7 100644 --- a/doc/examples/fit_initial.py +++ b/doc/examples/fit_initial.py @@ -10,14 +10,16 @@ # See LICENSE.txt for license information. # ############################################################################## -"""Example of peak fitting C60 PDF (unnormalized) with unreliable uncertainties. - -Peak fitting in SrMise means fitting a model of initial peaks, which may be -specified manually or estimated with a clustering-based convenience function, -just as with specifying initial peaks for peak extraction. Unlike peak -extraction, it does not attempt to add or remove peaks, apply termination -ripples, or otherwise do anything beyond chi-square fitting using the specified -grid.""" +"""Example of peak fitting C60 PDF (unnormalized) with unreliable +uncertainties. + +Peak fitting in SrMise means fitting a model of initial peaks, which may +be specified manually or estimated with a clustering-based convenience +function, just as with specifying initial peaks for peak extraction. +Unlike peak extraction, it does not attempt to add or remove peaks, +apply termination ripples, or otherwise do anything beyond chi-square +fitting using the specified grid. +""" import matplotlib.pyplot as plt diff --git a/doc/examples/multimodel_known_dG1.py b/doc/examples/multimodel_known_dG1.py index f1fe508..3d52ec0 100644 --- a/doc/examples/multimodel_known_dG1.py +++ b/doc/examples/multimodel_known_dG1.py @@ -10,8 +10,8 @@ # See LICENSE.txt for license information. # ############################################################################## -"""Extract multiple models from crystalline PDF with known uncertainties for -use in later AIC-driven multimodeling analysis. +"""Extract multiple models from crystalline PDF with known uncertainties +for use in later AIC-driven multimodeling analysis. The multimodel approach generates many models of varying complexity by assuming a range of experimental uncertainties are physically plausible. This example diff --git a/doc/examples/multimodel_known_dG2.py b/doc/examples/multimodel_known_dG2.py index 59add2e..142df83 100644 --- a/doc/examples/multimodel_known_dG2.py +++ b/doc/examples/multimodel_known_dG2.py @@ -10,7 +10,8 @@ # See LICENSE.txt for license information. # ############################################################################## -"""AIC-driven multimodel analysis of crystalline PDF with known uncertainties. +"""AIC-driven multimodel analysis of crystalline PDF with known +uncertainties. The multimodel approach generates many models of varying complexity by assuming a range of experimental uncertainties are physically plausible. This example diff --git a/doc/examples/multimodel_unknown_dG1.py b/doc/examples/multimodel_unknown_dG1.py index 4570f78..45324ee 100644 --- a/doc/examples/multimodel_unknown_dG1.py +++ b/doc/examples/multimodel_unknown_dG1.py @@ -10,8 +10,8 @@ # See LICENSE.txt for license information. # ############################################################################## -"""Extract multiple models from nanoparticle PDF with unknown uncertainties for -use in later AIC-driven multimodeling analysis. +"""Extract multiple models from nanoparticle PDF with unknown +uncertainties for use in later AIC-driven multimodeling analysis. The multimodel approach generates many models of varying complexity by assuming a range of experimental uncertainties are physically plausible. This example diff --git a/doc/examples/parameter_summary.py b/doc/examples/parameter_summary.py index 1d4095c..b135d82 100644 --- a/doc/examples/parameter_summary.py +++ b/doc/examples/parameter_summary.py @@ -25,7 +25,8 @@ nyquist (whether to use Nyquist sampling) supersample (minimum amount to oversample during initial stages) cres (clustering resolution) -initial_peaks (peaks already assumed to exist during extraction)""" +initial_peaks (peaks already assumed to exist during extraction) +""" import matplotlib.pyplot as plt diff --git a/doc/examples/query_results.py b/doc/examples/query_results.py index 8b90d4b..1659047 100644 --- a/doc/examples/query_results.py +++ b/doc/examples/query_results.py @@ -10,7 +10,8 @@ # See LICENSE.txt for license information. # ############################################################################## -"""Example of extracting multiple peaks and accessing results programmatically. +"""Example of extracting multiple peaks and accessing results +programmatically. This example shows how to extract a range of peaks from a simple crystalline PDF using a crystalline baseline obtained from an existing trial. It shows diff --git a/doc/source/img/.placeholder b/doc/source/img/.placeholder new file mode 100644 index 0000000..e69de29 diff --git a/doc/source/snippets/.placeholder b/doc/source/snippets/.placeholder new file mode 100644 index 0000000..e69de29 diff --git a/environment.yml b/environment.yml deleted file mode 100644 index b467ca2..0000000 --- a/environment.yml +++ /dev/null @@ -1,6 +0,0 @@ -name: diffpy.srmise -channels: - - conda-forge -dependencies: - - python=3 - - pip diff --git a/pyproject.toml b/pyproject.toml index 0a98f3b..cc5fa75 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,6 +67,9 @@ skip = "*.cif,*.dat" recursive = true wrap-summaries = 72 wrap-descriptions = 72 +exclude = [ + "src/diffpy/srmise/baselines/arbitrary.py" +] [tool.black] line-length = 115 diff --git a/requirements/build.txt b/requirements/build.txt deleted file mode 100644 index f72d870..0000000 --- a/requirements/build.txt +++ /dev/null @@ -1,2 +0,0 @@ -python -setuptools diff --git a/requirements/docs.txt b/requirements/docs.txt index ab17b1c..5f34c6e 100644 --- a/requirements/docs.txt +++ b/requirements/docs.txt @@ -1,4 +1,5 @@ sphinx sphinx_rtd_theme +sphinx-copybutton doctr m2r diff --git a/src/diffpy/__init__.py b/src/diffpy/__init__.py index 377a0f9..1fd9c20 100644 --- a/src/diffpy/__init__.py +++ b/src/diffpy/__init__.py @@ -12,7 +12,6 @@ # See LICENSE.rst for license information. # ############################################################################## - """Blank namespace package for module diffpy.""" diff --git a/src/diffpy/srmise/__init__.py b/src/diffpy/srmise/__init__.py index 65eb42b..52fd6a9 100644 --- a/src/diffpy/srmise/__init__.py +++ b/src/diffpy/srmise/__init__.py @@ -12,8 +12,8 @@ # See LICENSE.rst for license information. # ############################################################################## - -"""Peak extraction and peak fitting tool for atomic pair distribution functions.""" +"""Peak extraction and peak fitting tool for atomic pair distribution +functions.""" # package version from diffpy.srmise.version import __version__ diff --git a/src/diffpy/srmise/applications/plot.py b/src/diffpy/srmise/applications/plot.py index 0399565..788b7d0 100755 --- a/src/diffpy/srmise/applications/plot.py +++ b/src/diffpy/srmise/applications/plot.py @@ -11,7 +11,7 @@ # See LICENSE.txt for license information. # ############################################################################## -"""plot extracted peaks and comparison to ideal distances (if given)""" +"""Plot extracted peaks and comparison to ideal distances (if given)""" import optparse import sys @@ -175,7 +175,7 @@ def labelallsubplots(): def makeplot(ppe_or_stability, ip=None, **kwds): - """Plot stuff""" + """Plot stuff.""" if isinstance(ppe_or_stability, PeakStability): stability = ppe_or_stability ppe = stability.ppe @@ -530,7 +530,8 @@ def on_draw(event): def readcompare(filename): - """Returns a list of distances read from filename, otherwise None.""" + """Returns a list of distances read from filename, otherwise + None.""" # TODO: Make this safer try: diff --git a/src/diffpy/srmise/basefunction.py b/src/diffpy/srmise/basefunction.py index 7a955f0..1876788 100644 --- a/src/diffpy/srmise/basefunction.py +++ b/src/diffpy/srmise/basefunction.py @@ -11,7 +11,8 @@ # See LICENSE.txt for license information. # ############################################################################## -"""Defines BaseFunction, the base class for mathematical functions in srmise.""" +"""Defines BaseFunction, the base class for mathematical functions in +srmise.""" import logging import re @@ -25,7 +26,8 @@ class BaseFunction(object): - """Base class for mathematical functions which model numeric sequences. + """Base class for mathematical functions which model numeric + sequences. Attributes ------------- @@ -76,7 +78,7 @@ def __init__( base=None, Cache=None, ): - """Set parameterdict defined by subclass + """Set parameterdict defined by subclass. Parameters ---------- @@ -159,32 +161,50 @@ def __init__( # "Virtual" class methods #### def actualize(self, *args, **kwds): - """Create ModelPart instance of self with given parameters. ("Virtual" method)""" + """Create ModelPart instance of self with given parameters. + + ("Virtual" method) + """ emsg = "actualize() must be implemented in a BaseFunction subclass." raise NotImplementedError(emsg) def estimate_parameters(self, *args, **kwds): - """Estimate BaseFunction parameters from supplied data. ("Virtual" method)""" + """Estimate BaseFunction parameters from supplied data. + + ("Virtual" method) + """ emsg = "estimate_parameters() must be implemented in a BaseFunction subclass." raise NotImplementedError(emsg) def _jacobianraw(self, *args, **kwds): - """Calculate the jacobian. ("Virtual" method)""" + """Calculate the jacobian. + + ("Virtual" method) + """ emsg = "_jacobianraw() must be implemented in a BaseFunction subclass." raise NotImplementedError(emsg) def _transform_derivativesraw(self, *args, **kwds): - """Convert BaseFunction parameters to another form. ("Virtual" method)""" + """Convert BaseFunction parameters to another form. + + ("Virtual" method) + """ emsg = "transform_parameters() must be implemented in a BaseFunction subclass." raise NotImplementedError(emsg) def _transform_parametersraw(self, *args, **kwds): - """Convert BaseFunction parameters to another form. ("Virtual" method)""" + """Convert BaseFunction parameters to another form. + + ("Virtual" method) + """ emsg = "transform_parameters() must be implemented in a BaseFunction subclass." raise NotImplementedError(emsg) def _valueraw(self, *args, **kwds): - """Calculate value of function. ("Virtual" method)""" + """Calculate value of function. + + ("Virtual" method) + """ emsg = "_valueraw must() be implemented in a BaseFunction subclass." raise NotImplementedError(emsg) @@ -225,7 +245,8 @@ def jacobian(self, p, r, rng=None): return self._jacobianraw(p.pars, r, p.free) def transform_derivatives(self, pars, in_format=None, out_format=None): - """Return gradient matrix for pars converted from in_format to out_format. + """Return gradient matrix for pars converted from in_format to + out_format. Parameters ---------- @@ -266,7 +287,8 @@ def transform_derivatives(self, pars, in_format=None, out_format=None): return self._transform_derivativesraw(pars, in_format=in_format, out_format=out_format) def transform_parameters(self, pars, in_format=None, out_format=None): - """Return new sequence with pars converted from in_format to out_format. + """Return new sequence with pars converted from in_format to + out_format. Also restores parameters to a preferred range if it permits multiple values that correspond to the same physical result. @@ -310,7 +332,8 @@ def transform_parameters(self, pars, in_format=None, out_format=None): return self._transform_parametersraw(pars, in_format=in_format, out_format=out_format) def value(self, p, r, rng=None): - """Calculate value of ModelPart over r, possibly restricted by range. + """Calculate value of ModelPart over r, possibly restricted by + range. Parameters ---------- @@ -345,7 +368,8 @@ def value(self, p, r, rng=None): return self._valueraw(p.pars, r) def pgradient(self, p, format): - """Return gradient matrix of parameterization in specified format wrt "internal" format at p. + """Return gradient matrix of parameterization in specified + format wrt "internal" format at p. Consider the "internal" parameterization given by (i0, i1, ..., in). Each parameter in a different format, say (o0, o1, ..., om), is a @@ -373,7 +397,7 @@ def pgradient(self, p, format): return def getmodule(self): - """Return 'diffpy.srmise.basefunction'""" + """Return 'diffpy.srmise.basefunction'.""" return "diffpy.srmise.basefunction" def writestr(self, baselist): @@ -473,14 +497,16 @@ def factory(functionstr, baselist): @staticmethod def safefunctionlist(fs): - """Return list of BaseFunction instances where any dependencies occur earlier in list. + """Return list of BaseFunction instances where any dependencies + occur earlier in list. Any functions with hidden dependent functions (i.e. those not in fs) are included in the returned list. This list provides an order that is guaranteed to be safe for saving/reinstantiating peak functions. Parameters - fs: List of BaseFunction instances.""" + fs: List of BaseFunction instances. + """ fsafe = [] for f in fs: BaseFunction.safefunction(f, fsafe) @@ -488,7 +514,8 @@ def safefunctionlist(fs): @staticmethod def safefunction(f, fsafe): - """Append BaseFunction instance f to fsafe, but adding dependent functions first. + """Append BaseFunction instance f to fsafe, but adding dependent + functions first. Does not handle circular dependencies. diff --git a/src/diffpy/srmise/baselines/arbitrary.py b/src/diffpy/srmise/baselines/arbitrary.py index 80c1055..6101bbb 100644 --- a/src/diffpy/srmise/baselines/arbitrary.py +++ b/src/diffpy/srmise/baselines/arbitrary.py @@ -26,17 +26,17 @@ class Arbitrary(BaselineFunction): """Methods for evaluating a baseline from an arbitrary function. - Supports baseline calculations with arbitrary functions. These functions, - if implemented, must have the following signatures and return values: - valuef(pars, x) ==> numpy.array of length x if x is a sequence - ==> number if x is a number - jacobianf(pars, x, free) ==> list, each element a numpy.array of length x if - x is a sequence or None if value of free for - that parameter is False. - ==> list, each element a number if x is a number - or None if value of free for that parameter is - False - estimatef(x, y) ==> numpy.array of length npars + Supports baseline calculations with arbitrary functions. These + functions, if implemented, must have the following signatures and + return values: valuef(pars, x) ==> numpy.array of length x + if x is a sequence ==> number if x is a + number jacobianf(pars, x, free) ==> list, each element a numpy.array + of length x if x is a sequence or None + if value of free for that parameter is + False. ==> list, each element a number if x + is a number or None if value of free for + that parameter is False estimatef(x, y) + ==> numpy.array of length npars """ def __init__(self, npars, valuef, jacobianf=None, estimatef=None, Cache=None): @@ -117,7 +117,8 @@ def estimate_parameters(self, r, y): The numpy array of parameters in the default internal format. we raise NotImplementedError if no estimation routine is defined, and - SrMiseEstimationError if parameters cannot be estimated for any other.""" + SrMiseEstimationError if parameters cannot be estimated for any other. + """ if self.estimatef is None: emsg = "No estimation routine provided to Arbitrary." raise NotImplementedError(emsg) @@ -211,7 +212,8 @@ def _transform_parametersraw(self, pars, in_format, out_format): return temp def _valueraw(self, pars, r): - """Compute the value of the polynomial given a set of parameters and evaluation points. + """Compute the value of the polynomial given a set of parameters + and evaluation points. This method ensures that the input parameters conform to the expected count and then delegates the computation to an internal method `valuef`. diff --git a/src/diffpy/srmise/baselines/base.py b/src/diffpy/srmise/baselines/base.py index c1ecf0e..bad8244 100644 --- a/src/diffpy/srmise/baselines/base.py +++ b/src/diffpy/srmise/baselines/base.py @@ -24,7 +24,8 @@ class BaselineFunction(BaseFunction): - """Base class for functions which represent some data's baseline term. + """Base class for functions which represent some data's baseline + term. Class members ------------- @@ -71,7 +72,7 @@ def __init__( base=None, Cache=None, ): - """Set parameterdict defined by subclass + """Set parameterdict defined by subclass. parameterdict : dict The dictionary mapping string keys to their index in a @@ -91,7 +92,8 @@ def __init__( additional functionality. Cache : class The class (not instance) which implements caching of BaseFunction - evaluations.""" + evaluations. + """ BaseFunction.__init__(self, parameterdict, parformats, default_formats, metadict, base, Cache) # "Virtual" class methods #### @@ -117,10 +119,12 @@ def getmodule(self): class Baseline(ModelPart): - """Represents a baseline associated with a BaselineFunction subclass.""" + """Represents a baseline associated with a BaselineFunction + subclass.""" def __init__(self, owner, pars, free=None, removable=False, static_owner=False): - """Initialize the BaselineComponent instance with specified configurations. + """Initialize the BaselineComponent instance with specified + configurations. Parameters ---------- diff --git a/src/diffpy/srmise/baselines/fromsequence.py b/src/diffpy/srmise/baselines/fromsequence.py index 1866441..347c14d 100644 --- a/src/diffpy/srmise/baselines/fromsequence.py +++ b/src/diffpy/srmise/baselines/fromsequence.py @@ -23,14 +23,18 @@ class FromSequence(BaselineFunction): - """Methods for evaluation of a baseline from discrete data via interpolation. + """Methods for evaluation of a baseline from discrete data via + interpolation. - FromSequence uses cubic spline interpolation (no smoothing) on discrete - points to approximate the baseline at arbitrary points within the - interpolation domain. This baseline function permits no free parameters.""" + FromSequence uses cubic spline interpolation (no smoothing) on + discrete points to approximate the baseline at arbitrary points + within the interpolation domain. This baseline function permits no + free parameters. + """ def __init__(self, *args, **kwds): - """Initialize a baseline object based on input sequences `x` and `y`. + """Initialize a baseline object based on input sequences `x` and + `y`. This class provides two ways to initialize: by directly providing the sequences or by specifying a file that contains the sequences. @@ -181,7 +185,8 @@ def _transform_parametersraw(self, pars, in_format, out_format): return temp def _valueraw(self, pars, r): - """Return value of polynomial for the given parameters and r values. + """Return value of polynomial for the given parameters and r + values. Parameters ---------- @@ -233,7 +238,7 @@ def xyrepr(self, var): return "[%s]" % ", ".join([repr(v) for v in var]) def readxy(self, filename): - """ """ + """""" from diffpy.srmise.srmiseerrors import SrMiseDataFormatError # TODO: Make this safer diff --git a/src/diffpy/srmise/baselines/nanospherical.py b/src/diffpy/srmise/baselines/nanospherical.py index a76719f..1c199c2 100644 --- a/src/diffpy/srmise/baselines/nanospherical.py +++ b/src/diffpy/srmise/baselines/nanospherical.py @@ -22,7 +22,8 @@ class NanoSpherical(BaselineFunction): - """Methods for evaluation of baseline of spherical nanoparticle of uniform density. + """Methods for evaluation of baseline of spherical nanoparticle of + uniform density. Allowed formats are internal: [scale, radius] @@ -212,7 +213,8 @@ def _transform_parametersraw(self, pars, in_format, out_format): return temp def _valueraw(self, pars, r): - """Return value of spherical baseline for the given parameters and r values. + """Return value of spherical baseline for the given parameters + and r values. Outside the interval [0, radius] the baseline is 0. @@ -245,7 +247,8 @@ def _valueraw(self, pars, r): return out def _valueraw2(self, pars, r): - """Return value of spherical baseline without bounds checking for given parameters and r values. + """Return value of spherical baseline without bounds checking + for given parameters and r values. Parameters ---------- @@ -267,7 +270,7 @@ def _valueraw2(self, pars, r): return -s * r * (1 - (3.0 / 4.0) * rdivR + (1.0 / 16.0) * rdivR**3) def _getdomain(self, pars, r): - """Return slice object for which r > 0 and r < twice the radius + """Return slice object for which r > 0 and r < twice the radius. Parameters ---------- diff --git a/src/diffpy/srmise/baselines/polynomial.py b/src/diffpy/srmise/baselines/polynomial.py index 6ec155e..9d61574 100644 --- a/src/diffpy/srmise/baselines/polynomial.py +++ b/src/diffpy/srmise/baselines/polynomial.py @@ -23,7 +23,8 @@ class Polynomial(BaselineFunction): - """Methods for evaluation and parameter estimation of a polynomial baseline.""" + """Methods for evaluation and parameter estimation of a polynomial + baseline.""" def __init__(self, degree, Cache=None): """Initialize a polynomial function of degree d. @@ -186,7 +187,8 @@ def _transform_parametersraw(self, pars, in_format, out_format): return temp def _valueraw(self, pars, r): - """Return value of polynomial for the given parameters and r values. + """Return value of polynomial for the given parameters and r + values. Parameters ---------- diff --git a/src/diffpy/srmise/dataclusters.py b/src/diffpy/srmise/dataclusters.py index 4a057c3..5cac3b1 100644 --- a/src/diffpy/srmise/dataclusters.py +++ b/src/diffpy/srmise/dataclusters.py @@ -11,7 +11,8 @@ # See LICENSE.txt for license information. # ############################################################################## -"""Defines class to partition sequences representing the x and y axis into peak-like clusters.""" +"""Defines class to partition sequences representing the x and y axis +into peak-like clusters.""" import logging @@ -53,7 +54,7 @@ class DataClusters: """ def __init__(self, x, y, res): - """Constructor + """Constructor. Parameters ---------- @@ -102,8 +103,8 @@ def __eq__(self, other): ) def _clear(self): - """ - Clear all data and reset the cluster object to a transient initial state. + """Clear all data and reset the cluster object to a transient + initial state. The purpose of this method is to provide a clean state before creating new clustering operations. The object is updated in-place and no new instance is returned. @@ -176,7 +177,8 @@ def __next__(self): """Cluster point with largest y-coordinate left, returning self. next() always adds at least one additional point to the existing - cluster, or raises an exception if all points have been clustered. + cluster, or raises an exception if all points have been + clustered. """ if self.status == self.INIT: raise Exception("Cannot cluster next point while status is INIT.") @@ -257,7 +259,8 @@ def find_nearest_cluster2(self, x): return self.find_nearest_cluster(idx - 1) def find_nearest_cluster(self, idx): - """Return [cluster index, distance] for cluster nearest to x[idx]. + """Return [cluster index, distance] for cluster nearest to + x[idx]. The distance is positive/negative if the point is right/left of the nearest cluster. If the point is within an existing cluster then @@ -332,7 +335,8 @@ def cluster_is_full(self, cluster_idx): return self.clusters[cluster_idx, 0] == low and self.clusters[cluster_idx, 1] == high def combine_clusters(self, combine): - """Combine clusters specified by each subarray of cluster indices. + """Combine clusters specified by each subarray of cluster + indices. Clusters to combine must be contiguous, increasing, and have no unclustered points between them. @@ -386,7 +390,8 @@ def combine_clusters(self, combine): self.clusters = np.delete(self.clusters, todelete, 0) def find_adjacent_clusters(self): - """Return all cluster indices with no unclustered points between them. + """Return all cluster indices with no unclustered points between + them. Return array([[leftmost_idx1,...,rightmost_idx1],...]) such that there are no unclustered points between each element in subarray of clusters @@ -465,7 +470,10 @@ def plot(self, *args, **kwds): return def animate(self): - """Animate clustering. Restores state when complete.""" + """Animate clustering. + + Restores state when complete. + """ clusters = self.clusters current_idx = self.current_idx lastcluster_idx = self.lastcluster_idx diff --git a/src/diffpy/srmise/modelcluster.py b/src/diffpy/srmise/modelcluster.py index 1525ddc..0d92f30 100644 --- a/src/diffpy/srmise/modelcluster.py +++ b/src/diffpy/srmise/modelcluster.py @@ -40,7 +40,8 @@ class ModelCovariance(object): - """Helper class preserves uncertainty info (full covariance matrix) for a fit model. + """Helper class preserves uncertainty info (full covariance matrix) + for a fit model. This object preserves a light-weight "frozen" version of a model which can be used to interrogate the model about the uncertainties of its parameters. @@ -137,7 +138,8 @@ def setcovariance(self, model, cov): rawi += 1 def transform(self, in_format, out_format, **kwds): - """Transform parameters and covariance matrix under specified change of variables. + """Transform parameters and covariance matrix under specified + change of variables. By default this change applies to all parameters of the model. If the specified transformation is invalid for a given ModelPart the original parameterization is maintained for that part. @@ -226,7 +228,8 @@ def transform(self, in_format, out_format, **kwds): return def getcorrelation(self, i, j): - """Return the correlation between variables i and j, Corr_ij=Cov_ij/(sigma_i sigma_j) + """Return the correlation between variables i and j, + Corr_ij=Cov_ij/(sigma_i sigma_j) The variables may be specified as integers, or as a two-component tuple of integers (l, m) which indicate the mth parameter in peak l. @@ -262,8 +265,9 @@ def getcorrelation(self, i, j): def getvalue(self, i): """Return value of parameter i. - The variable may be specified as an integer, or as a two-component tuple of integers (l, m) - which indicate the mth parameter of modelpart l. + The variable may be specified as an integer, or as a two- + component tuple of integers (l, m) which indicate the mth + parameter of modelpart l. """ (l, m) = i if i in self.pmap else self.ipmap[i] return self.model[l][m] @@ -334,7 +338,8 @@ def get(self, i): return (self.getvalue(i), self.getuncertainty(i)) def correlationwarning(self, threshold=0.8): - """Report distinct variables with magnitude of correlation greater than threshold. + """Report distinct variables with magnitude of correlation + greater than threshold. Returns a list of tuples (i, j, c), where i and j are tuples indicating the modelpart and parameter indices of the correlated variables, and @@ -363,7 +368,8 @@ def correlationwarning(self, threshold=0.8): return correlated def __str__(self): - """Return string of value (uncertainty) pairs for all parameters.""" + """Return string of value (uncertainty) pairs for all + parameters.""" if self.model is None or self.cov is None: return "Model and/or Covariance matrix undefined." lines = [] @@ -426,7 +432,6 @@ class ModelCluster(object): value: Return value of the model plus baseline valuebl: Return value of the baseline writestr: Return string representation of self. - """ def __init__(self, model, *args, **kwds): @@ -501,7 +506,8 @@ def __init__(self, model, *args, **kwds): def copy(self): """Return copy of this ModelCluster. - Equivalent to ModelCluster(self)""" + Equivalent to ModelCluster(self) + """ return ModelCluster(self) def addexternalpeaks(self, peaks): @@ -964,7 +970,8 @@ def deletepeak(self, idx): self.replacepeaks([], slice(idx, idx + 1)) def estimatepeak(self): - """Attempt to add single peak to empty cluster. Return True if successful. + """Attempt to add single peak to empty cluster. Return True if + successful. Returns ------- @@ -1126,7 +1133,8 @@ def fit( return new_qual def contingent_fit(self, minpoints, growth_threshold): - """Fit cluster if it has grown sufficiently large since its last fit. + """Fit cluster if it has grown sufficiently large since its last + fit. Parameters ---------- @@ -1149,7 +1157,10 @@ def contingent_fit(self, minpoints, growth_threshold): return None def cleanfit(self): - """Remove poor-quality peaks in the fit. Return number removed.""" + """Remove poor-quality peaks in the fit. + + Return number removed. + """ # Find peaks located outside the cluster pos = np.array([p["position"] for p in self.model]) left_idx = pos.searchsorted(self.r_cluster[0]) @@ -1219,7 +1230,8 @@ def reduce_to(self, x, y): Returns ------- ModelEvaluator or None - Return ModelEvaluator instance if fit changed, otherwise None.""" + Return ModelEvaluator instance if fit changed, otherwise None. + """ # No reduction necessary if self.model.value(x) < y: logger.debug("reduce_to: No reduction necessary.") @@ -1295,7 +1307,8 @@ def residual(self): return self.y_cluster - self.value() def quality(self, evaluator=None, **kwds): - """Return ModelEvaluator instance containing calculated quality of the model. + """Return ModelEvaluator instance containing calculated quality + of the model. ModelEvaluator objects may be compared as though they were numerical quantities. Its raw value is given by the 'stat' member. For more @@ -1323,7 +1336,8 @@ def quality(self, evaluator=None, **kwds): return evaluator_inst def plottable(self, joined=False): - """Return sequence suitable for plotting cluster model+baseline with matplotlib. + """Return sequence suitable for plotting cluster model+baseline + with matplotlib. Parameters ---------- @@ -1346,7 +1360,8 @@ def plottable(self, joined=False): return toreturn def plottable_residual(self): - """Return sequence suitable for plotting cluster residual with matplotlib. + """Return sequence suitable for plotting cluster residual with + matplotlib. Returns ------- @@ -1356,7 +1371,8 @@ def plottable_residual(self): return [self.r_cluster, self.residual()] def augment(self, source): - """Add peaks from another ModelCluster that improve this one's quality. + """Add peaks from another ModelCluster that improve this one's + quality. Parameters ---------- @@ -1427,14 +1443,15 @@ def __str__(self): def prune(self): """Remove peaks until model quality no longer improves. - Peaks are removed in a greedy fashion, and the best possible model is - by no means guaranteed. + Peaks are removed in a greedy fashion, and the best possible + model is by no means guaranteed. - Due to the somewhat exploratory nature of prune many non-convergent - fits will generally be performed, but it severely restricts the number - of function evaluations permitted during fitting, and so fits that do - not converge rapidly are abandoned. Nevertheless, occasionally this - method will take an unusually long time to complete. + Due to the somewhat exploratory nature of prune many non- + convergent fits will generally be performed, but it severely + restricts the number of function evaluations permitted during + fitting, and so fits that do not converge rapidly are abandoned. + Nevertheless, occasionally this method will take an unusually + long time to complete. """ if len(self.model) == 0: return diff --git a/src/diffpy/srmise/modelevaluators/aic.py b/src/diffpy/srmise/modelevaluators/aic.py index 1a1973b..24b4ef5 100644 --- a/src/diffpy/srmise/modelevaluators/aic.py +++ b/src/diffpy/srmise/modelevaluators/aic.py @@ -46,12 +46,13 @@ class AIC(ModelEvaluator): """ def __init__(self): - """ """ + """""" ModelEvaluator.__init__(self, "AIC", False) return def evaluate(self, fit, count_fixed=False, kshift=0): - """Return quality of fit for given ModelCluster using AIC (Akaike's Information Criterion). + """Return quality of fit for given ModelCluster using AIC + (Akaike's Information Criterion). Parameters ---------- @@ -66,7 +67,8 @@ def evaluate(self, fit, count_fixed=False, kshift=0): Returns ------- quality : float - The quality of fit for given ModelCluster.""" + The quality of fit for given ModelCluster. + """ # Number of parameters. By default, fixed parameters are ignored. k = fit.model.npars(count_fixed=count_fixed) + kshift if k < 0: @@ -88,7 +90,8 @@ def evaluate(self, fit, count_fixed=False, kshift=0): return self.stat def minpoints(self, npars): - """Calculates the minimum number of points required to make an estimate of a model's quality. + """Calculates the minimum number of points required to make an + estimate of a model's quality. Parameters ---------- @@ -104,7 +107,8 @@ def minpoints(self, npars): return 1 def parpenalty(self, k): - """Returns the cost for adding k parameters to the current model cluster. + """Returns the cost for adding k parameters to the current model + cluster. Parameters ---------- @@ -124,8 +128,9 @@ def parpenalty(self, k): return (2 * k) * fudgefactor def growth_justified(self, fit, k_prime): - """Returns whether adding k_prime parameters to the given model (ModelCluster) is justified - given the current quality of the fit. + """Returns whether adding k_prime parameters to the given model + (ModelCluster) is justified given the current quality of the + fit. The assumption is that adding k_prime parameters will result in "effectively 0" chiSquared cost, and so adding it is justified if the cost of adding @@ -170,7 +175,7 @@ def growth_justified(self, fit, k_prime): @staticmethod def akaikeweights(aics): - """Return sequence of Akaike weights for sequence of AICs + """Return sequence of Akaike weights for sequence of AICs. Parameters ---------- @@ -189,7 +194,7 @@ def akaikeweights(aics): @staticmethod def akaikeprobs(aics): - """Return sequence of Akaike probabilities for sequence of AICs + """Return sequence of Akaike probabilities for sequence of AICs. Parameters ---------- @@ -199,7 +204,8 @@ def akaikeprobs(aics): Returns ------- array-like - The sequence of Akaike probabilities""" + The sequence of Akaike probabilities + """ aic_weights = AIC.akaikeweights(aics) return aic_weights / np.sum(aic_weights) diff --git a/src/diffpy/srmise/modelevaluators/aicc.py b/src/diffpy/srmise/modelevaluators/aicc.py index b2a9286..66d49fc 100644 --- a/src/diffpy/srmise/modelevaluators/aicc.py +++ b/src/diffpy/srmise/modelevaluators/aicc.py @@ -45,13 +45,14 @@ class AICc(ModelEvaluator): """ def __init__(self): - """ """ + """""" ModelEvaluator.__init__(self, "AICc", False) return def evaluate(self, fit, count_fixed=False, kshift=0): - """Return quality of fit for given ModelCluster using AICc (Akaike's Information Criterion - with 2nd order correction for small sample size). + """Return quality of fit for given ModelCluster using AICc + (Akaike's Information Criterion with 2nd order correction for + small sample size). Parameters fit: A ModelCluster @@ -65,7 +66,8 @@ def evaluate(self, fit, count_fixed=False, kshift=0): Returns ------- float - Quality of AICc""" + Quality of AICc + """ # Number of parameters. By default, fixed parameters are ignored. k = fit.model.npars(count_fixed=count_fixed) + kshift if k < 0: @@ -87,7 +89,8 @@ def evaluate(self, fit, count_fixed=False, kshift=0): return self.stat def minpoints(self, npars): - """Calculates the minimum number of points required to make an estimate of a model's quality. + """Calculates the minimum number of points required to make an + estimate of a model's quality. Parameters ---------- @@ -105,7 +108,8 @@ def minpoints(self, npars): return npars + 2 def parpenalty(self, k, n): - """Returns the cost for adding k parameters to the current model cluster. + """Returns the cost for adding k parameters to the current model + cluster. Parameters ---------- @@ -128,7 +132,8 @@ def parpenalty(self, k, n): return (2 * k + float(2 * k * (k + 1)) / (n - k - 1)) * fudgefactor def growth_justified(self, fit, k_prime): - """Is adding k_prime parameters to ModelCluster justified given the current quality of the fit. + """Is adding k_prime parameters to ModelCluster justified given + the current quality of the fit. The assumption is that adding k_prime parameters will result in "effectively 0" chiSquared cost, and so adding it is justified if the cost of adding these parameters is less than the current @@ -171,7 +176,7 @@ def growth_justified(self, fit, k_prime): @staticmethod def akaikeweights(aics): - """Return sequence of Akaike weights for sequence of AICs + """Return sequence of Akaike weights for sequence of AICs. Parameters ---------- @@ -190,7 +195,7 @@ def akaikeweights(aics): @staticmethod def akaikeprobs(aics): - """Return sequence of Akaike probabilities for sequence of AICs + """Return sequence of Akaike probabilities for sequence of AICs. Parameters ---------- @@ -200,7 +205,8 @@ def akaikeprobs(aics): Returns ------- array-like - The sequence of Akaike probabilities""" + The sequence of Akaike probabilities + """ aic_weights = AICc.akaikeweights(aics) return aic_weights / np.sum(aic_weights) diff --git a/src/diffpy/srmise/modelevaluators/base.py b/src/diffpy/srmise/modelevaluators/base.py index 179e082..f190e27 100644 --- a/src/diffpy/srmise/modelevaluators/base.py +++ b/src/diffpy/srmise/modelevaluators/base.py @@ -48,12 +48,14 @@ class ModelEvaluator: - """Class for evaluating the quality of a fit. Comparison between different - models of the same type is defined so that better models are 'greater than' - worse models.""" + """Class for evaluating the quality of a fit. + + Comparison between different models of the same type is defined so + that better models are 'greater than' worse models. + """ def __init__(self, method, higher_is_better): - """Constructor of ModelEvaluator + """Constructor of ModelEvaluator. Parameters ---------- @@ -69,7 +71,7 @@ def __init__(self, method, higher_is_better): return def __lt__(self, other): - """ """ + """""" assert self.method == other.method # Comparison between same types required assert self.stat is not None and other.stat is not None # The statistic must already be calculated @@ -80,7 +82,7 @@ def __lt__(self, other): return other.stat < self.stat def __le__(self, other): - """ """ + """""" assert self.method == other.method # Comparison between same types required assert self.stat is not None and other.stat is not None # The statistic must already be calculated @@ -91,7 +93,7 @@ def __le__(self, other): return other.stat <= self.stat def __eq__(self, other): - """ """ + """""" assert self.method == other.method # Comparison between same types required assert self.stat is not None and other.stat is not None # The statistic must already be calculated @@ -99,7 +101,7 @@ def __eq__(self, other): return self.stat == other.stat def __ne__(self, other): - """ """ + """""" assert self.method == other.method # Comparison between same types required assert self.stat is not None and other.stat is not None # The statistic must already be calculated @@ -107,7 +109,7 @@ def __ne__(self, other): return self.stat != other.stat def __gt__(self, other): - """ """ + """""" assert self.method == other.method # Comparison between same types required assert self.stat is not None and other.stat is not None # The statistic must already be calculated @@ -118,7 +120,7 @@ def __gt__(self, other): return other.stat > self.stat def __ge__(self, other): - """ """ + """""" assert self.method == other.method # Comparison between same types required assert self.stat is not None and other.stat is not None # The statistic must already be calculated @@ -138,7 +140,8 @@ def chi_squared(self, expected, observed, error): observed : float The observed value. error : float - The error statistic.""" + The error statistic. + """ self.chisq = np.sum((expected - observed) ** 2 / error**2) return self.chisq diff --git a/src/diffpy/srmise/modelparts.py b/src/diffpy/srmise/modelparts.py index 43a2141..8c591e1 100644 --- a/src/diffpy/srmise/modelparts.py +++ b/src/diffpy/srmise/modelparts.py @@ -569,7 +569,8 @@ def compress(self): Returns ------- pars : array-like - The compressed parameters of the model part.""" + The compressed parameters of the model part. + """ return self.pars[self.free] def jacobian(self, r, range=None): @@ -591,12 +592,14 @@ def jacobian(self, r, range=None): return self._owner.jacobian(self, r, range) def owner(self): - """Return the BaseFunction subclass instance which owns this part. + """Return the BaseFunction subclass instance which owns this + part. Returns ------- BaseFunction subclass - The BaseFunction subclass which owns this part.""" + The BaseFunction subclass which owns this part. + """ return self._owner def update(self, freepars): @@ -727,7 +730,8 @@ def npars(self, count_fixed=True): Returns ------- int - The number of parameters in all parts.""" + The number of parameters in all parts. + """ if count_fixed: return self._owner.npars else: @@ -738,7 +742,7 @@ def __str__(self): return str(self._owner.transform_parameters(self.pars, in_format="internal", out_format="default_output")) def __eq__(self, other): - """ """ + """""" if hasattr(other, "_owner"): return ( (self._owner is other._owner) @@ -750,7 +754,7 @@ def __eq__(self, other): return False def __ne__(self, other): - """ """ + """""" return not self == other def writestr(self, ownerlist): diff --git a/src/diffpy/srmise/multimodelselection.py b/src/diffpy/srmise/multimodelselection.py index c4c7b74..4bb85d1 100644 --- a/src/diffpy/srmise/multimodelselection.py +++ b/src/diffpy/srmise/multimodelselection.py @@ -33,10 +33,11 @@ def eatkwds(*args, **kwds): class MultimodelSelection(PeakStability): - """Quick and dirty multimodel selection using AIC and its offspring.""" + """Quick and dirty multimodel selection using AIC and its + offspring.""" def __init__(self): - """ """ + """""" self.dgs = np.array([]) self.dgs_idx = {} @@ -187,7 +188,8 @@ def makeaicprobs(self): self.aicprobs[dg] = em.akaikeprobs(self.aics[dg]) def makesortedprobs(self): - """Make probabilities for the sequence of AICs in a sorted order.""" + """Make probabilities for the sequence of AICs in a sorted + order.""" self.sortedprobs = {} for dg in self.dgs: @@ -203,7 +205,8 @@ def animate_probs(self, step=False, duration=0.0, **kwds): duration : float Minimum time in seconds to complete animation. Default is 0. - Keywords passed to pyplot.plot()""" + Keywords passed to pyplot.plot() + """ if duration > 0: import time @@ -248,7 +251,8 @@ def animate_classprobs(self, step=False, duration=0.0, **kwds): duration : float Minimum time in seconds to complete animation. Default is 0. - Keywords passed to pyplot.plot()""" + Keywords passed to pyplot.plot() + """ if duration > 0: import time @@ -461,7 +465,8 @@ def dg_key(self, dg_in): Returns ------- float - The dg value usable as a key nearest to dg_in.""" + The dg value usable as a key nearest to dg_in. + """ idx = (np.abs(self.dgs - dg_in)).argmin() return self.dgs[idx] @@ -476,7 +481,8 @@ def bestclasses(self, dgs=None): Returns ------- array-like - The best classes for all models.""" + The best classes for all models. + """ if dgs is None: dgs = self.dgs best = [] @@ -518,7 +524,8 @@ def classbestdgs(self, cls, dgs=None): Returns ------- array-like - Sequence of best uncertainties for the models.""" + Sequence of best uncertainties for the models. + """ if dgs is None: dgs = self.dgs bestdgs = [] @@ -528,7 +535,8 @@ def classbestdgs(self, cls, dgs=None): return bestdgs def modelbestdgs(self, model, dgs=None): - """Return uncertainties where given model has greatest Akaike probability. + """Return uncertainties where given model has greatest Akaike + probability. Parameters ---------- @@ -587,7 +595,8 @@ def plot3dclassprobs(self, **kwds): "fig" - The figure "axis" - The image axis "cbaxis" - The colorbar axis, if it exists. - "cb" - The colorbar, if it exists.""" + "cb" - The colorbar, if it exists. + """ from matplotlib import cm, colorbar, colors from matplotlib.collections import PolyCollection @@ -780,7 +789,8 @@ def get_class(self, dG, **kwds): return self.sortedclassprobs[dG][-1 - corder] # index of corderth best class def get_prob(self, dG, **kwds): - """Return Akaike probability of best model of best class at given dG. + """Return Akaike probability of best model of best class at + given dG. Parameters ---------- @@ -807,7 +817,8 @@ def get_prob(self, dG, **kwds): return self.classprobs[dG][cls_idx] def get_nfree(self, dG, **kwds): - """Return number of free parameters of best model of best class at given dG. + """Return number of free parameters of best model of best class + at given dG. Parameters ---------- @@ -832,7 +843,8 @@ def get_nfree(self, dG, **kwds): return model.npars(count_fixed=False) + baseline.npars(count_fixed=False) def get_aic(self, dG, **kwds): - """Return number of free parameters of best model of best class at given dG. + """Return number of free parameters of best model of best class + at given dG. Parameters ---------- @@ -855,7 +867,8 @@ def get_aic(self, dG, **kwds): return self.aics[dG][idx].stat def get(self, dG, *args, **kwds): - """Return tuple of values corresponding to string arguments for best model of best class at given dG. + """Return tuple of values corresponding to string arguments for + best model of best class at given dG. Parameters ---------- @@ -891,7 +904,8 @@ def get(self, dG, *args, **kwds): return tuple(values) def maxprobdG_byclass(self, model): - """Return the post-hoc dG for which the given model's Akaike probability is maximized. + """Return the post-hoc dG for which the given model's Akaike + probability is maximized. Each model is mapped to its class' best member. @@ -911,8 +925,8 @@ def maxprobdG_byclass(self, model): return self.dgs[prob_idx] def maxprobdG_bymodel(self, model): - """Return the post-hoc dG for which the given model's Akaike probability is maximized. - Classes are not considered. + """Return the post-hoc dG for which the given model's Akaike + probability is maximized. Classes are not considered. Parameters ---------- @@ -941,7 +955,8 @@ def maxprobmodel_byclass(self, dG): Returns ------- float - The model mapped by class which maximizes probability at given dG.""" + The model mapped by class which maximizes probability at given dG. + """ cls = self.sortedclassprobs[dG][-1] m = self.sortedclasses[dG][cls][-1] return m @@ -958,6 +973,7 @@ def maxprobmodel_bymodel(self, dG): Returns ------- model : array-like - The model which maximizes probability at given dG.""" + The model which maximizes probability at given dG. + """ # Note that if there are identical models this returns the one of greatest dg. return self.sortedprobs[dG][-1] diff --git a/src/diffpy/srmise/pdfdataset.py b/src/diffpy/srmise/pdfdataset.py index 6f41d30..56c473a 100644 --- a/src/diffpy/srmise/pdfdataset.py +++ b/src/diffpy/srmise/pdfdataset.py @@ -14,10 +14,7 @@ # LICENSE_PDFgui.txt for the full PDFgui license. # ############################################################################## - - -"""class PDFDataSet for experimental PDF data. -""" +"""Class PDFDataSet for experimental PDF data.""" import os.path @@ -32,7 +29,7 @@ class PDFComponent(object): """Common base class.""" def __init__(self, name): - """initialize the object + """Initialize the object. Parameter --------- @@ -42,7 +39,7 @@ def __init__(self, name): self.name = name def close(self, force=False): - """close myself + """Close myself. Parameter --------- @@ -122,9 +119,11 @@ def __init__(self, name): return def clear(self): - """reset all data members to initial empty values + """Reset all data members to initial empty values. - The purpose of this method is to set the PDF dataset to initial empty values.""" + The purpose of this method is to set the PDF dataset to initial + empty values. + """ self.robs = [] self.Gobs = [] self.drobs = [] @@ -144,7 +143,8 @@ def clear(self): def setvar(self, var, value): """Assign a data member using PdfFit-style variable notation. - This method is typically utilized by the `applyParameters()` function. + This method is typically utilized by the `applyParameters()` + function. Parameters ---------- @@ -169,8 +169,8 @@ def setvar(self, var, value): return def getvar(self, var): - """Obtain value corresponding to PdfFit dataset variable. - Used by findParameters(). + """Obtain value corresponding to PdfFit dataset variable. Used + by findParameters(). Parameters ---------- @@ -192,7 +192,7 @@ def getvar(self, var): return value def read(self, filename): - """load data from PDFGetX2 or PDFGetN gr file + """Load data from PDFGetX2 or PDFGetN gr file. filename : str file to read from @@ -217,7 +217,7 @@ def read(self, filename): return self def readStr(self, datastring): - """read experimental PDF data from a string + """Read experimental PDF data from a string. Parameter --------- @@ -364,7 +364,6 @@ def write(self, filename): def writeStr(self): """String representation of experimental PDF data. - Returns ------- str @@ -411,7 +410,7 @@ def writeStr(self): return datastring def copy(self, other=None): - """copy self to other. if other is None, create new instance + """Copy self to other. if other is None, create new instance. Parameters ---------- diff --git a/src/diffpy/srmise/pdfpeakextraction.py b/src/diffpy/srmise/pdfpeakextraction.py index 6142e68..af52fb4 100644 --- a/src/diffpy/srmise/pdfpeakextraction.py +++ b/src/diffpy/srmise/pdfpeakextraction.py @@ -36,8 +36,8 @@ class PDFPeakExtraction(PeakExtraction): - """PDFPeakExtraction extends the PeakExtraction class to specialize in extracting - peaks from PDF (Probability Density Function) data. + """PDFPeakExtraction extends the PeakExtraction class to specialize + in extracting peaks from PDF (Probability Density Function) data. Parameters ---------- @@ -77,7 +77,6 @@ def loadpdf(self, pdf): ---------- pdf: PDFDataSet instance or str The PDFDataSet instance or a PDF file name. - """ self.clear() if isinstance(pdf, PDFDataSet): @@ -98,7 +97,8 @@ def setdata(self, x, y, dx=None, dy=None): x : array-like The x-coordinates of the data. y : array-like - The y-coordinates of the data.""" + The y-coordinates of the data. + """ PeakExtraction.setdata(self, x, y, dx, dy) try: self.qmax_fromdata = find_qmax(self.x, self.y)[0] @@ -108,7 +108,9 @@ def setdata(self, x, y, dx=None, dy=None): def clear(self): """Clear all members. - The purpose of the method is to ensure the object is in a clean state.""" + The purpose of the method is to ensure the object is in a clean + state. + """ # TODO: Clear additional members self.filename = None self.nyquist = None @@ -190,7 +192,8 @@ def defaultvars(self, *args): Parameters ---------- *args : argparse.Namespace - Arguments passed to PeakExtraction.setdata().""" + Arguments passed to PeakExtraction.setdata(). + """ nargs = list(args) # qmax preference: reported, then fromdata, then 0. @@ -250,7 +253,8 @@ def defaultvars(self, *args): PeakExtraction.defaultvars(self, *nargs) def resampledata(self, dr, **kwds): - """Return (x, y, error in x, effective error in y) resampled by interval dr. + """Return (x, y, error in x, effective error in y) resampled by + interval dr. Uses values of self.x, self.y, self.dx, self.effective_dy. The range is constrained by self.rng. @@ -276,7 +280,8 @@ def resampledata(self, dr, **kwds): Returns ------- tuple of ndarray - A tuple containing the resampled (x, y, error in x, effective error in y).""" + A tuple containing the resampled (x, y, error in x, effective error in y). + """ self.defaultvars() # Find correct range if necessary. eps = kwds.get("eps", 10**-6) @@ -318,7 +323,8 @@ def errorscale(self, dr): Returns ------- float - The uncertainties scaled.""" + The uncertainties scaled. + """ if self.qmax > 0 and self.nyquist and self.scale: dr_nyquist = np.pi / self.qmax return np.max([np.sqrt(dr_nyquist / dr), 1.0]) @@ -326,7 +332,8 @@ def errorscale(self, dr): return 1.0 def extract(self, **kwds): - """Extract peaks from the PDF. Returns ModelCovariance instance summarizing results. + """Extract peaks from the PDF. Returns ModelCovariance instance + summarizing results. Parameters ---------- @@ -540,7 +547,8 @@ def extract(self, **kwds): return cov def fit(self, **kwds): - """Fit peaks in the PDF. Returns ModelCovariance instance summarizing results. + """Fit peaks in the PDF. Returns ModelCovariance instance + summarizing results. Parameters ---------- @@ -726,7 +734,8 @@ def writepwa(self, filename, comments="n/a"): return def writepwastr(self, comments): - """Return string of extracted peaks (position, width, area) in PDF. + """Return string of extracted peaks (position, width, area) in + PDF. There is not enough information to recreate the extracted peaks from this file. @@ -1033,7 +1042,8 @@ def find_qmax(r, y, showgraphs=False): def stdratio(data): - """Calculate ratio of standard deviation for runs of equal length in data. + """Calculate ratio of standard deviation for runs of equal length in + data. Uses a numerically-stable online algorithm for calculating the standard deviation. @@ -1047,7 +1057,8 @@ def stdratio(data): ------- array-like an array of length floor(len(data)/2)-1. The ith element is - equivalent to std(data[:i+2])/std(data[i+2:2i+4]).""" + equivalent to std(data[:i+2])/std(data[i+2:2i+4]). + """ limit = int(np.floor(len(data) / 2)) std_left = np.zeros(limit) diff --git a/src/diffpy/srmise/peakextraction.py b/src/diffpy/srmise/peakextraction.py index dd0b0cd..3bcb084 100644 --- a/src/diffpy/srmise/peakextraction.py +++ b/src/diffpy/srmise/peakextraction.py @@ -70,7 +70,8 @@ def __init__(self, newvars=[]): Parameters newvars : array-like - Sequence of strings that represent additional extraction parameters.""" + Sequence of strings that represent additional extraction parameters. + """ self.clear() self.extractvars = dict.fromkeys( ( @@ -94,7 +95,9 @@ def __init__(self, newvars=[]): def clear(self): """Clear all members. - The purpose of the method is to ensure the object is in initialized state.""" + The purpose of the method is to ensure the object is in + initialized state. + """ self.x = None self.y = None self.dx = None @@ -263,7 +266,8 @@ def __str__(self): return "\n".join(out) + "\n" def plot(self, **kwds): - """Convenience function to plot data and extracted peaks with matplotlib. + """Convenience function to plot data and extracted peaks with + matplotlib. Uses initial peaks instead if no peaks have been extracted. @@ -299,7 +303,7 @@ def plot(self, **kwds): plt.plot(*mcluster.plottable(kwds)) def read(self, filename): - """load PeakExtraction object from file + """Load PeakExtraction object from file. Parameters ---------- @@ -539,7 +543,8 @@ def readstr(self, datastring): self.extracted = ModelCluster.factory(mc, pfbaselist=safepf, blfbaselist=safebf) def write(self, filename): - """Write string representation of PeakExtraction instance to file. + """Write string representation of PeakExtraction instance to + file. Parameters ---------- @@ -712,7 +717,8 @@ def writesummary(self): pass def getrangeslice(self): - """Convert the ranges in terms of x-coordinates to a slice object.""" + """Convert the ranges in terms of x-coordinates to a slice + object.""" low_idx = 0 while self.x[low_idx] < max(self.x[0], self.rng[0]): low_idx += 1 @@ -785,7 +791,8 @@ def estimate_peak(self, x, add=True): return None def add_peaks(self, peaks): - """Add peaks to extracted peaks, or initial_peaks if no extracted peaks exist. + """Add peaks to extracted peaks, or initial_peaks if no + extracted peaks exist. Parameters ---------- @@ -801,14 +808,16 @@ def add_peaks(self, peaks): self.initial_peaks.sort(key="position") def extract_single(self, recursion_depth=1): - """Find ModelCluster with peaks extracted from data. Return ModelCovariance instance at top level. + """Find ModelCluster with peaks extracted from data. Return + ModelCovariance instance at top level. Every extracted peak is one of the peak functions supplied. All comparisons of different peak models are performed with the class specified by error_method. Parameters - recursion_depth: (1) Tracks recursion with extract_single.""" + recursion_depth: (1) Tracks recursion with extract_single. + """ self.clearcalc() tracer = srmiselog.tracer tracer.pushc() @@ -1319,8 +1328,10 @@ def extract_single(self, recursion_depth=1): return cov def fit_single(self): - """Fit peaks in initial_peaks with baseline. Return ModelCovariance - instance summarizing results.""" + """Fit peaks in initial_peaks with baseline. + + Return ModelCovariance instance summarizing results. + """ self.clearcalc() diff --git a/src/diffpy/srmise/peaks/base.py b/src/diffpy/srmise/peaks/base.py index 44c7963..a13a312 100644 --- a/src/diffpy/srmise/peaks/base.py +++ b/src/diffpy/srmise/peaks/base.py @@ -70,7 +70,7 @@ def __init__( base=None, Cache=None, ): - """Set parameterdict defined by subclass + """Set parameterdict defined by subclass. parameterdict: A dictionary mapping string keys to their index in a sequence of parameters for this PeakFunction subclass. @@ -85,7 +85,8 @@ def __init__( base: A basefunction subclass instance which this one decorates with additional functionality. Cache: A class (not instance) which implements caching of BaseFunction - evaluations.""" + evaluations. + """ if "position" not in parameterdict: emsg = "Argument parameterdict missing required key 'position'." raise ValueError(emsg) @@ -125,7 +126,8 @@ def __init__(self, *args, **kwds): ModelParts.__init__(self, *args, **kwds) def argsort(self, key="position"): - """Return sequence of indices which sort peaks in order specified by key.""" + """Return sequence of indices which sort peaks in order + specified by key.""" keypars = np.array([p[key] for p in self]) # In normal use the peaks will already be sorted, so check for it. sorted = True @@ -139,7 +141,8 @@ def argsort(self, key="position"): return range(len(keypars)) def match_at(self, x, y): - """Alter peaks so their sum at x is y, preserving each peak's maximum. + """Alter peaks so their sum at x is y, preserving each peak's + maximum. Each peak is scaled equally. Peaks with fixed parameters, a maximum very close to x, or other issues may prevent optimal results. If the @@ -201,7 +204,8 @@ def sort(self, reverse=False, key="position"): class Peak(ModelPart): - """Represents a single peak associated with a PeakFunction subclass.""" + """Represents a single peak associated with a PeakFunction + subclass.""" def __init__(self, owner, pars, free=None, removable=True, static_owner=False): """Set instance members. diff --git a/src/diffpy/srmise/peaks/gaussian.py b/src/diffpy/srmise/peaks/gaussian.py index c23358e..51a8513 100644 --- a/src/diffpy/srmise/peaks/gaussian.py +++ b/src/diffpy/srmise/peaks/gaussian.py @@ -23,7 +23,8 @@ class Gaussian(PeakFunction): - """Methods for evaluation and parameter estimation of width-limited Gaussian. + """Methods for evaluation and parameter estimation of width-limited + Gaussian. Allowed formats are internal: [position, parameterized width-squared, area] @@ -44,7 +45,7 @@ class Gaussian(PeakFunction): # which the function is considered 0. By default this distance is # equivalent to 3 standard deviations. def __init__(self, maxwidth, Cache=None): - """maxwidth defined as full width at half maximum for the + """Maxwidth defined as full width at half maximum for the corresponding Gaussian, which is physically relevant.""" parameterdict = {"position": 0, "width": 1, "area": 2} formats = ["internal", "pwa", "mu_sigma_area"] @@ -172,7 +173,8 @@ def scale_at(self, pars, x, scale): Returns ------- tuple - mu, area, and sigma that are scaled.""" + mu, area, and sigma that are scaled. + """ if scale <= 0: emsg = "".join(["Cannot scale by ", str(scale), "."]) raise SrMiseScalingError(emsg) @@ -346,7 +348,8 @@ def _transform_parametersraw(self, pars, in_format, out_format): return temp def _valueraw(self, pars, r): - """Compute the value of a width-limited Gaussian for the specified parameters at given radial distances. + """Compute the value of a width-limited Gaussian for the + specified parameters at given radial distances. This function calculates the value of a Gaussian distribution, where its effective width is constrained and related to the maxwidth. As `pars[1]` approaches infinity, @@ -383,6 +386,7 @@ def getmodule(self): def max(self, pars): """Return position and height of the peak maximum. + Parameters ---------- pars : array_like @@ -391,7 +395,8 @@ def max(self, pars): Returns ------- array_like - The position and height of the peak maximum.""" + The position and height of the peak maximum. + """ # TODO: Reconsider this behavior if len(pars) == 0: return None diff --git a/src/diffpy/srmise/peaks/gaussianoverr.py b/src/diffpy/srmise/peaks/gaussianoverr.py index 6e108e6..8e5d4cf 100644 --- a/src/diffpy/srmise/peaks/gaussianoverr.py +++ b/src/diffpy/srmise/peaks/gaussianoverr.py @@ -23,7 +23,8 @@ class GaussianOverR(PeakFunction): - """Methods for evaluation and parameter estimation of width-limited Gaussian/r. + """Methods for evaluation and parameter estimation of width-limited + Gaussian/r. Allowed formats are internal: [position, parameterized width-squared, area] @@ -44,7 +45,7 @@ class GaussianOverR(PeakFunction): # which the function is considered 0. By default this distance is # equivalent to 3 standard deviations. def __init__(self, maxwidth, Cache=None): - """maxwidth defined as full width at half maximum for the + """Maxwidth defined as full width at half maximum for the corresponding Gaussian, which is physically relevant.""" parameterdict = {"position": 0, "width": 1, "area": 2} formats = ["internal", "pwa", "mu_sigma_area"] @@ -221,8 +222,7 @@ def scale_at(self, pars, x, scale): return tpars def _jacobianraw(self, pars, r, free): - """ - Compute the Jacobian of a width-limited Gaussian/r function. + """Compute the Jacobian of a width-limited Gaussian/r function. This method calculates the partial derivatives of a Gaussian/r function with respect to its parameters, considering a limiting width. The Gaussian/r's @@ -285,7 +285,8 @@ def _jacobianraw(self, pars, r, free): return jacobian def _transform_derivativesraw(self, pars, in_format, out_format): - """Return gradient matrix for the pars converted from in_format to out_format. + """Return gradient matrix for the pars converted from in_format + to out_format. Parameters pars: Sequence of parameters @@ -412,7 +413,8 @@ def _transform_parametersraw(self, pars, in_format, out_format): return temp def _valueraw(self, pars, r): - """Compute the value of a width-limited Gaussian/r for the specified parameters at given radial distances. + """Compute the value of a width-limited Gaussian/r for the + specified parameters at given radial distances. This function calculates the value of a Gaussian/r distribution, where its effective width is constrained and related to the maxwidth. As `pars[1]` approaches infinity, @@ -456,7 +458,8 @@ def max(self, pars): Returns ------- array-like - The sequence of position and height of the peak maximum.""" + The sequence of position and height of the peak maximum. + """ # TODO: Reconsider this behavior if len(pars) == 0: return None diff --git a/src/diffpy/srmise/peaks/terminationripples.py b/src/diffpy/srmise/peaks/terminationripples.py index c516c96..e135083 100644 --- a/src/diffpy/srmise/peaks/terminationripples.py +++ b/src/diffpy/srmise/peaks/terminationripples.py @@ -23,10 +23,12 @@ class TerminationRipples(PeakFunction): - """Methods for evaluation and parameter estimation of a peak function with termination ripples.""" + """Methods for evaluation and parameter estimation of a peak + function with termination ripples.""" def __init__(self, base, qmax, extension=4.0, supersample=5.0, Cache=None): - """Peak function constructor which adds termination ripples to existing function. + """Peak function constructor which adds termination ripples to + existing function. Unlike other peak functions, TerminationRipples can only be evaluated over a uniform grid, or at a single value using an ad hoc uniform grid @@ -46,7 +48,8 @@ def __init__(self, base, qmax, extension=4.0, supersample=5.0, Cache=None): cannot be determined while extending calculations. Default is 5.0. Cache : class The class (not instance) which implements caching of PeakFunction - evaluations.""" + evaluations. + """ parameterdict = base.parameterdict formats = base.parformats default_formats = base.default_formats @@ -89,7 +92,8 @@ def estimate_parameters(self, r, y): # TODO: Can this be implemented sanely for termination ripples? def scale_at(self, pars, x, scale): - """Change parameters so value(x)->scale*value(x) for the base function. + """Change parameters so value(x)->scale*value(x) for the base + function. Does not change position or height of peak's maxima. Raises SrMiseScalingError if the parameters cannot be scaled. @@ -131,7 +135,8 @@ def _jacobianraw(self, pars, r, free): return self.base._jacobianraw(pars, r, free) def _transform_derivativesraw(self, pars, in_format, out_format): - """Return gradient matrix for the pars converted from in_format to out_format. + """Return gradient matrix for the pars converted from in_format + to out_format. Parameters ---------- @@ -169,7 +174,8 @@ def _transform_parametersraw(self, pars, in_format, out_format): return self.base._transform_parametersraw(pars, in_format, out_format) def _valueraw(self, pars, r): - """Return value of base peak function for the given parameters and r values. + """Return value of base peak function for the given parameters + and r values. pars : array-like The sequence of parameters for a single peak @@ -179,7 +185,8 @@ def _valueraw(self, pars, r): Returns ------- float - The value of base peak function for the given parameters and r.""" + The value of base peak function for the given parameters and r. + """ return self.base._valueraw(pars, r) # Overridden PeakFunction functions #### @@ -205,7 +212,8 @@ def jacobian(self, peak, r, rng=None): Returns ------- jac : array-like - The Jacobian of base function with termination ripples.""" + The Jacobian of base function with termination ripples. + """ if self is not peak._owner: raise ValueError( "Argument 'peak' must be evaluated by the " @@ -244,7 +252,8 @@ def jacobian(self, peak, r, rng=None): return jac def value(self, peak, r, rng=None): - """Calculate (rippled) value of peak, possibly restricted by range. + """Calculate (rippled) value of peak, possibly restricted by + range. This function overrides its counterpart in PeakFunction in order to minimize the impact of edge-effects from introducing termination @@ -361,7 +370,8 @@ def extend_grid(self, r, dr): Returns ------- tuple - The extended r, slice giving original range.""" + The extended r, slice giving original range. + """ ext = self.extension * 2 * np.pi / self.qmax left_ext = np.arange(r[0] - dr, max(0.0, r[0] - ext - dr), -dr)[::-1] right_ext = np.arange(r[-1] + dr, r[-1] + ext + dr, dr) diff --git a/src/diffpy/srmise/peakstability.py b/src/diffpy/srmise/peakstability.py index 28c9517..f95774b 100644 --- a/src/diffpy/srmise/peakstability.py +++ b/src/diffpy/srmise/peakstability.py @@ -29,7 +29,8 @@ class PeakStability: """Utility to test robustness of peaks. results: [error scalar, model, bl, dr] - ppe: a PDFPeakExtraction instance""" + ppe: a PDFPeakExtraction instance + """ def __init__(self): self.results = [] @@ -106,7 +107,10 @@ def plotseries(self, style="o", **kwds): plt.draw() def plot(self, **kwds): - """Plot the current model. Keywords passed to pyplot.plot()""" + """Plot the current model. + + Keywords passed to pyplot.plot() + """ plt.clf() plt.plot(*self.ppe.extracted.plottable(), **kwds) q = self.ppe.extracted.quality() @@ -187,7 +191,8 @@ def run(self, err, savecovs=False): The sequence of uncertainties to run at. savecovs : bool boolean to determine to save covariance matrix. Default is False. - If savecovs is True, return the covariance matrix for each final fit.""" + If savecovs is True, return the covariance matrix for each final fit. + """ self.results = [] covs = [] diff --git a/src/diffpy/srmise/srmiseerrors.py b/src/diffpy/srmise/srmiseerrors.py index 62953d5..22e8948 100644 --- a/src/diffpy/srmise/srmiseerrors.py +++ b/src/diffpy/srmise/srmiseerrors.py @@ -13,20 +13,20 @@ ############################################################################## """Defines all custom exceptions used by diffpy.srmise. - Classes - ------- - SrMiseError: Subclass of Exception, and superclass of all diffpy.srmise exceptions. - SrMiseDataFormatError: Error in format of diffpy.srmise data. - SrMiseEstimationError: Parameter estimation error. - SrMiseFileError: Error while reading/writing files. - SrMiseFitError: Error while fitting. - SrMiseLogError: Error while logging. - SrMiseModelEvaluatorError: Error while computing or comparing model quality. - SrMisePDFKeyError: Error in key referencing component of PDF dataset. - SrMiseQmaxError: Error in value of Qmax. - SrMiseScalingError: Error while scaling a peak function. - SrMiseStaticOwnerError: Error when changing ModelPart instance owner. - """ +Classes +------- +SrMiseError: Subclass of Exception, and superclass of all diffpy.srmise exceptions. +SrMiseDataFormatError: Error in format of diffpy.srmise data. +SrMiseEstimationError: Parameter estimation error. +SrMiseFileError: Error while reading/writing files. +SrMiseFitError: Error while fitting. +SrMiseLogError: Error while logging. +SrMiseModelEvaluatorError: Error while computing or comparing model quality. +SrMisePDFKeyError: Error in key referencing component of PDF dataset. +SrMiseQmaxError: Error in value of Qmax. +SrMiseScalingError: Error while scaling a peak function. +SrMiseStaticOwnerError: Error when changing ModelPart instance owner. +""" # Superclass class for diffpy.srmise.mise @@ -34,9 +34,10 @@ class SrMiseError(Exception): """Superclass of all diffpy.srmise exceptions.""" def __init__(self, info): - """initialize + """initialize. - info: description string""" + info: description string + """ Exception.__init__(self) self.info = info @@ -48,120 +49,168 @@ def __str__(self): class SrMiseDataFormatError(SrMiseError): - """diffpy.srmise exception class. Error in formatted data.""" + """diffpy.srmise exception class. + + Error in formatted data. + """ def __init__(self, info): - """initialize + """initialize. - info -- description string""" + info -- description string + """ SrMiseError.__init__(self, info) class SrMiseEstimationError(SrMiseError): - """diffpy.srmise.modelevaluator exception class. Parameter estimation error.""" + """diffpy.srmise.modelevaluator exception class. + + Parameter estimation error. + """ def __init__(self, info): - """initialize + """initialize. - info -- description string""" + info -- description string + """ SrMiseError.__init__(self, info) class SrMiseFileError(SrMiseError): - """diffpy.srmise exception class. Error while reading/writing files.""" + """diffpy.srmise exception class. + + Error while reading/writing files. + """ def __init__(self, info): - """initialize + """initialize. - info -- description string""" + info -- description string + """ SrMiseError.__init__(self, info) class SrMiseFitError(SrMiseError): - """diffpy.srmise exception class. Error occurred during fitting.""" + """diffpy.srmise exception class. + + Error occurred during fitting. + """ def __init__(self, info): - """initialize + """initialize. - info -- description string""" + info -- description string + """ SrMiseError.__init__(self, info) class SrMiseLogError(SrMiseError): - """diffpy.srmise exception class. Error while handling logging capabilities.""" + """diffpy.srmise exception class. + + Error while handling logging capabilities. + """ def __init__(self, info): - """initialize + """initialize. - info -- description string""" + info -- description string + """ SrMiseError.__init__(self, info) class SrMiseModelEvaluatorError(SrMiseError): - """diffpy.srmise.modelevaluator exception class. Error when comparing models.""" + """diffpy.srmise.modelevaluator exception class. + + Error when comparing models. + """ def __init__(self, info): - """initialize + """initialize. - info -- description string""" + info -- description string + """ SrMiseError.__init__(self, info) class SrMiseQmaxError(SrMiseError): - """diffpy.srmise.modelevaluator exception class. Error when setting qmax.""" + """diffpy.srmise.modelevaluator exception class. + + Error when setting qmax. + """ def __init__(self, info): - """initialize + """initialize. - info -- description string""" + info -- description string + """ SrMiseError.__init__(self, info) class SrMiseScalingError(SrMiseError): - """diffpy.srmise.peaks exception class. Error when scaling a peak function.""" + """diffpy.srmise.peaks exception class. + + Error when scaling a peak function. + """ def __init__(self, info): - """initialize + """initialize. - info -- description string""" + info -- description string + """ SrMiseError.__init__(self, info) class SrMiseStaticOwnerError(SrMiseError): - """diffpy.srmise exception class. Attempt to change owner of static model part.""" + """diffpy.srmise exception class. + + Attempt to change owner of static model part. + """ def __init__(self, info): - """initialize + """initialize. - info -- description string""" + info -- description string + """ SrMiseError.__init__(self, info) class SrMiseTransformationError(SrMiseError): - """diffpy.srmise exception class. Error transforming model/covariance parameters.""" + """diffpy.srmise exception class. + + Error transforming model/covariance parameters. + """ def __init__(self, info): - """initialize + """initialize. - info -- description string""" + info -- description string + """ SrMiseError.__init__(self, info) class SrMiseUndefinedCovarianceError(SrMiseError): - """diffpy.srmise exception class. Attempted to perform on undefined covariance.""" + """diffpy.srmise exception class. + + Attempted to perform on undefined covariance. + """ def __init__(self, info): - """initialize + """initialize. - info -- description string""" + info -- description string + """ SrMiseError.__init__(self, info) class SrMisePDFKeyError(SrMiseError): - """diffpy.srmise exception class. Requested PDF key can't be found.""" + """diffpy.srmise exception class. + + Requested PDF key can't be found. + """ def __init__(self, info): - """initialize + """initialize. - info -- description string""" + info -- description string + """ SrMiseError.__init__(self, info) diff --git a/src/diffpy/srmise/srmiselog.py b/src/diffpy/srmise/srmiselog.py index e4311a0..5393475 100644 --- a/src/diffpy/srmise/srmiselog.py +++ b/src/diffpy/srmise/srmiselog.py @@ -95,7 +95,8 @@ def setfilelevel(level): """Set level of file logger. Parameters - level: The logging level.""" + level: The logging level. + """ global fh if fh is not None: level = LEVELS.get(level, level) @@ -111,7 +112,8 @@ def setlevel(level): """Set level of default (stdout) logger. Parameters - level: The logging level.""" + level: The logging level. + """ global ch level = LEVELS.get(level, level) ch.setLevel(level) @@ -127,7 +129,8 @@ def liveplotting(lp, w=False): Parameters lp: Use live plotting (True) or not (False). - w: (False) Whether to wait for user after plotting.""" + w: (False) Whether to wait for user after plotting. + """ global liveplots global wait if lp is True or lp is False: @@ -172,8 +175,8 @@ def __init__(self, **kwds): def emit(self, *args, **kwds): """Write current trace to file. - Parameters - Any number of ModelCluster instances""" + Parameters Any number of ModelCluster instances + """ if not eval(self.filter): return else: @@ -236,7 +239,8 @@ def read(self, filename): "clusters" - List of cluster regions [[r0,r1],[r2,r3],...] "counter" - The count when object was created "mc" - A ModelCluster instance - "recursion" - The recursion level of mc""" + "recursion" - The recursion level of mc + """ try: return self.readstr(open(filename, "rb").read()) except SrMiseDataFormatError as err: @@ -258,7 +262,8 @@ def readstr(self, datastring): "clusters" - List of cluster regions [[r0,r1],[r2,r3],...] "counter" - The count when object was created "mc" - A ModelCluster instance - "recursion" - The recursion level of mc""" + "recursion" - The recursion level of mc + """ # find where the ModelCluster section starts res = re.search(r"^#+ ModelCluster\s*(?:#.*\s+)*", datastring, re.M) diff --git a/src/diffpy/srmise/version.py b/src/diffpy/srmise/version.py index 304027c..129ef83 100644 --- a/src/diffpy/srmise/version.py +++ b/src/diffpy/srmise/version.py @@ -12,7 +12,6 @@ # See LICENSE.rst for license information. # ############################################################################## - """Definition of __version__.""" # We do not use the other three variables, but can be added back if needed. diff --git a/tests/test_version.py b/tests/test_version.py index 1bc10c2..3ac5816 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -1,10 +1,10 @@ -"""Unit tests for __version__.py -""" +"""Unit tests for __version__.py.""" import diffpy.srmise def test_package_version(): - """Ensure the package version is defined and not set to the initial placeholder.""" + """Ensure the package version is defined and not set to the initial + placeholder.""" assert hasattr(diffpy.srmise, "__version__") assert diffpy.srmise.__version__ != "0.0.0"