def update(self): if not self.active: return with Timer('Ocellaris update hydrostatic pressure'): A = self.tensor_lhs b = assemble(self.form_rhs) if self.null_space is None: # Create vector that spans the null space, and normalize null_space_vector = b.copy() null_space_vector[:] = sqrt(1.0 / null_space_vector.size()) # Create null space basis object and attach to PETSc matrix self.null_space = VectorSpaceBasis([null_space_vector]) as_backend_type(A).set_nullspace(self.null_space) self.null_space.orthogonalize(b) self.solver.solve(A, self.func.vector(), b) if not self.every_timestep: # Give initial values for p, but do not continuously compute p_hydrostatic sim = self.simulation p = sim.data['p'] if p.vector().max() == p.vector().min() == 0.0: sim.log.info( 'Initial pressure field is identically zero, initializing to hydrostatic' ) p.interpolate(self.func) # Disable further hydrostatic pressure calculations self.func.vector().zero() del sim.data['p_hydrostatic'] del self.func self.active = False
def build_pressure_null_space(self): # Prepare function used to correct pressure values null_fcn = Function(self.subspace("p")) null_fcn.vector()[:] = 1.0 # Create vector that spans the null space and normalize null_vec = Vector(null_fcn.vector()) null_vec *= 1.0 / null_vec.norm("l2") # FIXME: Check what are relevant norms for different Krylov methods # Create null space basis object null_space = VectorSpaceBasis([null_vec]) return (null_space, null_fcn)
def build_pressure_null_space(self): # Prepare function used to correct pressure values W_ns = self.function_spaces()[1] # NOTE: The following works only for nodal elements # null_fcn = Function(W_ns) # W_ns.sub(1).dofmap().set(null_fcn.vector(), 1.0) null_fcn = self._get_constant_pressure(W_ns) # Create vector that spans the null space and normalize null_vec = Vector(null_fcn.vector()) null_vec *= 1.0 / null_vec.norm("l2") # FIXME: Check what are relevant norms for different Krylov methods # Create null space basis object null_space = VectorSpaceBasis([null_vec]) return (null_space, null_fcn)
class HydrostaticPressure: def __init__(self, simulation, every_timestep): """ Calculate the hydrostatic pressure """ self.simulation = simulation self.active = True self.every_timestep = every_timestep rho = simulation.data['rho'] g = simulation.data['g'] ph = simulation.data['p_hydrostatic'] # Define the weak form Vp = ph.function_space() p = TrialFunction(Vp) q = TestFunction(Vp) a = dot(grad(p), grad(q)) * dx L = rho * dot(g, grad(q)) * dx self.func = ph self.tensor_lhs = assemble(a) self.form_rhs = Form(L) self.null_space = None self.solver = linear_solver_from_input( simulation, 'solver/p_hydrostatic', default_parameters=DEFAULT_SOLVER_CONFIGURATION, ) def update(self): if not self.active: return with Timer('Ocellaris update hydrostatic pressure'): A = self.tensor_lhs b = assemble(self.form_rhs) if self.null_space is None: # Create vector that spans the null space, and normalize null_space_vector = b.copy() null_space_vector[:] = sqrt(1.0 / null_space_vector.size()) # Create null space basis object and attach to PETSc matrix self.null_space = VectorSpaceBasis([null_space_vector]) as_backend_type(A).set_nullspace(self.null_space) self.null_space.orthogonalize(b) self.solver.solve(A, self.func.vector(), b) if not self.every_timestep: # Give initial values for p, but do not continuously compute p_hydrostatic sim = self.simulation p = sim.data['p'] if p.vector().max() == p.vector().min() == 0.0: sim.log.info( 'Initial pressure field is identically zero, initializing to hydrostatic' ) p.interpolate(self.func) # Disable further hydrostatic pressure calculations self.func.vector().zero() del sim.data['p_hydrostatic'] del self.func self.active = False