def outputplease(whatson=None, dictofvelstrs=None): 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 + '_{0}'.format(whatson) + 't0{0:.4f}tE{1:.4f}Nts{2}'.format(t0, tE, np.int(Nts))) if plotit: dou.plot_outp_sig(tmesh=trange, outsig=yscomplist)
def compare_freqresp(mmat=None, amat=None, jmat=None, bmat=None, cmat=None, tr=None, tl=None, ahat=None, bhat=None, chat=None, plot=False, datastr=None): """ compare the frequency response of the original and the reduced model cf. [HeiSS08, p. 1059] but with B_2 = 0 Returns ------- freqrel : list of floats the frob norm of the transferfunction at a frequency range red_freqrel : list of floats from of the tf of the reduced model at the same frequencies absci : list of floats frequencies where the tfs are evaluated at """ if ahat is None: ahat = np.dot(tl.T, amat*tr) if bhat is None: bhat = tl.T*bmat if chat is None: chat = cmat*tr NV, red_nv = amat.shape[0], ahat.shape[0] imunit = 1j absci = np.logspace(-4, 8, base=10) freqrel, red_freqrel, diff_freqrel = [], [], [] for omega in absci: sadib = lau.solve_sadpnt_smw(amat=omega*imunit*mmat-amat, jmat=jmat, rhsv=bmat) freqrel.append(np.linalg.norm(cmat*sadib[:NV, :])) # print freqrel[-1] aib = np.linalg.solve(omega*imunit*np.eye(red_nv) - ahat, bhat) red_freqrel.append(np.linalg.norm(np.dot(chat, aib))) diff_freqrel.append(np.linalg.norm(np.dot(chat, aib) - cmat*sadib[:NV, :])) # print red_freqrel[-1] if datastr is not None: dou.save_output_json(dict(tmesh=absci.tolist(), fullsysfr=freqrel, redsysfr=red_freqrel, diffsysfr=diff_freqrel), fstring=datastr + 'forfreqrespplot') if plot: legstr = ['NV was {0}'.format(mmat.shape[0]), 'nv is {0}'.format(tr.shape[1]), 'difference'] fig = plt.figure() ax = fig.add_subplot(111) ax.plot(absci, freqrel, color='b', linewidth=2.0) ax.plot(absci, red_freqrel, color='r', linewidth=2.0) ax.plot(absci, diff_freqrel, color='b', linewidth=1.0) plt.legend(legstr, loc=3) plt.semilogx() plt.semilogy() plt.show(block=False) from matplotlib2tikz import save as tikz_save tikz_save(datastr + 'freqresp.tikz', figureheight='\\figureheight', figurewidth='\\figurewidth' ) return freqrel, red_freqrel, absci
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 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 compare_freqresp(mmat=None, amat=None, jmat=None, bmat=None, cmat=None, tr=None, tl=None, ahat=None, bhat=None, chat=None, plot=False, datastr=None): """ compare the frequency response of the original and the reduced model cf. [HeiSS08, p. 1059] but with B_2 = 0 Returns ------- freqrel : list of floats the frob norm of the transferfunction at a frequency range red_freqrel : list of floats from of the tf of the reduced model at the same frequencies absci : list of floats frequencies where the tfs are evaluated at """ if ahat is None: ahat = np.dot(tl.T, amat * tr) if bhat is None: bhat = tl.T * bmat if chat is None: chat = cmat * tr NV, red_nv = amat.shape[0], ahat.shape[0] imunit = 1j absci = np.logspace(-4, 8, base=10) freqrel, red_freqrel, diff_freqrel = [], [], [] for omega in absci: sadib = lau.solve_sadpnt_smw(amat=omega * imunit * mmat - amat, jmat=jmat, rhsv=bmat) freqrel.append(np.linalg.norm(cmat * sadib[:NV, :])) # print freqrel[-1] aib = np.linalg.solve(omega * imunit * np.eye(red_nv) - ahat, bhat) red_freqrel.append(np.linalg.norm(np.dot(chat, aib))) diff_freqrel.append( np.linalg.norm(np.dot(chat, aib) - cmat * sadib[:NV, :])) # print red_freqrel[-1] if datastr is not None: dou.save_output_json(dict(tmesh=absci.tolist(), fullsysfr=freqrel, redsysfr=red_freqrel, diffsysfr=diff_freqrel), fstring=datastr + 'forfreqrespplot') if plot: legstr = [ 'NV was {0}'.format(mmat.shape[0]), 'nv is {0}'.format(tr.shape[1]), 'difference' ] fig = plt.figure() ax = fig.add_subplot(111) ax.plot(absci, freqrel, color='b', linewidth=2.0) ax.plot(absci, red_freqrel, color='r', linewidth=2.0) ax.plot(absci, diff_freqrel, color='b', linewidth=1.0) plt.legend(legstr, loc=3) plt.semilogx() plt.semilogy() plt.show(block=False) from matplotlib2tikz import save as tikz_save tikz_save(datastr + 'freqresp.tikz', figureheight='\\figureheight', figurewidth='\\figurewidth') return freqrel, red_freqrel, absci
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)