def test_kymograph_collection(tmp_path): """test making kymographs for field collections""" # create some storage field = FieldCollection([ ScalarField(UnitGrid(8), label="a"), ScalarField(UnitGrid(8), label="b") ]) with get_memory_storage(field) as storage: for i in range(8): field.data = i storage.append(field, i) # create single kymograph path = tmp_path / "test1.png" plotting.plot_kymograph(storage, field_index=1, colorbar=True, transpose=True, filename=path) assert path.stat().st_size > 0 # create multiple kymographs path = tmp_path / "test2.png" plotting.plot_kymographs(storage, filename=path) assert path.stat().st_size > 0
def test_storage_apply(tmp_path): """ test the apply function of StorageBase """ grid = UnitGrid([2]) field = ScalarField(grid) storage_classes = {"None": None, "MemoryStorage": MemoryStorage} if module_available("h5py"): file_path = tmp_path / "test_storage_apply.hdf5" storage_classes["FileStorage"] = functools.partial( FileStorage, file_path) s1 = MemoryStorage() s1.start_writing(field, info={"b": 2}) s1.append(field.copy(data=np.array([0, 1])), 0) s1.append(field.copy(data=np.array([1, 2])), 1) s1.end_writing() for name, storage_cls in storage_classes.items(): out = None if storage_cls is None else storage_cls() s2 = s1.apply(lambda x: x + 1, out=out) assert storage_cls is None or s2 is out assert len(s2) == 2 np.testing.assert_allclose(s2.times, s1.times) assert s2[0] == ScalarField(grid, [1, 2]), name assert s2[1] == ScalarField(grid, [2, 3]), name # test empty storage s1 = MemoryStorage() s2 = s1.apply(lambda x: x + 1) assert len(s2) == 0
def test_pde_critical_input(): """test some wrong input and edge cases""" # test whether reserved symbols can be used as variables grid = grids.UnitGrid([4]) eq = PDE({"E": 1}) res = eq.solve(ScalarField(grid), t_range=2) np.testing.assert_allclose(res.data, 2) with pytest.raises(ValueError): PDE({"t": 1}) 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)) eq = PDE({"x": "x"}) with pytest.raises(ValueError): eq.evolution_rate(ScalarField(grid))
def test_vector_from_scalars(): """test how to compile vector fields from scalar fields""" g = UnitGrid([1, 2]) s1 = ScalarField(g, [[0, 1]]) s2 = ScalarField(g, [[2, 3]]) v = VectorField.from_scalars([s1, s2], label="test") assert v.label == "test" np.testing.assert_equal(v.data, [[[0, 1]], [[2, 3]]]) with pytest.raises(ValueError): VectorField.from_scalars([s1, s2, s1])
def test_collection_plot(tmp_path): """test Simple simulation""" # create some data field = FieldCollection([ ScalarField(UnitGrid([8, 8]), label="first"), ScalarField(UnitGrid([8, 8])) ]) with get_memory_storage(field) as storage: storage.append(field) path = tmp_path / "test_collection_plot.png" plotting.plot_magnitudes(storage, filename=path) assert path.stat().st_size > 0
def test_scalar_arithmetics(): """test simple arithmetics involving scalar fields""" grid = UnitGrid([3, 4]) s = ScalarField(grid, data=2) v = VectorField.random_uniform(grid) for f in [v, FieldCollection([v])]: f.data = s assert f.data.shape == (2, 3, 4) np.testing.assert_allclose(f.data, 2) f += s np.testing.assert_allclose(f.data, 4) np.testing.assert_allclose((f + s).data, 6) np.testing.assert_allclose((s + f).data, 6) f -= s np.testing.assert_allclose((f - s).data, 0) np.testing.assert_allclose((s - f).data, 0) f *= s np.testing.assert_allclose(f.data, 4) np.testing.assert_allclose((f * s).data, 8) np.testing.assert_allclose((s * f).data, 8) f /= s np.testing.assert_allclose((f / s).data, 1) with pytest.raises(TypeError): s / f with pytest.raises(TypeError): s /= f with pytest.raises(TypeError): s *= f
def test_field_type_guessing(): """ test the ability to guess the field type """ for cls in [ScalarField, VectorField, Tensor2Field]: grid = UnitGrid([3]) field = cls.random_normal(grid) s = MemoryStorage() s.start_writing(field) s.append(field, 0) s.append(field, 1) # delete information s._field = None s.info = {} assert not s.has_collection assert len(s) == 2 assert s[0] == field field = FieldCollection([ScalarField(grid), VectorField(grid)]) s = MemoryStorage() s.start_writing(field) s.append(field, 0) assert s.has_collection # delete information s._field = None s.info = {} with pytest.raises(RuntimeError): s[0]
def get_phase_field(self, grid: GridBase, *, vmin: float = 0, vmax: float = 1, label: str = None) -> ScalarField: """Creates an image of the droplet on the `grid` Args: grid (:class:`~pde.grids.base.GridBase`): The grid used for discretizing the droplet phase field vmin (float): Minimal value the phase field will attain (far away from droplet) vmax (float): Maximal value the phase field will attain (inside the droplet) label (str): The label associated with the returned scalar field Returns: :class:`~pde.fields.ScalarField`: A scalar field representing the droplet """ data = self._get_phase_field(grid) data = vmin + (vmax - vmin) * data # scale data return ScalarField(grid, data=data, label=label)
def test_memory_storage(): """test methods specific to memory storage""" sf = ScalarField(UnitGrid([1])) s1 = MemoryStorage() s1.start_writing(sf) sf.data = 0 s1.append(sf, 0) sf.data = 2 s1.append(sf, 1) s2 = MemoryStorage() s2.start_writing(sf) sf.data = 1 s2.append(sf, 0) sf.data = 3 s2.append(sf, 1) # test from_fields s3 = MemoryStorage.from_fields(s1.times, [s1[0], s1[1]]) assert s3.times == s1.times np.testing.assert_allclose(s3.data, s1.data) # test from_collection s3 = MemoryStorage.from_collection([s1, s2]) assert s3.times == s1.times np.testing.assert_allclose(np.ravel(s3.data), np.arange(4))
def get_phasefield(self, grid: GridBase = None, label: Optional[str] = None) -> ScalarField: """create a phase field representing a list of droplets Args: grid (:class:`pde.grids.base.GridBase`): The grid on which the phase field is created. If omitted, the grid associated with the emulsion is used. label (str): Optional label for the returned scalar field Returns: :class:`~pde.fields.scalar.ScalarField`: the actual phase field """ if grid is None: grid = self.grid if grid is None: raise RuntimeError("Grid needs to be specified") if len(self) == 0: return ScalarField(grid) else: result: ScalarField = self[0].get_phase_field(grid, label=label) for d in self[1:]: result += d.get_phase_field(grid) np.clip(result.data, 0, 1, out=result.data) return result
def test_pde_wrong_input(): """test some wrong input""" with pytest.raises(ValueError): PDE({"t": 1}) with pytest.raises(ValueError): PDE({"E": 1}) with pytest.raises(ValueError): PDE({"E": 1, "t": 0}) 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)) eq = PDE({"x": "x"}) with pytest.raises(ValueError): eq.evolution_rate(ScalarField(grid))
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_pde_time_dependent_bcs(backend): """test PDE with time-dependent BCs""" field = ScalarField(grids.UnitGrid([3])) eq = PDE({"c": "laplace(c)"}, bc={"value_expression": "Heaviside(t - 1.5)"}) storage = MemoryStorage() eq.solve(field, t_range=10, dt=1e-2, backend=backend, tracker=storage.tracker(1)) np.testing.assert_allclose(storage[1].data, 0) np.testing.assert_allclose(storage[-1].data, 1, rtol=1e-3)
def test_pde_spatial_args(backend): """test PDE with spatial dependence""" field = ScalarField(grids.UnitGrid([2])) eq = PDE({"a": "x"}) rhs = eq.make_pde_rhs(field, backend=backend) np.testing.assert_allclose(rhs(field.data, 0.0), np.array([0.5, 1.5])) # test combination of spatial dependence and differential oeprators eq = PDE({"a": "dot(gradient(x), gradient(a))"}) rhs = eq.make_pde_rhs(field, backend=backend) np.testing.assert_allclose(rhs(field.data, 0.0), np.array([0.0, 0.0])) # test invalid spatial dependence eq = PDE({"a": "x + y"}) with pytest.raises(RuntimeError): rhs = eq.make_pde_rhs(field, backend=backend) rhs(field.data, 0.0)
def test_kymograph_single(tmp_path): """ test making kymographs for single fields """ # create some storage field = ScalarField(UnitGrid(8)) with get_memory_storage(field) as storage: for i in range(8): storage.append(field.copy(data=i), i) # create single kymograph path = tmp_path / "test1.png" plotting.plot_kymograph(storage, colorbar=True, transpose=True, filename=path) assert path.stat().st_size > 0 # create multiple kymographs path = tmp_path / "test2.png" plotting.plot_kymographs(storage, filename=path) assert path.stat().st_size > 0
def test_pde_consts(): """test using the consts argument in PDE""" field = ScalarField(grids.UnitGrid([3]), 1) eq = PDE({"a": "b"}, consts={"b": 2}) np.testing.assert_allclose(eq.evolution_rate(field).data, 2) eq = PDE({"a": "b**2"}, consts={"b": field}) np.testing.assert_allclose(eq.evolution_rate(field).data, field.data) eq = PDE({"a": "laplace(b)"}, consts={"b": field}) np.testing.assert_allclose(eq.evolution_rate(field).data, 0) eq = PDE({"a": "laplace(b)"}, consts={"b": 3}) with pytest.raises(Exception): eq.evolution_rate(field) eq = PDE({"a": "laplace(b)"}, consts={"b": field.data}) with pytest.raises(Exception): eq.evolution_rate(field)
def test_storage_write(tmp_path): """test simple memory storage""" dim = 5 grid = UnitGrid([dim]) field = ScalarField(grid) storage_classes = {"MemoryStorage": MemoryStorage} if module_available("h5py"): file_path = tmp_path / "test_storage_write.hdf5" storage_classes["FileStorage"] = functools.partial( FileStorage, file_path) for name, storage_cls in storage_classes.items(): storage = storage_cls(info={"a": 1}) storage.start_writing(field, info={"b": 2}) field.data = np.arange(dim) storage.append(field, 0) field.data = np.arange(dim) storage.append(field, 1) storage.end_writing() assert not storage.has_collection np.testing.assert_allclose(storage.times, np.arange(2)) for f in storage: np.testing.assert_array_equal(f.data, np.arange(dim)) for i in range(2): np.testing.assert_array_equal(storage[i].data, np.arange(dim)) assert {"a": 1, "b": 2}.items() <= storage.info.items() storage = storage_cls() storage.clear() for i in range(3): storage.start_writing(field) field.data = np.arange(dim) + i storage.append(field, i) storage.end_writing() np.testing.assert_allclose(storage.times, np.arange(3), err_msg="storage class: " + name)
def test_storing_extract_range(tmp_path): """test methods specific to FieldCollections in memory storage""" sf = ScalarField(UnitGrid([1])) storage_classes = {"MemoryStorage": MemoryStorage} if module_available("h5py"): file_path = tmp_path / "test_storage_write.hdf5" storage_classes["FileStorage"] = functools.partial( FileStorage, file_path) for storage_cls in storage_classes.values(): # store some data s1 = storage_cls() s1.start_writing(sf) sf.data = np.array([0]) s1.append(sf, 0) sf.data = np.array([2]) s1.append(sf, 1) s1.end_writing() np.testing.assert_equal(s1[0].data, 0) np.testing.assert_equal(s1[1].data, 2) np.testing.assert_equal(s1[-1].data, 2) np.testing.assert_equal(s1[-2].data, 0) with pytest.raises(IndexError): s1[2] with pytest.raises(IndexError): s1[-3] # test extraction s2 = s1.extract_time_range() assert s2.times == list(s1.times) np.testing.assert_allclose(s2.data, s1.data) s3 = s1.extract_time_range(0.5) assert s3.times == s1.times[:1] np.testing.assert_allclose(s3.data, s1.data[:1]) s4 = s1.extract_time_range((0.5, 1.5)) assert s4.times == s1.times[1:] np.testing.assert_allclose(s4.data, s1.data[1:])