def get_pfromv(v=None, V=None, M=None, A=None, J=None, fv=None, fp=None,
               decouplevp=False, solve_M=None, symmetric=False,
               cgtol=1e-8,
               diribcs=None, dbcinds=None, dbcvals=None, invinds=None,
               **kwargs):
    """ for a velocity `v`, get the corresponding `p`

    Notes
    -----
    Formula is only valid for constant rhs in the continuity equation
    """

    import sadptprj_riclyap_adi.lin_alg_utils as lau

    _, rhs_con, _ = get_v_conv_conts(prev_v=v, V=V, invinds=invinds,
                                     dbcinds=dbcinds, dbcvals=dbcvals,
                                     diribcs=diribcs)

    if decouplevp and symmetric:
        vp = lau.solve_sadpnt_smw(jmat=J, jmatT=J.T,
                                  decouplevp=decouplevp, solve_A=solve_M,
                                  symmetric=symmetric, cgtol=1e-8,
                                  rhsv=-A*v-rhs_con+fv)
        return -vp[J.shape[1]:, :]
    else:
        vp = lau.solve_sadpnt_smw(amat=M, jmat=J, jmatT=J.T,
                                  decouplevp=decouplevp, solve_A=solve_M,
                                  symmetric=symmetric, cgtol=1e-8,
                                  rhsv=-A*v-rhs_con+fv)
        return -vp[J.shape[1]:, :]
Example #2
0
def get_pfromv(v=None,
               V=None,
               M=None,
               A=None,
               J=None,
               fv=None,
               fp=None,
               diribcs=None,
               invinds=None,
               **kwargs):
    """ for a velocity `v`, get the corresponding `p`

    Notes
    -----
    Formula is only valid for constant rhs in the continuity equation
    """

    import sadptprj_riclyap_adi.lin_alg_utils as lau

    _, rhs_con, _ = get_v_conv_conts(prev_v=v,
                                     V=V,
                                     invinds=invinds,
                                     diribcs=diribcs)

    vp = lau.solve_sadpnt_smw(amat=M,
                              jmat=J,
                              jmatT=-J.T,
                              rhsv=-A * v - rhs_con + fv)

    return vp[J.shape[1]:, :]
    def test_sadpnt_smw_krypy(self):
        """check the sadpnt solver with krypy"""

        umat, vmat, k, = self.U, self.V, self.k

        # self.Jt = self.J.T
        # check the formula
        AuvInvZ = lau.solve_sadpnt_smw(amat=self.A, jmat=self.J, rhsv=self.Z,
                                       jmatT=self.Jt, umat=self.U, vmat=self.V,
                                       krylov=True, krpslvprms=self.krpslvprms)

        sysm1 = sps.hstack([self.A, self.Jt], format='csr')
        sysm2 = sps.hstack([self.J, sps.csr_matrix((k, k))], format='csr')
        mata = sps.vstack([sysm1, sysm2], format='csr')

        umate = np.vstack([umat, np.zeros((k, umat.shape[1]))])
        vmate = np.hstack([vmat, np.zeros((vmat.shape[0], k))])
        ze = np.vstack([self.Z, np.zeros((k, self.Z.shape[1]))])

        AAinvZ = mata * AuvInvZ - np.dot(umate, np.dot(vmate, AuvInvZ))

        # likely to fail because of ill conditioned rand mats
        print(np.linalg.norm(AAinvZ - ze))
        self.assertTrue(np.allclose(AAinvZ, ze),
                        msg='likely to fail because of ill cond')
Example #4
0
def getthecoeffs(N=None, Re=None, scheme='CR',
                 inivp='Stokes', inifemp=None):
    femp, stokesmatsc, rhsmomcont \
        = dnsps.get_sysmats(problem='cylinderwake', N=N, Re=Re,
                            scheme=scheme, mergerhs=True)
    fp = rhsmomcont['fp']
    fv = rhsmomcont['fv']
    # stokesmatsc.update(rhsmomcont)

    J, MP = stokesmatsc['J'], stokesmatsc['MP']
    NV, NP = J.T.shape
    # Nv = J.shape[1]
    # Mpfac = spsla.splu(MP)

    if inivp is 'Stokes':
        inivp = lau.solve_sadpnt_smw(amat=stokesmatsc['A'], jmat=J,
                                     jmatT=-J.T, rhsv=fv, rhsp=fp)
        iniv = inivp[:NV]
        inip = snu.get_pfromv(v=iniv, V=femp['V'], M=stokesmatsc['M'],
                              A=stokesmatsc['A'], J=J, fv=fv, fp=fp,
                              diribcs=femp['diribcs'], invinds=femp['invinds'])
    else:
        inv, inp = dts.expand_vp_dolfunc(vp=inivp, **inifemp)
        # interpolate on new mesh and extract the invinds

    getconvvec = getconvvecfun(**femp)
    return dict(A=stokesmatsc['A'], M=stokesmatsc['M'], J=J, JT=J.T, MP=MP,
                fp=fp, fv=fv, getconvvec=getconvvec,
                iniv=iniv, inip=inip,
                V=femp['V'], Q=femp['Q'], invinds=femp['invinds'],
                diribcs=femp['diribcs'], ppin=femp['ppin'], femp=femp)
def roth_upd_ind2(vvec=None, cts=None, nu=None, Vc=None, diribcsc=None,
                  nmd=dict(V=None, Q=None,
                           M=None, A=None, J=None, fv=None, fp=None,
                           invinds=None, diribcs=None, coefalu=None),
                  returnalu=False, **kwargs):
    """ advancing `v, p` for one time using Rothe's method

    Parameters
    ---
    nmd : dict
        containing the data (mesh, matrices, rhs) from the next time step
    vvec : (n,1)-array
        current solution
    Vc : dolfin.mesh
        current mesh

    Notes
    -----
    Time dependent Dirichlet conditions are not supported by now
    """
    logger.debug("length of vvec={0}".format(vvec.size))
    if not nmd['V'] == Vc:
        vvec = _vctovn(vvec=vvec, Vc=Vc, Vn=nmd['V'])
        logger.debug('len(vvec)={0}, dim(Vn)={1}, dim(Vc)={2}'.
                     format(vvec.size, nmd['V'].dim(), Vc.dim()))
    mvvec = nmd['M']*vvec[nmd['invinds'], :]
    convvec = dts.get_convvec(u0_vec=vvec, V=nmd['V'],
                              diribcs=nmd['diribcs'],
                              invinds=nmd['invinds'])
    if nmd['coefalu'] is None:
        mta = nmd['M'] + cts*nmd['A']
        mtJT = -cts*nmd['J'].T
    else:
        mta = None
        mtJT = None

    rhsv = mvvec + cts*(nmd['fv'] - convvec)

    lsdpdict = dict(amat=mta, jmat=nmd['J'], jmatT=mtJT, rhsv=rhsv,
                    rhsp=nmd['fp'], sadlu=nmd['coefalu'],
                    return_alu=returnalu)
    if returnalu:
        vp_new, coefalu = lau.solve_sadpnt_smw(**lsdpdict)
        return vp_new, coefalu
    else:
        vp_new = lau.solve_sadpnt_smw(**lsdpdict)
        return vp_new
    def test_solve_proj_sadpnt_smw(self):
        """check the sadpnt as projection"""

        n = self.n

        # check whether it is a projection
        AuvInvZ = lau.solve_sadpnt_smw(amat=self.A, jmat=self.J, rhsv=self.Z,
                                       jmatT=self.Jt, umat=self.U, vmat=self.V)

        auvAUVinv = self.A * AuvInvZ[:n, :] - \
            lau.comp_uvz_spdns(self.U, self.V, AuvInvZ[:n, :])

        AuvInv2Z = lau.solve_sadpnt_smw(amat=self.A, jmat=self.J,
                                        rhsv=auvAUVinv,
                                        jmatT=self.Jt,
                                        umat=self.U, vmat=self.V)

        self.assertTrue(np.allclose(AuvInvZ[:n, :], AuvInv2Z[:n, :]),
                        msg='likely to fail because of ill cond')

        prjz = lau.app_prj_via_sadpnt(amat=self.A, jmat=self.J,
                                      rhsv=self.Z, jmatT=self.Jt)
        prprjz = lau.app_prj_via_sadpnt(amat=self.A, jmat=self.J,
                                        rhsv=self.Z, jmatT=self.Jt)

        # check projector
        self.assertTrue(np.allclose(prprjz, prjz))

        # onto kernel J
        self.assertTrue(np.linalg.norm(prjz) > 1e-8)
        self.assertTrue(np.linalg.norm(self.J*prjz)/np.linalg.norm(prjz)
                        < 1e-6)

        # check transpose
        idmat = np.eye(n)
        prj = lau.app_prj_via_sadpnt(amat=self.A, jmat=self.J,
                                     rhsv=idmat, jmatT=self.Jt)

        prjT = lau.app_prj_via_sadpnt(amat=self.A, jmat=self.J,
                                      rhsv=idmat, jmatT=self.Jt,
                                      transposedprj=True)

        self.assertTrue(np.allclose(prj, prjT.T))
Example #7
0
def get_pfromv(v=None, V=None, M=None, A=None, J=None, fv=None, fp=None,
               diribcs=None, invinds=None, **kwargs):
    """ for a velocity `v`, get the corresponding `p`

    Notes
    -----
    Formula is only valid for constant rhs in the continuity equation
    """

    import sadptprj_riclyap_adi.lin_alg_utils as lau

    _, rhs_con, _ = get_v_conv_conts(prev_v=v, V=V, invinds=invinds,
                                     diribcs=diribcs)

    vp = lau.solve_sadpnt_smw(amat=M, jmat=J, jmatT=-J.T,
                              rhsv=-A*v-rhs_con+fv)

    return vp[J.shape[1]:, :]
def solve_stst_feedbacknthrough(amat=None, mmat=None, jmat=None,
                                bmat=None, cmat=None,
                                fv=None, fl=None, fg=None, fl2=None,
                                nwtn_adi_dict=dict(adi_max_steps=150,
                                                   adi_newZ_reltol=1e-5,
                                                   nwtn_max_steps=14,
                                                   nwtn_upd_reltol=1e-8)):
    """solve for the stabilizing feedback gain and the feedthrough

    for the linear time invariant case"""

    Z = proj_alg_ric_newtonadi(mmat=mmat, amat=amat, jmat=jmat,
                               bmat=bmat, wmat=cmat,
                               nwtn_adi_dict=nwtn_adi_dict)

    mtxb = get_mTzzTtb(mmat.T, Z, bmat)
    mtxfv = get_mTzzTtb(mmat.T, Z, fv)

    wft = lau.solve_sadpnt_smw(amat=-amat.T, jmat=jmat, rhsv=fl-mtxfv,
                               umat=-mtxb, vmat=bmat.T)

    return Z, wft
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 comp_exp_nsmats(
    problemname="drivencavity",
    N=10,
    Re=1e2,
    nu=None,
    linear_system=False,
    refree=False,
    bccontrol=False,
    palpha=None,
    use_old_data=False,
    mddir="pathtodatastorage",
):
    """compute and export the system matrices for Navier-Stokes equations

    Parameters
    ---
    refree : boolean, optional
        whether to use `Re=1` (so that the `Re` number can be applied later by
        scaling the corresponding matrices, defaults to `False`
    linear_system : boolean, optional
        whether to compute/return the linearized system, defaults to `False`
    bccontrol : boolean, optional
        whether to model boundary control at the cylinder via penalized robin
        boundary conditions, defaults to `False`
    palpha : float, optional
        penalization parameter for the boundary control, defaults to `None`,
        `palpha` is mandatory for `linear_system`

    """

    if refree:
        Re = 1
        print "For the Reynoldsnumber free mats, we set Re=1"

    if problemname == "drivencavity" and bccontrol:
        raise NotImplementedError("boundary control for the driven cavity" + " is not implemented yet")

    if linear_system and bccontrol and palpha is None:
        raise UserWarning("For the linear system a" + " value for `palpha` is needed")
    if not linear_system and bccontrol:
        raise NotImplementedError("Nonlinear system with boundary control" + " is not implemented yet")
    femp, stokesmatsc, rhsd_vfrc, rhsd_stbc = dnsps.get_sysmats(problem=problemname, bccontrol=bccontrol, N=N, Re=Re)
    if linear_system and bccontrol:
        Arob = stokesmatsc["A"] + 1.0 / palpha * stokesmatsc["Arob"]
        Brob = 1.0 / palpha * stokesmatsc["Brob"]
    elif linear_system:
        Brob = 0

    invinds = femp["invinds"]
    A, J = stokesmatsc["A"], stokesmatsc["J"]
    fvc, fpc = rhsd_vfrc["fvc"], rhsd_vfrc["fpr"]
    fv_stbc, fp_stbc = rhsd_stbc["fv"], rhsd_stbc["fp"]
    invinds = femp["invinds"]
    NV = invinds.shape[0]
    data_prfx = problemname + "__N{0}Re{1}".format(N, Re)
    if bccontrol:
        data_prfx = data_prfx + "_penarob"

    soldict = stokesmatsc  # containing A, J, JT
    soldict.update(femp)  # adding V, Q, invinds, diribcs
    soldict.update(rhsd_vfrc)  # adding fvc, fpr
    fv = rhsd_vfrc["fvc"] + rhsd_stbc["fv"]
    fp = rhsd_vfrc["fpr"] + rhsd_stbc["fp"]
    # print 'get expmats: ||fv|| = {0}'.format(np.linalg.norm(fv))
    # print 'get expmats: ||fp|| = {0}'.format(np.linalg.norm(fp))
    # import scipy.sparse.linalg as spsla
    # print 'get expmats: ||A|| = {0}'.format(spsla.norm(A))
    # print 'get expmats: ||Arob|| = {0}'.format(spsla.norm(Arob))
    # print 'get expmats: ||A|| = {0}'.format(spsla.norm(stokesmatsc['A']))
    # raise Warning('TODO: debug')

    soldict.update(
        fv=fv,
        fp=fp,
        N=N,
        nu=nu,
        clearprvdata=~use_old_data,
        get_datastring=None,
        data_prfx=ddir + data_prfx + "_stst",
        paraviewoutput=False,
    )
    if bccontrol and linear_system:
        soldict.update(A=Arob)

    # compute the uncontrolled steady state Navier-Stokes solution
    vp_ss_nse, list_norm_nwtnupd = snu.solve_steadystate_nse(return_vp=True, **soldict)
    v_ss_nse, p_ss_nse = vp_ss_nse[:NV], vp_ss_nse[NV:]

    # specify in what spatial direction Bu changes. The remaining is constant
    if problemname == "drivencavity":
        uspacedep = 0
    elif problemname == "cylinderwake":
        uspacedep = 1

    #
    # Control mats
    #
    contsetupstr = problemname + "__NV{0}NU{1}NY{2}".format(NV, NU, NY)

    # get the control and observation operators
    try:
        b_mat = dou.load_spa(ddir + contsetupstr + "__b_mat")
        u_masmat = dou.load_spa(ddir + contsetupstr + "__u_masmat")
        print "loaded `b_mat`"
    except IOError:
        print "computing `b_mat`..."
        b_mat, u_masmat = cou.get_inp_opa(cdcoo=femp["cdcoo"], V=femp["V"], NU=NU, xcomp=uspacedep)
        dou.save_spa(b_mat, ddir + contsetupstr + "__b_mat")
        dou.save_spa(u_masmat, ddir + contsetupstr + "__u_masmat")
    try:
        mc_mat = dou.load_spa(ddir + contsetupstr + "__mc_mat")
        y_masmat = dou.load_spa(ddir + contsetupstr + "__y_masmat")
        print "loaded `c_mat`"
    except IOError:
        print "computing `c_mat`..."
        mc_mat, y_masmat = cou.get_mout_opa(odcoo=femp["odcoo"], V=femp["V"], NY=NY)
        dou.save_spa(mc_mat, ddir + contsetupstr + "__mc_mat")
        dou.save_spa(y_masmat, ddir + contsetupstr + "__y_masmat")

    # restrict the operators to the inner nodes
    mc_mat = mc_mat[:, invinds][:, :]
    b_mat = b_mat[invinds, :][:, :]

    c_mat = lau.apply_massinv(y_masmat, mc_mat, output="sparse")
    # TODO: right choice of norms for y
    #       and necessity of regularization here
    #       by now, we go on number save

    # the pressure observation mean over a small domain
    if problemname == "cylinderwake":
        podcoo = dict(xmin=0.6, xmax=0.64, ymin=0.18, ymax=0.22)
    elif problemname == "drivencavity":
        podcoo = dict(xmin=0.45, xmax=0.55, ymin=0.7, ymax=0.8)
    else:
        podcoo = femp["odcoo"]

    # description of the control and observation domains
    dmd = femp["cdcoo"]
    xmin, xmax, ymin, ymax = dmd["xmin"], dmd["xmax"], dmd["ymin"], dmd["ymax"]
    velcondomstr = "vel control domain: [{0}, {1}]x[{2}, {3}]\n".format(xmin, xmax, ymin, ymax)
    dmd = femp["odcoo"]
    xmin, xmax, ymin, ymax = dmd["xmin"], dmd["xmax"], dmd["ymin"], dmd["ymax"]
    velobsdomstr = "vel observation domain: [{0}, {1}]x[{2}, {3}]\n".format(xmin, xmax, ymin, ymax)
    dmd = podcoo
    xmin, xmax, ymin, ymax = dmd["xmin"], dmd["xmax"], dmd["ymin"], dmd["ymax"]
    pobsdomstr = "pressure observation domain: [{0}, {1}]x[{2}, {3}]\n".format(xmin, xmax, ymin, ymax)

    pcmat = cou.get_pavrg_onsubd(odcoo=podcoo, Q=femp["Q"], ppin=None)

    cdatstr = snu.get_datastr_snu(time=None, meshp=N, nu=nu, Nts=None)

    (coors, xinds, yinds, corfunvec) = dts.get_dof_coors(femp["V"], invinds=invinds)

    ctrl_visu_str = (
        " the (distributed) control setup is as follows \n"
        + " B maps into the domain of control -"
        + velcondomstr
        + " the first half of the columns"
        + "actuate in x-direction, the second in y direction \n"
        + " Cv measures averaged velocities in the domain of observation"
        + velobsdomstr
        + " Cp measures the averaged pressure"
        + " in the domain of pressure observation: "
        + pobsdomstr
        + " the first components are in x, the last in y-direction \n\n"
        + " Visualization: \n\n"
        + " `coors`   -- array of (x,y) coordinates in "
        + " the same order as v[xinds] or v[yinds] \n"
        + " `xinds`, `yinds` -- indices of x and y components"
        + " of v = [vx, vy] -- note that indexing starts with 0\n"
        + " for testing use corfunvec wich is the interpolant of\n"
        + " f(x,y) = [x, y] on the grid \n\n"
        + "Created in `get_exp_nsmats.py` "
        + "(see https://github.com/highlando/dolfin_navier_scipy) at\n"
        + datetime.datetime.now().strftime("%I:%M%p on %B %d, %Y")
    )

    if bccontrol and problemname == "cylinderwake" and linear_system:
        ctrl_visu_str = (
            "the boundary control is realized via penalized robin \n"
            + "boundary conditions, cf. e.g. [Hou/Ravindran `98], \n"
            + "with predefined shape functions for the cylinder wake \n"
            + "and the penalization parameter `palpha`={0}."
        ).format(palpha) + ctrl_visu_str

    if linear_system:
        convc_mat, rhs_con, rhsv_conbc = snu.get_v_conv_conts(
            prev_v=v_ss_nse, invinds=invinds, V=femp["V"], diribcs=femp["diribcs"]
        )
        # TODO: omg
        if bccontrol:
            f_mat = -Arob - convc_mat
        else:
            f_mat = -stokesmatsc["A"] - convc_mat

        infostr = (
            "These are the coefficient matrices of the linearized "
            + "Navier-Stokes Equations \n for the "
            + problemname
            + " to be used as \n\n"
            + " $M \\dot v = Av + J^Tp + Bu$   and  $Jv = 0$ \n\n"
            + " the Reynoldsnumber is computed as L/nu \n"
            + " Note this is the reduced system for the velocity update\n"
            + " caused by the control, i.e., no boundary conditions\n"
            + " or inhomogeneities here. To get the actual flow, superpose \n"
            + " the steadystate velocity solution `v_ss_nse` \n\n"
            + ctrl_visu_str
        )

        matstr = (mddir + problemname + "__mats_N{0}_Re{1}").format(NV, Re)
        if bccontrol:
            matstr = matstr + "__penarob_palpha{0}".format(palpha)

        scipy.io.savemat(
            matstr,
            dict(
                A=f_mat,
                M=stokesmatsc["M"],
                nu=femp["nu"],
                Re=femp["Re"],
                J=stokesmatsc["J"],
                B=b_mat,
                C=c_mat,
                Cp=pcmat,
                Brob=Brob,
                v_ss_nse=v_ss_nse,
                info=infostr,
                contsetupstr=contsetupstr,
                datastr=cdatstr,
                coors=coors,
                xinds=xinds,
                yinds=yinds,
                corfunvec=corfunvec,
            ),
        )

        print ("matrices saved to " + matstr)

    elif refree:
        hstr = ddir + problemname + "_N{0}_hmat".format(N)
        try:
            hmat = dou.load_spa(hstr)
            print "loaded `hmat`"
        except IOError:
            print "assembling hmat ..."
            hmat = dts.ass_convmat_asmatquad(W=femp["V"], invindsw=invinds)
            dou.save_spa(hmat, hstr)

        zerv = np.zeros((NV, 1))
        bc_conv, bc_rhs_conv, rhsbc_convbc = snu.get_v_conv_conts(
            prev_v=zerv, V=femp["V"], invinds=invinds, diribcs=femp["diribcs"], Picard=False
        )

        # diff_mat = stokesmatsc['A']
        # bcconv_mat = bc_conv
        # fv_bcdiff = fv_stbc
        # fv_bcconv = - bc_rhs_conv
        fv = fvc
        fp = fpc
        # fp_bc = fp_stbc

        infostr = (
            "These are the coefficient matrices of the quadratic "
            + "formulation of the Navier-Stokes Equations \n for the "
            + problemname
            + " to be used as \n\n"
            + " $M \\dot v + Av + H*kron(v,v) + J^Tp = Bu + fv$ \n"
            + " and  $Jv = fp$ \n\n"
            + " the Reynoldsnumber is computed as L/nu \n"
            + " note that `A` contains the diffusion and the linear term \n"
            + " that comes from the dirichlet boundary values \n"
            + " as initial value one can use the provided steady state \n"
            + " Stokes solution \n"
            + " see https://github.com/highlando/dolfin_navier_scipy/blob/"
            + " master/tests/solve_nse_quadraticterm.py for appl example\n"
            + ctrl_visu_str
        )

        scipy.io.savemat(
            mddir + problemname + "quadform__mats_N{0}_Re{1}".format(NV, Re),
            dict(
                A=f_mat,
                M=stokesmatsc["M"],
                H=-hmat,
                fv=fv,
                fp=fp,
                nu=femp["nu"],
                Re=femp["Re"],
                J=stokesmatsc["J"],
                B=b_mat,
                Cv=c_mat,
                Cp=pcmat,
                info=infostr,
                # ss_stokes=old_v,
                contsetupstr=contsetupstr,
                datastr=cdatstr,
                coors=coors,
                xinds=xinds,
                yinds=yinds,
                corfunvec=corfunvec,
            ),
        )
    else:
        hstr = ddir + problemname + "_N{0}_hmat".format(N)
        try:
            hmat = dou.load_spa(hstr)
            print "loaded `hmat`"
        except IOError:
            print "assembling hmat ..."
            hmat = dts.ass_convmat_asmatquad(W=femp["V"], invindsw=invinds)
            dou.save_spa(hmat, hstr)

        zerv = np.zeros((NV, 1))
        bc_conv, bc_rhs_conv, rhsbc_convbc = snu.get_v_conv_conts(
            prev_v=zerv, V=femp["V"], invinds=invinds, diribcs=femp["diribcs"], Picard=False
        )

        f_mat = -stokesmatsc["A"] - bc_conv
        l_mat = -bc_conv
        fv = fv_stbc + fvc - bc_rhs_conv
        fp = fp_stbc + fpc

        vp_stokes = lau.solve_sadpnt_smw(amat=A, jmat=J, rhsv=fv_stbc + fvc, rhsp=fp_stbc + fpc)
        old_v = vp_stokes[:NV]
        p_stokes = -vp_stokes[NV:]  # the pressure was flipped for symmetry

        infostr = (
            "These are the coefficient matrices of the quadratic "
            + "formulation of the Navier-Stokes Equations \n for the "
            + problemname
            + " to be used as \n\n"
            + " $M \\dot v = Av + H*kron(v,v) + J^Tp + Bu + fv$ \n"
            + " and  $Jv = fp$ \n\n"
            + " the Reynoldsnumber is computed as L/nu \n"
            + " note that `A` contains the diffusion and the linear term `L`\n"
            + " that comes from the dirichlet boundary values \n"
            + " for linearizations it might be necessary to consider `A-L` \n"
            + " as initial value one can use the provided steady state \n"
            + " Stokes solution \n"
            + " see https://github.com/highlando/dolfin_navier_scipy/blob/"
            + " master/tests/solve_nse_quadraticterm.py for appl example\n"
            + ctrl_visu_str
        )

        scipy.io.savemat(
            mddir + problemname + "quadform__mats_N{0}_Re{1}".format(NV, Re),
            dict(
                A=f_mat,
                M=stokesmatsc["M"],
                H=-hmat,
                fv=fv,
                fp=fp,
                L=l_mat,
                nu=femp["nu"],
                Re=femp["Re"],
                J=stokesmatsc["J"],
                B=b_mat,
                Cv=c_mat,
                Cp=pcmat,
                info=infostr,
                p_ss_stokes=p_stokes,
                p_ss_nse=p_ss_nse,
                v_ss_stokes=old_v,
                v_ss_nse=v_ss_nse,
                contsetupstr=contsetupstr,
                datastr=cdatstr,
                coors=coors,
                xinds=xinds,
                yinds=yinds,
                corfunvec=corfunvec,
            ),
        )
Example #11
0
def solve_steadystate_nse(A=None, J=None, JT=None, M=None,
                          fv=None, fp=None,
                          V=None, Q=None, invinds=None, diribcs=None,
                          return_vp=False, ppin=-1,
                          N=None, nu=None,
                          vel_pcrd_stps=10, vel_pcrd_tol=1e-4,
                          vel_nwtn_stps=20, vel_nwtn_tol=5e-15,
                          clearprvdata=False,
                          vel_start_nwtn=None,
                          get_datastring=None,
                          data_prfx='',
                          paraviewoutput=False,
                          save_intermediate_steps=False,
                          vfileprfx='', pfileprfx='',
                          **kw):

    """
    Solution of the steady state nonlinear NSE Problem

    using Newton's scheme. If no starting value is provided, the iteration
    is started with the steady state Stokes solution.

    Parameters
    ----------
    A : (N,N) sparse matrix
        stiffness matrix aka discrete Laplacian, note the sign!
    M : (N,N) sparse matrix
        mass matrix
    J : (M,N) sparse matrix
        discrete divergence operator
    JT : (N,M) sparse matrix, optional
        discrete gradient operator, set to J.T if not provided
    fv, fp : (N,1), (M,1) ndarrays
        right hand sides restricted via removing the boundary nodes in the
        momentum and the pressure freedom in the continuity equation
    ppin : {int, None}, optional
        which dof of `p` is used to pin the pressure, defaults to `-1`
    return_vp : boolean, optional
        whether to return also the pressure, defaults to `False`
    vel_pcrd_stps : int, optional
        Number of Picard iterations when computing a starting value for the
        Newton scheme, cf. Elman, Silvester, Wathen: *FEM and fast iterative
        solvers*, 2005, defaults to `100`
    vel_pcrd_tol : real, optional
        tolerance for the size of the Picard update, defaults to `1e-4`
    vel_nwtn_stps : int, optional
        Number of Newton iterations, defaults to `20`
    vel_nwtn_tol : real, optional
        tolerance for the size of the Newton update, defaults to `5e-15`
    """

    import sadptprj_riclyap_adi.lin_alg_utils as lau

    if get_datastring is None:
        get_datastring = get_datastr_snu

    if JT is None:
        JT = J.T

    NV = J.shape[1]

#
# Compute or load the uncontrolled steady state Navier-Stokes solution
#

    norm_nwtnupd_list = []
    vel_newtk, norm_nwtnupd = 0, 1
    # a dict to be passed to the get_datastring function
    datastrdict = dict(time=None, meshp=N, nu=nu,
                       Nts=None, data_prfx=data_prfx)

    if clearprvdata:
        cdatstr = get_datastring(**datastrdict)
        for fname in glob.glob(cdatstr + '*__vel*'):
            os.remove(fname)

    try:
        cdatstr = get_datastring(**datastrdict)

        norm_nwtnupd = dou.load_npa(cdatstr + '__norm_nwtnupd')
        vel_k = dou.load_npa(cdatstr + '__vel')
        norm_nwtnupd_list.append(norm_nwtnupd)

        print 'found vel files'
        print 'norm of last Nwtn update: {0}'.format(norm_nwtnupd)
        if norm_nwtnupd < vel_nwtn_tol:
            if not return_vp:
                return vel_k, norm_nwtnupd_list
            else:
                pfv = get_pfromv(v=vel_k[:NV, :], V=V, M=M, A=A, J=J, fv=fv,
                                 invinds=invinds, diribcs=diribcs)
                return (np.vstack([vel_k, pfv]), norm_nwtnupd_list)

    except IOError:
        print 'no old velocity data found'
        norm_nwtnupd = None

    if paraviewoutput:
        cdatstr = get_datastring(**datastrdict)
        vfile = dolfin.File(vfileprfx+'__steadystates.pvd')
        pfile = dolfin.File(pfileprfx+'__steadystates.pvd')
        prvoutdict = dict(V=V, Q=Q, vfile=vfile, pfile=pfile,
                          invinds=invinds, diribcs=diribcs, ppin=ppin,
                          vp=None, t=None, writeoutput=True)
    else:
        prvoutdict = dict(writeoutput=False)  # save 'if statements' here

    NV = A.shape[0]
    if vel_start_nwtn is None:
        vp_stokes = lau.solve_sadpnt_smw(amat=A, jmat=J, jmatT=JT,
                                         rhsv=fv, rhsp=fp)
        vp_stokes[NV:] = -vp_stokes[NV:]
        # pressure was flipped for symmetry

        # save the data
        cdatstr = get_datastring(**datastrdict)

        dou.save_npa(vp_stokes[:NV, ], fstring=cdatstr + '__vel')

        prvoutdict.update(dict(vp=vp_stokes))
        dou.output_paraview(**prvoutdict)

        # Stokes solution as starting value
        vp_k = vp_stokes
        vel_k = vp_stokes[:NV, ]

    else:
        vel_k = vel_start_nwtn

    # Picard iterations for a good starting value for Newton
    for k in range(vel_pcrd_stps):
        (convc_mat,
         rhs_con, rhsv_conbc) = get_v_conv_conts(prev_v=vel_k, invinds=invinds,
                                                 V=V, diribcs=diribcs,
                                                 Picard=True)

        vp_k = lau.solve_sadpnt_smw(amat=A+convc_mat, jmat=J, jmatT=JT,
                                    rhsv=fv+rhs_con+rhsv_conbc,
                                    rhsp=fp)
        normpicupd = np.sqrt(m_innerproduct(M, vel_k-vp_k[:NV, :]))[0]

        print 'Picard iteration: {0} -- norm of update: {1}'\
            .format(k+1, normpicupd)

        vel_k = vp_k[:NV, ]
        vp_k[NV:] = -vp_k[NV:]
        # pressure was flipped for symmetry

        if normpicupd < vel_pcrd_tol:
            break

    # Newton iteration
    while (vel_newtk < vel_nwtn_stps
            and (norm_nwtnupd is None or
                 norm_nwtnupd > vel_nwtn_tol or
                 norm_nwtnupd == np.array(None))):

        vel_newtk += 1

        cdatstr = get_datastring(**datastrdict)

        (convc_mat,
         rhs_con, rhsv_conbc) = get_v_conv_conts(vel_k, invinds=invinds,
                                                 V=V, diribcs=diribcs)

        vp_k = lau.solve_sadpnt_smw(amat=A+convc_mat, jmat=J, jmatT=JT,
                                    rhsv=fv+rhs_con+rhsv_conbc,
                                    rhsp=fp)

        norm_nwtnupd = np.sqrt(m_innerproduct(M, vel_k - vp_k[:NV, :]))[0]
        vel_k = vp_k[:NV, ]
        vp_k[NV:] = -vp_k[NV:]
        # pressure was flipped for symmetry
        print 'Steady State NSE: Newton iteration: {0} -- norm of update: {1}'\
            .format(vel_newtk, norm_nwtnupd)

        dou.save_npa(vel_k, fstring=cdatstr + '__vel')

        prvoutdict.update(dict(vp=vp_k))
        dou.output_paraview(**prvoutdict)

    dou.save_npa(norm_nwtnupd, cdatstr + '__norm_nwtnupd')

    dou.output_paraview(**prvoutdict)

    # savetomatlab = True
    # if savetomatlab:
    #     export_mats_to_matlab(E=None, A=None, matfname='matexport')
    if return_vp:
        return vp_k, norm_nwtnupd_list
    else:
        return vel_k, norm_nwtnupd_list
Example #12
0
def solve_nse(A=None, M=None, J=None, JT=None,
              fv=None, fp=None,
              fvc=None, fpc=None,  # TODO: this is to catch deprecated calls
              fv_tmdp=None, fv_tmdp_params={},
              fv_tmdp_memory=None,
              iniv=None, lin_vel_point=None,
              stokes_flow=False,
              trange=None,
              t0=None, tE=None, Nts=None,
              V=None, Q=None, invinds=None, diribcs=None,
              output_includes_bcs=False,
              N=None, nu=None,
              ppin=-1,
              closed_loop=False, static_feedback=False,
              feedbackthroughdict=None,
              return_vp=False,
              tb_mat=None, c_mat=None,
              vel_nwtn_stps=20, vel_nwtn_tol=5e-15,
              vel_pcrd_stps=4,
              krylov=None, krpslvprms={}, krplsprms={},
              clearprvdata=False,
              get_datastring=None,
              data_prfx='',
              paraviewoutput=False,
              vfileprfx='', pfileprfx='',
              return_dictofvelstrs=False,
              return_dictofpstrs=False,
              dictkeysstr=False,
              comp_nonl_semexp=False,
              return_as_list=False,
              start_ssstokes=False,
              **kw):
    """
    solution of the time-dependent nonlinear Navier-Stokes equation

    .. math::
        M\\dot v + Av + N(v)v + J^Tp = f \n
        Jv =g

    using a Newton scheme in function space, i.e. given :math:`v_k`,
    we solve for the update like

    .. math::
        M\\dot v + Av + N(v_k)v + N(v)v_k + J^Tp = N(v_k)v_k + f,

    and trapezoidal rule in time. To solve an *Oseen* system (linearization
    about a steady state) or a *Stokes* system, set the number of Newton
    steps to one and provide a linearization point and an initial value.


    Parameters
    ----------
    lin_vel_point : dictionary, optional
        contains the linearization point for the first Newton iteration

         * Steady State: {{`None`: 'path_to_nparray'}, {'None': nparray}}
         * Newton: {`t`: 'path_to_nparray'}

        defaults to `None`
    dictkeysstr : boolean, optional
        whether the `keys` of the result dictionaries are strings instead \
        of floats, defaults to `False`
    fv_tmdp : callable f(t, v, dict), optional
        time-dependent part of the right-hand side, set to zero if None
    fv_tmdp_params : dictionary, optional
        dictionary of parameters to be passed to `fv_tmdp`, defaults to `{}`
    fv_tmdp_memory : dictionary, optional
        memory of the function
    output_includes_bcs : boolean, optional
        whether append the boundary nodes to the computed and stored \
        velocities, defaults to `False`
    krylov : {None, 'gmres'}, optional
        whether or not to use an iterative solver, defaults to `None`
    krpslvprms : dictionary, optional
        to specify parameters of the linear solver for use in Krypy, e.g.,

          * initial guess
          * tolerance
          * number of iterations

        defaults to `None`
    krplsprms : dictionary, optional
        parameters to define the linear system like

          * preconditioner

    ppin : {int, None}, optional
        which dof of `p` is used to pin the pressure, defaults to `-1`
    stokes_flow : boolean, optional
        whether to consider the Stokes linearization, defaults to `False`
    start_ssstokes : boolean, optional
        for your convenience, compute and use the steady state stokes solution
        as initial value, defaults to `False`

    Returns
    -------
    dictofvelstrs : dictionary, on demand
        dictionary with time `t` as keys and path to velocity files as values

    dictofpstrs : dictionary, on demand
        dictionary with time `t` as keys and path to pressure files as values

    vellist : list, on demand
        list of the velocity solutions

    """
    import sadptprj_riclyap_adi.lin_alg_utils as lau

    if fvc is not None or fpc is not None:  # TODO: this is for catching calls
        raise UserWarning('deprecated use of `rhsd_vfrc`, use only `fv`, `fp`')

    if get_datastring is None:
        get_datastring = get_datastr_snu

    if paraviewoutput:
        prvoutdict = dict(V=V, Q=Q, invinds=invinds, diribcs=diribcs,
                          vp=None, t=None, writeoutput=True, ppin=ppin)
    else:
        prvoutdict = dict(writeoutput=False)  # save 'if statements' here

    if trange is None:
        trange = np.linspace(t0, tE, Nts+1)

    if comp_nonl_semexp and lin_vel_point is not None:
        raise UserWarning('I am not sure what you want! ' +
                          'set either `lin_vel_point=None` ' +
                          'or `comp_nonl_semexp=False`! \n' +
                          'as it is I will compute a linear case')

    if return_dictofpstrs:
        gpfvd = dict(V=V, M=M, A=A, J=J,
                     fv=fv, fp=fp,
                     diribcs=diribcs, invinds=invinds)

    NV, NP = A.shape[0], J.shape[0]

    if fv_tmdp is None:
        def fv_tmdp(time=None, curvel=None, **kw):
            return np.zeros((NV, 1)), None

    if iniv is None:
        if start_ssstokes:
            # Stokes solution as starting value
            (fv_tmdp_cont,
             fv_tmdp_memory) = fv_tmdp(time=0, **fv_tmdp_params)
            vp_stokes =\
                lau.solve_sadpnt_smw(amat=A, jmat=J, jmatT=JT,
                                     rhsv=fv + fv_tmdp_cont,
                                     krylov=krylov, krpslvprms=krpslvprms,
                                     krplsprms=krplsprms, rhsp=fp)
            iniv = vp_stokes[:NV]
        else:
            raise ValueError('No initial value given')

    datastrdict = dict(time=None, meshp=N, nu=nu,
                       Nts=trange.size-1, data_prfx=data_prfx)

    if return_as_list:
        clearprvdata = True  # we want the results at hand
    if clearprvdata:
        datastrdict['time'] = '*'
        cdatstr = get_datastring(**datastrdict)
        for fname in glob.glob(cdatstr + '__vel*'):
            os.remove(fname)
        for fname in glob.glob(cdatstr + '__p*'):
            os.remove(fname)

    def _atdct(cdict, t, thing):
        if dictkeysstr:
            cdict.update({'{0}'.format(t): thing})
        else:
            cdict.update({t: thing})

    def _gfdct(cdict, t):
        if dictkeysstr:
            return cdict['{0}'.format(t)]
        else:
            return cdict[t]

    if stokes_flow:
        vel_nwtn_stps = 1
        vel_pcrd_stps = 0
        print 'Stokes Flow!'
    elif lin_vel_point is None:
        comp_nonl_semexp_inig = True
        if not comp_nonl_semexp:
            print('No linearization point given - explicit' +
                  ' treatment of the nonlinearity in the first Iteration')
    else:
        cur_linvel_point = lin_vel_point
        comp_nonl_semexp_inig = False

    newtk, norm_nwtnupd, norm_nwtnupd_list = 0, 1, []

    # check for previously computed velocities
    if lin_vel_point is None and not stokes_flow:
        try:
            datastrdict.update(dict(time=trange[-1]))
            cdatstr = get_datastring(**datastrdict)

            norm_nwtnupd = dou.load_npa(cdatstr + '__norm_nwtnupd')
            v_old = dou.load_npa(cdatstr + '__vel')

            norm_nwtnupd_list.append(norm_nwtnupd)
            print 'found vel files'
            print 'norm of last Nwtn update: {0}'.format(norm_nwtnupd)
            if norm_nwtnupd < vel_nwtn_tol and not return_dictofvelstrs:
                return
            elif norm_nwtnupd < vel_nwtn_tol:
                datastrdict.update(dict(time=trange[0]))
                dictofvelstrs = {}
                _atdct(dictofvelstrs, trange[0], cdatstr + '__vel')
                if return_dictofpstrs:
                    try:
                        p_old = dou.load_npa(cdatstr + '__p')
                        dictofpstrs = {}
                        _atdct(dictofpstrs, trange[0], cdatstr+'__p')
                    except:
                        p_old = get_pfromv(v=v_old, **gpfvd)
                        dou.save_npa(p_old, fstring=cdatstr + '__p')
                        _atdct(dictofpstrs, trange[0], cdatstr+'__p')

                for t in trange[1:]:
                    # test if the vels are there
                    v_old = dou.load_npa(cdatstr + '__vel')
                    # update the dict
                    datastrdict.update(dict(time=t))
                    cdatstr = get_datastring(**datastrdict)
                    _atdct(dictofvelstrs, t, cdatstr + '__vel')
                    try:
                        p_old = dou.load_npa(cdatstr + '__p')
                        _atdct(dictofpstrs, t, cdatstr + '__p')
                    except:
                        p_old = get_pfromv(v=v_old, **gpfvd)
                        dou.save_npa(p_old, fstring=cdatstr + '__p')
                        _atdct(dictofpstrs, t, cdatstr + '__p')

                if return_dictofpstrs:
                    return dictofvelstrs, dictofpstrs
                else:
                    return dictofvelstrs

            comp_nonl_semexp = False

        except IOError:
            norm_nwtnupd = 2
            print 'no old velocity data found'

    def _append_bcs_ornot(vvec):
        if output_includes_bcs:  # make the switch here for better readibility
            vwbcs = dts.append_bcs_vec(vvec, vdim=V.dim(),
                                       invinds=invinds, diribcs=diribcs)
            return vwbcs
        else:
            return vvec

    def _get_mats_rhs_ts(mmat=None, dt=None, var_c=None,
                         coeffmat_c=None,
                         coeffmat_n=None,
                         fv_c=None, fv_n=None,
                         umat_c=None, vmat_c=None,
                         umat_n=None, vmat_n=None,
                         impeul=False):
        """ to be tweaked for different int schemes

        """
        solvmat = M + 0.5*dt*coeffmat_n
        rhs = M*var_c + 0.5*dt*(fv_n + fv_c - coeffmat_c*var_c)
        if umat_n is not None:
            matvec = lau.mm_dnssps
            umat = 0.5*dt*umat_n
            vmat = vmat_n
            # TODO: do we really need a PLUS here??'
            rhs = rhs + 0.5*dt*matvec(umat_c, matvec(vmat_c, var_c))
        else:
            umat, vmat = umat_n, vmat_n

        return solvmat, rhs, umat, vmat

    v_old = iniv  # start vector for time integration in every Newtonit
    datastrdict['time'] = trange[0]
    cdatstr = get_datastring(**datastrdict)

    dou.save_npa(_append_bcs_ornot(v_old), fstring=cdatstr + '__vel')
    dictofvelstrs = {}
    _atdct(dictofvelstrs, trange[0], cdatstr + '__vel')
    if return_dictofpstrs:
        p_old = get_pfromv(v=v_old, **gpfvd)
        dou.save_npa(p_old, fstring=cdatstr + '__p')
        dictofpstrs = {}
        _atdct(dictofpstrs, trange[0], cdatstr+'__p')

    if return_as_list:
        vellist = []
        vellist.append(_append_bcs_ornot(v_old))

    while (newtk < vel_nwtn_stps and norm_nwtnupd > vel_nwtn_tol):
        if stokes_flow:
            newtk = vel_nwtn_stps
        elif comp_nonl_semexp_inig and not comp_nonl_semexp:
            pcrd_anyone = False
            print 'explicit treatment of nonl. for initial guess'
        elif vel_pcrd_stps > 0 and not comp_nonl_semexp:
            vel_pcrd_stps -= 1
            pcrd_anyone = True
            print 'Picard iterations for initial value -- {0} left'.\
                format(vel_pcrd_stps)
        elif comp_nonl_semexp:
            pcrd_anyone = False
            newtk = vel_nwtn_stps
            print 'No Newton iterations - explicit treatment of the nonlin.'
        else:
            pcrd_anyone = False
            newtk += 1
            print 'Computing Newton Iteration {0}'.format(newtk)

        v_old = iniv  # start vector for time integration in every Newtonit
        try:
            if krpslvprms['krylovini'] == 'old':
                vp_old = np.vstack([v_old, np.zeros((NP, 1))])
            elif krpslvprms['krylovini'] == 'upd':
                vp_old = np.vstack([v_old, np.zeros((NP, 1))])
                vp_new = vp_old
                cts_old = trange[1] - trange[0]
        except (TypeError, KeyError):
            pass  # no inival for krylov solver required

        vfile = dolfin.File(vfileprfx+'__timestep.pvd')
        pfile = dolfin.File(pfileprfx+'__timestep.pvd')
        prvoutdict.update(dict(vp=None, vc=iniv, t=trange[0],
                               pfile=pfile, vfile=vfile))
        dou.output_paraview(**prvoutdict)

        # ## current values_c for application of trap rule
        if stokes_flow:
            convc_mat_c = sps.csr_matrix((NV, NV))
            rhs_con_c, rhsv_conbc_c = np.zeros((NV, 1)), np.zeros((NV, 1))
        else:
            if comp_nonl_semexp or comp_nonl_semexp_inig:
                prev_v = v_old
            else:
                try:
                    prev_v = dou.load_npa(_gfdct(cur_linvel_point, trange[0]))
                except KeyError:
                    try:
                        prev_v = dou.load_npa(_gfdct(cur_linvel_point, None))
                    except TypeError:
                        prev_v = cur_linvel_point[None]

            convc_mat_c, rhs_con_c, rhsv_conbc_c = \
                get_v_conv_conts(prev_v=iniv, invinds=invinds,
                                 V=V, diribcs=diribcs, Picard=pcrd_anyone)

        (fv_tmdp_cont,
         fv_tmdp_memory) = fv_tmdp(time=0,
                                   curvel=v_old,
                                   memory=fv_tmdp_memory,
                                   **fv_tmdp_params)

        fvn_c = fv + rhsv_conbc_c + rhs_con_c + fv_tmdp_cont

        if closed_loop:
            if static_feedback:
                mtxtb_c = dou.load_npa(feedbackthroughdict[None]['mtxtb'])
                w_c = dou.load_npa(feedbackthroughdict[None]['w'])
                # print '\nnorm of feedback: ', np.linalg.norm(mtxtb_c)
            else:
                mtxtb_c = dou.load_npa(feedbackthroughdict[0]['mtxtb'])
                w_c = dou.load_npa(feedbackthroughdict[0]['w'])

            fvn_c = fvn_c + tb_mat * (tb_mat.T * w_c)
            vmat_c = mtxtb_c.T
            try:
                umat_c = np.array(tb_mat.todense())
            except AttributeError:
                umat_c = tb_mat

        else:
            vmat_c = None
            umat_c = None

        norm_nwtnupd = 0
        print 'time to go',
        for tk, t in enumerate(trange[1:]):
            cts = t - trange[tk]
            datastrdict.update(dict(time=t))
            cdatstr = get_datastring(**datastrdict)
            sys.stdout.write("\rEnd: {1} -- now: {0:f}".format(t, trange[-1]))
            sys.stdout.flush()
            # prv_datastrdict = copy.deepcopy(datastrdict)

            # coeffs and rhs at next time instance
            if stokes_flow:
                convc_mat_n = sps.csr_matrix((NV, NV))
                rhs_con_n, rhsv_conbc_n = np.zeros((NV, 1)), np.zeros((NV, 1))
            else:
                if comp_nonl_semexp or comp_nonl_semexp_inig:
                    prev_v = v_old
                else:
                    try:
                        prev_v = dou.load_npa(_gfdct(cur_linvel_point, t))
                    except KeyError:
                        try:
                            prev_v = dou.load_npa(_gfdct(cur_linvel_point,
                                                         None))
                        except TypeError:
                            prev_v = cur_linvel_point[None]
                convc_mat_n, rhs_con_n, rhsv_conbc_n = \
                    get_v_conv_conts(prev_v=prev_v, invinds=invinds,
                                     V=V, diribcs=diribcs, Picard=pcrd_anyone)

            (fv_tmdp_cont,
             fv_tmdp_memory) = fv_tmdp(time=t,
                                       curvel=v_old,
                                       memory=fv_tmdp_memory,
                                       **fv_tmdp_params)

            fvn_n = fv + rhsv_conbc_n + rhs_con_n + fv_tmdp_cont

            if closed_loop:
                if static_feedback:
                    mtxtb_n = dou.load_npa(feedbackthroughdict[None]['mtxtb'])
                    w_n = dou.load_npa(feedbackthroughdict[None]['w'])
                    # fb = np.dot(tb_mat*mtxtb_n.T, v_old)
                    # print '\nnorm of feedback: ', np.linalg.norm(fb)
                    # print '\nnorm of v_old: ', np.linalg.norm(v_old)
                    # print '\nnorm of feedthrough: ', np.linalg.norm(next_w)
                else:
                    mtxtb_n = dou.load_npa(feedbackthroughdict[t]['mtxtb'])
                    w_n = dou.load_npa(feedbackthroughdict[t]['w'])

                fvn_n = fvn_n + tb_mat * (tb_mat.T * w_n)
                vmat_n = mtxtb_n.T
                try:
                    umat_n = np.array(tb_mat.todense())
                except AttributeError:
                    umat_n = tb_mat

            else:
                vmat_n = None
                umat_n = None

            (solvmat, rhsv, umat,
             vmat) = _get_mats_rhs_ts(mmat=M, dt=cts, var_c=v_old,
                                      coeffmat_c=A + convc_mat_c,
                                      coeffmat_n=A + convc_mat_n,
                                      fv_c=fvn_c, fv_n=fvn_n,
                                      umat_c=umat_c, vmat_c=vmat_c,
                                      umat_n=umat_n, vmat_n=vmat_n)

            try:
                if krpslvprms['krylovini'] == 'old':
                    krpslvprms['x0'] = vp_old
                elif krpslvprms['krylovini'] == 'upd':
                    vp_oldold = vp_old
                    vp_old = vp_new
                    krpslvprms['x0'] = vp_old + \
                        cts*(vp_old - vp_oldold)/cts_old
                    cts_old = cts
            except (TypeError, KeyError):
                pass  # no inival for krylov solver required

            vp_new = lau.solve_sadpnt_smw(amat=solvmat,
                                          jmat=J, jmatT=JT,
                                          rhsv=rhsv,
                                          rhsp=fp,
                                          krylov=krylov, krpslvprms=krpslvprms,
                                          krplsprms=krplsprms,
                                          umat=umat, vmat=vmat)

            v_old = vp_new[:NV, ]
            (umat_c, vmat_c, fvn_c,
                convc_mat_c) = umat_n, vmat_n, fvn_n, convc_mat_n

            dou.save_npa(_append_bcs_ornot(v_old), fstring=cdatstr + '__vel')
            _atdct(dictofvelstrs, t, cdatstr + '__vel')
            if return_dictofpstrs:
                p_new = -1/cts*vp_new[NV:, ]
                # p was flipped and scaled for symmetry
                dou.save_npa(p_new, fstring=cdatstr + '__p')
                _atdct(dictofpstrs, t, cdatstr + '__p')

            if return_as_list:
                vellist.append(_append_bcs_ornot(v_old))

            prvoutdict.update(dict(vp=vp_new, t=t))
            dou.output_paraview(**prvoutdict)

            # integrate the Newton error
            if stokes_flow or comp_nonl_semexp or comp_nonl_semexp_inig:
                norm_nwtnupd = [None]
            else:
                if len(prev_v) > len(invinds):
                    prev_v = prev_v[invinds, :]
                norm_nwtnupd += cts * m_innerproduct(M, v_old - prev_v)

        dou.save_npa(norm_nwtnupd, cdatstr + '__norm_nwtnupd')
        norm_nwtnupd_list.append(norm_nwtnupd[0])
        print '\nnorm of current Newton update: {}'.format(norm_nwtnupd)
        comp_nonl_semexp = False
        comp_nonl_semexp_inig = False

        cur_linvel_point = dictofvelstrs

    if return_dictofvelstrs:
        if return_dictofpstrs:
            return dictofvelstrs, dictofpstrs
        else:
            return dictofvelstrs
    elif return_as_list:
        return vellist
    else:
        return
Example #13
0
def optcon_nse(problemname='drivencavity',
               N=10, Nts=10, nu=1e-2, clearprvveldata=False,
               ini_vel_stokes=False, stst_control=False,
               closed_loop=True,
               outernwtnstps=1,
               t0=None, tE=None,
               use_ric_ini_nu=None,
               alphau=1e-9, gamma=1e-3,
               spec_tip_dict=None,
               nwtn_adi_dict=None,
               linearized_nse=False,
               stokes_flow=False,
               ystar=None):

    tip = time_int_params(Nts, t0=t0, tE=tE)
    if spec_tip_dict is not None:
        tip.update(spec_tip_dict)
    if nwtn_adi_dict is not None:
        tip['nwtn_adi_dict'] = nwtn_adi_dict

    problemdict = dict(drivencavity=dnsps.drivcav_fems,
                       cylinderwake=dnsps.cyl_fems)

    problemfem = problemdict[problemname]
    femp = problemfem(N)

    # output
    ddir = 'data/'
    try:
        os.chdir(ddir)
    except OSError:
        raise Warning('need "' + ddir + '" subdir for storing the data')
    os.chdir('..')

    if linearized_nse and not outernwtnstps == 1:
        raise Warning('Linearized problem can have only one Newton step')

    if closed_loop:
        if stst_control:
            data_prfx = ddir + 'stst_' + problemname + '__'
        else:
            data_prfx = ddir + 'tdst_' + problemname + '__'

    else:
        data_prfx = ddir + problemname + '__'

    if stokes_flow:
        data_prfx = data_prfx + 'stokes__'

    # specify in what spatial direction Bu changes. The remaining is constant
    if problemname == 'drivencavity':
        uspacedep = 0
    elif problemname == 'cylinderwake':
        uspacedep = 1

    stokesmats = dts.get_stokessysmats(femp['V'], femp['Q'], nu)
    rhsd_vf = dts.setget_rhs(femp['V'], femp['Q'],
                             femp['fv'], femp['fp'], t=0)

    # remove the freedom in the pressure
    stokesmats['J'] = stokesmats['J'][:-1, :][:, :]
    stokesmats['JT'] = stokesmats['JT'][:, :-1][:, :]
    rhsd_vf['fp'] = rhsd_vf['fp'][:-1, :]

    # reduce the matrices by resolving the BCs
    (stokesmatsc, rhsd_stbc,
     invinds, bcinds, bcvals) = dts.condense_sysmatsbybcs(stokesmats,
                                                          femp['diribcs'])

    print 'Dimension of the div matrix: ', stokesmatsc['J'].shape
    # pressure freedom and dirichlet reduced rhs
    rhsd_vfrc = dict(fpr=rhsd_vf['fp'], fvc=rhsd_vf['fv'][invinds, ])

    # add the info on boundary and inner nodes
    bcdata = {'bcinds': bcinds, 'bcvals': bcvals, 'invinds': invinds}
    femp.update(bcdata)

    # casting some parameters
    NV = len(femp['invinds'])

    soldict = stokesmatsc  # containing A, J, JT
    soldict.update(femp)  # adding V, Q, invinds, diribcs
    # soldict.update(rhsd_vfrc)  # adding fvc, fpr
    soldict.update(fv=rhsd_stbc['fv']+rhsd_vfrc['fvc'],
                   fp=rhsd_stbc['fp']+rhsd_vfrc['fpr'],
                   N=N, nu=nu,
                   trange=tip['tmesh'],
                   get_datastring=get_datastr,
                   data_prfx=data_prfx,
                   clearprvdata=clearprvveldata,
                   paraviewoutput=tip['ParaviewOutput'],
                   vfileprfx=tip['proutdir']+'vel_',
                   pfileprfx=tip['proutdir']+'p_')

#
# Prepare for control
#

    contp = ContParams(femp['odcoo'], ystar=ystar, alphau=alphau, gamma=gamma)
    # casting some parameters
    NY, NU = contp.NY, contp.NU

    contsetupstr = problemname + '__NV{0}NU{1}NY{2}'.format(NV, NU, NY)

    # get the control and observation operators
    try:
        b_mat = dou.load_spa(ddir + contsetupstr + '__b_mat')
        u_masmat = dou.load_spa(ddir + contsetupstr + '__u_masmat')
        print 'loaded `b_mat`'
    except IOError:
        print 'computing `b_mat`...'
        b_mat, u_masmat = cou.get_inp_opa(cdcoo=femp['cdcoo'], V=femp['V'],
                                          NU=NU, xcomp=uspacedep)
        dou.save_spa(b_mat, ddir + contsetupstr + '__b_mat')
        dou.save_spa(u_masmat, ddir + contsetupstr + '__u_masmat')
    try:
        mc_mat = dou.load_spa(ddir + contsetupstr + '__mc_mat')
        y_masmat = dou.load_spa(ddir + contsetupstr + '__y_masmat')
        print 'loaded `c_mat`'
    except IOError:
        print 'computing `c_mat`...'
        mc_mat, y_masmat = cou.get_mout_opa(odcoo=femp['odcoo'],
                                            V=femp['V'], NY=NY)
        dou.save_spa(mc_mat, ddir + contsetupstr + '__mc_mat')
        dou.save_spa(y_masmat, ddir + contsetupstr + '__y_masmat')

    # restrict the operators to the inner nodes
    mc_mat = mc_mat[:, invinds][:, :]
    b_mat = b_mat[invinds, :][:, :]

    # for further use:
    c_mat = lau.apply_massinv(y_masmat, mc_mat, output='sparse')

    if contp.ystarx is None:
        c_mat = c_mat[NY:, :][:, :]  # TODO: Do this right
        mc_mat = mc_mat[NY:, :][:, :]  # TODO: Do this right
        y_masmat = y_masmat[:NY, :][:, :NY]  # TODO: Do this right

    mct_mat_reg = lau.app_prj_via_sadpnt(amat=stokesmatsc['M'],
                                         jmat=stokesmatsc['J'],
                                         rhsv=mc_mat.T,
                                         transposedprj=True)

    # set the weighing matrices
    contp.R = contp.alphau * u_masmat

#
# solve the differential-alg. Riccati eqn for the feedback gain X
# via computing factors Z, such that X = -Z*Z.T
#
# at the same time we solve for the affine-linear correction w
#

    # tilde B = BR^{-1/2}
    tb_mat = lau.apply_invsqrt_fromright(contp.R, b_mat, output='sparse')
    # tb_dense = np.array(tb_mat.todense())

    trct_mat = lau.apply_invsqrt_fromright(y_masmat,
                                           mct_mat_reg, output='dense')

    if closed_loop:
        cntpstr = 'NV{3}NY{0}NU{1}alphau{2}gamma{4}'.\
            format(contp.NU, contp.NY, contp.alphau, NV, contp.gamma)
    else:
        cntpstr = ''

    # we gonna use this quite often
    M, A = stokesmatsc['M'], stokesmatsc['A']
    datastrdict = dict(time=None, meshp=N, nu=nu, Nts=Nts,
                       data_prfx=data_prfx)

    # compute the uncontrolled steady state (Navier-)Stokes solution
    # as initial value
    if ini_vel_stokes:
        # compute the uncontrolled steady state Stokes solution
        ini_vel, newtonnorms = snu.solve_steadystate_nse(vel_nwtn_stps=0,
                                                         vel_pcrd_stps=0,
                                                         **soldict)
        soldict.update(dict(iniv=ini_vel))
    else:
        ini_vel, newtonnorms = snu.solve_steadystate_nse(**soldict)
        soldict.update(dict(iniv=ini_vel))

    if closed_loop:
        if stst_control:
            if stokes_flow:
                convc_mat = sps.csr_matrix((NV, NV))
                rhs_con, rhsv_conbc = np.zeros((NV, 1)), np.zeros((NV, 1))
                lin_point = None
            else:
                lin_point, newtonnorms = snu.solve_steadystate_nse(**soldict)
                (convc_mat, rhs_con,
                 rhsv_conbc) = snu.get_v_conv_conts(prev_v=lin_point,
                                                    invinds=invinds,
                                                    V=femp['V'],
                                                    diribcs=femp['diribcs'])
            # infinite control horizon, steady target state
            cdatstr = get_datastr(time=None, meshp=N, nu=nu,
                                  Nts=None, data_prfx=data_prfx)

            try:
                Z = dou.load_npa(cdatstr + cntpstr + '__Z')
                print 'loaded ' + cdatstr + cntpstr + '__Z'
            except IOError:
                if use_ric_ini_nu is not None:
                    cdatstr = get_datastr(nwtn=None, time=None, meshp=N,
                                          nu=use_ric_ini_nu, Nts=None,
                                          data_prfx=data_prfx)
                    try:
                        zini = dou.load_npa(ddir + cdatstr
                                            + cntpstr + '__Z')
                        print 'Initialize Newton ADI by Z from ' + cdatstr
                    except IOError:
                        raise Warning('No data for initialization of '
                                      ' Newton ADI -- need ' + cdatstr
                                      + '__Z')
                    cdatstr = get_datastr(meshp=N, nu=nu,
                                          data_prfx=data_prfx)
                else:
                    zini = None

                parnadi = pru.proj_alg_ric_newtonadi
                Z = parnadi(mmat=M, amat=-A-convc_mat,
                            jmat=stokesmatsc['J'],
                            bmat=tb_mat, wmat=trct_mat, z0=zini,
                            nwtn_adi_dict=tip['nwtn_adi_dict'])['zfac']

                dou.save_npa(Z, fstring=cdatstr + cntpstr + '__Z')
                print 'saved ' + cdatstr + cntpstr + '__Z'

                if tip['compress_z']:
                    Zc = pru.compress_Zsvd(Z, thresh=tip['comprz_thresh'],
                                           k=tip['comprz_maxc'])
                    Z = Zc

            fvnstst = rhs_con + rhsv_conbc + rhsd_stbc['fv'] + rhsd_vfrc['fvc']

            # X = -ZZ.T
            mtxtb_stst = -pru.get_mTzzTtb(M.T, Z, tb_mat)
            mtxfv_stst = -pru.get_mTzzTtb(M.T, Z, fvnstst)

            fl = mc_mat.T * contp.ystarvec(0)

            wft = lau.solve_sadpnt_smw(amat=A.T+convc_mat.T,
                                       jmat=stokesmatsc['J'],
                                       rhsv=fl+mtxfv_stst,
                                       umat=mtxtb_stst,
                                       vmat=tb_mat.T)[:NV]

            auxstrg = cdatstr + cntpstr
            dou.save_npa(wft, fstring=cdatstr + cntpstr + '__w')
            dou.save_npa(mtxtb_stst, fstring=cdatstr + cntpstr + '__mtxtb')
            feedbackthroughdict = {None:
                                   dict(w=auxstrg + '__w',
                                        mtxtb=auxstrg + '__mtxtb')}

            cns = 0
            soldict.update(data_prfx=data_prfx+'_cns{0}'.format(cns))
            if linearized_nse:
                soldict.update(vel_pcrd_stps=0,
                               vel_nwtn_stps=1,
                               lin_vel_point={None: lin_point})
            dictofvels = snu.\
                solve_nse(return_dictofvelstrs=True,
                          closed_loop=True,
                          static_feedback=True,
                          tb_mat=tb_mat,
                          stokes_flow=stokes_flow,
                          clearprvveldata=True,
                          feedbackthroughdict=feedbackthroughdict, **soldict)

        else:  # time dep closed loop

            cns_data_prfx = 'data/cnsvars'
            invd = init_nwtnstps_value_dict
            curnwtnsdict = invd(tmesh=tip['tmesh'],
                                data_prfx=cns_data_prfx)
            # initialization: compute the forward solution
            if stokes_flow:
                dictofvels = None
            else:
                dictofvels = snu.solve_nse(return_dictofvelstrs=True,
                                           stokes_flow=stokes_flow,
                                           **soldict)

            # dbs.plot_vel_norms(tip['tmesh'], dictofvels)

            # function for the time depending parts
            # -- to be passed to the solver
            def get_tdpart(time=None, dictofvalues=None, feedback=False,
                           V=None, invinds=None, diribcs=None, **kw):

                if stokes_flow:
                    convc_mat = sps.csr_matrix((NV, NV))
                    rhs_con, rhsv_conbc = np.zeros((NV, 1)), np.zeros((NV, 1))
                else:
                    curvel = dou.load_npa(dictofvalues[time])
                    convc_mat, rhs_con, rhsv_conbc = \
                        snu.get_v_conv_conts(prev_v=curvel, invinds=invinds,
                                             V=V, diribcs=diribcs)

                return convc_mat, rhsv_conbc+rhs_con

            gttdprtargs = dict(dictofvalues=dictofvels,
                               V=femp['V'],
                               diribcs=femp['diribcs'],
                               invinds=invinds)

            # old version rhs
            # ftilde = rhs_con + rhsv_conbc + rhsd_stbc['fv']
            for cns in range(outernwtnstps):

                datastrdict.update(data_prfx=data_prfx+cntpstr+'_cns{0}'.
                                   format(cns))
                soldict.update(data_prfx=data_prfx+cntpstr+'_cns{0}'.
                               format(cns))

                sfd = sdr.solve_flow_daeric
                feedbackthroughdict = \
                    sfd(mmat=M, amat=A, jmat=stokesmatsc['J'],
                        bmat=b_mat,
                        # cmat=ct_mat_reg.T,
                        mcmat=mct_mat_reg.T,
                        v_is_my=True, rmat=contp.alphau*u_masmat,
                        vmat=y_masmat, rhsv=rhsd_stbc['fv'],
                        gamma=contp.gamma,
                        rhsp=None,
                        tmesh=tip['tmesh'], ystarvec=contp.ystarvec,
                        nwtn_adi_dict=tip['nwtn_adi_dict'],
                        comprz_thresh=tip['comprz_thresh'],
                        comprz_maxc=tip['comprz_maxc'], save_full_z=False,
                        get_tdpart=get_tdpart, gttdprtargs=gttdprtargs,
                        curnwtnsdict=curnwtnsdict,
                        get_datastr=get_datastr, gtdtstrargs=datastrdict)

                # for t in tip['tmesh']:  # feedbackthroughdict.keys():
                #     curw = dou.load_npa(feedbackthroughdict[t]['mtxtb'])
                #     print cns, t, np.linalg.norm(curw)

                cdatstr = get_datastr(time='all', meshp=N, nu=nu,
                                      Nts=None, data_prfx=data_prfx)

                if linearized_nse:
                    dictofvels = snu.\
                        solve_nse(return_dictofvelstrs=True,
                                  closed_loop=True, tb_mat=tb_mat,
                                  lin_vel_point=dictofvels,
                                  feedbackthroughdict=feedbackthroughdict,
                                  vel_nwtn_stps=1,
                                  vel_pcrd_stps=0,
                                  **soldict)
                else:
                    dictofvels = snu.\
                        solve_nse(return_dictofvelstrs=True,
                                  closed_loop=True, tb_mat=tb_mat,
                                  stokes_flow=stokes_flow,
                                  feedbackthroughdict=feedbackthroughdict,
                                  vel_pcrd_stps=1,
                                  vel_nwtn_stps=2,
                                  **soldict)

                # for t in dictofvels.keys():
                #     curw = dou.load_npa(dictofvels[t])
                #     print cns, t, np.linalg.norm(curw)

                gttdprtargs.update(dictofvalues=dictofvels)
    else:
        # no control
        feedbackthroughdict = None
        tb_mat = None
        cdatstr = get_datastr(meshp=N, nu=nu, time='all',
                              Nts=Nts, data_prfx=data_prfx)

        soldict.update(clearprvdata=True)
        dictofvels = snu.solve_nse(feedbackthroughdict=feedbackthroughdict,
                                   tb_mat=tb_mat, closed_loop=closed_loop,
                                   stokes_flow=stokes_flow,
                                   return_dictofvelstrs=True,
                                   static_feedback=stst_control,
                                   **soldict)

    (yscomplist,
     ystarlist) = dou.extract_output(dictofpaths=dictofvels,
                                     tmesh=tip['tmesh'],
                                     c_mat=c_mat, ystarvec=contp.ystarvec)

    save_output_json(yscomplist, tip['tmesh'].tolist(), ystar=ystarlist,
                     fstring=cdatstr + cntpstr + '__sigout')

    costfunval = eval_costfunc(W=y_masmat, V=contp.gamma*y_masmat,
                               R=None, tbmat=tb_mat, cmat=c_mat,
                               ystar=contp.ystarvec,
                               tmesh=tip['tmesh'], veldict=dictofvels,
                               fbftdict=feedbackthroughdict)

    print 'Value of cost functional: ', costfunval

    costfunval = eval_costfunc(W=y_masmat, V=contp.gamma*y_masmat,
                               R=None, tbmat=tb_mat, cmat=c_mat,
                               ystar=contp.ystarvec, penau=False,
                               tmesh=tip['tmesh'], veldict=dictofvels,
                               fbftdict=feedbackthroughdict)

    print 'Value of cost functional not considering `u`: ', costfunval

    print 'dim of v :', femp['V'].dim()
    charlene = .15 if problemname == 'cylinderwake' else 1.0
    print 'Re = charL / nu = {0}'.format(charlene/nu)
def test_qbdae_ass(problemname='cylinderwake', N=1, Re=None, nu=3e-2,
                   t0=0.0, tE=1.0, Nts=100, use_saved_mats=None):

    trange = np.linspace(t0, tE, Nts+1)
    DT = (tE-t0)/Nts
    rdir = 'results/'
    ddir = 'data/'

    if use_saved_mats is None:
        femp, stokesmatsc, rhsd_vfrc, rhsd_stbc = \
            dns.problem_setups.get_sysmats(problem=problemname, N=N, Re=Re)
        invinds = femp['invinds']

        A, J, M = stokesmatsc['A'], stokesmatsc['J'], stokesmatsc['M']
        L = 0*A
        fvc, fpc = rhsd_vfrc['fvc'], rhsd_vfrc['fpr']
        fv_stbc, fp_stbc = rhsd_stbc['fv'], rhsd_stbc['fp']

        hstr = ddir + problemname + '_N{0}_hmat'.format(N)
        try:
            hmat = dou.load_spa(hstr)
            print('loaded `hmat`')
        except IOError:
            print('assembling hmat ...')
            hmat = dnsts.ass_convmat_asmatquad(W=femp['V'], invindsw=invinds)
            dou.save_spa(hmat, hstr)

        invinds = femp['invinds']
        NV, NP = invinds.shape[0], J.shape[0]
        zerv = np.zeros((NV, 1))

        bc_conv, bc_rhs_conv, rhsbc_convbc = \
            snu.get_v_conv_conts(prev_v=zerv, V=femp['V'], invinds=invinds,
                                 diribcs=femp['diribcs'], Picard=False)
        fp = fp_stbc + fpc
        fv = fv_stbc + fvc - bc_rhs_conv

        if linnsesol:
            vp_nse, _ = snu.\
                solve_steadystate_nse(A=A, J=J, JT=None, M=M,
                                      fv=fv_stbc + fvc,
                                      fp=fp_stbc + fpc,
                                      V=femp['V'], Q=femp['Q'],
                                      invinds=invinds,
                                      diribcs=femp['diribcs'],
                                      return_vp=False, ppin=-1,
                                      N=N, nu=nu,
                                      clearprvdata=False)
            old_v = vp_nse[:NV]
        else:
            import sadptprj_riclyap_adi.lin_alg_utils as lau
            # Stokes solution as initial value
            vp_stokes = lau.solve_sadpnt_smw(amat=A, jmat=J,
                                             rhsv=fv_stbc + fvc,
                                             rhsp=fp_stbc + fpc)

            old_v = vp_stokes[:NV]

        sysmat = sps.vstack([sps.hstack([M+DT*(A+bc_conv), J.T]),
                             sps.hstack([J, sps.csc_matrix((NP, NP))])])

    if use_saved_mats is not None:
        # if saved as in ../get_exp_mats
        import scipy.io
        mats = scipy.io.loadmat(use_saved_mats)
        A = - mats['A']
        L = - mats['L']
        Re = mats['Re']
        N = A.shape[0]
        M = mats['M']
        J = mats['J']
        hmat = -mats['H']
        fv = mats['fv']
        fp = mats['fp']
        NV, NP = fv.shape[0], fp.shape[0]
        old_v = mats['ss_stokes']
        sysmat = sps.vstack([sps.hstack([M+DT*A, J.T]),
                             sps.hstack([J, sps.csc_matrix((NP, NP))])])

    if compevs:
        import matplotlib.pyplot as plt
        import scipy.linalg as spla

        hlstr = ddir + problemname + '_N{0}_Re{1}Nse{2}_hlmat'.\
            format(N, Re, linnsesol)
        HL = linearzd_quadterm(hmat, old_v, hlstr=hlstr)
        print(HL.shape)
        asysmat = sps.vstack([sps.hstack([-(A-L+HL), J.T]),
                              sps.hstack([J, sps.csc_matrix((NP, NP))])])
        msysmat = sps.vstack([sps.hstack([M, sps.csc_matrix((NV, NP))]),
                              sps.hstack([sps.csc_matrix((NP, NV)),
                                          sps.csc_matrix((NP, NP))])])
        levstr = ddir + problemname + '_N{0}Re{1}Nse{2}_levs'.\
            format(N, Re, linnsesol)
        try:
            levs = dou.load_npa(levstr)
            if debug:
                raise IOError()
            print('loaded the eigenvalues of the linearized system')
        except IOError:
            print('computing the eigenvalues of the linearized system')
            A = asysmat.todense()
            M = msysmat.todense()
            levs = spla.eigvals(A, M, overwrite_a=True, check_finite=False)
            dou.save_npa(levs, levstr)

        plt.figure(1)
        # plt.xlim((-25, 15))
        # plt.ylim((-50, 50))
        plt.plot(np.real(levs), np.imag(levs), '+')
        plt.show(block=False)

    if timeint:
        print('computing LU once...')
        sysmati = spsla.factorized(sysmat)

        vfile = dolfin.File(rdir + problemname + 'qdae__vel.pvd')
        pfile = dolfin.File(rdir + problemname + 'qdae__p.pvd')

        prvoutdict = dict(V=femp['V'], Q=femp['Q'], vfile=vfile, pfile=pfile,
                          invinds=invinds, diribcs=femp['diribcs'],
                          vp=None, t=None, writeoutput=True)

        print('doing the time loop...')
        for t in trange:
            crhsv = M*old_v + DT*(fv - hmat*np.kron(old_v, old_v))
            crhs = np.vstack([crhsv, fp])
            vp_new = np.atleast_2d(sysmati(crhs.flatten())).T

            prvoutdict.update(dict(vp=vp_new, t=t))
            dou.output_paraview(**prvoutdict)

            old_v = vp_new[:NV]
            print(t, np.linalg.norm(old_v))
def solve_steadystate_nse(A=None, J=None, JT=None, M=None,
                          fv=None, fp=None,
                          V=None, Q=None, invinds=None, diribcs=None,
                          dbcvals=None, dbcinds=None,
                          diricontbcinds=None, diricontbcvals=None,
                          diricontfuncs=None,
                          return_vp=False, ppin=-1,
                          return_nwtnupd_norms=False,
                          N=None, nu=None,
                          vel_pcrd_stps=10, vel_pcrd_tol=1e-4,
                          vel_nwtn_stps=20, vel_nwtn_tol=5e-15,
                          clearprvdata=False,
                          useolddata=False,
                          vel_start_nwtn=None,
                          get_datastring=None,
                          data_prfx='',
                          paraviewoutput=False,
                          save_data=True,
                          save_intermediate_steps=False,
                          vfileprfx='', pfileprfx='',
                          verbose=True,
                          **kw):

    """
    Solution of the steady state nonlinear NSE Problem

    using Newton's scheme. If no starting value is provided, the iteration
    is started with the steady state Stokes solution.

    Parameters
    ----------
    A : (N,N) sparse matrix
        stiffness matrix aka discrete Laplacian, note the sign!
    M : (N,N) sparse matrix
        mass matrix
    J : (M,N) sparse matrix
        discrete divergence operator
    JT : (N,M) sparse matrix, optional
        discrete gradient operator, set to J.T if not provided
    fv, fp : (N,1), (M,1) ndarrays
        right hand sides restricted via removing the boundary nodes in the
        momentum and the pressure freedom in the continuity equation
    ppin : {int, None}, optional
        which dof of `p` is used to pin the pressure, defaults to `-1`
    dbcinds: list, optional
        indices of the Dirichlet boundary conditions
    dbcvals: list, optional
        values of the Dirichlet boundary conditions (as listed in `dbcinds`)
    diricontbcinds: list, optional
        list of dirichlet indices that are to be controlled
    diricontbcvals: list, optional
        list of the vals corresponding to `diricontbcinds`
    diricontfuncs: list, optional
        list like `[ufunc]` where `ufunc: (t, v) -> u` where `u` is used to
        scale the corresponding `diricontbcvals`
    return_vp : boolean, optional
        whether to return also the pressure, defaults to `False`
    vel_pcrd_stps : int, optional
        Number of Picard iterations when computing a starting value for the
        Newton scheme, cf. Elman, Silvester, Wathen: *FEM and fast iterative
        solvers*, 2005, defaults to `100`
    vel_pcrd_tol : real, optional
        tolerance for the size of the Picard update, defaults to `1e-4`
    vel_nwtn_stps : int, optional
        Number of Newton iterations, defaults to `20`
    vel_nwtn_tol : real, optional
        tolerance for the size of the Newton update, defaults to `5e-15`

    Returns:
    ---
    vel_k : (N, 1) ndarray
        the velocity vector, if not `return_vp`, else
    (v, p) : tuple
        of the velocity and the pressure vector
    norm_nwtnupd_list : list, on demand
        list of the newton upd errors
    """

    import sadptprj_riclyap_adi.lin_alg_utils as lau

    if get_datastring is None:
        get_datastring = get_datastr_snu

    if JT is None:
        JT = J.T

    NV = J.shape[1]

#
# Compute or load the uncontrolled steady state Navier-Stokes solution
#

    norm_nwtnupd_list = []
    # a dict to be passed to the get_datastring function
    datastrdict = dict(time=None, meshp=N, nu=nu,
                       Nts=None, data_prfx=data_prfx)

    if clearprvdata:
        cdatstr = get_datastring(**datastrdict)
        for fname in glob.glob(cdatstr + '*__vel*'):
            os.remove(fname)

    if useolddata:
        try:
            cdatstr = get_datastring(**datastrdict)

            norm_nwtnupd = dou.load_npa(cdatstr + '__norm_nwtnupd')
            vel_k = dou.load_npa(cdatstr + '__vel')
            norm_nwtnupd_list.append(norm_nwtnupd)

            if verbose:
                print('found vel files')
                print('norm of last Nwtn update: {0}'.format(norm_nwtnupd))
                print('... loaded from ' + cdatstr)
            if np.atleast_1d(norm_nwtnupd)[0] is None:
                norm_nwtnupd = None
                pass  # nothing useful found

            elif norm_nwtnupd < vel_nwtn_tol:
                if not return_vp:
                    return vel_k, norm_nwtnupd_list
                else:
                    pfv = get_pfromv(v=vel_k[:NV, :], V=V,
                                     M=M, A=A, J=J, fv=fv,
                                     dbcinds=dbcinds, dbcvals=dbcvals,
                                     invinds=invinds, diribcs=diribcs)
                    return (np.vstack([vel_k, pfv]), norm_nwtnupd_list)

        except IOError:
            if verbose:
                print('no old velocity data found')
            norm_nwtnupd = None

    else:
        # we start from scratch
        norm_nwtnupd = None

    if paraviewoutput:
        cdatstr = get_datastring(**datastrdict)
        vfile = dolfin.File(vfileprfx+'__steadystates.pvd')
        pfile = dolfin.File(pfileprfx+'__steadystates.pvd')
        prvoutdict = dict(V=V, Q=Q, vfile=vfile, pfile=pfile,
                          invinds=invinds, diribcs=diribcs, ppin=ppin,
                          dbcinds=dbcinds, dbcvals=dbcvals,
                          vp=None, t=None, writeoutput=True)
    else:
        prvoutdict = dict(writeoutput=False)  # save 'if statements' later

    NV = A.shape[0]
    if vel_start_nwtn is None:
        loccntbcinds, cntrlldbcvals, glbcntbcinds = [], [], []
        if diricontbcinds is None or diricontbcinds == []:
            cmmat, camat, cj, cjt, cfv, cfp = M, A, J, JT, fv, fp
            cnv = NV
            dbcntinvinds = invinds
        else:
            def _localizecdbinds(cdbinds):
                """ find the local indices of the control dirichlet boundaries

                the given control dirichlet boundaries were indexed w.r.t. the
                full space `V`. Here, in the matrices, we have already
                resolved the constant Dirichlet bcs
                """
                allinds = np.arange(V.dim())
                redcdallinds = allinds[invinds]
                # now: find the positions of the control dbcs in the reduced
                # index vector
                lclinds = np.searchsorted(redcdallinds, cdbinds, side='left')
                return lclinds

            for k, cdbidbv in enumerate(diricontbcinds):
                ccntrlfunc = diricontfuncs[k]

                # no time at steady state, no starting value
                cntrlval = ccntrlfunc(None, None)

                localbcinds = (_localizecdbinds(cdbidbv)).tolist()
                loccntbcinds.extend(localbcinds)  # adding the boundary inds
                glbcntbcinds.extend(cdbidbv)
                ccntrlldbcvals = [cntrlval*bcvl for bcvl in diricontbcvals[k]]
                # adding the scaled boundary values
                cntrlldbcvals.extend(ccntrlldbcvals)

            dbcntinvinds = np.setdiff1d(invinds, glbcntbcinds).astype(np.int32)
            matdict = dict(M=M, A=A, J=J, JT=JT, MP=None)
            cmmat, camat, cjt, cj, _, cfv, cfp, _ = dts.\
                condense_sysmatsbybcs(matdict, dbcinds=loccntbcinds,
                                      dbcvals=cntrlldbcvals, mergerhs=True,
                                      rhsdict=dict(fv=fv, fp=fp),
                                      ret_unrolled=True)
            cnv = cmmat.shape[0]

        vp_stokes = lau.solve_sadpnt_smw(amat=camat, jmat=cj, jmatT=cjt,
                                         rhsv=cfv, rhsp=cfp)
        vp_stokes[cnv:] = -vp_stokes[cnv:]
        # pressure was flipped for symmetry

        # save the data
        cdatstr = get_datastring(**datastrdict)

        if save_data:
            dou.save_npa(vp_stokes[:cnv, ], fstring=cdatstr + '__vel')

        prvoutdict.update(dict(vp=vp_stokes,
                               dbcinds=[dbcinds, glbcntbcinds],
                               dbcvals=[dbcvals, cntrlldbcvals],
                               invinds=dbcntinvinds))
        dou.output_paraview(**prvoutdict)

        # Stokes solution as starting value
        vp_k = vp_stokes
        vel_k = vp_stokes[:cnv, ]

    else:
        vel_k = vel_start_nwtn

    matdict = dict(M=M, A=A, J=J, JT=JT, MP=None)
    rhsdict = dict(fv=fv, fp=fp)
    cndnsmtsdct = dict(dbcinds=loccntbcinds, mergerhs=True,
                       ret_unrolled=True)

    # Picard iterations for a good starting value for Newton
    for k in range(vel_pcrd_stps):

        cntrlldbcvals = _unroll_cntrl_dbcs(diricontbcvals, diricontfuncs,
                                           time=None, vel=vel_k)
        (convc_mat,
         rhs_con, rhsv_conbc) = \
            get_v_conv_conts(prev_v=vel_k, V=V, diribcs=diribcs,
                             invinds=dbcntinvinds,
                             dbcinds=[dbcinds, glbcntbcinds],
                             dbcvals=[dbcvals, cntrlldbcvals], Picard=True)

        _, _, _, _, _, cfv, cfp, _ = dts.\
            condense_sysmatsbybcs(matdict, dbcvals=cntrlldbcvals,
                                  rhsdict=rhsdict, **cndnsmtsdct)

        vp_k = lau.solve_sadpnt_smw(amat=camat+convc_mat, jmat=cj, jmatT=cjt,
                                    rhsv=cfv+rhsv_conbc, rhsp=cfp)
        # vp_k = lau.solve_sadpnt_smw(amat=A+convc_mat, jmat=J, jmatT=JT,
        #                             rhsv=fv+rhsv_conbc,
        #                             rhsp=fp)

        normpicupd = np.sqrt(m_innerproduct(cmmat, vel_k-vp_k[:cnv, ]))[0]

        if verbose:
            print('Picard iteration: {0} -- norm of update: {1}'.
                  format(k+1, normpicupd))

        vel_k = vp_k[:cnv, ]
        vp_k[cnv:] = -vp_k[cnv:]
        # pressure was flipped for symmetry

        if normpicupd < vel_pcrd_tol:
            break

    # Newton iteration

    for vel_newtk, k in enumerate(range(vel_nwtn_stps)):

        cdatstr = get_datastring(**datastrdict)

        cntrlldbcvals = _unroll_cntrl_dbcs(diricontbcvals, diricontfuncs,
                                           time=None, vel=vel_k)
        _, _, _, _, _, cfv, cfp, _ = dts.\
            condense_sysmatsbybcs(matdict, dbcvals=cntrlldbcvals,
                                  rhsdict=rhsdict, **cndnsmtsdct)
        (convc_mat, rhs_con, rhsv_conbc) = \
            get_v_conv_conts(prev_v=vel_k, V=V, diribcs=diribcs,
                             invinds=dbcntinvinds,
                             dbcinds=[dbcinds, glbcntbcinds],
                             dbcvals=[dbcvals, cntrlldbcvals])

        vp_k = lau.solve_sadpnt_smw(amat=camat+convc_mat, jmat=cj, jmatT=cjt,
                                    rhsv=cfv+rhs_con+rhsv_conbc,
                                    rhsp=cfp)

        norm_nwtnupd = np.sqrt(m_innerproduct(cmmat, vel_k - vp_k[:cnv, :]))[0]
        vel_k = vp_k[:cnv, ]
        vp_k[cnv:] = -vp_k[cnv:]
        # pressure was flipped for symmetry
        if verbose:
            print('Steady State NSE: Newton iteration: {0}'.format(vel_newtk) +
                  '-- norm of update: {0}'.format(norm_nwtnupd))

        if save_data:
            dou.save_npa(vel_k, fstring=cdatstr + '__vel')

        prvoutdict.update(dict(vp=vp_k, dbcvals=[dbcvals, cntrlldbcvals]))
        dou.output_paraview(**prvoutdict)

        if norm_nwtnupd < vel_nwtn_tol:
            break

    else:
        if vel_nwtn_stps == 0:
            print('No Newton steps = steady state probably not well converged')
        else:
            raise UserWarning('Steady State NSE: Newton has not converged')

    if save_data:
        dou.save_npa(norm_nwtnupd, cdatstr + '__norm_nwtnupd')

    prvoutdict.update(dict(vp=vp_k, dbcvals=[dbcvals, cntrlldbcvals]))
    dou.output_paraview(**prvoutdict)

    # savetomatlab = True
    # if savetomatlab:
    #     export_mats_to_matlab(E=None, A=None, matfname='matexport')

    vwc = _attach_cntbcvals(vel_k.flatten(), globbcinvinds=dbcntinvinds,
                            globbcinds=glbcntbcinds, dbcvals=cntrlldbcvals,
                            invinds=invinds, NV=V.dim())
    if return_vp:
        retthing = (vwc.reshape((NV, 1)), vp_k[cnv:, :])
    else:
        retthing = vwc.reshape((NV, 1))

    if return_nwtnupd_norms:
        return retthing, norm_nwtnupd_list
    else:
        return retthing
Example #16
0
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
Example #17
0
def comp_exp_nsmats(problemname='drivencavity',
                    N=10,
                    Re=1e2,
                    nu=None,
                    linear_system=False,
                    refree=False,
                    bccontrol=False,
                    palpha=None,
                    use_old_data=False,
                    mddir='pathtodatastorage'):
    """compute and export the system matrices for Navier-Stokes equations

    Parameters
    ---
    refree : boolean, optional
        whether to use `Re=1` (so that the `Re` number can be applied later by
        scaling the corresponding matrices, defaults to `False`
    linear_system : boolean, optional
        whether to compute/return the linearized system, defaults to `False`
    bccontrol : boolean, optional
        whether to model boundary control at the cylinder via penalized robin
        boundary conditions, defaults to `False`
    palpha : float, optional
        penalization parameter for the boundary control, defaults to `None`,
        `palpha` is mandatory for `linear_system`

    """

    if refree:
        Re = 1
        print 'For the Reynoldsnumber free mats, we set Re=1'

    if problemname == 'drivencavity' and bccontrol:
        raise NotImplementedError('boundary control for the driven cavity' +
                                  ' is not implemented yet')

    if linear_system and bccontrol and palpha is None:
        raise UserWarning('For the linear system a' +
                          ' value for `palpha` is needed')
    if not linear_system and bccontrol:
        raise NotImplementedError('Nonlinear system with boundary control' +
                                  ' is not implemented yet')
    femp, stokesmatsc, rhsd_vfrc, rhsd_stbc = \
        dnsps.get_sysmats(problem=problemname, bccontrol=bccontrol, N=N, Re=Re)
    if linear_system and bccontrol:
        Arob = stokesmatsc['A'] + 1. / palpha * stokesmatsc['Arob']
        Brob = 1. / palpha * stokesmatsc['Brob']
    elif linear_system:
        Brob = 0

    invinds = femp['invinds']
    A, J = stokesmatsc['A'], stokesmatsc['J']
    fvc, fpc = rhsd_vfrc['fvc'], rhsd_vfrc['fpr']
    fv_stbc, fp_stbc = rhsd_stbc['fv'], rhsd_stbc['fp']
    invinds = femp['invinds']
    NV = invinds.shape[0]
    data_prfx = problemname + '__N{0}Re{1}'.format(N, Re)
    if bccontrol:
        data_prfx = data_prfx + '_penarob'

    soldict = stokesmatsc  # containing A, J, JT
    soldict.update(femp)  # adding V, Q, invinds, diribcs
    soldict.update(rhsd_vfrc)  # adding fvc, fpr
    fv = rhsd_vfrc['fvc'] + rhsd_stbc['fv']
    fp = rhsd_vfrc['fpr'] + rhsd_stbc['fp']
    # print 'get expmats: ||fv|| = {0}'.format(np.linalg.norm(fv))
    # print 'get expmats: ||fp|| = {0}'.format(np.linalg.norm(fp))
    # import scipy.sparse.linalg as spsla
    # print 'get expmats: ||A|| = {0}'.format(spsla.norm(A))
    # print 'get expmats: ||Arob|| = {0}'.format(spsla.norm(Arob))
    # print 'get expmats: ||A|| = {0}'.format(spsla.norm(stokesmatsc['A']))
    # raise Warning('TODO: debug')

    soldict.update(fv=fv,
                   fp=fp,
                   N=N,
                   nu=nu,
                   clearprvdata=~use_old_data,
                   get_datastring=None,
                   data_prfx=ddir + data_prfx + '_stst',
                   paraviewoutput=False)
    if bccontrol and linear_system:
        soldict.update(A=Arob)

    # compute the uncontrolled steady state Navier-Stokes solution
    vp_ss_nse, list_norm_nwtnupd = snu.solve_steadystate_nse(return_vp=True,
                                                             **soldict)
    v_ss_nse, p_ss_nse = vp_ss_nse[:NV], vp_ss_nse[NV:]

    # specify in what spatial direction Bu changes. The remaining is constant
    if problemname == 'drivencavity':
        uspacedep = 0
    elif problemname == 'cylinderwake':
        uspacedep = 1

    #
    # Control mats
    #
    contsetupstr = problemname + '__NV{0}NU{1}NY{2}'.format(NV, NU, NY)

    # get the control and observation operators
    try:
        b_mat = dou.load_spa(ddir + contsetupstr + '__b_mat')
        u_masmat = dou.load_spa(ddir + contsetupstr + '__u_masmat')
        print 'loaded `b_mat`'
    except IOError:
        print 'computing `b_mat`...'
        b_mat, u_masmat = cou.get_inp_opa(cdcoo=femp['cdcoo'],
                                          V=femp['V'],
                                          NU=NU,
                                          xcomp=uspacedep)
        dou.save_spa(b_mat, ddir + contsetupstr + '__b_mat')
        dou.save_spa(u_masmat, ddir + contsetupstr + '__u_masmat')
    try:
        mc_mat = dou.load_spa(ddir + contsetupstr + '__mc_mat')
        y_masmat = dou.load_spa(ddir + contsetupstr + '__y_masmat')
        print 'loaded `c_mat`'
    except IOError:
        print 'computing `c_mat`...'
        mc_mat, y_masmat = cou.get_mout_opa(odcoo=femp['odcoo'],
                                            V=femp['V'],
                                            NY=NY)
        dou.save_spa(mc_mat, ddir + contsetupstr + '__mc_mat')
        dou.save_spa(y_masmat, ddir + contsetupstr + '__y_masmat')

    # restrict the operators to the inner nodes
    mc_mat = mc_mat[:, invinds][:, :]
    b_mat = b_mat[invinds, :][:, :]

    c_mat = lau.apply_massinv(y_masmat, mc_mat, output='sparse')
    # TODO: right choice of norms for y
    #       and necessity of regularization here
    #       by now, we go on number save

    # the pressure observation mean over a small domain
    if problemname == 'cylinderwake':
        podcoo = dict(xmin=0.6, xmax=0.64, ymin=0.18, ymax=0.22)
    elif problemname == 'drivencavity':
        podcoo = dict(xmin=0.45, xmax=0.55, ymin=0.7, ymax=0.8)
    else:
        podcoo = femp['odcoo']

    # description of the control and observation domains
    dmd = femp['cdcoo']
    xmin, xmax, ymin, ymax = dmd['xmin'], dmd['xmax'], dmd['ymin'], dmd['ymax']
    velcondomstr = 'vel control domain: [{0}, {1}]x[{2}, {3}]\n'.\
        format(xmin, xmax, ymin, ymax)
    dmd = femp['odcoo']
    xmin, xmax, ymin, ymax = dmd['xmin'], dmd['xmax'], dmd['ymin'], dmd['ymax']
    velobsdomstr = 'vel observation domain: [{0}, {1}]x[{2}, {3}]\n'.\
        format(xmin, xmax, ymin, ymax)
    dmd = podcoo
    xmin, xmax, ymin, ymax = dmd['xmin'], dmd['xmax'], dmd['ymin'], dmd['ymax']
    pobsdomstr = 'pressure observation domain: [{0}, {1}]x[{2}, {3}]\n'.\
        format(xmin, xmax, ymin, ymax)

    pcmat = cou.get_pavrg_onsubd(odcoo=podcoo, Q=femp['Q'], ppin=None)

    cdatstr = snu.get_datastr_snu(time=None, meshp=N, nu=nu, Nts=None)

    (coors, xinds, yinds, corfunvec) = dts.get_dof_coors(femp['V'],
                                                         invinds=invinds)

    ctrl_visu_str = \
        ' the (distributed) control setup is as follows \n' +\
        ' B maps into the domain of control -' +\
        velcondomstr +\
        ' the first half of the columns' +\
        'actuate in x-direction, the second in y direction \n' +\
        ' Cv measures averaged velocities in the domain of observation' +\
        velobsdomstr +\
        ' Cp measures the averaged pressure' +\
        ' in the domain of pressure observation: ' +\
        pobsdomstr +\
        ' the first components are in x, the last in y-direction \n\n' +\
        ' Visualization: \n\n' +\
        ' `coors`   -- array of (x,y) coordinates in ' +\
        ' the same order as v[xinds] or v[yinds] \n' +\
        ' `xinds`, `yinds` -- indices of x and y components' +\
        ' of v = [vx, vy] -- note that indexing starts with 0\n' +\
        ' for testing use corfunvec wich is the interpolant of\n' +\
        ' f(x,y) = [x, y] on the grid \n\n' +\
        'Created in `get_exp_nsmats.py` ' +\
        '(see https://github.com/highlando/dolfin_navier_scipy) at\n' +\
        datetime.datetime.now().strftime("%I:%M%p on %B %d, %Y")

    if bccontrol and problemname == 'cylinderwake' and linear_system:
        ctrl_visu_str = \
            ('the boundary control is realized via penalized robin \n' +
             'boundary conditions, cf. e.g. [Hou/Ravindran `98], \n' +
             'with predefined shape functions for the cylinder wake \n' +
             'and the penalization parameter `palpha`={0}.').format(palpha) +\
            ctrl_visu_str

    if linear_system:
        convc_mat, rhs_con, rhsv_conbc = \
            snu.get_v_conv_conts(prev_v=v_ss_nse, invinds=invinds,
                                 V=femp['V'], diribcs=femp['diribcs'])
        # TODO: omg
        if bccontrol:
            f_mat = -Arob - convc_mat
        else:
            f_mat = -stokesmatsc['A'] - convc_mat

        infostr = 'These are the coefficient matrices of the linearized ' +\
            'Navier-Stokes Equations \n for the ' +\
            problemname + ' to be used as \n\n' +\
            ' $M \\dot v = Av + J^Tp + Bu$   and  $Jv = 0$ \n\n' +\
            ' the Reynoldsnumber is computed as L/nu \n' +\
            ' Note this is the reduced system for the velocity update\n' +\
            ' caused by the control, i.e., no boundary conditions\n' +\
            ' or inhomogeneities here. To get the actual flow, superpose \n' +\
            ' the steadystate velocity solution `v_ss_nse` \n\n' +\
            ctrl_visu_str

        matstr = (mddir + problemname + '__mats_N{0}_Re{1}').format(NV, Re)
        if bccontrol:
            matstr = matstr + '__penarob_palpha{0}'.format(palpha)

        scipy.io.savemat(
            matstr,
            dict(A=f_mat,
                 M=stokesmatsc['M'],
                 nu=femp['nu'],
                 Re=femp['Re'],
                 J=stokesmatsc['J'],
                 B=b_mat,
                 C=c_mat,
                 Cp=pcmat,
                 Brob=Brob,
                 v_ss_nse=v_ss_nse,
                 info=infostr,
                 contsetupstr=contsetupstr,
                 datastr=cdatstr,
                 coors=coors,
                 xinds=xinds,
                 yinds=yinds,
                 corfunvec=corfunvec))

        print('matrices saved to ' + matstr)

    elif refree:
        hstr = ddir + problemname + '_N{0}_hmat'.format(N)
        try:
            hmat = dou.load_spa(hstr)
            print 'loaded `hmat`'
        except IOError:
            print 'assembling hmat ...'
            hmat = dts.ass_convmat_asmatquad(W=femp['V'], invindsw=invinds)
            dou.save_spa(hmat, hstr)

        zerv = np.zeros((NV, 1))
        bc_conv, bc_rhs_conv, rhsbc_convbc = \
            snu.get_v_conv_conts(prev_v=zerv, V=femp['V'], invinds=invinds,
                                 diribcs=femp['diribcs'], Picard=False)

        # diff_mat = stokesmatsc['A']
        # bcconv_mat = bc_conv
        # fv_bcdiff = fv_stbc
        # fv_bcconv = - bc_rhs_conv
        fv = fvc
        fp = fpc
        # fp_bc = fp_stbc

        infostr = 'These are the coefficient matrices of the quadratic ' +\
            'formulation of the Navier-Stokes Equations \n for the ' +\
            problemname + ' to be used as \n\n' +\
            ' $M \\dot v + Av + H*kron(v,v) + J^Tp = Bu + fv$ \n' +\
            ' and  $Jv = fp$ \n\n' +\
            ' the Reynoldsnumber is computed as L/nu \n' +\
            ' note that `A` contains the diffusion and the linear term \n' +\
            ' that comes from the dirichlet boundary values \n' +\
            ' as initial value one can use the provided steady state \n' +\
            ' Stokes solution \n' +\
            ' see https://github.com/highlando/dolfin_navier_scipy/blob/' +\
            ' master/tests/solve_nse_quadraticterm.py for appl example\n' +\
            ctrl_visu_str

        scipy.io.savemat(
            mddir + problemname + 'quadform__mats_N{0}_Re{1}'.format(NV, Re),
            dict(
                A=f_mat,
                M=stokesmatsc['M'],
                H=-hmat,
                fv=fv,
                fp=fp,
                nu=femp['nu'],
                Re=femp['Re'],
                J=stokesmatsc['J'],
                B=b_mat,
                Cv=c_mat,
                Cp=pcmat,
                info=infostr,
                # ss_stokes=old_v,
                contsetupstr=contsetupstr,
                datastr=cdatstr,
                coors=coors,
                xinds=xinds,
                yinds=yinds,
                corfunvec=corfunvec))
    else:
        hstr = ddir + problemname + '_N{0}_hmat'.format(N)
        try:
            hmat = dou.load_spa(hstr)
            print 'loaded `hmat`'
        except IOError:
            print 'assembling hmat ...'
            hmat = dts.ass_convmat_asmatquad(W=femp['V'], invindsw=invinds)
            dou.save_spa(hmat, hstr)

        zerv = np.zeros((NV, 1))
        bc_conv, bc_rhs_conv, rhsbc_convbc = \
            snu.get_v_conv_conts(prev_v=zerv, V=femp['V'], invinds=invinds,
                                 diribcs=femp['diribcs'], Picard=False)

        f_mat = -stokesmatsc['A'] - bc_conv
        l_mat = -bc_conv
        fv = fv_stbc + fvc - bc_rhs_conv
        fp = fp_stbc + fpc

        vp_stokes = lau.solve_sadpnt_smw(amat=A,
                                         jmat=J,
                                         rhsv=fv_stbc + fvc,
                                         rhsp=fp_stbc + fpc)
        old_v = vp_stokes[:NV]
        p_stokes = -vp_stokes[NV:]  # the pressure was flipped for symmetry

        infostr = 'These are the coefficient matrices of the quadratic ' +\
            'formulation of the Navier-Stokes Equations \n for the ' +\
            problemname + ' to be used as \n\n' +\
            ' $M \\dot v = Av + H*kron(v,v) + J^Tp + Bu + fv$ \n' +\
            ' and  $Jv = fp$ \n\n' +\
            ' the Reynoldsnumber is computed as L/nu \n' +\
            ' note that `A` contains the diffusion and the linear term `L`\n' +\
            ' that comes from the dirichlet boundary values \n' +\
            ' for linearizations it might be necessary to consider `A-L` \n' +\
            ' as initial value one can use the provided steady state \n' +\
            ' Stokes solution \n' +\
            ' see https://github.com/highlando/dolfin_navier_scipy/blob/' +\
            ' master/tests/solve_nse_quadraticterm.py for appl example\n' +\
            ctrl_visu_str

        scipy.io.savemat(
            mddir + problemname + 'quadform__mats_N{0}_Re{1}'.format(NV, Re),
            dict(A=f_mat,
                 M=stokesmatsc['M'],
                 H=-hmat,
                 fv=fv,
                 fp=fp,
                 L=l_mat,
                 nu=femp['nu'],
                 Re=femp['Re'],
                 J=stokesmatsc['J'],
                 B=b_mat,
                 Cv=c_mat,
                 Cp=pcmat,
                 info=infostr,
                 p_ss_stokes=p_stokes,
                 p_ss_nse=p_ss_nse,
                 v_ss_stokes=old_v,
                 v_ss_nse=v_ss_nse,
                 contsetupstr=contsetupstr,
                 datastr=cdatstr,
                 coors=coors,
                 xinds=xinds,
                 yinds=yinds,
                 corfunvec=corfunvec))
def cnab(trange=None,
         inivel=None,
         inip=None,
         bcs_ini=[],
         M=None,
         A=None,
         J=None,
         f_vdp=None,
         f_tdp=None,
         g_tdp=None,
         scalep=-1.,
         getbcs=None,
         applybcs=None,
         appndbcs=None,
         savevp=None,
         dynamic_rhs=None,
         dynamic_rhs_memory={},
         ntimeslices=10,
         verbose=True):

    dtvec = np.array(trange)[1:] - np.array(trange)[:-1]
    dotdtvec = dtvec[1:] - dtvec[:-1]
    uniformgrid = np.allclose(np.linalg.norm(dotdtvec), 0)
    if verbose:
        import time

    if not uniformgrid:
        raise NotImplementedError()

    dt = trange[1] - trange[0]
    NP, NV = J.shape
    zerorhs = np.zeros((NV, 1))

    if dynamic_rhs is None:

        def dynamic_rhs(t, vc=None, memory={}, mode=None):
            return zerorhs, memory

    drm = dynamic_rhs_memory

    savevp(appndbcs(inivel, bcs_ini), inip, time=trange[0])

    bcs_c = bcs_ini  # getbcs(trange[0], inivel, inip)
    bfv_c, bfp_c, mbc_c = applybcs(bcs_c)
    fv_c = f_tdp(trange[0])
    nfc_c = f_vdp(appndbcs(inivel, bcs_ini))
    dfv_c, drm = dynamic_rhs(trange[0], vc=inivel, memory=drm, mode='init')
    tdfv, drm = dynamic_rhs(trange[0], vc=inivel, memory=drm, mode='heunpred')

    tbcs = getbcs(trange[1], appndbcs(inivel, bcs_ini), inip, mode='heunpred')
    tbfv, tbfp, tmbc = applybcs(tbcs)
    fv_n, fp_n = f_tdp(trange[1]), g_tdp(trange[1])

    # Predictor Step -- CN + explicit Euler
    tfv = M*inivel - .5*dt*A*inivel + .5*dt*(fv_c+fv_n + tbfv+bfv_c + tdfv+dfv_c) \
        + dt*nfc_c - (tmbc-mbc_c)

    tvp_new, coeffmatlu = \
        lau.solve_sadpnt_smw(amat=M+.5*dt*A, jmat=J, jmatT=J.T,
                             rhsv=tfv,
                             rhsp=fp_n+tbfp,
                             return_alu=True)
    tv_new = tvp_new[:NV, :]
    tp_new = 1. / dt * scalep * tvp_new[NV:, :]
    savevp(appndbcs(tv_new, tbcs), tp_new, time=(trange[1], 'heunpred'))

    # Corrector Step
    dfv_n, drm = dynamic_rhs(trange[1], vc=tv_new, memory=drm, mode='heuncorr')
    nfc_n = f_vdp(appndbcs(tv_new, tbcs))
    bcs_n = getbcs(trange[1], appndbcs(tv_new, tbcs), tp_new, mode='heuncorr')
    bfv_n, bfp_n, mbc_n = applybcs(bcs_n)
    rhs_n = M*inivel - .5*dt*A*inivel - (mbc_n-mbc_c) +\
        .5*dt*(fv_c+fv_n + bfv_n+bfv_c + dfv_n+tdfv + nfc_c+nfc_n)

    vp_new = coeffmatlu(np.vstack([rhs_n, fp_n + bfp_n]).flatten())
    v_new = vp_new[:NV].reshape((NV, 1))
    p_new = 1. / dt * scalep * vp_new[NV:].reshape((NP, 1))

    savevp(appndbcs(v_new, bcs_n), p_new, time=trange[1])

    lltr = np.array(trange[2:])
    lnts = lltr.size
    lenofts = np.floor(lnts / ntimeslices).astype(np.int)
    listofts = [
        lltr[k * lenofts:(k + 1) * lenofts].tolist()
        for k in range(ntimeslices)
    ]
    listofts.append(lltr[ntimeslices * lenofts:].tolist())

    verbose = True
    for kck, ctrange in enumerate(listofts):
        if verbose:
            print('time-stepping {0}/{1} complete -- @runtime {2:.1f}'.format(
                kck, ntimeslices, time.clock()))
        for ctime in ctrange:
            v_old, p_old = v_new, p_new
            bcs_c = bcs_n
            bfv_c, mbc_c = bfv_n, mbc_n
            fv_c = fv_n
            dfv_c = dfv_n

            nfc_o = nfc_c
            nfc_c = f_vdp(appndbcs(v_old, bcs_c))

            bcs_n = getbcs(ctime, appndbcs(v_old, bcs_c), p_old, mode='abtwo')
            bfv_n, bfp_n, mbc_n = applybcs(bcs_n)
            fv_n, fp_n = f_tdp(ctime), g_tdp(ctime)
            dfv_n, drm = dynamic_rhs(ctime, vc=v_old, memory=drm, mode='abtwo')

            rhs_n = M*v_old - .5*dt*A*v_old + 1.5*dt*nfc_c-.5*dt*nfc_o \
                - (mbc_n-mbc_c) \
                + .5*dt*(fv_c+fv_n + bfv_n+bfv_c + dfv_n+dfv_c)

            vp_new = coeffmatlu(np.vstack([rhs_n, fp_n + bfp_n]).flatten())

            v_new = vp_new[:NV].reshape((NV, 1))
            p_new = 1. / dt * scalep * vp_new[NV:].reshape((NP, 1))

            savevp(appndbcs(v_new, bcs_n), p_new, time=ctime)

    return v_new, p_new
def solve_nse(A=None, M=None, J=None, JT=None,
              fv=None, fp=None,
              fvc=None, fpc=None,  # TODO: this is to catch deprecated calls
              fv_tmdp=None, fv_tmdp_params={},
              fv_tmdp_memory=None,
              iniv=None, lin_vel_point=None,
              stokes_flow=False,
              trange=None,
              t0=None, tE=None, Nts=None,
              V=None, Q=None, invinds=None, diribcs=None,
              dbcinds=None, dbcvals=None,
              output_includes_bcs=False,
              N=None, nu=None,
              ppin=-1,
              closed_loop=False, static_feedback=False,
              feedbackthroughdict=None,
              return_vp=False,
              tb_mat=None, cv_mat=None,
              vel_nwtn_stps=20, vel_nwtn_tol=5e-15,
              nsects=1, loc_nwtn_tol=5e-15, loc_pcrd_stps=True,
              addfullsweep=False,
              vel_pcrd_stps=4,
              krylov=None, krpslvprms={}, krplsprms={},
              clearprvdata=False,
              useolddata=False,
              get_datastring=None,
              data_prfx='',
              paraviewoutput=False,
              plttrange=None,
              vfileprfx='', pfileprfx='',
              return_dictofvelstrs=False,
              return_dictofpstrs=False,
              dictkeysstr=False,
              treat_nonl_explct=False,
              return_as_list=False,
              verbose=True,
              start_ssstokes=False,
              **kw):
    """
    solution of the time-dependent nonlinear Navier-Stokes equation

    .. math::
        M\\dot v + Av + N(v)v + J^Tp = f \n
        Jv =g

    using a Newton scheme in function space, i.e. given :math:`v_k`,
    we solve for the update like

    .. math::
        M\\dot v + Av + N(v_k)v + N(v)v_k + J^Tp = N(v_k)v_k + f,

    and trapezoidal rule in time. To solve an *Oseen* system (linearization
    about a steady state) or a *Stokes* system, set the number of Newton
    steps to one and provide a linearization point and an initial value.


    Parameters
    ----------
    lin_vel_point : dictionary, optional
        contains the linearization point for the first Newton iteration

         * Steady State: {{`None`: 'path_to_nparray'}, {'None': nparray}}
         * Newton: {`t`: 'path_to_nparray'}

        defaults to `None`
    dictkeysstr : boolean, optional
        whether the `keys` of the result dictionaries are strings instead \
        of floats, defaults to `False`
    fv_tmdp : callable f(t, v, dict), optional
        time-dependent part of the right-hand side, set to zero if None
    fv_tmdp_params : dictionary, optional
        dictionary of parameters to be passed to `fv_tmdp`, defaults to `{}`
    fv_tmdp_memory : dictionary, optional
        memory of the function
    output_includes_bcs : boolean, optional
        whether append the boundary nodes to the computed and stored \
        velocities, defaults to `False`
    krylov : {None, 'gmres'}, optional
        whether or not to use an iterative solver, defaults to `None`
    krpslvprms : dictionary, optional
        to specify parameters of the linear solver for use in Krypy, e.g.,

          * initial guess
          * tolerance
          * number of iterations

        defaults to `None`
    krplsprms : dictionary, optional
        parameters to define the linear system like

          * preconditioner

    ppin : {int, None}, optional
        which dof of `p` is used to pin the pressure, defaults to `-1`
    stokes_flow : boolean, optional
        whether to consider the Stokes linearization, defaults to `False`
    start_ssstokes : boolean, optional
        for your convenience, compute and use the steady state stokes solution
        as initial value, defaults to `False`
    treat_nonl_explct= string, optional
        whether to treat the nonlinearity explicitly, defaults to `False`
    nsects: int, optional
        in how many segments the trange is split up. (The newton iteration
        will be confined to the segments and, probably, converge faster than
        the global iteration), defaults to `1`
    loc_nwtn_tol: float, optional
        tolerance for the newton iteration on the segments,
        defaults to `1e-15`
    loc_pcrd_stps: boolean, optional
        whether to init with `vel_pcrd_stps` Picard steps on every section,
        if `False`, Picard iterations are performed only on the first section,
        defaults to `True`
    addfullsweep: boolean, optional
        whether to compute the newton iteration on the full `trange`,
        useful to check and for the plots, defaults to `False`
    cv_mat: (Ny, Nv) sparse array, optional
        output matrix for velocity outputs, needed, e.g., for output dependent
        feedback control, defaults to `None`

    Returns
    -------
    dictofvelstrs : dictionary, on demand
        dictionary with time `t` as keys and path to velocity files as values

    dictofpstrs : dictionary, on demand
        dictionary with time `t` as keys and path to pressure files as values

    vellist : list, on demand
        list of the velocity solutions

    """
    import sadptprj_riclyap_adi.lin_alg_utils as lau

    if fvc is not None or fpc is not None:  # TODO: this is for catching calls
        raise UserWarning('deprecated use of `rhsd_vfrc`, use only `fv`, `fp`')

    if get_datastring is None:
        get_datastring = get_datastr_snu

    if paraviewoutput:
        prvoutdict = dict(V=V, Q=Q,
                          invinds=invinds, diribcs=diribcs, ppin=ppin,
                          vp=None, t=None,
                          tfilter=plttrange, writeoutput=True)
    else:
        prvoutdict = dict(writeoutput=False)  # save 'if statements' here

    if trange is None:
        trange = np.linspace(t0, tE, Nts+1)

    if treat_nonl_explct and lin_vel_point is not None:
        raise UserWarning('cant use `lin_vel_point` ' +
                          'and explicit treatment of the nonlinearity')

    if return_dictofpstrs:
        gpfvd = dict(V=V, M=M, A=A, J=J,
                     fv=fv, fp=fp,
                     dbcinds=dbcinds, dbcvals=dbcvals,
                     diribcs=diribcs, invinds=invinds)

    NV, NP = A.shape[0], J.shape[0]
    fv = np.zeros((NV, 1)) if fv is None else fv
    fp = np.zeros((NP, 1)) if fp is None else fp

    if fv_tmdp is None:
        def fv_tmdp(time=None, curvel=None, **kw):
            return np.zeros((NV, 1)), None

    if iniv is None:
        if start_ssstokes:
            # Stokes solution as starting value
            vp_stokes =\
                lau.solve_sadpnt_smw(amat=A, jmat=J, jmatT=JT,
                                     rhsv=fv,  # + fv_tmdp_cont,
                                     krylov=krylov, krpslvprms=krpslvprms,
                                     krplsprms=krplsprms, rhsp=fp)
            iniv = vp_stokes[:NV]
        else:
            raise ValueError('No initial value given')

    datastrdict = dict(time=None, meshp=N, nu=nu,
                       Nts=trange.size-1, data_prfx=data_prfx,
                       semiexpl=treat_nonl_explct)

    if return_as_list:
        clearprvdata = True  # we want the results at hand
    if clearprvdata:
        datastrdict['time'] = '*'
        cdatstr = get_datastring(**datastrdict)
        for fname in glob.glob(cdatstr + '__vel*'):
            os.remove(fname)
        for fname in glob.glob(cdatstr + '__p*'):
            os.remove(fname)

    def _atdct(cdict, t, thing):
        if dictkeysstr:
            cdict.update({'{0}'.format(t): thing})
        else:
            cdict.update({t: thing})

    def _gfdct(cdict, t):
        if dictkeysstr:
            return cdict['{0}'.format(t)]
        else:
            return cdict[t]

    if stokes_flow:
        vel_nwtn_stps = 1
        vel_pcrd_stps = 0
        print('Stokes Flow!')
    elif lin_vel_point is None:
        comp_nonl_semexp_inig = True
        if not treat_nonl_explct:
            print(('No linearization point given - explicit' +
                  ' treatment of the nonlinearity in the first Iteration'))

    else:
        cur_linvel_point = lin_vel_point
        comp_nonl_semexp_inig = False

    newtk, norm_nwtnupd = 0, 1

    # check for previously computed velocities
    if useolddata and lin_vel_point is None and not stokes_flow:
        try:
            datastrdict.update(dict(time=trange[-1]))
            cdatstr = get_datastring(**datastrdict)

            norm_nwtnupd = (dou.load_npa(cdatstr + '__norm_nwtnupd')).flatten()
            try:
                if norm_nwtnupd[0] is None:
                    norm_nwtnupd = 1.
            except IndexError:
                norm_nwtnupd = 1.

            dou.load_npa(cdatstr + '__vel')

            print('found vel files')
            print('norm of last Nwtn update: {0}'.format(norm_nwtnupd))
            print('... loaded from ' + cdatstr)

            if norm_nwtnupd < vel_nwtn_tol and not return_dictofvelstrs:
                return
            elif norm_nwtnupd < vel_nwtn_tol or treat_nonl_explct:
                # looks like converged / or semi-expl
                # -- check if all values are there
                # t0:
                datastrdict.update(dict(time=trange[0]))
                cdatstr = get_datastring(**datastrdict)
                dictofvelstrs = {}
                _atdct(dictofvelstrs, trange[0], cdatstr + '__vel')
                if return_dictofpstrs:
                    dictofpstrs = {}

                for t in trange:
                    datastrdict.update(dict(time=t))
                    cdatstr = get_datastring(**datastrdict)
                    # test if the vels are there
                    v_old = dou.load_npa(cdatstr + '__vel')
                    # update the dict
                    _atdct(dictofvelstrs, t, cdatstr + '__vel')
                    if return_dictofpstrs:
                        try:
                            p_old = dou.load_npa(cdatstr + '__p')
                            _atdct(dictofpstrs, t, cdatstr + '__p')
                        except:
                            p_old = get_pfromv(v=v_old, **gpfvd)
                            dou.save_npa(p_old, fstring=cdatstr + '__p')
                            _atdct(dictofpstrs, t, cdatstr + '__p')

                if return_dictofpstrs:
                    return dictofvelstrs, dictofpstrs
                else:
                    return dictofvelstrs

            # comp_nonl_semexp = False

        except IOError:
            norm_nwtnupd = 2
            print('no old velocity data found')

    def _append_bcs_ornot(vvec):
        if output_includes_bcs:  # make the switch here for better readibility
            vwbcs = dts.append_bcs_vec(vvec, vdim=V.dim(),
                                       invinds=invinds, diribcs=diribcs)
            return vwbcs
        else:
            return vvec

    def _get_mats_rhs_ts(mmat=None, dt=None, var_c=None,
                         coeffmat_c=None,
                         coeffmat_n=None,
                         fv_c=None, fv_n=None,
                         umat_c=None, vmat_c=None,
                         umat_n=None, vmat_n=None,
                         impeul=False):
        """ to be tweaked for different int schemes

        """
        solvmat = M + 0.5*dt*coeffmat_n
        rhs = M*var_c + 0.5*dt*(fv_n + fv_c - coeffmat_c*var_c)
        if umat_n is not None:
            matvec = lau.mm_dnssps
            umat = 0.5*dt*umat_n
            vmat = vmat_n
            # TODO: do we really need a PLUS here??'
            rhs = rhs + 0.5*dt*matvec(umat_c, matvec(vmat_c, var_c))
        else:
            umat, vmat = umat_n, vmat_n

        return solvmat, rhs, umat, vmat

    v_old = iniv  # start vector for time integration in every Newtonit
    datastrdict['time'] = trange[0]
    cdatstr = get_datastring(**datastrdict)

    dou.save_npa(_append_bcs_ornot(v_old), fstring=cdatstr + '__vel')
    dictofvelstrs = {}
    _atdct(dictofvelstrs, trange[0], cdatstr + '__vel')
    if return_dictofpstrs:
        p_old = get_pfromv(v=v_old, **gpfvd)
        dou.save_npa(p_old, fstring=cdatstr + '__p')
        dictofpstrs = {}
        _atdct(dictofpstrs, trange[0], cdatstr+'__p')
    else:
        p_old = None

    if return_as_list:
        vellist = []
        vellist.append(_append_bcs_ornot(v_old))

    lensect = np.int(np.floor(trange.size/nsects))
    loctrngs = []
    for k in np.arange(nsects-1):
        loctrngs.append(trange[k*lensect: (k+1)*lensect+1])
    loctrngs.append(trange[(nsects-1)*lensect:])
    if addfullsweep:
        loctrngs.append(trange)
        realiniv = np.copy(iniv)
    if nsects == 1:
        loc_nwtn_tol = vel_nwtn_tol
        addfullsweep = False
        loctrngs = [trange]
    if loc_pcrd_stps:
        vel_loc_pcrd_steps = vel_pcrd_stps

    for loctrng in loctrngs:
        dtvec = np.array(loctrng)[1:] - np.array(loctrng)[1:]
        dotdtvec = dtvec[1:] - dtvec[:-1]
        uniformgrid = np.allclose(np.linalg.norm(dotdtvec), 0)
        coeffmatlu = None

        while (newtk < vel_nwtn_stps and norm_nwtnupd > loc_nwtn_tol):
            print('solve the NSE on the interval [{0}, {1}]'.
                  format(loctrng[0], loctrng[-1]))
            if stokes_flow:
                pcrd_anyone = False
                newtk = vel_nwtn_stps
            elif comp_nonl_semexp_inig and not treat_nonl_explct:
                pcrd_anyone = False
                loc_treat_nonl_explct = True
                print('explicit treatment of nonl. for initial guess!')
            elif treat_nonl_explct:
                pcrd_anyone = False
                loc_treat_nonl_explct = True
                newtk = vel_nwtn_stps
                print('No Newton iterations - explicit treatment ' +
                      'of the nonlinearity')

            if not comp_nonl_semexp_inig and not treat_nonl_explct:
                if vel_pcrd_stps > 0:
                    vel_pcrd_stps -= 1
                    pcrd_anyone = True
                    print('Picard iterations for initial value -- {0} left'.
                          format(vel_pcrd_stps))
                else:
                    pcrd_anyone = False
                    newtk += 1
                    print('Computing Newton Iteration {0}'.format(newtk))

            v_old = iniv  # start vector for time integration in every Newtonit
            try:
                if krpslvprms['krylovini'] == 'old':
                    vp_old = np.vstack([v_old, np.zeros((NP, 1))])
                elif krpslvprms['krylovini'] == 'upd':
                    vp_old = np.vstack([v_old, np.zeros((NP, 1))])
                    vp_new = vp_old
                    cts_old = loctrng[1] - loctrng[0]
            except (TypeError, KeyError):
                pass  # no inival for krylov solver required

            vfile = dolfin.File(vfileprfx+'__timestep.pvd')
            pfile = dolfin.File(pfileprfx+'__timestep.pvd')
            prvoutdict.update(dict(vp=None, vc=iniv, pc=p_old, t=loctrng[0],
                                   dbcinds=dbcinds, dbcvals=dbcvals,
                                   pfile=pfile, vfile=vfile))
            dou.output_paraview(**prvoutdict)

            # ## current values_c for application of trap rule
            if stokes_flow:
                convc_mat_c = sps.csr_matrix((NV, NV))
                rhs_con_c, rhsv_conbc_c = np.zeros((NV, 1)), np.zeros((NV, 1))
            else:
                if loc_treat_nonl_explct is not None:
                    prev_v = v_old
                else:
                    try:
                        prev_v = dou.load_npa(_gfdct(cur_linvel_point,
                                              loctrng[0]))
                    except KeyError:
                        try:
                            prev_v = dou.load_npa(_gfdct(cur_linvel_point,
                                                  None))
                        except TypeError:
                            prev_v = cur_linvel_point[None]

                convc_mat_c, rhs_con_c, rhsv_conbc_c = \
                    get_v_conv_conts(prev_v=iniv, invinds=invinds,
                                     semi_explicit=loc_treat_nonl_explct,
                                     dbcinds=dbcinds, dbcvals=dbcvals,
                                     V=V, diribcs=diribcs, Picard=pcrd_anyone)

            cury = None if cv_mat is None else cv_mat.dot(v_old)
            (fv_tmdp_cont,
             fv_tmdp_memory) = fv_tmdp(time=0,
                                       curvel=v_old,
                                       cury=cury,
                                       memory=fv_tmdp_memory,
                                       **fv_tmdp_params)

            _rhsconvc = 0. if pcrd_anyone else rhs_con_c
            fvn_c = fv + rhsv_conbc_c + _rhsconvc + fv_tmdp_cont

            if closed_loop:
                if static_feedback:
                    mtxtb_c = dou.load_npa(feedbackthroughdict[None]['mtxtb'])
                    w_c = dou.load_npa(feedbackthroughdict[None]['w'])
                else:
                    mtxtb_c = dou.load_npa(feedbackthroughdict[0]['mtxtb'])
                    w_c = dou.load_npa(feedbackthroughdict[0]['w'])

                fvn_c = fvn_c + tb_mat * (tb_mat.T * w_c)
                vmat_c = mtxtb_c.T
                try:
                    umat_c = np.array(tb_mat.todense())
                except AttributeError:
                    umat_c = tb_mat

            else:
                vmat_c = None
                umat_c = None

            norm_nwtnupd = 0
            if verbose:
                # define at which points of time the progress is reported
                nouts = 10  # number of output points
                locnts = loctrng.size  # TODO: trange may be a list...
                filtert = np.arange(0, locnts,
                                    np.int(np.floor(locnts/nouts)))
                loctinstances = loctrng[filtert]
                loctinstances[0] = loctrng[1]
                loctinstances = loctinstances.tolist()
                print('doing the time integration...')
            for tk, t in enumerate(loctrng[1:]):
                cts = t - loctrng[tk]
                datastrdict.update(dict(time=t))
                cdatstr = get_datastring(**datastrdict)
                try:
                    if verbose and t == loctinstances[0]:
                        curtinst = loctinstances.pop(0)
                        # print("runtime: {0} -- t: {1} -- tE: {2:f}".
                        #       format(time.clock(), curtinst, loctrng[-1]))
                        print("runtime: {0:.1f} - t/tE: {1:.2f} - t: {2:.4f}".
                              format(time.clock(), curtinst/loctrng[-1],
                                     curtinst))
                except IndexError:
                    pass  # if something goes wrong, don't stop

                # coeffs and rhs at next time instance
                if stokes_flow:
                    convc_mat_n = sps.csr_matrix((NV, NV))
                    rhs_con_n = np.zeros((NV, 1))
                    rhsv_conbc_n = np.zeros((NV, 1))
                else:
                    if loc_treat_nonl_explct:
                        prev_v = v_old
                    else:
                        try:
                            prev_v = dou.load_npa(_gfdct(cur_linvel_point, t))
                        except KeyError:
                            try:
                                prev_v = dou.load_npa(_gfdct(cur_linvel_point,
                                                             None))
                            except TypeError:
                                prev_v = cur_linvel_point[None]
                    convc_mat_n, rhs_con_n, rhsv_conbc_n = \
                        get_v_conv_conts(prev_v=prev_v, invinds=invinds, V=V,
                                         semi_explicit=loc_treat_nonl_explct,
                                         dbcinds=dbcinds, dbcvals=dbcvals,
                                         diribcs=diribcs, Picard=pcrd_anyone)

                cury = None if cv_mat is None else cv_mat.dot(v_old)
                (fv_tmdp_cont,
                 fv_tmdp_memory) = fv_tmdp(time=t,
                                           curvel=v_old,
                                           cury=cury,
                                           memory=fv_tmdp_memory,
                                           **fv_tmdp_params)

                _rhsconvn = 0. if pcrd_anyone else rhs_con_n
                fvn_n = fv + rhsv_conbc_n + _rhsconvn + fv_tmdp_cont
                if loc_treat_nonl_explct and not closed_loop:
                    fvn_c = fv + rhsv_conbc_n + _rhsconvn + fv_tmdp_cont

                if closed_loop:
                    if static_feedback:
                        mtxtb_n = dou.\
                            load_npa(feedbackthroughdict[None]['mtxtb'])
                        w_n = dou.load_npa(feedbackthroughdict[None]['w'])
                        # fb = np.dot(tb_mat*mtxtb_n.T, v_old)
                        # print '\nnorm of feedback: ', np.linalg.norm(fb)
                        # print '\nnorm of v_old: ', np.linalg.norm(v_old)
                    else:
                        mtxtb_n = dou.load_npa(feedbackthroughdict[t]['mtxtb'])
                        w_n = dou.load_npa(feedbackthroughdict[t]['w'])

                    fvn_n = fvn_n + tb_mat * (tb_mat.T * w_n)
                    vmat_n = mtxtb_n.T
                    try:
                        umat_n = np.array(tb_mat.todense())
                    except AttributeError:
                        umat_n = tb_mat

                else:
                    vmat_n = None
                    umat_n = None

                (solvmat, rhsv, umat,
                 vmat) = _get_mats_rhs_ts(mmat=M, dt=cts, var_c=v_old,
                                          coeffmat_c=A + convc_mat_c,
                                          coeffmat_n=A + convc_mat_n,
                                          fv_c=fvn_c, fv_n=fvn_n,
                                          umat_c=umat_c, vmat_c=vmat_c,
                                          umat_n=umat_n, vmat_n=vmat_n)

                try:
                    if krpslvprms['krylovini'] == 'old':
                        krpslvprms['x0'] = vp_old
                    elif krpslvprms['krylovini'] == 'upd':
                        vp_oldold = vp_old
                        vp_old = vp_new
                        krpslvprms['x0'] = vp_old + \
                            cts*(vp_old - vp_oldold)/cts_old
                        cts_old = cts
                except (TypeError, KeyError):
                    pass  # no inival for krylov solver required

                if loc_treat_nonl_explct and uniformgrid and not krylov:
                    if coeffmatlu is None:
                        print('gonna compute an LU of the coefficient ' +
                              'matrix \n and reuse it in the time stepping')
                    vp_new, coeffmatlu = \
                        lau.solve_sadpnt_smw(amat=solvmat, jmat=J, jmatT=JT,
                                             rhsv=rhsv, rhsp=fp,
                                             sadlu=coeffmatlu,
                                             return_alu=True,
                                             umat=umat, vmat=vmat)

                else:
                    vp_new = lau.solve_sadpnt_smw(amat=solvmat,
                                                  jmat=J, jmatT=JT,
                                                  rhsv=rhsv,
                                                  rhsp=fp,
                                                  krylov=krylov,
                                                  krpslvprms=krpslvprms,
                                                  krplsprms=krplsprms,
                                                  umat=umat, vmat=vmat)

                v_old = vp_new[:NV, ]
                (umat_c, vmat_c, fvn_c,
                    convc_mat_c) = umat_n, vmat_n, fvn_n, convc_mat_n

                dou.save_npa(_append_bcs_ornot(v_old),
                             fstring=cdatstr + '__vel')
                _atdct(dictofvelstrs, t, cdatstr + '__vel')
                p_new = -1/cts*vp_new[NV:, ]
                # p was flipped and scaled for symmetry
                if return_dictofpstrs:
                    dou.save_npa(p_new, fstring=cdatstr + '__p')
                    _atdct(dictofpstrs, t, cdatstr + '__p')

                if return_as_list:
                    vellist.append(_append_bcs_ornot(v_old))

                # integrate the Newton error
                if stokes_flow or treat_nonl_explct:
                    norm_nwtnupd = None
                elif comp_nonl_semexp_inig:
                    norm_nwtnupd = 1.

                else:
                    if len(prev_v) > len(invinds):
                        prev_v = prev_v[invinds, :]
                    addtonwtnupd = cts * m_innerproduct(M, v_old - prev_v)
                    norm_nwtnupd += np.float(addtonwtnupd.flatten()[0])

                if newtk == vel_nwtn_stps or norm_nwtnupd < loc_nwtn_tol:
                    # paraviewoutput in the (probably) last newton sweep
                    prvoutdict.update(dict(vc=v_old, pc=p_new, t=t))
                    dou.output_paraview(**prvoutdict)

            dou.save_npa(norm_nwtnupd, cdatstr + '__norm_nwtnupd')
            print('\nnorm of current Newton update: {}'.format(norm_nwtnupd))
            # print('\nsaved `norm_nwtnupd(={0})'.format(norm_nwtnupd) +
            #       ' to ' + cdatstr)
            loc_treat_nonl_explct = False
            comp_nonl_semexp_inig = False

            cur_linvel_point = dictofvelstrs

        iniv = v_old
        if not treat_nonl_explct and lin_vel_point is None:
            comp_nonl_semexp_inig = True
        if addfullsweep and loctrng is loctrngs[-2]:
            comp_nonl_semexp_inig = False
            iniv = realiniv
            loc_nwtn_tol = vel_nwtn_tol
        elif loc_pcrd_stps:
            vel_pcrd_stps = vel_loc_pcrd_steps

        norm_nwtnupd = 1.
        newtk = 0

    if return_dictofvelstrs:
        if return_dictofpstrs:
            return dictofvelstrs, dictofpstrs
        else:
            return dictofvelstrs
    elif return_as_list:
        return vellist
    else:
        return
def test_qbdae_ass(problemname='cylinderwake', N=1, Re=4e2, nu=3e-2,
                   t0=0.0, tE=1.0, Nts=100, use_saved_mats=None):

    trange = np.linspace(t0, tE, Nts+1)
    DT = (tE-t0)/Nts
    rdir = 'results/'
    femp, stokesmatsc, rhsd_vfrc, rhsd_stbc, \
        data_prfx, ddir, proutdir = \
        dns.problem_setups.get_sysmats(problem=problemname, N=N, Re=Re)
    invinds = femp['invinds']

    if use_saved_mats is None:

        A, J, M = stokesmatsc['A'], stokesmatsc['J'], stokesmatsc['M']
        fvc, fpc = rhsd_vfrc['fvc'], rhsd_vfrc['fpr']
        fv_stbc, fp_stbc = rhsd_stbc['fv'], rhsd_stbc['fp']

        hstr = ddir + problemname + '_N{0}_hmat'.format(N)
        try:
            hmat = dou.load_spa(hstr)
            print 'loaded `hmat`'
        except IOError:
            print 'assembling hmat ...'
            hmat = dnsts.ass_convmat_asmatquad(W=femp['V'], invindsw=invinds)
            dou.save_spa(hmat, hstr)

        invinds = femp['invinds']
        NV, NP = invinds.shape[0], J.shape[0]
        zerv = np.zeros((NV, 1))

        bc_conv, bc_rhs_conv, rhsbc_convbc = \
            snu.get_v_conv_conts(prev_v=zerv, V=femp['V'], invinds=invinds,
                                 diribcs=femp['diribcs'], Picard=False)
        fp = fp_stbc + fpc
        fv = fv_stbc + fvc - bc_rhs_conv

        # Stokes solution as initial value
        vp_stokes = lau.solve_sadpnt_smw(amat=A, jmat=J,
                                         rhsv=fv_stbc + fvc,
                                         rhsp=fp_stbc + fpc)
        old_v = vp_stokes[:NV]

        sysmat = sps.vstack([sps.hstack([M+DT*(A+bc_conv), J.T]),
                             sps.hstack([J, sps.csc_matrix((NP, NP))])])
        # the observation
        if problemname == 'cylinderwake':
            podcoo = dict(xmin=0.6,
                          xmax=0.64,
                          ymin=0.18,
                          ymax=0.22)
        elif problemname == 'drivencavity':
            podcoo = dict(xmin=0.45,
                          xmax=0.55,
                          ymin=0.7,
                          ymax=0.8)
        else:
            podcoo = femp['odcoo']

        pcmat = cou.get_pavrg_onsubd(odcoo=podcoo, Q=femp['Q'])

    if use_saved_mats is not None:
        # if saved as in ../get_exp_mats
        import scipy.io
        mats = scipy.io.loadmat(use_saved_mats)
        A = - mats['A']
        M = mats['M']
        J = mats['J']
        hmat = -mats['H']
        fv = mats['fv']
        fp = mats['fp']
        NV, NP = fv.shape[0], fp.shape[0]
        old_v = mats['ss_stokes']
        sysmat = sps.vstack([sps.hstack([M+DT*A, J.T]),
                             sps.hstack([J, sps.csc_matrix((NP, NP))])])
        pcmat = mats['Cp']

    print 'computing LU once...'
    sysmati = spsla.factorized(sysmat)

    vfile = dolfin.File(rdir + problemname + 'qdae__vel.pvd')
    pfile = dolfin.File(rdir + problemname + 'qdae__p.pvd')

    prvoutdict = dict(V=femp['V'], Q=femp['Q'], vfile=vfile, pfile=pfile,
                      invinds=invinds, diribcs=femp['diribcs'],
                      vp=None, t=None, writeoutput=True)

    print 'doing the time loop...'
    poutlist = []
    for t in trange:
        # conv_mat, rhs_conv, rhsbc_conv = \
        #     snu.get_v_conv_conts(prev_v=old_v, V=femp['V'], invinds=invinds,
        #                          diribcs=femp['diribcs'], Picard=False)
        # crhsv = M*old_v + DT*(fv_stbc + fvc + rhs_conv + rhsbc_conv
        #                       - conv_mat*old_v)
        # raise Warning('TODO: debug')
        crhsv = M*old_v + DT*(fv - hmat*np.kron(old_v, old_v))
        crhs = np.vstack([crhsv, fp])
        vp_new = np.atleast_2d(sysmati(crhs.flatten())).T
        # vp_new = lau.solve_sadpnt_smw(amat=M+DT*(A+0*conv_mat), jmat=J,
        #                               rhsv=crhsv,
        #                               rhsp=fp_stbc + fpc)

        vp_new[NV:] = pcmat.T  # *vp_new[NV:]
        prvoutdict.update(dict(vp=vp_new, t=t))
        dou.output_paraview(**prvoutdict)

        old_v = vp_new[:NV]
        p = vp_new[NV:]
        poutlist.append(np.dot(pcmat, p)[0][0])

        print t, np.linalg.norm(old_v)

    dou.plot_prs_outp(outsig=poutlist, tmesh=trange)
Example #21
0
def solve_flow_daeric(mmat=None, amat=None, jmat=None, bmat=None,
                      cmat=None, rhsv=None, rhsp=None,
                      mcmat=None, v_is_my=False,
                      rmat=None, vmat=None,
                      gamma=1.0,
                      tmesh=None, ystarvec=None,
                      nwtn_adi_dict=None,
                      curnwtnsdict=None,
                      comprz_thresh=None, comprz_maxc=None, save_full_z=False,
                      get_tdpart=None, gttdprtargs=None,
                      get_datastr=None, gtdtstrargs=None,
                      check_c_consist=True):

    """
    Routine for the solution of the DAE Riccati

    .. math::

        \\dot{MXM^T} + F^TXM + M^TXM + M^TXGXM + L(Y) = W \\\\
                JXM = 0 \\quad \\text{and} \\quad M^TXJ = 0 \\\\
                M^TX(T)M = W

    where :math:`F=A+N(t)`,
    where :math:`W:=C^T V C`, :math:`G:=B R^{-1} B^T`,
    and where :math:`L(Y)` is the Lagrange multiplier term.

    Simultaneously we solve for the feedforward term :math:`w`:

    .. math::

        \\dot{M^Tw} - [M^TXG+F^T]w - J^Tv = C^T V y^* + M^T[Xf + Yg] \\\\
                Jw = 0 \\\\
                M^Tw(T) = C^T V y^*(T)

    Note that :math:`V=M_y` if the norm of :math:`Y` is used
    in the cost function.


    Parameters
    ----------
    cmat : (NY, NV) array
        the (regularized aka projected) output matrix
    mcmat : (NY, NV) array
        output matrix times the mass matrix in the output space
    gamma : float, optional
        weighting parameter for penalization of the terminal value,
        TODO: rather provide the right weighting matrix V,
        defaults to `1.0`
    v_is_my : boolean
        whether the weighting matrix is the same as the mass matrix, \
                defaults to `False`
    get_tdpart : callable f(t)
        returns the `mattd, rhstd` -- time dependent coefficients matrices
        and right hand side at time `t`
    gtdtstrargs : dictionary
        **kwargs to the current data string
    gttdprtargs : dictionary
        `**kwargs` to get_tdpart

    Returns
    -------
    feedbackthroughdict : dictionary
        with time instances as keys and
        | `w` -- the current feedthrough value
        | `mtxtb` -- the current feedback gain part `(R.-1/2 * B.T * X * M).T`
        as values
    """

    if check_c_consist:
        if v_is_my and mcmat is not None:
            mic = lau.apply_massinv(mmat.T, mcmat.T)
            if np.linalg.norm(jmat*mic) > 1e-12:
                raise Warning('mcmat.T needs to be in the kernel of J*M.-1')
        elif cmat is not None:
            mic = lau.apply_massinv(mmat.T, cmat.T)
            if np.linalg.norm(jmat*mic) > 1e-12:
                raise Warning('cmat.T needs to be in the kernel of J*M.-1')

    MT, AT, NV = mmat.T, amat.T, amat.shape[0]

    gtdtstrargs.update(time=tmesh[-1])
    cdatstr = get_datastr(**gtdtstrargs)

    # set/compute the terminal values aka starting point
    if v_is_my and mcmat is not None:
        tct_mat = lau.apply_invsqrt_fromright(vmat, mcmat.T, output='dense')
    else:
        tct_mat = lau.apply_sqrt_fromright(vmat, cmat.T, output='dense')

    # TODO: good handling of bmat and umasmat
    tb_mat = lau.apply_invsqrt_fromright(rmat, bmat, output='sparse')
    # bmat_rpmo = bmat * np.linalg.inv(np.array(rmat.todense()))

    Zc = np.sqrt(gamma)*lau.apply_massinv(mmat, tct_mat)
    mtxtb = -pru.get_mTzzTtb(mmat.T, Zc, tb_mat)
    # mtxbrm = pru.get_mTzzTtb(mmat.T, Zc, bmat_rpmo)

    dou.save_npa(Zc, fstring=cdatstr + '__Z')
    dou.save_npa(mtxtb, fstring=cdatstr + '__mtxtb')

    if ystarvec is not None:
        wc = lau.apply_massinv(MT, gamma*np.dot(mcmat.T, ystarvec(tmesh[-1])))
        dou.save_npa(wc, fstring=cdatstr + '__w')
    else:
        wc = None

    feedbackthroughdict = {tmesh[-1]: dict(w=cdatstr + '__w',
                                           mtxtb=cdatstr + '__mtxtb')}

    # save the end values
    if curnwtnsdict is not None:
        dou.save_npa(wc, fstring=curnwtnsdict[tmesh[-1]]['w'])
        dou.save_npa(mtxtb, fstring=curnwtnsdict[tmesh[-1]]['mtxtb'])

    # time integration
    for tk, t in reversed(list(enumerate(tmesh[:-1]))):
        cts = tmesh[tk+1] - t

        print 'Time is {0}, timestep is {1}'.\
            format(t, cts)

        # get the previous time time-dep matrices
        gtdtstrargs.update(time=t)
        cdatstr = get_datastr(**gtdtstrargs)
        nmattd, rhsvtd = get_tdpart(time=t, **gttdprtargs)

        # get the feedback from the current newton step
        if curnwtnsdict is not None:
            try:
                cnsw = dou.load_npa(curnwtnsdict[t]['w'])
                cnsmtxtb = dou.load_npa(curnwtnsdict[t]['mtxtb'])
            except IOError:
                cnsw, cnsmtxtb = None, None
        else:
            cnsw, cnsmtxtb = None, None

        try:
            Zc = dou.load_npa(cdatstr + '__Z')
        except IOError:
            # coeffmat for nwtn adi
            ft_mat = -(0.5*MT + cts*(AT + nmattd.T))
            # rhs for nwtn adi
            w_mat = np.hstack([MT*Zc, np.sqrt(cts)*tct_mat])
            # feedback from a previous Newton step
            mtxb = np.sqrt(cts)*cnsmtxtb if cnsmtxtb is not None else None
            Zp = pru.proj_alg_ric_newtonadi(mmat=MT,
                                            amat=ft_mat, transposed=True,
                                            mtxoldb=mtxb,
                                            jmat=jmat,
                                            bmat=np.sqrt(cts)*tb_mat,
                                            wmat=w_mat, z0=Zc,
                                            nwtn_adi_dict=nwtn_adi_dict
                                            )['zfac']

            if comprz_maxc is not None or comprz_thresh is not None:
                Zc = pru.compress_Zsvd(Zp, thresh=comprz_thresh,
                                       k=comprz_maxc)
            else:
                Zc = Zp

            if save_full_z:
                dou.save_npa(Zp, fstring=cdatstr + '__Z')
            else:
                dou.save_npa(Zc, fstring=cdatstr + '__Z')

        # and the affine correction
        at_mat = MT + cts*(AT + nmattd.T)

        # current rhs
        ftilde = rhsvtd + rhsv

        # apply the feedback and through
        if cnsw is not None:
            ftilde = rhsvtd + rhsv + cnsw
        cnsmtxtb = cnsmtxtb + mtxtb if cnsmtxtb is not None else mtxtb

        mtxft = pru.get_mTzzTtb(MT, Zc, ftilde)

        fl1 = np.dot(mcmat.T, ystarvec(t))

        rhswc = MT*wc + cts*(fl1 - mtxft)

        mtxtb = -pru.get_mTzzTtb(MT, Zc, tb_mat)
        # mtxtbrm = pru.get_mTzzTtb(MT, Zc, bmat_rpmo)

        wc = lau.solve_sadpnt_smw(amat=at_mat, jmat=jmat,
                                  umat=cts*cnsmtxtb, vmat=tb_mat.T,
                                  rhsv=rhswc)[:NV]
        # wc = lau.solve_sadpnt_smw(amat=at_mat, jmat=jmat,
        #                           umat=-cts*mtxbrm, vmat=bmat.T,
        #                           rhsv=rhswc)[:NV]

        # update the feedback in Newton
        if curnwtnsdict is not None:
            cnsw = cnsw + wc if cnsw is not None else wc
            cnsmtxtb = cnsmtxtb + mtxtb if cnsmtxtb is not None else mtxtb
            dou.save_npa(cnsw, fstring=curnwtnsdict[t]['w'])
            dou.save_npa(cnsmtxtb, fstring=curnwtnsdict[t]['mtxtb'])

        dou.save_npa(wc, fstring=cdatstr + '__w')
        dou.save_npa(mtxtb, fstring=cdatstr + '__mtxtb')
        # dou.save_npa(mtxbrm, fstring=cdatstr + '__mtxbrm')
        feedbackthroughdict.update({t: dict(w=cdatstr + '__w',
                                            # mtxbrm=cdatstr + '__mtxbrm')})
                                            mtxtb=cdatstr + '__mtxtb')})

    return feedbackthroughdict
Example #22
0
def solve_nse(
        A=None,
        M=None,
        J=None,
        JT=None,
        fv=None,
        fp=None,
        fvc=None,
        fpc=None,  # TODO: this is to catch deprecated calls
        fv_tmdp=None,
        fv_tmdp_params={},
        fv_tmdp_memory=None,
        iniv=None,
        lin_vel_point=None,
        stokes_flow=False,
        trange=None,
        t0=None,
        tE=None,
        Nts=None,
        V=None,
        Q=None,
        invinds=None,
        diribcs=None,
        output_includes_bcs=False,
        N=None,
        nu=None,
        ppin=-1,
        closed_loop=False,
        static_feedback=False,
        feedbackthroughdict=None,
        return_vp=False,
        tb_mat=None,
        c_mat=None,
        vel_nwtn_stps=20,
        vel_nwtn_tol=5e-15,
        nsects=1,
        loc_nwtn_tol=5e-15,
        loc_pcrd_stps=True,
        addfullsweep=False,
        vel_pcrd_stps=4,
        krylov=None,
        krpslvprms={},
        krplsprms={},
        clearprvdata=False,
        get_datastring=None,
        data_prfx='',
        paraviewoutput=False,
        vfileprfx='',
        pfileprfx='',
        return_dictofvelstrs=False,
        return_dictofpstrs=False,
        dictkeysstr=False,
        comp_nonl_semexp=False,
        return_as_list=False,
        verbose=True,
        start_ssstokes=False,
        **kw):
    """
    solution of the time-dependent nonlinear Navier-Stokes equation

    .. math::
        M\\dot v + Av + N(v)v + J^Tp = f \n
        Jv =g

    using a Newton scheme in function space, i.e. given :math:`v_k`,
    we solve for the update like

    .. math::
        M\\dot v + Av + N(v_k)v + N(v)v_k + J^Tp = N(v_k)v_k + f,

    and trapezoidal rule in time. To solve an *Oseen* system (linearization
    about a steady state) or a *Stokes* system, set the number of Newton
    steps to one and provide a linearization point and an initial value.


    Parameters
    ----------
    lin_vel_point : dictionary, optional
        contains the linearization point for the first Newton iteration

         * Steady State: {{`None`: 'path_to_nparray'}, {'None': nparray}}
         * Newton: {`t`: 'path_to_nparray'}

        defaults to `None`
    dictkeysstr : boolean, optional
        whether the `keys` of the result dictionaries are strings instead \
        of floats, defaults to `False`
    fv_tmdp : callable f(t, v, dict), optional
        time-dependent part of the right-hand side, set to zero if None
    fv_tmdp_params : dictionary, optional
        dictionary of parameters to be passed to `fv_tmdp`, defaults to `{}`
    fv_tmdp_memory : dictionary, optional
        memory of the function
    output_includes_bcs : boolean, optional
        whether append the boundary nodes to the computed and stored \
        velocities, defaults to `False`
    krylov : {None, 'gmres'}, optional
        whether or not to use an iterative solver, defaults to `None`
    krpslvprms : dictionary, optional
        to specify parameters of the linear solver for use in Krypy, e.g.,

          * initial guess
          * tolerance
          * number of iterations

        defaults to `None`
    krplsprms : dictionary, optional
        parameters to define the linear system like

          * preconditioner

    ppin : {int, None}, optional
        which dof of `p` is used to pin the pressure, defaults to `-1`
    stokes_flow : boolean, optional
        whether to consider the Stokes linearization, defaults to `False`
    start_ssstokes : boolean, optional
        for your convenience, compute and use the steady state stokes solution
        as initial value, defaults to `False`
    nsects: int, optional
        in how many segments the trange is split up. (The newton iteration
        will be confined to the segments and, probably, converge faster than
        the global iteration), defaults to `1`
    loc_nwtn_tol: float, optional
        tolerance for the newton iteration on the segments,
        defaults to `1e-15`
    loc_pcrd_stps: boolean, optional
        whether to init with `vel_pcrd_stps` Picard steps on every section,
        if `False`, Picard iterations are performed only on the first section,
        defaults to `True`
    addfullsweep: boolean, optional
        whether to compute the newton iteration on the full `trange`,
        useful to check and for the plots, defaults to `False`

    Returns
    -------
    dictofvelstrs : dictionary, on demand
        dictionary with time `t` as keys and path to velocity files as values

    dictofpstrs : dictionary, on demand
        dictionary with time `t` as keys and path to pressure files as values

    vellist : list, on demand
        list of the velocity solutions

    """
    import sadptprj_riclyap_adi.lin_alg_utils as lau

    if fvc is not None or fpc is not None:  # TODO: this is for catching calls
        raise UserWarning('deprecated use of `rhsd_vfrc`, use only `fv`, `fp`')

    if get_datastring is None:
        get_datastring = get_datastr_snu

    if paraviewoutput:
        prvoutdict = dict(V=V,
                          Q=Q,
                          invinds=invinds,
                          diribcs=diribcs,
                          vp=None,
                          t=None,
                          writeoutput=True,
                          ppin=ppin)
    else:
        prvoutdict = dict(writeoutput=False)  # save 'if statements' here

    if trange is None:
        trange = np.linspace(t0, tE, Nts + 1)

    if comp_nonl_semexp and lin_vel_point is not None:
        raise UserWarning('I am not sure what you want! ' +
                          'set either `lin_vel_point=None` ' +
                          'or `comp_nonl_semexp=False`! \n' +
                          'as it is, I will compute a linear case')

    if return_dictofpstrs:
        gpfvd = dict(V=V,
                     M=M,
                     A=A,
                     J=J,
                     fv=fv,
                     fp=fp,
                     diribcs=diribcs,
                     invinds=invinds)

    NV, NP = A.shape[0], J.shape[0]

    if fv_tmdp is None:

        def fv_tmdp(time=None, curvel=None, **kw):
            return np.zeros((NV, 1)), None

    if iniv is None:
        if start_ssstokes:
            # Stokes solution as starting value
            (fv_tmdp_cont, fv_tmdp_memory) = fv_tmdp(time=0, **fv_tmdp_params)
            vp_stokes =\
                lau.solve_sadpnt_smw(amat=A, jmat=J, jmatT=JT,
                                     rhsv=fv + fv_tmdp_cont,
                                     krylov=krylov, krpslvprms=krpslvprms,
                                     krplsprms=krplsprms, rhsp=fp)
            iniv = vp_stokes[:NV]
        else:
            raise ValueError('No initial value given')

    datastrdict = dict(time=None,
                       meshp=N,
                       nu=nu,
                       Nts=trange.size - 1,
                       data_prfx=data_prfx)

    if return_as_list:
        clearprvdata = True  # we want the results at hand
    if clearprvdata:
        datastrdict['time'] = '*'
        cdatstr = get_datastring(**datastrdict)
        for fname in glob.glob(cdatstr + '__vel*'):
            os.remove(fname)
        for fname in glob.glob(cdatstr + '__p*'):
            os.remove(fname)

    def _atdct(cdict, t, thing):
        if dictkeysstr:
            cdict.update({'{0}'.format(t): thing})
        else:
            cdict.update({t: thing})

    def _gfdct(cdict, t):
        if dictkeysstr:
            return cdict['{0}'.format(t)]
        else:
            return cdict[t]

    if stokes_flow:
        vel_nwtn_stps = 1
        vel_pcrd_stps = 0
        print('Stokes Flow!')
    elif lin_vel_point is None:
        comp_nonl_semexp_inig = True
        if not comp_nonl_semexp:
            print(('No linearization point given - explicit' +
                   ' treatment of the nonlinearity in the first Iteration'))
    else:
        cur_linvel_point = lin_vel_point
        comp_nonl_semexp_inig = False

    newtk, norm_nwtnupd = 0, 1

    # check for previously computed velocities
    if lin_vel_point is None and not stokes_flow:
        try:
            datastrdict.update(dict(time=trange[-1]))
            cdatstr = get_datastring(**datastrdict)

            norm_nwtnupd = (dou.load_npa(cdatstr + '__norm_nwtnupd')).flatten()
            try:
                if norm_nwtnupd[0] is None:
                    norm_nwtnupd = 1.
            except IndexError:
                norm_nwtnupd = 1.

            dou.load_npa(cdatstr + '__vel')

            print('found vel files')
            print('norm of last Nwtn update: {0}'.format(norm_nwtnupd))
            print('... loaded from ' + cdatstr)

            if norm_nwtnupd < vel_nwtn_tol and not return_dictofvelstrs:
                return
            elif norm_nwtnupd < vel_nwtn_tol:
                # looks like converged -- check if all values are there
                # t0:
                datastrdict.update(dict(time=trange[0]))
                cdatstr = get_datastring(**datastrdict)
                dictofvelstrs = {}
                _atdct(dictofvelstrs, trange[0], cdatstr + '__vel')
                if return_dictofpstrs:
                    dictofpstrs = {}

                #     try:
                #         p_old = dou.load_npa(cdatstr + '__p')
                #         dictofpstrs = {}
                #         _atdct(dictofpstrs, trange[0], cdatstr+'__p')
                #     except:
                #         p_old = get_pfromv(v=v_old, **gpfvd)
                #         dou.save_npa(p_old, fstring=cdatstr + '__p')
                #         _atdct(dictofpstrs, trange[0], cdatstr+'__p')

                for t in trange:
                    datastrdict.update(dict(time=t))
                    cdatstr = get_datastring(**datastrdict)
                    # test if the vels are there
                    v_old = dou.load_npa(cdatstr + '__vel')
                    # update the dict
                    _atdct(dictofvelstrs, t, cdatstr + '__vel')
                    try:
                        p_old = dou.load_npa(cdatstr + '__p')
                        _atdct(dictofpstrs, t, cdatstr + '__p')
                    except:
                        p_old = get_pfromv(v=v_old, **gpfvd)
                        dou.save_npa(p_old, fstring=cdatstr + '__p')
                        _atdct(dictofpstrs, t, cdatstr + '__p')

                if return_dictofpstrs:
                    return dictofvelstrs, dictofpstrs
                else:
                    return dictofvelstrs

            comp_nonl_semexp = False

        except IOError:
            norm_nwtnupd = 2
            print('no old velocity data found')

    def _append_bcs_ornot(vvec):
        if output_includes_bcs:  # make the switch here for better readibility
            vwbcs = dts.append_bcs_vec(vvec,
                                       vdim=V.dim(),
                                       invinds=invinds,
                                       diribcs=diribcs)
            return vwbcs
        else:
            return vvec

    def _get_mats_rhs_ts(mmat=None,
                         dt=None,
                         var_c=None,
                         coeffmat_c=None,
                         coeffmat_n=None,
                         fv_c=None,
                         fv_n=None,
                         umat_c=None,
                         vmat_c=None,
                         umat_n=None,
                         vmat_n=None,
                         impeul=False):
        """ to be tweaked for different int schemes

        """
        solvmat = M + 0.5 * dt * coeffmat_n
        rhs = M * var_c + 0.5 * dt * (fv_n + fv_c - coeffmat_c * var_c)
        if umat_n is not None:
            matvec = lau.mm_dnssps
            umat = 0.5 * dt * umat_n
            vmat = vmat_n
            # TODO: do we really need a PLUS here??'
            rhs = rhs + 0.5 * dt * matvec(umat_c, matvec(vmat_c, var_c))
        else:
            umat, vmat = umat_n, vmat_n

        return solvmat, rhs, umat, vmat

    v_old = iniv  # start vector for time integration in every Newtonit
    datastrdict['time'] = trange[0]
    cdatstr = get_datastring(**datastrdict)

    dou.save_npa(_append_bcs_ornot(v_old), fstring=cdatstr + '__vel')
    dictofvelstrs = {}
    _atdct(dictofvelstrs, trange[0], cdatstr + '__vel')
    if return_dictofpstrs:
        p_old = get_pfromv(v=v_old, **gpfvd)
        dou.save_npa(p_old, fstring=cdatstr + '__p')
        dictofpstrs = {}
        _atdct(dictofpstrs, trange[0], cdatstr + '__p')
    else:
        p_old = None

    if return_as_list:
        vellist = []
        vellist.append(_append_bcs_ornot(v_old))

    lensect = np.int(np.floor(trange.size / nsects))
    loctrngs = []
    for k in np.arange(nsects - 1):
        loctrngs.append(trange[k * lensect:(k + 1) * lensect + 1])
    loctrngs.append(trange[(nsects - 1) * lensect:])
    if addfullsweep:
        loctrngs.append(trange)
        realiniv = np.copy(iniv)
    if nsects == 1:
        loc_nwtn_tol = vel_nwtn_tol
        addfullsweep = False
        loctrngs = [trange]
    if loc_pcrd_stps:
        vel_loc_pcrd_steps = vel_pcrd_stps

    for loctrng in loctrngs:
        while (newtk < vel_nwtn_stps and norm_nwtnupd > loc_nwtn_tol):
            print('solve the NSE on the interval [{0}, {1}]'.format(
                loctrng[0], loctrng[-1]))
            if stokes_flow:
                newtk = vel_nwtn_stps
            elif comp_nonl_semexp_inig and not comp_nonl_semexp:
                pcrd_anyone = False
                print('explicit treatment of nonl. for initial guess')
            elif vel_pcrd_stps > 0 and not comp_nonl_semexp:
                vel_pcrd_stps -= 1
                pcrd_anyone = True
                print('Picard iterations for initial value -- {0} left'.format(
                    vel_pcrd_stps))
            elif comp_nonl_semexp:
                pcrd_anyone = False
                newtk = vel_nwtn_stps
                print('No Newton iterations - explicit treatment' +
                      'of the nonlinerity')
            else:
                pcrd_anyone = False
                newtk += 1
                print('Computing Newton Iteration {0}'.format(newtk))

            v_old = iniv  # start vector for time integration in every Newtonit
            try:
                if krpslvprms['krylovini'] == 'old':
                    vp_old = np.vstack([v_old, np.zeros((NP, 1))])
                elif krpslvprms['krylovini'] == 'upd':
                    vp_old = np.vstack([v_old, np.zeros((NP, 1))])
                    vp_new = vp_old
                    cts_old = loctrng[1] - loctrng[0]
            except (TypeError, KeyError):
                pass  # no inival for krylov solver required

            vfile = dolfin.File(vfileprfx + '__timestep.pvd')
            pfile = dolfin.File(pfileprfx + '__timestep.pvd')
            prvoutdict.update(
                dict(vp=None,
                     vc=iniv,
                     pc=p_old,
                     t=loctrng[0],
                     pfile=pfile,
                     vfile=vfile))
            dou.output_paraview(**prvoutdict)

            # ## current values_c for application of trap rule
            if stokes_flow:
                convc_mat_c = sps.csr_matrix((NV, NV))
                rhs_con_c, rhsv_conbc_c = np.zeros((NV, 1)), np.zeros((NV, 1))
            else:
                if comp_nonl_semexp or comp_nonl_semexp_inig:
                    prev_v = v_old
                else:
                    try:
                        prev_v = dou.load_npa(
                            _gfdct(cur_linvel_point, loctrng[0]))
                    except KeyError:
                        try:
                            prev_v = dou.load_npa(
                                _gfdct(cur_linvel_point, None))
                        except TypeError:
                            prev_v = cur_linvel_point[None]

                convc_mat_c, rhs_con_c, rhsv_conbc_c = \
                    get_v_conv_conts(prev_v=iniv, invinds=invinds,
                                     V=V, diribcs=diribcs, Picard=pcrd_anyone)

            (fv_tmdp_cont, fv_tmdp_memory) = fv_tmdp(time=0,
                                                     curvel=v_old,
                                                     memory=fv_tmdp_memory,
                                                     **fv_tmdp_params)

            fvn_c = fv + rhsv_conbc_c + rhs_con_c + fv_tmdp_cont

            if closed_loop:
                if static_feedback:
                    mtxtb_c = dou.load_npa(feedbackthroughdict[None]['mtxtb'])
                    w_c = dou.load_npa(feedbackthroughdict[None]['w'])
                    # print '\nnorm of feedback: ', np.linalg.norm(mtxtb_c)
                else:
                    mtxtb_c = dou.load_npa(feedbackthroughdict[0]['mtxtb'])
                    w_c = dou.load_npa(feedbackthroughdict[0]['w'])

                fvn_c = fvn_c + tb_mat * (tb_mat.T * w_c)
                vmat_c = mtxtb_c.T
                try:
                    umat_c = np.array(tb_mat.todense())
                except AttributeError:
                    umat_c = tb_mat

            else:
                vmat_c = None
                umat_c = None

            norm_nwtnupd = 0
            if verbose:
                print('time to go')
            for tk, t in enumerate(loctrng[1:]):
                cts = t - loctrng[tk]
                datastrdict.update(dict(time=t))
                cdatstr = get_datastring(**datastrdict)
                if verbose:
                    sys.stdout.write("\rEnd: {1} -- now: {0:f}".format(
                        t, loctrng[-1]))
                    sys.stdout.flush()
                # prv_datastrdict = copy.deepcopy(datastrdict)

                # coeffs and rhs at next time instance
                if stokes_flow:
                    convc_mat_n = sps.csr_matrix((NV, NV))
                    rhs_con_n = np.zeros((NV, 1))
                    rhsv_conbc_n = np.zeros((NV, 1))
                else:
                    if comp_nonl_semexp or comp_nonl_semexp_inig:
                        prev_v = v_old
                    else:
                        try:
                            prev_v = dou.load_npa(_gfdct(cur_linvel_point, t))
                        except KeyError:
                            try:
                                prev_v = dou.load_npa(
                                    _gfdct(cur_linvel_point, None))
                            except TypeError:
                                prev_v = cur_linvel_point[None]
                    convc_mat_n, rhs_con_n, rhsv_conbc_n = \
                        get_v_conv_conts(prev_v=prev_v, invinds=invinds, V=V,
                                         diribcs=diribcs, Picard=pcrd_anyone)

                (fv_tmdp_cont, fv_tmdp_memory) = fv_tmdp(time=t,
                                                         curvel=v_old,
                                                         memory=fv_tmdp_memory,
                                                         **fv_tmdp_params)

                fvn_n = fv + rhsv_conbc_n + rhs_con_n + fv_tmdp_cont

                if closed_loop:
                    if static_feedback:
                        mtxtb_n = dou.\
                            load_npa(feedbackthroughdict[None]['mtxtb'])
                        w_n = dou.load_npa(feedbackthroughdict[None]['w'])
                        # fb = np.dot(tb_mat*mtxtb_n.T, v_old)
                        # print '\nnorm of feedback: ', np.linalg.norm(fb)
                        # print '\nnorm of v_old: ', np.linalg.norm(v_old)
                    else:
                        mtxtb_n = dou.load_npa(feedbackthroughdict[t]['mtxtb'])
                        w_n = dou.load_npa(feedbackthroughdict[t]['w'])

                    fvn_n = fvn_n + tb_mat * (tb_mat.T * w_n)
                    vmat_n = mtxtb_n.T
                    try:
                        umat_n = np.array(tb_mat.todense())
                    except AttributeError:
                        umat_n = tb_mat

                else:
                    vmat_n = None
                    umat_n = None

                (solvmat, rhsv, umat,
                 vmat) = _get_mats_rhs_ts(mmat=M,
                                          dt=cts,
                                          var_c=v_old,
                                          coeffmat_c=A + convc_mat_c,
                                          coeffmat_n=A + convc_mat_n,
                                          fv_c=fvn_c,
                                          fv_n=fvn_n,
                                          umat_c=umat_c,
                                          vmat_c=vmat_c,
                                          umat_n=umat_n,
                                          vmat_n=vmat_n)

                try:
                    if krpslvprms['krylovini'] == 'old':
                        krpslvprms['x0'] = vp_old
                    elif krpslvprms['krylovini'] == 'upd':
                        vp_oldold = vp_old
                        vp_old = vp_new
                        krpslvprms['x0'] = vp_old + \
                            cts*(vp_old - vp_oldold)/cts_old
                        cts_old = cts
                except (TypeError, KeyError):
                    pass  # no inival for krylov solver required

                vp_new = lau.solve_sadpnt_smw(amat=solvmat,
                                              jmat=J,
                                              jmatT=JT,
                                              rhsv=rhsv,
                                              rhsp=fp,
                                              krylov=krylov,
                                              krpslvprms=krpslvprms,
                                              krplsprms=krplsprms,
                                              umat=umat,
                                              vmat=vmat)

                v_old = vp_new[:NV, ]
                (umat_c, vmat_c, fvn_c,
                 convc_mat_c) = umat_n, vmat_n, fvn_n, convc_mat_n

                dou.save_npa(_append_bcs_ornot(v_old),
                             fstring=cdatstr + '__vel')
                _atdct(dictofvelstrs, t, cdatstr + '__vel')
                p_new = -1 / cts * vp_new[NV:, ]
                # p was flipped and scaled for symmetry
                if return_dictofpstrs:
                    dou.save_npa(p_new, fstring=cdatstr + '__p')
                    _atdct(dictofpstrs, t, cdatstr + '__p')

                if return_as_list:
                    vellist.append(_append_bcs_ornot(v_old))

                prvoutdict.update(dict(vc=v_old, pc=p_new, t=t))
                dou.output_paraview(**prvoutdict)

                # integrate the Newton error
                if stokes_flow or comp_nonl_semexp:
                    norm_nwtnupd = None
                elif comp_nonl_semexp_inig:
                    norm_nwtnupd = 1.

                else:
                    if len(prev_v) > len(invinds):
                        prev_v = prev_v[invinds, :]
                    addtonwtnupd = cts * m_innerproduct(M, v_old - prev_v)
                    norm_nwtnupd += np.float(addtonwtnupd.flatten()[0])

            dou.save_npa(norm_nwtnupd, cdatstr + '__norm_nwtnupd')
            print('\nnorm of current Newton update: {}'.format(norm_nwtnupd))
            # print('\nsaved `norm_nwtnupd(={0})'.format(norm_nwtnupd) +
            #       ' to ' + cdatstr)
            comp_nonl_semexp = False
            comp_nonl_semexp_inig = False

            cur_linvel_point = dictofvelstrs

        iniv = v_old
        if not comp_nonl_semexp:
            comp_nonl_semexp_inig = True
        if addfullsweep and loctrng is loctrngs[-2]:
            comp_nonl_semexp_inig = False
            iniv = realiniv
            loc_nwtn_tol = vel_nwtn_tol
        elif loc_pcrd_stps:
            vel_pcrd_stps = vel_loc_pcrd_steps

        norm_nwtnupd = 1.
        newtk = 0

    if return_dictofvelstrs:
        if return_dictofpstrs:
            return dictofvelstrs, dictofpstrs
        else:
            return dictofvelstrs
    elif return_as_list:
        return vellist
    else:
        return
Example #23
0
def solve_steadystate_nse(A=None,
                          J=None,
                          JT=None,
                          M=None,
                          fv=None,
                          fp=None,
                          V=None,
                          Q=None,
                          invinds=None,
                          diribcs=None,
                          return_vp=False,
                          ppin=-1,
                          N=None,
                          nu=None,
                          vel_pcrd_stps=10,
                          vel_pcrd_tol=1e-4,
                          vel_nwtn_stps=20,
                          vel_nwtn_tol=5e-15,
                          clearprvdata=False,
                          vel_start_nwtn=None,
                          get_datastring=None,
                          data_prfx='',
                          paraviewoutput=False,
                          save_intermediate_steps=False,
                          vfileprfx='',
                          pfileprfx='',
                          **kw):
    """
    Solution of the steady state nonlinear NSE Problem

    using Newton's scheme. If no starting value is provided, the iteration
    is started with the steady state Stokes solution.

    Parameters
    ----------
    A : (N,N) sparse matrix
        stiffness matrix aka discrete Laplacian, note the sign!
    M : (N,N) sparse matrix
        mass matrix
    J : (M,N) sparse matrix
        discrete divergence operator
    JT : (N,M) sparse matrix, optional
        discrete gradient operator, set to J.T if not provided
    fv, fp : (N,1), (M,1) ndarrays
        right hand sides restricted via removing the boundary nodes in the
        momentum and the pressure freedom in the continuity equation
    ppin : {int, None}, optional
        which dof of `p` is used to pin the pressure, defaults to `-1`
    return_vp : boolean, optional
        whether to return also the pressure, defaults to `False`
    vel_pcrd_stps : int, optional
        Number of Picard iterations when computing a starting value for the
        Newton scheme, cf. Elman, Silvester, Wathen: *FEM and fast iterative
        solvers*, 2005, defaults to `100`
    vel_pcrd_tol : real, optional
        tolerance for the size of the Picard update, defaults to `1e-4`
    vel_nwtn_stps : int, optional
        Number of Newton iterations, defaults to `20`
    vel_nwtn_tol : real, optional
        tolerance for the size of the Newton update, defaults to `5e-15`
    """

    import sadptprj_riclyap_adi.lin_alg_utils as lau

    if get_datastring is None:
        get_datastring = get_datastr_snu

    if JT is None:
        JT = J.T

    NV = J.shape[1]

    #
    # Compute or load the uncontrolled steady state Navier-Stokes solution
    #

    norm_nwtnupd_list = []
    vel_newtk, norm_nwtnupd = 0, 1
    # a dict to be passed to the get_datastring function
    datastrdict = dict(time=None,
                       meshp=N,
                       nu=nu,
                       Nts=None,
                       data_prfx=data_prfx)

    if clearprvdata:
        cdatstr = get_datastring(**datastrdict)
        for fname in glob.glob(cdatstr + '*__vel*'):
            os.remove(fname)

    try:
        cdatstr = get_datastring(**datastrdict)

        norm_nwtnupd = dou.load_npa(cdatstr + '__norm_nwtnupd')
        vel_k = dou.load_npa(cdatstr + '__vel')
        norm_nwtnupd_list.append(norm_nwtnupd)

        print('found vel files')
        print('norm of last Nwtn update: {0}'.format(norm_nwtnupd))
        print('... loaded from ' + cdatstr)
        if np.atleast_1d(norm_nwtnupd)[0] is None:
            norm_nwtnupd = None
            pass  # nothing useful found

        elif norm_nwtnupd < vel_nwtn_tol:
            if not return_vp:
                return vel_k, norm_nwtnupd_list
            else:
                pfv = get_pfromv(v=vel_k[:NV, :],
                                 V=V,
                                 M=M,
                                 A=A,
                                 J=J,
                                 fv=fv,
                                 invinds=invinds,
                                 diribcs=diribcs)
                return (np.vstack([vel_k, pfv]), norm_nwtnupd_list)

    except IOError:
        print('no old velocity data found')
        norm_nwtnupd = None

    if paraviewoutput:
        cdatstr = get_datastring(**datastrdict)
        vfile = dolfin.File(vfileprfx + '__steadystates.pvd')
        pfile = dolfin.File(pfileprfx + '__steadystates.pvd')
        prvoutdict = dict(V=V,
                          Q=Q,
                          vfile=vfile,
                          pfile=pfile,
                          invinds=invinds,
                          diribcs=diribcs,
                          ppin=ppin,
                          vp=None,
                          t=None,
                          writeoutput=True)
    else:
        prvoutdict = dict(writeoutput=False)  # save 'if statements' here

    NV = A.shape[0]
    if vel_start_nwtn is None:
        vp_stokes = lau.solve_sadpnt_smw(amat=A,
                                         jmat=J,
                                         jmatT=JT,
                                         rhsv=fv,
                                         rhsp=fp)
        vp_stokes[NV:] = -vp_stokes[NV:]
        # pressure was flipped for symmetry

        # save the data
        cdatstr = get_datastring(**datastrdict)

        dou.save_npa(vp_stokes[:NV, ], fstring=cdatstr + '__vel')

        prvoutdict.update(dict(vp=vp_stokes))
        dou.output_paraview(**prvoutdict)

        # Stokes solution as starting value
        vp_k = vp_stokes
        vel_k = vp_stokes[:NV, ]

    else:
        vel_k = vel_start_nwtn

    # Picard iterations for a good starting value for Newton
    for k in range(vel_pcrd_stps):
        (convc_mat, rhs_con, rhsv_conbc) = get_v_conv_conts(prev_v=vel_k,
                                                            invinds=invinds,
                                                            V=V,
                                                            diribcs=diribcs,
                                                            Picard=True)

        vp_k = lau.solve_sadpnt_smw(amat=A + convc_mat,
                                    jmat=J,
                                    jmatT=JT,
                                    rhsv=fv + rhs_con + rhsv_conbc,
                                    rhsp=fp)
        normpicupd = np.sqrt(m_innerproduct(M, vel_k - vp_k[:NV, :]))[0]

        print('Picard iteration: {0} -- norm of update: {1}'.format(
            k + 1, normpicupd))

        vel_k = vp_k[:NV, ]
        vp_k[NV:] = -vp_k[NV:]
        # pressure was flipped for symmetry

        if normpicupd < vel_pcrd_tol:
            break

    # Newton iteration
    while (vel_newtk < vel_nwtn_stps
           and (norm_nwtnupd is None or norm_nwtnupd > vel_nwtn_tol
                or norm_nwtnupd == np.array(None))):

        vel_newtk += 1

        cdatstr = get_datastring(**datastrdict)

        (convc_mat, rhs_con, rhsv_conbc) = get_v_conv_conts(vel_k,
                                                            invinds=invinds,
                                                            V=V,
                                                            diribcs=diribcs)

        vp_k = lau.solve_sadpnt_smw(amat=A + convc_mat,
                                    jmat=J,
                                    jmatT=JT,
                                    rhsv=fv + rhs_con + rhsv_conbc,
                                    rhsp=fp)

        norm_nwtnupd = np.sqrt(m_innerproduct(M, vel_k - vp_k[:NV, :]))[0]
        vel_k = vp_k[:NV, ]
        vp_k[NV:] = -vp_k[NV:]
        # pressure was flipped for symmetry
        print('Steady State NSE: Newton iteration: {0} -- norm of update: {1}'.
              format(vel_newtk, norm_nwtnupd))

        dou.save_npa(vel_k, fstring=cdatstr + '__vel')

        prvoutdict.update(dict(vp=vp_k))
        dou.output_paraview(**prvoutdict)

    dou.save_npa(norm_nwtnupd, cdatstr + '__norm_nwtnupd')

    dou.output_paraview(**prvoutdict)

    # savetomatlab = True
    # if savetomatlab:
    #     export_mats_to_matlab(E=None, A=None, matfname='matexport')
    if return_vp:
        return vp_k, norm_nwtnupd_list
    else:
        return vel_k, norm_nwtnupd_list
Example #24
0
def optcon_nse(problemname='drivencavity',
               N=10,
               Nts=10,
               nu=1e-2,
               clearprvveldata=False,
               ini_vel_stokes=False,
               stst_control=False,
               closed_loop=True,
               outernwtnstps=1,
               t0=None,
               tE=None,
               use_ric_ini_nu=None,
               alphau=1e-9,
               gamma=1e-3,
               spec_tip_dict=None,
               nwtn_adi_dict=None,
               linearized_nse=False,
               stokes_flow=False,
               ystar=None):

    tip = time_int_params(Nts, t0=t0, tE=tE)
    if spec_tip_dict is not None:
        tip.update(spec_tip_dict)
    if nwtn_adi_dict is not None:
        tip['nwtn_adi_dict'] = nwtn_adi_dict

    problemdict = dict(drivencavity=dnsps.drivcav_fems,
                       cylinderwake=dnsps.cyl_fems)

    problemfem = problemdict[problemname]
    femp = problemfem(N)

    # output
    ddir = 'data/'
    try:
        os.chdir(ddir)
    except OSError:
        raise Warning('need "' + ddir + '" subdir for storing the data')
    os.chdir('..')

    if linearized_nse and not outernwtnstps == 1:
        raise Warning('Linearized problem can have only one Newton step')

    if closed_loop:
        if stst_control:
            data_prfx = ddir + 'stst_' + problemname + '__'
        else:
            data_prfx = ddir + 'tdst_' + problemname + '__'

    else:
        data_prfx = ddir + problemname + '__'

    if stokes_flow:
        data_prfx = data_prfx + 'stokes__'

    # specify in what spatial direction Bu changes. The remaining is constant
    if problemname == 'drivencavity':
        uspacedep = 0
    elif problemname == 'cylinderwake':
        uspacedep = 1

    stokesmats = dts.get_stokessysmats(femp['V'], femp['Q'], nu)
    rhsd_vf = dts.setget_rhs(femp['V'], femp['Q'], femp['fv'], femp['fp'], t=0)

    # remove the freedom in the pressure
    stokesmats['J'] = stokesmats['J'][:-1, :][:, :]
    stokesmats['JT'] = stokesmats['JT'][:, :-1][:, :]
    rhsd_vf['fp'] = rhsd_vf['fp'][:-1, :]

    # reduce the matrices by resolving the BCs
    (stokesmatsc, rhsd_stbc, invinds, bcinds,
     bcvals) = dts.condense_sysmatsbybcs(stokesmats, femp['diribcs'])

    print 'Dimension of the div matrix: ', stokesmatsc['J'].shape
    # pressure freedom and dirichlet reduced rhs
    rhsd_vfrc = dict(fpr=rhsd_vf['fp'], fvc=rhsd_vf['fv'][invinds, ])

    # add the info on boundary and inner nodes
    bcdata = {'bcinds': bcinds, 'bcvals': bcvals, 'invinds': invinds}
    femp.update(bcdata)

    # casting some parameters
    NV = len(femp['invinds'])

    soldict = stokesmatsc  # containing A, J, JT
    soldict.update(femp)  # adding V, Q, invinds, diribcs
    # soldict.update(rhsd_vfrc)  # adding fvc, fpr
    soldict.update(fv=rhsd_stbc['fv'] + rhsd_vfrc['fvc'],
                   fp=rhsd_stbc['fp'] + rhsd_vfrc['fpr'],
                   N=N,
                   nu=nu,
                   trange=tip['tmesh'],
                   get_datastring=get_datastr,
                   data_prfx=data_prfx,
                   clearprvdata=clearprvveldata,
                   paraviewoutput=tip['ParaviewOutput'],
                   vfileprfx=tip['proutdir'] + 'vel_',
                   pfileprfx=tip['proutdir'] + 'p_')

    #
    # Prepare for control
    #

    contp = ContParams(femp['odcoo'], ystar=ystar, alphau=alphau, gamma=gamma)
    # casting some parameters
    NY, NU = contp.NY, contp.NU

    contsetupstr = problemname + '__NV{0}NU{1}NY{2}'.format(NV, NU, NY)

    # get the control and observation operators
    try:
        b_mat = dou.load_spa(ddir + contsetupstr + '__b_mat')
        u_masmat = dou.load_spa(ddir + contsetupstr + '__u_masmat')
        print 'loaded `b_mat`'
    except IOError:
        print 'computing `b_mat`...'
        b_mat, u_masmat = cou.get_inp_opa(cdcoo=femp['cdcoo'],
                                          V=femp['V'],
                                          NU=NU,
                                          xcomp=uspacedep)
        dou.save_spa(b_mat, ddir + contsetupstr + '__b_mat')
        dou.save_spa(u_masmat, ddir + contsetupstr + '__u_masmat')
    try:
        mc_mat = dou.load_spa(ddir + contsetupstr + '__mc_mat')
        y_masmat = dou.load_spa(ddir + contsetupstr + '__y_masmat')
        print 'loaded `c_mat`'
    except IOError:
        print 'computing `c_mat`...'
        mc_mat, y_masmat = cou.get_mout_opa(odcoo=femp['odcoo'],
                                            V=femp['V'],
                                            NY=NY)
        dou.save_spa(mc_mat, ddir + contsetupstr + '__mc_mat')
        dou.save_spa(y_masmat, ddir + contsetupstr + '__y_masmat')

    # restrict the operators to the inner nodes
    mc_mat = mc_mat[:, invinds][:, :]
    b_mat = b_mat[invinds, :][:, :]

    # for further use:
    c_mat = lau.apply_massinv(y_masmat, mc_mat, output='sparse')

    if contp.ystarx is None:
        c_mat = c_mat[NY:, :][:, :]  # TODO: Do this right
        mc_mat = mc_mat[NY:, :][:, :]  # TODO: Do this right
        y_masmat = y_masmat[:NY, :][:, :NY]  # TODO: Do this right

    mct_mat_reg = lau.app_prj_via_sadpnt(amat=stokesmatsc['M'],
                                         jmat=stokesmatsc['J'],
                                         rhsv=mc_mat.T,
                                         transposedprj=True)

    # set the weighing matrices
    contp.R = contp.alphau * u_masmat

    #
    # solve the differential-alg. Riccati eqn for the feedback gain X
    # via computing factors Z, such that X = -Z*Z.T
    #
    # at the same time we solve for the affine-linear correction w
    #

    # tilde B = BR^{-1/2}
    tb_mat = lau.apply_invsqrt_fromright(contp.R, b_mat, output='sparse')
    # tb_dense = np.array(tb_mat.todense())

    trct_mat = lau.apply_invsqrt_fromright(y_masmat,
                                           mct_mat_reg,
                                           output='dense')

    if closed_loop:
        cntpstr = 'NV{3}NY{0}NU{1}alphau{2}gamma{4}'.\
            format(contp.NU, contp.NY, contp.alphau, NV, contp.gamma)
    else:
        cntpstr = ''

    # we gonna use this quite often
    M, A = stokesmatsc['M'], stokesmatsc['A']
    datastrdict = dict(time=None, meshp=N, nu=nu, Nts=Nts, data_prfx=data_prfx)

    # compute the uncontrolled steady state (Navier-)Stokes solution
    # as initial value
    if ini_vel_stokes:
        # compute the uncontrolled steady state Stokes solution
        ini_vel, newtonnorms = snu.solve_steadystate_nse(vel_nwtn_stps=0,
                                                         vel_pcrd_stps=0,
                                                         **soldict)
        soldict.update(dict(iniv=ini_vel))
    else:
        ini_vel, newtonnorms = snu.solve_steadystate_nse(**soldict)
        soldict.update(dict(iniv=ini_vel))

    if closed_loop:
        if stst_control:
            if stokes_flow:
                convc_mat = sps.csr_matrix((NV, NV))
                rhs_con, rhsv_conbc = np.zeros((NV, 1)), np.zeros((NV, 1))
                lin_point = None
            else:
                lin_point, newtonnorms = snu.solve_steadystate_nse(**soldict)
                (convc_mat, rhs_con,
                 rhsv_conbc) = snu.get_v_conv_conts(prev_v=lin_point,
                                                    invinds=invinds,
                                                    V=femp['V'],
                                                    diribcs=femp['diribcs'])
            # infinite control horizon, steady target state
            cdatstr = get_datastr(time=None,
                                  meshp=N,
                                  nu=nu,
                                  Nts=None,
                                  data_prfx=data_prfx)

            try:
                Z = dou.load_npa(cdatstr + cntpstr + '__Z')
                print 'loaded ' + cdatstr + cntpstr + '__Z'
            except IOError:
                if use_ric_ini_nu is not None:
                    cdatstr = get_datastr(nwtn=None,
                                          time=None,
                                          meshp=N,
                                          nu=use_ric_ini_nu,
                                          Nts=None,
                                          data_prfx=data_prfx)
                    try:
                        zini = dou.load_npa(ddir + cdatstr + cntpstr + '__Z')
                        print 'Initialize Newton ADI by Z from ' + cdatstr
                    except IOError:
                        raise Warning('No data for initialization of '
                                      ' Newton ADI -- need ' + cdatstr + '__Z')
                    cdatstr = get_datastr(meshp=N, nu=nu, data_prfx=data_prfx)
                else:
                    zini = None

                parnadi = pru.proj_alg_ric_newtonadi
                Z = parnadi(mmat=M,
                            amat=-A - convc_mat,
                            jmat=stokesmatsc['J'],
                            bmat=tb_mat,
                            wmat=trct_mat,
                            z0=zini,
                            nwtn_adi_dict=tip['nwtn_adi_dict'])['zfac']

                dou.save_npa(Z, fstring=cdatstr + cntpstr + '__Z')
                print 'saved ' + cdatstr + cntpstr + '__Z'

                if tip['compress_z']:
                    Zc = pru.compress_Zsvd(Z,
                                           thresh=tip['comprz_thresh'],
                                           k=tip['comprz_maxc'])
                    Z = Zc

            fvnstst = rhs_con + rhsv_conbc + rhsd_stbc['fv'] + rhsd_vfrc['fvc']

            # X = -ZZ.T
            mtxtb_stst = -pru.get_mTzzTtb(M.T, Z, tb_mat)
            mtxfv_stst = -pru.get_mTzzTtb(M.T, Z, fvnstst)

            fl = mc_mat.T * contp.ystarvec(0)

            wft = lau.solve_sadpnt_smw(amat=A.T + convc_mat.T,
                                       jmat=stokesmatsc['J'],
                                       rhsv=fl + mtxfv_stst,
                                       umat=mtxtb_stst,
                                       vmat=tb_mat.T)[:NV]

            auxstrg = cdatstr + cntpstr
            dou.save_npa(wft, fstring=cdatstr + cntpstr + '__w')
            dou.save_npa(mtxtb_stst, fstring=cdatstr + cntpstr + '__mtxtb')
            feedbackthroughdict = {
                None: dict(w=auxstrg + '__w', mtxtb=auxstrg + '__mtxtb')
            }

            cns = 0
            soldict.update(data_prfx=data_prfx + '_cns{0}'.format(cns))
            if linearized_nse:
                soldict.update(vel_pcrd_stps=0,
                               vel_nwtn_stps=1,
                               lin_vel_point={None: lin_point})
            dictofvels = snu.\
                solve_nse(return_dictofvelstrs=True,
                          closed_loop=True,
                          static_feedback=True,
                          tb_mat=tb_mat,
                          stokes_flow=stokes_flow,
                          clearprvveldata=True,
                          feedbackthroughdict=feedbackthroughdict, **soldict)

        else:  # time dep closed loop

            cns_data_prfx = 'data/cnsvars'
            invd = init_nwtnstps_value_dict
            curnwtnsdict = invd(tmesh=tip['tmesh'], data_prfx=cns_data_prfx)
            # initialization: compute the forward solution
            if stokes_flow:
                dictofvels = None
            else:
                dictofvels = snu.solve_nse(return_dictofvelstrs=True,
                                           stokes_flow=stokes_flow,
                                           **soldict)

            # dbs.plot_vel_norms(tip['tmesh'], dictofvels)

            # function for the time depending parts
            # -- to be passed to the solver
            def get_tdpart(time=None,
                           dictofvalues=None,
                           feedback=False,
                           V=None,
                           invinds=None,
                           diribcs=None,
                           **kw):

                if stokes_flow:
                    convc_mat = sps.csr_matrix((NV, NV))
                    rhs_con, rhsv_conbc = np.zeros((NV, 1)), np.zeros((NV, 1))
                else:
                    curvel = dou.load_npa(dictofvalues[time])
                    convc_mat, rhs_con, rhsv_conbc = \
                        snu.get_v_conv_conts(prev_v=curvel, invinds=invinds,
                                             V=V, diribcs=diribcs)

                return convc_mat, rhsv_conbc + rhs_con

            gttdprtargs = dict(dictofvalues=dictofvels,
                               V=femp['V'],
                               diribcs=femp['diribcs'],
                               invinds=invinds)

            # old version rhs
            # ftilde = rhs_con + rhsv_conbc + rhsd_stbc['fv']
            for cns in range(outernwtnstps):

                datastrdict.update(data_prfx=data_prfx + cntpstr +
                                   '_cns{0}'.format(cns))
                soldict.update(data_prfx=data_prfx + cntpstr +
                               '_cns{0}'.format(cns))

                sfd = sdr.solve_flow_daeric
                feedbackthroughdict = \
                    sfd(mmat=M, amat=A, jmat=stokesmatsc['J'],
                        bmat=b_mat,
                        # cmat=ct_mat_reg.T,
                        mcmat=mct_mat_reg.T,
                        v_is_my=True, rmat=contp.alphau*u_masmat,
                        vmat=y_masmat, rhsv=rhsd_stbc['fv'],
                        gamma=contp.gamma,
                        rhsp=None,
                        tmesh=tip['tmesh'], ystarvec=contp.ystarvec,
                        nwtn_adi_dict=tip['nwtn_adi_dict'],
                        comprz_thresh=tip['comprz_thresh'],
                        comprz_maxc=tip['comprz_maxc'], save_full_z=False,
                        get_tdpart=get_tdpart, gttdprtargs=gttdprtargs,
                        curnwtnsdict=curnwtnsdict,
                        get_datastr=get_datastr, gtdtstrargs=datastrdict)

                # for t in tip['tmesh']:  # feedbackthroughdict.keys():
                #     curw = dou.load_npa(feedbackthroughdict[t]['mtxtb'])
                #     print cns, t, np.linalg.norm(curw)

                cdatstr = get_datastr(time='all',
                                      meshp=N,
                                      nu=nu,
                                      Nts=None,
                                      data_prfx=data_prfx)

                if linearized_nse:
                    dictofvels = snu.\
                        solve_nse(return_dictofvelstrs=True,
                                  closed_loop=True, tb_mat=tb_mat,
                                  lin_vel_point=dictofvels,
                                  feedbackthroughdict=feedbackthroughdict,
                                  vel_nwtn_stps=1,
                                  vel_pcrd_stps=0,
                                  **soldict)
                else:
                    dictofvels = snu.\
                        solve_nse(return_dictofvelstrs=True,
                                  closed_loop=True, tb_mat=tb_mat,
                                  stokes_flow=stokes_flow,
                                  feedbackthroughdict=feedbackthroughdict,
                                  vel_pcrd_stps=1,
                                  vel_nwtn_stps=2,
                                  **soldict)

                # for t in dictofvels.keys():
                #     curw = dou.load_npa(dictofvels[t])
                #     print cns, t, np.linalg.norm(curw)

                gttdprtargs.update(dictofvalues=dictofvels)
    else:
        # no control
        feedbackthroughdict = None
        tb_mat = None
        cdatstr = get_datastr(meshp=N,
                              nu=nu,
                              time='all',
                              Nts=Nts,
                              data_prfx=data_prfx)

        soldict.update(clearprvdata=True)
        dictofvels = snu.solve_nse(feedbackthroughdict=feedbackthroughdict,
                                   tb_mat=tb_mat,
                                   closed_loop=closed_loop,
                                   stokes_flow=stokes_flow,
                                   return_dictofvelstrs=True,
                                   static_feedback=stst_control,
                                   **soldict)

    (yscomplist, ystarlist) = dou.extract_output(dictofpaths=dictofvels,
                                                 tmesh=tip['tmesh'],
                                                 c_mat=c_mat,
                                                 ystarvec=contp.ystarvec)

    save_output_json(yscomplist,
                     tip['tmesh'].tolist(),
                     ystar=ystarlist,
                     fstring=cdatstr + cntpstr + '__sigout')

    costfunval = eval_costfunc(W=y_masmat,
                               V=contp.gamma * y_masmat,
                               R=None,
                               tbmat=tb_mat,
                               cmat=c_mat,
                               ystar=contp.ystarvec,
                               tmesh=tip['tmesh'],
                               veldict=dictofvels,
                               fbftdict=feedbackthroughdict)

    print 'Value of cost functional: ', costfunval

    costfunval = eval_costfunc(W=y_masmat,
                               V=contp.gamma * y_masmat,
                               R=None,
                               tbmat=tb_mat,
                               cmat=c_mat,
                               ystar=contp.ystarvec,
                               penau=False,
                               tmesh=tip['tmesh'],
                               veldict=dictofvels,
                               fbftdict=feedbackthroughdict)

    print 'Value of cost functional not considering `u`: ', costfunval

    print 'dim of v :', femp['V'].dim()
    charlene = .15 if problemname == 'cylinderwake' else 1.0
    print 'Re = charL / nu = {0}'.format(charlene / nu)
Example #25
0
def test_qbdae_ass(problemname='cylinderwake',
                   N=1,
                   Re=None,
                   nu=3e-2,
                   t0=0.0,
                   tE=1.0,
                   Nts=100,
                   use_saved_mats=None):

    trange = np.linspace(t0, tE, Nts + 1)
    DT = (tE - t0) / Nts
    rdir = 'results/'
    ddir = 'data/'

    if use_saved_mats is None:
        femp, stokesmatsc, rhsd_vfrc, rhsd_stbc = \
            dns.problem_setups.get_sysmats(problem=problemname, N=N, Re=Re)
        invinds = femp['invinds']

        A, J, M = stokesmatsc['A'], stokesmatsc['J'], stokesmatsc['M']
        L = 0 * A
        fvc, fpc = rhsd_vfrc['fvc'], rhsd_vfrc['fpr']
        fv_stbc, fp_stbc = rhsd_stbc['fv'], rhsd_stbc['fp']

        hstr = ddir + problemname + '_N{0}_hmat'.format(N)
        try:
            hmat = dou.load_spa(hstr)
            print('loaded `hmat`')
        except IOError:
            print('assembling hmat ...')
            hmat = dnsts.ass_convmat_asmatquad(W=femp['V'], invindsw=invinds)
            dou.save_spa(hmat, hstr)

        invinds = femp['invinds']
        NV, NP = invinds.shape[0], J.shape[0]
        zerv = np.zeros((NV, 1))

        bc_conv, bc_rhs_conv, rhsbc_convbc = \
            snu.get_v_conv_conts(prev_v=zerv, V=femp['V'], invinds=invinds,
                                 diribcs=femp['diribcs'], Picard=False)
        fp = fp_stbc + fpc
        fv = fv_stbc + fvc - bc_rhs_conv

        if linnsesol:
            vp_nse, _ = snu.\
                solve_steadystate_nse(A=A, J=J, JT=None, M=M,
                                      fv=fv_stbc + fvc,
                                      fp=fp_stbc + fpc,
                                      V=femp['V'], Q=femp['Q'],
                                      invinds=invinds,
                                      diribcs=femp['diribcs'],
                                      return_vp=False, ppin=-1,
                                      N=N, nu=nu,
                                      clearprvdata=False)
            old_v = vp_nse[:NV]
        else:
            import sadptprj_riclyap_adi.lin_alg_utils as lau
            # Stokes solution as initial value
            vp_stokes = lau.solve_sadpnt_smw(amat=A,
                                             jmat=J,
                                             rhsv=fv_stbc + fvc,
                                             rhsp=fp_stbc + fpc)

            old_v = vp_stokes[:NV]

        sysmat = sps.vstack([
            sps.hstack([M + DT * (A + bc_conv), J.T]),
            sps.hstack([J, sps.csc_matrix((NP, NP))])
        ])

    if use_saved_mats is not None:
        # if saved as in ../get_exp_mats
        import scipy.io
        mats = scipy.io.loadmat(use_saved_mats)
        A = -mats['A']
        L = -mats['L']
        Re = mats['Re']
        N = A.shape[0]
        M = mats['M']
        J = mats['J']
        hmat = -mats['H']
        fv = mats['fv']
        fp = mats['fp']
        NV, NP = fv.shape[0], fp.shape[0]
        old_v = mats['ss_stokes']
        sysmat = sps.vstack([
            sps.hstack([M + DT * A, J.T]),
            sps.hstack([J, sps.csc_matrix((NP, NP))])
        ])

    if compevs:
        import matplotlib.pyplot as plt
        import scipy.linalg as spla

        hlstr = ddir + problemname + '_N{0}_Re{1}Nse{2}_hlmat'.\
            format(N, Re, linnsesol)
        HL = linearzd_quadterm(hmat, old_v, hlstr=hlstr)
        print(HL.shape)
        asysmat = sps.vstack([
            sps.hstack([-(A - L + HL), J.T]),
            sps.hstack([J, sps.csc_matrix((NP, NP))])
        ])
        msysmat = sps.vstack([
            sps.hstack([M, sps.csc_matrix((NV, NP))]),
            sps.hstack([sps.csc_matrix((NP, NV)),
                        sps.csc_matrix((NP, NP))])
        ])
        levstr = ddir + problemname + '_N{0}Re{1}Nse{2}_levs'.\
            format(N, Re, linnsesol)
        try:
            levs = dou.load_npa(levstr)
            if debug:
                raise IOError()
            print('loaded the eigenvalues of the linearized system')
        except IOError:
            print('computing the eigenvalues of the linearized system')
            A = asysmat.todense()
            M = msysmat.todense()
            levs = spla.eigvals(A, M, overwrite_a=True, check_finite=False)
            dou.save_npa(levs, levstr)

        plt.figure(1)
        # plt.xlim((-25, 15))
        # plt.ylim((-50, 50))
        plt.plot(np.real(levs), np.imag(levs), '+')
        plt.show(block=False)

    if timeint:
        print('computing LU once...')
        sysmati = spsla.factorized(sysmat)

        vfile = dolfin.File(rdir + problemname + 'qdae__vel.pvd')
        pfile = dolfin.File(rdir + problemname + 'qdae__p.pvd')

        prvoutdict = dict(V=femp['V'],
                          Q=femp['Q'],
                          vfile=vfile,
                          pfile=pfile,
                          invinds=invinds,
                          diribcs=femp['diribcs'],
                          vp=None,
                          t=None,
                          writeoutput=True)

        print('doing the time loop...')
        for t in trange:
            crhsv = M * old_v + DT * (fv - hmat * np.kron(old_v, old_v))
            crhs = np.vstack([crhsv, fp])
            vp_new = np.atleast_2d(sysmati(crhs.flatten())).T

            prvoutdict.update(dict(vp=vp_new, t=t))
            dou.output_paraview(**prvoutdict)

            old_v = vp_new[:NV]
            print(t, np.linalg.norm(old_v))