123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- 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
|