def test_vec_link_call(): "Check that linked parameter models return the correct responses" model = double_vec linkedmodel = link(model, vec=['vec1', 'vec2']) x = np.linspace(0, 10, 40) ref = model(1, 2, dl.dd_gauss(x, 3, 0.2), dl.dd_gauss(x, 3, 0.2)) response = linkedmodel(1, 2, dl.dd_gauss(x, 3, 0.2)) assert np.allclose(response, ref)
def test_vec_twomodels_mixed(): "Check that that merge works correctly for two vector-based models" model1 = dl.dd_gauss model2 = model_vec model = merge(model1, model2) x = np.linspace(0, 10, 100) ref1 = model1(x, 3, 0.2) ref2 = model2(r=x, Pvec=dl.dd_gauss(x, 4, 0.3)) response = model(x, x, 3, 0.2, 1, dl.dd_gauss(x, 4, 0.3)) assert all( [np.allclose(response[n], ref) for n, ref in enumerate([ref1, ref2])])
def Kmodel(p, t, r): # Unpack parameters r1, w1, r2, w2 = p # Generate basic kernel K0 = dipolarkernel(t, r) # Get Gauss basis functions P1 = dd_gauss(r, r1, w1) P2 = dd_gauss(r, r2, w2) # Combine all non-linear functions into one K = np.zeros((len(t), 2)) K[:, 0] = K0 @ P1 K[:, 1] = K0 @ P2 return K
def test_vec_link_fit(): "Check that linked parameter models can be properly fitted" model = double_vec linkedmodel = link(model, vec=['vec1', 'vec2']) linkedmodel.shift.par0 = 1 linkedmodel.scale.par0 = 2 linkedmodel.shift.freeze(1) linkedmodel.scale.freeze(2) x = np.linspace(0, 10, 40) ref = model(1, 2, dl.dd_gauss(x, 3, 0.6), dl.dd_gauss(x, 3, 0.6)) result = fit(linkedmodel, ref, nonlin_tol=1e-3) assert np.allclose(result.model, ref, atol=1e-2)
def test_multiple_penalties(): # ====================================================================== "Check that multiple additional penaltyies can be passed correctly" t = np.linspace(0, 5, 300) r = np.linspace(2, 6, 90) P = dd_gauss(r, 4.5, 0.25) param = 0.2 K = dipolarkernel(t, r, mod=param) V = K @ P + whitegaussnoise(t, 0.001, seed=1) dr = np.mean(np.diff(r)) beta = 0.05 R = 0.5 compactness_penalty = lambda pnonlin, plin: beta * np.sqrt(plin * ( r - np.trapz(plin * r, r))**2 * dr) radial_penalty = lambda pnonlin, plin: 1 / R**2 * (np.linalg.norm( (pnonlin - param) / param - R))**2 Kmodel = lambda lam: dipolarkernel(t, r, mod=lam) fit0 = snlls(V, Kmodel, par0=0.2, lb=0, ub=1, lbl=np.zeros_like(r), extrapenalty=[compactness_penalty]) fitmoved = snlls(V, Kmodel, par0=0.2, lb=0, ub=1, lbl=np.zeros_like(r), extrapenalty=[compactness_penalty, radial_penalty]) assert ovl(P, fit0.lin) > ovl(P, fitmoved.lin)
def assert_uq(uq,attr): if attr=='mean': assert np.allclose(uq.mean,means,rtol=1e-2) elif attr=='std': assert np.allclose(uq.std,std,rtol=1e-2) elif attr=='median': assert np.allclose(uq.median,p50,rtol=1e-2) elif attr=='ci': assert np.allclose(uq.ci(95),ci95,rtol=1e-2) assert np.allclose(uq.ci(90),ci90,rtol=1e-2) assert np.allclose(uq.ci(50),ci50,rtol=1e-2) elif attr=='percentile': assert np.allclose(uq.percentile(95),p95,rtol=1e-2) assert np.allclose(uq.percentile(5),p5,rtol=1e-2) assert np.allclose(uq.percentile(50),p50,rtol=1e-2) elif attr=='pardist': x1,pdf1 = uq.pardist(0) x2,pdf2 = uq.pardist(1) xs = [x1,x2] pdfs = [pdf1,pdf2] pdfs_ref = [dd_gauss(x,mean,sigma) for x,mean,sigma in zip(xs,means,std)] assert ovl(pdfs[0],pdfs_ref[0])>0.99 assert ovl(pdfs[1],pdfs_ref[1])>0.99
def test_call_Pnonparametric(): "Check that the model with one dipolar pathway is correct" Vmodel = dipolarmodel(t,r,Bmodel=bg_hom3d,npathways=1) Vsim = Vmodel(mod=0.3,reftime=0.0,conc=50,P=1e5*dd_gauss(r,3,0.2)) assert np.allclose(Vsim,V1path)
def test_vec_addweights(): "Check that that weights can be introduced properly" model1 = model_vec model2 = model_vec model = lincombine(model1, model2, addweights=True) x = np.linspace(0, 10, 100) ref1 = dl.dd_gauss(x, 3, 0.2) ref2 = dl.dd_gauss(x, 4, 0.2) ref = ref1 + ref2 response = model(r_1=x, r_2=x, Pvec_1=ref1, Pvec_2=ref2, weight_1=1, weight_2=1) assert np.allclose(response, ref)
def test_global_weights(): # ====================================================================== "Check that the global weights properly work when specified" t = np.linspace(-0.3, 5, 300) r = np.linspace(2, 6, 150) P1 = dd_gauss(r, 3, 0.2) P2 = dd_gauss(r, 5, 0.2) K = dipolarkernel(t, r, mod=0.2) scales = [1e3, 1e9] sigma1 = 0.001 V1 = K @ P1 + whitegaussnoise(t, sigma1, seed=1) sigma2 = 0.001 V2 = K @ P2 + whitegaussnoise(t, sigma2, seed=1) V1 = scales[0] * V1 V2 = scales[1] * V2 Kmodel = lambda lam: [dipolarkernel(t, r, mod=lam)] * 2 fit1 = snlls([V1, V2], Kmodel, par0=[0.2], lb=0, ub=1, lbl=np.zeros_like(r), weights=[1, 1e-10]) fit2 = snlls([V1, V2], Kmodel, par0=[0.2], lb=0, ub=1, lbl=np.zeros_like(r), weights=[1e-10, 1]) assert ovl(P1, fit1.lin) > 0.93 and ovl(P2, fit2.lin) > 0.93
def test_global_weights_default(): # ====================================================================== "Check the correct fit of two signals when one is of very low quality" t = np.linspace(0, 5, 300) r = np.linspace(2, 6, 90) param = [4.5, 0.25] P = dd_gauss(r, *param) K = dipolarkernel(t, r, mod=0.2) scales = [1e3, 1e9] V1 = scales[0] * (K @ P + whitegaussnoise(t, 0.001, seed=1)) V2 = scales[1] * (K @ P + whitegaussnoise(t, 0.1, seed=1)) Kmodel = lambda lam: [dipolarkernel(t, r, mod=lam)] * 2 fit = snlls([V1, V2], Kmodel, par0=[0.2], lb=0, ub=1, lbl=np.zeros_like(r)) assert ovl(P, fit.lin) > 0.93
def test_extrapenalty(): # ====================================================================== "Check that an additional penalty can be passed correctly" t = np.linspace(0, 5, 300) r = np.linspace(2, 6, 90) P = dd_gauss(r, 4.5, 0.25) K = dipolarkernel(t, r, mod=0.2) V = K @ P + whitegaussnoise(t, 0.001, seed=1) dr = np.mean(np.diff(r)) beta = 0.05 compactness_penalty = lambda _, plin: beta * np.sqrt(plin * (r - np.trapz( plin * r, r))**2 * dr) Kmodel = lambda lam: dipolarkernel(t, r, mod=lam) fit = snlls(V, Kmodel, par0=0.2, lb=0, ub=1, lbl=np.zeros_like(r), extrapenalty=compactness_penalty) assert ovl(P, fit.lin) > 0.95
# Fit the datasets to the model globally fit = dl.fit(globalmodel, Vexps) # Extract the fitted fractions fracAfit = [fit.fracA_1, fit.fracA_2, fit.fracA_3] fracBfit = [1 - fit.fracA_1, 1 - fit.fracA_2, 1 - fit.fracA_3] plt.figure(figsize=(10, 8)) for i in range(Nsignals): # Get the fitted signals and confidence bands Vfit = fit.model[i] Vfit_ci = fit.modelUncert[i].ci(95) # Get the fitted distributions of the two states PAfit = fracAfit[i] * dl.dd_gauss(r, fit.meanA, fit.widthA) PBfit = fracBfit[i] * dl.dd_gauss(r, fit.meanB, fit.widthB) # Plot plt.subplot(Nsignals, 2, 2 * i + 1) plt.plot(ts[i], Vexps[i], '.', color='grey') plt.plot(ts[i], Vfit, 'tab:blue') plt.fill_between(ts[i], Vfit_ci[:, 0], Vfit_ci[:, 1], color='tab:blue', alpha=0.3) plt.xlabel('Time t (µs)') plt.ylabel(f'V$_{i+1}$(t) (arb.u)') plt.legend(['Data', 'Fit'], loc='best', frameon=False)
p95,p50,p5 = np.zeros(2),np.zeros(2),np.zeros(2) for n,sample in enumerate(samples): p95[n] = np.percentile(samples[n],95) p5[n] = np.percentile(samples[n],5) p50[n] = np.percentile(samples[n],50) # Reference confidence intervals ci95,ci90,ci50 = np.zeros((2,2)),np.zeros((2,2)),np.zeros((2,2)) for n,sample in enumerate(samples): ci95[n,:] = np.array([np.percentile(samples[n],2.5),np.percentile(samples[n],97.5)]) ci90[n,:] = np.array([np.percentile(samples[n],5.0),np.percentile(samples[n],95.0)]) ci50[n,:] = np.array([np.percentile(samples[n],25),np.percentile(samples[n],75)]) # Profile likelihood simulation x = np.linspace(0,10,1000) pdf1 = dd_gauss(x,means[0],std[0]) pdf2 = dd_gauss(x,means[1],std[1]) pdf1 /= max(pdf1) pdf2 /= max(pdf2) σ = 0.01 obj2likelihood = lambda f: 1/np.sqrt(σ*2*np.pi)*np.exp(-1/2*f/σ**2) likelihood2obj = lambda L: -2*np.log(L*np.sqrt(σ*2*np.pi))*σ**2 threshold = lambda coverage: σ**2*chi2.ppf(coverage, df=1) + likelihood2obj(max(pdf1)) profile1 = {'y': likelihood2obj(pdf1), 'x':x} profile2 = {'y': likelihood2obj(pdf2), 'x':x} # Construct uncertainty quantification objects uq_covariance = UQResult('covariance',data=np.array(means),covmat=covmat) uq_bootstrap = UQResult('bootstrap',data=np.vstack(samples).T) uq_profile = UQResult('profile',data=np.array(means),profiles=[profile1,profile2],threshold=threshold,noiselvl=σ)
def test_names(): "Check that the model has correct parameter names" model = dipolarmodel(t,r,dd_gauss,bg_hom3d,npathways=1) parameters = ['mean','width','conc','mod','reftime','scale'] for param in parameters: assert hasattr(model,param) # ====================================================================== t = np.linspace(-0.5,5,100) r = np.linspace(2,5,50) Bfcn = lambda t,lam: bg_hom3d(t,50,lam) Bfcn_pheno = lambda t,_: bg_exp(t,0.1) Pr = dd_gauss(r,3,0.2) V1path = 1e5*dipolarkernel(t,r,mod=0.3,bg=Bfcn)@Pr V1path_noB = 1e5*dipolarkernel(t,r,mod=0.3)@Pr V1path_phenoB = 1e5*dipolarkernel(t,r,mod=0.3,bg=Bfcn_pheno)@Pr V2path = 1e5*dipolarkernel(t,r,pathways=[[0.6],[0.3,0],[0.1,2]],bg=Bfcn)@Pr V3path = 1e5*dipolarkernel(t,r,pathways=[[0.5],[0.3,0],[0.1,2],[0.1,5]],bg=Bfcn)@Pr # ====================================================================== def test_call_positional(): "Check that the model called via positional arguments responds correctly" Vmodel = dipolarmodel(t,r,dd_gauss,bg_hom3d,npathways=1) Vsim = Vmodel(0.3,0.0,50,3,0.2,1e5)
def model(p): center, width = p y = dd_gauss(x, center, width) return y
def model(p): phase, center, width = p y = dd_gauss(x, center, width) y = y * np.exp(-1j * phase) return y
ax4.plot(ts[1], Vdis_fit, color=violet, label=f'Dispersed fraction {fit.eta*100:.1f}%') ax4.plot(ts[1], Vld_fit, color=orange, label=f'Liquid-droplet fraction {(1-fit.eta)*100:.1f}%') ax4.set_yticklabels([]) ax4.legend(frameon=False, loc='best') ax4.set_xlabel('Time t (μs)') ax4.set_ylim([0.2, 1]) plt.subplot(3, 1, 3) Pdis_fcn = lambda rmean_dis, width_dis: dl.dd_gauss(r, rmean_dis, width_dis) Pld_fcn = lambda rmean_ld, width_ld: dl.dd_gauss(r, rmean_ld, width_ld) Pdis_uq = fit.propagate(Pdis_fcn, lb=np.zeros_like(r)) Pld_uq = fit.propagate(Pld_fcn, lb=np.zeros_like(r)) plt.plot(r, Pdis_fcn(fit.rmean_dis, fit.width_dis), label=f'Dispersed fraction {fit.eta*100:.1f}%', color=violet) plt.fill_between(r, Pdis_uq.ci(95)[:, 0], Pdis_uq.ci(95)[:, 1], alpha=0.3, linewidth=0, color=violet)
def Ptwostates(meanA, meanB, widthA, widthB, fracA): PA = fracA * dl.dd_gauss(r, meanA, widthA) PB = (1 - fracA) * dl.dd_gauss(r, meanB, widthB) P = PA + PB P /= np.trapz(P) return P
import numpy as np from deerlab import dd_gauss, whitegaussnoise from deerlab.model import Penalty,fit from deerlab.utils import ovl from copy import deepcopy x = np.linspace(0,4,50) mock_data = dd_gauss(x,2,0.2) + whitegaussnoise(x,0.005,seed=1) def penalty_fcn(mean,width): P = dd_gauss(x,mean,width) P = P/np.trapz(P,x) return np.sqrt(P*(x - np.trapz(P*x,x))**2*np.mean(np.diff(x))) # ====================================================================== def test_type(): "Check that the output is the proper object type" penaltyobj = Penalty(penalty_fcn,'icc') assert isinstance(penaltyobj,Penalty) # ====================================================================== # ====================================================================== def test_signature(): "Check that signature of the original function is properly taken" penaltyobj = Penalty(penalty_fcn,'icc') assert np.all(penaltyobj.signature==['mean','width']) # ======================================================================
def penalty_fcn(mean,width): P = dd_gauss(x,mean,width) P = P/np.trapz(P,x) return np.sqrt(P*(x - np.trapz(P*x,x))**2*np.mean(np.diff(x)))