From f58d60c40377d4b336fd54adec856f1208d82108 Mon Sep 17 00:00:00 2001
From: Rudolf Weeber <weeber@icp.uni-stuttgart.de>
Date: Wed, 20 Nov 2019 15:37:56 +0100
Subject: [PATCH] Test for fluctuating LB, avg temperature and velocity
 distribution

---
 lbmpy_tests/test_fluctuating_lb.py | 94 ++++++++++++++++++++++++++++++
 1 file changed, 94 insertions(+)
 create mode 100644 lbmpy_tests/test_fluctuating_lb.py

diff --git a/lbmpy_tests/test_fluctuating_lb.py b/lbmpy_tests/test_fluctuating_lb.py
new file mode 100644
index 0000000..c47c8e8
--- /dev/null
+++ b/lbmpy_tests/test_fluctuating_lb.py
@@ -0,0 +1,94 @@
+"""
+This tests that for the thermalized LB (MRT with 15 equal relaxation times),
+the correct temperature is obtained and the velocity distribution matches
+the Maxwell-Boltzmann distribution
+"""
+
+
+import pystencils as ps
+from lbmpy.lbstep import LatticeBoltzmannStep
+from lbmpy.creationfunctions import create_lb_collision_rule
+from lbmpy.relaxationrates import relaxation_rate_from_lattice_viscosity, relaxation_rate_from_magic_number
+import numpy as np
+import pickle
+import gzip
+from time import time
+
+
+def single_component_maxwell(x1, x2, kT):
+    """Integrate the probability density from x1 to x2 using the trapezoidal rule"""
+    x = np.linspace(x1, x2, 1000)
+    return np.trapz(np.exp(-x**2 / (2. * kT)), x) / np.sqrt(2. * np.pi * kT)
+
+
+def run_scenario(scenario, steps):
+    scenario.pre_run()
+    for t in range(scenario.time_steps_run, scenario.time_steps_run + steps):
+        scenario.kernel_params['time_step'] = t
+        scenario.time_step()
+    scenario.post_run()
+    scenario.time_steps_run += steps
+
+
+def create_scenario(domain_size, temperature=None, viscosity=None, seed=2, target='cpu', openmp=4, method=None, num_rel_rates=None):
+    rr = [relaxation_rate_from_lattice_viscosity(viscosity)]
+    rr = rr*num_rel_rates
+    cr = create_lb_collision_rule(
+        stencil='D3Q19', compressible=True,
+        method=method, relaxation_rates=rr,
+        fluctuating={'temperature': temperature, 'seed': seed},
+        optimization={'cse_global': True, 'split': False,
+                      'cse_pdfs': True, 'vectorization': True}
+    )
+    return LatticeBoltzmannStep(periodicity=(True, True, True), domain_size=domain_size, compressible=True, stencil='D3Q19', collision_rule=cr, optimization={'target': target, 'openmp': openmp})
+
+
+def run_for_method(method, num_rel_rates):
+    print("Testing", method)
+    # Unit conversions (MD to lattice) for parameters known to work with Espresso
+    agrid = 1.
+    m = 1.  # mass per node
+    tau = 0.01  # time step
+    temperature = 4. / (m * agrid**2/tau**2)
+    viscosity = 3. * tau / agrid**2
+    n = 8
+    sc = create_scenario((n, n, n), viscosity=viscosity, temperature=temperature,
+                         target='cpu', openmp=4, method=method, num_rel_rates=num_rel_rates)
+    assert np.average(sc.velocity[:, :, :]) == 0.
+
+    # Warmup
+    run_scenario(sc, steps=500)
+    # sampling:
+    steps = 20000
+    v = np.zeros((steps, n, n, n, 3))
+    for i in range(steps):
+        run_scenario(sc, steps=2)
+        v[i, :, :, :, :] = np.copy(sc.velocity[:, :, :, :])
+
+    v = v.reshape((steps*n*n*n, 3))
+    np.testing.assert_allclose(np.mean(v, axis=0), [0, 0, 0], atol=6E-7)
+    np.testing.assert_allclose(
+        np.var(v, axis=0), [temperature, temperature, temperature], rtol=1E-2)
+    v_hist, v_bins = np.histogram(v, bins=11, range=(-.08, .08), density=True)
+
+    # Calculate expected values from single
+    v_expected = []
+    for i in range(len(v_hist)):
+        # Maxwell distribution
+        res = np.exp(-v_bins[i]**2/(2.*temperature)) / \
+            np.sqrt(2*np.pi*temperature)
+        res = 1./(v_bins[i+1]-v_bins[i]) * \
+            single_component_maxwell(v_bins[i], v_bins[i+1], temperature)
+        v_expected.append(res)
+    v_expected = np.array(v_expected)
+
+    # 8% accuracy on the entire histogram
+    np.testing.assert_allclose(v_hist, v_expected, rtol=0.08)
+    # 0.5% accuracy on the middle part
+    remove = 3
+    np.testing.assert_allclose(
+        v_hist[remove:-remove], v_expected[remove:-remove], rtol=0.005)
+
+
+def test_mrt():
+    run_for_method('mrt', 15)
-- 
GitLab