예제 #1
0
 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))
예제 #2
0
 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
예제 #6
0
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)
예제 #7
0
 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())
예제 #8
0
 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)
예제 #10
0
        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
예제 #11
0
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)
예제 #12
0
 def _mm_nonednssps(A, vvec):
     if A is None:
         return 0 * vvec
     else:
         return lau.mm_dnssps(A, vvec)
예제 #13
0
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)
예제 #15
0
 def _bbwdrhs(t):
     # TODO: -----------------------------> here we need vstar
     return (-lau.mm_dnssps(LVhmy, redvfun(te - t)).flatten() +
             lau.mm_dnssps(LVhmy, _redvstarfun(t)).flatten())
예제 #16
0
 def _bbwdnl_vdx(lvec, t):
     vdx = vdxoperator(vfun(te - t))
     return -(lau.mm_dnssps(vdx, lvec)).flatten()
예제 #17
0
 def redmatfunc(vvec):
     return np.dot(lau.mm_dnssps(ULk.T, matfunc(np.dot(UVk, vvec))), ULk)
예제 #18
0
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)