def test_field_labels(): """ test the FieldCollection.labels property """ grid = UnitGrid([5]) s1 = ScalarField(grid, label="s1") s2 = ScalarField(grid) fc = FieldCollection([s1, s2]) assert fc.labels == ["s1", None] assert len(fc.labels) == 2 assert fc.labels[0] == "s1" fc.labels = ["a", "b"] assert fc.labels == ["a", "b"] fc.labels[0] = "c" assert fc.labels == ["c", "b"] assert str(fc.labels) == str(["c", "b"]) assert repr(fc.labels) == repr(["c", "b"]) assert fc.labels[0:1] == ["c"] assert fc.labels[:] == ["c", "b"] fc.labels[0:1] = "d" assert fc.labels == ["d", "b"] fc.labels[:] = "a" assert fc.labels == ["a", "a"] labels = fc.labels[:] labels[0] = "e" assert fc.labels == ["a", "a"] fc = FieldCollection([s1, s2], labels=[None, "b"]) assert fc.labels == [None, "b"] fc = FieldCollection([s1, s2], labels=["a", "b"]) assert fc.labels == ["a", "b"]
def test_interactive_collection_plotting(): """ test the interactive plotting """ grid = UnitGrid([3, 3]) sf = ScalarField.random_uniform(grid, 0.1, 0.9) vf = VectorField.random_uniform(grid, 0.1, 0.9) field = FieldCollection([sf, vf]) field.plot_interactive(viewer_args={"show": False, "close": True})
def test_collection_1_field(): """ test field collections with only one field """ grid = UnitGrid([3]) s1 = ScalarField(grid, label="a") fc = FieldCollection([s1]) assert fc.labels == ["a"] fc.plot()
def test_shapes_nfields(example_grid): """ test single component field """ for num in [1, 3]: fields = [ScalarField.random_uniform(example_grid) for _ in range(num)] field = FieldCollection(fields) data_shape = (num,) + example_grid.shape np.testing.assert_equal(field.data.shape, data_shape) for pf_single in field: np.testing.assert_equal(pf_single.data.shape, example_grid.shape) field_c = field.copy() np.testing.assert_allclose(field.data, field_c.data) assert field.grid == field_c.grid
def test_collection_plotting(): """ test simple plotting of various fields on various grids """ grid = UnitGrid([5]) s1 = ScalarField(grid, label="s1") s2 = ScalarField(grid) fc = FieldCollection([s1, s2]) # test setting different figure sizes fc.plot(figsize="default") fc.plot(figsize="auto") fc.plot(figsize=(3, 3)) # test different arrangements fc.plot(arrangement="horizontal") fc.plot(arrangement="vertical")
def evolution_rate(self, state, t=0): v, w = state # membrane potential and recovery variable v_t = v.laplace(bc=self.bc) + v - v**3 / 3 - w + self.stimulus w_t = (v + self.a - self.b * w) / self.τ return FieldCollection([v_t, w_t])
def evolution_rate(self, state, t=0): s, i, r = state diff = self.diffusivity ds_dt = diff * s.laplace(self.bc) - self.beta * i * s di_dt = diff * i.laplace(self.bc) + self.beta * i * s - self.gamma * i dr_dt = diff * r.laplace(self.bc) + self.gamma * i return FieldCollection([ds_dt, di_dt, dr_dt])
def evolution_rate(self, state, t=0): u, w = state # membrane potential and recovery variable u_t = u.laplace(bc=self.bc) + u * (u - self.stimulus) * (1 - u) + w w_t = self.ε * u return FieldCollection([u_t, w_t])
def test_smoothing_collection(): """ test smoothing of a FieldCollection """ grid = UnitGrid([3, 4], periodic=[True, False]) sf = ScalarField.random_uniform(grid) vf = VectorField.random_uniform(grid) tf = Tensor2Field.random_uniform(grid) fields = FieldCollection([sf, vf, tf]) sgm = 0.5 + np.random.random() out = fields.smooth(sigma=sgm) for i in range(3): np.testing.assert_allclose(out[i].data, fields[i].smooth(sgm).data) out.data = 0 fields.smooth(sigma=sgm, out=out) for i in range(3): np.testing.assert_allclose(out[i].data, fields[i].smooth(sgm).data)
def test_scalar_random_uniform(): """ test creating collections using scalar_random_uniform """ grid = UnitGrid([3, 4], periodic=[True, False]) fc = FieldCollection.scalar_random_uniform(2, grid, label="c", labels=["a", "b"]) assert fc.label == "c" assert fc[0].label == "a" assert fc[1].label == "b" assert fc[0].grid is grid assert fc[1].grid is grid assert not np.allclose(fc[0].data, fc[1].data)
def get_state(self, s, i): """ generate a suitable initial state""" norm = (s + i).data.max() # maximal density if norm > 1: s /= norm i /= norm s.label = 'Susceptible' i.label = 'Infected' # create recovered field r = ScalarField(s.grid, data=1 - s - i, label='Recovered') return FieldCollection([s, i, r])
def test_pde_2scalar(): """test PDE with two scalar fields""" eq = PDE({"u": "laplace(u) - u", "v": "- u * v"}) assert not eq.explicit_time_dependence assert not eq.complex_valued grid = grids.UnitGrid([8]) field = FieldCollection.scalar_random_uniform(2, grid) res_a = eq.solve(field, t_range=1, dt=0.01, backend="numpy", tracker=None) res_b = eq.solve(field, t_range=1, dt=0.01, backend="numba", tracker=None) res_a.assert_field_compatible(res_b) np.testing.assert_allclose(res_a.data, res_b.data)
def test_from_scalar_expressions(): """ test creating field collections from scalar expressions """ grid = UnitGrid([3]) expressions = ["x**2", "1"] fc = FieldCollection.from_scalar_expressions( grid, expressions=expressions, label="c", labels=["a", "b"] ) assert fc.label == "c" assert fc[0].label == "a" assert fc[1].label == "b" assert fc[0].grid is grid assert fc[1].grid is grid np.testing.assert_allclose(fc[0].data, (np.arange(3) + 0.5) ** 2) np.testing.assert_allclose(fc[1].data, 1)
def test_pde_vector_scalar(): """test PDE with a vector and a scalar field""" eq = PDE({"u": "vector_laplace(u) - u + gradient(v)", "v": "- divergence(u)"}) assert not eq.explicit_time_dependence assert not eq.complex_valued grid = grids.UnitGrid([8, 8]) field = FieldCollection( [VectorField.random_uniform(grid), ScalarField.random_uniform(grid)] ) res_a = eq.solve(field, t_range=1, dt=0.01, backend="numpy", tracker=None) res_b = eq.solve(field, t_range=1, dt=0.01, backend="numba", tracker=None) res_a.assert_field_compatible(res_b) np.testing.assert_allclose(res_a.data, res_b.data)
def test_collections_copy(): """ test copying data of collections """ grid = UnitGrid([2, 2]) sf = ScalarField(grid, 0) vf = VectorField(grid, 1) fc = FieldCollection([sf, vf]) data = np.r_[np.zeros(4), np.ones(8)] np.testing.assert_allclose(fc.data.flat, data) fc2 = fc.copy() assert fc.data is not fc2.data assert fc[0].data is not fc2[0].data assert fc[1].data is not fc2[1].data sf.data = 1 np.testing.assert_allclose(fc.data.flat, np.ones(12)) np.testing.assert_allclose(fc2.data.flat, data) # special case fc = FieldCollection([sf, sf]) fc[0] = 2 np.testing.assert_allclose(fc[0].data, 2) np.testing.assert_allclose(fc[1].data, 1)
def test_collections(): """test field collections""" grid = UnitGrid([3, 4]) sf = ScalarField.random_uniform(grid, label="sf") vf = VectorField.random_uniform(grid, label="vf") tf = Tensor2Field.random_uniform(grid, label="tf") fields = FieldCollection([sf, vf, tf]) assert fields.data.shape == (7, 3, 4) assert isinstance(str(fields), str) fields.data[:] = 0 np.testing.assert_allclose(sf.data, 0) np.testing.assert_allclose(vf.data, 0) np.testing.assert_allclose(tf.data, 0) assert fields[0] is fields["sf"] assert fields[1] is fields["vf"] assert fields[2] is fields["tf"] with pytest.raises(KeyError): fields["42"] sf.data = 1 vf.data = 1 tf.data = 1 np.testing.assert_allclose(fields.data, 1) assert all(np.allclose(i, 12) for i in fields.integrals) assert all(np.allclose(i, 1) for i in fields.averages) assert np.allclose(fields.magnitudes, np.sqrt([1, 2, 4])) assert sf.data.shape == (3, 4) assert vf.data.shape == (2, 3, 4) assert tf.data.shape == (2, 2, 3, 4) c2 = FieldBase.from_state(fields.attributes, data=fields.data) assert c2 == fields assert c2.grid is grid attrs = FieldCollection.unserialize_attributes( fields.attributes_serialized) c2 = FieldCollection.from_state(attrs, data=fields.data) assert c2 == fields assert c2.grid is not grid fields["sf"] = 2.0 np.testing.assert_allclose(sf.data, 2) with pytest.raises(KeyError): fields["42"] = 0 fields.plot(subplot_args=[{}, {"scale": 1}, {"colorbar": False}])
def test_pde_noise(backend): """test noise operator on PDE class""" grid = grids.UnitGrid([64, 64]) state = FieldCollection([ScalarField(grid), ScalarField(grid)]) eq = PDE({"a": 0, "b": 0}, noise=0.5) res = eq.solve(state, t_range=1, backend=backend, dt=1, tracker=None) assert res.data.std() == pytest.approx(0.5, rel=0.1) eq = PDE({"a": 0, "b": 0}, noise=[0.01, 2.0]) res = eq.solve(state, t_range=1, backend=backend, dt=1) assert res.data[0].std() == pytest.approx(0.01, rel=0.1) assert res.data[1].std() == pytest.approx(2.0, rel=0.1) with pytest.raises(ValueError): eq = PDE({"a": 0}, noise=[0.01, 2.0]) eq.solve(ScalarField(grid), t_range=1, backend=backend, dt=1, tracker=None)
def test_solvers_complex(backend): """test solvers with a complex PDE""" r = FieldCollection.scalar_random_uniform(2, UnitGrid([3]), labels=["a", "b"]) c = r["a"] + 1j * r["b"] assert c.is_complex # assume c = a + i * b eq_c = PDE({"c": "-I * laplace(c)"}) eq_r = PDE({"a": "laplace(b)", "b": "-laplace(a)"}) res_r = eq_r.solve(r, t_range=1e-2, dt=1e-3, backend="numpy", tracker=None) exp_c = res_r[0].data + 1j * res_r[1].data for solver_class in [ExplicitSolver, ImplicitSolver, ScipySolver]: solver = solver_class(eq_c, backend=backend) controller = Controller(solver, t_range=1e-2, tracker=None) res_c = controller.run(c, dt=1e-3) np.testing.assert_allclose(res_c.data, exp_c, rtol=1e-3, atol=1e-3)
def test_pde_wrong_input(): """ test some wrong input """ with pytest.raises(RuntimeError): PDE({"t": 1}) grid = grids.UnitGrid([4]) eq = PDE({"u": 1}) assert eq.expressions == {"u": "1.0"} with pytest.raises(ValueError): eq.evolution_rate(FieldCollection.scalar_random_uniform(2, grid)) eq = PDE({"u": 1, "v": 2}) assert eq.expressions == {"u": "1.0", "v": "2.0"} with pytest.raises(ValueError): eq.evolution_rate(ScalarField.random_uniform(grid)) eq = PDE({"u": "a"}) with pytest.raises(RuntimeError): eq.evolution_rate(ScalarField.random_uniform(grid))
def test_collections_operators(): """ test field collections """ grid = UnitGrid([3, 4]) sf = ScalarField(grid, 1) vf = VectorField(grid, 1) fields = FieldCollection([sf, vf]) fields += fields np.testing.assert_allclose(fields.data, 2) np.testing.assert_allclose(sf.data, 2) np.testing.assert_allclose(vf.data, 2) fields = fields - 1 np.testing.assert_allclose(fields.data, 1) fields = fields + fields np.testing.assert_allclose(fields.data, 2) fields *= 2 np.testing.assert_allclose(fields.data, 4)
Here, :math:`D_0` and :math:`D_1` are the respective diffusivity and the parameters :math:`a` and :math:`b` are related to reaction rates. Note that the same result can also be achieved with a :doc:`full implementation of a custom class <pde_brusselator_class>`, which allows for more flexibility at the cost of code complexity. """ from pde import PDE, FieldCollection, PlotTracker, ScalarField, UnitGrid # define the PDE a, b = 1, 3 d0, d1 = 1, 0.1 eq = PDE( { "u": f"{d0} * laplace(u) + {a} - ({b} + 1) * u + u**2 * v", "v": f"{d1} * laplace(v) + {b} * u - u**2 * v", } ) # initialize state grid = UnitGrid([64, 64]) u = ScalarField(grid, a, label="Field $u$") v = b / a + 0.1 * ScalarField.random_normal(grid, label="Field $v$") state = FieldCollection([u, v]) # simulate the pde tracker = PlotTracker(interval=1, plot_args={"vmin": 0, "vmax": 5}) sol = eq.solve(state, t_range=20, dt=1e-3, tracker=tracker)
def get_initial_state(self, grid): """ prepare a useful initial state """ u = ScalarField(grid, self.a, label="Field $u$") v = self.b / self.a + 0.1 * ScalarField.random_normal(grid, label="Field $v$") return FieldCollection([u, v])
from pde import (UnitGrid, ScalarField, FieldCollection, DiffusionPDE, ExplicitSolver, ScipySolver, Controller) # initialize the grid, an initial condition, and the PDE grid = UnitGrid([32, 32]) field = ScalarField.random_uniform(grid, -1, 1) eq = DiffusionPDE() # try the explicit solver solver1 = ExplicitSolver(eq) controller1 = Controller(solver1, t_range=1, tracker=None) sol1 = controller1.run(field, dt=1e-3) sol1.label = 'explicit solver' print('Diagnostic information from first run:') print(controller1.diagnostics) print() # try the standard scipy solver solver2 = ScipySolver(eq) controller2 = Controller(solver2, t_range=1, tracker=None) sol2 = controller2.run(field) sol2.label = 'scipy solver' print('Diagnostic information from second run:') print(controller2.diagnostics) print() # plot both fields and give the deviation as the title title = f'Deviation: {((sol1 - sol2)**2).average:.2g}' FieldCollection([sol1, sol2]).plot(title=title)
def test_field_labels(): """ test the FieldCollection.labels property """ grid = UnitGrid([5]) s1 = ScalarField(grid, label="s1") s2 = ScalarField(grid) fc = FieldCollection([s1, s2]) assert fc.labels == ["s1", None] assert len(fc.labels) == 2 assert fc.labels[0] == "s1" assert fc.labels.index("s1") == 0 assert fc.labels.index(None) == 1 with pytest.raises(ValueError): fc.labels.index("a") fc.labels = ["a", "b"] assert fc.labels == ["a", "b"] fc.labels[0] = "c" assert fc.labels == ["c", "b"] assert str(fc.labels) == str(["c", "b"]) assert repr(fc.labels) == repr(["c", "b"]) assert fc.labels[0:1] == ["c"] assert fc.labels[:] == ["c", "b"] fc.labels[0:1] = "d" assert fc.labels == ["d", "b"] fc.labels[:] = "a" assert fc.labels == ["a", "a"] labels = fc.labels[:] labels[0] = "e" assert fc.labels == ["a", "a"] fc = FieldCollection([s1, s2], labels=[None, "b"]) assert fc.labels == [None, "b"] fc = FieldCollection([s1, s2], labels=["a", "b"]) assert fc.labels == ["a", "b"] with pytest.raises(TypeError): fc.labels = [1, "b"] with pytest.raises(TypeError): fc.labels[0] = 1
the recovery time scale. We implement this as a custom PDE class below. """ from pde import UnitGrid, FieldCollection, PDEBase class FitzhughNagumoPDE(PDEBase): """ FitzHugh–Nagumo model with diffusive coupling """ def __init__(self, stimulus=.5, τ=10, a=0, b=0, bc='natural'): self.bc = bc self.stimulus = stimulus self.τ = τ self.a = a self.b = b def evolution_rate(self, state, t=0): v, w = state # membrane potential and recovery variable v_t = v.laplace(bc=self.bc) + v - v**3 / 3 - w + self.stimulus w_t = (v + self.a - self.b * w) / self.τ return FieldCollection([v_t, w_t]) grid = UnitGrid([32, 32]) state = FieldCollection.scalar_random_uniform(2, grid) eq = FitzhughNagumoPDE() result = eq.solve(state, t_range=100, dt=0.01) result.plot()