def comp_evcs_evls(compall=False, nevs=None, linsysstr=None, bigamat=None, bigmmatshift=None, bigmmat=None, retinstevcs=False): whichevecs = '_leftevs' if leftevecs else '_rightevs' bcstr = '_palpha{0}'.format(palpha) if bccontrol else '' levstr = linsysstr + bcstr + whichevecs try: if debug: raise IOError() evls = dou.load_npa(levstr) print 'loaded the eigenvalues of the linearized system: \n' + levstr if retinstevcs: evcs = dou.load_npa(levstr+'_instableevcs') return evls, evcs except IOError: print 'computing the eigenvalues of the linearized system: \n' + levstr if compall: A = bigamat.todense() M = bigmmat.todense() if not shiftall else bigmmatshift.todense() evls = spla.eigvals(A, M, overwrite_a=True, check_finite=False) else: if leftevecs: bigamat = bigamat.T # TODO: we assume that M is symmetric msplu = spsla.splu(bigmmatshift) def minvavec(vvec): return msplu.solve(bigamat*vvec) miaop = spsla.LinearOperator(bigamat.shape, matvec=minvavec, dtype=bigamat.dtype) shiftamm = bigamat - sigma*bigmmatshift sammsplu = spsla.splu(shiftamm) def samminvmvec(vvec): return sammsplu.solve(bigmmatshift*vvec) samminvop = spsla.LinearOperator(bigamat.shape, matvec=samminvmvec, dtype=bigamat.dtype) evls, evcs = spsla.eigs(miaop, k=nevs, sigma=sigma, OPinv=samminvop, maxiter=100, # sigma=None, which='SM', return_eigenvectors=retinstevcs) dou.save_npa(evls, levstr) if retinstevcs: instevlsindx = np.real(evls) > 0 instevcs = evcs[:, instevlsindx] dou.save_npa(instevcs, levstr+'_instableevcs') else: instevcs = None return evls, instevcs
def compcong(): try: zwc = dou.load_npa(fdstr + '__zwc') print 'at least __zwc is there' except IOError: zwc = get_gramians(mmat=mmat, amat=f_mat, jmat=stokesmatsc['J'], bmat=b_mat, wmat=c_mat_reg.T, nwtn_adi_dict=nap, z0=zinic)['zfac'] dou.save_npa(zwc, fdstr + '__zwc')
def compcong(): try: zwc = dou.load_npa(fdstr + '__zwc') print('yeyeyeah, __zwc is there') except IOError: # XXX: why here bmat*Rmhalf and in zwo not? zwc = get_ricadifacs(mmat=mmat, amat=fmat, jmat=jmat, bmat=bmat, wmat=cmat.T, z0=zinic, **adidict)['zfac'] dou.save_npa(zwc, fdstr + '__zwc') return
def compobsg(): try: zwo = dou.load_npa(fdstr + '__zwo') print 'at least __zwo is there' except IOError: zwo = get_gramians(mmat=mmat.T, amat=f_mat.T, jmat=stokesmatsc['J'], bmat=c_mat_reg.T, wmat=b_mat, nwtn_adi_dict=nap, z0=zinio)['zfac'] dou.save_npa(zwo, fdstr + '__zwo')
def compobsg(): if zwconly: print('we only compute zwc') return try: zwo = dou.load_npa(fdstr + '__zwo') print('yeyeyeah, __zwo is there') except IOError: zwo = get_ricadifacs(mmat=mmat.T, amat=fmat.T, jmat=jmat, bmat=cmat.T, wmat=bmat, z0=zinio, **adidict)['zfac'] dou.save_npa(zwo, fdstr + '__zwo') return
def rothe_time_int(problem='cylinderwake', nu=None, Re=None, Nts=256, t0=0.0, tE=0.2, Nll=[2], viniv=None, piniv=None, Nini=None, scheme=None, dtstrdct={}, method=2): trange = np.linspace(t0, tE, Nts+1) t = trange[0] dtstrdct.update(dict(t=0, N=Nll[0])) cdatstr = get_dtstr(**dtstrdct) dou.save_npa(viniv, cdatstr + '__vel') curvdict = {t: cdatstr + '__vel'} dou.save_npa(piniv, cdatstr + '__p') logger.info('v/p saved to ' + cdatstr + '__v/__p') curpdict = {t: cdatstr + '__p'} smaminex = True if method == 1 else False vcurvec = viniv logger.debug(' t={0}, |v|={1}'.format(t, npla.norm(vcurvec))) curmeshdict = get_curmeshdict(problem=problem, N=Nll[0], nu=nu, Re=Re, scheme=scheme, smaminex=smaminex) curmeshdict.update(coefalu=None) Vc = curmeshdict['V'] for tk, t in enumerate(trange[1:]): cts = t - trange[tk] if not Nll[tk+1] == Nll[tk]: curmeshdict = get_curmeshdict(problem=problem, N=Nll[tk+1], nu=nu, Re=Re, scheme=scheme, smaminex=smaminex) curmeshdict.update(coefalu=None) logger.info('changed the mesh from N={0} to N={1} at t={2}'. format(Nll[tk], Nll[tk+1], t)) # change in the mesh Nvc = curmeshdict['A'].shape[0] logger.debug("t={0}, dim V={1}".format(t, curmeshdict['V'].dim())) if smaminex: vpcur, coefalu = \ roth_upd_smmx(vvec=vcurvec, cts=cts, Vc=Vc, diribcsc=curmeshdict['diribcs'], nmd=curmeshdict, returnalu=True) else: # index 2 vpcur, coefalu = \ roth_upd_ind2(vvec=vcurvec, cts=cts, Vc=Vc, diribcsc=curmeshdict['diribcs'], nmd=curmeshdict, returnalu=True) dtstrdct.update(dict(t=t, N=Nll[tk+1])) cdatstr = get_dtstr(**dtstrdct) # add the boundary values to the velocity vcurvec = dts.append_bcs_vec(vpcur[:Nvc], **curmeshdict) logger.debug(' t={0}, |v|={1}'.format(t, npla.norm(vcurvec))) dou.save_npa(vcurvec, cdatstr+'__vel') curvdict.update({t: cdatstr+'__vel'}) dou.save_npa(vpcur[Nvc:, :], cdatstr+'__p') curpdict.update({t: cdatstr+'__p'}) curmeshdict.update(dict(coefalu=coefalu)) Vc = curmeshdict['V'] return curvdict, curpdict
def optcon_nse(problemname='drivencavity', N=10, Nts=10, nu=1e-2, clearprvveldata=False, ini_vel_stokes=False, stst_control=False, closed_loop=True, outernwtnstps=1, t0=None, tE=None, use_ric_ini_nu=None, alphau=1e-9, gamma=1e-3, spec_tip_dict=None, nwtn_adi_dict=None, linearized_nse=False, stokes_flow=False, ystar=None): tip = time_int_params(Nts, t0=t0, tE=tE) if spec_tip_dict is not None: tip.update(spec_tip_dict) if nwtn_adi_dict is not None: tip['nwtn_adi_dict'] = nwtn_adi_dict problemdict = dict(drivencavity=dnsps.drivcav_fems, cylinderwake=dnsps.cyl_fems) problemfem = problemdict[problemname] femp = problemfem(N) # output ddir = 'data/' try: os.chdir(ddir) except OSError: raise Warning('need "' + ddir + '" subdir for storing the data') os.chdir('..') if linearized_nse and not outernwtnstps == 1: raise Warning('Linearized problem can have only one Newton step') if closed_loop: if stst_control: data_prfx = ddir + 'stst_' + problemname + '__' else: data_prfx = ddir + 'tdst_' + problemname + '__' else: data_prfx = ddir + problemname + '__' if stokes_flow: data_prfx = data_prfx + 'stokes__' # specify in what spatial direction Bu changes. The remaining is constant if problemname == 'drivencavity': uspacedep = 0 elif problemname == 'cylinderwake': uspacedep = 1 stokesmats = dts.get_stokessysmats(femp['V'], femp['Q'], nu) rhsd_vf = dts.setget_rhs(femp['V'], femp['Q'], femp['fv'], femp['fp'], t=0) # remove the freedom in the pressure stokesmats['J'] = stokesmats['J'][:-1, :][:, :] stokesmats['JT'] = stokesmats['JT'][:, :-1][:, :] rhsd_vf['fp'] = rhsd_vf['fp'][:-1, :] # reduce the matrices by resolving the BCs (stokesmatsc, rhsd_stbc, invinds, bcinds, bcvals) = dts.condense_sysmatsbybcs(stokesmats, femp['diribcs']) print 'Dimension of the div matrix: ', stokesmatsc['J'].shape # pressure freedom and dirichlet reduced rhs rhsd_vfrc = dict(fpr=rhsd_vf['fp'], fvc=rhsd_vf['fv'][invinds, ]) # add the info on boundary and inner nodes bcdata = {'bcinds': bcinds, 'bcvals': bcvals, 'invinds': invinds} femp.update(bcdata) # casting some parameters NV = len(femp['invinds']) soldict = stokesmatsc # containing A, J, JT soldict.update(femp) # adding V, Q, invinds, diribcs # soldict.update(rhsd_vfrc) # adding fvc, fpr soldict.update(fv=rhsd_stbc['fv'] + rhsd_vfrc['fvc'], fp=rhsd_stbc['fp'] + rhsd_vfrc['fpr'], N=N, nu=nu, trange=tip['tmesh'], get_datastring=get_datastr, data_prfx=data_prfx, clearprvdata=clearprvveldata, paraviewoutput=tip['ParaviewOutput'], vfileprfx=tip['proutdir'] + 'vel_', pfileprfx=tip['proutdir'] + 'p_') # # Prepare for control # contp = ContParams(femp['odcoo'], ystar=ystar, alphau=alphau, gamma=gamma) # casting some parameters NY, NU = contp.NY, contp.NU contsetupstr = problemname + '__NV{0}NU{1}NY{2}'.format(NV, NU, NY) # get the control and observation operators try: b_mat = dou.load_spa(ddir + contsetupstr + '__b_mat') u_masmat = dou.load_spa(ddir + contsetupstr + '__u_masmat') print 'loaded `b_mat`' except IOError: print 'computing `b_mat`...' b_mat, u_masmat = cou.get_inp_opa(cdcoo=femp['cdcoo'], V=femp['V'], NU=NU, xcomp=uspacedep) dou.save_spa(b_mat, ddir + contsetupstr + '__b_mat') dou.save_spa(u_masmat, ddir + contsetupstr + '__u_masmat') try: mc_mat = dou.load_spa(ddir + contsetupstr + '__mc_mat') y_masmat = dou.load_spa(ddir + contsetupstr + '__y_masmat') print 'loaded `c_mat`' except IOError: print 'computing `c_mat`...' mc_mat, y_masmat = cou.get_mout_opa(odcoo=femp['odcoo'], V=femp['V'], NY=NY) dou.save_spa(mc_mat, ddir + contsetupstr + '__mc_mat') dou.save_spa(y_masmat, ddir + contsetupstr + '__y_masmat') # restrict the operators to the inner nodes mc_mat = mc_mat[:, invinds][:, :] b_mat = b_mat[invinds, :][:, :] # for further use: c_mat = lau.apply_massinv(y_masmat, mc_mat, output='sparse') if contp.ystarx is None: c_mat = c_mat[NY:, :][:, :] # TODO: Do this right mc_mat = mc_mat[NY:, :][:, :] # TODO: Do this right y_masmat = y_masmat[:NY, :][:, :NY] # TODO: Do this right mct_mat_reg = lau.app_prj_via_sadpnt(amat=stokesmatsc['M'], jmat=stokesmatsc['J'], rhsv=mc_mat.T, transposedprj=True) # set the weighing matrices contp.R = contp.alphau * u_masmat # # solve the differential-alg. Riccati eqn for the feedback gain X # via computing factors Z, such that X = -Z*Z.T # # at the same time we solve for the affine-linear correction w # # tilde B = BR^{-1/2} tb_mat = lau.apply_invsqrt_fromright(contp.R, b_mat, output='sparse') # tb_dense = np.array(tb_mat.todense()) trct_mat = lau.apply_invsqrt_fromright(y_masmat, mct_mat_reg, output='dense') if closed_loop: cntpstr = 'NV{3}NY{0}NU{1}alphau{2}gamma{4}'.\ format(contp.NU, contp.NY, contp.alphau, NV, contp.gamma) else: cntpstr = '' # we gonna use this quite often M, A = stokesmatsc['M'], stokesmatsc['A'] datastrdict = dict(time=None, meshp=N, nu=nu, Nts=Nts, data_prfx=data_prfx) # compute the uncontrolled steady state (Navier-)Stokes solution # as initial value if ini_vel_stokes: # compute the uncontrolled steady state Stokes solution ini_vel, newtonnorms = snu.solve_steadystate_nse(vel_nwtn_stps=0, vel_pcrd_stps=0, **soldict) soldict.update(dict(iniv=ini_vel)) else: ini_vel, newtonnorms = snu.solve_steadystate_nse(**soldict) soldict.update(dict(iniv=ini_vel)) if closed_loop: if stst_control: if stokes_flow: convc_mat = sps.csr_matrix((NV, NV)) rhs_con, rhsv_conbc = np.zeros((NV, 1)), np.zeros((NV, 1)) lin_point = None else: lin_point, newtonnorms = snu.solve_steadystate_nse(**soldict) (convc_mat, rhs_con, rhsv_conbc) = snu.get_v_conv_conts(prev_v=lin_point, invinds=invinds, V=femp['V'], diribcs=femp['diribcs']) # infinite control horizon, steady target state cdatstr = get_datastr(time=None, meshp=N, nu=nu, Nts=None, data_prfx=data_prfx) try: Z = dou.load_npa(cdatstr + cntpstr + '__Z') print 'loaded ' + cdatstr + cntpstr + '__Z' except IOError: if use_ric_ini_nu is not None: cdatstr = get_datastr(nwtn=None, time=None, meshp=N, nu=use_ric_ini_nu, Nts=None, data_prfx=data_prfx) try: zini = dou.load_npa(ddir + cdatstr + cntpstr + '__Z') print 'Initialize Newton ADI by Z from ' + cdatstr except IOError: raise Warning('No data for initialization of ' ' Newton ADI -- need ' + cdatstr + '__Z') cdatstr = get_datastr(meshp=N, nu=nu, data_prfx=data_prfx) else: zini = None parnadi = pru.proj_alg_ric_newtonadi Z = parnadi(mmat=M, amat=-A - convc_mat, jmat=stokesmatsc['J'], bmat=tb_mat, wmat=trct_mat, z0=zini, nwtn_adi_dict=tip['nwtn_adi_dict'])['zfac'] dou.save_npa(Z, fstring=cdatstr + cntpstr + '__Z') print 'saved ' + cdatstr + cntpstr + '__Z' if tip['compress_z']: Zc = pru.compress_Zsvd(Z, thresh=tip['comprz_thresh'], k=tip['comprz_maxc']) Z = Zc fvnstst = rhs_con + rhsv_conbc + rhsd_stbc['fv'] + rhsd_vfrc['fvc'] # X = -ZZ.T mtxtb_stst = -pru.get_mTzzTtb(M.T, Z, tb_mat) mtxfv_stst = -pru.get_mTzzTtb(M.T, Z, fvnstst) fl = mc_mat.T * contp.ystarvec(0) wft = lau.solve_sadpnt_smw(amat=A.T + convc_mat.T, jmat=stokesmatsc['J'], rhsv=fl + mtxfv_stst, umat=mtxtb_stst, vmat=tb_mat.T)[:NV] auxstrg = cdatstr + cntpstr dou.save_npa(wft, fstring=cdatstr + cntpstr + '__w') dou.save_npa(mtxtb_stst, fstring=cdatstr + cntpstr + '__mtxtb') feedbackthroughdict = { None: dict(w=auxstrg + '__w', mtxtb=auxstrg + '__mtxtb') } cns = 0 soldict.update(data_prfx=data_prfx + '_cns{0}'.format(cns)) if linearized_nse: soldict.update(vel_pcrd_stps=0, vel_nwtn_stps=1, lin_vel_point={None: lin_point}) dictofvels = snu.\ solve_nse(return_dictofvelstrs=True, closed_loop=True, static_feedback=True, tb_mat=tb_mat, stokes_flow=stokes_flow, clearprvveldata=True, feedbackthroughdict=feedbackthroughdict, **soldict) else: # time dep closed loop cns_data_prfx = 'data/cnsvars' invd = init_nwtnstps_value_dict curnwtnsdict = invd(tmesh=tip['tmesh'], data_prfx=cns_data_prfx) # initialization: compute the forward solution if stokes_flow: dictofvels = None else: dictofvels = snu.solve_nse(return_dictofvelstrs=True, stokes_flow=stokes_flow, **soldict) # dbs.plot_vel_norms(tip['tmesh'], dictofvels) # function for the time depending parts # -- to be passed to the solver def get_tdpart(time=None, dictofvalues=None, feedback=False, V=None, invinds=None, diribcs=None, **kw): if stokes_flow: convc_mat = sps.csr_matrix((NV, NV)) rhs_con, rhsv_conbc = np.zeros((NV, 1)), np.zeros((NV, 1)) else: curvel = dou.load_npa(dictofvalues[time]) convc_mat, rhs_con, rhsv_conbc = \ snu.get_v_conv_conts(prev_v=curvel, invinds=invinds, V=V, diribcs=diribcs) return convc_mat, rhsv_conbc + rhs_con gttdprtargs = dict(dictofvalues=dictofvels, V=femp['V'], diribcs=femp['diribcs'], invinds=invinds) # old version rhs # ftilde = rhs_con + rhsv_conbc + rhsd_stbc['fv'] for cns in range(outernwtnstps): datastrdict.update(data_prfx=data_prfx + cntpstr + '_cns{0}'.format(cns)) soldict.update(data_prfx=data_prfx + cntpstr + '_cns{0}'.format(cns)) sfd = sdr.solve_flow_daeric feedbackthroughdict = \ sfd(mmat=M, amat=A, jmat=stokesmatsc['J'], bmat=b_mat, # cmat=ct_mat_reg.T, mcmat=mct_mat_reg.T, v_is_my=True, rmat=contp.alphau*u_masmat, vmat=y_masmat, rhsv=rhsd_stbc['fv'], gamma=contp.gamma, rhsp=None, tmesh=tip['tmesh'], ystarvec=contp.ystarvec, nwtn_adi_dict=tip['nwtn_adi_dict'], comprz_thresh=tip['comprz_thresh'], comprz_maxc=tip['comprz_maxc'], save_full_z=False, get_tdpart=get_tdpart, gttdprtargs=gttdprtargs, curnwtnsdict=curnwtnsdict, get_datastr=get_datastr, gtdtstrargs=datastrdict) # for t in tip['tmesh']: # feedbackthroughdict.keys(): # curw = dou.load_npa(feedbackthroughdict[t]['mtxtb']) # print cns, t, np.linalg.norm(curw) cdatstr = get_datastr(time='all', meshp=N, nu=nu, Nts=None, data_prfx=data_prfx) if linearized_nse: dictofvels = snu.\ solve_nse(return_dictofvelstrs=True, closed_loop=True, tb_mat=tb_mat, lin_vel_point=dictofvels, feedbackthroughdict=feedbackthroughdict, vel_nwtn_stps=1, vel_pcrd_stps=0, **soldict) else: dictofvels = snu.\ solve_nse(return_dictofvelstrs=True, closed_loop=True, tb_mat=tb_mat, stokes_flow=stokes_flow, feedbackthroughdict=feedbackthroughdict, vel_pcrd_stps=1, vel_nwtn_stps=2, **soldict) # for t in dictofvels.keys(): # curw = dou.load_npa(dictofvels[t]) # print cns, t, np.linalg.norm(curw) gttdprtargs.update(dictofvalues=dictofvels) else: # no control feedbackthroughdict = None tb_mat = None cdatstr = get_datastr(meshp=N, nu=nu, time='all', Nts=Nts, data_prfx=data_prfx) soldict.update(clearprvdata=True) dictofvels = snu.solve_nse(feedbackthroughdict=feedbackthroughdict, tb_mat=tb_mat, closed_loop=closed_loop, stokes_flow=stokes_flow, return_dictofvelstrs=True, static_feedback=stst_control, **soldict) (yscomplist, ystarlist) = dou.extract_output(dictofpaths=dictofvels, tmesh=tip['tmesh'], c_mat=c_mat, ystarvec=contp.ystarvec) save_output_json(yscomplist, tip['tmesh'].tolist(), ystar=ystarlist, fstring=cdatstr + cntpstr + '__sigout') costfunval = eval_costfunc(W=y_masmat, V=contp.gamma * y_masmat, R=None, tbmat=tb_mat, cmat=c_mat, ystar=contp.ystarvec, tmesh=tip['tmesh'], veldict=dictofvels, fbftdict=feedbackthroughdict) print 'Value of cost functional: ', costfunval costfunval = eval_costfunc(W=y_masmat, V=contp.gamma * y_masmat, R=None, tbmat=tb_mat, cmat=c_mat, ystar=contp.ystarvec, penau=False, tmesh=tip['tmesh'], veldict=dictofvels, fbftdict=feedbackthroughdict) print 'Value of cost functional not considering `u`: ', costfunval print 'dim of v :', femp['V'].dim() charlene = .15 if problemname == 'cylinderwake' else 1.0 print 'Re = charL / nu = {0}'.format(charlene / nu)
def solve_steadystate_nse(A=None, J=None, JT=None, M=None, fv=None, fp=None, V=None, Q=None, invinds=None, diribcs=None, dbcvals=None, dbcinds=None, diricontbcinds=None, diricontbcvals=None, diricontfuncs=None, return_vp=False, ppin=-1, return_nwtnupd_norms=False, N=None, nu=None, vel_pcrd_stps=10, vel_pcrd_tol=1e-4, vel_nwtn_stps=20, vel_nwtn_tol=5e-15, clearprvdata=False, useolddata=False, vel_start_nwtn=None, get_datastring=None, data_prfx='', paraviewoutput=False, save_data=True, save_intermediate_steps=False, vfileprfx='', pfileprfx='', verbose=True, **kw): """ Solution of the steady state nonlinear NSE Problem using Newton's scheme. If no starting value is provided, the iteration is started with the steady state Stokes solution. Parameters ---------- A : (N,N) sparse matrix stiffness matrix aka discrete Laplacian, note the sign! M : (N,N) sparse matrix mass matrix J : (M,N) sparse matrix discrete divergence operator JT : (N,M) sparse matrix, optional discrete gradient operator, set to J.T if not provided fv, fp : (N,1), (M,1) ndarrays right hand sides restricted via removing the boundary nodes in the momentum and the pressure freedom in the continuity equation ppin : {int, None}, optional which dof of `p` is used to pin the pressure, defaults to `-1` dbcinds: list, optional indices of the Dirichlet boundary conditions dbcvals: list, optional values of the Dirichlet boundary conditions (as listed in `dbcinds`) diricontbcinds: list, optional list of dirichlet indices that are to be controlled diricontbcvals: list, optional list of the vals corresponding to `diricontbcinds` diricontfuncs: list, optional list like `[ufunc]` where `ufunc: (t, v) -> u` where `u` is used to scale the corresponding `diricontbcvals` return_vp : boolean, optional whether to return also the pressure, defaults to `False` vel_pcrd_stps : int, optional Number of Picard iterations when computing a starting value for the Newton scheme, cf. Elman, Silvester, Wathen: *FEM and fast iterative solvers*, 2005, defaults to `100` vel_pcrd_tol : real, optional tolerance for the size of the Picard update, defaults to `1e-4` vel_nwtn_stps : int, optional Number of Newton iterations, defaults to `20` vel_nwtn_tol : real, optional tolerance for the size of the Newton update, defaults to `5e-15` Returns: --- vel_k : (N, 1) ndarray the velocity vector, if not `return_vp`, else (v, p) : tuple of the velocity and the pressure vector norm_nwtnupd_list : list, on demand list of the newton upd errors """ import sadptprj_riclyap_adi.lin_alg_utils as lau if get_datastring is None: get_datastring = get_datastr_snu if JT is None: JT = J.T NV = J.shape[1] # # Compute or load the uncontrolled steady state Navier-Stokes solution # norm_nwtnupd_list = [] # a dict to be passed to the get_datastring function datastrdict = dict(time=None, meshp=N, nu=nu, Nts=None, data_prfx=data_prfx) if clearprvdata: cdatstr = get_datastring(**datastrdict) for fname in glob.glob(cdatstr + '*__vel*'): os.remove(fname) if useolddata: try: cdatstr = get_datastring(**datastrdict) norm_nwtnupd = dou.load_npa(cdatstr + '__norm_nwtnupd') vel_k = dou.load_npa(cdatstr + '__vel') norm_nwtnupd_list.append(norm_nwtnupd) if verbose: print('found vel files') print('norm of last Nwtn update: {0}'.format(norm_nwtnupd)) print('... loaded from ' + cdatstr) if np.atleast_1d(norm_nwtnupd)[0] is None: norm_nwtnupd = None pass # nothing useful found elif norm_nwtnupd < vel_nwtn_tol: if not return_vp: return vel_k, norm_nwtnupd_list else: pfv = get_pfromv(v=vel_k[:NV, :], V=V, M=M, A=A, J=J, fv=fv, dbcinds=dbcinds, dbcvals=dbcvals, invinds=invinds, diribcs=diribcs) return (np.vstack([vel_k, pfv]), norm_nwtnupd_list) except IOError: if verbose: print('no old velocity data found') norm_nwtnupd = None else: # we start from scratch norm_nwtnupd = None if paraviewoutput: cdatstr = get_datastring(**datastrdict) vfile = dolfin.File(vfileprfx+'__steadystates.pvd') pfile = dolfin.File(pfileprfx+'__steadystates.pvd') prvoutdict = dict(V=V, Q=Q, vfile=vfile, pfile=pfile, invinds=invinds, diribcs=diribcs, ppin=ppin, dbcinds=dbcinds, dbcvals=dbcvals, vp=None, t=None, writeoutput=True) else: prvoutdict = dict(writeoutput=False) # save 'if statements' later NV = A.shape[0] if vel_start_nwtn is None: loccntbcinds, cntrlldbcvals, glbcntbcinds = [], [], [] if diricontbcinds is None or diricontbcinds == []: cmmat, camat, cj, cjt, cfv, cfp = M, A, J, JT, fv, fp cnv = NV dbcntinvinds = invinds else: def _localizecdbinds(cdbinds): """ find the local indices of the control dirichlet boundaries the given control dirichlet boundaries were indexed w.r.t. the full space `V`. Here, in the matrices, we have already resolved the constant Dirichlet bcs """ allinds = np.arange(V.dim()) redcdallinds = allinds[invinds] # now: find the positions of the control dbcs in the reduced # index vector lclinds = np.searchsorted(redcdallinds, cdbinds, side='left') return lclinds for k, cdbidbv in enumerate(diricontbcinds): ccntrlfunc = diricontfuncs[k] # no time at steady state, no starting value cntrlval = ccntrlfunc(None, None) localbcinds = (_localizecdbinds(cdbidbv)).tolist() loccntbcinds.extend(localbcinds) # adding the boundary inds glbcntbcinds.extend(cdbidbv) ccntrlldbcvals = [cntrlval*bcvl for bcvl in diricontbcvals[k]] # adding the scaled boundary values cntrlldbcvals.extend(ccntrlldbcvals) dbcntinvinds = np.setdiff1d(invinds, glbcntbcinds).astype(np.int32) matdict = dict(M=M, A=A, J=J, JT=JT, MP=None) cmmat, camat, cjt, cj, _, cfv, cfp, _ = dts.\ condense_sysmatsbybcs(matdict, dbcinds=loccntbcinds, dbcvals=cntrlldbcvals, mergerhs=True, rhsdict=dict(fv=fv, fp=fp), ret_unrolled=True) cnv = cmmat.shape[0] vp_stokes = lau.solve_sadpnt_smw(amat=camat, jmat=cj, jmatT=cjt, rhsv=cfv, rhsp=cfp) vp_stokes[cnv:] = -vp_stokes[cnv:] # pressure was flipped for symmetry # save the data cdatstr = get_datastring(**datastrdict) if save_data: dou.save_npa(vp_stokes[:cnv, ], fstring=cdatstr + '__vel') prvoutdict.update(dict(vp=vp_stokes, dbcinds=[dbcinds, glbcntbcinds], dbcvals=[dbcvals, cntrlldbcvals], invinds=dbcntinvinds)) dou.output_paraview(**prvoutdict) # Stokes solution as starting value vp_k = vp_stokes vel_k = vp_stokes[:cnv, ] else: vel_k = vel_start_nwtn matdict = dict(M=M, A=A, J=J, JT=JT, MP=None) rhsdict = dict(fv=fv, fp=fp) cndnsmtsdct = dict(dbcinds=loccntbcinds, mergerhs=True, ret_unrolled=True) # Picard iterations for a good starting value for Newton for k in range(vel_pcrd_stps): cntrlldbcvals = _unroll_cntrl_dbcs(diricontbcvals, diricontfuncs, time=None, vel=vel_k) (convc_mat, rhs_con, rhsv_conbc) = \ get_v_conv_conts(prev_v=vel_k, V=V, diribcs=diribcs, invinds=dbcntinvinds, dbcinds=[dbcinds, glbcntbcinds], dbcvals=[dbcvals, cntrlldbcvals], Picard=True) _, _, _, _, _, cfv, cfp, _ = dts.\ condense_sysmatsbybcs(matdict, dbcvals=cntrlldbcvals, rhsdict=rhsdict, **cndnsmtsdct) vp_k = lau.solve_sadpnt_smw(amat=camat+convc_mat, jmat=cj, jmatT=cjt, rhsv=cfv+rhsv_conbc, rhsp=cfp) # vp_k = lau.solve_sadpnt_smw(amat=A+convc_mat, jmat=J, jmatT=JT, # rhsv=fv+rhsv_conbc, # rhsp=fp) normpicupd = np.sqrt(m_innerproduct(cmmat, vel_k-vp_k[:cnv, ]))[0] if verbose: print('Picard iteration: {0} -- norm of update: {1}'. format(k+1, normpicupd)) vel_k = vp_k[:cnv, ] vp_k[cnv:] = -vp_k[cnv:] # pressure was flipped for symmetry if normpicupd < vel_pcrd_tol: break # Newton iteration for vel_newtk, k in enumerate(range(vel_nwtn_stps)): cdatstr = get_datastring(**datastrdict) cntrlldbcvals = _unroll_cntrl_dbcs(diricontbcvals, diricontfuncs, time=None, vel=vel_k) _, _, _, _, _, cfv, cfp, _ = dts.\ condense_sysmatsbybcs(matdict, dbcvals=cntrlldbcvals, rhsdict=rhsdict, **cndnsmtsdct) (convc_mat, rhs_con, rhsv_conbc) = \ get_v_conv_conts(prev_v=vel_k, V=V, diribcs=diribcs, invinds=dbcntinvinds, dbcinds=[dbcinds, glbcntbcinds], dbcvals=[dbcvals, cntrlldbcvals]) vp_k = lau.solve_sadpnt_smw(amat=camat+convc_mat, jmat=cj, jmatT=cjt, rhsv=cfv+rhs_con+rhsv_conbc, rhsp=cfp) norm_nwtnupd = np.sqrt(m_innerproduct(cmmat, vel_k - vp_k[:cnv, :]))[0] vel_k = vp_k[:cnv, ] vp_k[cnv:] = -vp_k[cnv:] # pressure was flipped for symmetry if verbose: print('Steady State NSE: Newton iteration: {0}'.format(vel_newtk) + '-- norm of update: {0}'.format(norm_nwtnupd)) if save_data: dou.save_npa(vel_k, fstring=cdatstr + '__vel') prvoutdict.update(dict(vp=vp_k, dbcvals=[dbcvals, cntrlldbcvals])) dou.output_paraview(**prvoutdict) if norm_nwtnupd < vel_nwtn_tol: break else: if vel_nwtn_stps == 0: print('No Newton steps = steady state probably not well converged') else: raise UserWarning('Steady State NSE: Newton has not converged') if save_data: dou.save_npa(norm_nwtnupd, cdatstr + '__norm_nwtnupd') prvoutdict.update(dict(vp=vp_k, dbcvals=[dbcvals, cntrlldbcvals])) dou.output_paraview(**prvoutdict) # savetomatlab = True # if savetomatlab: # export_mats_to_matlab(E=None, A=None, matfname='matexport') vwc = _attach_cntbcvals(vel_k.flatten(), globbcinvinds=dbcntinvinds, globbcinds=glbcntbcinds, dbcvals=cntrlldbcvals, invinds=invinds, NV=V.dim()) if return_vp: retthing = (vwc.reshape((NV, 1)), vp_k[cnv:, :]) else: retthing = vwc.reshape((NV, 1)) if return_nwtnupd_norms: return retthing, norm_nwtnupd_list else: return retthing
def optcon_nse(problemname='drivencavity', N=10, Nts=10, nu=1e-2, clearprvveldata=False, ini_vel_stokes=False, stst_control=False, closed_loop=True, outernwtnstps=1, t0=None, tE=None, use_ric_ini_nu=None, alphau=1e-9, gamma=1e-3, spec_tip_dict=None, nwtn_adi_dict=None, linearized_nse=False, stokes_flow=False, ystar=None): tip = time_int_params(Nts, t0=t0, tE=tE) if spec_tip_dict is not None: tip.update(spec_tip_dict) if nwtn_adi_dict is not None: tip['nwtn_adi_dict'] = nwtn_adi_dict problemdict = dict(drivencavity=dnsps.drivcav_fems, cylinderwake=dnsps.cyl_fems) problemfem = problemdict[problemname] femp = problemfem(N) # output ddir = 'data/' try: os.chdir(ddir) except OSError: raise Warning('need "' + ddir + '" subdir for storing the data') os.chdir('..') if linearized_nse and not outernwtnstps == 1: raise Warning('Linearized problem can have only one Newton step') if closed_loop: if stst_control: data_prfx = ddir + 'stst_' + problemname + '__' else: data_prfx = ddir + 'tdst_' + problemname + '__' else: data_prfx = ddir + problemname + '__' if stokes_flow: data_prfx = data_prfx + 'stokes__' # specify in what spatial direction Bu changes. The remaining is constant if problemname == 'drivencavity': uspacedep = 0 elif problemname == 'cylinderwake': uspacedep = 1 stokesmats = dts.get_stokessysmats(femp['V'], femp['Q'], nu) rhsd_vf = dts.setget_rhs(femp['V'], femp['Q'], femp['fv'], femp['fp'], t=0) # remove the freedom in the pressure stokesmats['J'] = stokesmats['J'][:-1, :][:, :] stokesmats['JT'] = stokesmats['JT'][:, :-1][:, :] rhsd_vf['fp'] = rhsd_vf['fp'][:-1, :] # reduce the matrices by resolving the BCs (stokesmatsc, rhsd_stbc, invinds, bcinds, bcvals) = dts.condense_sysmatsbybcs(stokesmats, femp['diribcs']) print 'Dimension of the div matrix: ', stokesmatsc['J'].shape # pressure freedom and dirichlet reduced rhs rhsd_vfrc = dict(fpr=rhsd_vf['fp'], fvc=rhsd_vf['fv'][invinds, ]) # add the info on boundary and inner nodes bcdata = {'bcinds': bcinds, 'bcvals': bcvals, 'invinds': invinds} femp.update(bcdata) # casting some parameters NV = len(femp['invinds']) soldict = stokesmatsc # containing A, J, JT soldict.update(femp) # adding V, Q, invinds, diribcs # soldict.update(rhsd_vfrc) # adding fvc, fpr soldict.update(fv=rhsd_stbc['fv']+rhsd_vfrc['fvc'], fp=rhsd_stbc['fp']+rhsd_vfrc['fpr'], N=N, nu=nu, trange=tip['tmesh'], get_datastring=get_datastr, data_prfx=data_prfx, clearprvdata=clearprvveldata, paraviewoutput=tip['ParaviewOutput'], vfileprfx=tip['proutdir']+'vel_', pfileprfx=tip['proutdir']+'p_') # # Prepare for control # contp = ContParams(femp['odcoo'], ystar=ystar, alphau=alphau, gamma=gamma) # casting some parameters NY, NU = contp.NY, contp.NU contsetupstr = problemname + '__NV{0}NU{1}NY{2}'.format(NV, NU, NY) # get the control and observation operators try: b_mat = dou.load_spa(ddir + contsetupstr + '__b_mat') u_masmat = dou.load_spa(ddir + contsetupstr + '__u_masmat') print 'loaded `b_mat`' except IOError: print 'computing `b_mat`...' b_mat, u_masmat = cou.get_inp_opa(cdcoo=femp['cdcoo'], V=femp['V'], NU=NU, xcomp=uspacedep) dou.save_spa(b_mat, ddir + contsetupstr + '__b_mat') dou.save_spa(u_masmat, ddir + contsetupstr + '__u_masmat') try: mc_mat = dou.load_spa(ddir + contsetupstr + '__mc_mat') y_masmat = dou.load_spa(ddir + contsetupstr + '__y_masmat') print 'loaded `c_mat`' except IOError: print 'computing `c_mat`...' mc_mat, y_masmat = cou.get_mout_opa(odcoo=femp['odcoo'], V=femp['V'], NY=NY) dou.save_spa(mc_mat, ddir + contsetupstr + '__mc_mat') dou.save_spa(y_masmat, ddir + contsetupstr + '__y_masmat') # restrict the operators to the inner nodes mc_mat = mc_mat[:, invinds][:, :] b_mat = b_mat[invinds, :][:, :] # for further use: c_mat = lau.apply_massinv(y_masmat, mc_mat, output='sparse') if contp.ystarx is None: c_mat = c_mat[NY:, :][:, :] # TODO: Do this right mc_mat = mc_mat[NY:, :][:, :] # TODO: Do this right y_masmat = y_masmat[:NY, :][:, :NY] # TODO: Do this right mct_mat_reg = lau.app_prj_via_sadpnt(amat=stokesmatsc['M'], jmat=stokesmatsc['J'], rhsv=mc_mat.T, transposedprj=True) # set the weighing matrices contp.R = contp.alphau * u_masmat # # solve the differential-alg. Riccati eqn for the feedback gain X # via computing factors Z, such that X = -Z*Z.T # # at the same time we solve for the affine-linear correction w # # tilde B = BR^{-1/2} tb_mat = lau.apply_invsqrt_fromright(contp.R, b_mat, output='sparse') # tb_dense = np.array(tb_mat.todense()) trct_mat = lau.apply_invsqrt_fromright(y_masmat, mct_mat_reg, output='dense') if closed_loop: cntpstr = 'NV{3}NY{0}NU{1}alphau{2}gamma{4}'.\ format(contp.NU, contp.NY, contp.alphau, NV, contp.gamma) else: cntpstr = '' # we gonna use this quite often M, A = stokesmatsc['M'], stokesmatsc['A'] datastrdict = dict(time=None, meshp=N, nu=nu, Nts=Nts, data_prfx=data_prfx) # compute the uncontrolled steady state (Navier-)Stokes solution # as initial value if ini_vel_stokes: # compute the uncontrolled steady state Stokes solution ini_vel, newtonnorms = snu.solve_steadystate_nse(vel_nwtn_stps=0, vel_pcrd_stps=0, **soldict) soldict.update(dict(iniv=ini_vel)) else: ini_vel, newtonnorms = snu.solve_steadystate_nse(**soldict) soldict.update(dict(iniv=ini_vel)) if closed_loop: if stst_control: if stokes_flow: convc_mat = sps.csr_matrix((NV, NV)) rhs_con, rhsv_conbc = np.zeros((NV, 1)), np.zeros((NV, 1)) lin_point = None else: lin_point, newtonnorms = snu.solve_steadystate_nse(**soldict) (convc_mat, rhs_con, rhsv_conbc) = snu.get_v_conv_conts(prev_v=lin_point, invinds=invinds, V=femp['V'], diribcs=femp['diribcs']) # infinite control horizon, steady target state cdatstr = get_datastr(time=None, meshp=N, nu=nu, Nts=None, data_prfx=data_prfx) try: Z = dou.load_npa(cdatstr + cntpstr + '__Z') print 'loaded ' + cdatstr + cntpstr + '__Z' except IOError: if use_ric_ini_nu is not None: cdatstr = get_datastr(nwtn=None, time=None, meshp=N, nu=use_ric_ini_nu, Nts=None, data_prfx=data_prfx) try: zini = dou.load_npa(ddir + cdatstr + cntpstr + '__Z') print 'Initialize Newton ADI by Z from ' + cdatstr except IOError: raise Warning('No data for initialization of ' ' Newton ADI -- need ' + cdatstr + '__Z') cdatstr = get_datastr(meshp=N, nu=nu, data_prfx=data_prfx) else: zini = None parnadi = pru.proj_alg_ric_newtonadi Z = parnadi(mmat=M, amat=-A-convc_mat, jmat=stokesmatsc['J'], bmat=tb_mat, wmat=trct_mat, z0=zini, nwtn_adi_dict=tip['nwtn_adi_dict'])['zfac'] dou.save_npa(Z, fstring=cdatstr + cntpstr + '__Z') print 'saved ' + cdatstr + cntpstr + '__Z' if tip['compress_z']: Zc = pru.compress_Zsvd(Z, thresh=tip['comprz_thresh'], k=tip['comprz_maxc']) Z = Zc fvnstst = rhs_con + rhsv_conbc + rhsd_stbc['fv'] + rhsd_vfrc['fvc'] # X = -ZZ.T mtxtb_stst = -pru.get_mTzzTtb(M.T, Z, tb_mat) mtxfv_stst = -pru.get_mTzzTtb(M.T, Z, fvnstst) fl = mc_mat.T * contp.ystarvec(0) wft = lau.solve_sadpnt_smw(amat=A.T+convc_mat.T, jmat=stokesmatsc['J'], rhsv=fl+mtxfv_stst, umat=mtxtb_stst, vmat=tb_mat.T)[:NV] auxstrg = cdatstr + cntpstr dou.save_npa(wft, fstring=cdatstr + cntpstr + '__w') dou.save_npa(mtxtb_stst, fstring=cdatstr + cntpstr + '__mtxtb') feedbackthroughdict = {None: dict(w=auxstrg + '__w', mtxtb=auxstrg + '__mtxtb')} cns = 0 soldict.update(data_prfx=data_prfx+'_cns{0}'.format(cns)) if linearized_nse: soldict.update(vel_pcrd_stps=0, vel_nwtn_stps=1, lin_vel_point={None: lin_point}) dictofvels = snu.\ solve_nse(return_dictofvelstrs=True, closed_loop=True, static_feedback=True, tb_mat=tb_mat, stokes_flow=stokes_flow, clearprvveldata=True, feedbackthroughdict=feedbackthroughdict, **soldict) else: # time dep closed loop cns_data_prfx = 'data/cnsvars' invd = init_nwtnstps_value_dict curnwtnsdict = invd(tmesh=tip['tmesh'], data_prfx=cns_data_prfx) # initialization: compute the forward solution if stokes_flow: dictofvels = None else: dictofvels = snu.solve_nse(return_dictofvelstrs=True, stokes_flow=stokes_flow, **soldict) # dbs.plot_vel_norms(tip['tmesh'], dictofvels) # function for the time depending parts # -- to be passed to the solver def get_tdpart(time=None, dictofvalues=None, feedback=False, V=None, invinds=None, diribcs=None, **kw): if stokes_flow: convc_mat = sps.csr_matrix((NV, NV)) rhs_con, rhsv_conbc = np.zeros((NV, 1)), np.zeros((NV, 1)) else: curvel = dou.load_npa(dictofvalues[time]) convc_mat, rhs_con, rhsv_conbc = \ snu.get_v_conv_conts(prev_v=curvel, invinds=invinds, V=V, diribcs=diribcs) return convc_mat, rhsv_conbc+rhs_con gttdprtargs = dict(dictofvalues=dictofvels, V=femp['V'], diribcs=femp['diribcs'], invinds=invinds) # old version rhs # ftilde = rhs_con + rhsv_conbc + rhsd_stbc['fv'] for cns in range(outernwtnstps): datastrdict.update(data_prfx=data_prfx+cntpstr+'_cns{0}'. format(cns)) soldict.update(data_prfx=data_prfx+cntpstr+'_cns{0}'. format(cns)) sfd = sdr.solve_flow_daeric feedbackthroughdict = \ sfd(mmat=M, amat=A, jmat=stokesmatsc['J'], bmat=b_mat, # cmat=ct_mat_reg.T, mcmat=mct_mat_reg.T, v_is_my=True, rmat=contp.alphau*u_masmat, vmat=y_masmat, rhsv=rhsd_stbc['fv'], gamma=contp.gamma, rhsp=None, tmesh=tip['tmesh'], ystarvec=contp.ystarvec, nwtn_adi_dict=tip['nwtn_adi_dict'], comprz_thresh=tip['comprz_thresh'], comprz_maxc=tip['comprz_maxc'], save_full_z=False, get_tdpart=get_tdpart, gttdprtargs=gttdprtargs, curnwtnsdict=curnwtnsdict, get_datastr=get_datastr, gtdtstrargs=datastrdict) # for t in tip['tmesh']: # feedbackthroughdict.keys(): # curw = dou.load_npa(feedbackthroughdict[t]['mtxtb']) # print cns, t, np.linalg.norm(curw) cdatstr = get_datastr(time='all', meshp=N, nu=nu, Nts=None, data_prfx=data_prfx) if linearized_nse: dictofvels = snu.\ solve_nse(return_dictofvelstrs=True, closed_loop=True, tb_mat=tb_mat, lin_vel_point=dictofvels, feedbackthroughdict=feedbackthroughdict, vel_nwtn_stps=1, vel_pcrd_stps=0, **soldict) else: dictofvels = snu.\ solve_nse(return_dictofvelstrs=True, closed_loop=True, tb_mat=tb_mat, stokes_flow=stokes_flow, feedbackthroughdict=feedbackthroughdict, vel_pcrd_stps=1, vel_nwtn_stps=2, **soldict) # for t in dictofvels.keys(): # curw = dou.load_npa(dictofvels[t]) # print cns, t, np.linalg.norm(curw) gttdprtargs.update(dictofvalues=dictofvels) else: # no control feedbackthroughdict = None tb_mat = None cdatstr = get_datastr(meshp=N, nu=nu, time='all', Nts=Nts, data_prfx=data_prfx) soldict.update(clearprvdata=True) dictofvels = snu.solve_nse(feedbackthroughdict=feedbackthroughdict, tb_mat=tb_mat, closed_loop=closed_loop, stokes_flow=stokes_flow, return_dictofvelstrs=True, static_feedback=stst_control, **soldict) (yscomplist, ystarlist) = dou.extract_output(dictofpaths=dictofvels, tmesh=tip['tmesh'], c_mat=c_mat, ystarvec=contp.ystarvec) save_output_json(yscomplist, tip['tmesh'].tolist(), ystar=ystarlist, fstring=cdatstr + cntpstr + '__sigout') costfunval = eval_costfunc(W=y_masmat, V=contp.gamma*y_masmat, R=None, tbmat=tb_mat, cmat=c_mat, ystar=contp.ystarvec, tmesh=tip['tmesh'], veldict=dictofvels, fbftdict=feedbackthroughdict) print 'Value of cost functional: ', costfunval costfunval = eval_costfunc(W=y_masmat, V=contp.gamma*y_masmat, R=None, tbmat=tb_mat, cmat=c_mat, ystar=contp.ystarvec, penau=False, tmesh=tip['tmesh'], veldict=dictofvels, fbftdict=feedbackthroughdict) print 'Value of cost functional not considering `u`: ', costfunval print 'dim of v :', femp['V'].dim() charlene = .15 if problemname == 'cylinderwake' else 1.0 print 'Re = charL / nu = {0}'.format(charlene/nu)
def solve_nse(A=None, M=None, J=None, JT=None, fv=None, fp=None, fvc=None, fpc=None, # TODO: this is to catch deprecated calls fv_tmdp=None, fv_tmdp_params={}, fv_tmdp_memory=None, iniv=None, lin_vel_point=None, stokes_flow=False, trange=None, t0=None, tE=None, Nts=None, V=None, Q=None, invinds=None, diribcs=None, output_includes_bcs=False, N=None, nu=None, ppin=-1, closed_loop=False, static_feedback=False, feedbackthroughdict=None, return_vp=False, tb_mat=None, c_mat=None, vel_nwtn_stps=20, vel_nwtn_tol=5e-15, vel_pcrd_stps=4, krylov=None, krpslvprms={}, krplsprms={}, clearprvdata=False, get_datastring=None, data_prfx='', paraviewoutput=False, vfileprfx='', pfileprfx='', return_dictofvelstrs=False, return_dictofpstrs=False, dictkeysstr=False, comp_nonl_semexp=False, return_as_list=False, start_ssstokes=False, **kw): """ solution of the time-dependent nonlinear Navier-Stokes equation .. math:: M\\dot v + Av + N(v)v + J^Tp = f \n Jv =g using a Newton scheme in function space, i.e. given :math:`v_k`, we solve for the update like .. math:: M\\dot v + Av + N(v_k)v + N(v)v_k + J^Tp = N(v_k)v_k + f, and trapezoidal rule in time. To solve an *Oseen* system (linearization about a steady state) or a *Stokes* system, set the number of Newton steps to one and provide a linearization point and an initial value. Parameters ---------- lin_vel_point : dictionary, optional contains the linearization point for the first Newton iteration * Steady State: {{`None`: 'path_to_nparray'}, {'None': nparray}} * Newton: {`t`: 'path_to_nparray'} defaults to `None` dictkeysstr : boolean, optional whether the `keys` of the result dictionaries are strings instead \ of floats, defaults to `False` fv_tmdp : callable f(t, v, dict), optional time-dependent part of the right-hand side, set to zero if None fv_tmdp_params : dictionary, optional dictionary of parameters to be passed to `fv_tmdp`, defaults to `{}` fv_tmdp_memory : dictionary, optional memory of the function output_includes_bcs : boolean, optional whether append the boundary nodes to the computed and stored \ velocities, defaults to `False` krylov : {None, 'gmres'}, optional whether or not to use an iterative solver, defaults to `None` krpslvprms : dictionary, optional to specify parameters of the linear solver for use in Krypy, e.g., * initial guess * tolerance * number of iterations defaults to `None` krplsprms : dictionary, optional parameters to define the linear system like * preconditioner ppin : {int, None}, optional which dof of `p` is used to pin the pressure, defaults to `-1` stokes_flow : boolean, optional whether to consider the Stokes linearization, defaults to `False` start_ssstokes : boolean, optional for your convenience, compute and use the steady state stokes solution as initial value, defaults to `False` Returns ------- dictofvelstrs : dictionary, on demand dictionary with time `t` as keys and path to velocity files as values dictofpstrs : dictionary, on demand dictionary with time `t` as keys and path to pressure files as values vellist : list, on demand list of the velocity solutions """ import sadptprj_riclyap_adi.lin_alg_utils as lau if fvc is not None or fpc is not None: # TODO: this is for catching calls raise UserWarning('deprecated use of `rhsd_vfrc`, use only `fv`, `fp`') if get_datastring is None: get_datastring = get_datastr_snu if paraviewoutput: prvoutdict = dict(V=V, Q=Q, invinds=invinds, diribcs=diribcs, vp=None, t=None, writeoutput=True, ppin=ppin) else: prvoutdict = dict(writeoutput=False) # save 'if statements' here if trange is None: trange = np.linspace(t0, tE, Nts+1) if comp_nonl_semexp and lin_vel_point is not None: raise UserWarning('I am not sure what you want! ' + 'set either `lin_vel_point=None` ' + 'or `comp_nonl_semexp=False`! \n' + 'as it is I will compute a linear case') if return_dictofpstrs: gpfvd = dict(V=V, M=M, A=A, J=J, fv=fv, fp=fp, diribcs=diribcs, invinds=invinds) NV, NP = A.shape[0], J.shape[0] if fv_tmdp is None: def fv_tmdp(time=None, curvel=None, **kw): return np.zeros((NV, 1)), None if iniv is None: if start_ssstokes: # Stokes solution as starting value (fv_tmdp_cont, fv_tmdp_memory) = fv_tmdp(time=0, **fv_tmdp_params) vp_stokes =\ lau.solve_sadpnt_smw(amat=A, jmat=J, jmatT=JT, rhsv=fv + fv_tmdp_cont, krylov=krylov, krpslvprms=krpslvprms, krplsprms=krplsprms, rhsp=fp) iniv = vp_stokes[:NV] else: raise ValueError('No initial value given') datastrdict = dict(time=None, meshp=N, nu=nu, Nts=trange.size-1, data_prfx=data_prfx) if return_as_list: clearprvdata = True # we want the results at hand if clearprvdata: datastrdict['time'] = '*' cdatstr = get_datastring(**datastrdict) for fname in glob.glob(cdatstr + '__vel*'): os.remove(fname) for fname in glob.glob(cdatstr + '__p*'): os.remove(fname) def _atdct(cdict, t, thing): if dictkeysstr: cdict.update({'{0}'.format(t): thing}) else: cdict.update({t: thing}) def _gfdct(cdict, t): if dictkeysstr: return cdict['{0}'.format(t)] else: return cdict[t] if stokes_flow: vel_nwtn_stps = 1 vel_pcrd_stps = 0 print 'Stokes Flow!' elif lin_vel_point is None: comp_nonl_semexp_inig = True if not comp_nonl_semexp: print('No linearization point given - explicit' + ' treatment of the nonlinearity in the first Iteration') else: cur_linvel_point = lin_vel_point comp_nonl_semexp_inig = False newtk, norm_nwtnupd, norm_nwtnupd_list = 0, 1, [] # check for previously computed velocities if lin_vel_point is None and not stokes_flow: try: datastrdict.update(dict(time=trange[-1])) cdatstr = get_datastring(**datastrdict) norm_nwtnupd = dou.load_npa(cdatstr + '__norm_nwtnupd') v_old = dou.load_npa(cdatstr + '__vel') norm_nwtnupd_list.append(norm_nwtnupd) print 'found vel files' print 'norm of last Nwtn update: {0}'.format(norm_nwtnupd) if norm_nwtnupd < vel_nwtn_tol and not return_dictofvelstrs: return elif norm_nwtnupd < vel_nwtn_tol: datastrdict.update(dict(time=trange[0])) dictofvelstrs = {} _atdct(dictofvelstrs, trange[0], cdatstr + '__vel') if return_dictofpstrs: try: p_old = dou.load_npa(cdatstr + '__p') dictofpstrs = {} _atdct(dictofpstrs, trange[0], cdatstr+'__p') except: p_old = get_pfromv(v=v_old, **gpfvd) dou.save_npa(p_old, fstring=cdatstr + '__p') _atdct(dictofpstrs, trange[0], cdatstr+'__p') for t in trange[1:]: # test if the vels are there v_old = dou.load_npa(cdatstr + '__vel') # update the dict datastrdict.update(dict(time=t)) cdatstr = get_datastring(**datastrdict) _atdct(dictofvelstrs, t, cdatstr + '__vel') try: p_old = dou.load_npa(cdatstr + '__p') _atdct(dictofpstrs, t, cdatstr + '__p') except: p_old = get_pfromv(v=v_old, **gpfvd) dou.save_npa(p_old, fstring=cdatstr + '__p') _atdct(dictofpstrs, t, cdatstr + '__p') if return_dictofpstrs: return dictofvelstrs, dictofpstrs else: return dictofvelstrs comp_nonl_semexp = False except IOError: norm_nwtnupd = 2 print 'no old velocity data found' def _append_bcs_ornot(vvec): if output_includes_bcs: # make the switch here for better readibility vwbcs = dts.append_bcs_vec(vvec, vdim=V.dim(), invinds=invinds, diribcs=diribcs) return vwbcs else: return vvec def _get_mats_rhs_ts(mmat=None, dt=None, var_c=None, coeffmat_c=None, coeffmat_n=None, fv_c=None, fv_n=None, umat_c=None, vmat_c=None, umat_n=None, vmat_n=None, impeul=False): """ to be tweaked for different int schemes """ solvmat = M + 0.5*dt*coeffmat_n rhs = M*var_c + 0.5*dt*(fv_n + fv_c - coeffmat_c*var_c) if umat_n is not None: matvec = lau.mm_dnssps umat = 0.5*dt*umat_n vmat = vmat_n # TODO: do we really need a PLUS here??' rhs = rhs + 0.5*dt*matvec(umat_c, matvec(vmat_c, var_c)) else: umat, vmat = umat_n, vmat_n return solvmat, rhs, umat, vmat v_old = iniv # start vector for time integration in every Newtonit datastrdict['time'] = trange[0] cdatstr = get_datastring(**datastrdict) dou.save_npa(_append_bcs_ornot(v_old), fstring=cdatstr + '__vel') dictofvelstrs = {} _atdct(dictofvelstrs, trange[0], cdatstr + '__vel') if return_dictofpstrs: p_old = get_pfromv(v=v_old, **gpfvd) dou.save_npa(p_old, fstring=cdatstr + '__p') dictofpstrs = {} _atdct(dictofpstrs, trange[0], cdatstr+'__p') if return_as_list: vellist = [] vellist.append(_append_bcs_ornot(v_old)) while (newtk < vel_nwtn_stps and norm_nwtnupd > vel_nwtn_tol): if stokes_flow: newtk = vel_nwtn_stps elif comp_nonl_semexp_inig and not comp_nonl_semexp: pcrd_anyone = False print 'explicit treatment of nonl. for initial guess' elif vel_pcrd_stps > 0 and not comp_nonl_semexp: vel_pcrd_stps -= 1 pcrd_anyone = True print 'Picard iterations for initial value -- {0} left'.\ format(vel_pcrd_stps) elif comp_nonl_semexp: pcrd_anyone = False newtk = vel_nwtn_stps print 'No Newton iterations - explicit treatment of the nonlin.' else: pcrd_anyone = False newtk += 1 print 'Computing Newton Iteration {0}'.format(newtk) v_old = iniv # start vector for time integration in every Newtonit try: if krpslvprms['krylovini'] == 'old': vp_old = np.vstack([v_old, np.zeros((NP, 1))]) elif krpslvprms['krylovini'] == 'upd': vp_old = np.vstack([v_old, np.zeros((NP, 1))]) vp_new = vp_old cts_old = trange[1] - trange[0] except (TypeError, KeyError): pass # no inival for krylov solver required vfile = dolfin.File(vfileprfx+'__timestep.pvd') pfile = dolfin.File(pfileprfx+'__timestep.pvd') prvoutdict.update(dict(vp=None, vc=iniv, t=trange[0], pfile=pfile, vfile=vfile)) dou.output_paraview(**prvoutdict) # ## current values_c for application of trap rule if stokes_flow: convc_mat_c = sps.csr_matrix((NV, NV)) rhs_con_c, rhsv_conbc_c = np.zeros((NV, 1)), np.zeros((NV, 1)) else: if comp_nonl_semexp or comp_nonl_semexp_inig: prev_v = v_old else: try: prev_v = dou.load_npa(_gfdct(cur_linvel_point, trange[0])) except KeyError: try: prev_v = dou.load_npa(_gfdct(cur_linvel_point, None)) except TypeError: prev_v = cur_linvel_point[None] convc_mat_c, rhs_con_c, rhsv_conbc_c = \ get_v_conv_conts(prev_v=iniv, invinds=invinds, V=V, diribcs=diribcs, Picard=pcrd_anyone) (fv_tmdp_cont, fv_tmdp_memory) = fv_tmdp(time=0, curvel=v_old, memory=fv_tmdp_memory, **fv_tmdp_params) fvn_c = fv + rhsv_conbc_c + rhs_con_c + fv_tmdp_cont if closed_loop: if static_feedback: mtxtb_c = dou.load_npa(feedbackthroughdict[None]['mtxtb']) w_c = dou.load_npa(feedbackthroughdict[None]['w']) # print '\nnorm of feedback: ', np.linalg.norm(mtxtb_c) else: mtxtb_c = dou.load_npa(feedbackthroughdict[0]['mtxtb']) w_c = dou.load_npa(feedbackthroughdict[0]['w']) fvn_c = fvn_c + tb_mat * (tb_mat.T * w_c) vmat_c = mtxtb_c.T try: umat_c = np.array(tb_mat.todense()) except AttributeError: umat_c = tb_mat else: vmat_c = None umat_c = None norm_nwtnupd = 0 print 'time to go', for tk, t in enumerate(trange[1:]): cts = t - trange[tk] datastrdict.update(dict(time=t)) cdatstr = get_datastring(**datastrdict) sys.stdout.write("\rEnd: {1} -- now: {0:f}".format(t, trange[-1])) sys.stdout.flush() # prv_datastrdict = copy.deepcopy(datastrdict) # coeffs and rhs at next time instance if stokes_flow: convc_mat_n = sps.csr_matrix((NV, NV)) rhs_con_n, rhsv_conbc_n = np.zeros((NV, 1)), np.zeros((NV, 1)) else: if comp_nonl_semexp or comp_nonl_semexp_inig: prev_v = v_old else: try: prev_v = dou.load_npa(_gfdct(cur_linvel_point, t)) except KeyError: try: prev_v = dou.load_npa(_gfdct(cur_linvel_point, None)) except TypeError: prev_v = cur_linvel_point[None] convc_mat_n, rhs_con_n, rhsv_conbc_n = \ get_v_conv_conts(prev_v=prev_v, invinds=invinds, V=V, diribcs=diribcs, Picard=pcrd_anyone) (fv_tmdp_cont, fv_tmdp_memory) = fv_tmdp(time=t, curvel=v_old, memory=fv_tmdp_memory, **fv_tmdp_params) fvn_n = fv + rhsv_conbc_n + rhs_con_n + fv_tmdp_cont if closed_loop: if static_feedback: mtxtb_n = dou.load_npa(feedbackthroughdict[None]['mtxtb']) w_n = dou.load_npa(feedbackthroughdict[None]['w']) # fb = np.dot(tb_mat*mtxtb_n.T, v_old) # print '\nnorm of feedback: ', np.linalg.norm(fb) # print '\nnorm of v_old: ', np.linalg.norm(v_old) # print '\nnorm of feedthrough: ', np.linalg.norm(next_w) else: mtxtb_n = dou.load_npa(feedbackthroughdict[t]['mtxtb']) w_n = dou.load_npa(feedbackthroughdict[t]['w']) fvn_n = fvn_n + tb_mat * (tb_mat.T * w_n) vmat_n = mtxtb_n.T try: umat_n = np.array(tb_mat.todense()) except AttributeError: umat_n = tb_mat else: vmat_n = None umat_n = None (solvmat, rhsv, umat, vmat) = _get_mats_rhs_ts(mmat=M, dt=cts, var_c=v_old, coeffmat_c=A + convc_mat_c, coeffmat_n=A + convc_mat_n, fv_c=fvn_c, fv_n=fvn_n, umat_c=umat_c, vmat_c=vmat_c, umat_n=umat_n, vmat_n=vmat_n) try: if krpslvprms['krylovini'] == 'old': krpslvprms['x0'] = vp_old elif krpslvprms['krylovini'] == 'upd': vp_oldold = vp_old vp_old = vp_new krpslvprms['x0'] = vp_old + \ cts*(vp_old - vp_oldold)/cts_old cts_old = cts except (TypeError, KeyError): pass # no inival for krylov solver required vp_new = lau.solve_sadpnt_smw(amat=solvmat, jmat=J, jmatT=JT, rhsv=rhsv, rhsp=fp, krylov=krylov, krpslvprms=krpslvprms, krplsprms=krplsprms, umat=umat, vmat=vmat) v_old = vp_new[:NV, ] (umat_c, vmat_c, fvn_c, convc_mat_c) = umat_n, vmat_n, fvn_n, convc_mat_n dou.save_npa(_append_bcs_ornot(v_old), fstring=cdatstr + '__vel') _atdct(dictofvelstrs, t, cdatstr + '__vel') if return_dictofpstrs: p_new = -1/cts*vp_new[NV:, ] # p was flipped and scaled for symmetry dou.save_npa(p_new, fstring=cdatstr + '__p') _atdct(dictofpstrs, t, cdatstr + '__p') if return_as_list: vellist.append(_append_bcs_ornot(v_old)) prvoutdict.update(dict(vp=vp_new, t=t)) dou.output_paraview(**prvoutdict) # integrate the Newton error if stokes_flow or comp_nonl_semexp or comp_nonl_semexp_inig: norm_nwtnupd = [None] else: if len(prev_v) > len(invinds): prev_v = prev_v[invinds, :] norm_nwtnupd += cts * m_innerproduct(M, v_old - prev_v) dou.save_npa(norm_nwtnupd, cdatstr + '__norm_nwtnupd') norm_nwtnupd_list.append(norm_nwtnupd[0]) print '\nnorm of current Newton update: {}'.format(norm_nwtnupd) comp_nonl_semexp = False comp_nonl_semexp_inig = False cur_linvel_point = dictofvelstrs if return_dictofvelstrs: if return_dictofpstrs: return dictofvelstrs, dictofpstrs else: return dictofvelstrs elif return_as_list: return vellist else: return
def solve_steadystate_nse(A=None, J=None, JT=None, M=None, fv=None, fp=None, V=None, Q=None, invinds=None, diribcs=None, return_vp=False, ppin=-1, N=None, nu=None, vel_pcrd_stps=10, vel_pcrd_tol=1e-4, vel_nwtn_stps=20, vel_nwtn_tol=5e-15, clearprvdata=False, vel_start_nwtn=None, get_datastring=None, data_prfx='', paraviewoutput=False, save_intermediate_steps=False, vfileprfx='', pfileprfx='', **kw): """ Solution of the steady state nonlinear NSE Problem using Newton's scheme. If no starting value is provided, the iteration is started with the steady state Stokes solution. Parameters ---------- A : (N,N) sparse matrix stiffness matrix aka discrete Laplacian, note the sign! M : (N,N) sparse matrix mass matrix J : (M,N) sparse matrix discrete divergence operator JT : (N,M) sparse matrix, optional discrete gradient operator, set to J.T if not provided fv, fp : (N,1), (M,1) ndarrays right hand sides restricted via removing the boundary nodes in the momentum and the pressure freedom in the continuity equation ppin : {int, None}, optional which dof of `p` is used to pin the pressure, defaults to `-1` return_vp : boolean, optional whether to return also the pressure, defaults to `False` vel_pcrd_stps : int, optional Number of Picard iterations when computing a starting value for the Newton scheme, cf. Elman, Silvester, Wathen: *FEM and fast iterative solvers*, 2005, defaults to `100` vel_pcrd_tol : real, optional tolerance for the size of the Picard update, defaults to `1e-4` vel_nwtn_stps : int, optional Number of Newton iterations, defaults to `20` vel_nwtn_tol : real, optional tolerance for the size of the Newton update, defaults to `5e-15` """ import sadptprj_riclyap_adi.lin_alg_utils as lau if get_datastring is None: get_datastring = get_datastr_snu if JT is None: JT = J.T NV = J.shape[1] # # Compute or load the uncontrolled steady state Navier-Stokes solution # norm_nwtnupd_list = [] vel_newtk, norm_nwtnupd = 0, 1 # a dict to be passed to the get_datastring function datastrdict = dict(time=None, meshp=N, nu=nu, Nts=None, data_prfx=data_prfx) if clearprvdata: cdatstr = get_datastring(**datastrdict) for fname in glob.glob(cdatstr + '*__vel*'): os.remove(fname) try: cdatstr = get_datastring(**datastrdict) norm_nwtnupd = dou.load_npa(cdatstr + '__norm_nwtnupd') vel_k = dou.load_npa(cdatstr + '__vel') norm_nwtnupd_list.append(norm_nwtnupd) print 'found vel files' print 'norm of last Nwtn update: {0}'.format(norm_nwtnupd) if norm_nwtnupd < vel_nwtn_tol: if not return_vp: return vel_k, norm_nwtnupd_list else: pfv = get_pfromv(v=vel_k[:NV, :], V=V, M=M, A=A, J=J, fv=fv, invinds=invinds, diribcs=diribcs) return (np.vstack([vel_k, pfv]), norm_nwtnupd_list) except IOError: print 'no old velocity data found' norm_nwtnupd = None if paraviewoutput: cdatstr = get_datastring(**datastrdict) vfile = dolfin.File(vfileprfx+'__steadystates.pvd') pfile = dolfin.File(pfileprfx+'__steadystates.pvd') prvoutdict = dict(V=V, Q=Q, vfile=vfile, pfile=pfile, invinds=invinds, diribcs=diribcs, ppin=ppin, vp=None, t=None, writeoutput=True) else: prvoutdict = dict(writeoutput=False) # save 'if statements' here NV = A.shape[0] if vel_start_nwtn is None: vp_stokes = lau.solve_sadpnt_smw(amat=A, jmat=J, jmatT=JT, rhsv=fv, rhsp=fp) vp_stokes[NV:] = -vp_stokes[NV:] # pressure was flipped for symmetry # save the data cdatstr = get_datastring(**datastrdict) dou.save_npa(vp_stokes[:NV, ], fstring=cdatstr + '__vel') prvoutdict.update(dict(vp=vp_stokes)) dou.output_paraview(**prvoutdict) # Stokes solution as starting value vp_k = vp_stokes vel_k = vp_stokes[:NV, ] else: vel_k = vel_start_nwtn # Picard iterations for a good starting value for Newton for k in range(vel_pcrd_stps): (convc_mat, rhs_con, rhsv_conbc) = get_v_conv_conts(prev_v=vel_k, invinds=invinds, V=V, diribcs=diribcs, Picard=True) vp_k = lau.solve_sadpnt_smw(amat=A+convc_mat, jmat=J, jmatT=JT, rhsv=fv+rhs_con+rhsv_conbc, rhsp=fp) normpicupd = np.sqrt(m_innerproduct(M, vel_k-vp_k[:NV, :]))[0] print 'Picard iteration: {0} -- norm of update: {1}'\ .format(k+1, normpicupd) vel_k = vp_k[:NV, ] vp_k[NV:] = -vp_k[NV:] # pressure was flipped for symmetry if normpicupd < vel_pcrd_tol: break # Newton iteration while (vel_newtk < vel_nwtn_stps and (norm_nwtnupd is None or norm_nwtnupd > vel_nwtn_tol or norm_nwtnupd == np.array(None))): vel_newtk += 1 cdatstr = get_datastring(**datastrdict) (convc_mat, rhs_con, rhsv_conbc) = get_v_conv_conts(vel_k, invinds=invinds, V=V, diribcs=diribcs) vp_k = lau.solve_sadpnt_smw(amat=A+convc_mat, jmat=J, jmatT=JT, rhsv=fv+rhs_con+rhsv_conbc, rhsp=fp) norm_nwtnupd = np.sqrt(m_innerproduct(M, vel_k - vp_k[:NV, :]))[0] vel_k = vp_k[:NV, ] vp_k[NV:] = -vp_k[NV:] # pressure was flipped for symmetry print 'Steady State NSE: Newton iteration: {0} -- norm of update: {1}'\ .format(vel_newtk, norm_nwtnupd) dou.save_npa(vel_k, fstring=cdatstr + '__vel') prvoutdict.update(dict(vp=vp_k)) dou.output_paraview(**prvoutdict) dou.save_npa(norm_nwtnupd, cdatstr + '__norm_nwtnupd') dou.output_paraview(**prvoutdict) # savetomatlab = True # if savetomatlab: # export_mats_to_matlab(E=None, A=None, matfname='matexport') if return_vp: return vp_k, norm_nwtnupd_list else: return vel_k, norm_nwtnupd_list
def solve_nse(A=None, M=None, J=None, JT=None, fv=None, fp=None, fvc=None, fpc=None, # TODO: this is to catch deprecated calls fv_tmdp=None, fv_tmdp_params={}, fv_tmdp_memory=None, iniv=None, lin_vel_point=None, stokes_flow=False, trange=None, t0=None, tE=None, Nts=None, V=None, Q=None, invinds=None, diribcs=None, dbcinds=None, dbcvals=None, output_includes_bcs=False, N=None, nu=None, ppin=-1, closed_loop=False, static_feedback=False, feedbackthroughdict=None, return_vp=False, tb_mat=None, cv_mat=None, vel_nwtn_stps=20, vel_nwtn_tol=5e-15, nsects=1, loc_nwtn_tol=5e-15, loc_pcrd_stps=True, addfullsweep=False, vel_pcrd_stps=4, krylov=None, krpslvprms={}, krplsprms={}, clearprvdata=False, useolddata=False, get_datastring=None, data_prfx='', paraviewoutput=False, plttrange=None, vfileprfx='', pfileprfx='', return_dictofvelstrs=False, return_dictofpstrs=False, dictkeysstr=False, treat_nonl_explct=False, return_as_list=False, verbose=True, start_ssstokes=False, **kw): """ solution of the time-dependent nonlinear Navier-Stokes equation .. math:: M\\dot v + Av + N(v)v + J^Tp = f \n Jv =g using a Newton scheme in function space, i.e. given :math:`v_k`, we solve for the update like .. math:: M\\dot v + Av + N(v_k)v + N(v)v_k + J^Tp = N(v_k)v_k + f, and trapezoidal rule in time. To solve an *Oseen* system (linearization about a steady state) or a *Stokes* system, set the number of Newton steps to one and provide a linearization point and an initial value. Parameters ---------- lin_vel_point : dictionary, optional contains the linearization point for the first Newton iteration * Steady State: {{`None`: 'path_to_nparray'}, {'None': nparray}} * Newton: {`t`: 'path_to_nparray'} defaults to `None` dictkeysstr : boolean, optional whether the `keys` of the result dictionaries are strings instead \ of floats, defaults to `False` fv_tmdp : callable f(t, v, dict), optional time-dependent part of the right-hand side, set to zero if None fv_tmdp_params : dictionary, optional dictionary of parameters to be passed to `fv_tmdp`, defaults to `{}` fv_tmdp_memory : dictionary, optional memory of the function output_includes_bcs : boolean, optional whether append the boundary nodes to the computed and stored \ velocities, defaults to `False` krylov : {None, 'gmres'}, optional whether or not to use an iterative solver, defaults to `None` krpslvprms : dictionary, optional to specify parameters of the linear solver for use in Krypy, e.g., * initial guess * tolerance * number of iterations defaults to `None` krplsprms : dictionary, optional parameters to define the linear system like * preconditioner ppin : {int, None}, optional which dof of `p` is used to pin the pressure, defaults to `-1` stokes_flow : boolean, optional whether to consider the Stokes linearization, defaults to `False` start_ssstokes : boolean, optional for your convenience, compute and use the steady state stokes solution as initial value, defaults to `False` treat_nonl_explct= string, optional whether to treat the nonlinearity explicitly, defaults to `False` nsects: int, optional in how many segments the trange is split up. (The newton iteration will be confined to the segments and, probably, converge faster than the global iteration), defaults to `1` loc_nwtn_tol: float, optional tolerance for the newton iteration on the segments, defaults to `1e-15` loc_pcrd_stps: boolean, optional whether to init with `vel_pcrd_stps` Picard steps on every section, if `False`, Picard iterations are performed only on the first section, defaults to `True` addfullsweep: boolean, optional whether to compute the newton iteration on the full `trange`, useful to check and for the plots, defaults to `False` cv_mat: (Ny, Nv) sparse array, optional output matrix for velocity outputs, needed, e.g., for output dependent feedback control, defaults to `None` Returns ------- dictofvelstrs : dictionary, on demand dictionary with time `t` as keys and path to velocity files as values dictofpstrs : dictionary, on demand dictionary with time `t` as keys and path to pressure files as values vellist : list, on demand list of the velocity solutions """ import sadptprj_riclyap_adi.lin_alg_utils as lau if fvc is not None or fpc is not None: # TODO: this is for catching calls raise UserWarning('deprecated use of `rhsd_vfrc`, use only `fv`, `fp`') if get_datastring is None: get_datastring = get_datastr_snu if paraviewoutput: prvoutdict = dict(V=V, Q=Q, invinds=invinds, diribcs=diribcs, ppin=ppin, vp=None, t=None, tfilter=plttrange, writeoutput=True) else: prvoutdict = dict(writeoutput=False) # save 'if statements' here if trange is None: trange = np.linspace(t0, tE, Nts+1) if treat_nonl_explct and lin_vel_point is not None: raise UserWarning('cant use `lin_vel_point` ' + 'and explicit treatment of the nonlinearity') if return_dictofpstrs: gpfvd = dict(V=V, M=M, A=A, J=J, fv=fv, fp=fp, dbcinds=dbcinds, dbcvals=dbcvals, diribcs=diribcs, invinds=invinds) NV, NP = A.shape[0], J.shape[0] fv = np.zeros((NV, 1)) if fv is None else fv fp = np.zeros((NP, 1)) if fp is None else fp if fv_tmdp is None: def fv_tmdp(time=None, curvel=None, **kw): return np.zeros((NV, 1)), None if iniv is None: if start_ssstokes: # Stokes solution as starting value vp_stokes =\ lau.solve_sadpnt_smw(amat=A, jmat=J, jmatT=JT, rhsv=fv, # + fv_tmdp_cont, krylov=krylov, krpslvprms=krpslvprms, krplsprms=krplsprms, rhsp=fp) iniv = vp_stokes[:NV] else: raise ValueError('No initial value given') datastrdict = dict(time=None, meshp=N, nu=nu, Nts=trange.size-1, data_prfx=data_prfx, semiexpl=treat_nonl_explct) if return_as_list: clearprvdata = True # we want the results at hand if clearprvdata: datastrdict['time'] = '*' cdatstr = get_datastring(**datastrdict) for fname in glob.glob(cdatstr + '__vel*'): os.remove(fname) for fname in glob.glob(cdatstr + '__p*'): os.remove(fname) def _atdct(cdict, t, thing): if dictkeysstr: cdict.update({'{0}'.format(t): thing}) else: cdict.update({t: thing}) def _gfdct(cdict, t): if dictkeysstr: return cdict['{0}'.format(t)] else: return cdict[t] if stokes_flow: vel_nwtn_stps = 1 vel_pcrd_stps = 0 print('Stokes Flow!') elif lin_vel_point is None: comp_nonl_semexp_inig = True if not treat_nonl_explct: print(('No linearization point given - explicit' + ' treatment of the nonlinearity in the first Iteration')) else: cur_linvel_point = lin_vel_point comp_nonl_semexp_inig = False newtk, norm_nwtnupd = 0, 1 # check for previously computed velocities if useolddata and lin_vel_point is None and not stokes_flow: try: datastrdict.update(dict(time=trange[-1])) cdatstr = get_datastring(**datastrdict) norm_nwtnupd = (dou.load_npa(cdatstr + '__norm_nwtnupd')).flatten() try: if norm_nwtnupd[0] is None: norm_nwtnupd = 1. except IndexError: norm_nwtnupd = 1. dou.load_npa(cdatstr + '__vel') print('found vel files') print('norm of last Nwtn update: {0}'.format(norm_nwtnupd)) print('... loaded from ' + cdatstr) if norm_nwtnupd < vel_nwtn_tol and not return_dictofvelstrs: return elif norm_nwtnupd < vel_nwtn_tol or treat_nonl_explct: # looks like converged / or semi-expl # -- check if all values are there # t0: datastrdict.update(dict(time=trange[0])) cdatstr = get_datastring(**datastrdict) dictofvelstrs = {} _atdct(dictofvelstrs, trange[0], cdatstr + '__vel') if return_dictofpstrs: dictofpstrs = {} for t in trange: datastrdict.update(dict(time=t)) cdatstr = get_datastring(**datastrdict) # test if the vels are there v_old = dou.load_npa(cdatstr + '__vel') # update the dict _atdct(dictofvelstrs, t, cdatstr + '__vel') if return_dictofpstrs: try: p_old = dou.load_npa(cdatstr + '__p') _atdct(dictofpstrs, t, cdatstr + '__p') except: p_old = get_pfromv(v=v_old, **gpfvd) dou.save_npa(p_old, fstring=cdatstr + '__p') _atdct(dictofpstrs, t, cdatstr + '__p') if return_dictofpstrs: return dictofvelstrs, dictofpstrs else: return dictofvelstrs # comp_nonl_semexp = False except IOError: norm_nwtnupd = 2 print('no old velocity data found') def _append_bcs_ornot(vvec): if output_includes_bcs: # make the switch here for better readibility vwbcs = dts.append_bcs_vec(vvec, vdim=V.dim(), invinds=invinds, diribcs=diribcs) return vwbcs else: return vvec def _get_mats_rhs_ts(mmat=None, dt=None, var_c=None, coeffmat_c=None, coeffmat_n=None, fv_c=None, fv_n=None, umat_c=None, vmat_c=None, umat_n=None, vmat_n=None, impeul=False): """ to be tweaked for different int schemes """ solvmat = M + 0.5*dt*coeffmat_n rhs = M*var_c + 0.5*dt*(fv_n + fv_c - coeffmat_c*var_c) if umat_n is not None: matvec = lau.mm_dnssps umat = 0.5*dt*umat_n vmat = vmat_n # TODO: do we really need a PLUS here??' rhs = rhs + 0.5*dt*matvec(umat_c, matvec(vmat_c, var_c)) else: umat, vmat = umat_n, vmat_n return solvmat, rhs, umat, vmat v_old = iniv # start vector for time integration in every Newtonit datastrdict['time'] = trange[0] cdatstr = get_datastring(**datastrdict) dou.save_npa(_append_bcs_ornot(v_old), fstring=cdatstr + '__vel') dictofvelstrs = {} _atdct(dictofvelstrs, trange[0], cdatstr + '__vel') if return_dictofpstrs: p_old = get_pfromv(v=v_old, **gpfvd) dou.save_npa(p_old, fstring=cdatstr + '__p') dictofpstrs = {} _atdct(dictofpstrs, trange[0], cdatstr+'__p') else: p_old = None if return_as_list: vellist = [] vellist.append(_append_bcs_ornot(v_old)) lensect = np.int(np.floor(trange.size/nsects)) loctrngs = [] for k in np.arange(nsects-1): loctrngs.append(trange[k*lensect: (k+1)*lensect+1]) loctrngs.append(trange[(nsects-1)*lensect:]) if addfullsweep: loctrngs.append(trange) realiniv = np.copy(iniv) if nsects == 1: loc_nwtn_tol = vel_nwtn_tol addfullsweep = False loctrngs = [trange] if loc_pcrd_stps: vel_loc_pcrd_steps = vel_pcrd_stps for loctrng in loctrngs: dtvec = np.array(loctrng)[1:] - np.array(loctrng)[1:] dotdtvec = dtvec[1:] - dtvec[:-1] uniformgrid = np.allclose(np.linalg.norm(dotdtvec), 0) coeffmatlu = None while (newtk < vel_nwtn_stps and norm_nwtnupd > loc_nwtn_tol): print('solve the NSE on the interval [{0}, {1}]'. format(loctrng[0], loctrng[-1])) if stokes_flow: pcrd_anyone = False newtk = vel_nwtn_stps elif comp_nonl_semexp_inig and not treat_nonl_explct: pcrd_anyone = False loc_treat_nonl_explct = True print('explicit treatment of nonl. for initial guess!') elif treat_nonl_explct: pcrd_anyone = False loc_treat_nonl_explct = True newtk = vel_nwtn_stps print('No Newton iterations - explicit treatment ' + 'of the nonlinearity') if not comp_nonl_semexp_inig and not treat_nonl_explct: if vel_pcrd_stps > 0: vel_pcrd_stps -= 1 pcrd_anyone = True print('Picard iterations for initial value -- {0} left'. format(vel_pcrd_stps)) else: pcrd_anyone = False newtk += 1 print('Computing Newton Iteration {0}'.format(newtk)) v_old = iniv # start vector for time integration in every Newtonit try: if krpslvprms['krylovini'] == 'old': vp_old = np.vstack([v_old, np.zeros((NP, 1))]) elif krpslvprms['krylovini'] == 'upd': vp_old = np.vstack([v_old, np.zeros((NP, 1))]) vp_new = vp_old cts_old = loctrng[1] - loctrng[0] except (TypeError, KeyError): pass # no inival for krylov solver required vfile = dolfin.File(vfileprfx+'__timestep.pvd') pfile = dolfin.File(pfileprfx+'__timestep.pvd') prvoutdict.update(dict(vp=None, vc=iniv, pc=p_old, t=loctrng[0], dbcinds=dbcinds, dbcvals=dbcvals, pfile=pfile, vfile=vfile)) dou.output_paraview(**prvoutdict) # ## current values_c for application of trap rule if stokes_flow: convc_mat_c = sps.csr_matrix((NV, NV)) rhs_con_c, rhsv_conbc_c = np.zeros((NV, 1)), np.zeros((NV, 1)) else: if loc_treat_nonl_explct is not None: prev_v = v_old else: try: prev_v = dou.load_npa(_gfdct(cur_linvel_point, loctrng[0])) except KeyError: try: prev_v = dou.load_npa(_gfdct(cur_linvel_point, None)) except TypeError: prev_v = cur_linvel_point[None] convc_mat_c, rhs_con_c, rhsv_conbc_c = \ get_v_conv_conts(prev_v=iniv, invinds=invinds, semi_explicit=loc_treat_nonl_explct, dbcinds=dbcinds, dbcvals=dbcvals, V=V, diribcs=diribcs, Picard=pcrd_anyone) cury = None if cv_mat is None else cv_mat.dot(v_old) (fv_tmdp_cont, fv_tmdp_memory) = fv_tmdp(time=0, curvel=v_old, cury=cury, memory=fv_tmdp_memory, **fv_tmdp_params) _rhsconvc = 0. if pcrd_anyone else rhs_con_c fvn_c = fv + rhsv_conbc_c + _rhsconvc + fv_tmdp_cont if closed_loop: if static_feedback: mtxtb_c = dou.load_npa(feedbackthroughdict[None]['mtxtb']) w_c = dou.load_npa(feedbackthroughdict[None]['w']) else: mtxtb_c = dou.load_npa(feedbackthroughdict[0]['mtxtb']) w_c = dou.load_npa(feedbackthroughdict[0]['w']) fvn_c = fvn_c + tb_mat * (tb_mat.T * w_c) vmat_c = mtxtb_c.T try: umat_c = np.array(tb_mat.todense()) except AttributeError: umat_c = tb_mat else: vmat_c = None umat_c = None norm_nwtnupd = 0 if verbose: # define at which points of time the progress is reported nouts = 10 # number of output points locnts = loctrng.size # TODO: trange may be a list... filtert = np.arange(0, locnts, np.int(np.floor(locnts/nouts))) loctinstances = loctrng[filtert] loctinstances[0] = loctrng[1] loctinstances = loctinstances.tolist() print('doing the time integration...') for tk, t in enumerate(loctrng[1:]): cts = t - loctrng[tk] datastrdict.update(dict(time=t)) cdatstr = get_datastring(**datastrdict) try: if verbose and t == loctinstances[0]: curtinst = loctinstances.pop(0) # print("runtime: {0} -- t: {1} -- tE: {2:f}". # format(time.clock(), curtinst, loctrng[-1])) print("runtime: {0:.1f} - t/tE: {1:.2f} - t: {2:.4f}". format(time.clock(), curtinst/loctrng[-1], curtinst)) except IndexError: pass # if something goes wrong, don't stop # coeffs and rhs at next time instance if stokes_flow: convc_mat_n = sps.csr_matrix((NV, NV)) rhs_con_n = np.zeros((NV, 1)) rhsv_conbc_n = np.zeros((NV, 1)) else: if loc_treat_nonl_explct: prev_v = v_old else: try: prev_v = dou.load_npa(_gfdct(cur_linvel_point, t)) except KeyError: try: prev_v = dou.load_npa(_gfdct(cur_linvel_point, None)) except TypeError: prev_v = cur_linvel_point[None] convc_mat_n, rhs_con_n, rhsv_conbc_n = \ get_v_conv_conts(prev_v=prev_v, invinds=invinds, V=V, semi_explicit=loc_treat_nonl_explct, dbcinds=dbcinds, dbcvals=dbcvals, diribcs=diribcs, Picard=pcrd_anyone) cury = None if cv_mat is None else cv_mat.dot(v_old) (fv_tmdp_cont, fv_tmdp_memory) = fv_tmdp(time=t, curvel=v_old, cury=cury, memory=fv_tmdp_memory, **fv_tmdp_params) _rhsconvn = 0. if pcrd_anyone else rhs_con_n fvn_n = fv + rhsv_conbc_n + _rhsconvn + fv_tmdp_cont if loc_treat_nonl_explct and not closed_loop: fvn_c = fv + rhsv_conbc_n + _rhsconvn + fv_tmdp_cont if closed_loop: if static_feedback: mtxtb_n = dou.\ load_npa(feedbackthroughdict[None]['mtxtb']) w_n = dou.load_npa(feedbackthroughdict[None]['w']) # fb = np.dot(tb_mat*mtxtb_n.T, v_old) # print '\nnorm of feedback: ', np.linalg.norm(fb) # print '\nnorm of v_old: ', np.linalg.norm(v_old) else: mtxtb_n = dou.load_npa(feedbackthroughdict[t]['mtxtb']) w_n = dou.load_npa(feedbackthroughdict[t]['w']) fvn_n = fvn_n + tb_mat * (tb_mat.T * w_n) vmat_n = mtxtb_n.T try: umat_n = np.array(tb_mat.todense()) except AttributeError: umat_n = tb_mat else: vmat_n = None umat_n = None (solvmat, rhsv, umat, vmat) = _get_mats_rhs_ts(mmat=M, dt=cts, var_c=v_old, coeffmat_c=A + convc_mat_c, coeffmat_n=A + convc_mat_n, fv_c=fvn_c, fv_n=fvn_n, umat_c=umat_c, vmat_c=vmat_c, umat_n=umat_n, vmat_n=vmat_n) try: if krpslvprms['krylovini'] == 'old': krpslvprms['x0'] = vp_old elif krpslvprms['krylovini'] == 'upd': vp_oldold = vp_old vp_old = vp_new krpslvprms['x0'] = vp_old + \ cts*(vp_old - vp_oldold)/cts_old cts_old = cts except (TypeError, KeyError): pass # no inival for krylov solver required if loc_treat_nonl_explct and uniformgrid and not krylov: if coeffmatlu is None: print('gonna compute an LU of the coefficient ' + 'matrix \n and reuse it in the time stepping') vp_new, coeffmatlu = \ lau.solve_sadpnt_smw(amat=solvmat, jmat=J, jmatT=JT, rhsv=rhsv, rhsp=fp, sadlu=coeffmatlu, return_alu=True, umat=umat, vmat=vmat) else: vp_new = lau.solve_sadpnt_smw(amat=solvmat, jmat=J, jmatT=JT, rhsv=rhsv, rhsp=fp, krylov=krylov, krpslvprms=krpslvprms, krplsprms=krplsprms, umat=umat, vmat=vmat) v_old = vp_new[:NV, ] (umat_c, vmat_c, fvn_c, convc_mat_c) = umat_n, vmat_n, fvn_n, convc_mat_n dou.save_npa(_append_bcs_ornot(v_old), fstring=cdatstr + '__vel') _atdct(dictofvelstrs, t, cdatstr + '__vel') p_new = -1/cts*vp_new[NV:, ] # p was flipped and scaled for symmetry if return_dictofpstrs: dou.save_npa(p_new, fstring=cdatstr + '__p') _atdct(dictofpstrs, t, cdatstr + '__p') if return_as_list: vellist.append(_append_bcs_ornot(v_old)) # integrate the Newton error if stokes_flow or treat_nonl_explct: norm_nwtnupd = None elif comp_nonl_semexp_inig: norm_nwtnupd = 1. else: if len(prev_v) > len(invinds): prev_v = prev_v[invinds, :] addtonwtnupd = cts * m_innerproduct(M, v_old - prev_v) norm_nwtnupd += np.float(addtonwtnupd.flatten()[0]) if newtk == vel_nwtn_stps or norm_nwtnupd < loc_nwtn_tol: # paraviewoutput in the (probably) last newton sweep prvoutdict.update(dict(vc=v_old, pc=p_new, t=t)) dou.output_paraview(**prvoutdict) dou.save_npa(norm_nwtnupd, cdatstr + '__norm_nwtnupd') print('\nnorm of current Newton update: {}'.format(norm_nwtnupd)) # print('\nsaved `norm_nwtnupd(={0})'.format(norm_nwtnupd) + # ' to ' + cdatstr) loc_treat_nonl_explct = False comp_nonl_semexp_inig = False cur_linvel_point = dictofvelstrs iniv = v_old if not treat_nonl_explct and lin_vel_point is None: comp_nonl_semexp_inig = True if addfullsweep and loctrng is loctrngs[-2]: comp_nonl_semexp_inig = False iniv = realiniv loc_nwtn_tol = vel_nwtn_tol elif loc_pcrd_stps: vel_pcrd_stps = vel_loc_pcrd_steps norm_nwtnupd = 1. newtk = 0 if return_dictofvelstrs: if return_dictofpstrs: return dictofvelstrs, dictofpstrs else: return dictofvelstrs elif return_as_list: return vellist else: return
def lqgbt(problemname='drivencavity', N=10, Re=1e2, plain_bt=False, use_ric_ini=None, t0=0.0, tE=1.0, Nts=11, NU=3, NY=3, bccontrol=True, palpha=1e-5, paraoutput=True, trunc_lqgbtcv=1e-6, nwtn_adi_dict=None, comp_freqresp=False, comp_stepresp='nonlinear', closed_loop=False, multiproc=False, perturbpara=1e-3): """Main routine for LQGBT Parameters ---------- problemname : string, optional what problem to be solved, 'cylinderwake' or 'drivencavity' N : int, optional parameter for the dimension of the space discretization Re : real, optional Reynolds number, defaults to `1e2` plain_bt : boolean, optional whether to try simple *balanced truncation*, defaults to False use_ric_ini : real, optional use the solution with this Re number as stabilizing initial guess, defaults to `None` t0, tE, Nts : real, real, int, optional starting and endpoint of the considered time interval, number of time instancses, default to `0.0, 1.0, 11` bccontrol : boolean, optional whether to apply boundary control via penalized robin conditions, defaults to `False` NU, NY : int, optional dimensions of components of in and output space (will double because there are two components), default to `3, 3` comp_freqresp : boolean, optional whether to compute and compare the frequency responses, defaults to `False` comp_stepresp : {'nonlinear', False, None} whether to compute and compare the step responses | if False -> no step response | if == 'nonlinear' -> compare linear reduced to nonlinear full model | else -> linear reduced versus linear full model defaults to `False` trunc_lqgbtcv : real, optional threshold at what the lqgbt characteristiv values are truncated, defaults to `1e-6` closed_loop : {'full_state_fb', 'red_output_fb', False, None} how to do the closed loop simulation: | if False -> no simulation | if == 'full_state_fb' -> full state feedback | if == 'red_output_fb' -> reduced output feedback | else -> no control is applied defaults to `False` """ typprb = 'BT' if plain_bt else 'LQG-BT' print '\n ### We solve the {0} problem for the {1} at Re={2} ###\n'.\ format(typprb, problemname, Re) if nwtn_adi_dict is not None: nap = nwtn_adi_dict else: nap = nwtn_adi_params()['nwtn_adi_dict'] # output ddir = 'data/' try: os.chdir(ddir) except OSError: raise Warning('need "' + ddir + '" subdir for storing the data') os.chdir('..') # stokesmats = dts.get_stokessysmats(femp['V'], femp['Q'], nu) # rhsd_vf = dts.setget_rhs(femp['V'], femp['Q'], # femp['fv'], femp['fp'], t=0) # # remove the freedom in the pressure # stokesmats['J'] = stokesmats['J'][:-1, :][:, :] # stokesmats['JT'] = stokesmats['JT'][:, :-1][:, :] # rhsd_vf['fp'] = rhsd_vf['fp'][:-1, :] # # reduce the matrices by resolving the BCs # (stokesmatsc, # rhsd_stbc, # invinds, # bcinds, # bcvals) = dts.condense_sysmatsbybcs(stokesmats, # femp['diribcs']) # # pressure freedom and dirichlet reduced rhs # rhsd_vfrc = dict(fpr=rhsd_vf['fp'], fvc=rhsd_vf['fv'][invinds, ]) # # add the info on boundary and inner nodes # bcdata = {'bcinds': bcinds, # 'bcvals': bcvals, # 'invinds': invinds} # femp.update(bcdata) femp, stokesmatsc, rhsd_vfrc, rhsd_stbc \ = dnsps.get_sysmats(problem=problemname, N=N, Re=Re, bccontrol=bccontrol, scheme='TH') nu = femp['charlen']/Re # specify in what spatial direction Bu changes. The remaining is constant uspacedep = femp['uspacedep'] # casting some parameters invinds, NV = femp['invinds'], len(femp['invinds']) prbstr = '_bt' if plain_bt else '_lqgbt' # contsetupstr = 'NV{0}NU{1}NY{2}alphau{3}'.format(NV, NU, NY, alphau) if bccontrol: import scipy.sparse as sps contsetupstr = 'NV{0}_bcc_NY{1}'.format(NV, NY) stokesmatsc['A'] = stokesmatsc['A'] + 1./palpha*stokesmatsc['Arob'] b_mat = 1./palpha*stokesmatsc['Brob'] u_masmat = sps.eye(b_mat.shape[1], format='csr') else: contsetupstr = 'NV{0}NU{1}NY{2}'.format(NV, NU, NY) def get_fdstr(Re): return ddir + problemname + '_Re{0}_'.format(Re) + \ contsetupstr + prbstr fdstr = get_fdstr(Re) soldict = stokesmatsc # containing A, J, JT soldict.update(femp) # adding V, Q, invinds, diribcs # soldict.update(rhsd_vfrc) # adding fvc, fpr soldict.update(fv=rhsd_stbc['fv']+rhsd_vfrc['fvc'], fp=rhsd_stbc['fp']+rhsd_vfrc['fpr'], N=N, nu=nu, data_prfx=fdstr) # # Prepare for control # # get the control and observation operators if not bccontrol: try: b_mat = dou.load_spa(ddir + contsetupstr + '__b_mat') u_masmat = dou.load_spa(ddir + contsetupstr + '__u_masmat') print 'loaded `b_mat`' except IOError: print 'computing `b_mat`...' b_mat, u_masmat = cou.get_inp_opa(cdcoo=femp['cdcoo'], V=femp['V'], NU=NU, xcomp=uspacedep) dou.save_spa(b_mat, ddir + contsetupstr + '__b_mat') dou.save_spa(u_masmat, ddir + contsetupstr + '__u_masmat') b_mat = b_mat[invinds, :][:, :] # tb_mat = 1./np.sqrt(alphau) try: mc_mat = dou.load_spa(ddir + contsetupstr + '__mc_mat') y_masmat = dou.load_spa(ddir + contsetupstr + '__y_masmat') print 'loaded `c_mat`' except IOError: print 'computing `c_mat`...' mc_mat, y_masmat = cou.get_mout_opa(odcoo=femp['odcoo'], V=femp['V'], NY=NY) dou.save_spa(mc_mat, ddir + contsetupstr + '__mc_mat') dou.save_spa(y_masmat, ddir + contsetupstr + '__y_masmat') c_mat = lau.apply_massinv(y_masmat, mc_mat, output='sparse') # restrict the operators to the inner nodes mc_mat = mc_mat[:, invinds][:, :] c_mat = c_mat[:, invinds][:, :] c_mat_reg = lau.app_prj_via_sadpnt(amat=stokesmatsc['M'], jmat=stokesmatsc['J'], rhsv=c_mat.T, transposedprj=True).T # c_mat_reg = np.array(c_mat.todense()) # TODO: right choice of norms for y # and necessity of regularization here # by now, we go on number save # # setup the system for the correction # # # compute the uncontrolled steady state Stokes solution # v_ss_nse, list_norm_nwtnupd = snu.solve_steadystate_nse(**soldict) (convc_mat, rhs_con, rhsv_conbc) = snu.get_v_conv_conts(prev_v=v_ss_nse, invinds=invinds, V=femp['V'], diribcs=femp['diribcs']) f_mat = - stokesmatsc['A'] - convc_mat mmat = stokesmatsc['M'] # ssv_rhs = rhsv_conbc + rhsv_conbc + rhsd_vfrc['fvc'] + rhsd_stbc['fv'] if plain_bt: get_gramians = pru.solve_proj_lyap_stein else: get_gramians = pru.proj_alg_ric_newtonadi truncstr = '__lqgbtcv{0}'.format(trunc_lqgbtcv) try: tl = dou.load_npa(fdstr + '__tl' + truncstr) tr = dou.load_npa(fdstr + '__tr' + truncstr) print 'loaded the left and right transformations: \n' + \ fdstr + '__tl/__tr' + truncstr except IOError: print 'computing the left and right transformations' + \ ' and saving to: \n' + fdstr + '__tl/__tr' + truncstr try: zwc = dou.load_npa(fdstr + '__zwc') zwo = dou.load_npa(fdstr + '__zwo') print 'loaded factor of the Gramians: \n\t' + \ fdstr + '__zwc/__zwo' except IOError: zinic, zinio = None, None if use_ric_ini is not None: fdstr = get_fdstr(use_ric_ini) try: zinic = dou.load_npa(fdstr + '__zwc') zinio = dou.load_npa(fdstr + '__zwo') print 'Initialize Newton ADI by zwc/zwo from ' + fdstr except IOError: raise UserWarning('No initial guess with Re={0}'. format(use_ric_ini)) fdstr = get_fdstr(Re) print 'computing factors of Gramians: \n\t' + \ fdstr + '__zwc/__zwo' def compobsg(): try: zwo = dou.load_npa(fdstr + '__zwo') print 'at least __zwo is there' except IOError: zwo = get_gramians(mmat=mmat.T, amat=f_mat.T, jmat=stokesmatsc['J'], bmat=c_mat_reg.T, wmat=b_mat, nwtn_adi_dict=nap, z0=zinio)['zfac'] dou.save_npa(zwo, fdstr + '__zwo') def compcong(): try: zwc = dou.load_npa(fdstr + '__zwc') print 'at least __zwc is there' except IOError: zwc = get_gramians(mmat=mmat, amat=f_mat, jmat=stokesmatsc['J'], bmat=b_mat, wmat=c_mat_reg.T, nwtn_adi_dict=nap, z0=zinic)['zfac'] dou.save_npa(zwc, fdstr + '__zwc') if multiproc: print '\n ### multithread start - ' +\ 'output might be intermangled' p1 = multiprocessing.Process(target=compobsg) p2 = multiprocessing.Process(target=compcong) p1.start() p2.start() p1.join() p2.join() print '### multithread end' else: compobsg() compcong() zwc = dou.load_npa(fdstr + '__zwc') zwo = dou.load_npa(fdstr + '__zwo') print 'computing the left and right transformations' + \ ' and saving to:\n' + fdstr + '__tr/__tl' + truncstr tl, tr = btu.\ compute_lrbt_transfos(zfc=zwc, zfo=zwo, mmat=stokesmatsc['M'], trunck={'threshh': trunc_lqgbtcv}) dou.save_npa(tl, fdstr + '__tl' + truncstr) dou.save_npa(tr, fdstr + '__tr' + truncstr) print 'NV = {0}, NP = {2}, k = {1}'.\ format(tl.shape[0], tl.shape[1], stokesmatsc['J'].shape[0]) if comp_freqresp: btu.compare_freqresp(mmat=stokesmatsc['M'], amat=f_mat, jmat=stokesmatsc['J'], bmat=b_mat, cmat=c_mat, tr=tr, tl=tl, plot=True, datastr=fdstr + '__tl' + truncstr) if comp_stepresp is not False: if comp_stepresp == 'nonlinear': stp_rsp_nwtn = 3 stp_rsp_dtpr = 'nonl_stepresp_' else: stp_rsp_nwtn = 1 stp_rsp_dtpr = 'stepresp_' def fullstepresp_lnse(bcol=None, trange=None, ini_vel=None, cmat=None, soldict=None): soldict.update(fv_stbc=rhsd_stbc['fv']+bcol, vel_nwtn_stps=stp_rsp_nwtn, trange=trange, iniv=ini_vel, lin_vel_point=ini_vel, clearprvdata=True, data_prfx=stp_rsp_dtpr, return_dictofvelstrs=True) dictofvelstrs = snu.solve_nse(**soldict) return cou.extract_output(strdict=dictofvelstrs, tmesh=trange, c_mat=cmat, load_data=dou.load_npa) # differences in the initial vector # print np.dot(c_mat_reg, v_ss_nse) # print np.dot(np.dot(c_mat_reg, tr), # np.dot(tl.T, stokesmatsc['M']*v_ss_nse)) jsonstr = fdstr + stp_rsp_dtpr + '_Nred{0}_t0tENts{1}{2}{3}.json'.\ format(tl.shape[1], t0, tE, Nts) btu.compare_stepresp(tmesh=np.linspace(t0, tE, Nts), a_mat=f_mat, c_mat=c_mat_reg, b_mat=b_mat, m_mat=stokesmatsc['M'], tr=tr, tl=tl, iniv=v_ss_nse, # ss_rhs=ssv_rhs, fullresp=fullstepresp_lnse, fsr_soldict=soldict, plot=True, jsonstr=jsonstr) # compute the regulated system trange = np.linspace(t0, tE, Nts) if closed_loop is False: return elif closed_loop == 'full_state_fb': zwc = dou.load_npa(fdstr + '__zwc') zwo = dou.load_npa(fdstr + '__zwo') mtxtb = pru.get_mTzzTtb(stokesmatsc['M'].T, zwc, b_mat) def fv_tmdp_fullstatefb(time=None, curvel=None, linv=None, tb_mat=None, tbxm_mat=None, **kw): """realizes a full state static feedback as a function that can be passed to a solution routine for the unsteady Navier-Stokes equations Parameters ---------- time : real current time curvel : (N,1) nparray current velocity linv : (N,1) nparray linearization point for the linear model tb_mat : (N,K) nparray input matrix containing the input weighting tbxm_mat : (N,K) nparray `tb_mat * gain * mass` Returns ------- actua : (N,1) nparray current contribution to the right-hand side , : dictionary dummy `{}` for consistency """ actua = -lau.comp_uvz_spdns(tb_mat, tbxm_mat, curvel-linv) # actua = 0*curvel print '\nnorm of deviation', np.linalg.norm(curvel-linv) # print 'norm of actuation {0}'.format(np.linalg.norm(actua)) return actua, {} tmdp_fsfb_dict = dict(linv=v_ss_nse, tb_mat=b_mat, tbxm_mat=mtxtb.T) fv_tmdp = fv_tmdp_fullstatefb fv_tmdp_params = tmdp_fsfb_dict fv_tmdp_memory = None elif closed_loop == 'red_output_fb': try: xok = dou.load_npa(fdstr+truncstr+'__xok') xck = dou.load_npa(fdstr+truncstr+'__xck') ak_mat = dou.load_npa(fdstr+truncstr+'__ak_mat') ck_mat = dou.load_npa(fdstr+truncstr+'__ck_mat') bk_mat = dou.load_npa(fdstr+truncstr+'__bk_mat') except IOError: print 'couldn"t load the red system - compute it' zwc = dou.load_npa(fdstr + '__zwc') zwo = dou.load_npa(fdstr + '__zwo') ak_mat = np.dot(tl.T, f_mat*tr) ck_mat = lau.mm_dnssps(c_mat_reg, tr) bk_mat = lau.mm_dnssps(tl.T, b_mat) tltm, trtm = tl.T*stokesmatsc['M'], tr.T*stokesmatsc['M'] xok = np.dot(np.dot(tltm, zwo), np.dot(zwo.T, tltm.T)) xck = np.dot(np.dot(trtm, zwc), np.dot(zwc.T, trtm.T)) dou.save_npa(xok, fdstr+truncstr+'__xok') dou.save_npa(xck, fdstr+truncstr+'__xck') dou.save_npa(ak_mat, fdstr+truncstr+'__ak_mat') dou.save_npa(ck_mat, fdstr+truncstr+'__ck_mat') dou.save_npa(bk_mat, fdstr+truncstr+'__bk_mat') obs_bk = np.dot(xok, ck_mat.T) DT = (tE - t0)/(Nts-1) sysmatk_inv = np.linalg.inv(np.eye(ak_mat.shape[1]) - DT*(ak_mat - np.dot(np.dot(xok, ck_mat.T), ck_mat) - np.dot(bk_mat, np.dot(bk_mat.T, xck)))) def fv_tmdp_redoutpfb(time=None, curvel=None, memory=None, linvel=None, ipsysk_mat_inv=None, obs_bk=None, cts=None, b_mat=None, c_mat=None, xck=None, bk_mat=None, **kw): """realizes a reduced static output feedback as a function that can be passed to a solution routine for the unsteady Navier-Stokes equations For convinience the Parameters ---------- time : real current time curvel : (N,1) nparray current velocity. For consistency, the full state is taken as input. However, internally, we only use the observation `y = c_mat*curvel` memory : dictionary contains values from previous call, in particular the previous state estimate linvel : (N,1) nparray linearization point for the linear model ipsysk_mat_inv : (K,K) nparray inverse of the system matrix that defines the update of the state estimate obs_bk : (K,NU) nparray input matrix in the observer cts : real time step length b_mat : (N,NU) sparse matrix input matrix of the full system c_mat=None, c_mat : (NY,N) sparse matrix output matrix of the full system xck : (K,K) nparray reduced solution of the CARE bk_mat : (K,NU) nparray reduced input matrix Returns ------- actua : (N,1) nparray the current actuation memory : dictionary to be passed back in the next timestep """ xk_old = memory['xk_old'] buk = cts*np.dot(obs_bk, lau.mm_dnssps(c_mat, (curvel-linvel))) xk_old = np.dot(ipsysk_mat_inv, xk_old + buk) # cts*np.dot(obs_bk, # lau.mm_dnssps(c_mat, (curvel-linvel)))) memory['xk_old'] = xk_old actua = -lau.mm_dnssps(b_mat, np.dot(bk_mat.T, np.dot(xck, xk_old))) print '\nnorm of deviation', np.linalg.norm(curvel-linvel) print 'norm of actuation {0}'.format(np.linalg.norm(actua)) return actua, memory fv_rofb_dict = dict(cts=DT, linvel=v_ss_nse, b_mat=b_mat, c_mat=c_mat_reg, obs_bk=obs_bk, bk_mat=bk_mat, ipsysk_mat_inv=sysmatk_inv, xck=xck) fv_tmdp = fv_tmdp_redoutpfb fv_tmdp_params = fv_rofb_dict fv_tmdp_memory = dict(xk_old=np.zeros((tl.shape[1], 1))) else: fv_tmdp = None fv_tmdp_params = {} fv_tmdp_memory = {} perturbini = perturbpara*np.ones((NV, 1)) reg_pertubini = lau.app_prj_via_sadpnt(amat=stokesmatsc['M'], jmat=stokesmatsc['J'], rhsv=perturbini) soldict.update(fv_stbc=rhsd_stbc['fv'], trange=trange, iniv=v_ss_nse + reg_pertubini, lin_vel_point=None, clearprvdata=True, data_prfx=fdstr + truncstr, fv_tmdp=fv_tmdp, comp_nonl_semexp=True, fv_tmdp_params=fv_tmdp_params, fv_tmdp_memory=fv_tmdp_memory, return_dictofvelstrs=True) outstr = truncstr + '{0}'.format(closed_loop) \ + 't0{0}tE{1}Nts{2}N{3}Re{4}'.format(t0, tE, Nts, N, Re) if paraoutput: soldict.update(paraviewoutput=True, vfileprfx='results/vel_'+outstr, pfileprfx='results/p_'+outstr) dictofvelstrs = snu.solve_nse(**soldict) yscomplist = cou.extract_output(strdict=dictofvelstrs, tmesh=trange, c_mat=c_mat, load_data=dou.load_npa) dou.save_output_json(dict(tmesh=trange.tolist(), outsig=yscomplist), fstring=fdstr + truncstr + '{0}'.format(closed_loop) + 't0{0}tE{1}Nts{2}'.format(t0, tE, Nts) + 'inipert{0}'.format(perturbpara)) dou.plot_outp_sig(tmesh=trange, outsig=yscomplist)
format(NN, Re, compall) try: if debug: raise IOError() levs = dou.load_npa(levstr) print 'loaded the eigenvalues of the linearized system' except IOError: print 'computing the eigenvalues of the linearized system' if compall: A = asysmat.todense() M = msysmat.todense() if not shiftall else mshiftsmat.todense() levs = spla.eigvals(A, M, overwrite_a=True, check_finite=False) else: levs = spsla.eigs(asysmat, M=mshiftsmat, sigma=1, k=10, which='LR', return_eigenvectors=False) dou.save_npa(levs, levstr) plt.figure(1) # plt.xlim((-20, 15)) # plt.ylim((-100, 100)) plt.plot(np.real(levs), np.imag(levs), '+') plt.show(block=False) projsys = False if projsys: mfac = spsla.splu(M) mijtl = [] for kcol in range(J.shape[0]): curcol = np.array(J.T[:, kcol].todense()) micc = np.array(mfac.solve(curcol.flatten())) mijtl.append(micc.reshape((NV, 1)))
def set_inival(whichinival='sstokes', soldict=None, perturbpara=None, v_ss_nse=None, trange=None, tpp=None, fdstr=None, retvssnse=False): ''' compute the wanted initial value and set it in the soldict ''' if (retvssnse or whichinival == 'sstate+d') and v_ss_nse is None: ret_v_ss_nse = snu.solve_steadystate_nse(**soldict) elif v_ss_nse is not None: ret_v_ss_nse = v_ss_nse else: ret_v_ss_nse is None if whichinival == 'sstokes': print('we start with Stokes -- `perturbpara` is not considered') soldict.update(dict(iniv=None, start_ssstokes=True)) shortinivstr = 'sks' return shortinivstr, ret_v_ss_nse if (whichinival == 'sstate+d' or whichinival == 'snse+d++' or whichinival == 'sstate+du'): perturbini = perturbpara*np.ones((soldict['M'].shape[0], 1)) reg_pertubini = lau.app_prj_via_sadpnt(amat=soldict['M'], jmat=soldict['J'], rhsv=perturbini) if whichinival == 'sstate+d': soldict.update(dict(iniv=ret_v_ss_nse + reg_pertubini)) shortinivstr = 'ssd{0}'.format(perturbpara) return shortinivstr, ret_v_ss_nse if whichinival == 'sstokes++' or whichinival == 'snse+d++': lctrng = (trange[trange < tpp]).tolist() lctrng.append(tpp) stksppdtstr = fdstr + 't0{0:.1f}tE{1:.4f}'.\ format(trange[0], tpp) + whichinival try: sstokspp = dou.load_npa(stksppdtstr) print('loaded ' + stksppdtstr + ' for inival') except IOError: inivsoldict = {} inivsoldict.update(soldict) # containing A, J, JT inivsoldict['fv_tmdp'] = None # don't want control here # import ipdb; ipdb.set_trace() inivsoldict.update(trange=np.array(lctrng), comp_nonl_semexp=True, return_dictofvelstrs=True) if whichinival == 'sstokes++': print('solving for `stokespp({0})` as inival'.format(tpp)) inivsoldict.update(iniv=None, start_ssstokes=True) else: inivsoldict.update(iniv=ret_v_ss_nse+reg_pertubini) print('solving for `nse+d+pp({0})` as inival'.format(tpp)) dcvlstrs = snu.solve_nse(**inivsoldict) sstokspp = dou.load_npa(dcvlstrs[tpp]) dou.save_npa(sstokspp, stksppdtstr) soldict.update(dict(iniv=sstokspp)) shortinivstr = 'sk{0}'.format(tpp) if whichinival == 'sstokes++' \ else 'nsk{0}'.format(tpp) return shortinivstr, ret_v_ss_nse
def test_qbdae_ass(problemname='cylinderwake', N=1, Re=None, nu=3e-2, t0=0.0, tE=1.0, Nts=100, use_saved_mats=None): trange = np.linspace(t0, tE, Nts + 1) DT = (tE - t0) / Nts rdir = 'results/' ddir = 'data/' if use_saved_mats is None: femp, stokesmatsc, rhsd_vfrc, rhsd_stbc = \ dns.problem_setups.get_sysmats(problem=problemname, N=N, Re=Re) invinds = femp['invinds'] A, J, M = stokesmatsc['A'], stokesmatsc['J'], stokesmatsc['M'] L = 0 * A fvc, fpc = rhsd_vfrc['fvc'], rhsd_vfrc['fpr'] fv_stbc, fp_stbc = rhsd_stbc['fv'], rhsd_stbc['fp'] hstr = ddir + problemname + '_N{0}_hmat'.format(N) try: hmat = dou.load_spa(hstr) print('loaded `hmat`') except IOError: print('assembling hmat ...') hmat = dnsts.ass_convmat_asmatquad(W=femp['V'], invindsw=invinds) dou.save_spa(hmat, hstr) invinds = femp['invinds'] NV, NP = invinds.shape[0], J.shape[0] zerv = np.zeros((NV, 1)) bc_conv, bc_rhs_conv, rhsbc_convbc = \ snu.get_v_conv_conts(prev_v=zerv, V=femp['V'], invinds=invinds, diribcs=femp['diribcs'], Picard=False) fp = fp_stbc + fpc fv = fv_stbc + fvc - bc_rhs_conv if linnsesol: vp_nse, _ = snu.\ solve_steadystate_nse(A=A, J=J, JT=None, M=M, fv=fv_stbc + fvc, fp=fp_stbc + fpc, V=femp['V'], Q=femp['Q'], invinds=invinds, diribcs=femp['diribcs'], return_vp=False, ppin=-1, N=N, nu=nu, clearprvdata=False) old_v = vp_nse[:NV] else: import sadptprj_riclyap_adi.lin_alg_utils as lau # Stokes solution as initial value vp_stokes = lau.solve_sadpnt_smw(amat=A, jmat=J, rhsv=fv_stbc + fvc, rhsp=fp_stbc + fpc) old_v = vp_stokes[:NV] sysmat = sps.vstack([ sps.hstack([M + DT * (A + bc_conv), J.T]), sps.hstack([J, sps.csc_matrix((NP, NP))]) ]) if use_saved_mats is not None: # if saved as in ../get_exp_mats import scipy.io mats = scipy.io.loadmat(use_saved_mats) A = -mats['A'] L = -mats['L'] Re = mats['Re'] N = A.shape[0] M = mats['M'] J = mats['J'] hmat = -mats['H'] fv = mats['fv'] fp = mats['fp'] NV, NP = fv.shape[0], fp.shape[0] old_v = mats['ss_stokes'] sysmat = sps.vstack([ sps.hstack([M + DT * A, J.T]), sps.hstack([J, sps.csc_matrix((NP, NP))]) ]) if compevs: import matplotlib.pyplot as plt import scipy.linalg as spla hlstr = ddir + problemname + '_N{0}_Re{1}Nse{2}_hlmat'.\ format(N, Re, linnsesol) HL = linearzd_quadterm(hmat, old_v, hlstr=hlstr) print(HL.shape) asysmat = sps.vstack([ sps.hstack([-(A - L + HL), J.T]), sps.hstack([J, sps.csc_matrix((NP, NP))]) ]) msysmat = sps.vstack([ sps.hstack([M, sps.csc_matrix((NV, NP))]), sps.hstack([sps.csc_matrix((NP, NV)), sps.csc_matrix((NP, NP))]) ]) levstr = ddir + problemname + '_N{0}Re{1}Nse{2}_levs'.\ format(N, Re, linnsesol) try: levs = dou.load_npa(levstr) if debug: raise IOError() print('loaded the eigenvalues of the linearized system') except IOError: print('computing the eigenvalues of the linearized system') A = asysmat.todense() M = msysmat.todense() levs = spla.eigvals(A, M, overwrite_a=True, check_finite=False) dou.save_npa(levs, levstr) plt.figure(1) # plt.xlim((-25, 15)) # plt.ylim((-50, 50)) plt.plot(np.real(levs), np.imag(levs), '+') plt.show(block=False) if timeint: print('computing LU once...') sysmati = spsla.factorized(sysmat) vfile = dolfin.File(rdir + problemname + 'qdae__vel.pvd') pfile = dolfin.File(rdir + problemname + 'qdae__p.pvd') prvoutdict = dict(V=femp['V'], Q=femp['Q'], vfile=vfile, pfile=pfile, invinds=invinds, diribcs=femp['diribcs'], vp=None, t=None, writeoutput=True) print('doing the time loop...') for t in trange: crhsv = M * old_v + DT * (fv - hmat * np.kron(old_v, old_v)) crhs = np.vstack([crhsv, fp]) vp_new = np.atleast_2d(sysmati(crhs.flatten())).T prvoutdict.update(dict(vp=vp_new, t=t)) dou.output_paraview(**prvoutdict) old_v = vp_new[:NV] print(t, np.linalg.norm(old_v))
def test_qbdae_ass(problemname='cylinderwake', N=1, Re=None, nu=3e-2, t0=0.0, tE=1.0, Nts=100, use_saved_mats=None): trange = np.linspace(t0, tE, Nts+1) DT = (tE-t0)/Nts rdir = 'results/' ddir = 'data/' if use_saved_mats is None: femp, stokesmatsc, rhsd_vfrc, rhsd_stbc = \ dns.problem_setups.get_sysmats(problem=problemname, N=N, Re=Re) invinds = femp['invinds'] A, J, M = stokesmatsc['A'], stokesmatsc['J'], stokesmatsc['M'] L = 0*A fvc, fpc = rhsd_vfrc['fvc'], rhsd_vfrc['fpr'] fv_stbc, fp_stbc = rhsd_stbc['fv'], rhsd_stbc['fp'] hstr = ddir + problemname + '_N{0}_hmat'.format(N) try: hmat = dou.load_spa(hstr) print('loaded `hmat`') except IOError: print('assembling hmat ...') hmat = dnsts.ass_convmat_asmatquad(W=femp['V'], invindsw=invinds) dou.save_spa(hmat, hstr) invinds = femp['invinds'] NV, NP = invinds.shape[0], J.shape[0] zerv = np.zeros((NV, 1)) bc_conv, bc_rhs_conv, rhsbc_convbc = \ snu.get_v_conv_conts(prev_v=zerv, V=femp['V'], invinds=invinds, diribcs=femp['diribcs'], Picard=False) fp = fp_stbc + fpc fv = fv_stbc + fvc - bc_rhs_conv if linnsesol: vp_nse, _ = snu.\ solve_steadystate_nse(A=A, J=J, JT=None, M=M, fv=fv_stbc + fvc, fp=fp_stbc + fpc, V=femp['V'], Q=femp['Q'], invinds=invinds, diribcs=femp['diribcs'], return_vp=False, ppin=-1, N=N, nu=nu, clearprvdata=False) old_v = vp_nse[:NV] else: import sadptprj_riclyap_adi.lin_alg_utils as lau # Stokes solution as initial value vp_stokes = lau.solve_sadpnt_smw(amat=A, jmat=J, rhsv=fv_stbc + fvc, rhsp=fp_stbc + fpc) old_v = vp_stokes[:NV] sysmat = sps.vstack([sps.hstack([M+DT*(A+bc_conv), J.T]), sps.hstack([J, sps.csc_matrix((NP, NP))])]) if use_saved_mats is not None: # if saved as in ../get_exp_mats import scipy.io mats = scipy.io.loadmat(use_saved_mats) A = - mats['A'] L = - mats['L'] Re = mats['Re'] N = A.shape[0] M = mats['M'] J = mats['J'] hmat = -mats['H'] fv = mats['fv'] fp = mats['fp'] NV, NP = fv.shape[0], fp.shape[0] old_v = mats['ss_stokes'] sysmat = sps.vstack([sps.hstack([M+DT*A, J.T]), sps.hstack([J, sps.csc_matrix((NP, NP))])]) if compevs: import matplotlib.pyplot as plt import scipy.linalg as spla hlstr = ddir + problemname + '_N{0}_Re{1}Nse{2}_hlmat'.\ format(N, Re, linnsesol) HL = linearzd_quadterm(hmat, old_v, hlstr=hlstr) print(HL.shape) asysmat = sps.vstack([sps.hstack([-(A-L+HL), J.T]), sps.hstack([J, sps.csc_matrix((NP, NP))])]) msysmat = sps.vstack([sps.hstack([M, sps.csc_matrix((NV, NP))]), sps.hstack([sps.csc_matrix((NP, NV)), sps.csc_matrix((NP, NP))])]) levstr = ddir + problemname + '_N{0}Re{1}Nse{2}_levs'.\ format(N, Re, linnsesol) try: levs = dou.load_npa(levstr) if debug: raise IOError() print('loaded the eigenvalues of the linearized system') except IOError: print('computing the eigenvalues of the linearized system') A = asysmat.todense() M = msysmat.todense() levs = spla.eigvals(A, M, overwrite_a=True, check_finite=False) dou.save_npa(levs, levstr) plt.figure(1) # plt.xlim((-25, 15)) # plt.ylim((-50, 50)) plt.plot(np.real(levs), np.imag(levs), '+') plt.show(block=False) if timeint: print('computing LU once...') sysmati = spsla.factorized(sysmat) vfile = dolfin.File(rdir + problemname + 'qdae__vel.pvd') pfile = dolfin.File(rdir + problemname + 'qdae__p.pvd') prvoutdict = dict(V=femp['V'], Q=femp['Q'], vfile=vfile, pfile=pfile, invinds=invinds, diribcs=femp['diribcs'], vp=None, t=None, writeoutput=True) print('doing the time loop...') for t in trange: crhsv = M*old_v + DT*(fv - hmat*np.kron(old_v, old_v)) crhs = np.vstack([crhsv, fp]) vp_new = np.atleast_2d(sysmati(crhs.flatten())).T prvoutdict.update(dict(vp=vp_new, t=t)) dou.output_paraview(**prvoutdict) old_v = vp_new[:NV] print(t, np.linalg.norm(old_v))
def solve_steadystate_nse(A=None, J=None, JT=None, M=None, fv=None, fp=None, V=None, Q=None, invinds=None, diribcs=None, return_vp=False, ppin=-1, N=None, nu=None, vel_pcrd_stps=10, vel_pcrd_tol=1e-4, vel_nwtn_stps=20, vel_nwtn_tol=5e-15, clearprvdata=False, vel_start_nwtn=None, get_datastring=None, data_prfx='', paraviewoutput=False, save_intermediate_steps=False, vfileprfx='', pfileprfx='', **kw): """ Solution of the steady state nonlinear NSE Problem using Newton's scheme. If no starting value is provided, the iteration is started with the steady state Stokes solution. Parameters ---------- A : (N,N) sparse matrix stiffness matrix aka discrete Laplacian, note the sign! M : (N,N) sparse matrix mass matrix J : (M,N) sparse matrix discrete divergence operator JT : (N,M) sparse matrix, optional discrete gradient operator, set to J.T if not provided fv, fp : (N,1), (M,1) ndarrays right hand sides restricted via removing the boundary nodes in the momentum and the pressure freedom in the continuity equation ppin : {int, None}, optional which dof of `p` is used to pin the pressure, defaults to `-1` return_vp : boolean, optional whether to return also the pressure, defaults to `False` vel_pcrd_stps : int, optional Number of Picard iterations when computing a starting value for the Newton scheme, cf. Elman, Silvester, Wathen: *FEM and fast iterative solvers*, 2005, defaults to `100` vel_pcrd_tol : real, optional tolerance for the size of the Picard update, defaults to `1e-4` vel_nwtn_stps : int, optional Number of Newton iterations, defaults to `20` vel_nwtn_tol : real, optional tolerance for the size of the Newton update, defaults to `5e-15` """ import sadptprj_riclyap_adi.lin_alg_utils as lau if get_datastring is None: get_datastring = get_datastr_snu if JT is None: JT = J.T NV = J.shape[1] # # Compute or load the uncontrolled steady state Navier-Stokes solution # norm_nwtnupd_list = [] vel_newtk, norm_nwtnupd = 0, 1 # a dict to be passed to the get_datastring function datastrdict = dict(time=None, meshp=N, nu=nu, Nts=None, data_prfx=data_prfx) if clearprvdata: cdatstr = get_datastring(**datastrdict) for fname in glob.glob(cdatstr + '*__vel*'): os.remove(fname) try: cdatstr = get_datastring(**datastrdict) norm_nwtnupd = dou.load_npa(cdatstr + '__norm_nwtnupd') vel_k = dou.load_npa(cdatstr + '__vel') norm_nwtnupd_list.append(norm_nwtnupd) print('found vel files') print('norm of last Nwtn update: {0}'.format(norm_nwtnupd)) print('... loaded from ' + cdatstr) if np.atleast_1d(norm_nwtnupd)[0] is None: norm_nwtnupd = None pass # nothing useful found elif norm_nwtnupd < vel_nwtn_tol: if not return_vp: return vel_k, norm_nwtnupd_list else: pfv = get_pfromv(v=vel_k[:NV, :], V=V, M=M, A=A, J=J, fv=fv, invinds=invinds, diribcs=diribcs) return (np.vstack([vel_k, pfv]), norm_nwtnupd_list) except IOError: print('no old velocity data found') norm_nwtnupd = None if paraviewoutput: cdatstr = get_datastring(**datastrdict) vfile = dolfin.File(vfileprfx + '__steadystates.pvd') pfile = dolfin.File(pfileprfx + '__steadystates.pvd') prvoutdict = dict(V=V, Q=Q, vfile=vfile, pfile=pfile, invinds=invinds, diribcs=diribcs, ppin=ppin, vp=None, t=None, writeoutput=True) else: prvoutdict = dict(writeoutput=False) # save 'if statements' here NV = A.shape[0] if vel_start_nwtn is None: vp_stokes = lau.solve_sadpnt_smw(amat=A, jmat=J, jmatT=JT, rhsv=fv, rhsp=fp) vp_stokes[NV:] = -vp_stokes[NV:] # pressure was flipped for symmetry # save the data cdatstr = get_datastring(**datastrdict) dou.save_npa(vp_stokes[:NV, ], fstring=cdatstr + '__vel') prvoutdict.update(dict(vp=vp_stokes)) dou.output_paraview(**prvoutdict) # Stokes solution as starting value vp_k = vp_stokes vel_k = vp_stokes[:NV, ] else: vel_k = vel_start_nwtn # Picard iterations for a good starting value for Newton for k in range(vel_pcrd_stps): (convc_mat, rhs_con, rhsv_conbc) = get_v_conv_conts(prev_v=vel_k, invinds=invinds, V=V, diribcs=diribcs, Picard=True) vp_k = lau.solve_sadpnt_smw(amat=A + convc_mat, jmat=J, jmatT=JT, rhsv=fv + rhs_con + rhsv_conbc, rhsp=fp) normpicupd = np.sqrt(m_innerproduct(M, vel_k - vp_k[:NV, :]))[0] print('Picard iteration: {0} -- norm of update: {1}'.format( k + 1, normpicupd)) vel_k = vp_k[:NV, ] vp_k[NV:] = -vp_k[NV:] # pressure was flipped for symmetry if normpicupd < vel_pcrd_tol: break # Newton iteration while (vel_newtk < vel_nwtn_stps and (norm_nwtnupd is None or norm_nwtnupd > vel_nwtn_tol or norm_nwtnupd == np.array(None))): vel_newtk += 1 cdatstr = get_datastring(**datastrdict) (convc_mat, rhs_con, rhsv_conbc) = get_v_conv_conts(vel_k, invinds=invinds, V=V, diribcs=diribcs) vp_k = lau.solve_sadpnt_smw(amat=A + convc_mat, jmat=J, jmatT=JT, rhsv=fv + rhs_con + rhsv_conbc, rhsp=fp) norm_nwtnupd = np.sqrt(m_innerproduct(M, vel_k - vp_k[:NV, :]))[0] vel_k = vp_k[:NV, ] vp_k[NV:] = -vp_k[NV:] # pressure was flipped for symmetry print('Steady State NSE: Newton iteration: {0} -- norm of update: {1}'. format(vel_newtk, norm_nwtnupd)) dou.save_npa(vel_k, fstring=cdatstr + '__vel') prvoutdict.update(dict(vp=vp_k)) dou.output_paraview(**prvoutdict) dou.save_npa(norm_nwtnupd, cdatstr + '__norm_nwtnupd') dou.output_paraview(**prvoutdict) # savetomatlab = True # if savetomatlab: # export_mats_to_matlab(E=None, A=None, matfname='matexport') if return_vp: return vp_k, norm_nwtnupd_list else: return vel_k, norm_nwtnupd_list
def solve_nse( A=None, M=None, J=None, JT=None, fv=None, fp=None, fvc=None, fpc=None, # TODO: this is to catch deprecated calls fv_tmdp=None, fv_tmdp_params={}, fv_tmdp_memory=None, iniv=None, lin_vel_point=None, stokes_flow=False, trange=None, t0=None, tE=None, Nts=None, V=None, Q=None, invinds=None, diribcs=None, output_includes_bcs=False, N=None, nu=None, ppin=-1, closed_loop=False, static_feedback=False, feedbackthroughdict=None, return_vp=False, tb_mat=None, c_mat=None, vel_nwtn_stps=20, vel_nwtn_tol=5e-15, nsects=1, loc_nwtn_tol=5e-15, loc_pcrd_stps=True, addfullsweep=False, vel_pcrd_stps=4, krylov=None, krpslvprms={}, krplsprms={}, clearprvdata=False, get_datastring=None, data_prfx='', paraviewoutput=False, vfileprfx='', pfileprfx='', return_dictofvelstrs=False, return_dictofpstrs=False, dictkeysstr=False, comp_nonl_semexp=False, return_as_list=False, verbose=True, start_ssstokes=False, **kw): """ solution of the time-dependent nonlinear Navier-Stokes equation .. math:: M\\dot v + Av + N(v)v + J^Tp = f \n Jv =g using a Newton scheme in function space, i.e. given :math:`v_k`, we solve for the update like .. math:: M\\dot v + Av + N(v_k)v + N(v)v_k + J^Tp = N(v_k)v_k + f, and trapezoidal rule in time. To solve an *Oseen* system (linearization about a steady state) or a *Stokes* system, set the number of Newton steps to one and provide a linearization point and an initial value. Parameters ---------- lin_vel_point : dictionary, optional contains the linearization point for the first Newton iteration * Steady State: {{`None`: 'path_to_nparray'}, {'None': nparray}} * Newton: {`t`: 'path_to_nparray'} defaults to `None` dictkeysstr : boolean, optional whether the `keys` of the result dictionaries are strings instead \ of floats, defaults to `False` fv_tmdp : callable f(t, v, dict), optional time-dependent part of the right-hand side, set to zero if None fv_tmdp_params : dictionary, optional dictionary of parameters to be passed to `fv_tmdp`, defaults to `{}` fv_tmdp_memory : dictionary, optional memory of the function output_includes_bcs : boolean, optional whether append the boundary nodes to the computed and stored \ velocities, defaults to `False` krylov : {None, 'gmres'}, optional whether or not to use an iterative solver, defaults to `None` krpslvprms : dictionary, optional to specify parameters of the linear solver for use in Krypy, e.g., * initial guess * tolerance * number of iterations defaults to `None` krplsprms : dictionary, optional parameters to define the linear system like * preconditioner ppin : {int, None}, optional which dof of `p` is used to pin the pressure, defaults to `-1` stokes_flow : boolean, optional whether to consider the Stokes linearization, defaults to `False` start_ssstokes : boolean, optional for your convenience, compute and use the steady state stokes solution as initial value, defaults to `False` nsects: int, optional in how many segments the trange is split up. (The newton iteration will be confined to the segments and, probably, converge faster than the global iteration), defaults to `1` loc_nwtn_tol: float, optional tolerance for the newton iteration on the segments, defaults to `1e-15` loc_pcrd_stps: boolean, optional whether to init with `vel_pcrd_stps` Picard steps on every section, if `False`, Picard iterations are performed only on the first section, defaults to `True` addfullsweep: boolean, optional whether to compute the newton iteration on the full `trange`, useful to check and for the plots, defaults to `False` Returns ------- dictofvelstrs : dictionary, on demand dictionary with time `t` as keys and path to velocity files as values dictofpstrs : dictionary, on demand dictionary with time `t` as keys and path to pressure files as values vellist : list, on demand list of the velocity solutions """ import sadptprj_riclyap_adi.lin_alg_utils as lau if fvc is not None or fpc is not None: # TODO: this is for catching calls raise UserWarning('deprecated use of `rhsd_vfrc`, use only `fv`, `fp`') if get_datastring is None: get_datastring = get_datastr_snu if paraviewoutput: prvoutdict = dict(V=V, Q=Q, invinds=invinds, diribcs=diribcs, vp=None, t=None, writeoutput=True, ppin=ppin) else: prvoutdict = dict(writeoutput=False) # save 'if statements' here if trange is None: trange = np.linspace(t0, tE, Nts + 1) if comp_nonl_semexp and lin_vel_point is not None: raise UserWarning('I am not sure what you want! ' + 'set either `lin_vel_point=None` ' + 'or `comp_nonl_semexp=False`! \n' + 'as it is, I will compute a linear case') if return_dictofpstrs: gpfvd = dict(V=V, M=M, A=A, J=J, fv=fv, fp=fp, diribcs=diribcs, invinds=invinds) NV, NP = A.shape[0], J.shape[0] if fv_tmdp is None: def fv_tmdp(time=None, curvel=None, **kw): return np.zeros((NV, 1)), None if iniv is None: if start_ssstokes: # Stokes solution as starting value (fv_tmdp_cont, fv_tmdp_memory) = fv_tmdp(time=0, **fv_tmdp_params) vp_stokes =\ lau.solve_sadpnt_smw(amat=A, jmat=J, jmatT=JT, rhsv=fv + fv_tmdp_cont, krylov=krylov, krpslvprms=krpslvprms, krplsprms=krplsprms, rhsp=fp) iniv = vp_stokes[:NV] else: raise ValueError('No initial value given') datastrdict = dict(time=None, meshp=N, nu=nu, Nts=trange.size - 1, data_prfx=data_prfx) if return_as_list: clearprvdata = True # we want the results at hand if clearprvdata: datastrdict['time'] = '*' cdatstr = get_datastring(**datastrdict) for fname in glob.glob(cdatstr + '__vel*'): os.remove(fname) for fname in glob.glob(cdatstr + '__p*'): os.remove(fname) def _atdct(cdict, t, thing): if dictkeysstr: cdict.update({'{0}'.format(t): thing}) else: cdict.update({t: thing}) def _gfdct(cdict, t): if dictkeysstr: return cdict['{0}'.format(t)] else: return cdict[t] if stokes_flow: vel_nwtn_stps = 1 vel_pcrd_stps = 0 print('Stokes Flow!') elif lin_vel_point is None: comp_nonl_semexp_inig = True if not comp_nonl_semexp: print(('No linearization point given - explicit' + ' treatment of the nonlinearity in the first Iteration')) else: cur_linvel_point = lin_vel_point comp_nonl_semexp_inig = False newtk, norm_nwtnupd = 0, 1 # check for previously computed velocities if lin_vel_point is None and not stokes_flow: try: datastrdict.update(dict(time=trange[-1])) cdatstr = get_datastring(**datastrdict) norm_nwtnupd = (dou.load_npa(cdatstr + '__norm_nwtnupd')).flatten() try: if norm_nwtnupd[0] is None: norm_nwtnupd = 1. except IndexError: norm_nwtnupd = 1. dou.load_npa(cdatstr + '__vel') print('found vel files') print('norm of last Nwtn update: {0}'.format(norm_nwtnupd)) print('... loaded from ' + cdatstr) if norm_nwtnupd < vel_nwtn_tol and not return_dictofvelstrs: return elif norm_nwtnupd < vel_nwtn_tol: # looks like converged -- check if all values are there # t0: datastrdict.update(dict(time=trange[0])) cdatstr = get_datastring(**datastrdict) dictofvelstrs = {} _atdct(dictofvelstrs, trange[0], cdatstr + '__vel') if return_dictofpstrs: dictofpstrs = {} # try: # p_old = dou.load_npa(cdatstr + '__p') # dictofpstrs = {} # _atdct(dictofpstrs, trange[0], cdatstr+'__p') # except: # p_old = get_pfromv(v=v_old, **gpfvd) # dou.save_npa(p_old, fstring=cdatstr + '__p') # _atdct(dictofpstrs, trange[0], cdatstr+'__p') for t in trange: datastrdict.update(dict(time=t)) cdatstr = get_datastring(**datastrdict) # test if the vels are there v_old = dou.load_npa(cdatstr + '__vel') # update the dict _atdct(dictofvelstrs, t, cdatstr + '__vel') try: p_old = dou.load_npa(cdatstr + '__p') _atdct(dictofpstrs, t, cdatstr + '__p') except: p_old = get_pfromv(v=v_old, **gpfvd) dou.save_npa(p_old, fstring=cdatstr + '__p') _atdct(dictofpstrs, t, cdatstr + '__p') if return_dictofpstrs: return dictofvelstrs, dictofpstrs else: return dictofvelstrs comp_nonl_semexp = False except IOError: norm_nwtnupd = 2 print('no old velocity data found') def _append_bcs_ornot(vvec): if output_includes_bcs: # make the switch here for better readibility vwbcs = dts.append_bcs_vec(vvec, vdim=V.dim(), invinds=invinds, diribcs=diribcs) return vwbcs else: return vvec def _get_mats_rhs_ts(mmat=None, dt=None, var_c=None, coeffmat_c=None, coeffmat_n=None, fv_c=None, fv_n=None, umat_c=None, vmat_c=None, umat_n=None, vmat_n=None, impeul=False): """ to be tweaked for different int schemes """ solvmat = M + 0.5 * dt * coeffmat_n rhs = M * var_c + 0.5 * dt * (fv_n + fv_c - coeffmat_c * var_c) if umat_n is not None: matvec = lau.mm_dnssps umat = 0.5 * dt * umat_n vmat = vmat_n # TODO: do we really need a PLUS here??' rhs = rhs + 0.5 * dt * matvec(umat_c, matvec(vmat_c, var_c)) else: umat, vmat = umat_n, vmat_n return solvmat, rhs, umat, vmat v_old = iniv # start vector for time integration in every Newtonit datastrdict['time'] = trange[0] cdatstr = get_datastring(**datastrdict) dou.save_npa(_append_bcs_ornot(v_old), fstring=cdatstr + '__vel') dictofvelstrs = {} _atdct(dictofvelstrs, trange[0], cdatstr + '__vel') if return_dictofpstrs: p_old = get_pfromv(v=v_old, **gpfvd) dou.save_npa(p_old, fstring=cdatstr + '__p') dictofpstrs = {} _atdct(dictofpstrs, trange[0], cdatstr + '__p') else: p_old = None if return_as_list: vellist = [] vellist.append(_append_bcs_ornot(v_old)) lensect = np.int(np.floor(trange.size / nsects)) loctrngs = [] for k in np.arange(nsects - 1): loctrngs.append(trange[k * lensect:(k + 1) * lensect + 1]) loctrngs.append(trange[(nsects - 1) * lensect:]) if addfullsweep: loctrngs.append(trange) realiniv = np.copy(iniv) if nsects == 1: loc_nwtn_tol = vel_nwtn_tol addfullsweep = False loctrngs = [trange] if loc_pcrd_stps: vel_loc_pcrd_steps = vel_pcrd_stps for loctrng in loctrngs: while (newtk < vel_nwtn_stps and norm_nwtnupd > loc_nwtn_tol): print('solve the NSE on the interval [{0}, {1}]'.format( loctrng[0], loctrng[-1])) if stokes_flow: newtk = vel_nwtn_stps elif comp_nonl_semexp_inig and not comp_nonl_semexp: pcrd_anyone = False print('explicit treatment of nonl. for initial guess') elif vel_pcrd_stps > 0 and not comp_nonl_semexp: vel_pcrd_stps -= 1 pcrd_anyone = True print('Picard iterations for initial value -- {0} left'.format( vel_pcrd_stps)) elif comp_nonl_semexp: pcrd_anyone = False newtk = vel_nwtn_stps print('No Newton iterations - explicit treatment' + 'of the nonlinerity') else: pcrd_anyone = False newtk += 1 print('Computing Newton Iteration {0}'.format(newtk)) v_old = iniv # start vector for time integration in every Newtonit try: if krpslvprms['krylovini'] == 'old': vp_old = np.vstack([v_old, np.zeros((NP, 1))]) elif krpslvprms['krylovini'] == 'upd': vp_old = np.vstack([v_old, np.zeros((NP, 1))]) vp_new = vp_old cts_old = loctrng[1] - loctrng[0] except (TypeError, KeyError): pass # no inival for krylov solver required vfile = dolfin.File(vfileprfx + '__timestep.pvd') pfile = dolfin.File(pfileprfx + '__timestep.pvd') prvoutdict.update( dict(vp=None, vc=iniv, pc=p_old, t=loctrng[0], pfile=pfile, vfile=vfile)) dou.output_paraview(**prvoutdict) # ## current values_c for application of trap rule if stokes_flow: convc_mat_c = sps.csr_matrix((NV, NV)) rhs_con_c, rhsv_conbc_c = np.zeros((NV, 1)), np.zeros((NV, 1)) else: if comp_nonl_semexp or comp_nonl_semexp_inig: prev_v = v_old else: try: prev_v = dou.load_npa( _gfdct(cur_linvel_point, loctrng[0])) except KeyError: try: prev_v = dou.load_npa( _gfdct(cur_linvel_point, None)) except TypeError: prev_v = cur_linvel_point[None] convc_mat_c, rhs_con_c, rhsv_conbc_c = \ get_v_conv_conts(prev_v=iniv, invinds=invinds, V=V, diribcs=diribcs, Picard=pcrd_anyone) (fv_tmdp_cont, fv_tmdp_memory) = fv_tmdp(time=0, curvel=v_old, memory=fv_tmdp_memory, **fv_tmdp_params) fvn_c = fv + rhsv_conbc_c + rhs_con_c + fv_tmdp_cont if closed_loop: if static_feedback: mtxtb_c = dou.load_npa(feedbackthroughdict[None]['mtxtb']) w_c = dou.load_npa(feedbackthroughdict[None]['w']) # print '\nnorm of feedback: ', np.linalg.norm(mtxtb_c) else: mtxtb_c = dou.load_npa(feedbackthroughdict[0]['mtxtb']) w_c = dou.load_npa(feedbackthroughdict[0]['w']) fvn_c = fvn_c + tb_mat * (tb_mat.T * w_c) vmat_c = mtxtb_c.T try: umat_c = np.array(tb_mat.todense()) except AttributeError: umat_c = tb_mat else: vmat_c = None umat_c = None norm_nwtnupd = 0 if verbose: print('time to go') for tk, t in enumerate(loctrng[1:]): cts = t - loctrng[tk] datastrdict.update(dict(time=t)) cdatstr = get_datastring(**datastrdict) if verbose: sys.stdout.write("\rEnd: {1} -- now: {0:f}".format( t, loctrng[-1])) sys.stdout.flush() # prv_datastrdict = copy.deepcopy(datastrdict) # coeffs and rhs at next time instance if stokes_flow: convc_mat_n = sps.csr_matrix((NV, NV)) rhs_con_n = np.zeros((NV, 1)) rhsv_conbc_n = np.zeros((NV, 1)) else: if comp_nonl_semexp or comp_nonl_semexp_inig: prev_v = v_old else: try: prev_v = dou.load_npa(_gfdct(cur_linvel_point, t)) except KeyError: try: prev_v = dou.load_npa( _gfdct(cur_linvel_point, None)) except TypeError: prev_v = cur_linvel_point[None] convc_mat_n, rhs_con_n, rhsv_conbc_n = \ get_v_conv_conts(prev_v=prev_v, invinds=invinds, V=V, diribcs=diribcs, Picard=pcrd_anyone) (fv_tmdp_cont, fv_tmdp_memory) = fv_tmdp(time=t, curvel=v_old, memory=fv_tmdp_memory, **fv_tmdp_params) fvn_n = fv + rhsv_conbc_n + rhs_con_n + fv_tmdp_cont if closed_loop: if static_feedback: mtxtb_n = dou.\ load_npa(feedbackthroughdict[None]['mtxtb']) w_n = dou.load_npa(feedbackthroughdict[None]['w']) # fb = np.dot(tb_mat*mtxtb_n.T, v_old) # print '\nnorm of feedback: ', np.linalg.norm(fb) # print '\nnorm of v_old: ', np.linalg.norm(v_old) else: mtxtb_n = dou.load_npa(feedbackthroughdict[t]['mtxtb']) w_n = dou.load_npa(feedbackthroughdict[t]['w']) fvn_n = fvn_n + tb_mat * (tb_mat.T * w_n) vmat_n = mtxtb_n.T try: umat_n = np.array(tb_mat.todense()) except AttributeError: umat_n = tb_mat else: vmat_n = None umat_n = None (solvmat, rhsv, umat, vmat) = _get_mats_rhs_ts(mmat=M, dt=cts, var_c=v_old, coeffmat_c=A + convc_mat_c, coeffmat_n=A + convc_mat_n, fv_c=fvn_c, fv_n=fvn_n, umat_c=umat_c, vmat_c=vmat_c, umat_n=umat_n, vmat_n=vmat_n) try: if krpslvprms['krylovini'] == 'old': krpslvprms['x0'] = vp_old elif krpslvprms['krylovini'] == 'upd': vp_oldold = vp_old vp_old = vp_new krpslvprms['x0'] = vp_old + \ cts*(vp_old - vp_oldold)/cts_old cts_old = cts except (TypeError, KeyError): pass # no inival for krylov solver required vp_new = lau.solve_sadpnt_smw(amat=solvmat, jmat=J, jmatT=JT, rhsv=rhsv, rhsp=fp, krylov=krylov, krpslvprms=krpslvprms, krplsprms=krplsprms, umat=umat, vmat=vmat) v_old = vp_new[:NV, ] (umat_c, vmat_c, fvn_c, convc_mat_c) = umat_n, vmat_n, fvn_n, convc_mat_n dou.save_npa(_append_bcs_ornot(v_old), fstring=cdatstr + '__vel') _atdct(dictofvelstrs, t, cdatstr + '__vel') p_new = -1 / cts * vp_new[NV:, ] # p was flipped and scaled for symmetry if return_dictofpstrs: dou.save_npa(p_new, fstring=cdatstr + '__p') _atdct(dictofpstrs, t, cdatstr + '__p') if return_as_list: vellist.append(_append_bcs_ornot(v_old)) prvoutdict.update(dict(vc=v_old, pc=p_new, t=t)) dou.output_paraview(**prvoutdict) # integrate the Newton error if stokes_flow or comp_nonl_semexp: norm_nwtnupd = None elif comp_nonl_semexp_inig: norm_nwtnupd = 1. else: if len(prev_v) > len(invinds): prev_v = prev_v[invinds, :] addtonwtnupd = cts * m_innerproduct(M, v_old - prev_v) norm_nwtnupd += np.float(addtonwtnupd.flatten()[0]) dou.save_npa(norm_nwtnupd, cdatstr + '__norm_nwtnupd') print('\nnorm of current Newton update: {}'.format(norm_nwtnupd)) # print('\nsaved `norm_nwtnupd(={0})'.format(norm_nwtnupd) + # ' to ' + cdatstr) comp_nonl_semexp = False comp_nonl_semexp_inig = False cur_linvel_point = dictofvelstrs iniv = v_old if not comp_nonl_semexp: comp_nonl_semexp_inig = True if addfullsweep and loctrng is loctrngs[-2]: comp_nonl_semexp_inig = False iniv = realiniv loc_nwtn_tol = vel_nwtn_tol elif loc_pcrd_stps: vel_pcrd_stps = vel_loc_pcrd_steps norm_nwtnupd = 1. newtk = 0 if return_dictofvelstrs: if return_dictofpstrs: return dictofvelstrs, dictofpstrs else: return dictofvelstrs elif return_as_list: return vellist else: return
def solve_flow_daeric(mmat=None, amat=None, jmat=None, bmat=None, cmat=None, rhsv=None, rhsp=None, mcmat=None, v_is_my=False, rmat=None, vmat=None, gamma=1.0, tmesh=None, ystarvec=None, nwtn_adi_dict=None, curnwtnsdict=None, comprz_thresh=None, comprz_maxc=None, save_full_z=False, get_tdpart=None, gttdprtargs=None, get_datastr=None, gtdtstrargs=None, check_c_consist=True): """ Routine for the solution of the DAE Riccati .. math:: \\dot{MXM^T} + F^TXM + M^TXM + M^TXGXM + L(Y) = W \\\\ JXM = 0 \\quad \\text{and} \\quad M^TXJ = 0 \\\\ M^TX(T)M = W where :math:`F=A+N(t)`, where :math:`W:=C^T V C`, :math:`G:=B R^{-1} B^T`, and where :math:`L(Y)` is the Lagrange multiplier term. Simultaneously we solve for the feedforward term :math:`w`: .. math:: \\dot{M^Tw} - [M^TXG+F^T]w - J^Tv = C^T V y^* + M^T[Xf + Yg] \\\\ Jw = 0 \\\\ M^Tw(T) = C^T V y^*(T) Note that :math:`V=M_y` if the norm of :math:`Y` is used in the cost function. Parameters ---------- cmat : (NY, NV) array the (regularized aka projected) output matrix mcmat : (NY, NV) array output matrix times the mass matrix in the output space gamma : float, optional weighting parameter for penalization of the terminal value, TODO: rather provide the right weighting matrix V, defaults to `1.0` v_is_my : boolean whether the weighting matrix is the same as the mass matrix, \ defaults to `False` get_tdpart : callable f(t) returns the `mattd, rhstd` -- time dependent coefficients matrices and right hand side at time `t` gtdtstrargs : dictionary **kwargs to the current data string gttdprtargs : dictionary `**kwargs` to get_tdpart Returns ------- feedbackthroughdict : dictionary with time instances as keys and | `w` -- the current feedthrough value | `mtxtb` -- the current feedback gain part `(R.-1/2 * B.T * X * M).T` as values """ if check_c_consist: if v_is_my and mcmat is not None: mic = lau.apply_massinv(mmat.T, mcmat.T) if np.linalg.norm(jmat*mic) > 1e-12: raise Warning('mcmat.T needs to be in the kernel of J*M.-1') elif cmat is not None: mic = lau.apply_massinv(mmat.T, cmat.T) if np.linalg.norm(jmat*mic) > 1e-12: raise Warning('cmat.T needs to be in the kernel of J*M.-1') MT, AT, NV = mmat.T, amat.T, amat.shape[0] gtdtstrargs.update(time=tmesh[-1]) cdatstr = get_datastr(**gtdtstrargs) # set/compute the terminal values aka starting point if v_is_my and mcmat is not None: tct_mat = lau.apply_invsqrt_fromright(vmat, mcmat.T, output='dense') else: tct_mat = lau.apply_sqrt_fromright(vmat, cmat.T, output='dense') # TODO: good handling of bmat and umasmat tb_mat = lau.apply_invsqrt_fromright(rmat, bmat, output='sparse') # bmat_rpmo = bmat * np.linalg.inv(np.array(rmat.todense())) Zc = np.sqrt(gamma)*lau.apply_massinv(mmat, tct_mat) mtxtb = -pru.get_mTzzTtb(mmat.T, Zc, tb_mat) # mtxbrm = pru.get_mTzzTtb(mmat.T, Zc, bmat_rpmo) dou.save_npa(Zc, fstring=cdatstr + '__Z') dou.save_npa(mtxtb, fstring=cdatstr + '__mtxtb') if ystarvec is not None: wc = lau.apply_massinv(MT, gamma*np.dot(mcmat.T, ystarvec(tmesh[-1]))) dou.save_npa(wc, fstring=cdatstr + '__w') else: wc = None feedbackthroughdict = {tmesh[-1]: dict(w=cdatstr + '__w', mtxtb=cdatstr + '__mtxtb')} # save the end values if curnwtnsdict is not None: dou.save_npa(wc, fstring=curnwtnsdict[tmesh[-1]]['w']) dou.save_npa(mtxtb, fstring=curnwtnsdict[tmesh[-1]]['mtxtb']) # time integration for tk, t in reversed(list(enumerate(tmesh[:-1]))): cts = tmesh[tk+1] - t print 'Time is {0}, timestep is {1}'.\ format(t, cts) # get the previous time time-dep matrices gtdtstrargs.update(time=t) cdatstr = get_datastr(**gtdtstrargs) nmattd, rhsvtd = get_tdpart(time=t, **gttdprtargs) # get the feedback from the current newton step if curnwtnsdict is not None: try: cnsw = dou.load_npa(curnwtnsdict[t]['w']) cnsmtxtb = dou.load_npa(curnwtnsdict[t]['mtxtb']) except IOError: cnsw, cnsmtxtb = None, None else: cnsw, cnsmtxtb = None, None try: Zc = dou.load_npa(cdatstr + '__Z') except IOError: # coeffmat for nwtn adi ft_mat = -(0.5*MT + cts*(AT + nmattd.T)) # rhs for nwtn adi w_mat = np.hstack([MT*Zc, np.sqrt(cts)*tct_mat]) # feedback from a previous Newton step mtxb = np.sqrt(cts)*cnsmtxtb if cnsmtxtb is not None else None Zp = pru.proj_alg_ric_newtonadi(mmat=MT, amat=ft_mat, transposed=True, mtxoldb=mtxb, jmat=jmat, bmat=np.sqrt(cts)*tb_mat, wmat=w_mat, z0=Zc, nwtn_adi_dict=nwtn_adi_dict )['zfac'] if comprz_maxc is not None or comprz_thresh is not None: Zc = pru.compress_Zsvd(Zp, thresh=comprz_thresh, k=comprz_maxc) else: Zc = Zp if save_full_z: dou.save_npa(Zp, fstring=cdatstr + '__Z') else: dou.save_npa(Zc, fstring=cdatstr + '__Z') # and the affine correction at_mat = MT + cts*(AT + nmattd.T) # current rhs ftilde = rhsvtd + rhsv # apply the feedback and through if cnsw is not None: ftilde = rhsvtd + rhsv + cnsw cnsmtxtb = cnsmtxtb + mtxtb if cnsmtxtb is not None else mtxtb mtxft = pru.get_mTzzTtb(MT, Zc, ftilde) fl1 = np.dot(mcmat.T, ystarvec(t)) rhswc = MT*wc + cts*(fl1 - mtxft) mtxtb = -pru.get_mTzzTtb(MT, Zc, tb_mat) # mtxtbrm = pru.get_mTzzTtb(MT, Zc, bmat_rpmo) wc = lau.solve_sadpnt_smw(amat=at_mat, jmat=jmat, umat=cts*cnsmtxtb, vmat=tb_mat.T, rhsv=rhswc)[:NV] # wc = lau.solve_sadpnt_smw(amat=at_mat, jmat=jmat, # umat=-cts*mtxbrm, vmat=bmat.T, # rhsv=rhswc)[:NV] # update the feedback in Newton if curnwtnsdict is not None: cnsw = cnsw + wc if cnsw is not None else wc cnsmtxtb = cnsmtxtb + mtxtb if cnsmtxtb is not None else mtxtb dou.save_npa(cnsw, fstring=curnwtnsdict[t]['w']) dou.save_npa(cnsmtxtb, fstring=curnwtnsdict[t]['mtxtb']) dou.save_npa(wc, fstring=cdatstr + '__w') dou.save_npa(mtxtb, fstring=cdatstr + '__mtxtb') # dou.save_npa(mtxbrm, fstring=cdatstr + '__mtxbrm') feedbackthroughdict.update({t: dict(w=cdatstr + '__w', # mtxbrm=cdatstr + '__mtxbrm')}) mtxtb=cdatstr + '__mtxtb')}) return feedbackthroughdict