def add_custom_hook(self, hook_point, hook, description): """ Add other type of hook, must give a string name for the hook name """ verify_key('custom hook point', hook_point, self._custom_hooks) self._custom_hooks[hook_point].append((hook, description))
def read_input(self, field_inp): self.name = field_inp.get_value('name', required_type='string') field_name0 = field_inp.get_value('field0', required_type='string') field_name1 = field_inp.get_value('field1', required_type='string') blend_def = field_inp.get_value('blending_function', required_type='string') verify_key( 'blending field0', field_name0, self.simulation.fields, 'BlendedField %s' % self.name, ) verify_key( 'blending field1', field_name1, self.simulation.fields, 'BlendedField %s' % self.name, ) blend = verify_field_variable_definition(self.simulation, blend_def, 'BlendedField %s' % self.name) self.field0 = self.simulation.fields[field_name0] self.field1 = self.simulation.fields[field_name1] self.blending_function = blend
def read_input(self): """ Read the simulation input """ sim = self.simulation # Create linear solvers self.velocity_solver = linear_solver_from_input( self.simulation, 'solver/u', default_parameters=SOLVER_U_OPTIONS) self.pressure_solver = linear_solver_from_input( self.simulation, 'solver/p', default_parameters=SOLVER_P_OPTIONS) # Lagrange multiplicator or remove null space via PETSc self.remove_null_space = True self.pressure_null_space = None self.use_lagrange_multiplicator = sim.input.get_value( 'solver/use_lagrange_multiplicator', USE_LAGRANGE_MULTIPLICATOR, 'bool') if self.use_lagrange_multiplicator: self.remove_null_space = False # No need for special treatment if the pressure is coupled via outlet BCs if sim.data['outlet_bcs']: self.remove_null_space = False self.use_lagrange_multiplicator = False # Control the form of the governing equations self.use_stress_divergence_form = sim.input.get_value( 'solver/use_stress_divergence_form', USE_STRESS_DIVERGENCE, 'bool') self.use_grad_p_form = sim.input.get_value('solver/use_grad_p_form', USE_GRAD_P_FORM, 'bool') self.use_grad_q_form = sim.input.get_value('solver/use_grad_q_form', USE_GRAD_Q_FORM, 'bool') self.incompressibility_flux_type = sim.input.get_value( 'solver/incompressibility_flux_type', INCOMPRESSIBILITY_FLUX_TYPE, 'string') assert sim.data['Vu'].ufl_element().family( ) == 'Discontinuous Lagrange' # Velocity post_processing self.velocity_postprocessing = sim.input.get_value( 'solver/velocity_postprocessing', BDM, 'string') verify_key('velocity post processing', self.velocity_postprocessing, ('none', BDM), 'SIMPLE solver') # Quasi-steady simulation input self.steady_velocity_eps = sim.input.get_value( 'solver/steady_velocity_stopping_criterion', None, 'float') self.is_steady = self.steady_velocity_eps is not None # How to approximate A_tilde self.num_elements_in_block = sim.input.get_value( 'solver/num_elements_in_A_tilde_block', NUM_ELEMENTS_IN_BLOCK, 'int') self.lump_diagonal = sim.input.get_value( 'solver/lump_A_tilde_diagonal', LUMP_DIAGONAL, 'bool') self.mass_only_A_tilde = sim.input.get_value( 'solver/A_tilde_is_mass_only', MASS_ONLY_A_TILDE, 'bool')
def read_input(self, field_inp): self.name = field_inp.get_value('name', required_type='string') field_name0 = field_inp.get_value('field0', required_type='string') field_name1 = field_inp.get_value('field1', required_type='string') verify_key('field0', field_name0, self.simulation.fields, 'MinField %s' % self.name) verify_key('field1', field_name1, self.simulation.fields, 'MinField %s' % self.name) self.field0 = self.simulation.fields[field_name0] self.field1 = self.simulation.fields[field_name1]
def setup(self): """ Deferred setup tasks that are run after the Navier-Stokes solver has finished its setup """ if self.probe_name is not None: verify_key( 'surface_probe', self.probe_name, self.simulation.probes, 'componentwise slope limiter for %s' % self.vel_name, ) self.surface_probe = self.simulation.probes[self.probe_name] self.simulation.log.info( 'Marking cells for limiting based on probe "%s" for %s' % (self.surface_probe.name, self.vel_name))
def _get_expression(self, name, quad_degree=None): keys = list(self._cpp.keys()) + ['u'] verify_key('variable', name, keys, 'Raschii wave field %r' % self.name) if name not in self._expressions: degree = self.polydeg if quad_degree is None else None expr, updater = OcellarisCppExpression( self.simulation, self._cpp[name], 'Raschii wave field %r' % name, degree, update=False, return_updater=True, quad_degree=quad_degree, ) self._expressions[name] = expr, updater return self._expressions[name][0]
def run_custom_hook(self, hook_point, *args, **kwargs): """ Called by the solver at a custom point Will run all custom hooks in the reverse order they have been added """ verify_key('custom hook point', hook_point, self._custom_hooks) with dolfin.Timer('Ocellaris custom hook %s' % hook_point): for hook, description in self._custom_hooks[hook_point][::-1]: try: hook(*args, **kwargs) except Exception: self.simulation.log.error('Got exception in hook: %s' % description) self.simulation.log.error(traceback.format_exc()) raise # Run any delayed actions self._process_call_after()
def _get_expression(self, name): keys = list(self._cpp.keys()) + ['u', 'uvert'] verify_key('variable', name, keys, 'Wave outflow field %r' % self.name) params = dict(u_above=self.const_speed_above, u_below=self.const_speed_below) if name not in self._expressions: expr, updater = OcellarisCppExpression( self.simulation, self._cpp[name], 'Wave outflow field %r' % name, self.polydeg, update=False, return_updater=True, params=params, ) self._expressions[name] = expr, updater return self._expressions[name][0]
def setup(self): """ Deferred setup tasks that are run after the Navier-Stokes solver has finished its setup """ if self.probe_name is not None: verify_key( 'surface_probe', self.probe_name, self.simulation.probes, 'solenoidal slope limiter for %s' % self.vel_name, ) self.surface_probe = self.simulation.probes[self.probe_name] self.simulation.log.info( 'Marking cells for limiting based on probe "%s" for %s' % (self.surface_probe.name, self.vel_name)) if self.limit_none: self.simulation.log.info('Marking no cells for limiting of %s' % self.vel_name) self.limit_cell[:] = False self.surface_probe = None self.limit_selected_cells_only = False
def add_forcing_zone(simulation, fzones, inp): """ Add a penalty forcing zone to the simulation """ name = inp.get_value('name', required_type='string') ztype = inp.get_value('type', required_type='string') penalty = inp.get_value('penalty', required_type='float') zone_vardef = inp.get_value('zone', required_type='string') target_vardef = inp.get_value('target', required_type='string') plot = inp.get_value('plot', False, required_type='bool') zone = verify_field_variable_definition( simulation, zone_vardef, 'forcing zone %r zone definition' % name) target = verify_field_variable_definition(simulation, target_vardef, 'forcing zone %r target' % name) verify_key( 'forcing zone type', ztype, ('MomentumForcing', 'ScalarForcing'), 'penalty forcing zone %s' % name, ) if ztype == 'MomentumForcing': varname = inp.get_value('variable', 'u', required_type='string') else: varname = inp.get_value('variable', required_type='string') fzones.setdefault(varname, []).append(ForcingZone(name, zone, target, penalty)) if plot: # Save zone blending function to a plot file for easy verification prefix = simulation.input.get_value('output/prefix', '', 'string') pfile = prefix + '_blending_zone_%s.pvd' % name zone.rename('beta', 'beta') dolfin.File(pfile) << zone
def load_mesh(simulation): """ Get the mesh from the simulation input Returns the facet regions contained in the mesh data or None if these do not exist """ inp = simulation.input mesh_type = inp.get_value('mesh/type', required_type='string') mesh_facet_regions = None # For testing COMM_SELF may be specified comm_type = inp.get_value('mesh/mpi_comm', 'WORLD', required_type='string') verify_key('mesh/mpi_comm', comm_type, ('SELF', 'WORLD')) if comm_type == 'WORLD': comm = dolfin.MPI.comm_world else: comm = dolfin.MPI.comm_self if mesh_type == 'Rectangle': simulation.log.info('Creating rectangular mesh') startx = inp.get_value('mesh/startx', 0, 'float') starty = inp.get_value('mesh/starty', 0, 'float') start = dolfin.Point(startx, starty) endx = inp.get_value('mesh/endx', 1, 'float') endy = inp.get_value('mesh/endy', 1, 'float') end = dolfin.Point(endx, endy) Nx = inp.get_value('mesh/Nx', required_type='int') Ny = inp.get_value('mesh/Ny', required_type='int') diagonal = inp.get_value('mesh/diagonal', 'right', required_type='string') mesh = dolfin.RectangleMesh(comm, start, end, Nx, Ny, diagonal) elif mesh_type == 'Box': simulation.log.info('Creating box mesh') startx = inp.get_value('mesh/startx', 0, 'float') starty = inp.get_value('mesh/starty', 0, 'float') startz = inp.get_value('mesh/startz', 0, 'float') start = dolfin.Point(startx, starty, startz) endx = inp.get_value('mesh/endx', 1, 'float') endy = inp.get_value('mesh/endy', 1, 'float') endz = inp.get_value('mesh/endz', 1, 'float') end = dolfin.Point(endx, endy, endz) Nx = inp.get_value('mesh/Nx', required_type='int') Ny = inp.get_value('mesh/Ny', required_type='int') Nz = inp.get_value('mesh/Nz', required_type='int') mesh = dolfin.BoxMesh(comm, start, end, Nx, Ny, Nz) elif mesh_type == 'UnitDisc': simulation.log.info('Creating circular mesh') N = inp.get_value('mesh/N', required_type='int') degree = inp.get_value('mesh/degree', 1, required_type='int') gdim = inp.get_value('mesh/gdim', 2, required_type='int') mesh = dolfin.UnitDiscMesh(comm, N, degree, gdim) if degree > 1 and dolfin.parameters['form_compiler'][ 'representation'] != 'uflacs': simulation.log.warning( 'Using isoparametric elements without uflacs!') elif mesh_type == 'XML': simulation.log.info('Creating mesh from XML file') simulation.log.warning('(deprecated, please use meshio reader)') mesh_file = inp.get_value('mesh/mesh_file', required_type='string') facet_region_file = inp.get_value('mesh/facet_region_file', None, required_type='string') # Load the mesh from file pth = inp.get_input_file_path(mesh_file) mesh = dolfin.Mesh(comm, pth) # Load the facet regions if available if facet_region_file is not None: pth = inp.get_input_file_path(facet_region_file) mesh_facet_regions = dolfin.MeshFunction('size_t', mesh, pth) else: mesh_facet_regions = None elif mesh_type == 'XDMF': simulation.log.info('Creating mesh from XDMF file') simulation.log.warning('(deprecated, please use meshio reader)') mesh_file = inp.get_value('mesh/mesh_file', required_type='string') # Load the mesh from file pth = inp.get_input_file_path(mesh_file) mesh = dolfin.Mesh(comm) with dolfin.XDMFFile(comm, pth) as xdmf: xdmf.read(mesh, False) elif mesh_type == 'HDF5': simulation.log.info('Creating mesh from DOLFIN HDF5 file') h5_file_name = inp.get_value('mesh/mesh_file', required_type='string') with dolfin.HDF5File(comm, h5_file_name, 'r') as h5: # Read mesh mesh = dolfin.Mesh(comm) h5.read(mesh, '/mesh', False) # Read facet regions if h5.has_dataset('/mesh_facet_regions'): mesh_facet_regions = dolfin.FacetFunction('size_t', mesh) h5.read(mesh_facet_regions, '/mesh_facet_regions') else: mesh_facet_regions = None elif mesh_type == 'meshio': simulation.log.info('Creating mesh with meshio reader') file_name = inp.get_value('mesh/mesh_file', required_type='string') file_type = inp.get_value('mesh/meshio_type', None, required_type='string') sort_order = inp.get_value('mesh/sort_order', None, required_type='list(int)') if sort_order: simulation.log.info(' Ordering mesh elements by ' + ', then '.join('xyz'[i] for i in sort_order)) # Read mesh on rank 0 t1 = time.time() mesh = dolfin.Mesh(comm) if comm.rank == 0: # Read a mesh file by use of meshio physical_regions = load_meshio_mesh(mesh, file_name, file_type, sort_order) simulation.log.info(' Read mesh with %d cells in %.2f seconds' % (mesh.num_cells(), time.time() - t1)) else: physical_regions = None # Distribute the mesh if comm.size > 1: physical_regions = comm.bcast(physical_regions) t1 = time.time() simulation.log.info(' Distributing mesh to %d processors' % comm.size) build_distributed_mesh(mesh) simulation.log.info(' Distributed mesh in %.2f seconds' % (time.time() - t1)) else: ocellaris_error('Unknown mesh type', 'Mesh type %r is not supported' % mesh_type) # Optionally move the mesh (for simple grading etc) move = inp.get_value('mesh/move', None, required_type='list(string)') if move is not None: simulation.log.info(' Moving mesh') if len(move) != mesh.geometry().dim(): ocellaris_error( 'Mesh move not correct', 'Length of move field is %d while geometric dimension is %r' % (len(move), mesh.geometry().dim()), ) e_move = dolfin.Expression(move, degree=1) V_move = dolfin.VectorFunctionSpace(mesh, 'CG', 1) f_move = dolfin.interpolate(e_move, V_move) dolfin.ALE.move(mesh, f_move) mesh.bounding_box_tree().build(mesh) # Update the simulation simulation.set_mesh(mesh, mesh_facet_regions) # Load meshio facet regions if mesh_type == 'meshio' and physical_regions: mfr = dolfin.MeshFunction("size_t", mesh, mesh.topology().dim() - 1) conn_FV = simulation.data['connectivity_FV'] vcoords = mesh.coordinates() for ifacet in range(mfr.size()): facet_vertices = conn_FV(ifacet) key = sorted([tuple(vcoords[vidx]) for vidx in facet_vertices]) number = physical_regions.get(tuple(key), 0) mfr[ifacet] = number # Store the loaded regions simulation.data['mesh_facet_regions'] = mfr mesh_facet_regions = mfr # Optionally plot mesh right after loading (for debugging) if simulation.input.get_value('output/plot_mesh', False, 'bool'): prefix = simulation.input.get_value('output/prefix', '', 'string') pfile = prefix + '_mesh.xdmf' simulation.log.info( ' Plotting mesh with current MPI ranks to XDMF file %r' % pfile) V0 = dolfin.FunctionSpace(mesh, 'DG', 0) ranks = dolfin.Function(V0) ranks.vector().set_local(ranks.vector().get_local() * 0 + comm.rank) ranks.vector().apply('insert') ranks.rename('MPI_rank', 'MPI_rank') with dolfin.XDMFFile(comm, pfile) as xdmf: xdmf.write(ranks) # Optionally plot facet regions to file if simulation.input.get_value('output/plot_facet_regions', False, 'bool'): prefix = simulation.input.get_value('output/prefix', '', 'string') pfile = prefix + '_input_facet_regions.xdmf' simulation.log.info( ' Plotting input mesh facet regions to XDMF file %r' % pfile) if mesh_facet_regions is None: simulation.log.warning( 'Cannot plot mesh facet regions, no regions found!') else: with dolfin.XDMFFile(comm, pfile) as xdmf: xdmf.write(mesh_facet_regions)
def __init__(self, simulation, vel_u, vel_name, vel_w, use_cpp=True): """ Use a solenoidal polynomial slope limiter on the convecting velocity field w and and use a prelimiter to limit the convected velocity u and set the target for the convecting velocity w """ from solenoidal import SolenoidalLimiter, COST_FUNCTIONS inp = simulation.input.get_value('slope_limiter/%s' % vel_name, required_type='Input') self.additional_plot_funcs = [] # Verify input V = vel_u[0].function_space() mesh = V.mesh() family = V.ufl_element().family() degree = V.ufl_element().degree() dim, = vel_u.ufl_shape cost_func = simulation.input.get_value('slope_limiter/cost_function', DEFAULT_LIMITER_W, 'string') loc = 'SolenoidalSlopeLimiterVelocity' verify_key('slope limited function', family, ['Discontinuous Lagrange'], loc) verify_key('slope limited degree', degree, (2, ), loc) verify_key('function dim', dim, (2, ), loc) verify_key('topological dimension', mesh.topology().dim(), [2], loc) verify_key('cost function', cost_func, COST_FUNCTIONS, loc) # We expect the convecting velocity as vel2 and the convected as vel assert vel_w is not None # Limit all cells regardless of location? self.limit_none = inp.get_value('limit_no_cells', False, 'bool') # Get the IsoSurface probe used to locate the free surface self.probe_name = inp.get_value('surface_probe', None, 'string') self.surface_probe = None self.limit_selected_cells_only = self.probe_name is not None # Use prelimiter to set (possibly) extended valid bounds and to avoid excessive # limiting of the convecting velocity w. The prelimiter is also used for slope # limiting the convected velocity u. This is not treated with the solenoidal limiter # since we cannot guarantee that all Gibbs oscillations are removed prelimiter_method = inp.get_value('prelimiter', DEFAULT_LIMITER_U, 'string') simulation.log.info( ' Using prelimiter %r for %s and for solenoidal targets' % (prelimiter_method, vel_name)) self.prelimiters = create_component_limiters(simulation, vel_name, vel_u, prelimiter_method) # Cost function options cf_options = {} cf_option_keys = ('out_of_bounds_penalty_fac', 'out_of_bounds_penalty_const') for key in cf_option_keys: if key in inp: cf_options[key] = inp.get_value(key, required_type='float') # Maximum allowed cost for solenoidal limiting of w max_cost = inp.get_value('max_cost', 1e100, 'float') # Maximum allowed cost for solenoidal limiting of u # Normally this is zero and u in only prelimited which # is typically done by a stable Componentwise limter max_cost_u = inp.get_value('max_cost_u', 0.0, 'float') # Store input self.simulation = simulation self.vel_u = vel_u self.vel_w = vel_w self.vel_name = vel_name self.degree = degree self.mesh = mesh self.use_cpp = use_cpp self.cf_options = cf_options self.max_cost = max_cost self.max_cost_u = max_cost_u # Create slope limiter self.sollim = SolenoidalLimiter(V, cost_function=cost_func, use_cpp=use_cpp, cf_options=cf_options) self.limit_cell = self.sollim.limit_cell # Create plot output functions V0 = dolfin.FunctionSpace(self.mesh, 'DG', 0) # Final cost from minimizer per cell self.cell_cost = dolfin.Function(V0) cname = 'SolenoidalCostFunc_%s' % self.vel_name self.cell_cost.rename(cname, cname) self.additional_plot_funcs.append(self.cell_cost) self.active_cells = None if self.limit_selected_cells_only: self.active_cells = dolfin.Function(V0) aname = 'SolenoidalActiveCells_%s' % self.vel_name self.active_cells.rename(aname, aname) self.additional_plot_funcs.append(self.active_cells) # Cell dofs tdim = self.mesh.topology().dim() Ncells = self.mesh.topology().ghost_offset(tdim) dm0 = V0.dofmap() self.cell_dofs_V0 = numpy.array( [int(dm0.cell_dofs(i)) for i in range(Ncells)], int) # Boundary cells where we do not fully trust the prelimiter targets (we trust BCs more) self.skip_target_cells = mark_cell_layers(simulation, V, layers=0) simulation.hooks.add_pre_simulation_hook( self.setup, 'SolenoidalSlopeLimiterVelocity - setup')
def read_input(self): """ Read the simulation input """ sim = self.simulation # Representation of velocity Vu_family = sim.data['Vu'].ufl_element().family() self.vel_is_discontinuous = Vu_family == 'Discontinuous Lagrange' # Create linear solvers self.velocity_solver = linear_solver_from_input( self.simulation, 'solver/u', default_parameters=SOLVER_U_OPTIONS) self.pressure_solver = linear_solver_from_input( self.simulation, 'solver/p', default_parameters=SOLVER_P_OPTIONS) # Velocity update can be performed with local solver for DG velocities self.use_local_solver_for_update = sim.input.get_value( 'solver/u_upd_local', self.vel_is_discontinuous, 'bool') if self.use_local_solver_for_update: self.u_upd_solver = None # Will be set when LHS is ready else: self.u_upd_solver = linear_solver_from_input( self.simulation, 'solver/u_upd', default_parameters=SOLVER_U_OPTIONS) # Get the class to be used for the equation system assembly self.equation_subtype = sim.input.get_value('solver/equation_subtype', EQUATION_SUBTYPE, 'string') verify_key('equation sub-type', self.equation_subtype, EQUATION_SUBTYPES, 'ipcs solver') # Lagrange multiplicator or remove null space via PETSc self.remove_null_space = True self.pressure_null_space = None self.use_lagrange_multiplicator = sim.input.get_value( 'solver/use_lagrange_multiplicator', USE_LAGRANGE_MULTIPLICATOR, 'bool') has_dirichlet = self.simulation.data['dirichlet_bcs'].get( 'p', []) or sim.data['outlet_bcs'] if self.use_lagrange_multiplicator or has_dirichlet: self.remove_null_space = False # No need for special treatment if the pressure is set via Dirichlet conditions somewhere if has_dirichlet: self.use_lagrange_multiplicator = False self.remove_null_space = False # Control the form of the governing equations self.use_stress_divergence_form = sim.input.get_value( 'solver/use_stress_divergence_form', USE_STRESS_DIVERGENCE, 'bool') self.use_grad_p_form = sim.input.get_value('solver/use_grad_p_form', USE_GRAD_P_FORM, 'bool') self.incompressibility_flux_type = sim.input.get_value( 'solver/incompressibility_flux_type', INCOMPRESSIBILITY_FLUX_TYPE, 'string') # Velocity post_processing default_postprocessing = BDM if self.vel_is_discontinuous else None self.velocity_postprocessing = sim.input.get_value( 'solver/velocity_postprocessing', default_postprocessing, 'string') verify_key('velocity post processing', self.velocity_postprocessing, (None, BDM), 'ipcs solver') # Quasi-steady simulation input self.steady_velocity_eps = sim.input.get_value( 'solver/steady_velocity_stopping_criterion', None, 'float') self.is_steady = self.steady_velocity_eps is not None
def __init__(self, simulation, phi_name, phi, skip_cells, boundary_conditions, limiter_input): """ Limit the slope of the given scalar to obtain boundedness """ # Verify input V = phi.function_space() mesh = V.mesh() family = V.ufl_element().family() degree = V.ufl_element().degree() tdim = mesh.topology().dim() gdim = mesh.geometry().dim() loc = 'HierarchalTaylor slope limiter' verify_key('slope limited function', family, ['Discontinuous Lagrange'], loc) verify_key('slope limited degree', degree, (0, 1, 2), loc) verify_key('function shape', phi.ufl_shape, [()], loc) verify_key('topological dimension', mesh.topology().dim(), [2, 3], loc) assert gdim == tdim, ( 'HierarchalTaylor slope limiter requires that ' 'topological and geometrical dimensions are identical') # Read input use_cpp = limiter_input.get_value('use_cpp', True, 'bool') enforce_bounds = limiter_input.get_value('enforce_bounds', False, 'bool') enforce_bcs = limiter_input.get_value('enforce_bcs', True, 'bool') use_weak_bcs = limiter_input.get_value('use_weak_bcs', True, 'bool') trust_robin_dval = limiter_input.get_value('trust_robin_dval', True, 'bool') simulation.log.info(' Enforce global bounds: %r' % enforce_bounds) simulation.log.info(' Enforcing BCs: %r' % enforce_bcs) simulation.log.info(' Using weak BCs: %r' % use_weak_bcs) # Store input self.phi_name = phi_name self.phi = phi self.degree = degree self.mesh = mesh self.boundary_conditions = boundary_conditions self.use_cpp = use_cpp self.enforce_global_bounds = enforce_bounds self.enforce_boundary_conditions = enforce_bcs self.use_weak_bcs = use_weak_bcs self.num_cells_owned = mesh.topology().ghost_offset(tdim) self.ndim = gdim # No limiter needed for piecewice constant functions if self.degree == 0: self.additional_plot_funcs = [] return # Alpha factors are secondary outputs V0 = df.FunctionSpace(self.mesh, 'DG', 0) self.alpha_funcs = [] for i in range(degree): func = df.Function(V0) name = 'SlopeLimiterAlpha%d_%s' % (i + 1, phi_name) func.rename(name, name) self.alpha_funcs.append(func) self.additional_plot_funcs = self.alpha_funcs # Intermediate DG Taylor function space self.taylor = df.Function(V) self.taylor_old = df.Function(V) # Remove given cells from limiter self.limit_cell = numpy.ones(self.num_cells_owned, numpy.intc) if skip_cells is not None: for cid in skip_cells: self.limit_cell[cid] = 0 self.input = SlopeLimiterInput(mesh, V, V0, use_cpp=use_cpp, trust_robin_dval=trust_robin_dval) if use_cpp: self.cpp_mod = self.input.get_cpp_mod()
def read_input(self): """ Read the simulation input """ sim = self.simulation # PISO mode switch self.solver_type = sim.input.get_value('solver/type', required_type='string') # Create linear solvers self.velocity_solver = linear_solver_from_input( self.simulation, 'solver/u', default_parameters=SOLVER_U_OPTIONS) self.pressure_solver = linear_solver_from_input( self.simulation, 'solver/p', default_parameters=SOLVER_P_OPTIONS) # Get the class to be used for the equation system assembly self.equation_subtype = sim.input.get_value('solver/equation_subtype', EQUATION_SUBTYPE, 'string') verify_key( 'equation sub-type', self.equation_subtype, EQUATION_SUBTYPES, 'SIMPLE solver', ) # Lagrange multiplicator or remove null space via PETSc self.remove_null_space = True self.pressure_null_space = None self.use_lagrange_multiplicator = sim.input.get_value( 'solver/use_lagrange_multiplicator', USE_LAGRANGE_MULTIPLICATOR, 'bool') if self.use_lagrange_multiplicator: self.remove_null_space = False # No need for special treatment if the pressure is set via Dirichlet conditions somewhere # No need for any tricks if the pressure is set via Dirichlet conditions somewhere if sim.data['dirichlet_bcs'].get('p', []) or sim.data['outlet_bcs']: self.remove_null_space = False self.use_lagrange_multiplicator = False # Control the form of the governing equations self.use_stress_divergence_form = sim.input.get_value( 'solver/use_stress_divergence_form', USE_STRESS_DIVERGENCE, 'bool') self.use_grad_p_form = sim.input.get_value('solver/use_grad_p_form', USE_GRAD_P_FORM, 'bool') self.use_grad_q_form = sim.input.get_value('solver/use_grad_q_form', USE_GRAD_Q_FORM, 'bool') self.incompressibility_flux_type = sim.input.get_value( 'solver/incompressibility_flux_type', INCOMPRESSIBILITY_FLUX_TYPE, 'string') # Representation of velocity Vu_family = sim.data['Vu'].ufl_element().family() self.vel_is_discontinuous = Vu_family == 'Discontinuous Lagrange' # Velocity post_processing default_postprocessing = BDM if self.vel_is_discontinuous else None self.velocity_postprocessing = sim.input.get_value( 'solver/velocity_postprocessing', default_postprocessing, 'string') self.project_rhs = sim.input.get_value('solver/project_rhs', PROJECT_RHS, 'bool') verify_key( 'velocity post processing', self.velocity_postprocessing, ('none', BDM), 'SIMPLE solver', ) # Quasi-steady simulation input self.steady_velocity_eps = sim.input.get_value( 'solver/steady_velocity_stopping_criterion', None, 'float') self.is_steady = self.steady_velocity_eps is not None # How to approximate A_tilde self.num_elements_in_block = sim.input.get_value( 'solver/num_elements_in_A_tilde_block', NUM_ELEMENTS_IN_BLOCK, 'int') self.lump_diagonal = sim.input.get_value( 'solver/lump_A_tilde_diagonal', LUMP_DIAGONAL, 'bool')
def read_input(self): """ Read the simulation input """ sim = self.simulation # Create linear solvers self.velocity_solver = linear_solver_from_input( self.simulation, 'solver/u', default_parameters=SOLVER_U_OPTIONS) self.pressure_solver = linear_solver_from_input( self.simulation, 'solver/p', default_parameters=SOLVER_P_OPTIONS) # Lagrange multiplicator or remove null space via PETSc self.remove_null_space = True self.pressure_null_space = None self.use_lagrange_multiplicator = sim.input.get_value( 'solver/use_lagrange_multiplicator', USE_LAGRANGE_MULTIPLICATOR, 'bool') if self.use_lagrange_multiplicator: self.remove_null_space = False # No need for special treatment if the pressure is coupled via outlet BCs if sim.data['outlet_bcs']: self.remove_null_space = False self.use_lagrange_multiplicator = False # Control the form of the governing equations self.use_stress_divergence_form = sim.input.get_value( 'solver/use_stress_divergence_form', USE_STRESS_DIVERGENCE, 'bool') self.use_grad_p_form = sim.input.get_value('solver/use_grad_p_form', USE_GRAD_P_FORM, 'bool') self.use_grad_q_form = sim.input.get_value('solver/use_grad_q_form', USE_GRAD_Q_FORM, 'bool') self.incompressibility_flux_type = sim.input.get_value( 'solver/incompressibility_flux_type', INCOMPRESSIBILITY_FLUX_TYPE, 'string') # Representation of velocity Vu_family = sim.data['Vu'].ufl_element().family() self.vel_is_discontinuous = Vu_family == 'Discontinuous Lagrange' # Velocity post_processing default_postprocessing = BDM if self.vel_is_discontinuous else 'none' self.velocity_postprocessing = sim.input.get_value( 'solver/velocity_postprocessing', default_postprocessing, 'string') verify_key('velocity post processing', self.velocity_postprocessing, ('none', BDM), 'IPCS-A solver') # What types of mass matrices to produce self.project_initial_velocity = sim.input.get_value( 'solver/project_initial_velocity', False, 'bool') self.splitting_approximation = sim.input.get_value( 'solver/splitting_approximation', SPLIT_APPROX_DEFAULT, 'string') verify_key( 'solver/mass_approximation', self.splitting_approximation, ( SPLIT_APPROX_MASS_WITH_RHO, SPLIT_APPROX_MASS_UNSCALED, SPLIT_APPROX_MASS_MIN_RHO, SPLIT_APPROX_BLOCK_DIAG_MA, ), 'IPCS-A solver', ) self.make_unscaled_M = (self.project_initial_velocity or self.splitting_approximation == SPLIT_APPROX_MASS_UNSCALED) # Quasi-steady simulation input self.steady_velocity_eps = sim.input.get_value( 'solver/steady_velocity_stopping_criterion', None, 'float') self.is_steady = self.steady_velocity_eps is not None