def velocity_update(self): """ Update the velocity predictions with the updated pressure field from the pressure correction equation """ if self.use_local_solver_for_update: # Element-wise projection if self.u_upd_solver is None: self.u_upd_solver = dolfin.LocalSolver( self.eqs_vel_upd[0].form_lhs) self.u_upd_solver.factorize() Vu = self.simulation.data['Vu'] for d in range(self.simulation.ndim): eq = self.eqs_vel_upd[d] b = eq.assemble_rhs() u_new = self.simulation.data['u%d' % d] self.u_upd_solver.solve_local(u_new.vector(), b, Vu.dofmap()) self.niters_u_upd[d] = 0 else: # Global projection for d in range(self.simulation.ndim): eq = self.eqs_vel_upd[d] if self.Au_upd is None: self.Au_upd = eq.assemble_lhs() A = self.Au_upd b = eq.assemble_rhs() u_new = self.simulation.data['u%d' % d] self.niters_u_upd[d] = self.u_upd_solver.solve( A, u_new.vector(), b)
def _setup_divergence(self, vel, method, name='u'): """ Calculate divergence and element to element velocity flux differences on the same edges """ V = df.FunctionSpace(self.mesh, 'DG', 0) n = df.FacetNormal(self.mesh) u, v = df.TrialFunction(V), df.TestFunction(V) # The difference between the flux on the same facet between two different cells a1 = u * v * dx w = dot(vel('+') - vel('-'), n('+')) if method == 'div0': L1 = w * avg(v) * dS else: L1 = abs(w) * avg(v) * dS # The divergence internally in the cell a2 = u * v * dx if method in ('div', 'div0'): L2 = abs(df.div(vel)) * v * dx elif method == 'gradq_avg': L2 = dot(avg(vel), n('+')) * jump(v) * dS - dot(vel, grad(v)) * dx else: raise ValueError('Divergence type %r not supported' % method) # Store for usage in projection storage = self._div[name] = {} storage['dS_solver'] = df.LocalSolver(a1, L1) storage['dx_solver'] = df.LocalSolver(a2, L2) storage['div_dS'] = df.Function(V) storage['div_dx'] = df.Function(V) # Pre-factorize matrices storage['dS_solver'].factorize() storage['dx_solver'].factorize() storage['div_dS'].rename('Divergence_%s_dS' % name, 'Divergence_%s_dS' % name) storage['div_dx'].rename('Divergence_%s_dx' % name, 'Divergence_%s_dx' % name)
def _setup_peclet(self, vel, nu): """ Pe = a*h/(2*nu) where a = mag(vel) """ V = df.FunctionSpace(self.mesh, 'DG', 0) h = self.simulation.data['h'] u, v = df.TrialFunction(V), df.TestFunction(V) a = u * v * dx L = dot(vel, vel)**0.5 * h / (2 * nu) * v * dx # Pre-factorize matrices and store for usage in projection self._peclet_solver = df.LocalSolver(a, L) self._peclet_solver.factorize() self._peclet = df.Function(V)
def __init__(self, expr, V, dxm): """ expr: expression to project V: quadrature function space dxm: dolfin.Measure("dx") that matches V """ dv = df.TrialFunction(V) v_ = df.TestFunction(V) a_proj = df.inner(dv, v_) * dxm b_proj = df.inner(expr, v_) * dxm self.solver = df.LocalSolver(a_proj, b_proj) self.solver.factorize()
def _setup_courant(self, vel, dt): """ Co = a*dt/h where a = mag(vel) """ V = df.FunctionSpace(self.mesh, 'DG', 0) h = self.simulation.data['h'] u, v = df.TrialFunction(V), df.TestFunction(V) a = u * v * dx vmag = sqrt(dot(vel, vel)) L = vmag * dt / h * v * dx # Pre-factorize matrices and store for usage in projection self._courant_solver = df.LocalSolver(a, L) self._courant_solver.factorize() self._courant = df.Function(V)
def solve(self, var, b): x = dolfin.Function(self.test_function().function_space()) # b is a libadjoint object (form or function) (a, L) = (self.data, b.data) # First: check if L is None (meaning zero) if L is None: x_vec = adjlinalg.Vector(x) return x_vec if isinstance(L, dolfin.Function): b_vec = L.vector() L = None else: b_vec = dolfin.assemble(L) # Next: if necessary, create a new solver and add to dictionary idx = a.arguments() if idx not in caching.localsolvers: if dolfin.parameters["adjoint"]["debug_cache"]: dolfin.info_red("Creating new LocalSolver") newsolver = dolfin.LocalSolver( a, None, solver_type=self.solver_parameters["solver_type"]) if self.solver_parameters["factorize"]: newsolver.factorize() caching.localsolvers[idx] = newsolver else: if dolfin.parameters["adjoint"]["debug_cache"]: dolfin.info_green("Reusing LocalSolver") # Get the right solver from the solver dictionary solver = caching.localsolvers[idx] solver.solve_local(x.vector(), b_vec, b.fn_space.dofmap()) x_vec = adjlinalg.Vector(x) return x_vec
def __init__(self, simulation, field_inp): """ A scalar field """ self.simulation = simulation self.read_input(field_inp) # Show the input data simulation.log.info('Creating a sharp field %r' % self.name) simulation.log.info(' Variable: %r' % self.var_name) simulation.log.info(' Local proj: %r' % self.local_projection) simulation.log.info(' Proj. degree: %r' % self.projection_degree) simulation.log.info(' Poly. degree: %r' % self.polynomial_degree) mesh = simulation.data['mesh'] self.V = dolfin.FunctionSpace(mesh, 'DG', self.polynomial_degree) self.func = dolfin.Function(self.V) if self.local_projection: # Represent the jump using a quadrature element quad_elem = dolfin.FiniteElement( 'Quadrature', mesh.ufl_cell(), self.projection_degree, quad_scheme="default", ) xpos, ypos, zpos = self.xpos, self.ypos, self.zpos if simulation.ndim == 2: cpp0 = 'x[0] < %r and x[1] < %r' % (xpos, ypos) else: cpp0 = 'x[0] < %r and x[1] < %r and x[2] < %r' % (xpos, ypos, zpos) cpp = '(%s) ? %r : %r' % (cpp0, self.val_below, self.val_above) e = dolfin.Expression(cpp, element=quad_elem) dx = dolfin.dx(metadata={'quadrature_degree': self.projection_degree}) # Perform the local projection u, v = dolfin.TrialFunction(self.V), dolfin.TestFunction(self.V) a = u * v * dolfin.dx L = e * v * dx ls = dolfin.LocalSolver(a, L) ls.solve_local_rhs(self.func) # Clip values to allowable bounds arr = self.func.vector().get_local() val_min = min(self.val_below, self.val_above) val_max = max(self.val_below, self.val_above) clipped_arr = numpy.clip(arr, val_min, val_max) self.func.vector().set_local(clipped_arr) self.func.vector().apply('insert') else: # Initialise the sharp static field dm = self.V.dofmap() arr = self.func.vector().get_local() above, below = self.val_above, self.val_below xpos, ypos, zpos = self.xpos, self.ypos, self.zpos for cell in dolfin.cells(simulation.data['mesh']): mp = cell.midpoint()[:] dof, = dm.cell_dofs(cell.index()) if ( mp[0] < xpos and mp[1] < ypos and (simulation.ndim == 2 or mp[2] < zpos) ): arr[dof] = below else: arr[dof] = above self.func.vector().set_local(arr) self.func.vector().apply('insert')
def local_project(v, fspace, solver_method: str = "", **kwargs): """ Parameters ---------- v : [type] input field fspace : [type] [description] solver_method : str, optional "LU" or "Cholesky" factorization. LU method used by default. keyword arguments ---------- metadata : dict, optional This can be used to define different quadrature degrees for different terms in a form, and to override other form compiler specific options separately for different terms. By default {} See UFL user manual for more information ** WARNING** : May be over ignored if dx argument is also used. (Non étudié) dx : Measure Impose the dx measure for the projection. This is for example useful to do some kind of interpolation on DG functionspaces. Returns ------- Function Notes ----- Source for this code: https://comet-fenics.readthedocs.io/en/latest/tips_and_tricks.html#efficient-projection-on-dg-or-quadrature-spaces """ metadata = kwargs.get("metadata", {}) dx = kwargs.get("dx", fe.dx(metadata=metadata)) reuse_solver = kwargs.get( "reuse_solver", True ) # Reuse a LocalSolver that already exists id_function_space = ( fspace.id() ) # The id is unique. https://fenicsproject.org/olddocs/dolfin/latest/cpp/d8/df0/classdolfin_1_1Variable.html#details dv = fe.TrialFunction(fspace) v_ = fe.TestFunction(fspace) a_proj = fe.inner(dv, v_) * dx b_proj = fe.inner(v, v_) * dx if solver_method == "LU": solver_type = fe.cpp.fem.LocalSolver.SolverType.LU solver = fe.LocalSolver(a_proj, b_proj, solver_type=solver_type) elif solver_method == "Cholesky": solver_type = fe.cpp.fem.LocalSolver.SolverType.Cholesky solver = fe.LocalSolver(a_proj, b_proj, solver_type=solver_type) else: solver = fe.LocalSolver(a_proj, b_proj) if not (reuse_solver and ((id_function_space, solver_method) in _local_solvers)): solver.factorize() # You can optionally call the factorize() method to pre-calculate the local left-hand side factorizations to speed up repeated applications of the LocalSolver with the same LHS # This class can be used for post-processing solutions, e.g.computing stress fields for visualisation, far more cheaply that using global projections # https://fenicsproject.org/olddocs/dolfin/latest/cpp/de/d86/classdolfin_1_1LocalSolver.html#details _local_solvers.append((id_function_space, solver_method)) u = fe.Function(fspace) solver.solve_local_rhs(u) return u