def test_make_incompressible_gradients_equal_tf_torch(self): DOMAIN = Domain(x=16, y=16, boundaries=OPEN, bounds=Box[0:100, 0:100]) # TODO CLOSED solve fails because div is not subtracted from dx velocity0 = DOMAIN.staggered_grid(Noise(vector=2)) grads = [] for backend in [TF_BACKEND, TORCH_BACKEND]: with backend: velocity = param = velocity0.with_(values=math.tensor(velocity0.values)) with math.record_gradients(param.values): solve = math.LinearSolve() velocity, _, _, _ = fluid.make_incompressible(velocity, DOMAIN, solve_params=solve) loss = field.l2_loss(velocity) assert math.isfinite(loss) grad = math.gradients(loss, param.values) assert math.all(math.isfinite(grad)) grads.append(grad) math.assert_close(*grads, abs_tolerance=1e-5)
def lies_inside(self, location): lower, upper = math.batch_align([self.lower, self.upper], 1, location) bool_inside = (location >= lower) & (location <= upper) return math.all(bool_inside, axis=-1, keepdims=True)
def lies_inside(self, location): bool_inside = (location >= self.lower) & (location <= self.upper) return math.all(bool_inside, 'vector')
def __eq__(self, other): return isinstance(other, Scene) and math.all(other._paths == self._paths)
def value_at(self, global_position): lower, upper = math.batch_align([self.lower, self.upper], 1, global_position) bool_inside = (global_position >= lower) & (global_position <= upper) bool_inside = math.all(bool_inside, axis=-1, keepdims=True) return math.to_float(bool_inside)
def make_incompressible(velocity: Grid, domain: Domain, obstacles: tuple or list = (), solve_params: math.LinearSolve = math.LinearSolve( None, 1e-3), pressure_guess: CenteredGrid = None): """ Projects the given velocity field by solving for the pressure and subtracting its gradient. This method is similar to :func:`field.divergence_free()` but differs in how the boundary conditions are specified. Args: velocity: Vector field sampled on a grid domain: Used to specify boundary conditions obstacles: List of Obstacles to specify boundary conditions inside the domain (Default value = ()) pressure_guess: Initial guess for the pressure solve solve_params: Parameters for the pressure solve Returns: velocity: divergence-free velocity of type `type(velocity)` pressure: solved pressure field, `CenteredGrid` iterations: Number of iterations required to solve for the pressure divergence: divergence field of input velocity, `CenteredGrid` """ input_velocity = velocity active = domain.grid( HardGeometryMask(~union(*[obstacle.geometry for obstacle in obstacles])), extrapolation=domain.boundaries['active_extrapolation']) accessible = domain.grid( active, extrapolation=domain.boundaries['accessible_extrapolation']) hard_bcs = field.stagger(accessible, math.minimum, domain.boundaries['accessible_extrapolation'], type=type(velocity)) velocity = layer_obstacle_velocities(velocity * hard_bcs, obstacles).with_( extrapolation=domain.boundaries['near_vector_extrapolation']) div = divergence(velocity) if domain.boundaries[ 'near_vector_extrapolation'] == math.extrapolation.BOUNDARY: div -= field.mean(div) # Solve pressure def laplace(p): grad = gradient(p, type(velocity)) grad *= hard_bcs grad = grad.with_( extrapolation=domain.boundaries['near_vector_extrapolation']) div = divergence(grad) lap = where(active, div, p) return lap pressure_guess = pressure_guess if pressure_guess is not None else domain.scalar_grid( 0) converged, pressure, iterations = field.solve(laplace, y=div, x0=pressure_guess, solve_params=solve_params, constants=[active, hard_bcs]) if math.all_available(converged) and not math.all(converged): raise AssertionError( f"pressure solve did not converge after {iterations} iterations\nResult: {pressure.values}" ) # Subtract grad pressure gradp = field.gradient(pressure, type=type(velocity)) * hard_bcs velocity = (velocity - gradp).with_(extrapolation=input_velocity.extrapolation) return velocity, pressure, iterations, div
def lies_inside(self, location): bool_inside = (location >= self.lower) & (location <= self.upper) bool_inside = math.all(bool_inside, 'vector') bool_inside = math.any( bool_inside, self.shape.instance) # union for instance dimensions return bool_inside
def __eq__(self, other): return isinstance(other, Sphere) \ and self._shape == other.shape \ and math.all(self._radius == other.radius) \ and math.all(self._center == other.center)
def test_all(self): for backend in BACKENDS: with backend: math.assert_close(math.all(math.tensor([[False, True], [True, True]], spatial('y,x')), dim='x'), [False, True]) math.assert_close(math.all(math.tensor([[False, True], [True, True]], spatial('y,x')), dim='x,y'), False) math.assert_close(math.all(math.tensor([[False, True], [True, True]], spatial('y,x'))), False)