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 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_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 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_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 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_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 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 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))