Example #1
0
def comp_evcs_evls(compall=False, nevs=None, linsysstr=None, bigamat=None,
                   bigmmatshift=None, bigmmat=None, retinstevcs=False):

    whichevecs = '_leftevs' if leftevecs else '_rightevs'
    bcstr = '_palpha{0}'.format(palpha) if bccontrol else ''

    levstr = linsysstr + bcstr + whichevecs

    try:
        if debug:
            raise IOError()
        evls = dou.load_npa(levstr)
        print 'loaded the eigenvalues of the linearized system: \n' + levstr
        if retinstevcs:
            evcs = dou.load_npa(levstr+'_instableevcs')
        return evls, evcs
    except IOError:
        print 'computing the eigenvalues of the linearized system: \n' + levstr
        if compall:
            A = bigamat.todense()
            M = bigmmat.todense() if not shiftall else bigmmatshift.todense()
            evls = spla.eigvals(A, M, overwrite_a=True, check_finite=False)
        else:
            if leftevecs:
                bigamat = bigamat.T
                # TODO: we assume that M is symmetric

            msplu = spsla.splu(bigmmatshift)

            def minvavec(vvec):
                return msplu.solve(bigamat*vvec)

            miaop = spsla.LinearOperator(bigamat.shape, matvec=minvavec,
                                         dtype=bigamat.dtype)

            shiftamm = bigamat - sigma*bigmmatshift
            sammsplu = spsla.splu(shiftamm)

            def samminvmvec(vvec):
                return sammsplu.solve(bigmmatshift*vvec)

            samminvop = spsla.LinearOperator(bigamat.shape, matvec=samminvmvec,
                                             dtype=bigamat.dtype)

            evls, evcs = spsla.eigs(miaop, k=nevs, sigma=sigma,
                                    OPinv=samminvop, maxiter=100,
                                    # sigma=None, which='SM',
                                    return_eigenvectors=retinstevcs)
        dou.save_npa(evls, levstr)
        if retinstevcs:
            instevlsindx = np.real(evls) > 0
            instevcs = evcs[:, instevlsindx]
            dou.save_npa(instevcs, levstr+'_instableevcs')
        else:
            instevcs = None
        return evls, instevcs
Example #2
0
 def compcong():
     try:
         zwc = dou.load_npa(fdstr + '__zwc')
         print 'at least __zwc is there'
     except IOError:
         zwc = get_gramians(mmat=mmat, amat=f_mat,
                            jmat=stokesmatsc['J'],
                            bmat=b_mat, wmat=c_mat_reg.T,
                            nwtn_adi_dict=nap,
                            z0=zinic)['zfac']
         dou.save_npa(zwc, fdstr + '__zwc')
 def compcong():
     try:
         zwc = dou.load_npa(fdstr + '__zwc')
         print('yeyeyeah, __zwc is there')
     except IOError:
         # XXX: why here bmat*Rmhalf and in zwo not?
         zwc = get_ricadifacs(mmat=mmat, amat=fmat, jmat=jmat,
                              bmat=bmat, wmat=cmat.T,
                              z0=zinic, **adidict)['zfac']
         dou.save_npa(zwc, fdstr + '__zwc')
     return
Example #4
0
 def compobsg():
     try:
         zwo = dou.load_npa(fdstr + '__zwo')
         print 'at least __zwo is there'
     except IOError:
         zwo = get_gramians(mmat=mmat.T, amat=f_mat.T,
                            jmat=stokesmatsc['J'],
                            bmat=c_mat_reg.T, wmat=b_mat,
                            nwtn_adi_dict=nap,
                            z0=zinio)['zfac']
         dou.save_npa(zwo, fdstr + '__zwo')
 def compobsg():
     if zwconly:
         print('we only compute zwc')
         return
     try:
         zwo = dou.load_npa(fdstr + '__zwo')
         print('yeyeyeah, __zwo is there')
     except IOError:
         zwo = get_ricadifacs(mmat=mmat.T, amat=fmat.T, jmat=jmat,
                              bmat=cmat.T, wmat=bmat,
                              z0=zinio, **adidict)['zfac']
         dou.save_npa(zwo, fdstr + '__zwo')
     return
def rothe_time_int(problem='cylinderwake', nu=None, Re=None,
                   Nts=256, t0=0.0, tE=0.2, Nll=[2],
                   viniv=None, piniv=None, Nini=None,
                   scheme=None, dtstrdct={}, method=2):

    trange = np.linspace(t0, tE, Nts+1)

    t = trange[0]
    dtstrdct.update(dict(t=0, N=Nll[0]))
    cdatstr = get_dtstr(**dtstrdct)
    dou.save_npa(viniv, cdatstr + '__vel')
    curvdict = {t: cdatstr + '__vel'}
    dou.save_npa(piniv, cdatstr + '__p')
    logger.info('v/p saved to ' + cdatstr + '__v/__p')
    curpdict = {t: cdatstr + '__p'}
    smaminex = True if method == 1 else False

    vcurvec = viniv
    logger.debug(' t={0}, |v|={1}'.format(t, npla.norm(vcurvec)))
    curmeshdict = get_curmeshdict(problem=problem, N=Nll[0], nu=nu, Re=Re,
                                  scheme=scheme, smaminex=smaminex)
    curmeshdict.update(coefalu=None)
    Vc = curmeshdict['V']
    for tk, t in enumerate(trange[1:]):
        cts = t - trange[tk]
        if not Nll[tk+1] == Nll[tk]:
            curmeshdict = get_curmeshdict(problem=problem, N=Nll[tk+1], nu=nu,
                                          Re=Re, scheme=scheme,
                                          smaminex=smaminex)
            curmeshdict.update(coefalu=None)
            logger.info('changed the mesh from N={0} to N={1} at t={2}'.
                        format(Nll[tk], Nll[tk+1], t))
            # change in the mesh
        Nvc = curmeshdict['A'].shape[0]
        logger.debug("t={0}, dim V={1}".format(t, curmeshdict['V'].dim()))
        if smaminex:
            vpcur, coefalu = \
                roth_upd_smmx(vvec=vcurvec, cts=cts,
                              Vc=Vc, diribcsc=curmeshdict['diribcs'],
                              nmd=curmeshdict, returnalu=True)
        else:  # index 2
            vpcur, coefalu = \
                roth_upd_ind2(vvec=vcurvec, cts=cts,
                              Vc=Vc, diribcsc=curmeshdict['diribcs'],
                              nmd=curmeshdict, returnalu=True)
        dtstrdct.update(dict(t=t, N=Nll[tk+1]))
        cdatstr = get_dtstr(**dtstrdct)
        # add the boundary values to the velocity
        vcurvec = dts.append_bcs_vec(vpcur[:Nvc], **curmeshdict)
        logger.debug(' t={0}, |v|={1}'.format(t, npla.norm(vcurvec)))
        dou.save_npa(vcurvec, cdatstr+'__vel')
        curvdict.update({t: cdatstr+'__vel'})
        dou.save_npa(vpcur[Nvc:, :], cdatstr+'__p')
        curpdict.update({t: cdatstr+'__p'})
        curmeshdict.update(dict(coefalu=coefalu))
        Vc = curmeshdict['V']

    return curvdict, curpdict
Example #7
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 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 #9
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 #10
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 #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
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
Example #13
0
def lqgbt(problemname='drivencavity',
          N=10, Re=1e2, plain_bt=False,
          use_ric_ini=None, t0=0.0, tE=1.0, Nts=11,
          NU=3, NY=3,
          bccontrol=True, palpha=1e-5,
          paraoutput=True,
          trunc_lqgbtcv=1e-6,
          nwtn_adi_dict=None,
          comp_freqresp=False, comp_stepresp='nonlinear',
          closed_loop=False, multiproc=False,
          perturbpara=1e-3):
    """Main routine for LQGBT

    Parameters
    ----------
    problemname : string, optional
        what problem to be solved, 'cylinderwake' or 'drivencavity'
    N : int, optional
        parameter for the dimension of the space discretization
    Re : real, optional
        Reynolds number, defaults to `1e2`
    plain_bt : boolean, optional
        whether to try simple *balanced truncation*, defaults to False
    use_ric_ini : real, optional
        use the solution with this Re number as stabilizing initial guess,
        defaults to `None`
    t0, tE, Nts : real, real, int, optional
        starting and endpoint of the considered time interval, number of
        time instancses, default to `0.0, 1.0, 11`
    bccontrol : boolean, optional
        whether to apply boundary control via penalized robin conditions,
        defaults to `False`
    NU, NY : int, optional
        dimensions of components of in and output space (will double because
        there are two components), default to `3, 3`
    comp_freqresp : boolean, optional
        whether to compute and compare the frequency responses,
        defaults to `False`
    comp_stepresp : {'nonlinear', False, None}
        whether to compute and compare the step responses

        | if False -> no step response
        | if == 'nonlinear' -> compare linear reduced to nonlinear full model
        | else -> linear reduced versus linear full model

        defaults to `False`

    trunc_lqgbtcv : real, optional
        threshold at what the lqgbt characteristiv values are truncated,
        defaults to `1e-6`
    closed_loop : {'full_state_fb', 'red_output_fb', False, None}
        how to do the closed loop simulation:

        | if False -> no simulation
        | if == 'full_state_fb' -> full state feedback
        | if == 'red_output_fb' -> reduced output feedback
        | else -> no control is applied

        defaults to `False`

    """

    typprb = 'BT' if plain_bt else 'LQG-BT'

    print '\n ### We solve the {0} problem for the {1} at Re={2} ###\n'.\
        format(typprb, problemname, Re)

    if nwtn_adi_dict is not None:
        nap = nwtn_adi_dict
    else:
        nap = nwtn_adi_params()['nwtn_adi_dict']
    # output
    ddir = 'data/'
    try:
        os.chdir(ddir)
    except OSError:
        raise Warning('need "' + ddir + '" subdir for storing the data')
    os.chdir('..')

    # stokesmats = dts.get_stokessysmats(femp['V'], femp['Q'], nu)

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

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

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

    # # pressure freedom and dirichlet reduced rhs
    # rhsd_vfrc = dict(fpr=rhsd_vf['fp'], fvc=rhsd_vf['fv'][invinds, ])

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

    femp, stokesmatsc, rhsd_vfrc, rhsd_stbc \
        = dnsps.get_sysmats(problem=problemname, N=N, Re=Re,
                            bccontrol=bccontrol, scheme='TH')

    nu = femp['charlen']/Re
    # specify in what spatial direction Bu changes. The remaining is constant
    uspacedep = femp['uspacedep']

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

    prbstr = '_bt' if plain_bt else '_lqgbt'
    # contsetupstr = 'NV{0}NU{1}NY{2}alphau{3}'.format(NV, NU, NY, alphau)
    if bccontrol:
        import scipy.sparse as sps
        contsetupstr = 'NV{0}_bcc_NY{1}'.format(NV, NY)
        stokesmatsc['A'] = stokesmatsc['A'] + 1./palpha*stokesmatsc['Arob']
        b_mat = 1./palpha*stokesmatsc['Brob']
        u_masmat = sps.eye(b_mat.shape[1], format='csr')
    else:
        contsetupstr = 'NV{0}NU{1}NY{2}'.format(NV, NU, NY)

    def get_fdstr(Re):
        return ddir + problemname + '_Re{0}_'.format(Re) + \
            contsetupstr + prbstr

    fdstr = get_fdstr(Re)

    soldict = stokesmatsc  # containing A, J, JT
    soldict.update(femp)  # adding V, Q, invinds, diribcs
    # soldict.update(rhsd_vfrc)  # adding fvc, fpr
    soldict.update(fv=rhsd_stbc['fv']+rhsd_vfrc['fvc'],
                   fp=rhsd_stbc['fp']+rhsd_vfrc['fpr'],
                   N=N, nu=nu, data_prfx=fdstr)

#
# Prepare for control
#

    # get the control and observation operators
    if not bccontrol:
        try:
            b_mat = dou.load_spa(ddir + contsetupstr + '__b_mat')
            u_masmat = dou.load_spa(ddir + contsetupstr + '__u_masmat')
            print 'loaded `b_mat`'
        except IOError:
            print 'computing `b_mat`...'
            b_mat, u_masmat = cou.get_inp_opa(cdcoo=femp['cdcoo'], V=femp['V'],
                                              NU=NU, xcomp=uspacedep)
            dou.save_spa(b_mat, ddir + contsetupstr + '__b_mat')
            dou.save_spa(u_masmat, ddir + contsetupstr + '__u_masmat')

        b_mat = b_mat[invinds, :][:, :]
        # tb_mat = 1./np.sqrt(alphau)

    try:
        mc_mat = dou.load_spa(ddir + contsetupstr + '__mc_mat')
        y_masmat = dou.load_spa(ddir + contsetupstr + '__y_masmat')
        print 'loaded `c_mat`'
    except IOError:
        print 'computing `c_mat`...'
        mc_mat, y_masmat = cou.get_mout_opa(odcoo=femp['odcoo'],
                                            V=femp['V'], NY=NY)
        dou.save_spa(mc_mat, ddir + contsetupstr + '__mc_mat')
        dou.save_spa(y_masmat, ddir + contsetupstr + '__y_masmat')

    c_mat = lau.apply_massinv(y_masmat, mc_mat, output='sparse')
    # restrict the operators to the inner nodes

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

    # c_mat_reg = np.array(c_mat.todense())

    # TODO: right choice of norms for y
    #       and necessity of regularization here
    #       by now, we go on number save
#
# setup the system for the correction
#
#
# compute the uncontrolled steady state Stokes solution
#
    v_ss_nse, list_norm_nwtnupd = snu.solve_steadystate_nse(**soldict)
    (convc_mat, rhs_con,
     rhsv_conbc) = snu.get_v_conv_conts(prev_v=v_ss_nse, invinds=invinds,
                                        V=femp['V'], diribcs=femp['diribcs'])

    f_mat = - stokesmatsc['A'] - convc_mat
    mmat = stokesmatsc['M']

    # ssv_rhs = rhsv_conbc + rhsv_conbc + rhsd_vfrc['fvc'] + rhsd_stbc['fv']

    if plain_bt:
        get_gramians = pru.solve_proj_lyap_stein
    else:
        get_gramians = pru.proj_alg_ric_newtonadi

    truncstr = '__lqgbtcv{0}'.format(trunc_lqgbtcv)
    try:
        tl = dou.load_npa(fdstr + '__tl' + truncstr)
        tr = dou.load_npa(fdstr + '__tr' + truncstr)
        print 'loaded the left and right transformations: \n' + \
            fdstr + '__tl/__tr' + truncstr
    except IOError:
        print 'computing the left and right transformations' + \
            ' and saving to: \n' + fdstr + '__tl/__tr' + truncstr

        try:
            zwc = dou.load_npa(fdstr + '__zwc')
            zwo = dou.load_npa(fdstr + '__zwo')
            print 'loaded factor of the Gramians: \n\t' + \
                fdstr + '__zwc/__zwo'
        except IOError:
            zinic, zinio = None, None
            if use_ric_ini is not None:
                fdstr = get_fdstr(use_ric_ini)
                try:
                    zinic = dou.load_npa(fdstr + '__zwc')
                    zinio = dou.load_npa(fdstr + '__zwo')
                    print 'Initialize Newton ADI by zwc/zwo from ' + fdstr
                except IOError:
                    raise UserWarning('No initial guess with Re={0}'.
                                      format(use_ric_ini))

            fdstr = get_fdstr(Re)
            print 'computing factors of Gramians: \n\t' + \
                fdstr + '__zwc/__zwo'

            def compobsg():
                try:
                    zwo = dou.load_npa(fdstr + '__zwo')
                    print 'at least __zwo is there'
                except IOError:
                    zwo = get_gramians(mmat=mmat.T, amat=f_mat.T,
                                       jmat=stokesmatsc['J'],
                                       bmat=c_mat_reg.T, wmat=b_mat,
                                       nwtn_adi_dict=nap,
                                       z0=zinio)['zfac']
                    dou.save_npa(zwo, fdstr + '__zwo')

            def compcong():
                try:
                    zwc = dou.load_npa(fdstr + '__zwc')
                    print 'at least __zwc is there'
                except IOError:
                    zwc = get_gramians(mmat=mmat, amat=f_mat,
                                       jmat=stokesmatsc['J'],
                                       bmat=b_mat, wmat=c_mat_reg.T,
                                       nwtn_adi_dict=nap,
                                       z0=zinic)['zfac']
                    dou.save_npa(zwc, fdstr + '__zwc')

            if multiproc:
                print '\n ### multithread start - ' +\
                    'output might be intermangled'
                p1 = multiprocessing.Process(target=compobsg)
                p2 = multiprocessing.Process(target=compcong)
                p1.start()
                p2.start()
                p1.join()
                p2.join()
                print '### multithread end'

            else:
                compobsg()
                compcong()

            zwc = dou.load_npa(fdstr + '__zwc')
            zwo = dou.load_npa(fdstr + '__zwo')

        print 'computing the left and right transformations' + \
            ' and saving to:\n' + fdstr + '__tr/__tl' + truncstr

        tl, tr = btu.\
            compute_lrbt_transfos(zfc=zwc, zfo=zwo,
                                  mmat=stokesmatsc['M'],
                                  trunck={'threshh': trunc_lqgbtcv})
        dou.save_npa(tl, fdstr + '__tl' + truncstr)
        dou.save_npa(tr, fdstr + '__tr' + truncstr)

    print 'NV = {0}, NP = {2}, k = {1}'.\
        format(tl.shape[0], tl.shape[1], stokesmatsc['J'].shape[0])

    if comp_freqresp:
        btu.compare_freqresp(mmat=stokesmatsc['M'], amat=f_mat,
                             jmat=stokesmatsc['J'], bmat=b_mat,
                             cmat=c_mat, tr=tr, tl=tl,
                             plot=True, datastr=fdstr + '__tl' + truncstr)

    if comp_stepresp is not False:
        if comp_stepresp == 'nonlinear':
            stp_rsp_nwtn = 3
            stp_rsp_dtpr = 'nonl_stepresp_'
        else:
            stp_rsp_nwtn = 1
            stp_rsp_dtpr = 'stepresp_'

        def fullstepresp_lnse(bcol=None, trange=None, ini_vel=None,
                              cmat=None, soldict=None):
            soldict.update(fv_stbc=rhsd_stbc['fv']+bcol,
                           vel_nwtn_stps=stp_rsp_nwtn, trange=trange,
                           iniv=ini_vel, lin_vel_point=ini_vel,
                           clearprvdata=True, data_prfx=stp_rsp_dtpr,
                           return_dictofvelstrs=True)

            dictofvelstrs = snu.solve_nse(**soldict)

            return cou.extract_output(strdict=dictofvelstrs, tmesh=trange,
                                      c_mat=cmat, load_data=dou.load_npa)

    # differences in the initial vector
    # print np.dot(c_mat_reg, v_ss_nse)
    # print np.dot(np.dot(c_mat_reg, tr),
    #              np.dot(tl.T, stokesmatsc['M']*v_ss_nse))

        jsonstr = fdstr + stp_rsp_dtpr + '_Nred{0}_t0tENts{1}{2}{3}.json'.\
            format(tl.shape[1], t0, tE, Nts)
        btu.compare_stepresp(tmesh=np.linspace(t0, tE, Nts),
                             a_mat=f_mat, c_mat=c_mat_reg, b_mat=b_mat,
                             m_mat=stokesmatsc['M'],
                             tr=tr, tl=tl, iniv=v_ss_nse,
                             # ss_rhs=ssv_rhs,
                             fullresp=fullstepresp_lnse, fsr_soldict=soldict,
                             plot=True, jsonstr=jsonstr)

# compute the regulated system
    trange = np.linspace(t0, tE, Nts)

    if closed_loop is False:
        return

    elif closed_loop == 'full_state_fb':
        zwc = dou.load_npa(fdstr + '__zwc')
        zwo = dou.load_npa(fdstr + '__zwo')

        mtxtb = pru.get_mTzzTtb(stokesmatsc['M'].T, zwc, b_mat)

        def fv_tmdp_fullstatefb(time=None, curvel=None,
                                linv=None, tb_mat=None, tbxm_mat=None, **kw):
            """realizes a full state static feedback as a function

            that can be passed to a solution routine for the
            unsteady Navier-Stokes equations

            Parameters
            ----------
            time : real
                current time
            curvel : (N,1) nparray
                current velocity
            linv : (N,1) nparray
                linearization point for the linear model
            tb_mat : (N,K) nparray
                input matrix containing the input weighting
            tbxm_mat : (N,K) nparray
                `tb_mat * gain * mass`

            Returns
            -------
            actua : (N,1) nparray
                current contribution to the right-hand side
            , : dictionary
                dummy `{}` for consistency
            """

            actua = -lau.comp_uvz_spdns(tb_mat, tbxm_mat, curvel-linv)
            # actua = 0*curvel
            print '\nnorm of deviation', np.linalg.norm(curvel-linv)
            # print 'norm of actuation {0}'.format(np.linalg.norm(actua))
            return actua, {}

        tmdp_fsfb_dict = dict(linv=v_ss_nse, tb_mat=b_mat, tbxm_mat=mtxtb.T)

        fv_tmdp = fv_tmdp_fullstatefb
        fv_tmdp_params = tmdp_fsfb_dict
        fv_tmdp_memory = None

    elif closed_loop == 'red_output_fb':
        try:
            xok = dou.load_npa(fdstr+truncstr+'__xok')
            xck = dou.load_npa(fdstr+truncstr+'__xck')
            ak_mat = dou.load_npa(fdstr+truncstr+'__ak_mat')
            ck_mat = dou.load_npa(fdstr+truncstr+'__ck_mat')
            bk_mat = dou.load_npa(fdstr+truncstr+'__bk_mat')
        except IOError:
            print 'couldn"t load the red system - compute it'
            zwc = dou.load_npa(fdstr + '__zwc')
            zwo = dou.load_npa(fdstr + '__zwo')

            ak_mat = np.dot(tl.T, f_mat*tr)
            ck_mat = lau.mm_dnssps(c_mat_reg, tr)
            bk_mat = lau.mm_dnssps(tl.T, b_mat)

            tltm, trtm = tl.T*stokesmatsc['M'], tr.T*stokesmatsc['M']
            xok = np.dot(np.dot(tltm, zwo), np.dot(zwo.T, tltm.T))
            xck = np.dot(np.dot(trtm, zwc), np.dot(zwc.T, trtm.T))

            dou.save_npa(xok, fdstr+truncstr+'__xok')
            dou.save_npa(xck, fdstr+truncstr+'__xck')
            dou.save_npa(ak_mat, fdstr+truncstr+'__ak_mat')
            dou.save_npa(ck_mat, fdstr+truncstr+'__ck_mat')
            dou.save_npa(bk_mat, fdstr+truncstr+'__bk_mat')

        obs_bk = np.dot(xok, ck_mat.T)
        DT = (tE - t0)/(Nts-1)

        sysmatk_inv = np.linalg.inv(np.eye(ak_mat.shape[1]) - DT*(ak_mat -
                                    np.dot(np.dot(xok, ck_mat.T), ck_mat) -
                                    np.dot(bk_mat, np.dot(bk_mat.T, xck))))

        def fv_tmdp_redoutpfb(time=None, curvel=None, memory=None,
                              linvel=None,
                              ipsysk_mat_inv=None,
                              obs_bk=None, cts=None,
                              b_mat=None, c_mat=None,
                              xck=None, bk_mat=None,
                              **kw):
            """realizes a reduced static output feedback as a function

            that can be passed to a solution routine for the
            unsteady Navier-Stokes equations

            For convinience the
            Parameters
            ----------
            time : real
                current time
            curvel : (N,1) nparray
                current velocity. For consistency, the full state is taken
                as input. However, internally, we only use the observation
                `y = c_mat*curvel`
            memory : dictionary
                contains values from previous call, in particular the
                previous state estimate
            linvel : (N,1) nparray
                linearization point for the linear model
            ipsysk_mat_inv : (K,K) nparray
                inverse of the system matrix that defines the update
                of the state estimate
            obs_bk : (K,NU) nparray
                input matrix in the observer
            cts : real
                time step length
            b_mat : (N,NU) sparse matrix
                input matrix of the full system
                c_mat=None,
            c_mat : (NY,N) sparse matrix
                output matrix of the full system
            xck : (K,K) nparray
                reduced solution of the CARE
            bk_mat : (K,NU) nparray
                reduced input matrix

            Returns
            -------
            actua : (N,1) nparray
                the current actuation
            memory : dictionary
                to be passed back in the next timestep

            """
            xk_old = memory['xk_old']
            buk = cts*np.dot(obs_bk,
                             lau.mm_dnssps(c_mat, (curvel-linvel)))
            xk_old = np.dot(ipsysk_mat_inv, xk_old + buk)
            #         cts*np.dot(obs_bk,
            #                 lau.mm_dnssps(c_mat, (curvel-linvel))))
            memory['xk_old'] = xk_old
            actua = -lau.mm_dnssps(b_mat,
                                   np.dot(bk_mat.T, np.dot(xck, xk_old)))
            print '\nnorm of deviation', np.linalg.norm(curvel-linvel)
            print 'norm of actuation {0}'.format(np.linalg.norm(actua))
            return actua, memory

        fv_rofb_dict = dict(cts=DT, linvel=v_ss_nse, b_mat=b_mat,
                            c_mat=c_mat_reg, obs_bk=obs_bk, bk_mat=bk_mat,
                            ipsysk_mat_inv=sysmatk_inv, xck=xck)

        fv_tmdp = fv_tmdp_redoutpfb
        fv_tmdp_params = fv_rofb_dict
        fv_tmdp_memory = dict(xk_old=np.zeros((tl.shape[1], 1)))

    else:
        fv_tmdp = None
        fv_tmdp_params = {}
        fv_tmdp_memory = {}

    perturbini = perturbpara*np.ones((NV, 1))
    reg_pertubini = lau.app_prj_via_sadpnt(amat=stokesmatsc['M'],
                                           jmat=stokesmatsc['J'],
                                           rhsv=perturbini)

    soldict.update(fv_stbc=rhsd_stbc['fv'],
                   trange=trange,
                   iniv=v_ss_nse + reg_pertubini,
                   lin_vel_point=None,
                   clearprvdata=True, data_prfx=fdstr + truncstr,
                   fv_tmdp=fv_tmdp,
                   comp_nonl_semexp=True,
                   fv_tmdp_params=fv_tmdp_params,
                   fv_tmdp_memory=fv_tmdp_memory,
                   return_dictofvelstrs=True)

    outstr = truncstr + '{0}'.format(closed_loop) \
        + 't0{0}tE{1}Nts{2}N{3}Re{4}'.format(t0, tE, Nts, N, Re)
    if paraoutput:
        soldict.update(paraviewoutput=True,
                       vfileprfx='results/vel_'+outstr,
                       pfileprfx='results/p_'+outstr)

    dictofvelstrs = snu.solve_nse(**soldict)

    yscomplist = cou.extract_output(strdict=dictofvelstrs, tmesh=trange,
                                    c_mat=c_mat, load_data=dou.load_npa)

    dou.save_output_json(dict(tmesh=trange.tolist(), outsig=yscomplist),
                         fstring=fdstr + truncstr + '{0}'.format(closed_loop) +
                         't0{0}tE{1}Nts{2}'.format(t0, tE, Nts) +
                         'inipert{0}'.format(perturbpara))

    dou.plot_outp_sig(tmesh=trange, outsig=yscomplist)
Example #14
0
    format(NN, Re, compall)
try:
    if debug:
        raise IOError()
    levs = dou.load_npa(levstr)
    print 'loaded the eigenvalues of the linearized system'
except IOError:
    print 'computing the eigenvalues of the linearized system'
    if compall:
        A = asysmat.todense()
        M = msysmat.todense() if not shiftall else mshiftsmat.todense()
        levs = spla.eigvals(A, M, overwrite_a=True, check_finite=False)
    else:
        levs = spsla.eigs(asysmat, M=mshiftsmat, sigma=1, k=10, which='LR',
                          return_eigenvectors=False)
    dou.save_npa(levs, levstr)

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

projsys = False
if projsys:
    mfac = spsla.splu(M)
    mijtl = []
    for kcol in range(J.shape[0]):
        curcol = np.array(J.T[:, kcol].todense())
        micc = np.array(mfac.solve(curcol.flatten()))
        mijtl.append(micc.reshape((NV, 1)))
def set_inival(whichinival='sstokes', soldict=None, perturbpara=None,
               v_ss_nse=None, trange=None, tpp=None, fdstr=None,
               retvssnse=False):
    ''' compute the wanted initial value and set it in the soldict

    '''

    if (retvssnse or whichinival == 'sstate+d') and v_ss_nse is None:
        ret_v_ss_nse = snu.solve_steadystate_nse(**soldict)
    elif v_ss_nse is not None:
        ret_v_ss_nse = v_ss_nse
    else:
        ret_v_ss_nse is None

    if whichinival == 'sstokes':
        print('we start with Stokes -- `perturbpara` is not considered')
        soldict.update(dict(iniv=None, start_ssstokes=True))
        shortinivstr = 'sks'
        return shortinivstr, ret_v_ss_nse

    if (whichinival == 'sstate+d' or
            whichinival == 'snse+d++' or whichinival == 'sstate+du'):
        perturbini = perturbpara*np.ones((soldict['M'].shape[0], 1))
        reg_pertubini = lau.app_prj_via_sadpnt(amat=soldict['M'],
                                               jmat=soldict['J'],
                                               rhsv=perturbini)
        if whichinival == 'sstate+d':
            soldict.update(dict(iniv=ret_v_ss_nse + reg_pertubini))
            shortinivstr = 'ssd{0}'.format(perturbpara)
            return shortinivstr, ret_v_ss_nse

    if whichinival == 'sstokes++' or whichinival == 'snse+d++':
        lctrng = (trange[trange < tpp]).tolist()
        lctrng.append(tpp)

        stksppdtstr = fdstr + 't0{0:.1f}tE{1:.4f}'.\
            format(trange[0], tpp) + whichinival
        try:
            sstokspp = dou.load_npa(stksppdtstr)
            print('loaded ' + stksppdtstr + ' for inival')
        except IOError:
            inivsoldict = {}
            inivsoldict.update(soldict)  # containing A, J, JT
            inivsoldict['fv_tmdp'] = None  # don't want control here
            # import ipdb; ipdb.set_trace()
            inivsoldict.update(trange=np.array(lctrng),
                               comp_nonl_semexp=True,
                               return_dictofvelstrs=True)
            if whichinival == 'sstokes++':
                print('solving for `stokespp({0})` as inival'.format(tpp))
                inivsoldict.update(iniv=None, start_ssstokes=True)
            else:
                inivsoldict.update(iniv=ret_v_ss_nse+reg_pertubini)
                print('solving for `nse+d+pp({0})` as inival'.format(tpp))
            dcvlstrs = snu.solve_nse(**inivsoldict)
            sstokspp = dou.load_npa(dcvlstrs[tpp])
            dou.save_npa(sstokspp, stksppdtstr)
        soldict.update(dict(iniv=sstokspp))
        shortinivstr = 'sk{0}'.format(tpp) if whichinival == 'sstokes++' \
            else 'nsk{0}'.format(tpp)
        return shortinivstr, ret_v_ss_nse
Example #16
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))
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))
Example #18
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 #19
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 #20
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