def burgers_spacedisc(N=10, nu=None, x0=0.0, xE=1.0, retfemdict=False, condensemats=True): mesh = dolfin.IntervalMesh(N, x0, xE) V = dolfin.FunctionSpace(mesh, 'CG', 1) u = dolfin.TrialFunction(V) v = dolfin.TestFunction(V) # boundaries and conditions ugamma = dolfin.Expression('0', degree=1) def _spaceboundary(x, on_boundary): return on_boundary diribc = dolfin.DirichletBC(V, ugamma, _spaceboundary) mass = assemble(v*u*dx) stif = assemble(nu*inner(nabla_grad(v), nabla_grad(u))*dx) M = dts.mat_dolfin2sparse(mass) A = dts.mat_dolfin2sparse(stif) M, _, bcdict = dts.condense_velmatsbybcs(M, [diribc], return_bcinfo=True) ininds = bcdict['ininds'] A, rhsa = dts.condense_velmatsbybcs(A, [diribc]) def burger_nonl(vvec, t): v0 = expandvfunc(vvec, V=V, ininds=ininds) bnl = assemble(0.5*v*((v0*v0).dx(0))*dx) return bnl.array()[ininds] if retfemdict: return M, A, rhsa, burger_nonl, dict(V=V, diribc=diribc, ininds=ininds) else: return M, A, rhsa, burger_nonl
def get_burgertensor_spacecomp(V=None, podmat=None, ininds=None, diribc=None, Ukyleft=None, bwd=False, **kwargs): if not podmat.shape[0] == len(ininds): raise Warning("Looks like this is not the right POD basis") if Ukyleft is None: Ukyleft = podmat v = dolfin.TestFunction(V) u = dolfin.TrialFunction(V) if bwd: uvvdxl = [] for ui in podmat.T: hatui = expandvfunc(ui, V=V, ininds=ininds) uivvdx = assemble(hatui*v*((u).dx(0))*dx) Uivvdx = dts.mat_dolfin2sparse(uivvdx) Uivvdx, _ = dts.condense_velmatsbybcs(Uivvdx, [diribc]) uvvdxl.append(np.dot(Ukyleft.T, Uivvdx*podmat)) else: uvvdxl = [] for ui in podmat.T: hatui = expandvfunc(ui, V=V, ininds=ininds) uivvdx = assemble(0.5*hatui*((v*u).dx(0))*dx) Uivvdx = dts.mat_dolfin2sparse(uivvdx) Uivvdx, _ = dts.condense_velmatsbybcs(Uivvdx, [diribc]) uvvdxl.append(np.dot(Ukyleft.T, Uivvdx*podmat)) return uvvdxl
def get_v_conv_conts(prev_v=None, V=None, invinds=None, diribcs=None, Picard=False): """ get and condense the linearized convection to be used in a Newton scheme .. math:: (u \\cdot \\nabla) u \\to (u_0 \\cdot \\nabla) u + \ (u \\cdot \\nabla) u_0 - (u_0 \\cdot \\nabla) u_0 or in a Picard scheme .. math:: (u \\cdot \\nabla) u \\to (u_0 \\cdot \\nabla) u Parameters ---------- prev_v : (N,1) ndarray convection velocity V : dolfin.VectorFunctionSpace FEM space of the velocity invinds : (N,) ndarray or list indices of the inner nodes diribcs : list of dolfin Dirichlet boundary conditons Picard : boolean whether Picard linearization is applied, defaults to `False` Returns ------- convc_mat : (N,N) sparse matrix representing the linearized convection at the inner nodes rhs_con : (N,1) array representing :math:`(u_0 \\cdot \\nabla )u_0` at the inner nodes rhsv_conbc : (N,1) ndarray representing the boundary conditions """ N1, N2, rhs_con = dts.get_convmats(u0_vec=prev_v, V=V, invinds=invinds, diribcs=diribcs) if Picard: convc_mat, rhsv_conbc = \ dts.condense_velmatsbybcs(N1, diribcs) return convc_mat, 0 * rhs_con[invinds, ], rhsv_conbc else: convc_mat, rhsv_conbc = \ dts.condense_velmatsbybcs(N1 + N2, diribcs) return convc_mat, rhs_con[invinds, ], rhsv_conbc
def get_v_conv_conts(prev_v=None, V=None, invinds=None, diribcs=None, Picard=False): """ get and condense the linearized convection to be used in a Newton scheme .. math:: (u \\cdot \\nabla) u \\to (u_0 \\cdot \\nabla) u + \ (u \\cdot \\nabla) u_0 - (u_0 \\cdot \\nabla) u_0 or in a Picard scheme .. math:: (u \\cdot \\nabla) u \\to (u_0 \\cdot \\nabla) u Parameters ---------- prev_v : (N,1) ndarray convection velocity V : dolfin.VectorFunctionSpace FEM space of the velocity invinds : (N,) ndarray or list indices of the inner nodes diribcs : list of dolfin Dirichlet boundary conditons Picard : boolean whether Picard linearization is applied, defaults to `False` Returns ------- convc_mat : (N,N) sparse matrix representing the linearized convection at the inner nodes rhs_con : (N,1) array representing :math:`(u_0 \\cdot \\nabla )u_0` at the inner nodes rhsv_conbc : (N,1) ndarray representing the boundary conditions """ N1, N2, rhs_con = dts.get_convmats(u0_vec=prev_v, V=V, invinds=invinds, diribcs=diribcs) if Picard: convc_mat, rhsv_conbc = \ dts.condense_velmatsbybcs(N1, diribcs) return convc_mat, 0*rhs_con[invinds, ], rhsv_conbc else: convc_mat, rhsv_conbc = \ dts.condense_velmatsbybcs(N1 + N2, diribcs) return convc_mat, rhs_con[invinds, ], rhsv_conbc
def get_sysmats(problem='drivencavity', N=10, scheme=None, ppin=None, Re=None, nu=None, bccontrol=False, mergerhs=False, onlymesh=False): """ retrieve the system matrices for stokes flow Parameters ---------- problem : {'drivencavity', 'cylinderwake'} problem class N : int mesh parameter nu : real, optional kinematic viscosity, is set to `L/Re` if `Re` is provided Re : real, optional Reynoldsnumber, is set to `L/nu` if `nu` is provided bccontrol : boolean, optional whether to consider boundary control via penalized Robin \ defaults to `False` mergerhs : boolean, optional whether to merge the actual rhs and the contribution from the \ boundary conditions into one rhs, defaults to `False` onlymesh : boolean, optional whether to only return `femp`, containing the mesh and FEM spaces, \ defaults to `False` Returns ------- femp : dict with the keys: * `V`: FEM space of the velocity * `Q`: FEM space of the pressure * `diribcs`: list of the (Dirichlet) boundary conditions * `bcinds`: indices of the boundary nodes * `bcvals`: values of the boundary nodes * `invinds`: indices of the inner nodes * `fv`: right hand side of the momentum equation * `fp`: right hand side of the continuity equation * `charlen`: characteristic length of the setup * `nu`: the kinematic viscosity * `Re`: the Reynolds number * `odcoo`: dictionary with the coordinates of the domain of \ observation * `cdcoo`: dictionary with the coordinates of the domain of \ * `ppin` : {int, None} which dof of `p` is used to pin the pressure, typically \ `-1` for internal flows, and `None` for flows with outflow control stokesmatsc : dict a dictionary of the condensed matrices: * `M`: the mass matrix of the velocity space, * `MP`: the mass matrix of the pressure space, * `A`: the stiffness matrix, * `JT`: the gradient matrix, and * `J`: the divergence matrix * `Jfull`: the uncondensed divergence matrix and, if `bccontrol=True`, the boundary control matrices that weakly \ impose `Arob*v = Brob*u`, where * `Arob`: contribution to `A` * `Brob`: input operator `if mergerhs` rhsd : dict `rhsd_vfrc` and `rhsd_stbc` merged `else` rhsd_vfrc : dict of the dirichlet and pressure fix reduced right hand sides rhsd_stbc : dict of the contributions of the boundary data to the rhs: * `fv`: contribution to momentum equation, * `fp`: contribution to continuity equation Examples -------- femp, stokesmatsc, rhsd_vfrc, rhsd_stbc \ = get_sysmats(problem='drivencavity', N=10, nu=1e-2) """ problemdict = dict(drivencavity=drivcav_fems, cylinderwake=cyl_fems) problemfem = problemdict[problem] femp = problemfem(N, scheme=scheme, bccontrol=bccontrol) if onlymesh: return femp # setting some parameters if Re is not None: nu = femp['charlen']/Re else: Re = femp['charlen']/nu if bccontrol: cbclist = femp['contrbcssubdomains'] cbshapefuns = femp['contrbcsshapefuns'] else: cbclist, cbshapefuns = None, None stokesmats = dts.get_stokessysmats(femp['V'], femp['Q'], nu, cbclist=cbclist, cbshapefuns=cbshapefuns, bccontrol=bccontrol) rhsd_vf = dts.setget_rhs(femp['V'], femp['Q'], femp['fv'], femp['fp'], t=0) # remove the freedom in the pressure if required if problem == 'cylinderwake': print('cylinderwake: pressure need not be pinned') if ppin is not None: raise UserWarning('pinning the p will give wrong results') elif ppin is None: print('pressure is not pinned - `J` may be singular for internal flow') elif ppin == -1: stokesmats['J'] = stokesmats['J'][:-1, :][:, :] stokesmats['JT'] = stokesmats['JT'][:, :-1][:, :] rhsd_vf['fp'] = rhsd_vf['fp'][:-1, :] print('pressure pinned at last dof `-1`') else: raise NotImplementedError('Cannot pin `p` other than at `-1`') # reduce the matrices by resolving the BCs (stokesmatsc, rhsd_stbc, invinds, bcinds, bcvals) = dts.condense_sysmatsbybcs(stokesmats, femp['diribcs']) stokesmatsc.update({'Jfull': stokesmats['J']}) # pressure freedom and dirichlet reduced rhs rhsd_vfrc = dict(fpr=rhsd_vf['fp'], fvc=rhsd_vf['fv'][invinds, ]) if bccontrol: Arob, fvrob = dts.condense_velmatsbybcs(stokesmats['amatrob'], femp['diribcs']) if np.linalg.norm(fvrob) > 1e-15: raise UserWarning('diri and control bc must not intersect') Brob = stokesmats['bmatrob'][invinds, :] stokesmatsc.update({'Brob': Brob, 'Arob': Arob}) # add the info on boundary and inner nodes bcdata = {'bcinds': bcinds, 'bcvals': bcvals, 'invinds': invinds, 'ppin': ppin} femp.update(bcdata) femp.update({'nu': nu}) femp.update({'Re': Re}) if mergerhs: rhsd = dict(fv=rhsd_vfrc['fvc']+rhsd_stbc['fv'], fp=rhsd_vfrc['fpr']+rhsd_stbc['fp']) return femp, stokesmatsc, rhsd else: return femp, stokesmatsc, rhsd_vfrc, rhsd_stbc
def get_sysmats(problem='drivencavity', N=10, scheme=None, ppin=None, Re=None, nu=None, bccontrol=False, mergerhs=False, onlymesh=False): """ retrieve the system matrices for stokes flow Parameters ---------- problem : {'drivencavity', 'cylinderwake'} problem class N : int mesh parameter nu : real, optional kinematic viscosity, is set to `L/Re` if `Re` is provided Re : real, optional Reynoldsnumber, is set to `L/nu` if `nu` is provided bccontrol : boolean, optional whether to consider boundary control via penalized Robin \ defaults to `False` mergerhs : boolean, optional whether to merge the actual rhs and the contribution from the \ boundary conditions into one rhs onlymesh : boolean, optional whether to only return `femp`, containing the mesh and FEM spaces, \ defaults to `False` Returns ------- femp : dict with the keys: * `V`: FEM space of the velocity * `Q`: FEM space of the pressure * `diribcs`: list of the (Dirichlet) boundary conditions * `bcinds`: indices of the boundary nodes * `bcvals`: values of the boundary nodes * `invinds`: indices of the inner nodes * `fv`: right hand side of the momentum equation * `fp`: right hand side of the continuity equation * `charlen`: characteristic length of the setup * `nu`: the kinematic viscosity * `Re`: the Reynolds number * `odcoo`: dictionary with the coordinates of the domain of \ observation * `cdcoo`: dictionary with the coordinates of the domain of \ * `ppin` : {int, None} which dof of `p` is used to pin the pressure, typically \ `-1` for internal flows, and `None` for flows with outflow control stokesmatsc : dict a dictionary of the condensed matrices: * `M`: the mass matrix of the velocity space, * `A`: the stiffness matrix, * `JT`: the gradient matrix, and * `J`: the divergence matrix * `Jfull`: the uncondensed divergence matrix and, if `bccontrol=True`, the boundary control matrices that weakly \ impose `Arob*v = Brob*u`, where * `Arob`: contribution to `A` * `Brob`: input operator `if mergerhs` rhsd : dict `rhsd_vfrc` and `rhsd_stbc` merged `else` rhsd_vfrc : dict of the dirichlet and pressure fix reduced right hand sides rhsd_stbc : dict of the contributions of the boundary data to the rhs: * `fv`: contribution to momentum equation, * `fp`: contribution to continuity equation Examples -------- femp, stokesmatsc, rhsd_vfrc, rhsd_stbc \ = get_sysmats(problem='drivencavity', N=10, nu=1e-2) """ problemdict = dict(drivencavity=drivcav_fems, cylinderwake=cyl_fems) problemfem = problemdict[problem] femp = problemfem(N, scheme=scheme, bccontrol=bccontrol) if onlymesh: return femp # setting some parameters if Re is not None: nu = femp['charlen']/Re else: Re = femp['charlen']/nu if bccontrol: cbclist = femp['contrbcssubdomains'] cbshapefuns = femp['contrbcsshapefuns'] else: cbclist, cbshapefuns = None, None stokesmats = dts.get_stokessysmats(femp['V'], femp['Q'], nu, cbclist=cbclist, cbshapefuns=cbshapefuns, bccontrol=bccontrol) rhsd_vf = dts.setget_rhs(femp['V'], femp['Q'], femp['fv'], femp['fp'], t=0) # remove the freedom in the pressure if required if problem == 'cylinderwake': print 'cylinderwake: pressure need not be pinned' if ppin is not None: raise UserWarning('pinning the p will give wrong results') elif ppin is None: print 'pressure is not pinned - `J` may be singular for internal flow' elif ppin == -1: stokesmats['J'] = stokesmats['J'][:-1, :][:, :] stokesmats['JT'] = stokesmats['JT'][:, :-1][:, :] rhsd_vf['fp'] = rhsd_vf['fp'][:-1, :] print 'pressure pinned at last dof `-1`' else: raise NotImplementedError('Cannot pin `p` other than at `-1`') # reduce the matrices by resolving the BCs (stokesmatsc, rhsd_stbc, invinds, bcinds, bcvals) = dts.condense_sysmatsbybcs(stokesmats, femp['diribcs']) stokesmatsc.update({'Jfull': stokesmats['J']}) # pressure freedom and dirichlet reduced rhs rhsd_vfrc = dict(fpr=rhsd_vf['fp'], fvc=rhsd_vf['fv'][invinds, ]) if bccontrol: Arob, fvrob = dts.condense_velmatsbybcs(stokesmats['amatrob'], femp['diribcs']) if np.linalg.norm(fvrob) > 1e-15: raise UserWarning('diri and control bc must not intersect') Brob = stokesmats['bmatrob'][invinds, :] stokesmatsc.update({'Brob': Brob, 'Arob': Arob}) # add the info on boundary and inner nodes bcdata = {'bcinds': bcinds, 'bcvals': bcvals, 'invinds': invinds, 'ppin': ppin} femp.update(bcdata) femp.update({'nu': nu}) femp.update({'Re': Re}) if mergerhs: rhsd = dict(fv=rhsd_vfrc['fvc']+rhsd_stbc['fv'], fp=rhsd_vfrc['fpr']+rhsd_stbc['fp']) return femp, stokesmatsc, rhsd else: return femp, stokesmatsc, rhsd_vfrc, rhsd_stbc
def vdxop(vvec): v0 = expandvfunc(vvec, V=V, ininds=ininds) bnl = assemble((v*v0*u.dx(0))*dx) Bnl = dts.mat_dolfin2sparse(bnl) Bnl, rhsa = dts.condense_velmatsbybcs(Bnl, [diribc]) return Bnl