def get_pfromv(v=None, V=None, M=None, A=None, J=None, fv=None, fp=None, decouplevp=False, solve_M=None, symmetric=False, cgtol=1e-8, diribcs=None, dbcinds=None, dbcvals=None, invinds=None, **kwargs): """ for a velocity `v`, get the corresponding `p` Notes ----- Formula is only valid for constant rhs in the continuity equation """ import sadptprj_riclyap_adi.lin_alg_utils as lau _, rhs_con, _ = get_v_conv_conts(prev_v=v, V=V, invinds=invinds, dbcinds=dbcinds, dbcvals=dbcvals, diribcs=diribcs) if decouplevp and symmetric: vp = lau.solve_sadpnt_smw(jmat=J, jmatT=J.T, decouplevp=decouplevp, solve_A=solve_M, symmetric=symmetric, cgtol=1e-8, rhsv=-A*v-rhs_con+fv) return -vp[J.shape[1]:, :] else: vp = lau.solve_sadpnt_smw(amat=M, jmat=J, jmatT=J.T, decouplevp=decouplevp, solve_A=solve_M, symmetric=symmetric, cgtol=1e-8, rhsv=-A*v-rhs_con+fv) return -vp[J.shape[1]:, :]
def get_pfromv(v=None, V=None, M=None, A=None, J=None, fv=None, fp=None, diribcs=None, invinds=None, **kwargs): """ for a velocity `v`, get the corresponding `p` Notes ----- Formula is only valid for constant rhs in the continuity equation """ import sadptprj_riclyap_adi.lin_alg_utils as lau _, rhs_con, _ = get_v_conv_conts(prev_v=v, V=V, invinds=invinds, diribcs=diribcs) vp = lau.solve_sadpnt_smw(amat=M, jmat=J, jmatT=-J.T, rhsv=-A * v - rhs_con + fv) return vp[J.shape[1]:, :]
def test_sadpnt_smw_krypy(self): """check the sadpnt solver with krypy""" umat, vmat, k, = self.U, self.V, self.k # self.Jt = self.J.T # check the formula AuvInvZ = lau.solve_sadpnt_smw(amat=self.A, jmat=self.J, rhsv=self.Z, jmatT=self.Jt, umat=self.U, vmat=self.V, krylov=True, krpslvprms=self.krpslvprms) sysm1 = sps.hstack([self.A, self.Jt], format='csr') sysm2 = sps.hstack([self.J, sps.csr_matrix((k, k))], format='csr') mata = sps.vstack([sysm1, sysm2], format='csr') umate = np.vstack([umat, np.zeros((k, umat.shape[1]))]) vmate = np.hstack([vmat, np.zeros((vmat.shape[0], k))]) ze = np.vstack([self.Z, np.zeros((k, self.Z.shape[1]))]) AAinvZ = mata * AuvInvZ - np.dot(umate, np.dot(vmate, AuvInvZ)) # likely to fail because of ill conditioned rand mats print(np.linalg.norm(AAinvZ - ze)) self.assertTrue(np.allclose(AAinvZ, ze), msg='likely to fail because of ill cond')
def getthecoeffs(N=None, Re=None, scheme='CR', inivp='Stokes', inifemp=None): femp, stokesmatsc, rhsmomcont \ = dnsps.get_sysmats(problem='cylinderwake', N=N, Re=Re, scheme=scheme, mergerhs=True) fp = rhsmomcont['fp'] fv = rhsmomcont['fv'] # stokesmatsc.update(rhsmomcont) J, MP = stokesmatsc['J'], stokesmatsc['MP'] NV, NP = J.T.shape # Nv = J.shape[1] # Mpfac = spsla.splu(MP) if inivp is 'Stokes': inivp = lau.solve_sadpnt_smw(amat=stokesmatsc['A'], jmat=J, jmatT=-J.T, rhsv=fv, rhsp=fp) iniv = inivp[:NV] inip = snu.get_pfromv(v=iniv, V=femp['V'], M=stokesmatsc['M'], A=stokesmatsc['A'], J=J, fv=fv, fp=fp, diribcs=femp['diribcs'], invinds=femp['invinds']) else: inv, inp = dts.expand_vp_dolfunc(vp=inivp, **inifemp) # interpolate on new mesh and extract the invinds getconvvec = getconvvecfun(**femp) return dict(A=stokesmatsc['A'], M=stokesmatsc['M'], J=J, JT=J.T, MP=MP, fp=fp, fv=fv, getconvvec=getconvvec, iniv=iniv, inip=inip, V=femp['V'], Q=femp['Q'], invinds=femp['invinds'], diribcs=femp['diribcs'], ppin=femp['ppin'], femp=femp)
def roth_upd_ind2(vvec=None, cts=None, nu=None, Vc=None, diribcsc=None, nmd=dict(V=None, Q=None, M=None, A=None, J=None, fv=None, fp=None, invinds=None, diribcs=None, coefalu=None), returnalu=False, **kwargs): """ advancing `v, p` for one time using Rothe's method Parameters --- nmd : dict containing the data (mesh, matrices, rhs) from the next time step vvec : (n,1)-array current solution Vc : dolfin.mesh current mesh Notes ----- Time dependent Dirichlet conditions are not supported by now """ logger.debug("length of vvec={0}".format(vvec.size)) if not nmd['V'] == Vc: vvec = _vctovn(vvec=vvec, Vc=Vc, Vn=nmd['V']) logger.debug('len(vvec)={0}, dim(Vn)={1}, dim(Vc)={2}'. format(vvec.size, nmd['V'].dim(), Vc.dim())) mvvec = nmd['M']*vvec[nmd['invinds'], :] convvec = dts.get_convvec(u0_vec=vvec, V=nmd['V'], diribcs=nmd['diribcs'], invinds=nmd['invinds']) if nmd['coefalu'] is None: mta = nmd['M'] + cts*nmd['A'] mtJT = -cts*nmd['J'].T else: mta = None mtJT = None rhsv = mvvec + cts*(nmd['fv'] - convvec) lsdpdict = dict(amat=mta, jmat=nmd['J'], jmatT=mtJT, rhsv=rhsv, rhsp=nmd['fp'], sadlu=nmd['coefalu'], return_alu=returnalu) if returnalu: vp_new, coefalu = lau.solve_sadpnt_smw(**lsdpdict) return vp_new, coefalu else: vp_new = lau.solve_sadpnt_smw(**lsdpdict) return vp_new
def test_solve_proj_sadpnt_smw(self): """check the sadpnt as projection""" n = self.n # check whether it is a projection AuvInvZ = lau.solve_sadpnt_smw(amat=self.A, jmat=self.J, rhsv=self.Z, jmatT=self.Jt, umat=self.U, vmat=self.V) auvAUVinv = self.A * AuvInvZ[:n, :] - \ lau.comp_uvz_spdns(self.U, self.V, AuvInvZ[:n, :]) AuvInv2Z = lau.solve_sadpnt_smw(amat=self.A, jmat=self.J, rhsv=auvAUVinv, jmatT=self.Jt, umat=self.U, vmat=self.V) self.assertTrue(np.allclose(AuvInvZ[:n, :], AuvInv2Z[:n, :]), msg='likely to fail because of ill cond') prjz = lau.app_prj_via_sadpnt(amat=self.A, jmat=self.J, rhsv=self.Z, jmatT=self.Jt) prprjz = lau.app_prj_via_sadpnt(amat=self.A, jmat=self.J, rhsv=self.Z, jmatT=self.Jt) # check projector self.assertTrue(np.allclose(prprjz, prjz)) # onto kernel J self.assertTrue(np.linalg.norm(prjz) > 1e-8) self.assertTrue(np.linalg.norm(self.J*prjz)/np.linalg.norm(prjz) < 1e-6) # check transpose idmat = np.eye(n) prj = lau.app_prj_via_sadpnt(amat=self.A, jmat=self.J, rhsv=idmat, jmatT=self.Jt) prjT = lau.app_prj_via_sadpnt(amat=self.A, jmat=self.J, rhsv=idmat, jmatT=self.Jt, transposedprj=True) self.assertTrue(np.allclose(prj, prjT.T))
def get_pfromv(v=None, V=None, M=None, A=None, J=None, fv=None, fp=None, diribcs=None, invinds=None, **kwargs): """ for a velocity `v`, get the corresponding `p` Notes ----- Formula is only valid for constant rhs in the continuity equation """ import sadptprj_riclyap_adi.lin_alg_utils as lau _, rhs_con, _ = get_v_conv_conts(prev_v=v, V=V, invinds=invinds, diribcs=diribcs) vp = lau.solve_sadpnt_smw(amat=M, jmat=J, jmatT=-J.T, rhsv=-A*v-rhs_con+fv) return vp[J.shape[1]:, :]
def solve_stst_feedbacknthrough(amat=None, mmat=None, jmat=None, bmat=None, cmat=None, fv=None, fl=None, fg=None, fl2=None, nwtn_adi_dict=dict(adi_max_steps=150, adi_newZ_reltol=1e-5, nwtn_max_steps=14, nwtn_upd_reltol=1e-8)): """solve for the stabilizing feedback gain and the feedthrough for the linear time invariant case""" Z = proj_alg_ric_newtonadi(mmat=mmat, amat=amat, jmat=jmat, bmat=bmat, wmat=cmat, nwtn_adi_dict=nwtn_adi_dict) mtxb = get_mTzzTtb(mmat.T, Z, bmat) mtxfv = get_mTzzTtb(mmat.T, Z, fv) wft = lau.solve_sadpnt_smw(amat=-amat.T, jmat=jmat, rhsv=fl-mtxfv, umat=-mtxb, vmat=bmat.T) return Z, wft
def compare_freqresp(mmat=None, amat=None, jmat=None, bmat=None, cmat=None, tr=None, tl=None, ahat=None, bhat=None, chat=None, plot=False, datastr=None): """ compare the frequency response of the original and the reduced model cf. [HeiSS08, p. 1059] but with B_2 = 0 Returns ------- freqrel : list of floats the frob norm of the transferfunction at a frequency range red_freqrel : list of floats from of the tf of the reduced model at the same frequencies absci : list of floats frequencies where the tfs are evaluated at """ if ahat is None: ahat = np.dot(tl.T, amat*tr) if bhat is None: bhat = tl.T*bmat if chat is None: chat = cmat*tr NV, red_nv = amat.shape[0], ahat.shape[0] imunit = 1j absci = np.logspace(-4, 8, base=10) freqrel, red_freqrel, diff_freqrel = [], [], [] for omega in absci: sadib = lau.solve_sadpnt_smw(amat=omega*imunit*mmat-amat, jmat=jmat, rhsv=bmat) freqrel.append(np.linalg.norm(cmat*sadib[:NV, :])) # print freqrel[-1] aib = np.linalg.solve(omega*imunit*np.eye(red_nv) - ahat, bhat) red_freqrel.append(np.linalg.norm(np.dot(chat, aib))) diff_freqrel.append(np.linalg.norm(np.dot(chat, aib) - cmat*sadib[:NV, :])) # print red_freqrel[-1] if datastr is not None: dou.save_output_json(dict(tmesh=absci.tolist(), fullsysfr=freqrel, redsysfr=red_freqrel, diffsysfr=diff_freqrel), fstring=datastr + 'forfreqrespplot') if plot: legstr = ['NV was {0}'.format(mmat.shape[0]), 'nv is {0}'.format(tr.shape[1]), 'difference'] fig = plt.figure() ax = fig.add_subplot(111) ax.plot(absci, freqrel, color='b', linewidth=2.0) ax.plot(absci, red_freqrel, color='r', linewidth=2.0) ax.plot(absci, diff_freqrel, color='b', linewidth=1.0) plt.legend(legstr, loc=3) plt.semilogx() plt.semilogy() plt.show(block=False) from matplotlib2tikz import save as tikz_save tikz_save(datastr + 'freqresp.tikz', figureheight='\\figureheight', figurewidth='\\figurewidth' ) return freqrel, red_freqrel, absci
def comp_exp_nsmats( problemname="drivencavity", N=10, Re=1e2, nu=None, linear_system=False, refree=False, bccontrol=False, palpha=None, use_old_data=False, mddir="pathtodatastorage", ): """compute and export the system matrices for Navier-Stokes equations Parameters --- refree : boolean, optional whether to use `Re=1` (so that the `Re` number can be applied later by scaling the corresponding matrices, defaults to `False` linear_system : boolean, optional whether to compute/return the linearized system, defaults to `False` bccontrol : boolean, optional whether to model boundary control at the cylinder via penalized robin boundary conditions, defaults to `False` palpha : float, optional penalization parameter for the boundary control, defaults to `None`, `palpha` is mandatory for `linear_system` """ if refree: Re = 1 print "For the Reynoldsnumber free mats, we set Re=1" if problemname == "drivencavity" and bccontrol: raise NotImplementedError("boundary control for the driven cavity" + " is not implemented yet") if linear_system and bccontrol and palpha is None: raise UserWarning("For the linear system a" + " value for `palpha` is needed") if not linear_system and bccontrol: raise NotImplementedError("Nonlinear system with boundary control" + " is not implemented yet") femp, stokesmatsc, rhsd_vfrc, rhsd_stbc = dnsps.get_sysmats(problem=problemname, bccontrol=bccontrol, N=N, Re=Re) if linear_system and bccontrol: Arob = stokesmatsc["A"] + 1.0 / palpha * stokesmatsc["Arob"] Brob = 1.0 / palpha * stokesmatsc["Brob"] elif linear_system: Brob = 0 invinds = femp["invinds"] A, J = stokesmatsc["A"], stokesmatsc["J"] fvc, fpc = rhsd_vfrc["fvc"], rhsd_vfrc["fpr"] fv_stbc, fp_stbc = rhsd_stbc["fv"], rhsd_stbc["fp"] invinds = femp["invinds"] NV = invinds.shape[0] data_prfx = problemname + "__N{0}Re{1}".format(N, Re) if bccontrol: data_prfx = data_prfx + "_penarob" soldict = stokesmatsc # containing A, J, JT soldict.update(femp) # adding V, Q, invinds, diribcs soldict.update(rhsd_vfrc) # adding fvc, fpr fv = rhsd_vfrc["fvc"] + rhsd_stbc["fv"] fp = rhsd_vfrc["fpr"] + rhsd_stbc["fp"] # print 'get expmats: ||fv|| = {0}'.format(np.linalg.norm(fv)) # print 'get expmats: ||fp|| = {0}'.format(np.linalg.norm(fp)) # import scipy.sparse.linalg as spsla # print 'get expmats: ||A|| = {0}'.format(spsla.norm(A)) # print 'get expmats: ||Arob|| = {0}'.format(spsla.norm(Arob)) # print 'get expmats: ||A|| = {0}'.format(spsla.norm(stokesmatsc['A'])) # raise Warning('TODO: debug') soldict.update( fv=fv, fp=fp, N=N, nu=nu, clearprvdata=~use_old_data, get_datastring=None, data_prfx=ddir + data_prfx + "_stst", paraviewoutput=False, ) if bccontrol and linear_system: soldict.update(A=Arob) # compute the uncontrolled steady state Navier-Stokes solution vp_ss_nse, list_norm_nwtnupd = snu.solve_steadystate_nse(return_vp=True, **soldict) v_ss_nse, p_ss_nse = vp_ss_nse[:NV], vp_ss_nse[NV:] # specify in what spatial direction Bu changes. The remaining is constant if problemname == "drivencavity": uspacedep = 0 elif problemname == "cylinderwake": uspacedep = 1 # # Control mats # contsetupstr = problemname + "__NV{0}NU{1}NY{2}".format(NV, NU, NY) # get the control and observation operators try: b_mat = dou.load_spa(ddir + contsetupstr + "__b_mat") u_masmat = dou.load_spa(ddir + contsetupstr + "__u_masmat") print "loaded `b_mat`" except IOError: print "computing `b_mat`..." b_mat, u_masmat = cou.get_inp_opa(cdcoo=femp["cdcoo"], V=femp["V"], NU=NU, xcomp=uspacedep) dou.save_spa(b_mat, ddir + contsetupstr + "__b_mat") dou.save_spa(u_masmat, ddir + contsetupstr + "__u_masmat") try: mc_mat = dou.load_spa(ddir + contsetupstr + "__mc_mat") y_masmat = dou.load_spa(ddir + contsetupstr + "__y_masmat") print "loaded `c_mat`" except IOError: print "computing `c_mat`..." mc_mat, y_masmat = cou.get_mout_opa(odcoo=femp["odcoo"], V=femp["V"], NY=NY) dou.save_spa(mc_mat, ddir + contsetupstr + "__mc_mat") dou.save_spa(y_masmat, ddir + contsetupstr + "__y_masmat") # restrict the operators to the inner nodes mc_mat = mc_mat[:, invinds][:, :] b_mat = b_mat[invinds, :][:, :] c_mat = lau.apply_massinv(y_masmat, mc_mat, output="sparse") # TODO: right choice of norms for y # and necessity of regularization here # by now, we go on number save # the pressure observation mean over a small domain if problemname == "cylinderwake": podcoo = dict(xmin=0.6, xmax=0.64, ymin=0.18, ymax=0.22) elif problemname == "drivencavity": podcoo = dict(xmin=0.45, xmax=0.55, ymin=0.7, ymax=0.8) else: podcoo = femp["odcoo"] # description of the control and observation domains dmd = femp["cdcoo"] xmin, xmax, ymin, ymax = dmd["xmin"], dmd["xmax"], dmd["ymin"], dmd["ymax"] velcondomstr = "vel control domain: [{0}, {1}]x[{2}, {3}]\n".format(xmin, xmax, ymin, ymax) dmd = femp["odcoo"] xmin, xmax, ymin, ymax = dmd["xmin"], dmd["xmax"], dmd["ymin"], dmd["ymax"] velobsdomstr = "vel observation domain: [{0}, {1}]x[{2}, {3}]\n".format(xmin, xmax, ymin, ymax) dmd = podcoo xmin, xmax, ymin, ymax = dmd["xmin"], dmd["xmax"], dmd["ymin"], dmd["ymax"] pobsdomstr = "pressure observation domain: [{0}, {1}]x[{2}, {3}]\n".format(xmin, xmax, ymin, ymax) pcmat = cou.get_pavrg_onsubd(odcoo=podcoo, Q=femp["Q"], ppin=None) cdatstr = snu.get_datastr_snu(time=None, meshp=N, nu=nu, Nts=None) (coors, xinds, yinds, corfunvec) = dts.get_dof_coors(femp["V"], invinds=invinds) ctrl_visu_str = ( " the (distributed) control setup is as follows \n" + " B maps into the domain of control -" + velcondomstr + " the first half of the columns" + "actuate in x-direction, the second in y direction \n" + " Cv measures averaged velocities in the domain of observation" + velobsdomstr + " Cp measures the averaged pressure" + " in the domain of pressure observation: " + pobsdomstr + " the first components are in x, the last in y-direction \n\n" + " Visualization: \n\n" + " `coors` -- array of (x,y) coordinates in " + " the same order as v[xinds] or v[yinds] \n" + " `xinds`, `yinds` -- indices of x and y components" + " of v = [vx, vy] -- note that indexing starts with 0\n" + " for testing use corfunvec wich is the interpolant of\n" + " f(x,y) = [x, y] on the grid \n\n" + "Created in `get_exp_nsmats.py` " + "(see https://github.com/highlando/dolfin_navier_scipy) at\n" + datetime.datetime.now().strftime("%I:%M%p on %B %d, %Y") ) if bccontrol and problemname == "cylinderwake" and linear_system: ctrl_visu_str = ( "the boundary control is realized via penalized robin \n" + "boundary conditions, cf. e.g. [Hou/Ravindran `98], \n" + "with predefined shape functions for the cylinder wake \n" + "and the penalization parameter `palpha`={0}." ).format(palpha) + ctrl_visu_str if linear_system: convc_mat, rhs_con, rhsv_conbc = snu.get_v_conv_conts( prev_v=v_ss_nse, invinds=invinds, V=femp["V"], diribcs=femp["diribcs"] ) # TODO: omg if bccontrol: f_mat = -Arob - convc_mat else: f_mat = -stokesmatsc["A"] - convc_mat infostr = ( "These are the coefficient matrices of the linearized " + "Navier-Stokes Equations \n for the " + problemname + " to be used as \n\n" + " $M \\dot v = Av + J^Tp + Bu$ and $Jv = 0$ \n\n" + " the Reynoldsnumber is computed as L/nu \n" + " Note this is the reduced system for the velocity update\n" + " caused by the control, i.e., no boundary conditions\n" + " or inhomogeneities here. To get the actual flow, superpose \n" + " the steadystate velocity solution `v_ss_nse` \n\n" + ctrl_visu_str ) matstr = (mddir + problemname + "__mats_N{0}_Re{1}").format(NV, Re) if bccontrol: matstr = matstr + "__penarob_palpha{0}".format(palpha) scipy.io.savemat( matstr, dict( A=f_mat, M=stokesmatsc["M"], nu=femp["nu"], Re=femp["Re"], J=stokesmatsc["J"], B=b_mat, C=c_mat, Cp=pcmat, Brob=Brob, v_ss_nse=v_ss_nse, info=infostr, contsetupstr=contsetupstr, datastr=cdatstr, coors=coors, xinds=xinds, yinds=yinds, corfunvec=corfunvec, ), ) print ("matrices saved to " + matstr) elif refree: hstr = ddir + problemname + "_N{0}_hmat".format(N) try: hmat = dou.load_spa(hstr) print "loaded `hmat`" except IOError: print "assembling hmat ..." hmat = dts.ass_convmat_asmatquad(W=femp["V"], invindsw=invinds) dou.save_spa(hmat, hstr) zerv = np.zeros((NV, 1)) bc_conv, bc_rhs_conv, rhsbc_convbc = snu.get_v_conv_conts( prev_v=zerv, V=femp["V"], invinds=invinds, diribcs=femp["diribcs"], Picard=False ) # diff_mat = stokesmatsc['A'] # bcconv_mat = bc_conv # fv_bcdiff = fv_stbc # fv_bcconv = - bc_rhs_conv fv = fvc fp = fpc # fp_bc = fp_stbc infostr = ( "These are the coefficient matrices of the quadratic " + "formulation of the Navier-Stokes Equations \n for the " + problemname + " to be used as \n\n" + " $M \\dot v + Av + H*kron(v,v) + J^Tp = Bu + fv$ \n" + " and $Jv = fp$ \n\n" + " the Reynoldsnumber is computed as L/nu \n" + " note that `A` contains the diffusion and the linear term \n" + " that comes from the dirichlet boundary values \n" + " as initial value one can use the provided steady state \n" + " Stokes solution \n" + " see https://github.com/highlando/dolfin_navier_scipy/blob/" + " master/tests/solve_nse_quadraticterm.py for appl example\n" + ctrl_visu_str ) scipy.io.savemat( mddir + problemname + "quadform__mats_N{0}_Re{1}".format(NV, Re), dict( A=f_mat, M=stokesmatsc["M"], H=-hmat, fv=fv, fp=fp, nu=femp["nu"], Re=femp["Re"], J=stokesmatsc["J"], B=b_mat, Cv=c_mat, Cp=pcmat, info=infostr, # ss_stokes=old_v, contsetupstr=contsetupstr, datastr=cdatstr, coors=coors, xinds=xinds, yinds=yinds, corfunvec=corfunvec, ), ) else: hstr = ddir + problemname + "_N{0}_hmat".format(N) try: hmat = dou.load_spa(hstr) print "loaded `hmat`" except IOError: print "assembling hmat ..." hmat = dts.ass_convmat_asmatquad(W=femp["V"], invindsw=invinds) dou.save_spa(hmat, hstr) zerv = np.zeros((NV, 1)) bc_conv, bc_rhs_conv, rhsbc_convbc = snu.get_v_conv_conts( prev_v=zerv, V=femp["V"], invinds=invinds, diribcs=femp["diribcs"], Picard=False ) f_mat = -stokesmatsc["A"] - bc_conv l_mat = -bc_conv fv = fv_stbc + fvc - bc_rhs_conv fp = fp_stbc + fpc vp_stokes = lau.solve_sadpnt_smw(amat=A, jmat=J, rhsv=fv_stbc + fvc, rhsp=fp_stbc + fpc) old_v = vp_stokes[:NV] p_stokes = -vp_stokes[NV:] # the pressure was flipped for symmetry infostr = ( "These are the coefficient matrices of the quadratic " + "formulation of the Navier-Stokes Equations \n for the " + problemname + " to be used as \n\n" + " $M \\dot v = Av + H*kron(v,v) + J^Tp + Bu + fv$ \n" + " and $Jv = fp$ \n\n" + " the Reynoldsnumber is computed as L/nu \n" + " note that `A` contains the diffusion and the linear term `L`\n" + " that comes from the dirichlet boundary values \n" + " for linearizations it might be necessary to consider `A-L` \n" + " as initial value one can use the provided steady state \n" + " Stokes solution \n" + " see https://github.com/highlando/dolfin_navier_scipy/blob/" + " master/tests/solve_nse_quadraticterm.py for appl example\n" + ctrl_visu_str ) scipy.io.savemat( mddir + problemname + "quadform__mats_N{0}_Re{1}".format(NV, Re), dict( A=f_mat, M=stokesmatsc["M"], H=-hmat, fv=fv, fp=fp, L=l_mat, nu=femp["nu"], Re=femp["Re"], J=stokesmatsc["J"], B=b_mat, Cv=c_mat, Cp=pcmat, info=infostr, p_ss_stokes=p_stokes, p_ss_nse=p_ss_nse, v_ss_stokes=old_v, v_ss_nse=v_ss_nse, contsetupstr=contsetupstr, datastr=cdatstr, coors=coors, xinds=xinds, yinds=yinds, corfunvec=corfunvec, ), )
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, 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
def optcon_nse(problemname='drivencavity', N=10, Nts=10, nu=1e-2, clearprvveldata=False, ini_vel_stokes=False, stst_control=False, closed_loop=True, outernwtnstps=1, t0=None, tE=None, use_ric_ini_nu=None, alphau=1e-9, gamma=1e-3, spec_tip_dict=None, nwtn_adi_dict=None, linearized_nse=False, stokes_flow=False, ystar=None): tip = time_int_params(Nts, t0=t0, tE=tE) if spec_tip_dict is not None: tip.update(spec_tip_dict) if nwtn_adi_dict is not None: tip['nwtn_adi_dict'] = nwtn_adi_dict problemdict = dict(drivencavity=dnsps.drivcav_fems, cylinderwake=dnsps.cyl_fems) problemfem = problemdict[problemname] femp = problemfem(N) # output ddir = 'data/' try: os.chdir(ddir) except OSError: raise Warning('need "' + ddir + '" subdir for storing the data') os.chdir('..') if linearized_nse and not outernwtnstps == 1: raise Warning('Linearized problem can have only one Newton step') if closed_loop: if stst_control: data_prfx = ddir + 'stst_' + problemname + '__' else: data_prfx = ddir + 'tdst_' + problemname + '__' else: data_prfx = ddir + problemname + '__' if stokes_flow: data_prfx = data_prfx + 'stokes__' # specify in what spatial direction Bu changes. The remaining is constant if problemname == 'drivencavity': uspacedep = 0 elif problemname == 'cylinderwake': uspacedep = 1 stokesmats = dts.get_stokessysmats(femp['V'], femp['Q'], nu) rhsd_vf = dts.setget_rhs(femp['V'], femp['Q'], femp['fv'], femp['fp'], t=0) # remove the freedom in the pressure stokesmats['J'] = stokesmats['J'][:-1, :][:, :] stokesmats['JT'] = stokesmats['JT'][:, :-1][:, :] rhsd_vf['fp'] = rhsd_vf['fp'][:-1, :] # reduce the matrices by resolving the BCs (stokesmatsc, rhsd_stbc, invinds, bcinds, bcvals) = dts.condense_sysmatsbybcs(stokesmats, femp['diribcs']) print 'Dimension of the div matrix: ', stokesmatsc['J'].shape # pressure freedom and dirichlet reduced rhs rhsd_vfrc = dict(fpr=rhsd_vf['fp'], fvc=rhsd_vf['fv'][invinds, ]) # add the info on boundary and inner nodes bcdata = {'bcinds': bcinds, 'bcvals': bcvals, 'invinds': invinds} femp.update(bcdata) # casting some parameters NV = len(femp['invinds']) soldict = stokesmatsc # containing A, J, JT soldict.update(femp) # adding V, Q, invinds, diribcs # soldict.update(rhsd_vfrc) # adding fvc, fpr soldict.update(fv=rhsd_stbc['fv']+rhsd_vfrc['fvc'], fp=rhsd_stbc['fp']+rhsd_vfrc['fpr'], N=N, nu=nu, trange=tip['tmesh'], get_datastring=get_datastr, data_prfx=data_prfx, clearprvdata=clearprvveldata, paraviewoutput=tip['ParaviewOutput'], vfileprfx=tip['proutdir']+'vel_', pfileprfx=tip['proutdir']+'p_') # # Prepare for control # contp = ContParams(femp['odcoo'], ystar=ystar, alphau=alphau, gamma=gamma) # casting some parameters NY, NU = contp.NY, contp.NU contsetupstr = problemname + '__NV{0}NU{1}NY{2}'.format(NV, NU, NY) # get the control and observation operators try: b_mat = dou.load_spa(ddir + contsetupstr + '__b_mat') u_masmat = dou.load_spa(ddir + contsetupstr + '__u_masmat') print 'loaded `b_mat`' except IOError: print 'computing `b_mat`...' b_mat, u_masmat = cou.get_inp_opa(cdcoo=femp['cdcoo'], V=femp['V'], NU=NU, xcomp=uspacedep) dou.save_spa(b_mat, ddir + contsetupstr + '__b_mat') dou.save_spa(u_masmat, ddir + contsetupstr + '__u_masmat') try: mc_mat = dou.load_spa(ddir + contsetupstr + '__mc_mat') y_masmat = dou.load_spa(ddir + contsetupstr + '__y_masmat') print 'loaded `c_mat`' except IOError: print 'computing `c_mat`...' mc_mat, y_masmat = cou.get_mout_opa(odcoo=femp['odcoo'], V=femp['V'], NY=NY) dou.save_spa(mc_mat, ddir + contsetupstr + '__mc_mat') dou.save_spa(y_masmat, ddir + contsetupstr + '__y_masmat') # restrict the operators to the inner nodes mc_mat = mc_mat[:, invinds][:, :] b_mat = b_mat[invinds, :][:, :] # for further use: c_mat = lau.apply_massinv(y_masmat, mc_mat, output='sparse') if contp.ystarx is None: c_mat = c_mat[NY:, :][:, :] # TODO: Do this right mc_mat = mc_mat[NY:, :][:, :] # TODO: Do this right y_masmat = y_masmat[:NY, :][:, :NY] # TODO: Do this right mct_mat_reg = lau.app_prj_via_sadpnt(amat=stokesmatsc['M'], jmat=stokesmatsc['J'], rhsv=mc_mat.T, transposedprj=True) # set the weighing matrices contp.R = contp.alphau * u_masmat # # solve the differential-alg. Riccati eqn for the feedback gain X # via computing factors Z, such that X = -Z*Z.T # # at the same time we solve for the affine-linear correction w # # tilde B = BR^{-1/2} tb_mat = lau.apply_invsqrt_fromright(contp.R, b_mat, output='sparse') # tb_dense = np.array(tb_mat.todense()) trct_mat = lau.apply_invsqrt_fromright(y_masmat, mct_mat_reg, output='dense') if closed_loop: cntpstr = 'NV{3}NY{0}NU{1}alphau{2}gamma{4}'.\ format(contp.NU, contp.NY, contp.alphau, NV, contp.gamma) else: cntpstr = '' # we gonna use this quite often M, A = stokesmatsc['M'], stokesmatsc['A'] datastrdict = dict(time=None, meshp=N, nu=nu, Nts=Nts, data_prfx=data_prfx) # compute the uncontrolled steady state (Navier-)Stokes solution # as initial value if ini_vel_stokes: # compute the uncontrolled steady state Stokes solution ini_vel, newtonnorms = snu.solve_steadystate_nse(vel_nwtn_stps=0, vel_pcrd_stps=0, **soldict) soldict.update(dict(iniv=ini_vel)) else: ini_vel, newtonnorms = snu.solve_steadystate_nse(**soldict) soldict.update(dict(iniv=ini_vel)) if closed_loop: if stst_control: if stokes_flow: convc_mat = sps.csr_matrix((NV, NV)) rhs_con, rhsv_conbc = np.zeros((NV, 1)), np.zeros((NV, 1)) lin_point = None else: lin_point, newtonnorms = snu.solve_steadystate_nse(**soldict) (convc_mat, rhs_con, rhsv_conbc) = snu.get_v_conv_conts(prev_v=lin_point, invinds=invinds, V=femp['V'], diribcs=femp['diribcs']) # infinite control horizon, steady target state cdatstr = get_datastr(time=None, meshp=N, nu=nu, Nts=None, data_prfx=data_prfx) try: Z = dou.load_npa(cdatstr + cntpstr + '__Z') print 'loaded ' + cdatstr + cntpstr + '__Z' except IOError: if use_ric_ini_nu is not None: cdatstr = get_datastr(nwtn=None, time=None, meshp=N, nu=use_ric_ini_nu, Nts=None, data_prfx=data_prfx) try: zini = dou.load_npa(ddir + cdatstr + cntpstr + '__Z') print 'Initialize Newton ADI by Z from ' + cdatstr except IOError: raise Warning('No data for initialization of ' ' Newton ADI -- need ' + cdatstr + '__Z') cdatstr = get_datastr(meshp=N, nu=nu, data_prfx=data_prfx) else: zini = None parnadi = pru.proj_alg_ric_newtonadi Z = parnadi(mmat=M, amat=-A-convc_mat, jmat=stokesmatsc['J'], bmat=tb_mat, wmat=trct_mat, z0=zini, nwtn_adi_dict=tip['nwtn_adi_dict'])['zfac'] dou.save_npa(Z, fstring=cdatstr + cntpstr + '__Z') print 'saved ' + cdatstr + cntpstr + '__Z' if tip['compress_z']: Zc = pru.compress_Zsvd(Z, thresh=tip['comprz_thresh'], k=tip['comprz_maxc']) Z = Zc fvnstst = rhs_con + rhsv_conbc + rhsd_stbc['fv'] + rhsd_vfrc['fvc'] # X = -ZZ.T mtxtb_stst = -pru.get_mTzzTtb(M.T, Z, tb_mat) mtxfv_stst = -pru.get_mTzzTtb(M.T, Z, fvnstst) fl = mc_mat.T * contp.ystarvec(0) wft = lau.solve_sadpnt_smw(amat=A.T+convc_mat.T, jmat=stokesmatsc['J'], rhsv=fl+mtxfv_stst, umat=mtxtb_stst, vmat=tb_mat.T)[:NV] auxstrg = cdatstr + cntpstr dou.save_npa(wft, fstring=cdatstr + cntpstr + '__w') dou.save_npa(mtxtb_stst, fstring=cdatstr + cntpstr + '__mtxtb') feedbackthroughdict = {None: dict(w=auxstrg + '__w', mtxtb=auxstrg + '__mtxtb')} cns = 0 soldict.update(data_prfx=data_prfx+'_cns{0}'.format(cns)) if linearized_nse: soldict.update(vel_pcrd_stps=0, vel_nwtn_stps=1, lin_vel_point={None: lin_point}) dictofvels = snu.\ solve_nse(return_dictofvelstrs=True, closed_loop=True, static_feedback=True, tb_mat=tb_mat, stokes_flow=stokes_flow, clearprvveldata=True, feedbackthroughdict=feedbackthroughdict, **soldict) else: # time dep closed loop cns_data_prfx = 'data/cnsvars' invd = init_nwtnstps_value_dict curnwtnsdict = invd(tmesh=tip['tmesh'], data_prfx=cns_data_prfx) # initialization: compute the forward solution if stokes_flow: dictofvels = None else: dictofvels = snu.solve_nse(return_dictofvelstrs=True, stokes_flow=stokes_flow, **soldict) # dbs.plot_vel_norms(tip['tmesh'], dictofvels) # function for the time depending parts # -- to be passed to the solver def get_tdpart(time=None, dictofvalues=None, feedback=False, V=None, invinds=None, diribcs=None, **kw): if stokes_flow: convc_mat = sps.csr_matrix((NV, NV)) rhs_con, rhsv_conbc = np.zeros((NV, 1)), np.zeros((NV, 1)) else: curvel = dou.load_npa(dictofvalues[time]) convc_mat, rhs_con, rhsv_conbc = \ snu.get_v_conv_conts(prev_v=curvel, invinds=invinds, V=V, diribcs=diribcs) return convc_mat, rhsv_conbc+rhs_con gttdprtargs = dict(dictofvalues=dictofvels, V=femp['V'], diribcs=femp['diribcs'], invinds=invinds) # old version rhs # ftilde = rhs_con + rhsv_conbc + rhsd_stbc['fv'] for cns in range(outernwtnstps): datastrdict.update(data_prfx=data_prfx+cntpstr+'_cns{0}'. format(cns)) soldict.update(data_prfx=data_prfx+cntpstr+'_cns{0}'. format(cns)) sfd = sdr.solve_flow_daeric feedbackthroughdict = \ sfd(mmat=M, amat=A, jmat=stokesmatsc['J'], bmat=b_mat, # cmat=ct_mat_reg.T, mcmat=mct_mat_reg.T, v_is_my=True, rmat=contp.alphau*u_masmat, vmat=y_masmat, rhsv=rhsd_stbc['fv'], gamma=contp.gamma, rhsp=None, tmesh=tip['tmesh'], ystarvec=contp.ystarvec, nwtn_adi_dict=tip['nwtn_adi_dict'], comprz_thresh=tip['comprz_thresh'], comprz_maxc=tip['comprz_maxc'], save_full_z=False, get_tdpart=get_tdpart, gttdprtargs=gttdprtargs, curnwtnsdict=curnwtnsdict, get_datastr=get_datastr, gtdtstrargs=datastrdict) # for t in tip['tmesh']: # feedbackthroughdict.keys(): # curw = dou.load_npa(feedbackthroughdict[t]['mtxtb']) # print cns, t, np.linalg.norm(curw) cdatstr = get_datastr(time='all', meshp=N, nu=nu, Nts=None, data_prfx=data_prfx) if linearized_nse: dictofvels = snu.\ solve_nse(return_dictofvelstrs=True, closed_loop=True, tb_mat=tb_mat, lin_vel_point=dictofvels, feedbackthroughdict=feedbackthroughdict, vel_nwtn_stps=1, vel_pcrd_stps=0, **soldict) else: dictofvels = snu.\ solve_nse(return_dictofvelstrs=True, closed_loop=True, tb_mat=tb_mat, stokes_flow=stokes_flow, feedbackthroughdict=feedbackthroughdict, vel_pcrd_stps=1, vel_nwtn_stps=2, **soldict) # for t in dictofvels.keys(): # curw = dou.load_npa(dictofvels[t]) # print cns, t, np.linalg.norm(curw) gttdprtargs.update(dictofvalues=dictofvels) else: # no control feedbackthroughdict = None tb_mat = None cdatstr = get_datastr(meshp=N, nu=nu, time='all', Nts=Nts, data_prfx=data_prfx) soldict.update(clearprvdata=True) dictofvels = snu.solve_nse(feedbackthroughdict=feedbackthroughdict, tb_mat=tb_mat, closed_loop=closed_loop, stokes_flow=stokes_flow, return_dictofvelstrs=True, static_feedback=stst_control, **soldict) (yscomplist, ystarlist) = dou.extract_output(dictofpaths=dictofvels, tmesh=tip['tmesh'], c_mat=c_mat, ystarvec=contp.ystarvec) save_output_json(yscomplist, tip['tmesh'].tolist(), ystar=ystarlist, fstring=cdatstr + cntpstr + '__sigout') costfunval = eval_costfunc(W=y_masmat, V=contp.gamma*y_masmat, R=None, tbmat=tb_mat, cmat=c_mat, ystar=contp.ystarvec, tmesh=tip['tmesh'], veldict=dictofvels, fbftdict=feedbackthroughdict) print 'Value of cost functional: ', costfunval costfunval = eval_costfunc(W=y_masmat, V=contp.gamma*y_masmat, R=None, tbmat=tb_mat, cmat=c_mat, ystar=contp.ystarvec, penau=False, tmesh=tip['tmesh'], veldict=dictofvels, fbftdict=feedbackthroughdict) print 'Value of cost functional not considering `u`: ', costfunval print 'dim of v :', femp['V'].dim() charlene = .15 if problemname == 'cylinderwake' else 1.0 print 'Re = charL / nu = {0}'.format(charlene/nu)
def test_qbdae_ass(problemname='cylinderwake', N=1, Re=None, nu=3e-2, t0=0.0, tE=1.0, Nts=100, use_saved_mats=None): trange = np.linspace(t0, tE, Nts+1) DT = (tE-t0)/Nts rdir = 'results/' ddir = 'data/' if use_saved_mats is None: femp, stokesmatsc, rhsd_vfrc, rhsd_stbc = \ dns.problem_setups.get_sysmats(problem=problemname, N=N, Re=Re) invinds = femp['invinds'] A, J, M = stokesmatsc['A'], stokesmatsc['J'], stokesmatsc['M'] L = 0*A fvc, fpc = rhsd_vfrc['fvc'], rhsd_vfrc['fpr'] fv_stbc, fp_stbc = rhsd_stbc['fv'], rhsd_stbc['fp'] hstr = ddir + problemname + '_N{0}_hmat'.format(N) try: hmat = dou.load_spa(hstr) print('loaded `hmat`') except IOError: print('assembling hmat ...') hmat = dnsts.ass_convmat_asmatquad(W=femp['V'], invindsw=invinds) dou.save_spa(hmat, hstr) invinds = femp['invinds'] NV, NP = invinds.shape[0], J.shape[0] zerv = np.zeros((NV, 1)) bc_conv, bc_rhs_conv, rhsbc_convbc = \ snu.get_v_conv_conts(prev_v=zerv, V=femp['V'], invinds=invinds, diribcs=femp['diribcs'], Picard=False) fp = fp_stbc + fpc fv = fv_stbc + fvc - bc_rhs_conv if linnsesol: vp_nse, _ = snu.\ solve_steadystate_nse(A=A, J=J, JT=None, M=M, fv=fv_stbc + fvc, fp=fp_stbc + fpc, V=femp['V'], Q=femp['Q'], invinds=invinds, diribcs=femp['diribcs'], return_vp=False, ppin=-1, N=N, nu=nu, clearprvdata=False) old_v = vp_nse[:NV] else: import sadptprj_riclyap_adi.lin_alg_utils as lau # Stokes solution as initial value vp_stokes = lau.solve_sadpnt_smw(amat=A, jmat=J, rhsv=fv_stbc + fvc, rhsp=fp_stbc + fpc) old_v = vp_stokes[:NV] sysmat = sps.vstack([sps.hstack([M+DT*(A+bc_conv), J.T]), sps.hstack([J, sps.csc_matrix((NP, NP))])]) if use_saved_mats is not None: # if saved as in ../get_exp_mats import scipy.io mats = scipy.io.loadmat(use_saved_mats) A = - mats['A'] L = - mats['L'] Re = mats['Re'] N = A.shape[0] M = mats['M'] J = mats['J'] hmat = -mats['H'] fv = mats['fv'] fp = mats['fp'] NV, NP = fv.shape[0], fp.shape[0] old_v = mats['ss_stokes'] sysmat = sps.vstack([sps.hstack([M+DT*A, J.T]), sps.hstack([J, sps.csc_matrix((NP, NP))])]) if compevs: import matplotlib.pyplot as plt import scipy.linalg as spla hlstr = ddir + problemname + '_N{0}_Re{1}Nse{2}_hlmat'.\ format(N, Re, linnsesol) HL = linearzd_quadterm(hmat, old_v, hlstr=hlstr) print(HL.shape) asysmat = sps.vstack([sps.hstack([-(A-L+HL), J.T]), sps.hstack([J, sps.csc_matrix((NP, NP))])]) msysmat = sps.vstack([sps.hstack([M, sps.csc_matrix((NV, NP))]), sps.hstack([sps.csc_matrix((NP, NV)), sps.csc_matrix((NP, NP))])]) levstr = ddir + problemname + '_N{0}Re{1}Nse{2}_levs'.\ format(N, Re, linnsesol) try: levs = dou.load_npa(levstr) if debug: raise IOError() print('loaded the eigenvalues of the linearized system') except IOError: print('computing the eigenvalues of the linearized system') A = asysmat.todense() M = msysmat.todense() levs = spla.eigvals(A, M, overwrite_a=True, check_finite=False) dou.save_npa(levs, levstr) plt.figure(1) # plt.xlim((-25, 15)) # plt.ylim((-50, 50)) plt.plot(np.real(levs), np.imag(levs), '+') plt.show(block=False) if timeint: print('computing LU once...') sysmati = spsla.factorized(sysmat) vfile = dolfin.File(rdir + problemname + 'qdae__vel.pvd') pfile = dolfin.File(rdir + problemname + 'qdae__p.pvd') prvoutdict = dict(V=femp['V'], Q=femp['Q'], vfile=vfile, pfile=pfile, invinds=invinds, diribcs=femp['diribcs'], vp=None, t=None, writeoutput=True) print('doing the time loop...') for t in trange: crhsv = M*old_v + DT*(fv - hmat*np.kron(old_v, old_v)) crhs = np.vstack([crhsv, fp]) vp_new = np.atleast_2d(sysmati(crhs.flatten())).T prvoutdict.update(dict(vp=vp_new, t=t)) dou.output_paraview(**prvoutdict) old_v = vp_new[:NV] print(t, np.linalg.norm(old_v))
def solve_steadystate_nse(A=None, J=None, JT=None, M=None, fv=None, fp=None, V=None, Q=None, invinds=None, diribcs=None, dbcvals=None, dbcinds=None, diricontbcinds=None, diricontbcvals=None, diricontfuncs=None, return_vp=False, ppin=-1, return_nwtnupd_norms=False, N=None, nu=None, vel_pcrd_stps=10, vel_pcrd_tol=1e-4, vel_nwtn_stps=20, vel_nwtn_tol=5e-15, clearprvdata=False, useolddata=False, vel_start_nwtn=None, get_datastring=None, data_prfx='', paraviewoutput=False, save_data=True, save_intermediate_steps=False, vfileprfx='', pfileprfx='', verbose=True, **kw): """ Solution of the steady state nonlinear NSE Problem using Newton's scheme. If no starting value is provided, the iteration is started with the steady state Stokes solution. Parameters ---------- A : (N,N) sparse matrix stiffness matrix aka discrete Laplacian, note the sign! M : (N,N) sparse matrix mass matrix J : (M,N) sparse matrix discrete divergence operator JT : (N,M) sparse matrix, optional discrete gradient operator, set to J.T if not provided fv, fp : (N,1), (M,1) ndarrays right hand sides restricted via removing the boundary nodes in the momentum and the pressure freedom in the continuity equation ppin : {int, None}, optional which dof of `p` is used to pin the pressure, defaults to `-1` dbcinds: list, optional indices of the Dirichlet boundary conditions dbcvals: list, optional values of the Dirichlet boundary conditions (as listed in `dbcinds`) diricontbcinds: list, optional list of dirichlet indices that are to be controlled diricontbcvals: list, optional list of the vals corresponding to `diricontbcinds` diricontfuncs: list, optional list like `[ufunc]` where `ufunc: (t, v) -> u` where `u` is used to scale the corresponding `diricontbcvals` return_vp : boolean, optional whether to return also the pressure, defaults to `False` vel_pcrd_stps : int, optional Number of Picard iterations when computing a starting value for the Newton scheme, cf. Elman, Silvester, Wathen: *FEM and fast iterative solvers*, 2005, defaults to `100` vel_pcrd_tol : real, optional tolerance for the size of the Picard update, defaults to `1e-4` vel_nwtn_stps : int, optional Number of Newton iterations, defaults to `20` vel_nwtn_tol : real, optional tolerance for the size of the Newton update, defaults to `5e-15` Returns: --- vel_k : (N, 1) ndarray the velocity vector, if not `return_vp`, else (v, p) : tuple of the velocity and the pressure vector norm_nwtnupd_list : list, on demand list of the newton upd errors """ import sadptprj_riclyap_adi.lin_alg_utils as lau if get_datastring is None: get_datastring = get_datastr_snu if JT is None: JT = J.T NV = J.shape[1] # # Compute or load the uncontrolled steady state Navier-Stokes solution # norm_nwtnupd_list = [] # a dict to be passed to the get_datastring function datastrdict = dict(time=None, meshp=N, nu=nu, Nts=None, data_prfx=data_prfx) if clearprvdata: cdatstr = get_datastring(**datastrdict) for fname in glob.glob(cdatstr + '*__vel*'): os.remove(fname) if useolddata: try: cdatstr = get_datastring(**datastrdict) norm_nwtnupd = dou.load_npa(cdatstr + '__norm_nwtnupd') vel_k = dou.load_npa(cdatstr + '__vel') norm_nwtnupd_list.append(norm_nwtnupd) if verbose: print('found vel files') print('norm of last Nwtn update: {0}'.format(norm_nwtnupd)) print('... loaded from ' + cdatstr) if np.atleast_1d(norm_nwtnupd)[0] is None: norm_nwtnupd = None pass # nothing useful found elif norm_nwtnupd < vel_nwtn_tol: if not return_vp: return vel_k, norm_nwtnupd_list else: pfv = get_pfromv(v=vel_k[:NV, :], V=V, M=M, A=A, J=J, fv=fv, dbcinds=dbcinds, dbcvals=dbcvals, invinds=invinds, diribcs=diribcs) return (np.vstack([vel_k, pfv]), norm_nwtnupd_list) except IOError: if verbose: print('no old velocity data found') norm_nwtnupd = None else: # we start from scratch norm_nwtnupd = None if paraviewoutput: cdatstr = get_datastring(**datastrdict) vfile = dolfin.File(vfileprfx+'__steadystates.pvd') pfile = dolfin.File(pfileprfx+'__steadystates.pvd') prvoutdict = dict(V=V, Q=Q, vfile=vfile, pfile=pfile, invinds=invinds, diribcs=diribcs, ppin=ppin, dbcinds=dbcinds, dbcvals=dbcvals, vp=None, t=None, writeoutput=True) else: prvoutdict = dict(writeoutput=False) # save 'if statements' later NV = A.shape[0] if vel_start_nwtn is None: loccntbcinds, cntrlldbcvals, glbcntbcinds = [], [], [] if diricontbcinds is None or diricontbcinds == []: cmmat, camat, cj, cjt, cfv, cfp = M, A, J, JT, fv, fp cnv = NV dbcntinvinds = invinds else: def _localizecdbinds(cdbinds): """ find the local indices of the control dirichlet boundaries the given control dirichlet boundaries were indexed w.r.t. the full space `V`. Here, in the matrices, we have already resolved the constant Dirichlet bcs """ allinds = np.arange(V.dim()) redcdallinds = allinds[invinds] # now: find the positions of the control dbcs in the reduced # index vector lclinds = np.searchsorted(redcdallinds, cdbinds, side='left') return lclinds for k, cdbidbv in enumerate(diricontbcinds): ccntrlfunc = diricontfuncs[k] # no time at steady state, no starting value cntrlval = ccntrlfunc(None, None) localbcinds = (_localizecdbinds(cdbidbv)).tolist() loccntbcinds.extend(localbcinds) # adding the boundary inds glbcntbcinds.extend(cdbidbv) ccntrlldbcvals = [cntrlval*bcvl for bcvl in diricontbcvals[k]] # adding the scaled boundary values cntrlldbcvals.extend(ccntrlldbcvals) dbcntinvinds = np.setdiff1d(invinds, glbcntbcinds).astype(np.int32) matdict = dict(M=M, A=A, J=J, JT=JT, MP=None) cmmat, camat, cjt, cj, _, cfv, cfp, _ = dts.\ condense_sysmatsbybcs(matdict, dbcinds=loccntbcinds, dbcvals=cntrlldbcvals, mergerhs=True, rhsdict=dict(fv=fv, fp=fp), ret_unrolled=True) cnv = cmmat.shape[0] vp_stokes = lau.solve_sadpnt_smw(amat=camat, jmat=cj, jmatT=cjt, rhsv=cfv, rhsp=cfp) vp_stokes[cnv:] = -vp_stokes[cnv:] # pressure was flipped for symmetry # save the data cdatstr = get_datastring(**datastrdict) if save_data: dou.save_npa(vp_stokes[:cnv, ], fstring=cdatstr + '__vel') prvoutdict.update(dict(vp=vp_stokes, dbcinds=[dbcinds, glbcntbcinds], dbcvals=[dbcvals, cntrlldbcvals], invinds=dbcntinvinds)) dou.output_paraview(**prvoutdict) # Stokes solution as starting value vp_k = vp_stokes vel_k = vp_stokes[:cnv, ] else: vel_k = vel_start_nwtn matdict = dict(M=M, A=A, J=J, JT=JT, MP=None) rhsdict = dict(fv=fv, fp=fp) cndnsmtsdct = dict(dbcinds=loccntbcinds, mergerhs=True, ret_unrolled=True) # Picard iterations for a good starting value for Newton for k in range(vel_pcrd_stps): cntrlldbcvals = _unroll_cntrl_dbcs(diricontbcvals, diricontfuncs, time=None, vel=vel_k) (convc_mat, rhs_con, rhsv_conbc) = \ get_v_conv_conts(prev_v=vel_k, V=V, diribcs=diribcs, invinds=dbcntinvinds, dbcinds=[dbcinds, glbcntbcinds], dbcvals=[dbcvals, cntrlldbcvals], Picard=True) _, _, _, _, _, cfv, cfp, _ = dts.\ condense_sysmatsbybcs(matdict, dbcvals=cntrlldbcvals, rhsdict=rhsdict, **cndnsmtsdct) vp_k = lau.solve_sadpnt_smw(amat=camat+convc_mat, jmat=cj, jmatT=cjt, rhsv=cfv+rhsv_conbc, rhsp=cfp) # vp_k = lau.solve_sadpnt_smw(amat=A+convc_mat, jmat=J, jmatT=JT, # rhsv=fv+rhsv_conbc, # rhsp=fp) normpicupd = np.sqrt(m_innerproduct(cmmat, vel_k-vp_k[:cnv, ]))[0] if verbose: print('Picard iteration: {0} -- norm of update: {1}'. format(k+1, normpicupd)) vel_k = vp_k[:cnv, ] vp_k[cnv:] = -vp_k[cnv:] # pressure was flipped for symmetry if normpicupd < vel_pcrd_tol: break # Newton iteration for vel_newtk, k in enumerate(range(vel_nwtn_stps)): cdatstr = get_datastring(**datastrdict) cntrlldbcvals = _unroll_cntrl_dbcs(diricontbcvals, diricontfuncs, time=None, vel=vel_k) _, _, _, _, _, cfv, cfp, _ = dts.\ condense_sysmatsbybcs(matdict, dbcvals=cntrlldbcvals, rhsdict=rhsdict, **cndnsmtsdct) (convc_mat, rhs_con, rhsv_conbc) = \ get_v_conv_conts(prev_v=vel_k, V=V, diribcs=diribcs, invinds=dbcntinvinds, dbcinds=[dbcinds, glbcntbcinds], dbcvals=[dbcvals, cntrlldbcvals]) vp_k = lau.solve_sadpnt_smw(amat=camat+convc_mat, jmat=cj, jmatT=cjt, rhsv=cfv+rhs_con+rhsv_conbc, rhsp=cfp) norm_nwtnupd = np.sqrt(m_innerproduct(cmmat, vel_k - vp_k[:cnv, :]))[0] vel_k = vp_k[:cnv, ] vp_k[cnv:] = -vp_k[cnv:] # pressure was flipped for symmetry if verbose: print('Steady State NSE: Newton iteration: {0}'.format(vel_newtk) + '-- norm of update: {0}'.format(norm_nwtnupd)) if save_data: dou.save_npa(vel_k, fstring=cdatstr + '__vel') prvoutdict.update(dict(vp=vp_k, dbcvals=[dbcvals, cntrlldbcvals])) dou.output_paraview(**prvoutdict) if norm_nwtnupd < vel_nwtn_tol: break else: if vel_nwtn_stps == 0: print('No Newton steps = steady state probably not well converged') else: raise UserWarning('Steady State NSE: Newton has not converged') if save_data: dou.save_npa(norm_nwtnupd, cdatstr + '__norm_nwtnupd') prvoutdict.update(dict(vp=vp_k, dbcvals=[dbcvals, cntrlldbcvals])) dou.output_paraview(**prvoutdict) # savetomatlab = True # if savetomatlab: # export_mats_to_matlab(E=None, A=None, matfname='matexport') vwc = _attach_cntbcvals(vel_k.flatten(), globbcinvinds=dbcntinvinds, globbcinds=glbcntbcinds, dbcvals=cntrlldbcvals, invinds=invinds, NV=V.dim()) if return_vp: retthing = (vwc.reshape((NV, 1)), vp_k[cnv:, :]) else: retthing = vwc.reshape((NV, 1)) if return_nwtnupd_norms: return retthing, norm_nwtnupd_list else: return retthing
def compare_freqresp(mmat=None, amat=None, jmat=None, bmat=None, cmat=None, tr=None, tl=None, ahat=None, bhat=None, chat=None, plot=False, datastr=None): """ compare the frequency response of the original and the reduced model cf. [HeiSS08, p. 1059] but with B_2 = 0 Returns ------- freqrel : list of floats the frob norm of the transferfunction at a frequency range red_freqrel : list of floats from of the tf of the reduced model at the same frequencies absci : list of floats frequencies where the tfs are evaluated at """ if ahat is None: ahat = np.dot(tl.T, amat * tr) if bhat is None: bhat = tl.T * bmat if chat is None: chat = cmat * tr NV, red_nv = amat.shape[0], ahat.shape[0] imunit = 1j absci = np.logspace(-4, 8, base=10) freqrel, red_freqrel, diff_freqrel = [], [], [] for omega in absci: sadib = lau.solve_sadpnt_smw(amat=omega * imunit * mmat - amat, jmat=jmat, rhsv=bmat) freqrel.append(np.linalg.norm(cmat * sadib[:NV, :])) # print freqrel[-1] aib = np.linalg.solve(omega * imunit * np.eye(red_nv) - ahat, bhat) red_freqrel.append(np.linalg.norm(np.dot(chat, aib))) diff_freqrel.append( np.linalg.norm(np.dot(chat, aib) - cmat * sadib[:NV, :])) # print red_freqrel[-1] if datastr is not None: dou.save_output_json(dict(tmesh=absci.tolist(), fullsysfr=freqrel, redsysfr=red_freqrel, diffsysfr=diff_freqrel), fstring=datastr + 'forfreqrespplot') if plot: legstr = [ 'NV was {0}'.format(mmat.shape[0]), 'nv is {0}'.format(tr.shape[1]), 'difference' ] fig = plt.figure() ax = fig.add_subplot(111) ax.plot(absci, freqrel, color='b', linewidth=2.0) ax.plot(absci, red_freqrel, color='r', linewidth=2.0) ax.plot(absci, diff_freqrel, color='b', linewidth=1.0) plt.legend(legstr, loc=3) plt.semilogx() plt.semilogy() plt.show(block=False) from matplotlib2tikz import save as tikz_save tikz_save(datastr + 'freqresp.tikz', figureheight='\\figureheight', figurewidth='\\figurewidth') return freqrel, red_freqrel, absci
def comp_exp_nsmats(problemname='drivencavity', N=10, Re=1e2, nu=None, linear_system=False, refree=False, bccontrol=False, palpha=None, use_old_data=False, mddir='pathtodatastorage'): """compute and export the system matrices for Navier-Stokes equations Parameters --- refree : boolean, optional whether to use `Re=1` (so that the `Re` number can be applied later by scaling the corresponding matrices, defaults to `False` linear_system : boolean, optional whether to compute/return the linearized system, defaults to `False` bccontrol : boolean, optional whether to model boundary control at the cylinder via penalized robin boundary conditions, defaults to `False` palpha : float, optional penalization parameter for the boundary control, defaults to `None`, `palpha` is mandatory for `linear_system` """ if refree: Re = 1 print 'For the Reynoldsnumber free mats, we set Re=1' if problemname == 'drivencavity' and bccontrol: raise NotImplementedError('boundary control for the driven cavity' + ' is not implemented yet') if linear_system and bccontrol and palpha is None: raise UserWarning('For the linear system a' + ' value for `palpha` is needed') if not linear_system and bccontrol: raise NotImplementedError('Nonlinear system with boundary control' + ' is not implemented yet') femp, stokesmatsc, rhsd_vfrc, rhsd_stbc = \ dnsps.get_sysmats(problem=problemname, bccontrol=bccontrol, N=N, Re=Re) if linear_system and bccontrol: Arob = stokesmatsc['A'] + 1. / palpha * stokesmatsc['Arob'] Brob = 1. / palpha * stokesmatsc['Brob'] elif linear_system: Brob = 0 invinds = femp['invinds'] A, J = stokesmatsc['A'], stokesmatsc['J'] fvc, fpc = rhsd_vfrc['fvc'], rhsd_vfrc['fpr'] fv_stbc, fp_stbc = rhsd_stbc['fv'], rhsd_stbc['fp'] invinds = femp['invinds'] NV = invinds.shape[0] data_prfx = problemname + '__N{0}Re{1}'.format(N, Re) if bccontrol: data_prfx = data_prfx + '_penarob' soldict = stokesmatsc # containing A, J, JT soldict.update(femp) # adding V, Q, invinds, diribcs soldict.update(rhsd_vfrc) # adding fvc, fpr fv = rhsd_vfrc['fvc'] + rhsd_stbc['fv'] fp = rhsd_vfrc['fpr'] + rhsd_stbc['fp'] # print 'get expmats: ||fv|| = {0}'.format(np.linalg.norm(fv)) # print 'get expmats: ||fp|| = {0}'.format(np.linalg.norm(fp)) # import scipy.sparse.linalg as spsla # print 'get expmats: ||A|| = {0}'.format(spsla.norm(A)) # print 'get expmats: ||Arob|| = {0}'.format(spsla.norm(Arob)) # print 'get expmats: ||A|| = {0}'.format(spsla.norm(stokesmatsc['A'])) # raise Warning('TODO: debug') soldict.update(fv=fv, fp=fp, N=N, nu=nu, clearprvdata=~use_old_data, get_datastring=None, data_prfx=ddir + data_prfx + '_stst', paraviewoutput=False) if bccontrol and linear_system: soldict.update(A=Arob) # compute the uncontrolled steady state Navier-Stokes solution vp_ss_nse, list_norm_nwtnupd = snu.solve_steadystate_nse(return_vp=True, **soldict) v_ss_nse, p_ss_nse = vp_ss_nse[:NV], vp_ss_nse[NV:] # specify in what spatial direction Bu changes. The remaining is constant if problemname == 'drivencavity': uspacedep = 0 elif problemname == 'cylinderwake': uspacedep = 1 # # Control mats # contsetupstr = problemname + '__NV{0}NU{1}NY{2}'.format(NV, NU, NY) # get the control and observation operators try: b_mat = dou.load_spa(ddir + contsetupstr + '__b_mat') u_masmat = dou.load_spa(ddir + contsetupstr + '__u_masmat') print 'loaded `b_mat`' except IOError: print 'computing `b_mat`...' b_mat, u_masmat = cou.get_inp_opa(cdcoo=femp['cdcoo'], V=femp['V'], NU=NU, xcomp=uspacedep) dou.save_spa(b_mat, ddir + contsetupstr + '__b_mat') dou.save_spa(u_masmat, ddir + contsetupstr + '__u_masmat') try: mc_mat = dou.load_spa(ddir + contsetupstr + '__mc_mat') y_masmat = dou.load_spa(ddir + contsetupstr + '__y_masmat') print 'loaded `c_mat`' except IOError: print 'computing `c_mat`...' mc_mat, y_masmat = cou.get_mout_opa(odcoo=femp['odcoo'], V=femp['V'], NY=NY) dou.save_spa(mc_mat, ddir + contsetupstr + '__mc_mat') dou.save_spa(y_masmat, ddir + contsetupstr + '__y_masmat') # restrict the operators to the inner nodes mc_mat = mc_mat[:, invinds][:, :] b_mat = b_mat[invinds, :][:, :] c_mat = lau.apply_massinv(y_masmat, mc_mat, output='sparse') # TODO: right choice of norms for y # and necessity of regularization here # by now, we go on number save # the pressure observation mean over a small domain if problemname == 'cylinderwake': podcoo = dict(xmin=0.6, xmax=0.64, ymin=0.18, ymax=0.22) elif problemname == 'drivencavity': podcoo = dict(xmin=0.45, xmax=0.55, ymin=0.7, ymax=0.8) else: podcoo = femp['odcoo'] # description of the control and observation domains dmd = femp['cdcoo'] xmin, xmax, ymin, ymax = dmd['xmin'], dmd['xmax'], dmd['ymin'], dmd['ymax'] velcondomstr = 'vel control domain: [{0}, {1}]x[{2}, {3}]\n'.\ format(xmin, xmax, ymin, ymax) dmd = femp['odcoo'] xmin, xmax, ymin, ymax = dmd['xmin'], dmd['xmax'], dmd['ymin'], dmd['ymax'] velobsdomstr = 'vel observation domain: [{0}, {1}]x[{2}, {3}]\n'.\ format(xmin, xmax, ymin, ymax) dmd = podcoo xmin, xmax, ymin, ymax = dmd['xmin'], dmd['xmax'], dmd['ymin'], dmd['ymax'] pobsdomstr = 'pressure observation domain: [{0}, {1}]x[{2}, {3}]\n'.\ format(xmin, xmax, ymin, ymax) pcmat = cou.get_pavrg_onsubd(odcoo=podcoo, Q=femp['Q'], ppin=None) cdatstr = snu.get_datastr_snu(time=None, meshp=N, nu=nu, Nts=None) (coors, xinds, yinds, corfunvec) = dts.get_dof_coors(femp['V'], invinds=invinds) ctrl_visu_str = \ ' the (distributed) control setup is as follows \n' +\ ' B maps into the domain of control -' +\ velcondomstr +\ ' the first half of the columns' +\ 'actuate in x-direction, the second in y direction \n' +\ ' Cv measures averaged velocities in the domain of observation' +\ velobsdomstr +\ ' Cp measures the averaged pressure' +\ ' in the domain of pressure observation: ' +\ pobsdomstr +\ ' the first components are in x, the last in y-direction \n\n' +\ ' Visualization: \n\n' +\ ' `coors` -- array of (x,y) coordinates in ' +\ ' the same order as v[xinds] or v[yinds] \n' +\ ' `xinds`, `yinds` -- indices of x and y components' +\ ' of v = [vx, vy] -- note that indexing starts with 0\n' +\ ' for testing use corfunvec wich is the interpolant of\n' +\ ' f(x,y) = [x, y] on the grid \n\n' +\ 'Created in `get_exp_nsmats.py` ' +\ '(see https://github.com/highlando/dolfin_navier_scipy) at\n' +\ datetime.datetime.now().strftime("%I:%M%p on %B %d, %Y") if bccontrol and problemname == 'cylinderwake' and linear_system: ctrl_visu_str = \ ('the boundary control is realized via penalized robin \n' + 'boundary conditions, cf. e.g. [Hou/Ravindran `98], \n' + 'with predefined shape functions for the cylinder wake \n' + 'and the penalization parameter `palpha`={0}.').format(palpha) +\ ctrl_visu_str if linear_system: convc_mat, rhs_con, rhsv_conbc = \ snu.get_v_conv_conts(prev_v=v_ss_nse, invinds=invinds, V=femp['V'], diribcs=femp['diribcs']) # TODO: omg if bccontrol: f_mat = -Arob - convc_mat else: f_mat = -stokesmatsc['A'] - convc_mat infostr = 'These are the coefficient matrices of the linearized ' +\ 'Navier-Stokes Equations \n for the ' +\ problemname + ' to be used as \n\n' +\ ' $M \\dot v = Av + J^Tp + Bu$ and $Jv = 0$ \n\n' +\ ' the Reynoldsnumber is computed as L/nu \n' +\ ' Note this is the reduced system for the velocity update\n' +\ ' caused by the control, i.e., no boundary conditions\n' +\ ' or inhomogeneities here. To get the actual flow, superpose \n' +\ ' the steadystate velocity solution `v_ss_nse` \n\n' +\ ctrl_visu_str matstr = (mddir + problemname + '__mats_N{0}_Re{1}').format(NV, Re) if bccontrol: matstr = matstr + '__penarob_palpha{0}'.format(palpha) scipy.io.savemat( matstr, dict(A=f_mat, M=stokesmatsc['M'], nu=femp['nu'], Re=femp['Re'], J=stokesmatsc['J'], B=b_mat, C=c_mat, Cp=pcmat, Brob=Brob, v_ss_nse=v_ss_nse, info=infostr, contsetupstr=contsetupstr, datastr=cdatstr, coors=coors, xinds=xinds, yinds=yinds, corfunvec=corfunvec)) print('matrices saved to ' + matstr) elif refree: hstr = ddir + problemname + '_N{0}_hmat'.format(N) try: hmat = dou.load_spa(hstr) print 'loaded `hmat`' except IOError: print 'assembling hmat ...' hmat = dts.ass_convmat_asmatquad(W=femp['V'], invindsw=invinds) dou.save_spa(hmat, hstr) zerv = np.zeros((NV, 1)) bc_conv, bc_rhs_conv, rhsbc_convbc = \ snu.get_v_conv_conts(prev_v=zerv, V=femp['V'], invinds=invinds, diribcs=femp['diribcs'], Picard=False) # diff_mat = stokesmatsc['A'] # bcconv_mat = bc_conv # fv_bcdiff = fv_stbc # fv_bcconv = - bc_rhs_conv fv = fvc fp = fpc # fp_bc = fp_stbc infostr = 'These are the coefficient matrices of the quadratic ' +\ 'formulation of the Navier-Stokes Equations \n for the ' +\ problemname + ' to be used as \n\n' +\ ' $M \\dot v + Av + H*kron(v,v) + J^Tp = Bu + fv$ \n' +\ ' and $Jv = fp$ \n\n' +\ ' the Reynoldsnumber is computed as L/nu \n' +\ ' note that `A` contains the diffusion and the linear term \n' +\ ' that comes from the dirichlet boundary values \n' +\ ' as initial value one can use the provided steady state \n' +\ ' Stokes solution \n' +\ ' see https://github.com/highlando/dolfin_navier_scipy/blob/' +\ ' master/tests/solve_nse_quadraticterm.py for appl example\n' +\ ctrl_visu_str scipy.io.savemat( mddir + problemname + 'quadform__mats_N{0}_Re{1}'.format(NV, Re), dict( A=f_mat, M=stokesmatsc['M'], H=-hmat, fv=fv, fp=fp, nu=femp['nu'], Re=femp['Re'], J=stokesmatsc['J'], B=b_mat, Cv=c_mat, Cp=pcmat, info=infostr, # ss_stokes=old_v, contsetupstr=contsetupstr, datastr=cdatstr, coors=coors, xinds=xinds, yinds=yinds, corfunvec=corfunvec)) else: hstr = ddir + problemname + '_N{0}_hmat'.format(N) try: hmat = dou.load_spa(hstr) print 'loaded `hmat`' except IOError: print 'assembling hmat ...' hmat = dts.ass_convmat_asmatquad(W=femp['V'], invindsw=invinds) dou.save_spa(hmat, hstr) zerv = np.zeros((NV, 1)) bc_conv, bc_rhs_conv, rhsbc_convbc = \ snu.get_v_conv_conts(prev_v=zerv, V=femp['V'], invinds=invinds, diribcs=femp['diribcs'], Picard=False) f_mat = -stokesmatsc['A'] - bc_conv l_mat = -bc_conv fv = fv_stbc + fvc - bc_rhs_conv fp = fp_stbc + fpc vp_stokes = lau.solve_sadpnt_smw(amat=A, jmat=J, rhsv=fv_stbc + fvc, rhsp=fp_stbc + fpc) old_v = vp_stokes[:NV] p_stokes = -vp_stokes[NV:] # the pressure was flipped for symmetry infostr = 'These are the coefficient matrices of the quadratic ' +\ 'formulation of the Navier-Stokes Equations \n for the ' +\ problemname + ' to be used as \n\n' +\ ' $M \\dot v = Av + H*kron(v,v) + J^Tp + Bu + fv$ \n' +\ ' and $Jv = fp$ \n\n' +\ ' the Reynoldsnumber is computed as L/nu \n' +\ ' note that `A` contains the diffusion and the linear term `L`\n' +\ ' that comes from the dirichlet boundary values \n' +\ ' for linearizations it might be necessary to consider `A-L` \n' +\ ' as initial value one can use the provided steady state \n' +\ ' Stokes solution \n' +\ ' see https://github.com/highlando/dolfin_navier_scipy/blob/' +\ ' master/tests/solve_nse_quadraticterm.py for appl example\n' +\ ctrl_visu_str scipy.io.savemat( mddir + problemname + 'quadform__mats_N{0}_Re{1}'.format(NV, Re), dict(A=f_mat, M=stokesmatsc['M'], H=-hmat, fv=fv, fp=fp, L=l_mat, nu=femp['nu'], Re=femp['Re'], J=stokesmatsc['J'], B=b_mat, Cv=c_mat, Cp=pcmat, info=infostr, p_ss_stokes=p_stokes, p_ss_nse=p_ss_nse, v_ss_stokes=old_v, v_ss_nse=v_ss_nse, contsetupstr=contsetupstr, datastr=cdatstr, coors=coors, xinds=xinds, yinds=yinds, corfunvec=corfunvec))
def cnab(trange=None, inivel=None, inip=None, bcs_ini=[], M=None, A=None, J=None, f_vdp=None, f_tdp=None, g_tdp=None, scalep=-1., getbcs=None, applybcs=None, appndbcs=None, savevp=None, dynamic_rhs=None, dynamic_rhs_memory={}, ntimeslices=10, verbose=True): dtvec = np.array(trange)[1:] - np.array(trange)[:-1] dotdtvec = dtvec[1:] - dtvec[:-1] uniformgrid = np.allclose(np.linalg.norm(dotdtvec), 0) if verbose: import time if not uniformgrid: raise NotImplementedError() dt = trange[1] - trange[0] NP, NV = J.shape zerorhs = np.zeros((NV, 1)) if dynamic_rhs is None: def dynamic_rhs(t, vc=None, memory={}, mode=None): return zerorhs, memory drm = dynamic_rhs_memory savevp(appndbcs(inivel, bcs_ini), inip, time=trange[0]) bcs_c = bcs_ini # getbcs(trange[0], inivel, inip) bfv_c, bfp_c, mbc_c = applybcs(bcs_c) fv_c = f_tdp(trange[0]) nfc_c = f_vdp(appndbcs(inivel, bcs_ini)) dfv_c, drm = dynamic_rhs(trange[0], vc=inivel, memory=drm, mode='init') tdfv, drm = dynamic_rhs(trange[0], vc=inivel, memory=drm, mode='heunpred') tbcs = getbcs(trange[1], appndbcs(inivel, bcs_ini), inip, mode='heunpred') tbfv, tbfp, tmbc = applybcs(tbcs) fv_n, fp_n = f_tdp(trange[1]), g_tdp(trange[1]) # Predictor Step -- CN + explicit Euler tfv = M*inivel - .5*dt*A*inivel + .5*dt*(fv_c+fv_n + tbfv+bfv_c + tdfv+dfv_c) \ + dt*nfc_c - (tmbc-mbc_c) tvp_new, coeffmatlu = \ lau.solve_sadpnt_smw(amat=M+.5*dt*A, jmat=J, jmatT=J.T, rhsv=tfv, rhsp=fp_n+tbfp, return_alu=True) tv_new = tvp_new[:NV, :] tp_new = 1. / dt * scalep * tvp_new[NV:, :] savevp(appndbcs(tv_new, tbcs), tp_new, time=(trange[1], 'heunpred')) # Corrector Step dfv_n, drm = dynamic_rhs(trange[1], vc=tv_new, memory=drm, mode='heuncorr') nfc_n = f_vdp(appndbcs(tv_new, tbcs)) bcs_n = getbcs(trange[1], appndbcs(tv_new, tbcs), tp_new, mode='heuncorr') bfv_n, bfp_n, mbc_n = applybcs(bcs_n) rhs_n = M*inivel - .5*dt*A*inivel - (mbc_n-mbc_c) +\ .5*dt*(fv_c+fv_n + bfv_n+bfv_c + dfv_n+tdfv + nfc_c+nfc_n) vp_new = coeffmatlu(np.vstack([rhs_n, fp_n + bfp_n]).flatten()) v_new = vp_new[:NV].reshape((NV, 1)) p_new = 1. / dt * scalep * vp_new[NV:].reshape((NP, 1)) savevp(appndbcs(v_new, bcs_n), p_new, time=trange[1]) lltr = np.array(trange[2:]) lnts = lltr.size lenofts = np.floor(lnts / ntimeslices).astype(np.int) listofts = [ lltr[k * lenofts:(k + 1) * lenofts].tolist() for k in range(ntimeslices) ] listofts.append(lltr[ntimeslices * lenofts:].tolist()) verbose = True for kck, ctrange in enumerate(listofts): if verbose: print('time-stepping {0}/{1} complete -- @runtime {2:.1f}'.format( kck, ntimeslices, time.clock())) for ctime in ctrange: v_old, p_old = v_new, p_new bcs_c = bcs_n bfv_c, mbc_c = bfv_n, mbc_n fv_c = fv_n dfv_c = dfv_n nfc_o = nfc_c nfc_c = f_vdp(appndbcs(v_old, bcs_c)) bcs_n = getbcs(ctime, appndbcs(v_old, bcs_c), p_old, mode='abtwo') bfv_n, bfp_n, mbc_n = applybcs(bcs_n) fv_n, fp_n = f_tdp(ctime), g_tdp(ctime) dfv_n, drm = dynamic_rhs(ctime, vc=v_old, memory=drm, mode='abtwo') rhs_n = M*v_old - .5*dt*A*v_old + 1.5*dt*nfc_c-.5*dt*nfc_o \ - (mbc_n-mbc_c) \ + .5*dt*(fv_c+fv_n + bfv_n+bfv_c + dfv_n+dfv_c) vp_new = coeffmatlu(np.vstack([rhs_n, fp_n + bfp_n]).flatten()) v_new = vp_new[:NV].reshape((NV, 1)) p_new = 1. / dt * scalep * vp_new[NV:].reshape((NP, 1)) savevp(appndbcs(v_new, bcs_n), p_new, time=ctime) return v_new, p_new
def solve_nse(A=None, M=None, J=None, JT=None, fv=None, fp=None, fvc=None, fpc=None, # TODO: this is to catch deprecated calls fv_tmdp=None, fv_tmdp_params={}, fv_tmdp_memory=None, iniv=None, lin_vel_point=None, stokes_flow=False, trange=None, t0=None, tE=None, Nts=None, V=None, Q=None, invinds=None, diribcs=None, dbcinds=None, dbcvals=None, output_includes_bcs=False, N=None, nu=None, ppin=-1, closed_loop=False, static_feedback=False, feedbackthroughdict=None, return_vp=False, tb_mat=None, cv_mat=None, vel_nwtn_stps=20, vel_nwtn_tol=5e-15, nsects=1, loc_nwtn_tol=5e-15, loc_pcrd_stps=True, addfullsweep=False, vel_pcrd_stps=4, krylov=None, krpslvprms={}, krplsprms={}, clearprvdata=False, useolddata=False, get_datastring=None, data_prfx='', paraviewoutput=False, plttrange=None, vfileprfx='', pfileprfx='', return_dictofvelstrs=False, return_dictofpstrs=False, dictkeysstr=False, treat_nonl_explct=False, return_as_list=False, verbose=True, start_ssstokes=False, **kw): """ solution of the time-dependent nonlinear Navier-Stokes equation .. math:: M\\dot v + Av + N(v)v + J^Tp = f \n Jv =g using a Newton scheme in function space, i.e. given :math:`v_k`, we solve for the update like .. math:: M\\dot v + Av + N(v_k)v + N(v)v_k + J^Tp = N(v_k)v_k + f, and trapezoidal rule in time. To solve an *Oseen* system (linearization about a steady state) or a *Stokes* system, set the number of Newton steps to one and provide a linearization point and an initial value. Parameters ---------- lin_vel_point : dictionary, optional contains the linearization point for the first Newton iteration * Steady State: {{`None`: 'path_to_nparray'}, {'None': nparray}} * Newton: {`t`: 'path_to_nparray'} defaults to `None` dictkeysstr : boolean, optional whether the `keys` of the result dictionaries are strings instead \ of floats, defaults to `False` fv_tmdp : callable f(t, v, dict), optional time-dependent part of the right-hand side, set to zero if None fv_tmdp_params : dictionary, optional dictionary of parameters to be passed to `fv_tmdp`, defaults to `{}` fv_tmdp_memory : dictionary, optional memory of the function output_includes_bcs : boolean, optional whether append the boundary nodes to the computed and stored \ velocities, defaults to `False` krylov : {None, 'gmres'}, optional whether or not to use an iterative solver, defaults to `None` krpslvprms : dictionary, optional to specify parameters of the linear solver for use in Krypy, e.g., * initial guess * tolerance * number of iterations defaults to `None` krplsprms : dictionary, optional parameters to define the linear system like * preconditioner ppin : {int, None}, optional which dof of `p` is used to pin the pressure, defaults to `-1` stokes_flow : boolean, optional whether to consider the Stokes linearization, defaults to `False` start_ssstokes : boolean, optional for your convenience, compute and use the steady state stokes solution as initial value, defaults to `False` treat_nonl_explct= string, optional whether to treat the nonlinearity explicitly, defaults to `False` nsects: int, optional in how many segments the trange is split up. (The newton iteration will be confined to the segments and, probably, converge faster than the global iteration), defaults to `1` loc_nwtn_tol: float, optional tolerance for the newton iteration on the segments, defaults to `1e-15` loc_pcrd_stps: boolean, optional whether to init with `vel_pcrd_stps` Picard steps on every section, if `False`, Picard iterations are performed only on the first section, defaults to `True` addfullsweep: boolean, optional whether to compute the newton iteration on the full `trange`, useful to check and for the plots, defaults to `False` cv_mat: (Ny, Nv) sparse array, optional output matrix for velocity outputs, needed, e.g., for output dependent feedback control, defaults to `None` Returns ------- dictofvelstrs : dictionary, on demand dictionary with time `t` as keys and path to velocity files as values dictofpstrs : dictionary, on demand dictionary with time `t` as keys and path to pressure files as values vellist : list, on demand list of the velocity solutions """ import sadptprj_riclyap_adi.lin_alg_utils as lau if fvc is not None or fpc is not None: # TODO: this is for catching calls raise UserWarning('deprecated use of `rhsd_vfrc`, use only `fv`, `fp`') if get_datastring is None: get_datastring = get_datastr_snu if paraviewoutput: prvoutdict = dict(V=V, Q=Q, invinds=invinds, diribcs=diribcs, ppin=ppin, vp=None, t=None, tfilter=plttrange, writeoutput=True) else: prvoutdict = dict(writeoutput=False) # save 'if statements' here if trange is None: trange = np.linspace(t0, tE, Nts+1) if treat_nonl_explct and lin_vel_point is not None: raise UserWarning('cant use `lin_vel_point` ' + 'and explicit treatment of the nonlinearity') if return_dictofpstrs: gpfvd = dict(V=V, M=M, A=A, J=J, fv=fv, fp=fp, dbcinds=dbcinds, dbcvals=dbcvals, diribcs=diribcs, invinds=invinds) NV, NP = A.shape[0], J.shape[0] fv = np.zeros((NV, 1)) if fv is None else fv fp = np.zeros((NP, 1)) if fp is None else fp if fv_tmdp is None: def fv_tmdp(time=None, curvel=None, **kw): return np.zeros((NV, 1)), None if iniv is None: if start_ssstokes: # Stokes solution as starting value vp_stokes =\ lau.solve_sadpnt_smw(amat=A, jmat=J, jmatT=JT, rhsv=fv, # + fv_tmdp_cont, krylov=krylov, krpslvprms=krpslvprms, krplsprms=krplsprms, rhsp=fp) iniv = vp_stokes[:NV] else: raise ValueError('No initial value given') datastrdict = dict(time=None, meshp=N, nu=nu, Nts=trange.size-1, data_prfx=data_prfx, semiexpl=treat_nonl_explct) if return_as_list: clearprvdata = True # we want the results at hand if clearprvdata: datastrdict['time'] = '*' cdatstr = get_datastring(**datastrdict) for fname in glob.glob(cdatstr + '__vel*'): os.remove(fname) for fname in glob.glob(cdatstr + '__p*'): os.remove(fname) def _atdct(cdict, t, thing): if dictkeysstr: cdict.update({'{0}'.format(t): thing}) else: cdict.update({t: thing}) def _gfdct(cdict, t): if dictkeysstr: return cdict['{0}'.format(t)] else: return cdict[t] if stokes_flow: vel_nwtn_stps = 1 vel_pcrd_stps = 0 print('Stokes Flow!') elif lin_vel_point is None: comp_nonl_semexp_inig = True if not treat_nonl_explct: print(('No linearization point given - explicit' + ' treatment of the nonlinearity in the first Iteration')) else: cur_linvel_point = lin_vel_point comp_nonl_semexp_inig = False newtk, norm_nwtnupd = 0, 1 # check for previously computed velocities if useolddata and lin_vel_point is None and not stokes_flow: try: datastrdict.update(dict(time=trange[-1])) cdatstr = get_datastring(**datastrdict) norm_nwtnupd = (dou.load_npa(cdatstr + '__norm_nwtnupd')).flatten() try: if norm_nwtnupd[0] is None: norm_nwtnupd = 1. except IndexError: norm_nwtnupd = 1. dou.load_npa(cdatstr + '__vel') print('found vel files') print('norm of last Nwtn update: {0}'.format(norm_nwtnupd)) print('... loaded from ' + cdatstr) if norm_nwtnupd < vel_nwtn_tol and not return_dictofvelstrs: return elif norm_nwtnupd < vel_nwtn_tol or treat_nonl_explct: # looks like converged / or semi-expl # -- check if all values are there # t0: datastrdict.update(dict(time=trange[0])) cdatstr = get_datastring(**datastrdict) dictofvelstrs = {} _atdct(dictofvelstrs, trange[0], cdatstr + '__vel') if return_dictofpstrs: dictofpstrs = {} for t in trange: datastrdict.update(dict(time=t)) cdatstr = get_datastring(**datastrdict) # test if the vels are there v_old = dou.load_npa(cdatstr + '__vel') # update the dict _atdct(dictofvelstrs, t, cdatstr + '__vel') if return_dictofpstrs: try: p_old = dou.load_npa(cdatstr + '__p') _atdct(dictofpstrs, t, cdatstr + '__p') except: p_old = get_pfromv(v=v_old, **gpfvd) dou.save_npa(p_old, fstring=cdatstr + '__p') _atdct(dictofpstrs, t, cdatstr + '__p') if return_dictofpstrs: return dictofvelstrs, dictofpstrs else: return dictofvelstrs # comp_nonl_semexp = False except IOError: norm_nwtnupd = 2 print('no old velocity data found') def _append_bcs_ornot(vvec): if output_includes_bcs: # make the switch here for better readibility vwbcs = dts.append_bcs_vec(vvec, vdim=V.dim(), invinds=invinds, diribcs=diribcs) return vwbcs else: return vvec def _get_mats_rhs_ts(mmat=None, dt=None, var_c=None, coeffmat_c=None, coeffmat_n=None, fv_c=None, fv_n=None, umat_c=None, vmat_c=None, umat_n=None, vmat_n=None, impeul=False): """ to be tweaked for different int schemes """ solvmat = M + 0.5*dt*coeffmat_n rhs = M*var_c + 0.5*dt*(fv_n + fv_c - coeffmat_c*var_c) if umat_n is not None: matvec = lau.mm_dnssps umat = 0.5*dt*umat_n vmat = vmat_n # TODO: do we really need a PLUS here??' rhs = rhs + 0.5*dt*matvec(umat_c, matvec(vmat_c, var_c)) else: umat, vmat = umat_n, vmat_n return solvmat, rhs, umat, vmat v_old = iniv # start vector for time integration in every Newtonit datastrdict['time'] = trange[0] cdatstr = get_datastring(**datastrdict) dou.save_npa(_append_bcs_ornot(v_old), fstring=cdatstr + '__vel') dictofvelstrs = {} _atdct(dictofvelstrs, trange[0], cdatstr + '__vel') if return_dictofpstrs: p_old = get_pfromv(v=v_old, **gpfvd) dou.save_npa(p_old, fstring=cdatstr + '__p') dictofpstrs = {} _atdct(dictofpstrs, trange[0], cdatstr+'__p') else: p_old = None if return_as_list: vellist = [] vellist.append(_append_bcs_ornot(v_old)) lensect = np.int(np.floor(trange.size/nsects)) loctrngs = [] for k in np.arange(nsects-1): loctrngs.append(trange[k*lensect: (k+1)*lensect+1]) loctrngs.append(trange[(nsects-1)*lensect:]) if addfullsweep: loctrngs.append(trange) realiniv = np.copy(iniv) if nsects == 1: loc_nwtn_tol = vel_nwtn_tol addfullsweep = False loctrngs = [trange] if loc_pcrd_stps: vel_loc_pcrd_steps = vel_pcrd_stps for loctrng in loctrngs: dtvec = np.array(loctrng)[1:] - np.array(loctrng)[1:] dotdtvec = dtvec[1:] - dtvec[:-1] uniformgrid = np.allclose(np.linalg.norm(dotdtvec), 0) coeffmatlu = None while (newtk < vel_nwtn_stps and norm_nwtnupd > loc_nwtn_tol): print('solve the NSE on the interval [{0}, {1}]'. format(loctrng[0], loctrng[-1])) if stokes_flow: pcrd_anyone = False newtk = vel_nwtn_stps elif comp_nonl_semexp_inig and not treat_nonl_explct: pcrd_anyone = False loc_treat_nonl_explct = True print('explicit treatment of nonl. for initial guess!') elif treat_nonl_explct: pcrd_anyone = False loc_treat_nonl_explct = True newtk = vel_nwtn_stps print('No Newton iterations - explicit treatment ' + 'of the nonlinearity') if not comp_nonl_semexp_inig and not treat_nonl_explct: if vel_pcrd_stps > 0: vel_pcrd_stps -= 1 pcrd_anyone = True print('Picard iterations for initial value -- {0} left'. format(vel_pcrd_stps)) else: pcrd_anyone = False newtk += 1 print('Computing Newton Iteration {0}'.format(newtk)) v_old = iniv # start vector for time integration in every Newtonit try: if krpslvprms['krylovini'] == 'old': vp_old = np.vstack([v_old, np.zeros((NP, 1))]) elif krpslvprms['krylovini'] == 'upd': vp_old = np.vstack([v_old, np.zeros((NP, 1))]) vp_new = vp_old cts_old = loctrng[1] - loctrng[0] except (TypeError, KeyError): pass # no inival for krylov solver required vfile = dolfin.File(vfileprfx+'__timestep.pvd') pfile = dolfin.File(pfileprfx+'__timestep.pvd') prvoutdict.update(dict(vp=None, vc=iniv, pc=p_old, t=loctrng[0], dbcinds=dbcinds, dbcvals=dbcvals, pfile=pfile, vfile=vfile)) dou.output_paraview(**prvoutdict) # ## current values_c for application of trap rule if stokes_flow: convc_mat_c = sps.csr_matrix((NV, NV)) rhs_con_c, rhsv_conbc_c = np.zeros((NV, 1)), np.zeros((NV, 1)) else: if loc_treat_nonl_explct is not None: prev_v = v_old else: try: prev_v = dou.load_npa(_gfdct(cur_linvel_point, loctrng[0])) except KeyError: try: prev_v = dou.load_npa(_gfdct(cur_linvel_point, None)) except TypeError: prev_v = cur_linvel_point[None] convc_mat_c, rhs_con_c, rhsv_conbc_c = \ get_v_conv_conts(prev_v=iniv, invinds=invinds, semi_explicit=loc_treat_nonl_explct, dbcinds=dbcinds, dbcvals=dbcvals, V=V, diribcs=diribcs, Picard=pcrd_anyone) cury = None if cv_mat is None else cv_mat.dot(v_old) (fv_tmdp_cont, fv_tmdp_memory) = fv_tmdp(time=0, curvel=v_old, cury=cury, memory=fv_tmdp_memory, **fv_tmdp_params) _rhsconvc = 0. if pcrd_anyone else rhs_con_c fvn_c = fv + rhsv_conbc_c + _rhsconvc + fv_tmdp_cont if closed_loop: if static_feedback: mtxtb_c = dou.load_npa(feedbackthroughdict[None]['mtxtb']) w_c = dou.load_npa(feedbackthroughdict[None]['w']) else: mtxtb_c = dou.load_npa(feedbackthroughdict[0]['mtxtb']) w_c = dou.load_npa(feedbackthroughdict[0]['w']) fvn_c = fvn_c + tb_mat * (tb_mat.T * w_c) vmat_c = mtxtb_c.T try: umat_c = np.array(tb_mat.todense()) except AttributeError: umat_c = tb_mat else: vmat_c = None umat_c = None norm_nwtnupd = 0 if verbose: # define at which points of time the progress is reported nouts = 10 # number of output points locnts = loctrng.size # TODO: trange may be a list... filtert = np.arange(0, locnts, np.int(np.floor(locnts/nouts))) loctinstances = loctrng[filtert] loctinstances[0] = loctrng[1] loctinstances = loctinstances.tolist() print('doing the time integration...') for tk, t in enumerate(loctrng[1:]): cts = t - loctrng[tk] datastrdict.update(dict(time=t)) cdatstr = get_datastring(**datastrdict) try: if verbose and t == loctinstances[0]: curtinst = loctinstances.pop(0) # print("runtime: {0} -- t: {1} -- tE: {2:f}". # format(time.clock(), curtinst, loctrng[-1])) print("runtime: {0:.1f} - t/tE: {1:.2f} - t: {2:.4f}". format(time.clock(), curtinst/loctrng[-1], curtinst)) except IndexError: pass # if something goes wrong, don't stop # coeffs and rhs at next time instance if stokes_flow: convc_mat_n = sps.csr_matrix((NV, NV)) rhs_con_n = np.zeros((NV, 1)) rhsv_conbc_n = np.zeros((NV, 1)) else: if loc_treat_nonl_explct: prev_v = v_old else: try: prev_v = dou.load_npa(_gfdct(cur_linvel_point, t)) except KeyError: try: prev_v = dou.load_npa(_gfdct(cur_linvel_point, None)) except TypeError: prev_v = cur_linvel_point[None] convc_mat_n, rhs_con_n, rhsv_conbc_n = \ get_v_conv_conts(prev_v=prev_v, invinds=invinds, V=V, semi_explicit=loc_treat_nonl_explct, dbcinds=dbcinds, dbcvals=dbcvals, diribcs=diribcs, Picard=pcrd_anyone) cury = None if cv_mat is None else cv_mat.dot(v_old) (fv_tmdp_cont, fv_tmdp_memory) = fv_tmdp(time=t, curvel=v_old, cury=cury, memory=fv_tmdp_memory, **fv_tmdp_params) _rhsconvn = 0. if pcrd_anyone else rhs_con_n fvn_n = fv + rhsv_conbc_n + _rhsconvn + fv_tmdp_cont if loc_treat_nonl_explct and not closed_loop: fvn_c = fv + rhsv_conbc_n + _rhsconvn + fv_tmdp_cont if closed_loop: if static_feedback: mtxtb_n = dou.\ load_npa(feedbackthroughdict[None]['mtxtb']) w_n = dou.load_npa(feedbackthroughdict[None]['w']) # fb = np.dot(tb_mat*mtxtb_n.T, v_old) # print '\nnorm of feedback: ', np.linalg.norm(fb) # print '\nnorm of v_old: ', np.linalg.norm(v_old) else: mtxtb_n = dou.load_npa(feedbackthroughdict[t]['mtxtb']) w_n = dou.load_npa(feedbackthroughdict[t]['w']) fvn_n = fvn_n + tb_mat * (tb_mat.T * w_n) vmat_n = mtxtb_n.T try: umat_n = np.array(tb_mat.todense()) except AttributeError: umat_n = tb_mat else: vmat_n = None umat_n = None (solvmat, rhsv, umat, vmat) = _get_mats_rhs_ts(mmat=M, dt=cts, var_c=v_old, coeffmat_c=A + convc_mat_c, coeffmat_n=A + convc_mat_n, fv_c=fvn_c, fv_n=fvn_n, umat_c=umat_c, vmat_c=vmat_c, umat_n=umat_n, vmat_n=vmat_n) try: if krpslvprms['krylovini'] == 'old': krpslvprms['x0'] = vp_old elif krpslvprms['krylovini'] == 'upd': vp_oldold = vp_old vp_old = vp_new krpslvprms['x0'] = vp_old + \ cts*(vp_old - vp_oldold)/cts_old cts_old = cts except (TypeError, KeyError): pass # no inival for krylov solver required if loc_treat_nonl_explct and uniformgrid and not krylov: if coeffmatlu is None: print('gonna compute an LU of the coefficient ' + 'matrix \n and reuse it in the time stepping') vp_new, coeffmatlu = \ lau.solve_sadpnt_smw(amat=solvmat, jmat=J, jmatT=JT, rhsv=rhsv, rhsp=fp, sadlu=coeffmatlu, return_alu=True, umat=umat, vmat=vmat) else: vp_new = lau.solve_sadpnt_smw(amat=solvmat, jmat=J, jmatT=JT, rhsv=rhsv, rhsp=fp, krylov=krylov, krpslvprms=krpslvprms, krplsprms=krplsprms, umat=umat, vmat=vmat) v_old = vp_new[:NV, ] (umat_c, vmat_c, fvn_c, convc_mat_c) = umat_n, vmat_n, fvn_n, convc_mat_n dou.save_npa(_append_bcs_ornot(v_old), fstring=cdatstr + '__vel') _atdct(dictofvelstrs, t, cdatstr + '__vel') p_new = -1/cts*vp_new[NV:, ] # p was flipped and scaled for symmetry if return_dictofpstrs: dou.save_npa(p_new, fstring=cdatstr + '__p') _atdct(dictofpstrs, t, cdatstr + '__p') if return_as_list: vellist.append(_append_bcs_ornot(v_old)) # integrate the Newton error if stokes_flow or treat_nonl_explct: norm_nwtnupd = None elif comp_nonl_semexp_inig: norm_nwtnupd = 1. else: if len(prev_v) > len(invinds): prev_v = prev_v[invinds, :] addtonwtnupd = cts * m_innerproduct(M, v_old - prev_v) norm_nwtnupd += np.float(addtonwtnupd.flatten()[0]) if newtk == vel_nwtn_stps or norm_nwtnupd < loc_nwtn_tol: # paraviewoutput in the (probably) last newton sweep prvoutdict.update(dict(vc=v_old, pc=p_new, t=t)) dou.output_paraview(**prvoutdict) dou.save_npa(norm_nwtnupd, cdatstr + '__norm_nwtnupd') print('\nnorm of current Newton update: {}'.format(norm_nwtnupd)) # print('\nsaved `norm_nwtnupd(={0})'.format(norm_nwtnupd) + # ' to ' + cdatstr) loc_treat_nonl_explct = False comp_nonl_semexp_inig = False cur_linvel_point = dictofvelstrs iniv = v_old if not treat_nonl_explct and lin_vel_point is None: comp_nonl_semexp_inig = True if addfullsweep and loctrng is loctrngs[-2]: comp_nonl_semexp_inig = False iniv = realiniv loc_nwtn_tol = vel_nwtn_tol elif loc_pcrd_stps: vel_pcrd_stps = vel_loc_pcrd_steps norm_nwtnupd = 1. newtk = 0 if return_dictofvelstrs: if return_dictofpstrs: return dictofvelstrs, dictofpstrs else: return dictofvelstrs elif return_as_list: return vellist else: return
def test_qbdae_ass(problemname='cylinderwake', N=1, Re=4e2, nu=3e-2, t0=0.0, tE=1.0, Nts=100, use_saved_mats=None): trange = np.linspace(t0, tE, Nts+1) DT = (tE-t0)/Nts rdir = 'results/' femp, stokesmatsc, rhsd_vfrc, rhsd_stbc, \ data_prfx, ddir, proutdir = \ dns.problem_setups.get_sysmats(problem=problemname, N=N, Re=Re) invinds = femp['invinds'] if use_saved_mats is None: A, J, M = stokesmatsc['A'], stokesmatsc['J'], stokesmatsc['M'] fvc, fpc = rhsd_vfrc['fvc'], rhsd_vfrc['fpr'] fv_stbc, fp_stbc = rhsd_stbc['fv'], rhsd_stbc['fp'] hstr = ddir + problemname + '_N{0}_hmat'.format(N) try: hmat = dou.load_spa(hstr) print 'loaded `hmat`' except IOError: print 'assembling hmat ...' hmat = dnsts.ass_convmat_asmatquad(W=femp['V'], invindsw=invinds) dou.save_spa(hmat, hstr) invinds = femp['invinds'] NV, NP = invinds.shape[0], J.shape[0] zerv = np.zeros((NV, 1)) bc_conv, bc_rhs_conv, rhsbc_convbc = \ snu.get_v_conv_conts(prev_v=zerv, V=femp['V'], invinds=invinds, diribcs=femp['diribcs'], Picard=False) fp = fp_stbc + fpc fv = fv_stbc + fvc - bc_rhs_conv # Stokes solution as initial value vp_stokes = lau.solve_sadpnt_smw(amat=A, jmat=J, rhsv=fv_stbc + fvc, rhsp=fp_stbc + fpc) old_v = vp_stokes[:NV] sysmat = sps.vstack([sps.hstack([M+DT*(A+bc_conv), J.T]), sps.hstack([J, sps.csc_matrix((NP, NP))])]) # the observation if problemname == 'cylinderwake': podcoo = dict(xmin=0.6, xmax=0.64, ymin=0.18, ymax=0.22) elif problemname == 'drivencavity': podcoo = dict(xmin=0.45, xmax=0.55, ymin=0.7, ymax=0.8) else: podcoo = femp['odcoo'] pcmat = cou.get_pavrg_onsubd(odcoo=podcoo, Q=femp['Q']) if use_saved_mats is not None: # if saved as in ../get_exp_mats import scipy.io mats = scipy.io.loadmat(use_saved_mats) A = - mats['A'] M = mats['M'] J = mats['J'] hmat = -mats['H'] fv = mats['fv'] fp = mats['fp'] NV, NP = fv.shape[0], fp.shape[0] old_v = mats['ss_stokes'] sysmat = sps.vstack([sps.hstack([M+DT*A, J.T]), sps.hstack([J, sps.csc_matrix((NP, NP))])]) pcmat = mats['Cp'] print 'computing LU once...' sysmati = spsla.factorized(sysmat) vfile = dolfin.File(rdir + problemname + 'qdae__vel.pvd') pfile = dolfin.File(rdir + problemname + 'qdae__p.pvd') prvoutdict = dict(V=femp['V'], Q=femp['Q'], vfile=vfile, pfile=pfile, invinds=invinds, diribcs=femp['diribcs'], vp=None, t=None, writeoutput=True) print 'doing the time loop...' poutlist = [] for t in trange: # conv_mat, rhs_conv, rhsbc_conv = \ # snu.get_v_conv_conts(prev_v=old_v, V=femp['V'], invinds=invinds, # diribcs=femp['diribcs'], Picard=False) # crhsv = M*old_v + DT*(fv_stbc + fvc + rhs_conv + rhsbc_conv # - conv_mat*old_v) # raise Warning('TODO: debug') crhsv = M*old_v + DT*(fv - hmat*np.kron(old_v, old_v)) crhs = np.vstack([crhsv, fp]) vp_new = np.atleast_2d(sysmati(crhs.flatten())).T # vp_new = lau.solve_sadpnt_smw(amat=M+DT*(A+0*conv_mat), jmat=J, # rhsv=crhsv, # rhsp=fp_stbc + fpc) vp_new[NV:] = pcmat.T # *vp_new[NV:] prvoutdict.update(dict(vp=vp_new, t=t)) dou.output_paraview(**prvoutdict) old_v = vp_new[:NV] p = vp_new[NV:] poutlist.append(np.dot(pcmat, p)[0][0]) print t, np.linalg.norm(old_v) dou.plot_prs_outp(outsig=poutlist, tmesh=trange)
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
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
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
def optcon_nse(problemname='drivencavity', N=10, Nts=10, nu=1e-2, clearprvveldata=False, ini_vel_stokes=False, stst_control=False, closed_loop=True, outernwtnstps=1, t0=None, tE=None, use_ric_ini_nu=None, alphau=1e-9, gamma=1e-3, spec_tip_dict=None, nwtn_adi_dict=None, linearized_nse=False, stokes_flow=False, ystar=None): tip = time_int_params(Nts, t0=t0, tE=tE) if spec_tip_dict is not None: tip.update(spec_tip_dict) if nwtn_adi_dict is not None: tip['nwtn_adi_dict'] = nwtn_adi_dict problemdict = dict(drivencavity=dnsps.drivcav_fems, cylinderwake=dnsps.cyl_fems) problemfem = problemdict[problemname] femp = problemfem(N) # output ddir = 'data/' try: os.chdir(ddir) except OSError: raise Warning('need "' + ddir + '" subdir for storing the data') os.chdir('..') if linearized_nse and not outernwtnstps == 1: raise Warning('Linearized problem can have only one Newton step') if closed_loop: if stst_control: data_prfx = ddir + 'stst_' + problemname + '__' else: data_prfx = ddir + 'tdst_' + problemname + '__' else: data_prfx = ddir + problemname + '__' if stokes_flow: data_prfx = data_prfx + 'stokes__' # specify in what spatial direction Bu changes. The remaining is constant if problemname == 'drivencavity': uspacedep = 0 elif problemname == 'cylinderwake': uspacedep = 1 stokesmats = dts.get_stokessysmats(femp['V'], femp['Q'], nu) rhsd_vf = dts.setget_rhs(femp['V'], femp['Q'], femp['fv'], femp['fp'], t=0) # remove the freedom in the pressure stokesmats['J'] = stokesmats['J'][:-1, :][:, :] stokesmats['JT'] = stokesmats['JT'][:, :-1][:, :] rhsd_vf['fp'] = rhsd_vf['fp'][:-1, :] # reduce the matrices by resolving the BCs (stokesmatsc, rhsd_stbc, invinds, bcinds, bcvals) = dts.condense_sysmatsbybcs(stokesmats, femp['diribcs']) print 'Dimension of the div matrix: ', stokesmatsc['J'].shape # pressure freedom and dirichlet reduced rhs rhsd_vfrc = dict(fpr=rhsd_vf['fp'], fvc=rhsd_vf['fv'][invinds, ]) # add the info on boundary and inner nodes bcdata = {'bcinds': bcinds, 'bcvals': bcvals, 'invinds': invinds} femp.update(bcdata) # casting some parameters NV = len(femp['invinds']) soldict = stokesmatsc # containing A, J, JT soldict.update(femp) # adding V, Q, invinds, diribcs # soldict.update(rhsd_vfrc) # adding fvc, fpr soldict.update(fv=rhsd_stbc['fv'] + rhsd_vfrc['fvc'], fp=rhsd_stbc['fp'] + rhsd_vfrc['fpr'], N=N, nu=nu, trange=tip['tmesh'], get_datastring=get_datastr, data_prfx=data_prfx, clearprvdata=clearprvveldata, paraviewoutput=tip['ParaviewOutput'], vfileprfx=tip['proutdir'] + 'vel_', pfileprfx=tip['proutdir'] + 'p_') # # Prepare for control # contp = ContParams(femp['odcoo'], ystar=ystar, alphau=alphau, gamma=gamma) # casting some parameters NY, NU = contp.NY, contp.NU contsetupstr = problemname + '__NV{0}NU{1}NY{2}'.format(NV, NU, NY) # get the control and observation operators try: b_mat = dou.load_spa(ddir + contsetupstr + '__b_mat') u_masmat = dou.load_spa(ddir + contsetupstr + '__u_masmat') print 'loaded `b_mat`' except IOError: print 'computing `b_mat`...' b_mat, u_masmat = cou.get_inp_opa(cdcoo=femp['cdcoo'], V=femp['V'], NU=NU, xcomp=uspacedep) dou.save_spa(b_mat, ddir + contsetupstr + '__b_mat') dou.save_spa(u_masmat, ddir + contsetupstr + '__u_masmat') try: mc_mat = dou.load_spa(ddir + contsetupstr + '__mc_mat') y_masmat = dou.load_spa(ddir + contsetupstr + '__y_masmat') print 'loaded `c_mat`' except IOError: print 'computing `c_mat`...' mc_mat, y_masmat = cou.get_mout_opa(odcoo=femp['odcoo'], V=femp['V'], NY=NY) dou.save_spa(mc_mat, ddir + contsetupstr + '__mc_mat') dou.save_spa(y_masmat, ddir + contsetupstr + '__y_masmat') # restrict the operators to the inner nodes mc_mat = mc_mat[:, invinds][:, :] b_mat = b_mat[invinds, :][:, :] # for further use: c_mat = lau.apply_massinv(y_masmat, mc_mat, output='sparse') if contp.ystarx is None: c_mat = c_mat[NY:, :][:, :] # TODO: Do this right mc_mat = mc_mat[NY:, :][:, :] # TODO: Do this right y_masmat = y_masmat[:NY, :][:, :NY] # TODO: Do this right mct_mat_reg = lau.app_prj_via_sadpnt(amat=stokesmatsc['M'], jmat=stokesmatsc['J'], rhsv=mc_mat.T, transposedprj=True) # set the weighing matrices contp.R = contp.alphau * u_masmat # # solve the differential-alg. Riccati eqn for the feedback gain X # via computing factors Z, such that X = -Z*Z.T # # at the same time we solve for the affine-linear correction w # # tilde B = BR^{-1/2} tb_mat = lau.apply_invsqrt_fromright(contp.R, b_mat, output='sparse') # tb_dense = np.array(tb_mat.todense()) trct_mat = lau.apply_invsqrt_fromright(y_masmat, mct_mat_reg, output='dense') if closed_loop: cntpstr = 'NV{3}NY{0}NU{1}alphau{2}gamma{4}'.\ format(contp.NU, contp.NY, contp.alphau, NV, contp.gamma) else: cntpstr = '' # we gonna use this quite often M, A = stokesmatsc['M'], stokesmatsc['A'] datastrdict = dict(time=None, meshp=N, nu=nu, Nts=Nts, data_prfx=data_prfx) # compute the uncontrolled steady state (Navier-)Stokes solution # as initial value if ini_vel_stokes: # compute the uncontrolled steady state Stokes solution ini_vel, newtonnorms = snu.solve_steadystate_nse(vel_nwtn_stps=0, vel_pcrd_stps=0, **soldict) soldict.update(dict(iniv=ini_vel)) else: ini_vel, newtonnorms = snu.solve_steadystate_nse(**soldict) soldict.update(dict(iniv=ini_vel)) if closed_loop: if stst_control: if stokes_flow: convc_mat = sps.csr_matrix((NV, NV)) rhs_con, rhsv_conbc = np.zeros((NV, 1)), np.zeros((NV, 1)) lin_point = None else: lin_point, newtonnorms = snu.solve_steadystate_nse(**soldict) (convc_mat, rhs_con, rhsv_conbc) = snu.get_v_conv_conts(prev_v=lin_point, invinds=invinds, V=femp['V'], diribcs=femp['diribcs']) # infinite control horizon, steady target state cdatstr = get_datastr(time=None, meshp=N, nu=nu, Nts=None, data_prfx=data_prfx) try: Z = dou.load_npa(cdatstr + cntpstr + '__Z') print 'loaded ' + cdatstr + cntpstr + '__Z' except IOError: if use_ric_ini_nu is not None: cdatstr = get_datastr(nwtn=None, time=None, meshp=N, nu=use_ric_ini_nu, Nts=None, data_prfx=data_prfx) try: zini = dou.load_npa(ddir + cdatstr + cntpstr + '__Z') print 'Initialize Newton ADI by Z from ' + cdatstr except IOError: raise Warning('No data for initialization of ' ' Newton ADI -- need ' + cdatstr + '__Z') cdatstr = get_datastr(meshp=N, nu=nu, data_prfx=data_prfx) else: zini = None parnadi = pru.proj_alg_ric_newtonadi Z = parnadi(mmat=M, amat=-A - convc_mat, jmat=stokesmatsc['J'], bmat=tb_mat, wmat=trct_mat, z0=zini, nwtn_adi_dict=tip['nwtn_adi_dict'])['zfac'] dou.save_npa(Z, fstring=cdatstr + cntpstr + '__Z') print 'saved ' + cdatstr + cntpstr + '__Z' if tip['compress_z']: Zc = pru.compress_Zsvd(Z, thresh=tip['comprz_thresh'], k=tip['comprz_maxc']) Z = Zc fvnstst = rhs_con + rhsv_conbc + rhsd_stbc['fv'] + rhsd_vfrc['fvc'] # X = -ZZ.T mtxtb_stst = -pru.get_mTzzTtb(M.T, Z, tb_mat) mtxfv_stst = -pru.get_mTzzTtb(M.T, Z, fvnstst) fl = mc_mat.T * contp.ystarvec(0) wft = lau.solve_sadpnt_smw(amat=A.T + convc_mat.T, jmat=stokesmatsc['J'], rhsv=fl + mtxfv_stst, umat=mtxtb_stst, vmat=tb_mat.T)[:NV] auxstrg = cdatstr + cntpstr dou.save_npa(wft, fstring=cdatstr + cntpstr + '__w') dou.save_npa(mtxtb_stst, fstring=cdatstr + cntpstr + '__mtxtb') feedbackthroughdict = { None: dict(w=auxstrg + '__w', mtxtb=auxstrg + '__mtxtb') } cns = 0 soldict.update(data_prfx=data_prfx + '_cns{0}'.format(cns)) if linearized_nse: soldict.update(vel_pcrd_stps=0, vel_nwtn_stps=1, lin_vel_point={None: lin_point}) dictofvels = snu.\ solve_nse(return_dictofvelstrs=True, closed_loop=True, static_feedback=True, tb_mat=tb_mat, stokes_flow=stokes_flow, clearprvveldata=True, feedbackthroughdict=feedbackthroughdict, **soldict) else: # time dep closed loop cns_data_prfx = 'data/cnsvars' invd = init_nwtnstps_value_dict curnwtnsdict = invd(tmesh=tip['tmesh'], data_prfx=cns_data_prfx) # initialization: compute the forward solution if stokes_flow: dictofvels = None else: dictofvels = snu.solve_nse(return_dictofvelstrs=True, stokes_flow=stokes_flow, **soldict) # dbs.plot_vel_norms(tip['tmesh'], dictofvels) # function for the time depending parts # -- to be passed to the solver def get_tdpart(time=None, dictofvalues=None, feedback=False, V=None, invinds=None, diribcs=None, **kw): if stokes_flow: convc_mat = sps.csr_matrix((NV, NV)) rhs_con, rhsv_conbc = np.zeros((NV, 1)), np.zeros((NV, 1)) else: curvel = dou.load_npa(dictofvalues[time]) convc_mat, rhs_con, rhsv_conbc = \ snu.get_v_conv_conts(prev_v=curvel, invinds=invinds, V=V, diribcs=diribcs) return convc_mat, rhsv_conbc + rhs_con gttdprtargs = dict(dictofvalues=dictofvels, V=femp['V'], diribcs=femp['diribcs'], invinds=invinds) # old version rhs # ftilde = rhs_con + rhsv_conbc + rhsd_stbc['fv'] for cns in range(outernwtnstps): datastrdict.update(data_prfx=data_prfx + cntpstr + '_cns{0}'.format(cns)) soldict.update(data_prfx=data_prfx + cntpstr + '_cns{0}'.format(cns)) sfd = sdr.solve_flow_daeric feedbackthroughdict = \ sfd(mmat=M, amat=A, jmat=stokesmatsc['J'], bmat=b_mat, # cmat=ct_mat_reg.T, mcmat=mct_mat_reg.T, v_is_my=True, rmat=contp.alphau*u_masmat, vmat=y_masmat, rhsv=rhsd_stbc['fv'], gamma=contp.gamma, rhsp=None, tmesh=tip['tmesh'], ystarvec=contp.ystarvec, nwtn_adi_dict=tip['nwtn_adi_dict'], comprz_thresh=tip['comprz_thresh'], comprz_maxc=tip['comprz_maxc'], save_full_z=False, get_tdpart=get_tdpart, gttdprtargs=gttdprtargs, curnwtnsdict=curnwtnsdict, get_datastr=get_datastr, gtdtstrargs=datastrdict) # for t in tip['tmesh']: # feedbackthroughdict.keys(): # curw = dou.load_npa(feedbackthroughdict[t]['mtxtb']) # print cns, t, np.linalg.norm(curw) cdatstr = get_datastr(time='all', meshp=N, nu=nu, Nts=None, data_prfx=data_prfx) if linearized_nse: dictofvels = snu.\ solve_nse(return_dictofvelstrs=True, closed_loop=True, tb_mat=tb_mat, lin_vel_point=dictofvels, feedbackthroughdict=feedbackthroughdict, vel_nwtn_stps=1, vel_pcrd_stps=0, **soldict) else: dictofvels = snu.\ solve_nse(return_dictofvelstrs=True, closed_loop=True, tb_mat=tb_mat, stokes_flow=stokes_flow, feedbackthroughdict=feedbackthroughdict, vel_pcrd_stps=1, vel_nwtn_stps=2, **soldict) # for t in dictofvels.keys(): # curw = dou.load_npa(dictofvels[t]) # print cns, t, np.linalg.norm(curw) gttdprtargs.update(dictofvalues=dictofvels) else: # no control feedbackthroughdict = None tb_mat = None cdatstr = get_datastr(meshp=N, nu=nu, time='all', Nts=Nts, data_prfx=data_prfx) soldict.update(clearprvdata=True) dictofvels = snu.solve_nse(feedbackthroughdict=feedbackthroughdict, tb_mat=tb_mat, closed_loop=closed_loop, stokes_flow=stokes_flow, return_dictofvelstrs=True, static_feedback=stst_control, **soldict) (yscomplist, ystarlist) = dou.extract_output(dictofpaths=dictofvels, tmesh=tip['tmesh'], c_mat=c_mat, ystarvec=contp.ystarvec) save_output_json(yscomplist, tip['tmesh'].tolist(), ystar=ystarlist, fstring=cdatstr + cntpstr + '__sigout') costfunval = eval_costfunc(W=y_masmat, V=contp.gamma * y_masmat, R=None, tbmat=tb_mat, cmat=c_mat, ystar=contp.ystarvec, tmesh=tip['tmesh'], veldict=dictofvels, fbftdict=feedbackthroughdict) print 'Value of cost functional: ', costfunval costfunval = eval_costfunc(W=y_masmat, V=contp.gamma * y_masmat, R=None, tbmat=tb_mat, cmat=c_mat, ystar=contp.ystarvec, penau=False, tmesh=tip['tmesh'], veldict=dictofvels, fbftdict=feedbackthroughdict) print 'Value of cost functional not considering `u`: ', costfunval print 'dim of v :', femp['V'].dim() charlene = .15 if problemname == 'cylinderwake' else 1.0 print 'Re = charL / nu = {0}'.format(charlene / nu)
def test_qbdae_ass(problemname='cylinderwake', N=1, Re=None, nu=3e-2, t0=0.0, tE=1.0, Nts=100, use_saved_mats=None): trange = np.linspace(t0, tE, Nts + 1) DT = (tE - t0) / Nts rdir = 'results/' ddir = 'data/' if use_saved_mats is None: femp, stokesmatsc, rhsd_vfrc, rhsd_stbc = \ dns.problem_setups.get_sysmats(problem=problemname, N=N, Re=Re) invinds = femp['invinds'] A, J, M = stokesmatsc['A'], stokesmatsc['J'], stokesmatsc['M'] L = 0 * A fvc, fpc = rhsd_vfrc['fvc'], rhsd_vfrc['fpr'] fv_stbc, fp_stbc = rhsd_stbc['fv'], rhsd_stbc['fp'] hstr = ddir + problemname + '_N{0}_hmat'.format(N) try: hmat = dou.load_spa(hstr) print('loaded `hmat`') except IOError: print('assembling hmat ...') hmat = dnsts.ass_convmat_asmatquad(W=femp['V'], invindsw=invinds) dou.save_spa(hmat, hstr) invinds = femp['invinds'] NV, NP = invinds.shape[0], J.shape[0] zerv = np.zeros((NV, 1)) bc_conv, bc_rhs_conv, rhsbc_convbc = \ snu.get_v_conv_conts(prev_v=zerv, V=femp['V'], invinds=invinds, diribcs=femp['diribcs'], Picard=False) fp = fp_stbc + fpc fv = fv_stbc + fvc - bc_rhs_conv if linnsesol: vp_nse, _ = snu.\ solve_steadystate_nse(A=A, J=J, JT=None, M=M, fv=fv_stbc + fvc, fp=fp_stbc + fpc, V=femp['V'], Q=femp['Q'], invinds=invinds, diribcs=femp['diribcs'], return_vp=False, ppin=-1, N=N, nu=nu, clearprvdata=False) old_v = vp_nse[:NV] else: import sadptprj_riclyap_adi.lin_alg_utils as lau # Stokes solution as initial value vp_stokes = lau.solve_sadpnt_smw(amat=A, jmat=J, rhsv=fv_stbc + fvc, rhsp=fp_stbc + fpc) old_v = vp_stokes[:NV] sysmat = sps.vstack([ sps.hstack([M + DT * (A + bc_conv), J.T]), sps.hstack([J, sps.csc_matrix((NP, NP))]) ]) if use_saved_mats is not None: # if saved as in ../get_exp_mats import scipy.io mats = scipy.io.loadmat(use_saved_mats) A = -mats['A'] L = -mats['L'] Re = mats['Re'] N = A.shape[0] M = mats['M'] J = mats['J'] hmat = -mats['H'] fv = mats['fv'] fp = mats['fp'] NV, NP = fv.shape[0], fp.shape[0] old_v = mats['ss_stokes'] sysmat = sps.vstack([ sps.hstack([M + DT * A, J.T]), sps.hstack([J, sps.csc_matrix((NP, NP))]) ]) if compevs: import matplotlib.pyplot as plt import scipy.linalg as spla hlstr = ddir + problemname + '_N{0}_Re{1}Nse{2}_hlmat'.\ format(N, Re, linnsesol) HL = linearzd_quadterm(hmat, old_v, hlstr=hlstr) print(HL.shape) asysmat = sps.vstack([ sps.hstack([-(A - L + HL), J.T]), sps.hstack([J, sps.csc_matrix((NP, NP))]) ]) msysmat = sps.vstack([ sps.hstack([M, sps.csc_matrix((NV, NP))]), sps.hstack([sps.csc_matrix((NP, NV)), sps.csc_matrix((NP, NP))]) ]) levstr = ddir + problemname + '_N{0}Re{1}Nse{2}_levs'.\ format(N, Re, linnsesol) try: levs = dou.load_npa(levstr) if debug: raise IOError() print('loaded the eigenvalues of the linearized system') except IOError: print('computing the eigenvalues of the linearized system') A = asysmat.todense() M = msysmat.todense() levs = spla.eigvals(A, M, overwrite_a=True, check_finite=False) dou.save_npa(levs, levstr) plt.figure(1) # plt.xlim((-25, 15)) # plt.ylim((-50, 50)) plt.plot(np.real(levs), np.imag(levs), '+') plt.show(block=False) if timeint: print('computing LU once...') sysmati = spsla.factorized(sysmat) vfile = dolfin.File(rdir + problemname + 'qdae__vel.pvd') pfile = dolfin.File(rdir + problemname + 'qdae__p.pvd') prvoutdict = dict(V=femp['V'], Q=femp['Q'], vfile=vfile, pfile=pfile, invinds=invinds, diribcs=femp['diribcs'], vp=None, t=None, writeoutput=True) print('doing the time loop...') for t in trange: crhsv = M * old_v + DT * (fv - hmat * np.kron(old_v, old_v)) crhs = np.vstack([crhsv, fp]) vp_new = np.atleast_2d(sysmati(crhs.flatten())).T prvoutdict.update(dict(vp=vp_new, t=t)) dou.output_paraview(**prvoutdict) old_v = vp_new[:NV] print(t, np.linalg.norm(old_v))