import numpy import scipy.integrate #scipy solve_ivp interface using system of n equations #infrastructure for sensitivity analysis of y with respect #to model parameters p also integrated # #General form of equation: # dy/dt=M*y+u #where y is an n-vector and M is nxn Jacobi matrix # #implementation of system has to provide attributes: # - n, number of variables # - m, number of parameters # - M(t), nxn, a time dependent Jacobi matrix, # - u(t), 1xn, a time dependent source term # - fS(t) mxn, a time dependent array of derivatives # fS(t)[p,:] = d(M*y)/dp (t) # where y is internal interpolated y-only ivp solution # - fSY(t,y), mxn, a time dependent array of derivatives: # fS(t)[p,:] = d(M*y)/dp (t) # where current y is supplied at each step # - Su(t), mxn, a (time dependent) array of partial derivatives: # Su(t)[p,i] = du_i/dp (t) def dfdy(t,y,system): dfdy=system.M(t).dot(y)+system.u(t) return dfdy def jacobi(t,y,system): return system.M(t) #SE post calculation def dfdyS(t,S,system): #unwrap S to NxM where M is number of parameters mS=numpy.reshape(S,(system.n,system.m)) mOut=system.M(t).dot(mS)+system.fS(t) return numpy.ravel(mOut) def jacobiSE(t,S,system): N=system.n*(system.m) fJ=numpy.zeros((N,N)) #print('fJ shape {}'.format(fJ.shape)) for i in range(system.m): fJ[i*system.n:(i+1)*system.n,i*system.n:(i+1)*system.n]=system.M(t) return fJ #SE simultaeneous calculation def dfdySFull(t,S,system): #unwrap S to NxM where M is number of parameters mS=numpy.reshape(S,(system.n,system.m+1)) #system.fS(y,t) is NxM matrix where M are parameters y=mS[:,0] mOut=system.M(t,y).dot(mS)+system.fSY(y,t) #add u derivatives mOut[:,1:]+=numpy.transpose(system.Su(t)) try: system.iPrint+=1 except AttributeError: system.iPrint=0 if system.iPrint>1000: print('At t={:.2f}'.format(t),flush=True) system.iPrint=0 return numpy.ravel(mOut) def jacobiSEFull(t,S,system): return system.jacobiFull(t) def solveSimultaneous(model,tmax,atol,rtol,method='LSODA',nt=201,\ t0=0,y0=numpy.array([]), sIn=numpy.array([])): t_eval=numpy.linspace(t0,tmax,nt) s0=numpy.zeros((model.n,model.m+1)) if sIn.size!=0: s0[:,1:]=sIn if y0.size==0: y0=numpy.zeros(model.n) #set initial condition s0[:,0]=y0 s0=s0.ravel() sol=scipy.integrate.solve_ivp(dfdySFull,[t0, tmax],s0, args=(model,),\ jac=jacobiSEFull, method=method, \ atol=atol, rtol=rtol, t_eval=t_eval) t=sol.t sFull=numpy.reshape(numpy.transpose(sol.y),(len(t),model.n,model.m+1)) s1=sFull[:,:,1:] ysol=sFull[:,:,0] se=model.calculateUncertainty(s1) print('Done simultaneous LSODA SE') return t,ysol,se,s1 def solveSequential(model,tmax,atol,rtol,method='LSODA',nt=201,\ t0=0,y0=numpy.array([]), sIn=numpy.array([])): t_eval=numpy.linspace(t0,tmax,nt) if y0.size==0: y0=numpy.zeros(model.n) solIVP=scipy.integrate.solve_ivp(dfdy,[t0, tmax],y0, args=(model,), jac=jacobi, method=method, atol=atol, rtol=rtol, t_eval=t_eval) #y is n x nt (odeint nt x n) sol=numpy.transpose(solIVP.y) t=solIVP.t print('shape (y) {}'.format(sol.shape)) model.setY(t,sol) s0=numpy.zeros((model.n,model.m)) if sIn.size==0: s0=sIn s0=s0.ravel() solIVPSE=scipy.integrate.solve_ivp(dfdyS,[0, tmax],s0, args=(model,), jac=jacobiSE, method=method, atol=atol, rtol=rtol,t_eval=t_eval) sraw=numpy.reshape(numpy.transpose(solIVPSE.y),(len(solIVPSE.t),model.n,model.m)) #interpolate on t s1=numpy.zeros((len(t),model.n,model.m)) for i in range(model.n): for j in range(model.m): tck = scipy.interpolate.splrep(solIVPSE.t, sraw[:,i,j], s=0) s1[:,i,j]=scipy.interpolate.splev(t, tck, der=0) se=model.calculateUncertainty(s1) return t,sol,se,s1 def solveSimultaneousOdeint(model,tmax,nt=201,t0=0,y0=numpy.array([]), sIn=numpy.array([])): t = numpy.linspace(t0,tmax, nt) if y0.size==0: y0=numpy.zeros(model.n) s0=numpy.zeros((model.n,model.m+1)) if sIn.size!=0: s0[:,1:]=sIn #set initial condition s0[:,0]=y0 s0=s0.ravel() solSE1=scipy.integrate.odeint(dfdySFull, s0, t, args=(model,),Dfun=jacobiSEFull,tfirst=True) sFull=numpy.reshape(solSE1,(len(t),model.n,model.m+1)) s1=sFull[:,:,1:] sol=sFull[:,:,0] se=sys.calculateUncertainty(s1) print('Done simultaneous SE') return t,sol,se,s1 def solveSequentialOdeint(model,tmax,nt=201,t0=0,y0=numpy.array([]),sIn=numpy.array([])): t = numpy.linspace(t0,tmax, nt) if y0.size==0: y0=numpy.zeros(sys.n) sol = scipy.integrate.odeint(dfdy, y0=y0, t=t, args=(model,),Dfun=jacobi,tfirst=True) print('shape (y) {}'.format(sol.shape)) model.setY(t,sol) s0=numpy.zeros((model.n,model.m)) if sIn.size==0: s0=sIn s0=s0.ravel() solSE=scipy.integrate.odeint(dfdyS, s0, t, args=(model,),Dfun=jacobiSE,tfirst=True) s1=numpy.reshape(solSE,(len(t),model.n,model.m)) se=model.calculateUncertainty(s1) print('Done sequential SE') return t,sol,se,s1