Skip to content

Commit

Permalink
Merge branch 'JeschkeLab:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
HKaras authored Aug 1, 2023
2 parents 8ae74cf + 71ff589 commit bd3f25b
Show file tree
Hide file tree
Showing 25 changed files with 263 additions and 42 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/ci_PR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ on:

jobs:
tests:
name: python test
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: [3.9]
python-version: ['3.10','3.11']

steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci_scheduled.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: [3.8, 3.9, "3.10", "3.11"]
python-version: [3.8, 3.9, "3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v3

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/deploy_ghpages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Set up Python 3.9
- name: Set up Python 3.10
uses: actions/setup-python@v1
with:
python-version: 3.9
python-version: '3.10'
- uses: actions/cache@v2
with:
path: |
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/docs_PR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Set up Python 3.9
- name: Set up Python 3.10
uses: actions/setup-python@v1
with:
python-version: 3.9
python-version: '3.10'
- uses: actions/cache@v2
with:
path: |
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/examples_PR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Set up Python 3.9
- name: Set up Python 3.10
uses: actions/setup-python@v1
with:
python-version: 3.9
python-version: '3.10'
- uses: actions/cache@v2
with:
path: |
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The early versions of DeerLab (up to version 0.9.2) are written in MATLAB. The o

## Requirements

DeerLab is available for Windows, Mac and Linux systems and requires **Python 3.8**, **3.9**, or **3.10**.
DeerLab is available for Windows, Mac and Linux systems and requires **Python 3.8**, **3.9**, **3.10**, or **3.11**.

All additional dependencies are automatically downloaded and installed during the setup.

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v1.0.0
v1.0.2
6 changes: 3 additions & 3 deletions deerlab/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -1569,11 +1569,11 @@ def fit(model_, y, *constants, par0=None, penalties=None, bootstrap=0, noiselvl=
nnlsSolver : string, optional
Solver used to solve a non-negative least-squares problem (if applicable):
* ``'qp'`` - Optimization of the NNLS problem using the ``quadprog`` package.
* ``'qp'`` - Optimization of the NNLS problem using the ``quadprog`` package. Only Python <= 3.10.
* ``'cvx'`` - Optimization of the NNLS problem using the ``cvxopt`` package.
* ``'fnnls'`` - Optimization using the fast NNLS algorithm.
The default is ``'qp'``.
The default is ``'cvx'``.
verbose : scalar integer, optional
Level of verbosity during the analysis:
Expand Down Expand Up @@ -1754,7 +1754,7 @@ def bootstrap_fcn(ysim):
# Dictionary of parameter names and fit uncertainties
FitResult_paramuq = {f'{key}Uncert': model._getparamuq(fitresults.paramUncert,idx) for key,idx in zip(keys,param_idx)}
# Dictionary of other fit quantities of interest
FitResult_dict = {key: getattr(fitresults,key) for key in ['param','paramUncert','model','cost','plot','residuals','stats','regparam']}
FitResult_dict = {key: getattr(fitresults,key) for key in ['param','paramUncert','model','cost','plot','residuals','stats','regparam','regparam_stats']}
_paramlist = model._parameter_list('vector')

# Prepare the propagate() and evaluate() methods
Expand Down
2 changes: 1 addition & 1 deletion deerlab/selregparam.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def selregparam(y, A, solver, method='aic', algorithm='brent', noiselvl=None,
residuals : ndarray
Values of the residual norms evaluated during the search.
Returned if full_output is True.
residuals : ndarray
penalties : ndarray
Values of the penalty norms evaluated during the search.
Returned if full_output is True.
"""
Expand Down
41 changes: 30 additions & 11 deletions deerlab/solvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import time
from functools import partial
from copy import deepcopy
from quadprog import solve_qp


def timestamp():
Expand Down Expand Up @@ -136,7 +135,6 @@ def _plot(ys,yfits,yuqs,noiselvls,axis=None,xlabel=None,gof=False,fontsize=13):
# Adjust fontsize
for ax in axs:
for label in (ax.get_xticklabels() + ax.get_yticklabels()):
label.set_fontname('Calibri')
label.set_fontsize(fontsize)

return fig
Expand Down Expand Up @@ -388,7 +386,7 @@ def _insertfrozen(parfit,parfrozen,frozen):
# ===========================================================================================


def snlls(y, Amodel, par0=None, lb=None, ub=None, lbl=None, ubl=None, nnlsSolver='qp', reg='auto', weights=None, verbose=0,
def snlls(y, Amodel, par0=None, lb=None, ub=None, lbl=None, ubl=None, nnlsSolver='cvx', reg='auto', weights=None, verbose=0,
regparam='aic', regparamrange=None, multistart=1, regop=None, alphareopt=1e-3, extrapenalty=None, subsets=None,
ftol=1e-8, xtol=1e-8, max_nfev=1e8, lin_tol=1e-15, lin_maxiter=1e4, noiselvl=None, lin_frozen=None, mask=None,
nonlin_frozen=None, uq=True, modeluq=False):
Expand Down Expand Up @@ -482,11 +480,11 @@ def snlls(y, Amodel, par0=None, lb=None, ub=None, lbl=None, ubl=None, nnlsSolver
nnlsSolver : string, optional
Solver used to solve a non-negative least-squares problem (if applicable):
* ``'qp'`` - Optimization of the NNLS problem using the ``quadprog`` package.
* ``'qp'`` - Optimization of the NNLS problem using the ``quadprog`` package. Only Python <= 3.10.
* ``'cvx'`` - Optimization of the NNLS problem using the ``cvxopt`` package.
* ``'fnnls'`` - Optimization using the fast NNLS algorithm.
The default is ``'qp'``.
The default is ``'cvx'``.
noiselvl : array_like, optional
Noise standard deviation of the input signal(s), if not specified it is estimated automatically.
Expand Down Expand Up @@ -714,10 +712,18 @@ def linear_problem(y,A,optimize_alpha,alpha):
yfrozen = (A[:,lin_frozen]@lin_parfrozen[lin_frozen]).astype(float)

# Optimiza the regularization parameter only if needed


if optimize_alpha:
alpha = dl.selregparam((y-yfrozen)[mask], Ared[mask,:], linSolver, regparam,
output = dl.selregparam((y-yfrozen)[mask], Ared[mask,:], linSolver, regparam,
weights=weights[mask], regop=L, candidates=regparamrange,
noiselvl=noiselvl,searchrange=regparamrange)
noiselvl=noiselvl,searchrange=regparamrange,full_output=True)
alpha = output[0]
alpha_stats['alphas_evaled'] = output[1]
alpha_stats['functional'] = output[2]
alpha_stats['residuals'] = output[3]
alpha_stats['penalties'] = output[4]


# Components for linear least-squares
AtA, Aty = _lsqcomponents((y-yfrozen)[mask], Ared[mask,:], L, alpha, weights=weights[mask])
Expand All @@ -732,8 +738,8 @@ def linear_problem(y,A,optimize_alpha,alpha):
# Insert back the frozen linear parameters
xfit = _insertfrozen(xfit,lin_parfrozen,lin_frozen)


return xfit, alpha, Ndof

#===========================================================================

def ResidualsFcn(p):
Expand All @@ -745,8 +751,10 @@ def ResidualsFcn(p):
non-linear least-squares solver.
"""

nonlocal par_prev, check, regparam_prev, xfit, alpha, Ndof, Ndof_lin

nonlocal par_prev, check, regparam_prev, xfit, alpha, alpha_stats, Ndof, Ndof_lin



# Non-linear model evaluation
A = Amodel(p)

Expand Down Expand Up @@ -803,6 +811,8 @@ def ResidualsFcn(p):
return res
#===========================================================================

alpha_stats = {'alphas_evaled':[],'functional':[],'residuals':[],'penalties':[]}

# -------------------------------------------------------------------
# Only linear parameters
# -------------------------------------------------------------------
Expand Down Expand Up @@ -981,7 +991,7 @@ def ymodel(n):

return FitResult(nonlin=nonlinfit, lin=linfit, param=parfit, model=modelfit, nonlinUncert=paramuq_nonlin,
linUncert=paramuq_lin, paramUncert=paramuq, modelUncert=modelfituq, regparam=alpha, plot=plotfcn,
stats=stats, cost=fvals, residuals=res, noiselvl=noiselvl)
stats=stats, cost=fvals, residuals=res, noiselvl=noiselvl,regparam_stats=alpha_stats)
# ===========================================================================================


Expand Down Expand Up @@ -1232,6 +1242,15 @@ def qpnnls(AtA, Atb):
Mathematical Programming, 27, 1-33.
"""

try:
from quadprog import solve_qp
except ModuleNotFoundError:
raise ModuleNotFoundError(
'The quadprog package is required for this function.'+
'Install it with "pip install quadprog".')


N = np.shape(AtA)[1]
I = np.eye(N)
lb = np.zeros(N)
Expand Down
29 changes: 29 additions & 0 deletions docsrc/source/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,35 @@ Release Notes
- |fix| : Something which was not working as expected or leading to errors has been fixed.
- |api| : This will require changes in your scripts or code.

Release ``v1.0.2`` - July 2023
------------------------------------------
- |fix| : Fixes errors in documentation (:pr:`429`).

* Changes the file name of figures 'modelling*.png` to `modeling*.png`. To keep all spelling consistent with american english.
* Adds a missing `)` in `fitting_guide`
* Corrects the time axis in `echo_crossing` example.

- |fix| : Fixes an errors in tests (:pr:`429`).

* The test `test_algorithms` had an incorrect search range.

- |fix| : Removes the default font from the `fit` function due to conflicts on some systems (:pr:`429`).

Release ``v1.0.1`` - March 2023
------------------------------------------
- |fix| : Fixes some minor bugs in the documentation.

* The file modelling_guide.rst is renamed to modeling_guide.rst to keep spelling consistency.
* The "Simulating a two-pathway 5-pulse DEER signal" and "Simulating a three-pathway 4-pulse DEER signal" examples now run correctly.
*
- |fix| : Fixes issues with CVXOPT in tests.

* The testing will now use quadprog as the default solver. To account for the change tested values are now generated using the grid method

- |fix| : Updates GitHub actions to use latest packages.
- |api| : Hardcodes out Python 3.11 support. This will remain until quadprog is fixed.
- |api| : Removes hard-wired RNG seeding

Release ``v1.0.0`` - December 2022
------------------------------------------

Expand Down
2 changes: 1 addition & 1 deletion docsrc/source/fitting_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Fitting multi-dataset models
Models merged using the ``merge`` function (see :ref:`here <modeling_merging>` for details) can describe multiple datasets with a single model object and a common parameter set. To fit such a merged model to multiple datasets, the ``fit`` function can be used as above by passing a list of datasets ``[y1,y2,...,yN]`` instead of a single dataset ::

# Fit the model to multiple datasets
result = dl.fit(model, [y1,y2,y3]
result = dl.fit(model, [y1,y2,y3])

The number of datasets must match the number of responses returned by the model. Additionally, the ordering in the list of datasets must match the order of responses from the model, i.e. ``response1`` of ``model`` will be fitted to ``y1``, and so on.

Expand Down
2 changes: 1 addition & 1 deletion docsrc/source/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Requirements

To install DeerLab, first install Python on your computer. Python can be downloaded from the `official Python distribution <https://www.python.org/>`_. There are
many online tutorials to guide you through the installation and setup (see `here <https://realpython.com/installing-python/>`_ for example). Make sure you install
one of the Python versions compatible with DeerLab, either **Python 3.8**, **3.9**, or **3.10**.
one of the Python versions compatible with DeerLab, either **Python 3.8**, **3.9**, **3.10**, or **3.11**.

.. rubric:: Windows systems

Expand Down
2 changes: 2 additions & 0 deletions examples/intermediate/ex_crossing_echoes_masking.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
# Load the experimental data
t,Vexp = dl.deerload('../data/example_4pdeer_5.DTA')

t *= 1e3 # convert from ms to us

# Experimental parameters
tau1 = 0.5 # First inter-pulse time delay, μs
tau2 = 4.5 # Second inter-pulse time delay, μs
Expand Down
Loading

0 comments on commit bd3f25b

Please sign in to comment.