def _dywdy(t, V=None): cvel = np.load(veldict[t]+'.npy') delty = ystar(t) - lau.mm_dnssps(cmat, cvel) if V is None: return np.dot(delty.T, lau.mm_dnssps(W, delty)) else: return np.dot(delty.T, lau.mm_dnssps(V, delty))
def _dywdy(t, V=None): cvel = np.load(veldict[t] + '.npy') delty = ystar(t) - lau.mm_dnssps(cmat, cvel) if V is None: return np.dot(delty.T, lau.mm_dnssps(W, delty)) else: return np.dot(delty.T, lau.mm_dnssps(V, delty))
def timspanorm(x, mspace=None, mtime=None): ynorml = [] for col in range(x.shape[1]): ccol = x[:, col] ynorml.append(np.dot(ccol.T, lau.mm_dnssps(mspace, ccol))) ynormvec = np.array(ynorml).reshape((x.shape[1], 1)) return np.sqrt(np.dot(ynormvec.T, lau.mm_dnssps(mtime, ynormvec)))
def burger_fwd_gpresidual(ms=None, ay=None, dms=None, rhs=None, my=None, iniv=None, htittl=None, uvvdxl=None): """ function to return the residuals of the burger genpod apprxm DEPRECATED """ import spacetime_pod_utils as spu if rhs is not None and np.linalg.norm(rhs) > 0: raise NotImplementedError('rhs not considered in the alg') # lns = ms.shape[0] # dimension of time disc lnq = ay.shape[0] # dimension of space disc dmsz = dms[1:, :1] # the part of the mass matrix related to the ini value msz = ms[1:, :1] dmsI = dms[1:, 1:] # mass matrices w/o ini values (test and trial) msI = ms[1:, 1:] def _nonlinres(tsvec): def evabrgquadterm(tvvec): return eva_burger_quadratic(tvvec=tvvec, htittl=htittl, uvvdxl=uvvdxl) bres = spu.get_spacetimepodres(tvvec=tsvec, dms=dms, ms=ms, my=my, ared=ay, nfunc=evabrgquadterm, rhs=None, retnorm=False, iniv=iniv) return bres[0 * lnq:, ].flatten() solmat = np.kron(dmsI, my) + np.kron(msI, ay) linrhs = - np.kron(dmsz, lau.mm_dnssps(my, iniv)) \ - np.kron(msz, lau.mm_dnssps(ay, iniv)) def _linres(tsvec): tsvecs = tsvec.reshape((tsvec.size, 1)) lres = (np.dot(solmat, tsvecs) - linrhs) return lres.flatten() def _lrprime(tsvec): return solmat
def sollintimspasys(dms=None, ms=None, ay=None, my=None, iniv=None, opti=False): lns = ms.shape[0] lnq = ay.shape[0] dmsz = dms[1:, :1] msz = ms[1:, :1] dmsI = dms[1:, 1:] msI = ms[1:, 1:] solmat = np.kron(dmsI, my) + np.kron(msI, ay) rhs = -np.kron(dmsz, lau.mm_dnssps(my, iniv)) \ - np.kron(msz, lau.mm_dnssps(ay, iniv)) if opti: import scipy.optimize as sco def _linres(tsvec): tsvecs = tsvec.reshape((tsvec.size, 1)) lres = (np.dot(solmat, tsvecs) - rhs) return lres.flatten() def _lrprime(tsvec): return solmat sol = sco.fsolve(_linres, np.zeros(((lns - 1) * lnq, )), fprime=_lrprime) else: sol = np.linalg.solve(solmat, rhs) fsol = np.hstack([iniv, sol.reshape((lns - 1, lnq)).T]) return fsol
def space_time_norm(errvecsqrd=None, tmesh=None, spatimvals=None, spacemmat=None): """ compute the space time norm `int_T |v(t)|_M dt` (with the squares and roots) using the piecewise trapezoidal rule in time """ if errvecsqrd is None: errvecsql = [] for row in range(spatimvals.shape[0]): crow = spatimvals[row, :] errvecsql.append(np.dot(crow.T, lau.mm_dnssps(spacemmat, crow))) errvecsqrd = np.array(errvecsql) dtvec = tmesh[1:] - tmesh[:-1] trapv = 0.5 * (errvecsqrd[:-1] + errvecsqrd[1:]) errvsqrd = (dtvec * trapv).sum() return np.sqrt(errvsqrd)
def _bbwdrhs(t): # TODO: -----------------------------> here we need vstar return (-lau.mm_dnssps(MLV, vfun(te - t)).flatten() + lau.mm_dnssps(MLV, _vstarfun(te - t)).flatten())
def _contrl_rhs(t): if t > tE: # the integrator may require values outside [t0, tE] return rhs(t).flatten() + lau.mm_dnssps(MVU, ufun(tE)).flatten() else: return rhs(t).flatten() + lau.mm_dnssps(MVU, ufun(t)).flatten()
def compare_stepresp(tmesh=None, a_mat=None, c_mat=None, b_mat=None, m_mat=None, tl=None, tr=None, iniv=None, fullresp=None, fsr_soldict=None, plot=False, jsonstr=None): """ compare the system's step response to unit inputs in time domain with reduced system's response. We consider the system .. math:: M\\dot v = Av + Bu, \\quad y = Cv on the discretized time interval :math:`(t_0, t_E)` and the reduced system with :math:`\\hat A = t_l^TAt_r`. Parameters ---------- tmesh : iterable list or ndarray vector of the time instances a_mat : (N,N) sparse matrix system matrix c_mat : (ny,N) sparse matrix or ndarray output matrix b_mat : (N,nu) sparse matrix or ndarray input operator m_mat : (N,N) sparse matrix mass matrix tl, tr : (N,K) ndarrays left, right transformation for the reduced system iniv : (N,1) ndarray initial value and linearization point of the full system fullresp : callable f(v, **dict) returns the response of the full system fsr_soldict : dictionary parameters to be passed to `fullresp` plot : boolean, optional whether to plot, defaults to `False` jsonstr: string, optional if defined, the output is stored in this json file, defaults to `None` """ from scipy.integrate import odeint ahat = np.dot(tl.T, a_mat*tr) chat = lau.mm_dnssps(c_mat, tr) inivhat = np.dot(tl.T, m_mat*iniv) inivout = lau.mm_dnssps(c_mat, iniv).tolist() red_stp_rsp, ful_stp_rsp = [], [] for ccol in [0]: # , b_mat.shape[1]-1]: # range(2): # b_mat.shape[1]): bmc = b_mat[:, ccol][:, :] red_bmc = tl.T * bmc def dtfunc(v, t): return (np.dot(ahat, v).flatten() + red_bmc.flatten()) # +\ red_state = odeint(dtfunc, 0*inivhat.flatten(), tmesh) red_stp_rsp.append(np.dot(chat, red_state.T).T.tolist()) ful_stp_rsp.append(fullresp(bcol=bmc, trange=tmesh, ini_vel=iniv, cmat=c_mat, soldict=fsr_soldict)) if jsonstr: try: tmesh = tmesh.tolist() except AttributeError: pass # is a list already dou.save_output_json(datadict={"tmesh": tmesh, "ful_stp_rsp": ful_stp_rsp, "red_stp_rsp": red_stp_rsp, "inivout": inivout}, fstring=jsonstr, module='sadptprj_riclyap_adi.bal_trunc_utils', plotroutine='plot_step_resp') if plot: plot_step_resp(tmesh=tmesh, red_stp_rsp=red_stp_rsp, ful_stp_rsp=ful_stp_rsp, inivout=inivout)
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
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)
def _mm_nonednssps(A, vvec): if A is None: return 0 * vvec else: return lau.mm_dnssps(A, vvec)
dmsz = rbd['hdms'][1:, :1] # part of the mass matrix related to the ini value msz = rbd['hms'][1:, :1] dmsI = rbd['hdms'][1:, 1:] # mass matrices w/o ini values (test and trial) msI = rbd['hms'][1:, 1:] solmat = np.kron(dmsI, rbd['hmy']) + np.kron(msI, rbd['hay']) hshysol = np.dot(Ukslin.T, np.dot(xlin.T, Ukylin)) hshysolvec = hshysol.reshape((hs*hq, 1), order='C') inivlin = hshysolvec[:hq, :] insollin = hshysolvec[hq:, :] linrhs = - np.kron(dmsz, lau.mm_dnssps(rbd['hmy'], inivlin)) \ - np.kron(msz, lau.mm_dnssps(rbd['hay'], inivlin)) print 'residual projsol: ', norm(np.dot(solmat, insollin) - linrhs) print norm(xlin.T - np.dot(Ukslin, np.dot(hshysol, Ukylin.T))) linsyssolvec = np.linalg.solve(solmat, linrhs) diff = linsyssolvec - insollin print 'diff ', norm(diff) print 'residual linsyssol: ', norm(np.dot(solmat, linsyssolvec) - linrhs) print 'cond A ', np.linalg.cond(solmat) linsyssol = linsyssolvec.reshape((hs-1, hq)) plotmat(vvl, fignum=113) plotmat(np.dot(Ukslin, np.dot(hshysol, Ukylin.T)), fignum=114) plotmat(linsyssol, fignum=115)
def proj_alg_ric_newtonadi(mmat=None, amat=None, jmat=None, bmat=None, wmat=None, z0=None, mtxoldb=None, transposed=False, nwtn_adi_dict=dict(adi_max_steps=150, adi_newZ_reltol=1e-5, nwtn_max_steps=14, nwtn_upd_reltol=1e-8), **kw): """ solve the projected algebraic ricc via newton adi `M.T*X*A + A.T*X*M - M.T*X*B*B.T*X*M + J(Y) = -WW.T` `JXM = 0 and M.TXJ.T = 0` If `mtxb` is given, (e.g. as the feedback computed in a previous step of a Newton iteration), the coefficient matrix with feedback `A.T <- A.T - mtxb*b` is considered """ if transposed: mt, at = mmat, amat else: mt, at = mmat.T, amat.T loctransposed = True if sps.isspmatrix(wmat): wmat = np.array(wmat.todense()) znc = z0 nwtn_stp, upd_fnorm, upd_fnorm_n = 0, None, None nwtn_upd_fnorms = [] # import pdb # pdb.set_trace() while nwtn_stp < nwtn_adi_dict['nwtn_max_steps']: if znc is None: # i.e., if z0 was None rhsadi = wmat mtxbt = None else: mtxb = mt * np.dot(znc, lau.mm_dnssps(znc.T, bmat)) mtxbt = mtxb.T rhsadi = np.hstack([mtxb, wmat]) # to avoid a dense matrix we use the smw formula # to compute (A-UV).-T # for the factorization mTxg.T = tb * mTxtb.T = U*V # and we add the previous feedback: if mtxoldb is not None: mtxbt = mtxbt + mtxoldb.T znn = solve_proj_lyap_stein(amat=at, mmat=mt, jmat=jmat, wmat=rhsadi, umat=bmat, vmat=mtxbt, transposed=loctransposed, nwtn_adi_dict=nwtn_adi_dict)['zfac'] if nwtn_adi_dict['full_upd_norm_check']: if znc is None: # there was no initial guess znc = 0*znn upd_fnorm = lau.comp_sqfnrm_factrd_diff(znn, znc) upd_fnorm = np.sqrt(np.abs(upd_fnorm)) else: if znc is None: # there was no initial guess znc = 0*znn vec = np.random.randn(znn.shape[0], 1) vecn1 = comp_diff_zzv(znn, znc, vec) vec = np.random.randn(znn.shape[0], 1) vecn2 = comp_diff_zzv(znn, znc, vec) vec = np.random.randn(znn.shape[0], 1) # to make the estimate relative vecn3 = np.linalg.norm(np.dot(znn, np.dot(znn.T, vec))) if (vecn2 + vecn1)/vecn3 < 8e-9: upd_fnorm, nzn, nzc = lau.\ comp_sqfnrm_factrd_diff(znn, znc, ret_sing_norms=True) upd_fnorm_n = np.sqrt(np.abs(upd_fnorm) / np.abs(nzn)) nwtn_upd_fnorms.append(upd_fnorm_n) try: if np.allclose(upd_fnorm_n, upd_fnorm): print('no more change in the norm of the update... break') break except TypeError: pass if nwtn_adi_dict['full_upd_norm_check']: upd_fnorm = upd_fnorm_n elif (vecn2 + vecn1)/vecn3 < 8e-9: upd_fnorm = upd_fnorm_n try: if nwtn_adi_dict['verbose']: print(('Newton ADI step: {1} -- ' + 'rel f norm of update: {0}').format(upd_fnorm, nwtn_stp + 1)) if not nwtn_adi_dict['full_upd_norm_check']: print(('btw, we decided whether to compute the actual ' + 'norm on the base of estimates:')) print('|| upd * vec || / || vec || = {0}'.format(vecn2)) print('||Z*vec|| = {0}'.format(vecn3)) except KeyError: pass # no verbosity specified - nothing is shown znc = znn nwtn_stp += 1 if (upd_fnorm is not None and upd_fnorm < nwtn_adi_dict['nwtn_upd_reltol']): break return dict(zfac=znn, nwtn_upd_fnorms=nwtn_upd_fnorms)
def _bbwdrhs(t): # TODO: -----------------------------> here we need vstar return (-lau.mm_dnssps(LVhmy, redvfun(te - t)).flatten() + lau.mm_dnssps(LVhmy, _redvstarfun(t)).flatten())
def _bbwdnl_vdx(lvec, t): vdx = vdxoperator(vfun(te - t)) return -(lau.mm_dnssps(vdx, lvec)).flatten()
def redmatfunc(vvec): return np.dot(lau.mm_dnssps(ULk.T, matfunc(np.dot(UVk, vvec))), ULk)
def compare_stepresp(tmesh=None, a_mat=None, c_mat=None, b_mat=None, m_mat=None, tl=None, tr=None, iniv=None, fullresp=None, fsr_soldict=None, plot=False, jsonstr=None): """ compare the system's step response to unit inputs in time domain with reduced system's response. We consider the system .. math:: M\\dot v = Av + Bu, \\quad y = Cv on the discretized time interval :math:`(t_0, t_E)` and the reduced system with :math:`\\hat A = t_l^TAt_r`. Parameters ---------- tmesh : iterable list or ndarray vector of the time instances a_mat : (N,N) sparse matrix system matrix c_mat : (ny,N) sparse matrix or ndarray output matrix b_mat : (N,nu) sparse matrix or ndarray input operator m_mat : (N,N) sparse matrix mass matrix tl, tr : (N,K) ndarrays left, right transformation for the reduced system iniv : (N,1) ndarray initial value and linearization point of the full system fullresp : callable f(v, **dict) returns the response of the full system fsr_soldict : dictionary parameters to be passed to `fullresp` plot : boolean, optional whether to plot, defaults to `False` jsonstr: string, optional if defined, the output is stored in this json file, defaults to `None` """ from scipy.integrate import odeint ahat = np.dot(tl.T, a_mat * tr) chat = lau.mm_dnssps(c_mat, tr) inivhat = np.dot(tl.T, m_mat * iniv) inivout = lau.mm_dnssps(c_mat, iniv).tolist() red_stp_rsp, ful_stp_rsp = [], [] for ccol in [0]: # , b_mat.shape[1]-1]: # range(2): # b_mat.shape[1]): bmc = b_mat[:, ccol][:, :] red_bmc = tl.T * bmc def dtfunc(v, t): return (np.dot(ahat, v).flatten() + red_bmc.flatten()) # +\ red_state = odeint(dtfunc, 0 * inivhat.flatten(), tmesh) red_stp_rsp.append(np.dot(chat, red_state.T).T.tolist()) ful_stp_rsp.append( fullresp(bcol=bmc, trange=tmesh, ini_vel=iniv, cmat=c_mat, soldict=fsr_soldict)) if jsonstr: try: tmesh = tmesh.tolist() except AttributeError: pass # is a list already dou.save_output_json(datadict={ "tmesh": tmesh, "ful_stp_rsp": ful_stp_rsp, "red_stp_rsp": red_stp_rsp, "inivout": inivout }, fstring=jsonstr, module='sadptprj_riclyap_adi.bal_trunc_utils', plotroutine='plot_step_resp') if plot: plot_step_resp(tmesh=tmesh, red_stp_rsp=red_stp_rsp, ful_stp_rsp=ful_stp_rsp, inivout=inivout)