Hi Edward, I understand your point of fitting pA and kex instead of keg and kge (or kAB/kBA). Please find attached a program with the convention of kex and pB. The states A and B are called G and E (ground/excited), so the parameters are generally associated with E and G instead of A and B. |
# -*- coding: ISO-8859-1 -*- from math import* import shutil import sys import pylab from pylab import * from scipy import * from scipy.linalg import expm from scipy.optimize import fmin from scipy.optimize import leastsq from random import gauss import numpy as np import matplotlib.pyplot as plt import matplotlib.patches as patches import matplotlib.path as path import matplotlib.pylab as pyl import numpy as np import scipy.integrate as itg import random import scipy.stats as stats import math import xlrd import os import matplotlib.gridspec as gridspec import cmath import math print ('------IN------') wb = xlrd.open_workbook('myworkbook.xls') sh = wb.sheet_by_index(0) PathOutputFile=str(sh.cell(25,1).value) if not os.path.exists(PathOutputFile): os.mkdir(PathOutputFile) nb_fields=int(sh.cell(0,1).value) in_nlin={} in_freq={} my_fields=np.zeros(nb_fields) for kk in range(nb_fields): my_fields[kk]=float(sh.cell(2,1+kk).value) in_nlin[kk]=str(sh.cell(3,1+kk).value) in_freq[kk]=str(sh.cell(4,1+kk).value) nbCALLfunc=int(sh.cell(6,1).value) nbMC=int(sh.cell(7,1).value) print ('------CALCULATION START------') '''residues listing''' paramCPMG0={} #paramCPMG0 contains the initial parameters which will be fitted for all residues my_residues=[] #my_residues contains the list of the names of the residues for res in range(int(sh.cell(9,1).value)): my_residues.append(str(sh.cell(10,1+res).value)) paramCPMG0[res]=[] for param in range(3+nb_fields): paramCPMG0[res].append(float(sh.cell(12+param,1+res).value)) Tc=float(sh.cell(1,1).value) #Tc is the constant-time of the CPMG experiment f={} #f contains the name of the nlin.tab for each field which contain the data (HEIGHT, DHEIGHT, A_Z0...) for kk in range(nb_fields): f[kk]='f'+str(kk) for kk in range(nb_fields): f[kk] = open(in_nlin[kk],'r') '''end of the header number line''' lignes = f[0].readlines() l_vars=lignes[0].split() #header of the nlin.tab file, read once from the nlin.tab file of the first field for kk in range(nb_fields): f[kk].close() '''colunm nulber of the height and the intensities ratio''' for j in range(len(l_vars)): #header reading, colunm data recovery if l_vars[j] == 'HEIGHT': num_col_HEIGHT=j if l_vars[j] == 'Z_A0': ncol_Z_A0=j '''nlin.tab file reading''' my_intensities={} #contains the arrays of the intensities of all residues my_noises={} #contains the arrays of the calculated noises from experiment noise of all residues my_R2eff={} #contains the arrays of the calculated R2eff from my_intensities of all residues for kk in range(nb_fields): f[kk] = open(in_nlin[kk],'r') for kk in range(nb_fields): lignes = f[kk].readlines()[1:] ## reading of the kk field nlin.tab ii=0 for line in lignes: intensities=[] noises=[] R2eff=[] liste = line.split() for k in range(len(liste)-ncol_Z_A0+1): intensity=float(liste[k-1+ncol_Z_A0])*float(liste[num_col_HEIGHT-1]) #there is a lag noise=float(liste[num_col_HEIGHT]) #num col of DHEIGHT (because of the lag) intensities.append(intensity) noises.append(noise) R=-1./Tc*log(abs(float(liste[k-1+ncol_Z_A0]))) R2eff.append(R) my_intensities[kk, ii]=intensities my_noises[kk, ii]=noises my_R2eff[kk, ii]=R2eff ii +=1 freq={} #contains the arrays of the numbers of pulses of each CPMG experiment '''reading of the frequencies''' for jj in range(nb_fields): f_freqCPMG=open(in_freq[jj], 'r') lignes = f_freqCPMG.readlines() freq[jj]=np.zeros(len(lignes)) kk=0 for line in lignes: liste = line.split() freq[jj][kk]=float(liste[1]) #the number of pulses must be on the second column of the freq.txt file kk+=1 f_freqCPMG.close() '''Error bars calculation''' my_errors={} for jj in range(nb_fields): for k in range (len(my_residues)): error=[] for kk in range(len(freq[jj])): error.append(abs(my_noises[jj, k][kk]/(Tc*float(my_intensities[jj, k][kk])))) my_errors[jj,k]=error for kk in range(nb_fields): f[kk].close() print('------files reading: ok------') '''definition de la matrice d echange''' def RCPMG_3D(R1E,R1G, R2E, R2G,df, kGE, kEG): fG=0; fE=df; IGeq=kEG/(kEG+kGE); IEeq=kGE/(kEG+kGE) temp=np.matrix([ [ 0, 0, 0, 0, 0, 0, 0], [ 0, -R2G-kGE, -fG, 0, kEG, 0, 0], [ 0, fG, -R2G-kGE, 0, 0, kEG, 0], [2.0*R1G*IGeq, 0, 0, -R1G-kGE, 0, 0, kEG], [ 0, kGE, 0, 0, -R2E-kEG, -fE, 0], [ 0, 0, kGE, 0, fE, -R2E-kEG, 0], [2.0*R1E*IEeq, 0, 0, kGE, 0, 0, -R1E-kEG]]) return temp def RCPMG_2D(R2E, R2G,df, kGE, kEG): #fG=0; fE=fG+df; fG=0 ; fE=fG+df temp=np.matrix([ [-R2G-kGE, -fG, kEG, 0], [ fG, -R2G-kGE, 0, kEG], [ kGE, 0, -R2E-kEG, -fE], [ 0, kGE, fE, -R2E-kEG]]) return temp '''rotational matrix ''' def R180_3Dx(a): theta=180.0 R=np.matrix([[1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0,cos(2*math.pi*(theta+a)/360), -sin(2*math.pi*(theta+a)/360), 0.0, 0.0, 0.0], [0.0, 0.0, sin(2*math.pi*(theta+a)/360),cos(2*math.pi*(theta+a)/360), 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0,cos(2*math.pi*(theta+a)/360), -sin(2*math.pi*(theta+a)/360)], [0.0, 0.0, 0.0, 0.0, 0.0, sin(2*math.pi*(theta+a)/360),cos(2*math.pi*(theta+a)/360)]]) return R def R180x_2D(a): R=np.matrix([ [1, 0, 0.0, 0.0], [0,-1, 0.0, 0.0], [0.0, 0.0,1, 0], [0.0, 0.0, 0,-1]]) return R def mpower(x,y): '''Compute x raised to the power y when x is a square matrix and y is a scalar.''' s = shape(x) if len(s) != 2 or s[0] != s[1]: raise ValueError('matrix must be square') if y == 0: return eye(s[0]) [e,v] = eig(x) d = diag(e) return dot(dot(v,d**y),inv(v)) numbercallofe=0 def incremente(): global numbercallofe numbercallofe +=1 '''CPMG process for R calculation''' fit_function={} for kk in range(5): fit_function[kk]='func'+str(kk) '''function which simulates a R2eff profile (exchange model) according to the number of pulses during the constant time:''' def MakeFunction(a): if a==1: print('optimization with the function 3D_slow') def func1(r1e,r1g,r2e,r2g,df,kex,pg, nb_pulse): #R2E, R2G,df, kGE, kEG,nb_pulse,tcpmg kge=(1-pg)*kex; keg=pg*kex Rcalc_array=np.zeros(len(nb_pulse)) Rtemp=RCPMG_3D(r1e,r1g,r2e,r2g,df,kge,keg) M0=np.matrix([[0.5],[pg],[0.0],[0.0],[1-pg],[0.0],[0.0]]) for k in range(len(nb_pulse)): tcp=Tc/(4.0*nb_pulse[k]) nb_total = 2*int(nb_pulse[k]) Mint=M0 Rexpo=expm(Rtemp*tcp) for kk in range(0, nb_total): Mint=Rexpo*Mint Mint=R180_3Dx(0)*Mint Mint=Rexpo*Mint Rcalc_array[k]=-(1.0/Tc)*log(fabs((Mint[1])/pg)); return Rcalc_array if a==2: # This function is actually not required. The above "slow" version is enough. # The difference is just that one evaluates the magnetizations on both states, while # this one only considers the major state. Taking only the major state is always correct, while # taking both states is only correct in the case of fast exchange. In other words, the "fast" version is not needed, because in cases where this is correct the other one is correct, too. print('optimization with the function 3D_fast') def func1(r1e,r1g,r2e,r2g,df,kex,pg, nb_pulse): #R2E, R2G,df, kGE, kEG,nb_pulse,tcpmg kge=(1-pg)*kex; keg=pg*kex Rcalc_array=np.zeros(len(nb_pulse)) Rtemp=RCPMG_3D(r1e,r1g,r2e,r2g,df,kge,keg) M0=np.matrix([[0.5],[pg],[0.0],[0.0],[1-pg],[0.0],[0.0]]) for k in range(len(nb_pulse)): tcp=Tc/(4.0*nb_pulse[k]) nb_total = 2*int(nb_pulse[k]) Mint=M0 Rexpo=expm(Rtemp*tcp) for kk in range(0, nb_total): Mint=Rexpo*Mint Mint=R180_3Dx(0)*Mint Mint=Rexpo*Mint Rcalc_array[k]=-(1.0/Tc)*log(fabs((Mint[1]+Mint[4]))); return Rcalc_array if a==3: print('optimization with the function 2D_slow') def func1(r1e,r1g,r2e,r2g,df,kex,pg, nb_pulse): #ATTENTION nb_pulse (not nu_cpmg) kge=(1-pg)*kex; keg=pg*kex Rcalc_array=np.zeros(len(nb_pulse)) Rtemp=RCPMG_2D(r2e, r2g,df, kge, keg) M0=np.matrix([[pg],[0.0],[1-pg],[0.0]]) for k in range(len(nb_pulse)): tcp=Tc/(4.0*nb_pulse[k]) nb_total = 2*int(nb_pulse[k]) Mint=M0 Rexpo=expm(Rtemp*tcp) for kk in range(0, nb_total): Mint=Rexpo*Mint Mint=R180x_2D(0)*Mint Mint=Rexpo*Mint Rcalc_array[k]=-(1.0/Tc)*log(fabs(Mint[0]/pg)); return Rcalc_array if a==4: # This function is not required. the above "slow" version is enough. print('optimization with the function 2D_fast') def func1(r1e,r1g,r2e,r2g,df,kex,pg, nb_pulse): #ATTENTION nb_pulse (not nu_cpmg) kge=(1-pg)*kex; keg=pg*kex Rcalc_array=np.zeros(len(nb_pulse)) Rtemp=RCPMG_2D(r2e, r2g,df, kge, keg) M0=np.matrix([[pg],[0.0],[1-pg],[0.0]]) for k in range(len(nb_pulse)): tcp=Tc/(4.0*nb_pulse[k]) nb_total = 2*int(nb_pulse[k]) Mint=M0 Rexpo=expm(Rtemp*tcp) for kk in range(0, nb_total): Mint=Rexpo*Mint Mint=R180x_2D(0)*Mint Mint=Rexpo*Mint Rcalc_array[k]=-(1.0/Tc)*log(fabs((Mint[0]+Mint[2]))); return Rcalc_array if a==5: #This function is EXACT, just as the explicit Bloch-McConnell numerical treatments above. # It comes from a Maple derivation based on the Bloch-McConnell equations. It is much faster # than the numerical Bloch-McConnell solution. # It was derived by Nikolai Skrynnikov, and is provided with his permission. print('optimization with the function 2D_num') def func1(r1e,r1g,r2e,r2g,df,kex,pg, nb_pulse): Rcalc_array=np.zeros(len(nb_pulse)) kge=(1-pg)*kex; keg=pg*kex M0=np.matrix([[pg],[1-pg]]) tcp=Tc/(nb_pulse) N = Tc/tcp Mint=M0 Kb=keg; Ka=kge; Rinf=r2g; dw=df #*math.pi*2 j=complex(0,1); t3 = j; t4 = t3*dw; t5 = Kb*Kb; t8 = 2*t3*Kb*dw; t10 = 2*Kb*Ka; t11 = dw*dw; t14 = 2*t3*Ka*dw; t15 = Ka*Ka; t17 = cmath.sqrt(t5-t8+t10-t11+t14+t15); t21 = np.exp((-Kb+t4-Ka+t17)*tcp/4); t22 = 1./t17; t28 = np.exp((-Kb+t4-Ka-t17)*tcp/4); t31 = t21*t22*Ka-t28*t22*Ka; t33 = cmath.sqrt(t5+t8+t10-t11-t14+t15); t34 = Kb+t4-Ka+t33; t37 = np.exp((-Kb-t4-Ka+t33)*tcp/2); t39 = 1./t33; t41 = Kb+t4-Ka-t33; t44 = np.exp((-Kb-t4-Ka-t33)*tcp/2); t47 = t34*t37*t39/2-t41*t44*t39/2; t49 = Kb-t4-Ka-t17; t51 = t21*t49*t22; t52 = Kb-t4-Ka+t17; t54 = t28*t52*t22; t55 = -t51+t54; t60 = t37*t39*Ka-t44*t39*Ka; t62 = t31*t47+t55*t60/2; t63 = 1./Ka; t68 = -t52*t63*t51/2+t49*t63*t54/2; t69 = t62*t68/2; t72 = t37*t41*t39; t76 = t44*t34*t39; t78 = -t34*t63*t72/2+t41*t63*t76/2; t80 = -t72+t76; t82 = t31*t78/2+t55*t80/4; t83 = t82*t55/2; t88 = t52*t21*t22/2-t49*t28*t22/2; t91 = t88*t47+t68*t60/2; t92 = t91*t88; t95 = t88*t78/2+t68*t80/4; t96 = t95*t31; t97 = t69+t83; t98 = t97*t97; t99 = t92+t96; t102 = t99*t99; t108 = t62*t88+t82*t31; t112 = np.sqrt(t98-2*t99*t97+t102+4*(t91*t68/2+t95*t55/2)*t108); t113 = t69+t83-t92-t96-t112; t115 = N/2; t116 = np.power(t69/2+t83/2+t92/2+t96/2+t112/2,t115) t118 = 1./t112; t120 = t69+t83-t92-t96+t112; t122 = np.power(t69/2+t83/2+t92/2+t96/2-t112/2,t115) t127 = 1./t108; t139 = 1./(Ka+Kb)*((-t113*t116*t118/2+t120*t122*t118/2)*Kb+(-t113*t127*t116*t120*t118/2+t120*t127*t122*t113*t118/2)*Ka/2); intensity0 = pg intensity = np.real(t139)*np.exp(-Tc*Rinf) Rcalc=-(1./Tc)*np.log(intensity/intensity0); return Rcalc if a==6: # This function does the numerical solution of the BlochMcConnell equations. It neglects the z component. The difference to the above "2D_slow and 2D_fast" is that it uses complex matrices, this reduces the number of matrix manipulations and thus speeds up the process. print('optimization with the function 2D complex') def func1(r1e,r1g,r2e,r2g,df,kex,pg, nb_pulse): # def func1(R2E,R2G,fg,kge,keg, cpmgfreq,tcpmg): kge=(1-pg)*kex; keg=pg*kex Rcalc_array=np.zeros(len(nb_pulse)) Rr = -1.*np.matrix([[r2g, 0.],[0., r2e]]) Rex = -1.*np.matrix([[kge,-keg],[-kge, keg]]) RCS = complex(0.,-1.)*np.matrix([[0. ,0.],[0.,df]]) R = Rr + Rex + RCS cR = np.conj(R) M0=np.matrix([[keg/(keg+kge)],[kge/(keg+kge)]]) for k in range(len(nb_pulse)): tcp=Tc/(4.*nb_pulse[k]) #tcp=Tc/(4.0*nb_pulse[k]) prop_2 = np.dot(np.dot(expm(R*tcp),expm(cR*2.*tcp)),expm(R*tcp)) prop_total =mpower(prop_2,nb_pulse[k]) Moft = prop_total*M0 Mgx=Moft[0].real/M0[0] Rcalc=-(1./Tc)*math.log(Mgx); Rcalc_array[k]=Rcalc return Rcalc_array else: print ('ERROR! enter a number between 1 and 5 to chose the optimization function') return func1 print('optimization function number: '),int(sh.cell(8,1).value) fp0=MakeFunction(int(sh.cell(8,1).value)) '''function which simulates a flat R2eff profile (non exchange model) according to the number of pulses during the constant time:''' def fpS0(v0,nb_pulse): #v0=R2inf Rcalc_array=np.zeros(len(nb_pulse)) for k in range(len(nb_pulse)): Rcalc_array[k]=v0 return Rcalc_array '''khi2 calculation function between 2 same-size arrays''' def chi(Rc, Rd, data_err): KHI=(Rc-Rd)/data_err return KHI '''error function for the exchange model''' def e(p, x, my_data, R1E, R1G, R2E, data_err): KHI2=np.zeros(0) #len(my_data[0])=nb of R2eff if p[1]<0: p[1]=-p[1] if p[2]<0: p[2]=-p[2] for kk in range(len(my_data)): #len(my_data)=nb of fields KHI2=np.append(KHI2, chi(fp0(R1E,R1G,R2E, p[3+kk],p[0]*my_fields[kk],p[1], p[2],x[kk]), my_data[kk], data_err[kk])) return KHI2 '''error function for the non exchange model''' def eS(p, x, my_data, R1E, R1G, R2E, data_err): KHI2=np.zeros(0) for kk in range(len(my_data)): #len(my_data)=nb of fields KHI2=np.append(KHI2,chi(fpS0(p[kk], x[kk]), my_data[kk], data_err[kk])) return KHI2 KHI2={} #contains the KHI2 of the exchange model fit compared with data, for each MonteCarlo simulation, for all residues pSTAT=[] #contains the pValue for all residues f=open(PathOutputFile+str('fitting.txt'), 'w') f.close() for kres in range(len(my_residues)): '''non fitted parameters''' R1E=float(sh.cell(21,1+res).value) R1G=float(sh.cell(22,1+res).value) R2E=float(sh.cell(23,1+res).value) name=my_residues[kres] print('------R2eff fitting calculation for residue: '), name data_EXP={} x={} data_EXP_error={} paramCPMG_0=paramCPMG0[kres] index=np.zeros(nb_fields) for nf in range(nb_fields): data_EXP[nf]=np.delete(my_R2eff[nf, kres], 0) #deletion of the first point, from the reference spectrum (no pulse applied) data_EXP_error[nf]=np.delete(my_errors[nf, kres], 0) #deletion of the first point, from the reference spectrum (no pulse applied) x[nf]=np.delete(freq[nf], 0) #deletion of the first point, from the reference spectrum (no pulse applied) for kk in range(len(x[nf])): #search for the repetition of the first point if x[nf][kk]==0: index[nf]=kk if index[nf]!=0: x[nf]=np.delete(x[nf], index[nf]) data_EXP[nf]=np.delete(data_EXP[nf], index[nf]) data_EXP_error[nf]=np.delete(data_EXP_error[nf], index[nf]) '''param=[ df, kex, pg, R2G_f1, R2G_f2]''' p, success =leastsq(e, paramCPMG_0, args=(x,data_EXP, R1E, R1G, R2E,data_EXP_error), maxfev=nbCALLfunc) pS, success =leastsq(eS, paramCPMG_0[3:], args=(x, data_EXP, R1E, R1G, R2E, data_EXP_error), maxfev=nbCALLfunc) print('initial parameters: '), paramCPMG_0 print('fitted parameters: '), p yS={} #contains the fitted R2eff with non-exchange model for all fields for one residue y={} #contains the fitted R2eff with exchange model for all fields for one residue chi2EMF_n={} #contains the khi2 between R2eff data and fitted R2eff for the exchange model chi2SMF_n={} #contains the khi2 between R2eff data and fitted R2eff for the non exchange model for nf in range(nb_fields): yS[nf]=fpS0(pS[nf], x[nf]) y[nf]=fp0(R1E,R1G,R2E, p[3+nf],p[0]*my_fields[nf],p[1], p[2],x[nf]) chi2EMF_n[nf]=chi(y[nf], data_EXP[nf], data_EXP_error[nf])*chi(y[nf], data_EXP[nf], data_EXP_error[nf]) chi2SMF_n[nf]=chi(yS[nf], data_EXP[nf], data_EXP_error[nf])*chi(yS[nf], data_EXP[nf], data_EXP_error[nf]) '''Ftest''' KHI2_emf=sum(chi2EMF_n[0])+sum(chi2EMF_n[1]) #sum of the khi2 for only 2 fields, exchange model KHI2_smf=sum(chi2SMF_n[0])+sum(chi2SMF_n[1]) #sum of the khi2 for only 2 fields, non exchange model print('KHI2 for the model with exchange : '), KHI2_emf print('KHI2 for the model without exchange : '), KHI2_smf P_SMF=nb_fields; P_EMF=nb_fields+3 ###number of fitted parameters Diff_SMF=len(x[0])-P_SMF; Diff_EMF=len(x[0])-P_EMF Ftest=stats.f_value(KHI2_smf, KHI2_emf, Diff_SMF, Diff_EMF) # F test Pvalue=stats.f.sf(Ftest, Diff_SMF-Diff_EMF, Diff_EMF) # p value calculation print('Pvalue: '), Pvalue pSTAT.append(Pvalue) '''data plot and fit curves plot ''' parameters=[round(p[0],2), round(p[1],2), round(p[2],2)] for nf in range(nb_fields): parameters.append(round(p[3+nf],2)) parameters.append(round(KHI2_emf)) parameters.append(round(KHI2_smf)) parameters.append(Pvalue) parametersNAME=['delta(ppm)', 'kex (s-1)', 'pG '] for nf in range(nb_fields): parametersNAME.append(str('R2G_')+str(int(my_fields[nf]))+str('(s-1)')) parametersNAME.append('khi2(ex)') parametersNAME.append('khi2(non ex)') parametersNAME.append('Pvalue') fig = plt.figure() PlotData={} NameFields=[] for nf in range(nb_fields): if index[nf]!=0: plot(x[nf][:index[nf]], y[nf][:index[nf]]) #x[0][:22], y[:22] else: plot(x[nf], y[nf]) plot(x[nf], yS[nf]) PlotData[nf]=errorbar(x[nf],data_EXP[nf], yerr=data_EXP_error[nf], fmt='o') NameFields.append(str(my_fields[nf])+str('MHz')) plotdata=[] for nf in range(nb_fields): plotdata.append(PlotData[nf]) legend(plotdata, NameFields) f=open(PathOutputFile+str('fitting.txt'), 'a') if kres == 0: f.write('param:') f.write(' ') for jj in range(len(parameters)): f.write(parametersNAME[jj]) f.write(' ') f.write('\n') f.write(name) f.write(' ') for jj in range(len(parameters)): f.write(str(parameters[jj])) if jj != len(parameters)-1: f.write(' ') plt.title(name) plt.savefig(PathOutputFile+name) #plt.pause(0.5) f.close() if nbMC!=0: #test if MC calculation is expected nbCall=100 #number of e function calls to fit the pseudo-data, calculated from the fit curve + gaussian noise print ('-----MonteCarlo calculations:-----'), nbMC R_pdE={} R_pdS={} for nf in range(nb_fields): R_pdE[nf]=fp0(R1E,R1G,R2E,p[3+nf],p[0]*my_fields[nf],p[1],p[2], x[nf]) R_pdS[nf]=fpS0(pS[0], x[nf]) KHI2[kres]=[] pMC={} for jj in range(nbMC): #if nbMC%10==0: # print ('MonteCarlo loading: '), jj loading=0 data={} for nf in range(nb_fields): data[nf]=np.zeros(len(R_pdE[nf])) for j in range(len(data[nf])): data[nf][j]=gauss(R_pdE[nf][j], data_EXP_error[nf][j]) pE, success=leastsq(e, p, args=(x,data, R1E, R1G, R2E,data_EXP_error), maxfev=nbCall) pSmc, success =leastsq(eS, pS, args=(x, data, R1E, R1G, R2E, data_EXP_error), maxfev=nbCall) numbercallofe=0 yE={} k2={} for nf in range(nb_fields): yE[nf]=fp0(R1E,R1G,R2E,pE[3+nf],pE[0]*my_fields[nf],pE[1],pE[2], x[nf]) k2[nf]=chi(yE[nf], data[nf],data_EXP_error[nf])*chi(yE[nf], data[nf], data_EXP_error[nf]) KHI2[kres].append(sum(k2[0])+sum(k2[1])) pMC[jj]=pE # print ('KHI2 for the residue '), name # print('is: '), KHI2[kres] fig = plt.figure() pylab.hist(KHI2[kres], bins=nbMC) DeviationStandard=np.std(KHI2[kres]) figtext(0.7, 0.75, 'Standard deviation:') figtext(0.7, 0.72, round(DeviationStandard, 2)) figtext(0.7, 0.67, 'Khi2 exp:') figtext(0.7, 0.64, round(KHI2_emf, 2)) legend([name]) plt.title(str('Khi2 for ')+str(nbMC)+str(' MonteCarlo simulations')) plt.savefig(PathOutputFile+name+str('_Khi2')) # plt.pause(0.5) pp={} for NbPar in range(3+nb_fields): pp[NbPar]=np.zeros(nbMC) for jj in range(nbMC): pp[NbPar][jj]=pMC[jj][NbPar] fig = plt.figure() pylab.hist(pp[NbPar], bins=nbMC) DeviationStandard=np.std(pp[NbPar]) figtext(0.7, 0.75, 'Standard deviation:') figtext(0.7, 0.72, round(DeviationStandard, 2)) figtext(0.7, 0.67, parametersNAME[NbPar]+str(':')) figtext(0.7, 0.64,parameters[NbPar] ) legend([name]) plt.title(str(sh.cell(12+NbPar,0).value)+str(' (')+str(nbMC)+str(' MonteCarlo simulations)')) plt.savefig(PathOutputFile+name+str('_')+str(NbPar)) # plt.pause(0.5) else: print('-----No MonteCarlo calculation-----')
You will find in the attached program six different implementations, that can be chosen with the variable a set to 1-6. In practice, however, we are using only the "2D complex" numerical approach (a=6), or the Maple-derived approach (a=5). The latter is faster, and is most-often used. It has not been published, though. The numerical Bloch-McConnell treatment is described in many introductory NMR books, and also in e.g. McConnell, H. J Chem Phys 1958, 28, 430–431. (the original reference) Palmer, A. G. Chem Rev 2004, 104, 3623–3640. Palmer, A. G.; Massi, F. Chem Rev 2006, 106, 1700–1719. Baldwin, A. J.; Kay, L. E. J Biomol NMR 2013. The latter two are R1rho, but the formalism of Bloch-McConnell is the same. Paul Hi Paul, |