[docs]classTemporalDiscretization(Frozen):"""A wrapper of the temporal discretization setting of a weak formulation."""def__init__(self,wf):""""""self._wf=wfself._initialize_odes()self._ats=Noneself._freeze()def_initialize_odes(self):"""Initialize odes."""fromsrc.ode.mainimportode# must import locally here to avoid a circular importwf=self._wfvalid_ode=dict()foriinwf._term_dict:terms=wf._term_dict[i]signs=wf._sign_dict[i]v_ode=ode(terms_and_signs=[terms,signs])valid_ode[i]=v_odeself._valid_ode=valid_odedef__getitem__(self,item):"""Return the ode."""returnself._valid_ode[item].discretizedef__iter__(self):"""iter over valid ode numbers."""forvalid_ode_numberinself._valid_ode:yieldvalid_ode_numberdef__call__(self,*args,clean=True,**kwargs):"""Return a new weak formulation by combining all equations."""wfs:Dict=dict()foriinself:wfs[i]=self[i]()foriinself._wf._term_dict:ifinotinwfs:wfs[i]={'_term_dict':self._wf._term_dict[i],'_sign_dict':self._wf._sign_dict[i]}else:passwf=self._wf.__class__(self._wf._test_forms,merge=wfs)wf._bc=self._wf._bc# we get the new weak formulation by combining each pde.ifclean:# make sure this temporal discretization is used only once.self._wf=Noneself._valid_ode=Noneelse:passreturnwf@propertydefts(self):returnself._ats@propertydeftime_sequence(self):"""The time sequence this temporal discretization is working on."""returnself._ats
[docs]defset_time_sequence(self,ts=None):"""The method of setting time sequence. .. note:: Note that each wf only use one time sequence. If your time sequence is complex, you should carefully design it instead of using multiple time sequences. """iftsisNone:# make a new onets=AbstractTimeSequence()else:passassertts.__class__.__name__=='AbstractTimeSequence',f"I need an abstract time sequence object."assertself._atsisNone,f"time_sequence existing, change it may leads to unexpected issue."self._ats=tsforiinself:self[i].set_time_sequence(self._ats)
[docs]defdefine_abstract_time_instants(self,*atis):"""Define abstract time instants for the temporal discretization."""foriinself:self[i].define_abstract_time_instants(*atis)
[docs]defdifferentiate(self,index,*args):"""Differentiate the term indexed ``index`` at abstract time instances."""assertindexinself._wf,f"index={index} is illegal, print representations to check the indices."i,j=index.split('-')ode_d=self[int(i)]ode_d.differentiate(j,*args)
[docs]defaverage(self,index,f,*args,which='all'):"""Average the term indexed ``index`` at abstract time instances."""assertindexinself._wf,f"index={index} is illegal, print representations to check the indices."i,j=index.split('-')ode_d=self[int(i)]iflen(args)==1:ode_d.average(j,f,*args,which=which)else:ode_d.average(j,f,args,which=which)
if__name__=='__main__':# python src/wf/td.pyimport__init__asphsamples=ph.samplesoph=samples.pde_canonical_pH(n=3,p=3)[0]oph.pr()a3,b2=oph.unknownswf=oph.test_with(oph.unknowns,sym_repr=[r'v^3',r'u^2'])wf=wf.derive.integration_by_parts('1-1')wf.pr(indexing=True)td=wf.tdtd.set_time_sequence()# initialize a time sequencetd.define_abstract_time_instants('k-1','k-1/2','k')td.differentiate('0-0','k-1','k')td.average('0-1',b2,['k-1','k'])td.differentiate('1-0','k-1','k')td.average('1-1',a3,['k-1','k'])td.average('1-2',a3,['k-1/2'])dt=td.time_sequence.make_time_interval('k-1','k')wf=td()wf.pr()wf.unknowns=[a3@td.time_sequence['k'],b2@td.time_sequence['k']]wf=wf.derive.split('0-0','f0',[a3@td.ts['k'],a3@td.ts['k-1']],['+','-'],factors=[1/dt,1/dt])wf=wf.derive.split('0-2','f0',[ph.d(b2@td.ts['k-1']),ph.d(b2@td.ts['k'])],['+','+'],factors=[1/2,1/2])wf=wf.derive.split('1-0','f0',[b2@td.ts['k'],b2@td.ts['k-1']],['+','-'],factors=[1/dt,1/dt])wf=wf.derive.split('1-2','f0',[a3@td.ts['k-1'],a3@td.ts['k']],['+','+'],factors=[1/2,1/2])wf=wf.derive.rearrange({0:'0, 3 = 1, 2',1:'3, 0 = 2, 1, 4',})ph.space.finite(3)ap=wf.apwf.pr()# wf.pr()# print(wf.elementary_forms)