# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Validation tests for JAX-CFD.""" import functools from absl.testing import absltest from absl.testing import parameterized import jax.numpy as jnp from jax_cfd.base import advection from jax_cfd.base import diffusion from jax_cfd.base import equations from jax_cfd.base import funcutils from jax_cfd.base import test_util from jax_cfd.base import time_stepping from jax_cfd.base import validation_problems class ValidationTests(test_util.TestCase): @parameterized.named_parameters( dict( testcase_name='_TaylorGreen_SemiImplicitNavierStokes', problem=validation_problems.TaylorGreen( shape=(1024, 1024), density=1., viscosity=1e-3), solver=functools.partial( equations.semi_implicit_navier_stokes, convect=advection.convect_linear), implicit_diffusion=False, max_courant_number=.1, time=10., atol=1e-5), dict( testcase_name='_TaylorGreen_SemiImplicitNavierStokes_rk1', problem=validation_problems.TaylorGreen( shape=(512, 512), density=1., viscosity=1e-2), solver=functools.partial( equations.semi_implicit_navier_stokes, convect=advection.convect_linear, time_stepper=time_stepping.forward_euler, ), implicit_diffusion=False, max_courant_number=.1, time=40., atol=6e-6), dict( testcase_name='_TaylorGreen_SemiImplicitNavierStokes_rk4', problem=validation_problems.TaylorGreen( shape=(512, 512), density=1., viscosity=1e-2), solver=functools.partial( equations.semi_implicit_navier_stokes, convect=advection.convect_linear, time_stepper=time_stepping.classic_rk4, ), implicit_diffusion=False, max_courant_number=.1, time=40., atol=8e-7), dict( testcase_name='_TaylorGreen_ImplicitDiffusionNavierStokes_matmul', problem=validation_problems.TaylorGreen( shape=(1024, 1024), density=1., viscosity=1e-3), solver=functools.partial( equations.implicit_diffusion_navier_stokes, convect=advection.convect_linear, diffusion_solve=functools.partial( diffusion.solve_fast_diag, implementation='matmul'), ), implicit_diffusion=True, max_courant_number=.1, time=10., atol=3e-5), dict( testcase_name='_TaylorGreen_ImplicitDiffusionNavierStokes_fft', problem=validation_problems.TaylorGreen( shape=(1024, 1024), density=1., viscosity=1e-3), solver=functools.partial( equations.implicit_diffusion_navier_stokes, convect=advection.convect_linear, diffusion_solve=functools.partial( diffusion.solve_fast_diag, implementation='fft'), ), implicit_diffusion=True, max_courant_number=.1, time=10., atol=4e-5), dict( testcase_name='_TaylorGreen_ImplicitDiffusionNavierStokes_rfft', problem=validation_problems.TaylorGreen( shape=(1024, 1024), density=1., viscosity=1e-3), solver=functools.partial( equations.implicit_diffusion_navier_stokes, convect=advection.convect_linear, diffusion_solve=functools.partial( diffusion.solve_fast_diag, implementation='rfft'), ), implicit_diffusion=True, max_courant_number=.1, time=10., atol=4e-5), dict( testcase_name='_TaylorGreen_ImplicitDiffusionNavierStokes_cg', problem=validation_problems.TaylorGreen( shape=(1024, 1024), density=1., viscosity=1e-3), solver=functools.partial( equations.implicit_diffusion_navier_stokes, convect=advection.convect_linear, diffusion_solve=functools.partial( diffusion.solve_cg, atol=1e-6, maxiter=512)), implicit_diffusion=True, max_courant_number=.1, time=10., atol=3e-5), dict( testcase_name='_TaylorGreen_ImplicitDiffusionNavierStokes_viscous', problem=validation_problems.TaylorGreen( shape=(1024, 1024), density=1., viscosity=0.5), solver=functools.partial( equations.implicit_diffusion_navier_stokes, convect=advection.convect_linear), implicit_diffusion=True, max_courant_number=.5, time=1.0, atol=6e-4, ), ) def test_accuracy(self, problem, solver, implicit_diffusion, max_courant_number, time, atol): """Test the accuracy of `solver` on the given `problem`. Args: problem: an instance of `validation_problems.Problem`. solver: a callable that takes `density`, `viscosity`, `dt`, `grid`, and `steps`. It returns a callable that takes `velocity`, `pressure_correction` and `force` and returns updated versions of these values at the next time step. implicit_diffusion: whether or not the solver models diffusion implicitly. max_courant_number: a float used to choose the size of the time step `dt` according to the Courant-Friedrichs-Lewy condition. See https://en.wikipedia.org/wiki/Courant-Friedrichs-Lewy_condition. time: the amount of time to run the simulation for. atol: absolute error tolerance per entry. """ v = problem.velocity(0.) dt = equations.dynamic_time_step( v, max_courant_number, problem.viscosity, problem.grid, implicit_diffusion) steps = int(jnp.ceil(time / dt)) navier_stokes = solver(density=problem.density, viscosity=problem.viscosity, dt=dt, grid=problem.grid) v_computed = funcutils.repeated(navier_stokes, steps)(v) v_analytic = problem.velocity(time) for u_c, u_a in zip(v_computed, v_analytic): self.assertAllClose(u_c, u_a, atol=atol) if __name__ == '__main__': absltest.main()