def get_genpodmats(sol=None, poddim=None, sdim=None, tmesh=None, plotsvs=False, basfuntype='pl'): Yg, My = get_genmeasuremat(sol=sol, sdim=sdim, tmesh=tmesh, basfuntype=basfuntype) Ygminvsqrt = lau.apply_invsqrt_fromright(My, Yg) U, S, V = np.linalg.svd(Ygminvsqrt) Uk = U[:, 0:poddim] if plotsvs: plt.figure(222) plt.plot(S, 'o', label='genPOD') plt.semilogy() plt.title('Singular Values of the generalized measurement matrix') plt.legend() plt.show(block=False) print 'POD-ratio: {0}'.format(np.sum(S[0:poddim]) / np.sum(S)) return Uk
def get_podbases(measmat=None, nlsvecs=0, nrsvecs=0, plotsvs=False, sqrtlm=None, sqrtrm=None, invsqrtlm=None, invsqrtrm=None, retsvals=False): if sqrtlm is not None: print('apply mass sqrt : This part will be deprecated soon') measmat = lau.apply_sqrt_fromright(sqrtlm, measmat.T).T if sqrtrm is not None: measmat = lau.apply_sqrt_fromright(sqrtrm, measmat) print('apply mass sqrt : This part will be deprecated soon') if invsqrtlm is not None: measmat = lau.apply_invsqrt_fromright(invsqrtlm, measmat.T).T print('apply mass sqrt : This part will be deprecated soon') if invsqrtrm is not None: measmat = lau.apply_invsqrt_fromright(invsqrtrm, measmat) print('apply mass sqrt : This part will be deprecated soon') U, S, V = np.linalg.svd(measmat) Uk = U[:, 0:nlsvecs] Vk = V[:nrsvecs, :] if plotsvs: plt.figure(222) plt.plot(S, 'o', label='genPOD') plt.semilogy() plt.title('Singular Values of the generalized measurement matrix') plt.legend() plt.show(block=False) if retsvals: return Uk, Vk, S else: return Uk, Vk
def get_genpodmats(Y, poddim, k, tmesh, plotsvs=False): Yg, My = gpu.massPL(Y, k, tmesh, haar=True) Ygminvsqrt = lau.apply_invsqrt_fromright(My, Yg) U, S, V = np.linalg.svd(Ygminvsqrt) Uk = U[:, 0:poddim] if plotsvs: plt.plot(S, label='genPOD') plt.semilogy() plt.title('Singular Values of the generalized measurement matrix') plt.legend() plt.show(block=False) print 'POD-ratio: {0}'.format(np.sum(S[0:poddim]) / np.sum(S)) return Uk
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_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
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)