From 9e8362f5ada182ed3be9978749b246ee8e88aa51 Mon Sep 17 00:00:00 2001 From: Hugo Karas Date: Wed, 27 Nov 2024 10:42:47 +0100 Subject: [PATCH 01/17] Bump Version and update README --- README.md | 2 +- VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2442dea3b..133ed84bb 100644 --- a/README.md +++ b/README.md @@ -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.9**, **3.10**, **3.11**, or **3.12**. +DeerLab is available for Windows, Mac and Linux systems and requires **Python 3.9** to **3.13** All additional dependencies are automatically downloaded and installed during the setup. diff --git a/VERSION b/VERSION index c64122024..79127d85a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v1.1.4 +v1.2.0 From e541f2e28e21985df7bdb43955f3028337b48d58 Mon Sep 17 00:00:00 2001 From: Hugo Karas Date: Wed, 27 Nov 2024 10:46:17 +0100 Subject: [PATCH 02/17] Update changelog --- docsrc/source/changelog.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docsrc/source/changelog.rst b/docsrc/source/changelog.rst index 08714a20b..a702b2b8b 100644 --- a/docsrc/source/changelog.rst +++ b/docsrc/source/changelog.rst @@ -24,6 +24,15 @@ 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.2`` - December 2024 +------------------------------------------ +- |feature| : `modelUncert` is now returned in the `FitResult` object +- |fix| : Fixes issues with bootrstrap uncertainties +- |api| : N bootstrap samples no longer produces N+1 samples +- |enhancement| : Support Python 3.13 +- |fix| : All gaussian models now normalise to 1 + Release ``v1.1.4`` - September 2024 ------------------------------------------ - |enhancement| : Expanded sophgrid to allow for closed phi integral. (:pr:`482`) From 385093e3f2f5066b7f4e5343cef6e6fcf74e819c Mon Sep 17 00:00:00 2001 From: Hugo Karas Date: Tue, 26 Nov 2024 11:08:10 +0100 Subject: [PATCH 03/17] Rename trapz to trapezoid --- deerlab/bg_models.py | 4 ++-- deerlab/classes.py | 8 ++++---- deerlab/dd_models.py | 4 ++-- deerlab/dipolarmodel.py | 4 ++-- deerlab/diststats.py | 8 ++++---- deerlab/solvers.py | 2 +- examples/advanced/ex_forcefield_fit.py | 2 +- examples/advanced/ex_global_twostates_parametric.py | 2 +- examples/advanced/ex_multigauss_fitting_4pdeer.py | 4 ++-- examples/advanced/ex_pseudotitration_parameter_free.py | 2 +- examples/basic/ex_fitting_4pdeer_gauss.py | 2 +- examples/basic/ex_restraints_4pdeer.py | 6 +++--- test/test_ddmodels.py | 2 +- test/test_dipolarmodel.py | 2 +- test/test_model_penalty.py | 4 ++-- test/test_snlls.py | 4 ++-- 16 files changed, 30 insertions(+), 30 deletions(-) diff --git a/deerlab/bg_models.py b/deerlab/bg_models.py index 037f61dcd..c0a11c8f4 100644 --- a/deerlab/bg_models.py +++ b/deerlab/bg_models.py @@ -188,7 +188,7 @@ def _hom3dex(t,conc,rex,lam): # Averaging integral z = np.linspace(0,1,1000)[np.newaxis,:] Dt = D*t[:,np.newaxis]*1e-6 - Is = 4*np.pi/3*np.trapz(Dt*(1-3*z**2)*sici((Dt*(1-3*z**2))/((rex*1e-9)**3))[0],z,axis=1) + Is = 4*np.pi/3*np.trapezoid(Dt*(1-3*z**2)*sici((Dt*(1-3*z**2))/((rex*1e-9)**3))[0],z,axis=1) # Background function C_k = -Vex + Is + np.squeeze(Vex*(dipolarkernel(t,rex,integralop=False))) @@ -242,7 +242,7 @@ def _hom3dex_phase(t,conc,rex,lam): ξ = 8*pi**2/9/np.sqrt(3)*(np.sqrt(3)+np.log(2-np.sqrt(3)))/np.pi*D z = np.linspace(0,1,1000)[np.newaxis,:] Dt = D*t[:,np.newaxis]*1e-6 - Ic = -ξ*(t*1e-6) + 4*np.pi/3*np.trapz(Dt*(1-3*z**2)*sici((Dt*np.abs(1-3*z**2))/((rex*1e-9)**3))[1],z,axis=1) + Ic = -ξ*(t*1e-6) + 4*np.pi/3*np.trapezoid(Dt*(1-3*z**2)*sici((Dt*np.abs(1-3*z**2))/((rex*1e-9)**3))[1],z,axis=1) # Background function C_k = - Ic - np.squeeze(Vex*(dipolarkernel(t,rex,integralop=False,complex=True)).imag) diff --git a/deerlab/classes.py b/deerlab/classes.py index 39063cbf4..7c16d29ce 100644 --- a/deerlab/classes.py +++ b/deerlab/classes.py @@ -151,8 +151,8 @@ def __init__(self,uqtype,data=None,covmat=None,lb=None,ub=None,threshold=None,pr elif uqtype == 'profile': xs = [self.pardist(n)[0] for n in range(nParam)] pardists = [self.pardist(n)[1] for n in range(nParam)] - means = [np.trapz(pardist*x,x) for x,pardist in zip(xs,pardists)] - std = [np.sqrt(np.trapz(pardist*(x-mean)**2,x)) for x,pardist,mean in zip(xs,pardists,means)] + means = [np.trapezoid(pardist*x,x) for x,pardist in zip(xs,pardists)] + std = [np.sqrt(np.trapezoid(pardist*(x-mean)**2,x)) for x,pardist,mean in zip(xs,pardists,means)] self.mean = means self.median = self.percentile(50) self.std = std @@ -342,8 +342,8 @@ def pardist(self,n=0): # Ensure normalization of the probability density function (if not a Dirac delta function) if not isdelta: - if np.trapz(pdf, x)!=0: - pdf = pdf/np.trapz(pdf, x) + if np.trapezoid(pdf, x)!=0: + pdf = pdf/np.trapezoid(pdf, x) return x, pdf #-------------------------------------------------------------------------------- diff --git a/deerlab/dd_models.py b/deerlab/dd_models.py index 1c4d6d3ff..2293f0905 100644 --- a/deerlab/dd_models.py +++ b/deerlab/dd_models.py @@ -99,7 +99,7 @@ def docstr_example(fcnstr): # ================================================================= def _normalize(r,P): if not all(P==0): - P = P/np.trapz(P,r) + P = P/np.trapezoid(P,r) return P # ================================================================= @@ -129,7 +129,7 @@ def _multirice3dfun(r,nu,sig): P[P<0] = 0 # Normalization - P = np.squeeze(P)/np.sum([np.trapz(c,np.squeeze(r)) for c in P.T]) + P = np.squeeze(P)/np.sum([np.trapezoid(c,np.squeeze(r)) for c in P.T]) return P # ================================================================= diff --git a/deerlab/dipolarmodel.py b/deerlab/dipolarmodel.py index 80035e5a6..1f3f0a79e 100644 --- a/deerlab/dipolarmodel.py +++ b/deerlab/dipolarmodel.py @@ -642,8 +642,8 @@ def dipolarpenalty(Pmodel, r, type, selection=None): def compactness_penalty(*args): P = Pmodel(*[r]*Nconstants,*args) if not np.all(P==0): - P = P/np.trapz(P,r) - return np.sqrt(P*(r - np.trapz(P*r,r))**2*np.mean(np.diff(r))) + P = P/np.trapezoid(P,r) + return np.sqrt(P*(r - np.trapezoid(P*r,r))**2*np.mean(np.diff(r))) # Add the penalty to the Pmodel penalty = Penalty(compactness_penalty,selection, signature = Pmodel._parameter_list(), diff --git a/deerlab/diststats.py b/deerlab/diststats.py index 22d5d0229..23ca2744c 100644 --- a/deerlab/diststats.py +++ b/deerlab/diststats.py @@ -103,7 +103,7 @@ def analyze_rmode(V): # Auxiliary functions # ------------------- - int = np.trapz(P,r) if not np.all(P==0) else 1 + int = np.trapezoid(P,r) if not np.all(P==0) else 1 def normalize(P): return P/int # Percentile function @@ -114,7 +114,7 @@ def pctile(r,P,p): return rpctile # Expectation operator function def E(x,P,r): - return np.trapz(x*normalize(P),r) + return np.trapezoid(x*normalize(P),r) # Location estimators # ------------------- @@ -125,7 +125,7 @@ def E(x,P,r): # Interquartile mean def iqmfcn(P): IQrange = (r>pctile(r,P,25)) & (r1: label=None plt.plot(r,2*n + Pfit,'k',label='Total contribution' if n<1 else None) plt.fill(r,2*n + xA*results.P_1,color=green,alpha=0.5,label='State A (natural)' if n<1 else None) diff --git a/examples/basic/ex_fitting_4pdeer_gauss.py b/examples/basic/ex_fitting_4pdeer_gauss.py index 225827c22..e110613e9 100644 --- a/examples/basic/ex_fitting_4pdeer_gauss.py +++ b/examples/basic/ex_fitting_4pdeer_gauss.py @@ -52,7 +52,7 @@ # Extract fitted distance distribution Pfit = results.evaluate(Pmodel,r) -scale = np.trapz(Pfit,r) +scale = np.trapezoid(Pfit,r) Puncert = results.propagate(Pmodel,r,lb=np.zeros_like(r)) Pfit = Pfit/scale Pci95 = Puncert.ci(95)/scale diff --git a/examples/basic/ex_restraints_4pdeer.py b/examples/basic/ex_restraints_4pdeer.py index d58675f37..d3c71a103 100644 --- a/examples/basic/ex_restraints_4pdeer.py +++ b/examples/basic/ex_restraints_4pdeer.py @@ -70,9 +70,9 @@ # Plot distribution and confidence bands violet = '#4550e6' -Pci95 = fit.PUncert.ci(95)/np.trapz(fit.P,r) -Pci50 = fit.PUncert.ci(50)/np.trapz(fit.P,r) -plt.plot(r,fit.P/np.trapz(fit.P,r),linewidth=2,color=violet,label='Distance distribution fit') +Pci95 = fit.PUncert.ci(95)/np.trapezoid(fit.P,r) +Pci50 = fit.PUncert.ci(50)/np.trapezoid(fit.P,r) +plt.plot(r,fit.P/np.trapezoid(fit.P,r),linewidth=2,color=violet,label='Distance distribution fit') plt.fill_between(r,Pci95[:,0],Pci95[:,1],color=violet,alpha=0.3) plt.fill_between(r,Pci50[:,0],Pci50[:,1],color=violet,alpha=0.4) diff --git a/test/test_ddmodels.py b/test/test_ddmodels.py index d7cba5482..a3bfd125e 100644 --- a/test/test_ddmodels.py +++ b/test/test_ddmodels.py @@ -30,7 +30,7 @@ def assert_ddmodel(model): assert all(P1 >= 0) assert all(P1 >= 0) and all(P2 >= 0) assert all(~np.isnan(P1)) and all(~np.isnan(P2)) and all(~np.isnan(P3)) and all(~np.isnan(P4)) - assert np.round(np.trapz(P5,rnus),2) == 1 + assert np.round(np.trapezoid(P5,rnus),2) == 1 assert len(lower)==nParam assert len(upper)==nParam assert len(meta['names'])==nParam diff --git a/test/test_dipolarmodel.py b/test/test_dipolarmodel.py index 05fe75645..f7b987e03 100644 --- a/test/test_dipolarmodel.py +++ b/test/test_dipolarmodel.py @@ -320,7 +320,7 @@ def test_fit_Pnonparametric_normalization(V1path): result = fit(Vmodel,V1path,ftol=1e-5) - assert np.isclose(np.trapz(result.P,r),1) + assert np.isclose(np.trapezoid(result.P,r),1) # ====================================================================== # Fixtures diff --git a/test/test_model_penalty.py b/test/test_model_penalty.py index 3020843e2..7919e89cc 100644 --- a/test/test_model_penalty.py +++ b/test/test_model_penalty.py @@ -24,8 +24,8 @@ def mock_data(): def penalty_fcn(): def _penalty_fcn(mean,std): P = dd_gauss(x,mean,std) - P = P/np.trapz(P,x) - return np.sqrt(P*(x - np.trapz(P*x,x))**2*np.mean(np.diff(x))) + P = P/np.trapezoid(P,x) + return np.sqrt(P*(x - np.trapezoid(P*x,x))**2*np.mean(np.diff(x))) return _penalty_fcn # ----------------------------------------------------------------------- diff --git a/test/test_snlls.py b/test/test_snlls.py index 29cc45e08..39799218d 100644 --- a/test/test_snlls.py +++ b/test/test_snlls.py @@ -207,7 +207,7 @@ def test_SNLLS_cost_value(mock_data,mock_Amodel): def test_SNLLS_fit_with_extra_penalty(mock_data,mock_Amodel): "Check that an additional penalty can be passed correctly to the SNLLS functional" beta = 0.05 - compactness_penalty = lambda _,plin: beta*np.sqrt(plin*(r - np.trapz(plin*r,r))**2*dr) + compactness_penalty = lambda _,plin: beta*np.sqrt(plin*(r - np.trapezoid(plin*r,r))**2*dr) fit = snlls(mock_data,mock_Amodel,nlpar0,lb,ub,lbl,extrapenalty=compactness_penalty) assert np.all(abs(lin_param - fit.lin) < 1e-1) and np.all(abs(nonlin_param - fit.nonlin[0]) < 1e-1) # ====================================================================== @@ -216,7 +216,7 @@ def test_SNLLS_fit_with_multiple_extra_penalties(mock_data,mock_Amodel): # ====================================================================== "Check that multiple additional penaltyies can be passed correctly to the SNLLS functional" beta = 0.05 - compactness_penalty = lambda _,plin: beta*np.sqrt(plin*(r - np.trapz(plin*r,r))**2*dr) + compactness_penalty = lambda _,plin: beta*np.sqrt(plin*(r - np.trapezoid(plin*r,r))**2*dr) fit = snlls(mock_data,mock_Amodel,nlpar0,lb,ub,lbl,extrapenalty=[compactness_penalty]) R = 0.5 radial_penalty = lambda pnonlin,_: 1/R**2*(np.linalg.norm((pnonlin-nonlin_param)/nonlin_param-R))**2 From e1f8723e0bf891eb1cec1e81d02fc51326dedefd Mon Sep 17 00:00:00 2001 From: Hugo Karas Date: Tue, 26 Nov 2024 11:10:34 +0100 Subject: [PATCH 04/17] Update github actions --- .github/workflows/ci_PR.yml | 2 +- .github/workflows/ci_scheduled.yml | 2 +- .github/workflows/deploy_ghpages.yml | 4 ++-- .github/workflows/docs_PR.yml | 4 ++-- .github/workflows/examples_PR.yml | 4 ++-- .github/workflows/package_upload.yml | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci_PR.yml b/.github/workflows/ci_PR.yml index 88374ad6f..344e3a7a2 100644 --- a/.github/workflows/ci_PR.yml +++ b/.github/workflows/ci_PR.yml @@ -12,7 +12,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ['3.11','3.12'] + python-version: ['3.12','3.13'] steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/ci_scheduled.yml b/.github/workflows/ci_scheduled.yml index 655421332..fc331730b 100644 --- a/.github/workflows/ci_scheduled.yml +++ b/.github/workflows/ci_scheduled.yml @@ -12,7 +12,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: [3.9, "3.10", "3.11", "3.12"] + python-version: ["3.10", "3.11", "3.12","3.13"] steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/deploy_ghpages.yml b/.github/workflows/deploy_ghpages.yml index 195370c98..98173fd71 100644 --- a/.github/workflows/deploy_ghpages.yml +++ b/.github/workflows/deploy_ghpages.yml @@ -12,10 +12,10 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up Python 3.10 + - name: Set up Python 3.12 uses: actions/setup-python@v4 with: - python-version: '3.10' + python-version: '3.12' cache: 'pip' cache-dependency-path: setup.py - name: Install dependencies diff --git a/.github/workflows/docs_PR.yml b/.github/workflows/docs_PR.yml index cd4f9f670..d5150a578 100644 --- a/.github/workflows/docs_PR.yml +++ b/.github/workflows/docs_PR.yml @@ -16,10 +16,10 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up Python 3.10 + - name: Set up Python 3.12 uses: actions/setup-python@v4 with: - python-version: '3.10' + python-version: '3.12' cache: 'pip' cache-dependency-path: setup.py - name: Install dependencies diff --git a/.github/workflows/examples_PR.yml b/.github/workflows/examples_PR.yml index 94a5ddfcf..2b54a30ae 100644 --- a/.github/workflows/examples_PR.yml +++ b/.github/workflows/examples_PR.yml @@ -16,10 +16,10 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up Python 3.10 + - name: Set up Python 3.12 uses: actions/setup-python@v4 with: - python-version: '3.10' + python-version: '3.12' cache: 'pip' cache-dependency-path: setup.py diff --git a/.github/workflows/package_upload.yml b/.github/workflows/package_upload.yml index 4a3b99777..09d146fe0 100644 --- a/.github/workflows/package_upload.yml +++ b/.github/workflows/package_upload.yml @@ -11,10 +11,10 @@ jobs: steps: - name: Checkout uses: actions/checkout@v1 - - name: Set up Python 3.11 + - name: Set up Python 3.12 uses: actions/setup-python@v1 with: - python-version: "3.11" + python-version: "3.12" - name: Install pypa/build run: >- python -m pip install build --user From 6067f3eb015253b6ad43826a03424ac9cd3ac4aa Mon Sep 17 00:00:00 2001 From: Hugo Karas Date: Wed, 27 Nov 2024 15:27:07 +0100 Subject: [PATCH 05/17] revent gauss norm --- deerlab/dd_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deerlab/dd_models.py b/deerlab/dd_models.py index 2293f0905..27692032d 100644 --- a/deerlab/dd_models.py +++ b/deerlab/dd_models.py @@ -197,7 +197,7 @@ def _gauss2(r,mean1,std1,mean2,std2): #======================================================================================= # dd_gauss3 #======================================================================================= -ntoes = r""" +notes = r""" **Model** :math:`P(r) = a_1\frac{1}{\sigma_1\sqrt{2\pi}}\exp\left(-\frac{(r-\left)^2}{2\sigma_1^2}\right) + a_2\frac{1}{\sigma_2\sqrt{2\pi}}\exp\left(-\frac{(r-\left)^2}{2\sigma_2^2}\right) + a_3\frac{1}{\sigma_3\sqrt{2\pi}}\exp\left(-\frac{(r-\left)^2}{2\sigma_3^2}\right)` From a7004e6eac6ed2a83a7ff69d170caadcff218f97 Mon Sep 17 00:00:00 2001 From: Hugo Karas Date: Wed, 27 Nov 2024 15:33:32 +0100 Subject: [PATCH 06/17] Add par0 to dockstring --- deerlab/dd_models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/deerlab/dd_models.py b/deerlab/dd_models.py index 27692032d..690c011c6 100644 --- a/deerlab/dd_models.py +++ b/deerlab/dd_models.py @@ -50,16 +50,17 @@ def _dd_docstring(model,notes): string += '\n' string += '\n' table = [] - table.append(['Name','Lower','Upper','Type','Frozen','Unit','Description']) + table.append(['Name','Lower','Upper','par0','Type','Frozen','Unit','Description']) for n,paramname in enumerate(model._parameter_list(order='vector')): param_str = f'``{paramname}``' lb_str = f'{np.atleast_1d(getattr(model,paramname).lb)[0]:5.3g}' ub_str = f'{np.atleast_1d(getattr(model,paramname).ub)[0]:5.3g}' + par0_str = f'{np.atleast_1d(getattr(model,paramname).par0)[0]:5.3g}' linear_str = "linear" if np.all(getattr(model,paramname).linear) else "nonlin" frozen_str = "Yes" if np.all(getattr(model,paramname).frozen) else "No" unit_str = str(getattr(model,paramname).unit) desc_str = str(getattr(model,paramname).description) - table.append([param_str,lb_str,ub_str,linear_str,frozen_str,unit_str,desc_str]) + table.append([param_str,lb_str,ub_str,par0_str,linear_str,frozen_str,unit_str,desc_str]) string += formatted_table(table) string += f'\n{notes}' From f13a8702b1311c562b0835468360a779e32f15cc Mon Sep 17 00:00:00 2001 From: Hugo Karas Date: Thu, 9 Jan 2025 14:14:43 +0100 Subject: [PATCH 07/17] Updated github actions --- .github/workflows/ci_PR.yml | 4 ++-- .github/workflows/ci_scheduled.yml | 4 ++-- .github/workflows/deploy_ghpages.yml | 4 ++-- .github/workflows/docs_PR.yml | 4 ++-- .github/workflows/examples_PR.yml | 4 ++-- .github/workflows/package_upload.yml | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci_PR.yml b/.github/workflows/ci_PR.yml index 344e3a7a2..e220f780c 100644 --- a/.github/workflows/ci_PR.yml +++ b/.github/workflows/ci_PR.yml @@ -15,10 +15,10 @@ jobs: python-version: ['3.12','3.13'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: 'pip' diff --git a/.github/workflows/ci_scheduled.yml b/.github/workflows/ci_scheduled.yml index fc331730b..c39e60342 100644 --- a/.github/workflows/ci_scheduled.yml +++ b/.github/workflows/ci_scheduled.yml @@ -14,10 +14,10 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] python-version: ["3.10", "3.11", "3.12","3.13"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: 'pip' diff --git a/.github/workflows/deploy_ghpages.yml b/.github/workflows/deploy_ghpages.yml index 98173fd71..7c0b068d4 100644 --- a/.github/workflows/deploy_ghpages.yml +++ b/.github/workflows/deploy_ghpages.yml @@ -10,10 +10,10 @@ jobs: deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python 3.12 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.12' cache: 'pip' diff --git a/.github/workflows/docs_PR.yml b/.github/workflows/docs_PR.yml index d5150a578..7469c5720 100644 --- a/.github/workflows/docs_PR.yml +++ b/.github/workflows/docs_PR.yml @@ -14,10 +14,10 @@ jobs: docsbuild: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python 3.12 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.12' cache: 'pip' diff --git a/.github/workflows/examples_PR.yml b/.github/workflows/examples_PR.yml index 2b54a30ae..8f5ee2804 100644 --- a/.github/workflows/examples_PR.yml +++ b/.github/workflows/examples_PR.yml @@ -14,10 +14,10 @@ jobs: deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python 3.12 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.12' cache: 'pip' diff --git a/.github/workflows/package_upload.yml b/.github/workflows/package_upload.yml index 09d146fe0..a6114eb45 100644 --- a/.github/workflows/package_upload.yml +++ b/.github/workflows/package_upload.yml @@ -10,9 +10,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v4 - name: Set up Python 3.12 - uses: actions/setup-python@v1 + uses: actions/setup-python@v5 with: python-version: "3.12" - name: Install pypa/build From d4a4559ed7a4c6bce19b8e839d66c43949bbea49 Mon Sep 17 00:00:00 2001 From: Hugo Karas Date: Mon, 13 Apr 2026 17:21:04 +0200 Subject: [PATCH 08/17] Closes #507 --- deerlab/fitresult.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deerlab/fitresult.py b/deerlab/fitresult.py index 4841f9e67..b27310f73 100644 --- a/deerlab/fitresult.py +++ b/deerlab/fitresult.py @@ -360,7 +360,7 @@ def plot(self,axis=None,xlabel=None,gof=False,fontsize=13): bins = np.linspace(-4,4,300) N0 = dd_gauss(bins,0,1) axs[n].get_yaxis().set_visible(False) - axs[n].fill(bins,N0,'k',alpha=0.4, label='$\mathcal{N}(0,1)$') + axs[n].fill(bins,N0,'k',alpha=0.4, label=r'$\mathcal{N}(0,1)$') axs[n].set_xlabel('Normalized residuals',size=fontsize) axs[n].set_yticks([]) axs[n].spines.right.set_visible(False) From 7d6d055aad583403b808eedd271a6b76448e0164 Mon Sep 17 00:00:00 2001 From: Hugo Karas Date: Fri, 17 Apr 2026 19:26:19 +0200 Subject: [PATCH 09/17] Start of doc page for DeerLab 1.2 --- docsrc/source/deerlab1_2.rst | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 docsrc/source/deerlab1_2.rst diff --git a/docsrc/source/deerlab1_2.rst b/docsrc/source/deerlab1_2.rst new file mode 100644 index 000000000..a0ae0b6e8 --- /dev/null +++ b/docsrc/source/deerlab1_2.rst @@ -0,0 +1,21 @@ +DeerLab Version 1.2 +======================== + +DeerLab version 1.2 is a major update which brings a number of new features and improvements to the library. The most significant changes include: +- **Background model support in fit results**: When fitting a dipolar signal model that includes a background component, the fit results now include the evaluated background signal and its uncertainty. This allows users to easily access and analyze the background contribution to their fitted models. +- **Saving and Loading of Fit Results**: The fit results can now be saved to and loaded from disk, allowing users to preserve their fitting outcomes and share them with others. + +The following sections provide more details on these new features and how to use them effectively in your analysis. + + +Background Model Support in Fit Results +--------------------------------------- + + + + + +Saving and Loading of Fit Results +---------------------------------- + + From 2b992fddd1525cdb3da5b84af03cc77b71d252d3 Mon Sep 17 00:00:00 2001 From: Hugo Karas Date: Wed, 27 May 2026 10:33:34 +0200 Subject: [PATCH 10/17] Pathways example bug fixed: --- examples/intermediate/ex_fitting_4pdeer_pathways.py | 2 +- examples/intermediate/ex_fitting_5pdeer_pathways.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/intermediate/ex_fitting_4pdeer_pathways.py b/examples/intermediate/ex_fitting_4pdeer_pathways.py index cef4d058f..dd5cd41e0 100644 --- a/examples/intermediate/ex_fitting_4pdeer_pathways.py +++ b/examples/intermediate/ex_fitting_4pdeer_pathways.py @@ -70,7 +70,7 @@ lams = [results.lam1, results.lam2, results.lam3] reftimes = [results.reftime1, results.reftime2, results.reftime3] colors= ['tab:blue',green, red] -Vinter = results.P_scale*(1-np.sum(lams))*np.prod([dl.bg_hom3d(t-reftime,results.conc,lam) for lam,reftime in zip(lams,reftimes)],axis=0) +Vinter = results.P_scale*np.prod([dl.bg_hom3d(t-reftime,results.conc,lam) for lam,reftime in zip(lams,reftimes)],axis=0) for n,(lam,reftime,color) in enumerate(zip(lams,reftimes,colors)): Vpath = (1-np.sum(lams) + lam*dl.dipolarkernel(t-reftime,r)@Pfit)*Vinter plt.plot(t,Vpath,linewidth=3,label=f'Pathway #{n+1}',color=color) diff --git a/examples/intermediate/ex_fitting_5pdeer_pathways.py b/examples/intermediate/ex_fitting_5pdeer_pathways.py index 370a7d937..964cb6386 100644 --- a/examples/intermediate/ex_fitting_5pdeer_pathways.py +++ b/examples/intermediate/ex_fitting_5pdeer_pathways.py @@ -72,7 +72,7 @@ lams = [results.lam1, results.lam2, results.lam3, results.lam5] reftimes = [results.reftime1, results.reftime2, results.reftime3, results.reftime5] colors= ['tab:blue','tab:orange', red, green] -Vinter = results.P_scale*(1-np.sum(lams))*np.prod([dl.bg_hom3d(t-reftime,results.conc,lam) for lam,reftime in zip(lams,reftimes)],axis=0) +Vinter = results.P_scale*np.prod([dl.bg_hom3d(t-reftime,results.conc,lam) for lam,reftime in zip(lams,reftimes)],axis=0) for (lam,reftime,color,label) in zip(lams,reftimes,colors,labels): Vpath = (1-np.sum(lams) + lam*dl.dipolarkernel(t-reftime,r)@Pfit)*Vinter plt.plot(t,Vpath,linewidth=3,label=f'Pathway #{label}',color=color) From 80fb13613a8813a6ac078007513d1ca77e7ae3bd Mon Sep 17 00:00:00 2001 From: Hugo Karas Date: Wed, 27 May 2026 10:44:33 +0200 Subject: [PATCH 11/17] Updated Github actions --- .github/workflows/ci_PR.yml | 74 +++++++++--------- .github/workflows/ci_scheduled.yml | 107 +++++++++------------------ .github/workflows/deploy_ghpages.yml | 75 ++++++++++--------- .github/workflows/docs_PR.yml | 85 ++++++++++----------- .github/workflows/examples_PR.yml | 84 ++++++++++----------- .github/workflows/package_upload.yml | 59 ++++++++------- 6 files changed, 233 insertions(+), 251 deletions(-) diff --git a/.github/workflows/ci_PR.yml b/.github/workflows/ci_PR.yml index e220f780c..dedc0989a 100644 --- a/.github/workflows/ci_PR.yml +++ b/.github/workflows/ci_PR.yml @@ -1,33 +1,41 @@ -name: DeerLab PR tests -on: - pull_request: - branches: - - "**" - -jobs: - tests: - name: python test - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ['3.12','3.13'] - - steps: - - uses: actions/checkout@v4 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - cache: 'pip' - cache-dependency-path: setup.py - - run: | - python -m pip install --upgrade pip - pip install wheel - pip install . - - - name: Test with pytest - run: | - pytest +name: DeerLab PR tests + +on: + pull_request: + branches: + - "**" + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + tests: + name: python test + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: ['3.12', '3.13', '3.14'] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + cache-dependency-path: setup.py + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install . + + - name: Test with pytest + run: pytest diff --git a/.github/workflows/ci_scheduled.yml b/.github/workflows/ci_scheduled.yml index c39e60342..c2feb593c 100644 --- a/.github/workflows/ci_scheduled.yml +++ b/.github/workflows/ci_scheduled.yml @@ -1,70 +1,37 @@ -name: Scheduled DeerLab tests -on: - workflow_dispatch: - schedule: - # Run once a week on Monday at 6:30 AM - - cron: '30 6 * * 1' - -jobs: - matrix_test: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.10", "3.11", "3.12","3.13"] - steps: - - uses: actions/checkout@v4 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - cache: 'pip' - cache-dependency-path: setup.py - - run: | - python -m pip install --upgrade pip - pip install wheel - pip install . - -# - uses: actions/cache@v2 -# if: startsWith(runner.os, 'Windows') -# with: -# path: | -# ~\AppData\Local\pip\Cache -# key: ${{ runner.os }}-${{ hashFiles('**/setup.py') }} -# restore-keys: | -# {{ runner.os }}-pip- - -# - uses: actions/cache@v2 -# if: startsWith(runner.os, 'macOS') -# with: -# path: | -# ~/Library/Caches/pip -# key: ${{ runner.os }}-${{ hashFiles('**/setup.py') }} -# restore-keys: | -# {{ runner.os }}-pip- - -# - uses: actions/cache@v2 -# if: startsWith(runner.os, 'Linux') -# with: -# path: | -# ~/.cache/pip -# key: ${{ runner.os }}-${{ hashFiles('**/setup.py') }} -# restore-keys: | -# {{ runner.os }}-pip- - -# - name: Install dependencies -# if: steps.cache.outputs.cache-hit != 'false' -# run: | -# python -m pip install --upgrade pip -# pip install wheel -# pip install . - -# - name: Windows MKL linking -# if: matrix.os == 'windows-latest' -# run: | -# python upgrade_mkl.py - - - name: Test with pytest - run: pytest +name: Scheduled DeerLab tests + +on: + workflow_dispatch: + schedule: + # Run once a week on Monday at 6:30 AM UTC + - cron: '30 6 * * 1' + +permissions: + contents: read + +jobs: + matrix_test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: ["3.10", "3.11", "3.12", "3.13"] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + cache-dependency-path: setup.py + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install . + + - name: Test with pytest + run: pytest diff --git a/.github/workflows/deploy_ghpages.yml b/.github/workflows/deploy_ghpages.yml index 7c0b068d4..95984f87f 100644 --- a/.github/workflows/deploy_ghpages.yml +++ b/.github/workflows/deploy_ghpages.yml @@ -1,44 +1,53 @@ name: Docs Build & Deployment -on: +on: workflow_dispatch: release: types: [published] +permissions: + contents: read + pages: write + id-token: write + jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python 3.13 + uses: actions/setup-python@v5 + with: + python-version: '3.13' + cache: 'pip' + cache-dependency-path: setup.py + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install furo numpydoc sphinx-gallery sphinxcontrib-httpdomain sphinxcontrib-ghcontributors sphinx-issues sphinx-copybutton sphinx sphinx-design . + sudo apt-get update -y + sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended + + - name: Configure Pages + uses: actions/configure-pages@v5 + + - name: Build with Sphinx + run: sphinx-build -E -b html ./docsrc/source ./docs + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./docs deploy: + needs: build runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} steps: - - uses: actions/checkout@v4 - - - name: Set up Python 3.12 - uses: actions/setup-python@v5 - with: - python-version: '3.12' - cache: 'pip' - cache-dependency-path: setup.py - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install furo - python -m pip install numpydoc - python -m pip install sphinx-gallery - python -m pip install sphinxcontrib-httpdomain - python -m pip install sphinxcontrib-ghcontributors - python -m pip install sphinx-issues - python -m pip install sphinx-copybutton - python -m pip install sphinx - python -m pip install sphinx-design - python -m pip install . - sudo apt-get update -y - sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended - - name: Build with Sphinx - run: | - sphinx-build -E -b html ./docsrc/source ./docs - - name: Deploy to GH-Pages - if: always() - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./docs + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/docs_PR.yml b/.github/workflows/docs_PR.yml index 7469c5720..7f01bdbe4 100644 --- a/.github/workflows/docs_PR.yml +++ b/.github/workflows/docs_PR.yml @@ -1,44 +1,41 @@ -name: Test documentation build PR - -on: - pull_request: - branches: - - "**" - paths: - - 'docsrc/**' - - '.github/workflows/deploy_ghpages.yml' - - '.github/workflows/docs_PR.yml' - - '.github/workflows/examples_PR.yml' -jobs: - - docsbuild: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Set up Python 3.12 - uses: actions/setup-python@v5 - with: - python-version: '3.12' - cache: 'pip' - cache-dependency-path: setup.py - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install furo - pip install numpydoc - pip install sphinx-gallery - pip install sphinxcontrib-httpdomain - pip install sphinxcontrib-ghcontributors - pip install sphinx-issues - pip install sphinx-copybutton - pip install sphinx - pip install sphinx-design - python -m pip install . - sudo apt-get update -y - sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended - - - - name: Build with Sphinx - run: | - sphinx-build -E -b html ./docsrc/source ./docs -D plot_gallery=0 +name: Test documentation build PR + +on: + pull_request: + branches: + - "**" + paths: + - 'docsrc/**' + - '.github/workflows/deploy_ghpages.yml' + - '.github/workflows/docs_PR.yml' + - '.github/workflows/examples_PR.yml' + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + docsbuild: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python 3.13 + uses: actions/setup-python@v5 + with: + python-version: '3.13' + cache: 'pip' + cache-dependency-path: setup.py + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install furo numpydoc sphinx-gallery sphinxcontrib-httpdomain sphinxcontrib-ghcontributors sphinx-issues sphinx-copybutton sphinx sphinx-design . + sudo apt-get update -y + sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended + + - name: Build with Sphinx + run: sphinx-build -E -b html ./docsrc/source ./docs -D plot_gallery=0 diff --git a/.github/workflows/examples_PR.yml b/.github/workflows/examples_PR.yml index 8f5ee2804..a89905065 100644 --- a/.github/workflows/examples_PR.yml +++ b/.github/workflows/examples_PR.yml @@ -1,43 +1,41 @@ -name: Test documentation examples build PR - -on: - pull_request: - branches: - - "**" - paths: - - 'examples/**' - - '.github/workflows/deploy_ghpages.yml' - - '.github/workflows/docs_PR.yml' - - '.github/workflows/examples_PR.yml' -jobs: - - deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Set up Python 3.12 - uses: actions/setup-python@v5 - with: - python-version: '3.12' - cache: 'pip' - cache-dependency-path: setup.py - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install furo - python -m pip install numpydoc - python -m pip install sphinx-gallery - python -m pip install sphinxcontrib-httpdomain - python -m pip install sphinxcontrib-ghcontributors - python -m pip install sphinx-issues - python -m pip install sphinx-copybutton - python -m pip install sphinx - python -m pip install sphinx-design - python -m pip install . - sudo apt-get update -y - sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended - - name: Build with Sphinx - run: | - sphinx-build -E -b html ./docsrc/source ./docs +name: Test documentation examples build PR + +on: + pull_request: + branches: + - "**" + paths: + - 'examples/**' + - '.github/workflows/deploy_ghpages.yml' + - '.github/workflows/docs_PR.yml' + - '.github/workflows/examples_PR.yml' + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + docsbuild: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python 3.13 + uses: actions/setup-python@v5 + with: + python-version: '3.13' + cache: 'pip' + cache-dependency-path: setup.py + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install furo numpydoc sphinx-gallery sphinxcontrib-httpdomain sphinxcontrib-ghcontributors sphinx-issues sphinx-copybutton sphinx sphinx-design . + sudo apt-get update -y + sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended + + - name: Build with Sphinx + run: sphinx-build -E -b html ./docsrc/source ./docs diff --git a/.github/workflows/package_upload.yml b/.github/workflows/package_upload.yml index a6114eb45..1e2a73b07 100644 --- a/.github/workflows/package_upload.yml +++ b/.github/workflows/package_upload.yml @@ -1,28 +1,31 @@ -name: Build & Upload DeerLab to PyPI - -on: - release: - types: [published] - -jobs: - - pypi-build-n-publish: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Set up Python 3.12 - uses: actions/setup-python@v5 - with: - python-version: "3.12" - - name: Install pypa/build - run: >- - python -m pip install build --user - - name: Build a binary wheel and a source tarball - run: >- - python -m build --sdist --wheel --outdir dist/ - - name: Publish distribution to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.PYPI_API_TOKEN }} +name: Build & Upload DeerLab to PyPI + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + pypi-build-n-publish: + runs-on: ubuntu-latest + environment: pypi + permissions: + id-token: write + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python 3.13 + uses: actions/setup-python@v5 + with: + python-version: "3.13" + + - name: Build package + run: | + python -m pip install build + python -m build --sdist --wheel --outdir dist/ + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 From b111ca5e4713c508ad73486f104bf9ff9660a013 Mon Sep 17 00:00:00 2001 From: Hugo Karas Date: Sun, 31 May 2026 08:56:21 +0200 Subject: [PATCH 12/17] Dipolar Spectrum example --- .../intermediate/ex_plot_dipolar_spectrum.py | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 examples/intermediate/ex_plot_dipolar_spectrum.py diff --git a/examples/intermediate/ex_plot_dipolar_spectrum.py b/examples/intermediate/ex_plot_dipolar_spectrum.py new file mode 100644 index 000000000..44a610160 --- /dev/null +++ b/examples/intermediate/ex_plot_dipolar_spectrum.py @@ -0,0 +1,85 @@ +# %% [markdown] +""" +Plotting the dipolar spectrum / Pake pattern +------------------------------------------------------------------------- + +The dipolar spectrum or Pake patern is the Fourier transform of the dipolar signal, and can be useful for visualising the dipolar frequencies present in the signal. We can also overlay the dipolar spectrum of the fitted model to see how well the fit captures the dipolar frequencies in the data. +""" + + +import numpy as np +import matplotlib.pyplot as plt +import deerlab as dl +# %% +# File location +path = '../data/' +file = 'example_4pdeer_1.DTA' + +# Experimental parameters +tau1 = 0.3 # First inter-pulse delay, μs +tau2 = 4.0 # Second inter-pulse delay, μs +tmin = 0.1 # Start time, μs + +# Load the experimental data +t,Vexp = dl.deerload(path + file) + +# Pre-processing +Vexp = dl.correctphase(Vexp) # Phase correction +Vexp = Vexp/np.max(Vexp) # Rescaling (aesthetic) +t = t - t[0] # Account for zerotime +t = t + tmin +# Distance vector +r = np.arange(2.5,5,0.01) # nm + +# Construct the model +experimentInfo = dl.ex_4pdeer(tau1,tau2, pathways=[1]) +Vmodel = dl.dipolarmodel(t,r, experiment = experimentInfo, Bmodel=dl.bg_hom3d) + +# Fit the model to the data +results = dl.fit(Vmodel,Vexp) + +# Print results summary +print(results) +results.plot() + +# %% [markdown] +""" +Fourier transform ++++++++++++++++++ +""" +import numpy.fft as fft + + +# Fourier transform of the data and model +# Before background division +Vexp_ft = fft.fftshift(fft.fft(Vexp)) +Vmodel_ft = fft.fftshift(fft.fft(results.model)) +ft_axis = fft.fftshift(fft.fftfreq(len(t), d=t[1]-t[0])) + +# After background division +Vexp_div = Vexp / results.bg -1 +Vmodel_div = results.model / results.bg - 1 +Vexp_div_ft = fft.fftshift(fft.fft(Vexp_div)) +Vmodel_div_ft = fft.fftshift(fft.fft(Vmodel_div)) + +# Plotting +violet = '#4550e6' +fig,axs = plt.subplots(1,2,figsize=[10,6],sharex=True) +axs[0].set_title('Before background division') +axs[0].plot(ft_axis, np.abs(Vexp_ft), '.', color='grey', label='Data') +axs[0].plot(ft_axis, np.abs(Vmodel_ft), linewidth=3, color=violet, label='Fit') +axs[0].legend() +axs[0].set_ylabel('Magnitude (arb.u.)') +axs[0].set_xlabel('Dipolar frequency (MHz)') +axs[0].set_xlim(-10, 10) # Limit x-axis to focus on relevant frequencies + + +axs[1].set_title('After background division') +axs[1].plot(ft_axis, np.abs(Vexp_div_ft), '.', color='grey', label='Data') +axs[1].plot(ft_axis, np.abs(Vmodel_div_ft), linewidth=3, color=violet, label='Fit') +axs[1].legend() +axs[1].set_xlabel('Dipolar frequency (MHz)') +axs[1].set_ylabel('Magnitude (arb.u.)') +axs[1].set_xlim(-10, 10) # Limit x-axis to + +# %% From da58fd2bfe95c2bea886e12d9b0efbd30b2af152 Mon Sep 17 00:00:00 2001 From: Hugo Karas Date: Sun, 31 May 2026 09:42:56 +0200 Subject: [PATCH 13/17] `fitresult.modelUncert` exports properly for bootstrapped fits --- deerlab/fit.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/deerlab/fit.py b/deerlab/fit.py index c1c27da30..9b7a9fc52 100644 --- a/deerlab/fit.py +++ b/deerlab/fit.py @@ -501,13 +501,14 @@ def bootstrap_fcn(ysim): fitresults.param = fitresults.paramUncert.median # Get the uncertainty estimates for the model response - modellb = np.min(param_uq[1].samples,axis=0) - modelub = np.max(param_uq[1].samples,axis=0) + modellb = [np.min(param_uq[n].samples,axis=0) for n in range(1,len(param_uq))] + modelub = [np.max(param_uq[n].samples,axis=0) for n in range(1,len(param_uq))] fitresults.model = [param_uq[n].median for n in range(1,len(param_uq))] - fitresults.modelUncert = UQResult('bootstrap',data=param_uq[1].samples,lb=modellb,ub=modelub) + fitresults.modelUncert = [UQResult('bootstrap',data=param_uq[n].samples,lb=modellb[n-1],ub=modelub[n-1]) for n in range(1,len(param_uq))] if len(fitresults.model)==1: fitresults.model = fitresults.model[0] + fitresults.modelUncert = fitresults.modelUncert[0] # Get some basic information on the parameter vector keys = model._parameter_list(order='vector') From c8666bbad963a30d27db5432efd74e447c085a6c Mon Sep 17 00:00:00 2001 From: Hugo Karas Date: Sun, 31 May 2026 09:43:04 +0200 Subject: [PATCH 14/17] Updated changelog --- docsrc/source/changelog.rst | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docsrc/source/changelog.rst b/docsrc/source/changelog.rst index a702b2b8b..3c8306feb 100644 --- a/docsrc/source/changelog.rst +++ b/docsrc/source/changelog.rst @@ -25,13 +25,20 @@ Release Notes - |api| : This will require changes in your scripts or code. -Release ``v1.2`` - December 2024 +Release ``v1.2`` - June 2026 ------------------------------------------ - |feature| : `modelUncert` is now returned in the `FitResult` object +- |feature| : Added new saving and loading options for `FitResult` and `UQResult` objects, using `save` and `load` functions. +- |feature| : Added new automatic calculation of background function with `dipolarbackgroundmodel` function. Added `FitResult.bg` and `FitResult.bgUncert` attributes to store the fitted background function and its uncertainty, when possible. +- |feature| : Added multi-core parallelization to the `profile_analysis` function via the `cores` argument. +- |feature| : Added a new `show_config` function to display deatils about how DeerLab is configured in the current system. - |fix| : Fixes issues with bootrstrap uncertainties - |api| : N bootstrap samples no longer produces N+1 samples -- |enhancement| : Support Python 3.13 +- |enhancement| : Support Python 3.13 and 3.14 - |fix| : All gaussian models now normalise to 1 +- |fix| : Fixed bug in `ex_fitting_5pdeer_pathways` so scales are now correct on the pathways. +- |api| : Models are now deepcopied on import to avoid issues with users modifying the built-in models. +- |fix| : Fixes bug where some parameters frozen before the `dl.dipolarmodel` function were not frozen in the resulting model. Release ``v1.1.4`` - September 2024 ------------------------------------------ From a8ba7444b1ed3616ac7686ae2a9093001f28ff83 Mon Sep 17 00:00:00 2001 From: Hugo Karas Date: Sun, 31 May 2026 09:47:03 +0200 Subject: [PATCH 15/17] Example bug fix --- examples/basic/ex_saving_loading.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/basic/ex_saving_loading.py b/examples/basic/ex_saving_loading.py index aa7d92b15..a3ac61613 100644 --- a/examples/basic/ex_saving_loading.py +++ b/examples/basic/ex_saving_loading.py @@ -64,7 +64,7 @@ # %% np.savetxt('fitted_signal.txt', np.column_stack((t, Vexp, results.model, results.bg)), header='Time (μs), Data, Fit, Background') -Pfit = results.evaluate(dl.dd_gauss2, r) -Puncert = results.propagate(dl.dd_gauss2, r).ci(95) +Pfit = results.P +Puncert = results.PUncert.ci(95) np.savetxt('distance_distribution.txt', np.column_stack((r, Pfit, Puncert[:,0], Puncert[:,1])), header='Distance (nm), P(r), P(r) 95% CI lower, P(r) 95% CI upper') # %% From e584c5e4ae2fca42b0939df09be21e2cca42e525 Mon Sep 17 00:00:00 2001 From: Hugo Karas Date: Sun, 31 May 2026 10:44:15 +0200 Subject: [PATCH 16/17] Updated README.md and setup.py --- .gitignore | 6 ++++++ README.md | 3 ++- setup.py | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index fa662345d..e06f9135a 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,9 @@ docsrc/source/_autosummary/**/* docsrc/source/auto_examples/**/* docsrc/plot_directive/ docsrc/source/_build/ + +examples/**/*.txt +examples/**/*.hdf5 +examples/**/*.npy +examples/**/*.npz +examples/**/*.csv diff --git a/README.md b/README.md index 133ed84bb..959dfdd73 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ The documentation can be found [here](https://jeschkelab.github.io/DeerLab/index The early versions of DeerLab (up to version 0.9.2) are written in MATLAB. The old MATLAB codebase is archived and can be found [here](https://github.com/JeschkeLab/DeerLab-Matlab). +A graphical user interface (GUI) for processing DEER data using DeerLab is now available as a separate package called [DeerAnalysis](https://github.com/JeschkeLab/DeerAnalysis). ## Requirements DeerLab is available for Windows, Mac and Linux systems and requires **Python 3.9** to **3.13** @@ -58,4 +59,4 @@ Here is the citation in bibtex format: DeerLab is licensed under the [MIT License](LICENSE). -Copyright © 2019-2024: Luis Fábregas Ibáñez, Stefan Stoll, Gunnar Jeschke, and [other contributors](https://github.com/JeschkeLab/DeerLab/contributors). +Copyright © 2019-2026: Luis Fábregas Ibáñez, Stefan Stoll, Hugo Karas, Gunnar Jeschke, and [other contributors](https://github.com/JeschkeLab/DeerLab/contributors). diff --git a/setup.py b/setup.py index 5a81d4407..46872106c 100644 --- a/setup.py +++ b/setup.py @@ -44,6 +44,8 @@ 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', + 'Programming Language :: Python :: 3.14', 'Topic :: Scientific/Engineering :: Chemistry', ] ) From 41b20d163e48149813dfc96714bee01690158b17 Mon Sep 17 00:00:00 2001 From: Hugo Karas Date: Sun, 31 May 2026 10:44:32 +0200 Subject: [PATCH 17/17] Updated reference.rst --- docsrc/source/reference.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docsrc/source/reference.rst b/docsrc/source/reference.rst index 1cf06c352..d8b395890 100644 --- a/docsrc/source/reference.rst +++ b/docsrc/source/reference.rst @@ -87,7 +87,7 @@ Reference Index formatted_table store_pickle read_pickle - dump_jsons - load_jsons + json_dumps + json_loads show_config freedist