# -*- coding: utf-8 -*-"""This module helps to build a transfer matrix and applying it to an DAS."""importsympyimportnumpyasnpimportscipy.linalgaslafromtypingimportListimportnumbers
[docs]classTransition(object):""" Represents a transtion between comparments. """def__init__(self,from_comp,to_comp,rate=None,qy=None):ifrateisNone:self.rate=sympy.Symbol(from_comp+'_'+to_comp,real=True,positive=True)else:self.rate=sympy.Symbol(rate,real=True,positive=True)self.from_comp=from_compself.to_comp=to_compifqyisNone:qy=1ifisinstance(qy,str):qy=sympy.Symbol(qy,real=True,positive=True)self.qu_yield=qy
[docs]classModel(object):""" Helper class to make a model """def__init__(self):self.transitions:List[Transition]=[]
[docs]defadd_transition(self,from_comp,to_comp,rate=None,qy=None):""" Adds an transition to the model. Parameters ---------- from_comp : str Start of the transition to_comp : str Target of the transition rate : str, optional Name of the associated rate, by default None, which generates a default name. qy : str of float, optional The yield of the transition, by default 1 """trans=Transition(from_comp,to_comp,rate,qy)self.transitions.append(trans)
[docs]defbuild_matrix(self):""" Builds the n x n k-matrix """comp=get_comparments(self.transitions)idx_dict=dict(enumerate(comp))inv_idx=dict(zip(idx_dict.values(),idx_dict.keys()))mat=sympy.zeros(len(comp))fortinself.transitions:i=inv_idx[t.from_comp]mat[i,i]=mat[i,i]-t.rate*t.qu_yieldift.to_comp!='zero':mat[inv_idx[t.to_comp],i]+=t.rate*t.qu_yieldself.mat=matreturnmat
[docs]defbuild_mat_func(self):# Use dict as an ordered setrates={t.rate:Nonefortinself.transitions}.keys()yields=(t.qu_yieldfortinself.transitionsifnotisinstance(t.qu_yield,numbers.Number))params=list(rates)+list(yields)K=self.build_matrix()K_func=sympy.lambdify(params,K)returnK_func
[docs]defget_trans(self,y0,taus,t):""" Return the solution """symbols=get_symbols(self.transitions)k=np.array(self.mat.subs(zip(symbols,taus))).astype('float')o=np.zeros((len(t),k.shape[0]))foriinrange(t.shape[0]):o[i,:]=la.expm(k*t[i]).dot(y0)[:,0]returno
[docs]defget_comparments(list_trans):""" Getting a list of transtions, return the compartments """l=[]fortransinlist_trans:iftrans.from_compnotinl:l.append(trans.from_comp)iftrans.to_compnotinlandtrans.to_comp!='zero':l.append(trans.to_comp)returnl
[docs]defget_symbols(list_trans):""" Return the used symbols """return[t.ratefortinlist_trans]