diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 6dd3a39..d521d64 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -3,60 +3,70 @@ name: Tests on: [push, pull_request] jobs: - black: + latest: runs-on: ubuntu-latest if: always() steps: - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v2 - - - name: Install Poetry - run: | - pip install poetry - poetry --version + - uses: actions/checkout@v3 + - name: Set up Python 3.11 + uses: actions/setup-python@v4 + with: + python-version: '3.11' - name: Install dependencies run: | - python -m poetry install + python -m pip install . + - name: Check formatting with black run: | - poetry run black --check . + black --check . + + - name: Test with pytest + run: | + coverage run -m pytest + coverage xml - pytest: + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + # env_vars: OS,PYTHON + # fail_ci_if_error: true + # files: ./coverage.xml,!./cache + # name: codecov-umbrella + # verbose: true - runs-on: ubuntu-20.04 + - name: Type checking with mypy + run: | + mypy --ignore-missing-imports blobmodel + + python-3-10: + + runs-on: ubuntu-latest if: always() - strategy: - matrix: - python-version: [3.10.2] - pip-packages: - - "setuptools pip pytest pytest-cov coverage codecov mypy" - fail-fast: false steps: - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + + - name: Set up Python 3.10 + uses: actions/setup-python@v4 with: - python-version: ${{ matrix.python-version }} - - name: Install Poetry - run: | - pip install poetry - poetry --version + python-version: '3.10' + - name: Install dependencies run: | - python -m poetry install - - name: Install pytest-cov - run: poetry add pytest-cov + python -m pip install . + + - name: Check formatting with black + run: | + black --check . + - name: Test with pytest run: | - poetry run pytest -v --cov - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v2 + pytest --cov . - name: Type checking with mypy run: | - poetry run mypy --ignore-missing-imports . + mypy --ignore-missing-imports blobmodel diff --git a/.gitignore b/.gitignore index 0198ac3..1950842 100644 --- a/.gitignore +++ b/.gitignore @@ -144,3 +144,5 @@ example.gif # png files *.png + +old_files/ diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 0000000..fe11770 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,32 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + # You can also specify other tool versions: + # nodejs: "19" + # rust: "1.64" + # golang: "1.19" + +# Build documentation in the "docs/" directory with Sphinx +sphinx: + configuration: docs/conf.py + +# Optionally build your docs in additional formats such as PDF and ePub +# formats: +# - pdf +# - epub + +# Optional but recommended, declare the Python requirements required +# to build your documentation +# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html +python: + install: + - requirements: docs/requirements.txt diff --git a/README.md b/README.md index 2540952..ab8005c 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,40 @@ +# blobmodel + +[![Python version](./readme_files/tmp5kfvrjp5.svg)](https://www.python.org/) +[![Pypi](./readme_files/tmpp0mi4n8p.svg)](https://pypi.org/project/blobmodel/#description) +[![codecov](https://codecov.io/github/uit-cosmo/blobmodel/branch/main/graph/badge.svg?token=QSS3BYQC6Y)](https://codecov.io/github/uit-cosmo/blobmodel) ![Tests](https://github.com/uit-cosmo/2d_propagating_blobs/actions/workflows/workflow.yml/badge.svg) [![Checked with mypy](http://www.mypy-lang.org/static/mypy_badge.svg)](http://mypy-lang.org/) -[![Sourcery](https://img.shields.io/badge/Sourcery-enabled-brightgreen)](https://sourcery.ai) - -# blobmodel -Two dimensional model of advecting and dissipating blobs. +[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Documentation Status](https://readthedocs.org/projects/blobmodel/badge/?version=latest)](https://blobmodel.readthedocs.io/en/latest/?badge=latest) + +This package provides realizations of advecting and dissipating blobs in up to two dimensions. + +All blob parameters can be choosen freely, and multiple blob shapes are implemented. Originally, the model is developed for studying the scrape-off layer of fusion experiments, but it can be applicable to many 1d or 2d systems. See the [blobmodel documentation](https://blobmodel.readthedocs.io/en/latest/?badge=latest) for further details. + +Examples for one and two dimensions are shown below: + + + + + + + + + + +
1D 2D
+Density evolution -The code has been developed originally to model profiles in the scrape-off layer of fusion experiments but it can be used to model any 1d or 2d system consisting of advecting pulses. Examples for one and two dimensions are shown below: -![Density evolution](readme_gifs/2d_blobs.gif) -![Density evolution](readme_gifs/1d_blobs.gif) + + +Density evolution + + +
+ ## Installation The package is published to PyPI and can be installed with ```sh @@ -21,13 +45,13 @@ If you want the development version you must first clone the repo to your local then install the project in development mode: ```sh -git clone git@github.com:uit-cosmo/2d-propagating-blobs.git -cd 2d-propagating-blobs -poetry install +git clone https://github.com/uit-cosmo/blobmodel.git +cd blobmodel +python -m pip install -e . ``` ## Usage -Create the grid on which the blobs are discretized with using the `Model` class. The `make_realization()` method computes the output as an xarray dataset which can also be written out as a `netcdf` file if the argument `file_name` is specified. A simple example is shown below: +Create a grid on which the blobs are discretized using the `Model` class. The `make_realization()` method computes the output as an xarray dataset which can also be written out as a `netcdf` file if the argument `file_name` is specified. A simple example is shown below: ```Python from blobmodel import Model, show_model @@ -45,7 +69,7 @@ You can specify the blob parameters with a BlobFactory class. The DefaultBlobFac ```Python from blobmodel import Model, DefaultBlobFactory -# use DefaultBlobFactory to define distribution functions fo random variables +# use DefaultBlobFactory to define distribution functions of random variables bf = DefaultBlobFactory(A_dist="exp", wx_dist="uniform", vx_dist="deg", vy_dist="normal") # pass on bf when creating the Model @@ -63,85 +87,8 @@ tmp = Model( blob_factory=bf, ) ``` -Alternatively, you can specify all blob parameters exactly as you want by writing your own class which inherits from BlobFactory. See `examples/custom_blobfactory.py` as an example. -## Input parameters -### `Model()` -- `Nx`: int, grid points in x -- `Ny`: int, grid points in y -- `Lx`: float, length of grid in x -- `Ly`: float, length of grid in y -- `dt`: float, time step -- `T`: float, time length -- `periodic_y`: bool, optional, - allow periodicity in y-direction - - !!! this is only a good approximation if Ly is significantly bigger than blobs !!! -- `blob_shape`: AbstractBlobShape or str, optional, -- `num_blobs`: int, optional - number of blobs -- `t_drain`: float, optional, - drain time for blobs -- `blob_factory`: BlobFactory, optional, - object containing blob parameters -- `labels`: str, optional, - "off": no blob labels returned, - "same": regions where blobs are present are set to label 1, - "individual": different blobs return individual labels, - used for creating training data for supervised machine learning algorithms -- `label_border`: float, optional, - defines region of blob as region where density >= label_border * amplitude of Blob - only used if labels = True -### `DefaultBlobFactory()` -- `A_dist`: str, optional, - distribution of blob amplitudes -- `W_dist`: str, optional, - distribution of blob widths -- `vx_dist`: str, optinal, - distribution of blob velocities in x-dimension -- `vy_dist`: str, optinal, - distribution of blob velocities in y-dimension -- `A_parameter`: float, optional, - `free_parameter` for amplitudes -- `W_parameter`: float, optional, - `free_parameter` for widths -- `vx_parameter`: float, optional, - `free_parameter` for vx -- `vy_parameter`: float, optional, - `free_parameter` for vy -- `shape_param_x_parameter`: float = 0.5, -- `shape_param_y_parameter`: float = 0.5 - -The following distributions are implemented: - -- `exp`: exponential distribution with mean 1 -- `gamma`: gamma distribution with `free_parameter` as shape parameter and mean 1 -- `normal`: normal distribution with zero mean and `free_parameter` as scale parameter -- `uniform`: uniorm distribution with mean 1 and `free_parameter` as width -- `ray`: rayleight distribution with mean 1 -- `deg`: array on ones -- `zeros`: array of zeros -### `make_realization()` -- `file_name`: str, optional, - file name for .nc file containing data as xarray dataset -- `speed_up`: bool, optional, - speeding up code by discretizing each single blob at smaller time window - when blob values fall under given error value the blob gets discarded - - !!! this is only a good approximation for blob_shape='exp' !!! -- `error`: float, optional, - numerical error at x = Lx when blob gets truncated -### `show_model()` -- `ds`: xarray Dataset, - Model data -- `interval`: int, optional, - time interval between frames in ms -- `save`: bool, optional, - if True save animation as gif -- `gif_name`: str, optional, - set name for gif -- `fps`: int, optional, - set fps for gif - -## Contact -If you have questions, suggestions or other comments you can contact me under gregor.decristoforo@uit.no +Alternatively, you can specify all blob parameters exactly as you want by writing your own class which inherits from BlobFactory. See `examples/custom_blobfactory.py` as an example or take a look at the [blobmodel documentation](https://blobmodel.readthedocs.io/en/latest/?badge=latest). + +## Contributing +Feel free to raise issues about anything. Contributions through pull requests are also very welcome. Please take a look at our [Contributor guide](https://blobmodel.readthedocs.io/en/latest/contributor_guide.html) for further details. diff --git a/blobmodel/__init__.py b/blobmodel/__init__.py index a4a5412..7e50733 100644 --- a/blobmodel/__init__.py +++ b/blobmodel/__init__.py @@ -3,4 +3,4 @@ from .plotting import show_model from .stochasticality import BlobFactory, DefaultBlobFactory from .geometry import Geometry -from .pulse_shape import AbstractBlobShape, BlobShapeImpl +from .blob_shape import AbstractBlobShape, BlobShapeImpl diff --git a/blobmodel/pulse_shape.py b/blobmodel/blob_shape.py similarity index 87% rename from blobmodel/pulse_shape.py rename to blobmodel/blob_shape.py index 24765b1..341e20c 100644 --- a/blobmodel/pulse_shape.py +++ b/blobmodel/blob_shape.py @@ -6,17 +6,17 @@ class AbstractBlobShape(ABC): """Abstract class containing the blob pulse shapes. Two-dimensional blob - pulse shapes are written in the form. + pulse shapes are written in the form: - `phi(theta_x, theta_y) = phi_x(theta_x) * phi_y(theta_y)`. + ``phi(theta_x, theta_y) = phi_x(theta_x) * phi_y(theta_y)`` """ @abstractmethod - def get_pulse_shape_prop(self, theta: np.ndarray, **kwargs) -> np.ndarray: + def get_blob_shape_prop(self, theta: np.ndarray, **kwargs) -> np.ndarray: raise NotImplementedError @abstractmethod - def get_pulse_shape_perp(self, theta: np.ndarray, **kwargs) -> np.ndarray: + def get_blob_shape_perp(self, theta: np.ndarray, **kwargs) -> np.ndarray: raise NotImplementedError @@ -40,17 +40,17 @@ def __init__(self, pulse_shape_prop="gauss", pulse_shape_perp="gauss"): raise NotImplementedError( f"{self.__class__.__name__}.blob_shape not implemented" ) - self.get_pulse_shape_prop = BlobShapeImpl.__GENERATORS.get(pulse_shape_prop) - self.get_pulse_shape_perp = BlobShapeImpl.__GENERATORS.get(pulse_shape_perp) + self.get_blob_shape_prop = BlobShapeImpl.__GENERATORS.get(pulse_shape_prop) + self.get_blob_shape_perp = BlobShapeImpl.__GENERATORS.get(pulse_shape_perp) - def get_pulse_shape_prop(self, theta: np.ndarray, **kwargs) -> np.ndarray: + def get_blob_shape_prop(self, theta: np.ndarray, **kwargs) -> np.ndarray: """Compute the pulse shape in the propagation direction. Parameters ---------- theta : np.ndarray Array of theta values. - **kwargs + kwargs Additional keyword arguments. Returns @@ -60,14 +60,14 @@ def get_pulse_shape_prop(self, theta: np.ndarray, **kwargs) -> np.ndarray: """ raise NotImplementedError - def get_pulse_shape_perp(self, theta: np.ndarray, **kwargs) -> np.ndarray: + def get_blob_shape_perp(self, theta: np.ndarray, **kwargs) -> np.ndarray: """Compute the pulse shape perpendicular to the propagation direction. Parameters ---------- theta : np.ndarray Array of theta values. - **kwargs + kwargs Additional keyword arguments. Returns @@ -85,7 +85,7 @@ def _get_exponential_shape(theta: np.ndarray, **kwargs) -> np.ndarray: ---------- theta : np.ndarray Array of theta values. - **kwargs + kwargs Additional keyword arguments. Returns @@ -103,7 +103,7 @@ def _get_lorentz_shape(theta: np.ndarray, **kwargs) -> np.ndarray: ---------- theta : np.ndarray Array of theta values. - **kwargs + kwargs Additional keyword arguments. Returns @@ -121,7 +121,7 @@ def _get_double_exponential_shape(theta: np.ndarray, **kwargs) -> np.ndarray: ---------- theta : np.ndarray Array of theta values. - **kwargs + kwargs Additional keyword arguments. lam : float Asymmetry parameter controlling the shape. @@ -146,7 +146,7 @@ def _get_gaussian_shape(theta: np.ndarray, **kwargs) -> np.ndarray: ---------- theta : np.ndarray Array of theta values. - **kwargs + kwargs Additional keyword arguments. Returns @@ -164,7 +164,7 @@ def _get_secant_shape(theta: np.ndarray, **kwargs) -> np.ndarray: ---------- theta : np.ndarray Array of theta values. - **kwargs + kwargs Additional keyword arguments. Returns diff --git a/blobmodel/blobs.py b/blobmodel/blobs.py index 0f1177b..345129d 100644 --- a/blobmodel/blobs.py +++ b/blobmodel/blobs.py @@ -1,10 +1,10 @@ """This module defines a Blob class and related functions for discretizing and manipulating blobs.""" import warnings -from typing import Tuple, Union +from typing import Tuple, Union, Any from nptyping import NDArray import numpy as np -from .pulse_shape import AbstractBlobShape +from .blob_shape import AbstractBlobShape import cmath @@ -24,11 +24,10 @@ def __init__( pos_y: float, t_init: float, t_drain: Union[float, NDArray], - prop_shape_parameters: dict = None, - perp_shape_parameters: dict = None, + prop_shape_parameters: Union[dict, None] = None, + perp_shape_parameters: Union[dict, None] = None, blob_alignment: bool = True, ) -> None: - """ Initialize a single blob. @@ -175,14 +174,14 @@ def discretize_blob( def _single_blob( self, - x_prop: NDArray, - y_perp: NDArray, - t: NDArray, + x_prop: Union[int, NDArray], + y_perp: Union[int, NDArray], + t: Union[int, NDArray], Ly: float, periodic_y: bool, - number_of_y_propagations: NDArray = 0, - x_offset: NDArray = 0, - y_offset: NDArray = 0, + number_of_y_propagations: Union[NDArray, int] = 0, + x_offset: Union[NDArray, int] = 0, + y_offset: Union[NDArray, int] = 0, one_dimensional: bool = False, ) -> NDArray: """ @@ -238,7 +237,7 @@ def _single_blob( ) ) - def _drain(self, t: NDArray) -> NDArray: + def _drain(self, t: Union[int, NDArray]) -> NDArray: """ Calculate the drain factor for the blob. @@ -259,11 +258,11 @@ def _drain(self, t: NDArray) -> NDArray: def _propagation_direction_shape( self, - x: NDArray, - t: NDArray, + x: Union[int, NDArray], + t: Union[int, NDArray], Ly: float, periodic_y: bool, - number_of_y_propagations: NDArray, + number_of_y_propagations: Union[int, NDArray], ) -> NDArray: """ Calculate the shape in the propagation direction. @@ -296,17 +295,17 @@ def _propagation_direction_shape( else: x_diffs = x - self._prop_dir_blob_position(t) theta_x = x_diffs / self.width_prop - return self.blob_shape.get_pulse_shape_prop( + return self.blob_shape.get_blob_shape_prop( theta_x, **self.prop_shape_parameters ) def _perpendicular_direction_shape( self, - y: NDArray, - t: NDArray, + y: Union[int, NDArray], + t: Union[int, NDArray], Ly: float, periodic_y: bool, - number_of_y_propagations: NDArray, + number_of_y_propagations: Union[int, NDArray], ) -> NDArray: """ Calculate the shape in the perpendicular direction. @@ -337,11 +336,11 @@ def _perpendicular_direction_shape( else: y_diffs = y - self._perp_dir_blob_position(t) theta_y = y_diffs / self.width_perp - return self.blob_shape.get_pulse_shape_perp( + return self.blob_shape.get_blob_shape_perp( theta_y, **self.perp_shape_parameters ) - def _prop_dir_blob_position(self, t: NDArray) -> NDArray: + def _prop_dir_blob_position(self, t: Union[int, NDArray]) -> NDArray: """ Calculate the position of the blob in the propagation direction. @@ -362,7 +361,7 @@ def _prop_dir_blob_position(self, t: NDArray) -> NDArray: else self.pos_x + self.v_x * (t - self.t_init) ) - def _perp_dir_blob_position(self, t: NDArray) -> float: + def _perp_dir_blob_position(self, t: Union[int, NDArray]) -> Any: """ Return the position of the blob in the perpendicular direction. diff --git a/blobmodel/geometry.py b/blobmodel/geometry.py index eb91f0e..f23981f 100644 --- a/blobmodel/geometry.py +++ b/blobmodel/geometry.py @@ -1,7 +1,8 @@ """This module defines the Geometry class for creating a grid for the Model.""" from typing import Any -from nptyping import NDArray, Float +from nptyping import NDArray +from typing_extensions import Literal import numpy as np @@ -47,12 +48,12 @@ def __init__( self.periodic_y = periodic_y # calculate x, y and t coordinates - self.x: NDArray[Any, Float[64]] = np.arange(0, self.Lx, self.Lx / self.Nx) + self.x: NDArray[Literal[64], Any] = np.arange(0, self.Lx, self.Lx / self.Nx) if self.Ly == 0: - self.y: NDArray[Any, Float[64]] = 0 + self.y: NDArray[Literal[64], Any] = np.array([0]) else: self.y = np.arange(0, self.Ly, self.Ly / self.Ny) - self.t: NDArray[Any, Float[64]] = np.arange(0, self.T, self.dt) + self.t: NDArray[Literal[64], Any] = np.arange(0, self.T, self.dt) self.x_matrix, self.y_matrix, self.t_matrix = np.meshgrid( self.x, self.y, self.t ) diff --git a/blobmodel/model.py b/blobmodel/model.py index 65e0dfa..c789203 100644 --- a/blobmodel/model.py +++ b/blobmodel/model.py @@ -9,7 +9,7 @@ from .geometry import Geometry from nptyping import NDArray import warnings -from .pulse_shape import AbstractBlobShape, BlobShapeImpl +from .blob_shape import AbstractBlobShape, BlobShapeImpl class Model: @@ -26,7 +26,7 @@ def __init__( periodic_y: bool = False, blob_shape: Union[AbstractBlobShape, str] = BlobShapeImpl("gauss"), num_blobs: int = 1000, - t_drain: Union[float, NDArray] = 10, + t_drain: Union[float, NDArray, int] = 10, blob_factory: BlobFactory = DefaultBlobFactory(), labels: str = "off", label_border: float = 0.75, @@ -117,7 +117,7 @@ def __init__( isinstance(t_drain, (int, float)) or len(t_drain) == Nx ), "t_drain must be of either length 1 or Nx" - self._blobs: list[Blob] = [] + self._blobs: List[Blob] = [] self._blob_factory = blob_factory self._labels = labels self._label_border = label_border @@ -155,7 +155,7 @@ def get_blobs(self) -> List[Blob]: def make_realization( self, - file_name: str = None, + file_name: Union[str, None] = None, speed_up: bool = False, error: float = 1e-10, ) -> xr.Dataset: diff --git a/blobmodel/plotting.py b/blobmodel/plotting.py index f26a7e8..1c66076 100644 --- a/blobmodel/plotting.py +++ b/blobmodel/plotting.py @@ -5,14 +5,14 @@ import numpy as np import xarray as xr from matplotlib import animation +from typing import Union def show_model( dataset: xr.Dataset, variable: str = "n", interval: int = 100, - save: bool = False, - gif_name: str = "blobs.gif", + gif_name: Union[str, None] = None, fps: int = 10, ) -> None: """ @@ -26,10 +26,8 @@ def show_model( Variable to be animated (default: "n"). interval : int, optional Time interval between frames in milliseconds (default: 100). - save : bool, optional - If True, save the animation as a GIF (default: False). gif_name : str, optional - Set the name for the saved GIF (default: "blobs.gif"). + If not None, save the animation as a GIF and name it acoridingly. fps : int, optional Set the frames per second for the saved GIF (default: 10). @@ -103,7 +101,7 @@ def animate_2d(i: int) -> None: fig, animate_2d, frames=dataset["t"].values.size, interval=interval ) - if save: + if gif_name: ani.save(gif_name, writer="ffmpeg", fps=fps) plt.show() diff --git a/blobmodel/stochasticality.py b/blobmodel/stochasticality.py index fb23fab..4ef7df7 100644 --- a/blobmodel/stochasticality.py +++ b/blobmodel/stochasticality.py @@ -3,9 +3,9 @@ from abc import ABC, abstractmethod import numpy as np from nptyping import NDArray, Float -from typing import Any, List +from typing import Any, List, Union, Dict from .blobs import Blob -from .pulse_shape import AbstractBlobShape +from .blob_shape import AbstractBlobShape class BlobFactory(ABC): @@ -19,7 +19,7 @@ def sample_blobs( T: float, num_blobs: int, blob_shape: AbstractBlobShape, - t_drain: float, + t_drain: Union[float, NDArray], ) -> List[Blob]: """creates list of Blobs used in Model.""" raise NotImplementedError @@ -56,7 +56,6 @@ def __init__( shape_param_y_parameter: float = 0.5, blob_alignment: bool = True, ) -> None: - """ Default implementation of BlobFactory. @@ -130,7 +129,7 @@ def _draw_random_variables( dist_type: str, free_parameter: float, num_blobs: int, - ) -> NDArray[Any, Float[64]]: + ) -> np.ndarray: """ Draws random variables from a specified distribution. @@ -149,23 +148,27 @@ def _draw_random_variables( Array of random variables drawn from the specified distribution. """ if dist_type == "exp": - return np.random.exponential(scale=1, size=num_blobs) + return np.random.exponential(scale=1, size=num_blobs).astype(np.float64) elif dist_type == "gamma": return np.random.gamma( shape=free_parameter, scale=1 / free_parameter, size=num_blobs - ) + ).astype(np.float64) elif dist_type == "normal": - return np.random.normal(loc=0, scale=free_parameter, size=num_blobs) + return np.random.normal(loc=0, scale=free_parameter, size=num_blobs).astype( + np.float64 + ) elif dist_type == "uniform": return np.random.uniform( low=1 - free_parameter / 2, high=1 + free_parameter / 2, size=num_blobs - ) + ).astype(np.float64) elif dist_type == "ray": - return np.random.rayleigh(scale=np.sqrt(2.0 / np.pi), size=num_blobs) + return np.random.rayleigh( + scale=np.sqrt(2.0 / np.pi), size=num_blobs + ).astype(np.float64) elif dist_type == "deg": - return free_parameter * np.ones(num_blobs) + return free_parameter * np.ones(num_blobs).astype(np.float64) elif dist_type == "zeros": - return np.zeros(num_blobs) + return np.zeros(num_blobs).astype(np.float64) else: raise NotImplementedError( self.__class__.__name__ + ".distribution function not implemented" @@ -177,7 +180,7 @@ def sample_blobs( T: float, num_blobs: int, blob_shape: AbstractBlobShape, - t_drain: float, + t_drain: Union[float, NDArray], ) -> List[Blob]: """ Creates a list of Blobs used in the Model. @@ -224,8 +227,8 @@ def sample_blobs( self.shape_param_y_dist, self.shape_param_y_parameter, num_blobs ) # For now, only a lambda parameter is implemented - spxs = [{"lam": s} for s in spxs] - spys = [{"lam": s} for s in spys] + spxs_dict = [{"lam": s} for s in spxs] + spys_dict = [{"lam": s} for s in spys] posxs = np.zeros(num_blobs) posys = np.random.uniform(low=0.0, high=Ly, size=num_blobs) t_inits = np.random.uniform(low=0, high=T, size=num_blobs) @@ -243,15 +246,15 @@ def sample_blobs( pos_y=posys[i], t_init=t_inits[i], t_drain=t_drain, - prop_shape_parameters=spxs[i], - perp_shape_parameters=spys[i], + prop_shape_parameters=spxs_dict[i], + perp_shape_parameters=spys_dict[i], blob_alignment=self.blob_alignment, ) for i in range(num_blobs) ] # sort blobs by amplitude - return np.array(blobs)[np.argsort(amps)] + return sorted(blobs, key=lambda x: x.amplitude) def is_one_dimensional(self) -> bool: """ diff --git a/docs/2-sided_pulse_shape.png b/docs/2-sided_pulse_shape.png new file mode 100644 index 0000000..081a164 Binary files /dev/null and b/docs/2-sided_pulse_shape.png differ diff --git a/docs/alignment_false.gif b/docs/alignment_false.gif new file mode 100644 index 0000000..81cc59b Binary files /dev/null and b/docs/alignment_false.gif differ diff --git a/docs/alignment_true.gif b/docs/alignment_true.gif new file mode 100644 index 0000000..644c81f Binary files /dev/null and b/docs/alignment_true.gif differ diff --git a/docs/blob_alignment.rst b/docs/blob_alignment.rst new file mode 100644 index 0000000..df7a6e9 --- /dev/null +++ b/docs/blob_alignment.rst @@ -0,0 +1,43 @@ +.. _blob-alignment: + +Blob Alignment +============== + +By default, the blob shape is rotated to its propagation direction. The rotation angle :math:`\theta` is calculated as ``cmath.phase(vx + vy * 1j)``. + +An example of a rotated blob is shown below. + +.. image:: alignment_true.gif + :alt: StreamPlayer + :align: center + :scale: 80% + +Alternatively, we can force :math:`\theta = 0` for all blobs. The blob propagation direction won't be affected but the blob shape stays orientated towards x and y. +We achieve this by setting ``blob_alignment`` to False when the ``Blob`` object is instantiated. +If you want to implement a whole ``Model`` with unaligned blobs you need to use the ``CustomBlobFactory`` since blob alignment is not handled on a ``Model`` level. + +Instantiating a single blob as follows results in a unaligned blob: + +.. code-block:: python + + from blobmodel import Blob + + Blob( + blob_id=0, + blob_shape="exp", + amplitude=1, + width_prop=1, + width_perp=1, + v_x=1, + v_y=1, + pos_x=0, + pos_y=5, + t_init=0, + t_drain=1e10, + ) + +.. image:: alignment_false.gif + :alt: StreamPlayer + :align: center + :scale: 80% + diff --git a/docs/blob_labels.rst b/docs/blob_labels.rst new file mode 100644 index 0000000..7c7240b --- /dev/null +++ b/docs/blob_labels.rst @@ -0,0 +1,50 @@ +.. _blob-lables: + +Blob labels +=========== + +We can create an additional field showing blob labels by setting the ``labels`` argument to either ``same`` or ``individual`` when instantiating the ``Model`` object. +``same`` will label regions where blobs are present to 1 and the background to zero. ``individual`` will give individual integers as labels for each blob. +The resulting filed will be stored as ``blob_labels`` in the xarray dataset. This option can be useful for creating a training dataset for supervised machine learning algorithms. + +The borders of the blob labels are defined with the ``label_border`` argument. The label regions are located where ``density >= label_border * amplitude``. + +Let's take a look at an example: Let's say we want to calculate the individual blob labels of some Gaussian blobs: + +.. code-block:: python + + from blobmodel import Model + import numpy as np + import matplotlib.pyplot as plt + + + bm = Model( + Nx=100, + Ny=100, + Lx=20, + Ly=20, + dt=0.1, + T=20, + periodic_y=True, + blob_shape="gauss", + num_blobs=10, + t_drain=1e10, + labels="individual", + label_border=0.75 + ) + + ds = bm.make_realization(speed_up=True, error=1e-2) + + ds['n'].isel(t=-1).plot() + plt.figure() + ds['blob_labels'].isel(t=-1).plot() + + plt.show() + +|pic1| |pic2| + +.. |pic1| image:: labels_n.png + :width: 49% + +.. |pic2| image:: labels_labels.png + :width: 49% diff --git a/docs/blob_shapes.rst b/docs/blob_shapes.rst new file mode 100644 index 0000000..a2ac626 --- /dev/null +++ b/docs/blob_shapes.rst @@ -0,0 +1,108 @@ +.. _blob-shapes: + + +Blob Shapes +=========== + +We can choose between four different blob shapes that are specified with the ``blob_shape`` argument of the ``Model`` class. + +The blob shape consists of two parts, the blob shape in the propagation direction and the blob shape in the perpendicular direction thereof. +The propagation direction is calculated from vx and vy of each individual blob (see :ref:`blob-alignment` for further details). + +You can choose one of the following blob shapes for the propagation and perpendicular direction: + +.. list-table:: + :widths: 10 10 10 10 + :header-rows: 1 + + * - "exp" + - "gauss" + - "lorentz" + - "secant" + * - Exponential Pulse + - Gaussian Pulse + - Lorentz Pulse + - Secant Pulse + * - ``np.exp(theta) * np.heaviside(-1.0 * t, 1)`` + - ``1 / np.sqrt(np.pi) * np.exp(-(t**2))`` + - ``1 / (np.pi * (1 + t**2))`` + - ``2 / np.pi / (np.exp(t) + np.exp(-t))`` + +.. image:: pulse_shapes.png + :scale: 80% + ++++++++++++++++++++++ +Propagation direction ++++++++++++++++++++++ + +If you specify the ``blob_shape`` as a string such as ``blob_shape = "exp"``, the specified blob shape will be used in the propagation direction. +The perpendicular blob shape will be set to ``gauss``. + ++++++++++++++++++++++++ +Perpendicular direction ++++++++++++++++++++++++ + +In order to specify the blob shape in the perpendicular direction we need to specify the blob shapes with the ``BlobShapeImpl`` class. +The first argument refers to the propagation direction and the second one refers to the perpendicular direction. +An example would look like this: + +.. code-block:: python + + from blobmodel import Model, BlobShapeImpl + + bm = Model( + Nx=100, + Ny=100, + Lx=10, + Ly=10, + dt=0.1, + T=10, + num_blobs=10, + blob_shape=BlobShapeImpl("exp", "lorentz"), + periodic_y=True, + t_drain=1e10, + ) + + +++++++++++++++++++++++++++++++++ +Two-sided exponential blob shape +++++++++++++++++++++++++++++++++ + +The last blob shape we discuss is the two-sided exponential blob shape. In contrast to the shapes above, it requires an asymmetry parameter ``lam`` to specify the exact shape. +The shape is implemented as follows: + +.. code-block:: python + + shape[t < 0] = np.exp(t[t < 0] / lam) + shape[t >= 0] = np.exp(-t[t >= 0] / (1 - lam)) + +.. image:: 2-sided_pulse_shape.png + :scale: 80% + +We specify the asymmetry parameter when defining the ``blob_factory``. An example would look like this: + +.. code-block:: python + + bf = DefaultBlobFactory( + A_dist="deg", + wx_dist="deg", + spx_dist="deg", + spy_dist="deg", + shape_param_x_parameter=0.5, + shape_param_y_parameter=0.5, + ) + + bm = Model( + Nx=100, + Ny=100, + Lx=10, + Ly=10, + dt=0.1, + T=10, + num_blobs=10, + blob_shape=BlobShapeImpl("2-exp", "2-exp"), + t_drain=1e10, + blob_factory=bf, + ) + +Take a look at ``examples/2_sided_exp_pulse.py`` for a fully implemented example. diff --git a/docs/blobmodel.rst b/docs/blobmodel.rst new file mode 100644 index 0000000..0a8d6c3 --- /dev/null +++ b/docs/blobmodel.rst @@ -0,0 +1,61 @@ +blobmodel package +================= + +Submodules +---------- + +blobmodel.blob\_shape module +---------------------------- + +.. automodule:: blobmodel.blob_shape + :members: + :undoc-members: + :show-inheritance: + +blobmodel.blobs module +---------------------- + +.. automodule:: blobmodel.blobs + :members: + :undoc-members: + :show-inheritance: + +blobmodel.geometry module +------------------------- + +.. automodule:: blobmodel.geometry + :members: + :undoc-members: + :show-inheritance: + +blobmodel.model module +---------------------- + +.. automodule:: blobmodel.model + :members: + :undoc-members: + :show-inheritance: + +blobmodel.plotting module +------------------------- + +.. automodule:: blobmodel.plotting + :members: + :undoc-members: + :show-inheritance: + +blobmodel.stochasticality module +-------------------------------- + +.. automodule:: blobmodel.stochasticality + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: blobmodel + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/change_t_drain_plot.png b/docs/change_t_drain_plot.png new file mode 100644 index 0000000..8628aa6 Binary files /dev/null and b/docs/change_t_drain_plot.png differ diff --git a/docs/changing_t_drain_plot.py b/docs/changing_t_drain_plot.py new file mode 100644 index 0000000..bfafc80 --- /dev/null +++ b/docs/changing_t_drain_plot.py @@ -0,0 +1,50 @@ +from blobmodel import Model, DefaultBlobFactory +import matplotlib.pyplot as plt +import numpy as np + +bf = DefaultBlobFactory(A_dist="deg", wx_dist="deg", vx_dist="deg", vy_dist="zeros") + +t_drain = np.linspace(2, 1, 100) + +tmp = Model( + Nx=100, + Ny=1, + Lx=10, + Ly=0, + dt=1, + T=1000, + blob_shape="exp", + t_drain=t_drain, + periodic_y=False, + num_blobs=10000, + blob_factory=bf, +) + +ds_changing_t_drain = tmp.make_realization(speed_up=False) + +tmp = Model( + Nx=100, + Ny=1, + Lx=10, + Ly=0, + dt=1, + T=1000, + blob_shape="exp", + t_drain=2, + periodic_y=False, + num_blobs=10000, + blob_factory=bf, +) + +ds_constant_drain = tmp.make_realization(speed_up=False) + + +def plot_cahnging_t_drain(changing, constant): + changing.n.isel(y=0).mean(dim=("t")).plot(label="decreasing t_drain") + constant.n.isel(y=0).mean(dim=("t")).plot(label="constant t_drain") + plt.yscale("log") + plt.legend() + plt.show() + + +plot_cahnging_t_drain(ds_changing_t_drain, ds_constant_drain) diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..289437b --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,37 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = "blobmodel" +copyright = "2023, gregordecristoforo" +author = "gregordecristoforo" +release = "0.1.1" + +import os +import sys + +sys.path.insert(0, os.path.abspath("../")) + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + "sphinx.ext.autosummary", + "sphinx.ext.autodoc", + "sphinx.ext.napoleon", +] + +templates_path = ["_templates"] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = "sphinx_rtd_theme" +# html_static_path = ["_static"] + +html_favicon = "./logo.png" diff --git a/docs/contributor_guide.rst b/docs/contributor_guide.rst new file mode 100644 index 0000000..a2632f0 --- /dev/null +++ b/docs/contributor_guide.rst @@ -0,0 +1,100 @@ +.. _contributor-guide: + +Contributor Guide +================= + +Thanks for your interest in contributing to :py:mod:`blobmodel`! Any contributions such as bug reports, feature requests or even pull requests are very welcome! + ++++++++++++++++++++++++++++ +Install development version ++++++++++++++++++++++++++++ + +If you want to contribute code to :py:mod:`blobmodel`, we recommend first forking the `GitHub repository `_. +Next, install the package in development mode: + +.. code-block:: bash + + # replace your_account with appropriate name + git clone https://github.com/your_account/blobmodel.git + cd blobmodel + pip install -e . + +The :py:mod:`-e` specifies that this will be an `editable installation `_. + +.. tip:: + + It is advisable to use a virtual environment for code development. Popular options are `Virtualenv `_ and `Conda `_. + +++++++++++++++++++++++++++ +Code Contribution Workflow +++++++++++++++++++++++++++ + +After the package is installed, we can startthe cycle of making changes: + +1. Edit or create the files and save the changes. +2. In a terminal, run: + + .. code-block:: bash + + git add filename + + Replace `filename` with the name of the edited file(s). + +3. Commit the changes: + + .. code-block:: bash + + git commit -m "commit message" + + Replace `commit message` with a description of the committed changes. + +4. Push the changes to GitHub: + + .. code-block:: bash + + git push + +5. If you now go back to your GitHub repository of :py:mod:`blobmodel`, a pale yellow box will appear near the top of the screen, there click on :guilabel:`Compare & pull request`. + +6. Add a descriptive title and a description of the pull request, then select :guilabel:`Create pull request`. + +++++++++++++++++ +Formatting Guide +++++++++++++++++ + +:py:mod:`blobmodel` uses `Black `_ for code formatting. Make sure to run + +.. code-block:: bash + + black edited/new file + +on all edited and added python files in your pull request. For documentation we recomend following the `numpy style guide `_. + ++++++++++++++ +Testing Guide ++++++++++++++ + +Any new code contributed to :py:mod:`blobmodel` requires testing before it can be merged. All tests are located in the subdirectory `tests/`. +After you added your tests to this directory you can run + +.. code-block:: bash + + pytest + +to check whether all tests pass. + +In order to check whether all your new code is covered by tests, run: + +.. code-block:: bash + + pytest --cov + coverage html + +You can now open `htmlcov/index.html` with your browser to check whether all of your lines are covered by tests. + +As a last point, we recommend adding type hints to your new functions and classes, which ensures that you’re using variables and functions in your code correctly. +We use `mypy `_ for this purpose. Check your code by running: + +.. code-block:: bash + + mypy --ignore-missing-imports . diff --git a/docs/create_logo.py b/docs/create_logo.py new file mode 100644 index 0000000..18a3baf --- /dev/null +++ b/docs/create_logo.py @@ -0,0 +1,85 @@ +from blobmodel import ( + Model, + BlobFactory, + Blob, + show_model, + AbstractBlobShape, +) +import numpy as np +from typing import List + + +# create custom class that inherits from BlobFactory +# here you can define your custom parameter distributions +class CustomBlobFactory(BlobFactory): + def __init__(self) -> None: + pass + + def sample_blobs( + self, + Ly: float, + T: float, + num_blobs: int, + blob_shape: AbstractBlobShape, + t_drain: float, + ) -> List[Blob]: + # set custom parameter distributions + amp = [1, 1, 1] + width = [2, 1, 1] + vx = [1, 1, 1] + vy = [0, 0, 0] + + posx = np.zeros(num_blobs) + posy = [5, 2.5, 7.5] + t_init = [0.0, 2.0, 5.0] + + # sort blobs by _t_init + t_init = np.sort(t_init).tolist() + + return [ + Blob( + blob_id=i, + blob_shape=blob_shape, + amplitude=amp[i], + width_prop=width[i], + width_perp=width[i], + v_x=vx[i], + v_y=vy[i], + pos_x=posx[i], + pos_y=posy[i], + t_init=t_init[i], + t_drain=t_drain, + ) + for i in range(num_blobs) + ] + + def is_one_dimensional(self) -> bool: + return False + + +bf = CustomBlobFactory() +tmp = Model( + Nx=64, + Ny=64, + Lx=10, + Ly=10, + dt=1, + T=10, + blob_shape="gauss", + t_drain=100000, + periodic_y=True, + num_blobs=3, + blob_factory=bf, +) + +ds = tmp.make_realization(speed_up=True, error=1e-1) + +import matplotlib.pyplot as plt + +logo = ds.n.isel(t=7).values +plt.contourf(logo, 32) +plt.axis("off") +ax = plt.gca() +ax.set_aspect("equal", adjustable="box") +plt.savefig("logo.png", bbox_inches="tight") +plt.show() diff --git a/docs/drainage_time.rst b/docs/drainage_time.rst new file mode 100644 index 0000000..b09c11c --- /dev/null +++ b/docs/drainage_time.rst @@ -0,0 +1,39 @@ +.. _drainage-time: + +Drainage Time +============= + +By default, the drainage time is set to a constant value in the whole domain. In this case ``t_drain`` is simply set to an integer or float. +We can also set ``t_drain`` to an array like of length ``Nx``. In this case ``t_drain`` will vary accordingly with x. + +Let's take a look at a quick example. Let's assume we want ``t_drain`` to decrease linearly with x. We could implement this as follows: + +.. code-block:: python + + from blobmodel import Model, DefaultBlobFactory + import numpy as np + + bf = DefaultBlobFactory(A_dist="deg", wx_dist="deg", vx_dist="deg", vy_dist="zeros") + + t_drain = np.linspace(2, 1, 100) + + tmp = Model( + Nx=100, + Ny=1, + Lx=10, + Ly=0, + dt=1, + T=1000, + blob_shape="exp", + t_drain=t_drain, + periodic_y=False, + num_blobs=10000, + blob_factory=bf, + ) + + ds_changing_t_drain = tmp.make_realization() + +The time averaged x-profile of ``n`` compared to a constant ``t_drain`` = 2 would then look like this: + +.. image:: change_t_drain_plot.png + :scale: 80% diff --git a/docs/getting_started.rst b/docs/getting_started.rst new file mode 100644 index 0000000..57afedf --- /dev/null +++ b/docs/getting_started.rst @@ -0,0 +1,58 @@ +.. _getting-started: + +Getting Started +=============== + +++++++++++++++++ +Creating a model +++++++++++++++++ + +We create a grid on which the blobs are discretized with using the ``Model`` class. Here, we specify the geometry of the model by the number of grid points, the lengths of the domain, the time step and the time length of our realization. + +In addition, we can specify the blob shape, drainage time and the number of blobs when creating a ``Model`` object. For more details about the geometry, take a look at the :ref:`blobmodel-geometry` section. + +.. code-block:: python + + from blobmodel import Model + + bm = Model( + Nx=200, + Ny=100, + Lx=10, + Ly=10, + dt=0.1, + T=20, + blob_shape="gauss", + t_drain=100, + num_blobs=100, + ) + + ++++++++++++++++++ +Superposing blobs ++++++++++++++++++ + +We can now call the ``make_realization()`` method to sum up the individual blobs. The blob parameters are sampled from the according distribution functions (see :ref:`parameter-distributions` for further details). +If we provide a ``file_name`` to the ``make_realization`` method, it will store the realization under this name on your machine. + +.. code-block:: python + + ds = bm.make_realization(file_name="example.nc") + +The ``make_realization`` mehtod can take two more arguments, ``speed_up`` and ``error``, which can be helpful for integrating very large datasets. +By setting ``spee_up`` to ``True``, the code will truncate the blobs when the blob values fall under the given ``error`` value. +The code assumes an exponential shape for the blobs when calculating the truncation position (see :ref:`blob-shapes` for further details). + + +The ``make_realization`` method returns the realization in the form of an `xarray dataset `_. +The superposed pulses are stored in the ``n`` variable of the dataset. We can now analyse the data using the convenient xarray syntax, for example: + +.. code-block:: python + + import matplotlib.pyplot as plt + + ds["n"].isel(y=0).mean(dim=("t")).plot() + plt.show() + +.. image:: xarray_example.png + :scale: 80% diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..98cf92a --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,84 @@ +.. blobmodel documentation master file, created by + sphinx-quickstart on Fri Jun 16 13:31:30 2023. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +.. image:: logo.png + :alt: PlasmaPy logo + :align: right + :scale: 40% + + +blobmodel Documentation +======================= + +:py:mod:`blobmodel` is a python package for creating numerical realizations of advecting and dissipating blobs in up to two spatial dimensions. +This open source project is developed by the Complex Systems Modelling group at UiT The Arctic University of Norway. + +:py:mod:`blobmodel` is developed openly `on GitHub `_, where you can request a new feature, report a bug or contribute to the package by creating a pull request. + +Mathematically, the model of :math:`K` superposed blobs, :math:`\Phi_K`, can be expressed as + +.. math:: + + \Phi_K(x, y, t) = \sum_{k=1}^{K} \phi_k(x, y, t). + +The blobs :math:`\phi_k` consists of an amplitude :math:`a_k` and a blob shape :math:`\varphi` with a blob width in x and y, given by :math:`l_x` and :math:`l_y`: + +.. math:: + + \phi(x, y, t) = a_k \varphi\left(\frac{x}{l_x}, \frac{y}{l_y}, t \right). + +Each blob has an individual velocity in x and y, :math:`v_x` and :math:`v_y`, and decreases in amplitude with the drainage time :math:`\tau`: + +.. math:: + + \frac{\partial \phi_k}{\partial t} + v_x \frac{\partial \phi_k}{\partial x} + v_y \frac{\partial \phi_k}{\partial y} + \frac{\phi_k}{\tau} = 0. + + +A 2D example of the model is shown below: + +.. image:: ../readme_files/2d_blobs.gif + :alt: StreamPlayer + :align: center + :scale: 80% + +The model can also be reduced to one spatial dimension as shown in the following example: + +.. image:: ../readme_files/1d_blobs.gif + :alt: StreamPlayer + :align: center + :scale: 80% + +The following sections provide detailed information about the package components. +Alternatively, you can take a look at the examples gallery at :py:mod:`blobmodel/examples/` for a quick overview of the package's functionalities. + + +.. toctree:: + :caption: Contents + :maxdepth: 1 + + Installing + getting_started + visualize_model + model_geometry + blob_shapes + parameter_distributions + blob_labels + drainage_time + blob_alignment + contributor_guide + + +.. toctree:: + :maxdepth: 2 + :caption: API reference + + modules + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/install.rst b/docs/install.rst new file mode 100644 index 0000000..6d56bd1 --- /dev/null +++ b/docs/install.rst @@ -0,0 +1,25 @@ +.. _blobmodel-install: + +******************** +Installing blobmodel +******************** + +To install the most recent release of :py:mod:`blobmodel` on PyPI with pip into +an existing Python environment, open a terminal and run: + +.. code-block:: bash + + pip install plasmapy + +If you want the development version you must first clone the repository to your local machine, then install the project in development mode: + +.. code-block:: bash + + git clone https://github.com/uit-cosmo/blobmodel.git + cd blobmodel + pip install -e . + +.. note:: + + If you would like to contribute to :py:mod:`blobmodel`, please check out the :ref:`contributor-guide`. + diff --git a/docs/labels_labels.png b/docs/labels_labels.png new file mode 100644 index 0000000..1f02ec8 Binary files /dev/null and b/docs/labels_labels.png differ diff --git a/docs/labels_n.png b/docs/labels_n.png new file mode 100644 index 0000000..47da2a5 Binary files /dev/null and b/docs/labels_n.png differ diff --git a/docs/logo.png b/docs/logo.png new file mode 100644 index 0000000..4ebd537 Binary files /dev/null and b/docs/logo.png differ diff --git a/docs/model_geometry.rst b/docs/model_geometry.rst new file mode 100644 index 0000000..b9303ad --- /dev/null +++ b/docs/model_geometry.rst @@ -0,0 +1,30 @@ +.. _blobmodel-geometry: + +Model Geometry +============== + +In addition to setting the domain and grid size, the ``Model`` class provides some additional functionality. + ++++++++++++++ +y-periodicity ++++++++++++++ + +By setting the ``periodic_y`` argument of the ``Model`` class to ``True``, blobs that propagate out of the domain in the ``y`` direction enter at the opposite end. + +.. note:: + + Using ``periodic_y`` is only a good idea if the domain size in y is large compared to the blob widths since the periodicity is implemented by adding additional "ghost blobs" outside of the domain. + The code will give a warning if the blob width is less than ``0.1 * Ly``. + +.. image:: y-periodicity.gif + :alt: StreamPlayer + :align: center + :scale: 80% + +++++++++ +1D model +++++++++ + +By setting the ``one_dimensional`` argument of the ``Model`` class to ``True``, the perpendicular shape of the blobs will be discarded (see :ref:`blob-shapes` for further information). +The parameters for the y-component (Ny and Ly) will be overwritten to ``Ny=1`` and ``Ly=0``. + diff --git a/docs/modules.rst b/docs/modules.rst new file mode 100644 index 0000000..88a69f6 --- /dev/null +++ b/docs/modules.rst @@ -0,0 +1,4 @@ +.. toctree:: + :maxdepth: 4 + + blobmodel diff --git a/docs/parameter_distributions.rst b/docs/parameter_distributions.rst new file mode 100644 index 0000000..fb0a02a --- /dev/null +++ b/docs/parameter_distributions.rst @@ -0,0 +1,163 @@ +.. _parameter-distributions: + +Parameter Distributions +======================= + +While instantiating a ``Model`` object, we define the distribution functions used to sample blob parameters from. +So far we have only used the default distributions but in this section we cover how change these. + +++++++++++++++++++ +DefaultBlobFactory +++++++++++++++++++ + +We can use ``DefaultBlobFactory`` class in order to change the distribution functions of the following blob parameters: + +* Amplitudes +* widths in x +* widths in y +* velocities in x +* velocities in y + +The distributions for these parameters are set with the ``*_dist`` arguments. The following distribution functions are implemented: + +.. list-table:: + :widths: 10 50 + :header-rows: 0 + + * - "exp" + - exponential distribution with mean 1 + + * - "gamma" + - gamma distribution with ``free_parameter`` as shape parameter and mean 1 + + * - "normal" + - normal distribution with zero mean and ``free_parameter`` as scale parameter + + * - "uniform" + - uniform distribution with mean 1 and ``free_parameter`` as width + + * - "ray" + - Rayleight distribution with mean 1 + + * - "deg" + - degenerate distribution at ``free_parameter`` + + * - "zeros" + - array of zeros + +As you can see, some of these distributions require an additional ``free_parameter`` to specify the distribution. +This is done by the ``*_parameter`` arguments. + +Let's take a look at an example. Let's assume we want to sample the blob amplitudes from normal distribution with 5 as the scale parameter. +We chose the defualt distributions for all other blob parameters. We would set up the Model as follows: + + +.. code-block:: python + + from blobmodel import Model, DefaultBlobFactory + + my_blob_factory = DefaultBlobFactory(A_dist="normal", A_parameter=5) + + bm = Model( + Nx=200, + Ny=100, + Lx=10, + Ly=10, + dt=0.1, + T=20, + blob_shape="gauss", + blob_factory=my_blob_factory, + t_drain=100, + num_blobs=100, + ) + + ds = bm.make_realization() + ++++++++++++++++++ +CustomBlobFactory ++++++++++++++++++ + +But what if you want to use a distribution function that is not implemented? Or maybe you even want to change the initial position and arrival time of each blob? +In this case you can use the ``CustomBlobFactory`` class to define all blob parameters individually. An example could look like this: + +.. code-block:: python + + from blobmodel import ( + Model, + BlobFactory, + Blob, + AbstractBlobShape, + ) + import numpy as np + + # create custom class that inherits from BlobFactory + # here you can define your custom parameter distributions + class CustomBlobFactory(BlobFactory): + def __init__(self) -> None: + pass + + def sample_blobs( + self, + Ly: float, + T: float, + num_blobs: int, + blob_shape: AbstractBlobShape, + t_drain: float, + ) -> list[Blob]: + + # set custom parameter distributions + amp = np.linspace(0.01, 1, num=num_blobs) + width = np.linspace(0.01, 1, num=num_blobs) + vx = np.linspace(0.01, 1, num=num_blobs) + vy = np.linspace(0.01, 1, num=num_blobs) + + posx = np.zeros(num_blobs) + posy = np.random.uniform(low=0.0, high=Ly, size=num_blobs) + t_init = np.random.uniform(low=0, high=T, size=num_blobs) + + # sort blobs by _t_init + t_init = np.sort(t_init) + + return [ + Blob( + blob_id=i, + blob_shape=blob_shape, + amplitude=amp[i], + width_prop=width[i], + width_perp=width[i], + v_x=vx[i], + v_y=vy[i], + pos_x=posx[i], + pos_y=posy[i], + t_init=t_init[i], + t_drain=t_drain, + ) + for i in range(num_blobs) + ] + + def is_one_dimensional(self) -> bool: + return False + + + bf = CustomBlobFactory() + tmp = Model( + Nx=100, + Ny=100, + Lx=2, + Ly=2, + dt=0.1, + T=10, + blob_shape="gauss", + t_drain=2, + periodic_y=True, + num_blobs=1000, + blob_factory=bf, + ) + + ds = tmp.make_realization() + +By assigning an array like to the variables ``amp``, ``width``, ``vx``, ``vy``, ``posx``, ``posy`` and ``t_init`` we can exactly define every single blob parameter of every single blob. + +.. note:: + + When using ``CustomBlobFactory`` it is your responsibility to make sure all blob variables have the correct dimensions. Also, if you wish to normalize the parameters you have to do this manually. diff --git a/docs/plot_pulses.py b/docs/plot_pulses.py new file mode 100644 index 0000000..ef4774f --- /dev/null +++ b/docs/plot_pulses.py @@ -0,0 +1,31 @@ +import numpy as np +import matplotlib.pyplot as plt + +t = np.linspace(-5, 5, 1000) + +exp = np.exp(t) * np.heaviside(-1.0 * t, 1) +lorentz = 1 / (np.pi * (1 + t**2)) +gauss = 1 / np.sqrt(np.pi) * np.exp(-(t**2)) +secant = 2 / np.pi / (np.exp(t) + np.exp(-t)) + +plt.plot(t, exp, label="exp") +plt.plot(t, lorentz, label="lorentz") +plt.plot(t, gauss, label="gauss") +plt.plot(t, secant, label="secant") +plt.legend() +plt.xlabel("t") +plt.ylabel("n") +plt.savefig("pulse_shapes.png") +plt.show() + +for lam in [0.2, 0.5, 0.8]: + shape = np.zeros(1000) + shape[t < 0] = np.exp(t[t < 0] / lam) + shape[t >= 0] = np.exp(-t[t >= 0] / (1 - lam)) + plt.plot(t, shape, label=f"lam = {lam}") + +plt.xlabel("t") +plt.ylabel("n") +plt.legend() +plt.savefig("2-sided_pulse_shape.png") +plt.show() diff --git a/docs/pulse_shapes.png b/docs/pulse_shapes.png new file mode 100644 index 0000000..f1e90bd Binary files /dev/null and b/docs/pulse_shapes.png differ diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..adca622 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,136 @@ +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile --output-file=requirements.txt +# +alabaster==0.7.13 + # via sphinx +babel==2.12.1 + # via sphinx +black==23.7.0 + # via blobmodel (pyproject.toml) +certifi==2023.5.7 + # via + # netcdf4 + # requests +cftime==1.6.2 + # via netcdf4 +charset-normalizer==3.2.0 + # via requests +click==8.1.6 + # via black +contourpy==1.1.0 + # via matplotlib +coverage[toml]==7.2.7 + # via pytest-cov +cycler==0.11.0 + # via matplotlib +docutils==0.18.1 + # via + # sphinx + # sphinx-rtd-theme +fonttools==4.41.0 + # via matplotlib +idna==3.4 + # via requests +imagesize==1.4.1 + # via sphinx +iniconfig==2.0.0 + # via pytest +jinja2==3.1.2 + # via sphinx +kiwisolver==1.4.4 + # via matplotlib +markupsafe==2.1.3 + # via jinja2 +matplotlib==3.7.2 + # via blobmodel (pyproject.toml) +mypy==1.4.1 + # via blobmodel (pyproject.toml) +mypy-extensions==1.0.0 + # via + # black + # mypy +netcdf4==1.6.4 + # via blobmodel (pyproject.toml) +nptyping==2.5.0 + # via blobmodel (pyproject.toml) +numpy==1.25.1 + # via + # blobmodel (pyproject.toml) + # cftime + # contourpy + # matplotlib + # netcdf4 + # nptyping + # pandas + # xarray +packaging==23.1 + # via + # black + # matplotlib + # pytest + # sphinx + # xarray +pandas==2.0.3 + # via xarray +pathspec==0.11.1 + # via black +pillow==10.0.0 + # via matplotlib +platformdirs==3.9.1 + # via black +pluggy==1.2.0 + # via pytest +pygments==2.15.1 + # via sphinx +pyparsing==3.0.9 + # via matplotlib +pytest==7.4.0 + # via pytest-cov +pytest-cov==4.1.0 + # via blobmodel (pyproject.toml) +python-dateutil==2.8.2 + # via + # matplotlib + # pandas +pytz==2023.3 + # via pandas +requests==2.31.0 + # via sphinx +six==1.16.0 + # via python-dateutil +snowballstemmer==2.2.0 + # via sphinx +sphinx==6.2.1 + # via + # blobmodel (pyproject.toml) + # sphinx-rtd-theme + # sphinxcontrib-jquery +sphinx-rtd-theme==1.2.2 + # via blobmodel (pyproject.toml) +sphinxcontrib-applehelp==1.0.4 + # via sphinx +sphinxcontrib-devhelp==1.0.2 + # via sphinx +sphinxcontrib-htmlhelp==2.0.1 + # via sphinx +sphinxcontrib-jquery==4.1 + # via sphinx-rtd-theme +sphinxcontrib-jsmath==1.0.1 + # via sphinx +sphinxcontrib-qthelp==1.0.3 + # via sphinx +sphinxcontrib-serializinghtml==1.1.5 + # via sphinx +tqdm==4.65.0 + # via blobmodel (pyproject.toml) +typing-extensions==4.7.1 + # via mypy +tzdata==2023.3 + # via pandas +urllib3==2.0.4 + # via requests +xarray==2023.7.0 + # via blobmodel (pyproject.toml) diff --git a/docs/visualize_model.rst b/docs/visualize_model.rst new file mode 100644 index 0000000..c917468 --- /dev/null +++ b/docs/visualize_model.rst @@ -0,0 +1,31 @@ +.. _visualize-model: + + +Visualize Model +=============== + +:py:mod:`blobmodel` provides a ``show_model`` function which makes visualizing a dataset very easy. +``show_model`` creates an animation of the model over time and saves it as a GIF if a filename is provided: + + +.. code-block:: python + + from blobmodel import show_model + + show_model(ds, gif_name = "example.gif") + +You can also adjust the interval between frames in milliseconds with the ``interval`` argument and change the fps of the created GIF with the ``fps`` argument. +A 2D example GIF would look like the following: + +.. image:: ../readme_files/2d_blobs.gif + :alt: StreamPlayer + :align: center + :scale: 80% + + +If you pass a 1D dataset to ``show_model`` the function automatically switches to creating a 1D animation like the following: + +.. image:: ../readme_files/1d_blobs.gif + :alt: StreamPlayer + :align: center + :scale: 80% diff --git a/docs/xarray_example.png b/docs/xarray_example.png new file mode 100644 index 0000000..8e4ff66 Binary files /dev/null and b/docs/xarray_example.png differ diff --git a/docs/y-periodicity.gif b/docs/y-periodicity.gif new file mode 100644 index 0000000..cd70581 Binary files /dev/null and b/docs/y-periodicity.gif differ diff --git a/examples/1d_animation.py b/examples/1d_animation.py index 6ae010f..352c181 100644 --- a/examples/1d_animation.py +++ b/examples/1d_animation.py @@ -17,4 +17,4 @@ ) ds = bm.make_realization(speed_up=True, error=1e-2) -show_model(dataset=ds, interval=100, save=True) +show_model(dataset=ds, interval=100, gif_name="1d_animation.gif") diff --git a/examples/2_sided_exp_pulse.py b/examples/2_sided_exp_pulse.py new file mode 100644 index 0000000..67448c5 --- /dev/null +++ b/examples/2_sided_exp_pulse.py @@ -0,0 +1,33 @@ +from blobmodel import Model, show_model, DefaultBlobFactory, BlobShapeImpl +import matplotlib.pyplot as plt +import numpy as np + + +bf = DefaultBlobFactory( + A_dist="deg", + wx_dist="deg", + spx_dist="deg", + spy_dist="deg", + shape_param_x_parameter=0.5, + shape_param_y_parameter=0.5, +) + +bm = Model( + Nx=100, + Ny=100, + Lx=10, + Ly=10, + dt=0.1, + T=10, + num_blobs=10, + blob_shape=BlobShapeImpl("2-exp", "2-exp"), + periodic_y=True, + t_drain=1e10, + blob_factory=bf, +) + +ds = bm.make_realization(speed_up=True, error=1e-10) + +show_model(ds) + +plt.show() diff --git a/examples/2d_animation.py b/examples/2d_animation.py index 4952886..ebb0a1e 100644 --- a/examples/2d_animation.py +++ b/examples/2d_animation.py @@ -18,4 +18,4 @@ # create data ds = bm.make_realization(speed_up=True, error=1e-2) # show animation and save as gif -show_model(dataset=ds, interval=100, save=True, gif_name="example.gif", fps=10) +show_model(dataset=ds, interval=100, gif_name="2d_animation.gif", fps=10) diff --git a/examples/changing_t_drain.py b/examples/changing_t_drain.py index 7773a2c..87ab345 100644 --- a/examples/changing_t_drain.py +++ b/examples/changing_t_drain.py @@ -24,7 +24,6 @@ def plot_cahnging_t_drain(ds): - x = np.linspace(0, 10, 100) t_p = 1 t_w = 1 / 10 diff --git a/examples/compare_to_analytical_sol.py b/examples/compare_to_analytical_sol.py index 87fe113..fe8946b 100644 --- a/examples/compare_to_analytical_sol.py +++ b/examples/compare_to_analytical_sol.py @@ -21,11 +21,10 @@ blob_factory=bf, ) -ds = tmp.make_realization(file_name="profile_comparison.nc", speed_up=True, error=1e-2) +ds = tmp.make_realization(file_name="profile_comparison.nc", speed_up=False, error=1e-4) def plot_convergence_to_analytical_solution(ds): - x = np.linspace(0, 10, 100) t_p = 1 t_w = 1 / 10 diff --git a/examples/custom_blobfactory.py b/examples/custom_blobfactory.py index d75edfa..aecfb1b 100644 --- a/examples/custom_blobfactory.py +++ b/examples/custom_blobfactory.py @@ -7,6 +7,7 @@ ) import numpy as np + # create custom class that inherits from BlobFactory # here you can define your custom parameter distributions class CustomBlobFactory(BlobFactory): @@ -21,7 +22,6 @@ def sample_blobs( blob_shape: AbstractBlobShape, t_drain: float, ) -> list[Blob]: - # set custom parameter distributions amp = np.linspace(0.01, 1, num=num_blobs) width = np.linspace(0.01, 1, num=num_blobs) diff --git a/examples/single_blob.py b/examples/single_blob.py index 421393b..2d5879c 100644 --- a/examples/single_blob.py +++ b/examples/single_blob.py @@ -1,6 +1,7 @@ from blobmodel import Model, show_model, BlobFactory, Blob, AbstractBlobShape import numpy as np + # here you can define your custom parameter distributions class CustomBlobFactory(BlobFactory): def __init__(self) -> None: @@ -14,7 +15,6 @@ def sample_blobs( blob_shape: AbstractBlobShape, t_drain: float, ) -> list[Blob]: - # set custom parameter distributions amp = np.ones(num_blobs) width = np.ones(num_blobs) @@ -66,4 +66,4 @@ def is_one_dimensional(self) -> bool: ds = bm.make_realization(speed_up=True, error=1e-2) # show animation and save as gif -show_model(dataset=ds, interval=100, save=True, gif_name="example.gif", fps=10) +show_model(dataset=ds, interval=100, gif_name="example.gif", fps=10) diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index 23880a7..0000000 --- a/poetry.lock +++ /dev/null @@ -1,764 +0,0 @@ -[[package]] -name = "atomicwrites" -version = "1.4.0" -description = "Atomic file writes." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[[package]] -name = "attrs" -version = "21.4.0" -description = "Classes Without Boilerplate" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] -docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] - -[[package]] -name = "black" -version = "22.1.0" -description = "The uncompromising code formatter." -category = "main" -optional = false -python-versions = ">=3.6.2" - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = ">=1.1.0" - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - -[[package]] -name = "click" -version = "8.0.4" -description = "Composable command line interface toolkit" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "colorama" -version = "0.4.4" -description = "Cross-platform colored terminal text." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[[package]] -name = "cycler" -version = "0.11.0" -description = "Composable style cycles" -category = "main" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "docformatter" -version = "1.4" -description = "Formats docstrings to follow PEP 257." -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -untokenize = "*" - -[[package]] -name = "fonttools" -version = "4.29.1" -description = "Tools to manipulate font files" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.extras] -all = ["fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "zopfli (>=0.1.4)", "lz4 (>=1.7.4.2)", "matplotlib", "sympy", "skia-pathops (>=0.5.0)", "brotlicffi (>=0.8.0)", "scipy", "brotli (>=1.0.1)", "munkres", "unicodedata2 (>=14.0.0)", "xattr"] -graphite = ["lz4 (>=1.7.4.2)"] -interpolatable = ["scipy", "munkres"] -lxml = ["lxml (>=4.0,<5)"] -pathops = ["skia-pathops (>=0.5.0)"] -plot = ["matplotlib"] -symfont = ["sympy"] -type1 = ["xattr"] -ufo = ["fs (>=2.2.0,<3)"] -unicode = ["unicodedata2 (>=14.0.0)"] -woff = ["zopfli (>=0.1.4)", "brotlicffi (>=0.8.0)", "brotli (>=1.0.1)"] - -[[package]] -name = "iniconfig" -version = "1.1.1" -description = "iniconfig: brain-dead simple config-ini parsing" -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "kiwisolver" -version = "1.3.2" -description = "A fast implementation of the Cassowary constraint solver" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "matplotlib" -version = "3.5.1" -description = "Python plotting package" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -cycler = ">=0.10" -fonttools = ">=4.22.0" -kiwisolver = ">=1.0.1" -numpy = ">=1.17" -packaging = ">=20.0" -pillow = ">=6.2.0" -pyparsing = ">=2.2.1" -python-dateutil = ">=2.7" -setuptools_scm = ">=4" - -[[package]] -name = "mypy" -version = "0.931" -description = "Optional static typing for Python" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -mypy-extensions = ">=0.4.3" -tomli = ">=1.1.0" -typing-extensions = ">=3.10" - -[package.extras] -dmypy = ["psutil (>=4.0)"] -python2 = ["typed-ast (>=1.4.0,<2)"] - -[[package]] -name = "mypy-extensions" -version = "0.4.3" -description = "Experimental type system extensions for programs checked with the mypy typechecker." -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "nptyping" -version = "1.4.4" -description = "Type hints for Numpy." -category = "main" -optional = false -python-versions = ">=3.5" - -[package.dependencies] -numpy = "*" -typish = ">=1.7.0" - -[package.extras] -test = ["pycodestyle", "pylint", "pytest", "coverage", "codecov", "scons", "radon", "xenon", "autoflake", "isort"] - -[[package]] -name = "numpy" -version = "1.22.2" -description = "NumPy is the fundamental package for array computing with Python." -category = "main" -optional = false -python-versions = ">=3.8" - -[[package]] -name = "packaging" -version = "21.3" -description = "Core utilities for Python packages" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" - -[[package]] -name = "pandas" -version = "1.4.1" -description = "Powerful data structures for data analysis, time series, and statistics" -category = "main" -optional = false -python-versions = ">=3.8" - -[package.dependencies] -numpy = {version = ">=1.21.0", markers = "python_version >= \"3.10\""} -python-dateutil = ">=2.8.1" -pytz = ">=2020.1" - -[package.extras] -test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] - -[[package]] -name = "pathspec" -version = "0.9.0" -description = "Utility library for gitignore style pattern matching of file paths." -category = "main" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" - -[[package]] -name = "pillow" -version = "9.0.1" -description = "Python Imaging Library (Fork)" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "platformdirs" -version = "2.5.1" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "main" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] - -[[package]] -name = "pluggy" -version = "1.0.0" -description = "plugin and hook calling mechanisms for python" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "py" -version = "1.11.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[[package]] -name = "pyparsing" -version = "3.0.7" -description = "Python parsing module" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.extras] -diagrams = ["jinja2", "railroad-diagrams"] - -[[package]] -name = "pytest" -version = "7.0.1" -description = "pytest: simple powerful testing with Python" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} -attrs = ">=19.2.0" -colorama = {version = "*", markers = "sys_platform == \"win32\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=0.12,<2.0" -py = ">=1.8.2" -tomli = ">=1.0.0" - -[package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] - -[[package]] -name = "python-dateutil" -version = "2.8.2" -description = "Extensions to the standard Python datetime module" -category = "main" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "pytz" -version = "2021.3" -description = "World timezone definitions, modern and historical" -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "scipy" -version = "1.8.0" -description = "SciPy: Scientific Library for Python" -category = "main" -optional = false -python-versions = ">=3.8,<3.11" - -[package.dependencies] -numpy = ">=1.17.3,<1.25.0" - -[[package]] -name = "setuptools-scm" -version = "6.4.2" -description = "the blessed package to manage your versions by scm tags" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -packaging = ">=20.0" -tomli = ">=1.0.0" - -[package.extras] -test = ["pytest (>=6.2)", "virtualenv (>20)"] -toml = ["setuptools (>=42)"] - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "tqdm" -version = "4.62.3" -description = "Fast, Extensible Progress Meter" -category = "main" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[package.extras] -dev = ["py-make (>=0.1.0)", "twine", "wheel"] -notebook = ["ipywidgets (>=6)"] -telegram = ["requests"] - -[[package]] -name = "typing-extensions" -version = "4.1.1" -description = "Backported and Experimental Type Hints for Python 3.6+" -category = "main" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "typish" -version = "1.9.3" -description = "Functionality for types" -category = "main" -optional = false -python-versions = "*" - -[package.extras] -test = ["numpy", "nptyping (>=1.3.0)", "pycodestyle", "pylint", "mypy", "pytest", "coverage", "codecov"] - -[[package]] -name = "untokenize" -version = "0.1.1" -description = "Transforms tokens into original source code (while preserving whitespace)." -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "xarray" -version = "0.21.1" -description = "N-D labeled arrays and datasets in Python" -category = "main" -optional = false -python-versions = ">=3.8" - -[package.dependencies] -numpy = ">=1.18" -packaging = ">=20.0" -pandas = ">=1.1" - -[package.extras] -accel = ["scipy", "bottleneck", "numbagg"] -complete = ["netcdf4", "h5netcdf", "scipy", "pydap", "zarr", "fsspec", "cftime", "rasterio", "cfgrib", "pooch", "bottleneck", "numbagg", "dask", "matplotlib", "seaborn", "nc-time-axis"] -docs = ["netcdf4", "h5netcdf", "scipy", "pydap", "zarr", "fsspec", "cftime", "rasterio", "cfgrib", "pooch", "bottleneck", "numbagg", "dask", "matplotlib", "seaborn", "nc-time-axis", "sphinx-autosummary-accessors", "sphinx-rtd-theme", "ipython", "ipykernel", "jupyter-client", "nbsphinx", "scanpydoc"] -io = ["netcdf4", "h5netcdf", "scipy", "pydap", "zarr", "fsspec", "cftime", "rasterio", "cfgrib", "pooch"] -parallel = ["dask"] -viz = ["matplotlib", "seaborn", "nc-time-axis"] - -[metadata] -lock-version = "1.1" -python-versions = ">=3.10,<3.11" -content-hash = "ca4ac62c517d28aa7129ac829eeb6b151977a4c9632042bedb010f64d4f7bd1f" - -[metadata.files] -atomicwrites = [ - {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, - {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, -] -attrs = [ - {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, - {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, -] -black = [ - {file = "black-22.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1297c63b9e1b96a3d0da2d85d11cd9bf8664251fd69ddac068b98dc4f34f73b6"}, - {file = "black-22.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ff96450d3ad9ea499fc4c60e425a1439c2120cbbc1ab959ff20f7c76ec7e866"}, - {file = "black-22.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e21e1f1efa65a50e3960edd068b6ae6d64ad6235bd8bfea116a03b21836af71"}, - {file = "black-22.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f69158a7d120fd641d1fa9a921d898e20d52e44a74a6fbbcc570a62a6bc8ab"}, - {file = "black-22.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:228b5ae2c8e3d6227e4bde5920d2fc66cc3400fde7bcc74f480cb07ef0b570d5"}, - {file = "black-22.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b1a5ed73ab4c482208d20434f700d514f66ffe2840f63a6252ecc43a9bc77e8a"}, - {file = "black-22.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35944b7100af4a985abfcaa860b06af15590deb1f392f06c8683b4381e8eeaf0"}, - {file = "black-22.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7835fee5238fc0a0baf6c9268fb816b5f5cd9b8793423a75e8cd663c48d073ba"}, - {file = "black-22.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dae63f2dbf82882fa3b2a3c49c32bffe144970a573cd68d247af6560fc493ae1"}, - {file = "black-22.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa1db02410b1924b6749c245ab38d30621564e658297484952f3d8a39fce7e8"}, - {file = "black-22.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c8226f50b8c34a14608b848dc23a46e5d08397d009446353dad45e04af0c8e28"}, - {file = "black-22.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2d6f331c02f0f40aa51a22e479c8209d37fcd520c77721c034517d44eecf5912"}, - {file = "black-22.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:742ce9af3086e5bd07e58c8feb09dbb2b047b7f566eb5f5bc63fd455814979f3"}, - {file = "black-22.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fdb8754b453fb15fad3f72cd9cad3e16776f0964d67cf30ebcbf10327a3777a3"}, - {file = "black-22.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5660feab44c2e3cb24b2419b998846cbb01c23c7fe645fee45087efa3da2d61"}, - {file = "black-22.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:6f2f01381f91c1efb1451998bd65a129b3ed6f64f79663a55fe0e9b74a5f81fd"}, - {file = "black-22.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:efbadd9b52c060a8fc3b9658744091cb33c31f830b3f074422ed27bad2b18e8f"}, - {file = "black-22.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8871fcb4b447206904932b54b567923e5be802b9b19b744fdff092bd2f3118d0"}, - {file = "black-22.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccad888050f5393f0d6029deea2a33e5ae371fd182a697313bdbd835d3edaf9c"}, - {file = "black-22.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07e5c049442d7ca1a2fc273c79d1aecbbf1bc858f62e8184abe1ad175c4f7cc2"}, - {file = "black-22.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:373922fc66676133ddc3e754e4509196a8c392fec3f5ca4486673e685a421321"}, - {file = "black-22.1.0-py3-none-any.whl", hash = "sha256:3524739d76b6b3ed1132422bf9d82123cd1705086723bc3e235ca39fd21c667d"}, - {file = "black-22.1.0.tar.gz", hash = "sha256:a7c0192d35635f6fc1174be575cb7915e92e5dd629ee79fdaf0dcfa41a80afb5"}, -] -click = [ - {file = "click-8.0.4-py3-none-any.whl", hash = "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1"}, - {file = "click-8.0.4.tar.gz", hash = "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"}, -] -colorama = [ - {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, - {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, -] -cycler = [ - {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, - {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, -] -docformatter = [ - {file = "docformatter-1.4.tar.gz", hash = "sha256:064e6d81f04ac96bc0d176cbaae953a0332482b22d3ad70d47c8a7f2732eef6f"}, -] -fonttools = [ - {file = "fonttools-4.29.1-py3-none-any.whl", hash = "sha256:1933415e0fbdf068815cb1baaa1f159e17830215f7e8624e5731122761627557"}, - {file = "fonttools-4.29.1.zip", hash = "sha256:2b18a172120e32128a80efee04cff487d5d140fe7d817deb648b2eee023a40e4"}, -] -iniconfig = [ - {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, - {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, -] -kiwisolver = [ - {file = "kiwisolver-1.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1d819553730d3c2724582124aee8a03c846ec4362ded1034c16fb3ef309264e6"}, - {file = "kiwisolver-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8d93a1095f83e908fc253f2fb569c2711414c0bfd451cab580466465b235b470"}, - {file = "kiwisolver-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4550a359c5157aaf8507e6820d98682872b9100ce7607f8aa070b4b8af6c298"}, - {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2210f28778c7d2ee13f3c2a20a3a22db889e75f4ec13a21072eabb5693801e84"}, - {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:82f49c5a79d3839bc8f38cb5f4bfc87e15f04cbafa5fbd12fb32c941cb529cfb"}, - {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9661a04ca3c950a8ac8c47f53cbc0b530bce1b52f516a1e87b7736fec24bfff0"}, - {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ddb500a2808c100e72c075cbb00bf32e62763c82b6a882d403f01a119e3f402"}, - {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72be6ebb4e92520b9726d7146bc9c9b277513a57a38efcf66db0620aec0097e0"}, - {file = "kiwisolver-1.3.2-cp310-cp310-win32.whl", hash = "sha256:83d2c9db5dfc537d0171e32de160461230eb14663299b7e6d18ca6dca21e4977"}, - {file = "kiwisolver-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:cba430db673c29376135e695c6e2501c44c256a81495da849e85d1793ee975ad"}, - {file = "kiwisolver-1.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4116ba9a58109ed5e4cb315bdcbff9838f3159d099ba5259c7c7fb77f8537492"}, - {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19554bd8d54cf41139f376753af1a644b63c9ca93f8f72009d50a2080f870f77"}, - {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7a4cf5bbdc861987a7745aed7a536c6405256853c94abc9f3287c3fa401b174"}, - {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0007840186bacfaa0aba4466d5890334ea5938e0bb7e28078a0eb0e63b5b59d5"}, - {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec2eba188c1906b05b9b49ae55aae4efd8150c61ba450e6721f64620c50b59eb"}, - {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3dbb3cea20b4af4f49f84cffaf45dd5f88e8594d18568e0225e6ad9dec0e7967"}, - {file = "kiwisolver-1.3.2-cp37-cp37m-win32.whl", hash = "sha256:5326ddfacbe51abf9469fe668944bc2e399181a2158cb5d45e1d40856b2a0589"}, - {file = "kiwisolver-1.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:c6572c2dab23c86a14e82c245473d45b4c515314f1f859e92608dcafbd2f19b8"}, - {file = "kiwisolver-1.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b5074fb09429f2b7bc82b6fb4be8645dcbac14e592128beeff5461dcde0af09f"}, - {file = "kiwisolver-1.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:22521219ca739654a296eea6d4367703558fba16f98688bd8ce65abff36eaa84"}, - {file = "kiwisolver-1.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c358721aebd40c243894298f685a19eb0491a5c3e0b923b9f887ef1193ddf829"}, - {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ba5a1041480c6e0a8b11a9544d53562abc2d19220bfa14133e0cdd9967e97af"}, - {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44e6adf67577dbdfa2d9f06db9fbc5639afefdb5bf2b4dfec25c3a7fbc619536"}, - {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1d45d1c74f88b9f41062716c727f78f2a59a5476ecbe74956fafb423c5c87a76"}, - {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70adc3658138bc77a36ce769f5f183169bc0a2906a4f61f09673f7181255ac9b"}, - {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6a5431940f28b6de123de42f0eb47b84a073ee3c3345dc109ad550a3307dd28"}, - {file = "kiwisolver-1.3.2-cp38-cp38-win32.whl", hash = "sha256:ee040a7de8d295dbd261ef2d6d3192f13e2b08ec4a954de34a6fb8ff6422e24c"}, - {file = "kiwisolver-1.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:8dc3d842fa41a33fe83d9f5c66c0cc1f28756530cd89944b63b072281e852031"}, - {file = "kiwisolver-1.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a498bcd005e8a3fedd0022bb30ee0ad92728154a8798b703f394484452550507"}, - {file = "kiwisolver-1.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:80efd202108c3a4150e042b269f7c78643420cc232a0a771743bb96b742f838f"}, - {file = "kiwisolver-1.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f8eb7b6716f5b50e9c06207a14172cf2de201e41912ebe732846c02c830455b9"}, - {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f441422bb313ab25de7b3dbfd388e790eceb76ce01a18199ec4944b369017009"}, - {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:30fa008c172355c7768159983a7270cb23838c4d7db73d6c0f6b60dde0d432c6"}, - {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f8f6c8f4f1cff93ca5058d6ec5f0efda922ecb3f4c5fb76181f327decff98b8"}, - {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba677bcaff9429fd1bf01648ad0901cea56c0d068df383d5f5856d88221fe75b"}, - {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7843b1624d6ccca403a610d1277f7c28ad184c5aa88a1750c1a999754e65b439"}, - {file = "kiwisolver-1.3.2-cp39-cp39-win32.whl", hash = "sha256:e6f5eb2f53fac7d408a45fbcdeda7224b1cfff64919d0f95473420a931347ae9"}, - {file = "kiwisolver-1.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:eedd3b59190885d1ebdf6c5e0ca56828beb1949b4dfe6e5d0256a461429ac386"}, - {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:dedc71c8eb9c5096037766390172c34fb86ef048b8e8958b4e484b9e505d66bc"}, - {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:bf7eb45d14fc036514c09554bf983f2a72323254912ed0c3c8e697b62c4c158f"}, - {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2b65bd35f3e06a47b5c30ea99e0c2b88f72c6476eedaf8cfbc8e66adb5479dcf"}, - {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25405f88a37c5f5bcba01c6e350086d65e7465fd1caaf986333d2a045045a223"}, - {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:bcadb05c3d4794eb9eee1dddf1c24215c92fb7b55a80beae7a60530a91060560"}, - {file = "kiwisolver-1.3.2.tar.gz", hash = "sha256:fc4453705b81d03568d5b808ad8f09c77c47534f6ac2e72e733f9ca4714aa75c"}, -] -matplotlib = [ - {file = "matplotlib-3.5.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:456cc8334f6d1124e8ff856b42d2cc1c84335375a16448189999496549f7182b"}, - {file = "matplotlib-3.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8a77906dc2ef9b67407cec0bdbf08e3971141e535db888974a915be5e1e3efc6"}, - {file = "matplotlib-3.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e70ae6475cfd0fad3816dcbf6cac536dc6f100f7474be58d59fa306e6e768a4"}, - {file = "matplotlib-3.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53273c5487d1c19c3bc03b9eb82adaf8456f243b97ed79d09dded747abaf1235"}, - {file = "matplotlib-3.5.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3b6f3fd0d8ca37861c31e9a7cab71a0ef14c639b4c95654ea1dd153158bf0df"}, - {file = "matplotlib-3.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8c87cdaf06fd7b2477f68909838ff4176f105064a72ca9d24d3f2a29f73d393"}, - {file = "matplotlib-3.5.1-cp310-cp310-win32.whl", hash = "sha256:e2f28a07b4f82abb40267864ad7b3a4ed76f1b1663e81c7efc84a9b9248f672f"}, - {file = "matplotlib-3.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:d70a32ee1f8b55eed3fd4e892f0286df8cccc7e0475c11d33b5d0a148f5c7599"}, - {file = "matplotlib-3.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:68fa30cec89b6139dc559ed6ef226c53fd80396da1919a1b5ef672c911aaa767"}, - {file = "matplotlib-3.5.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e3484d8455af3fdb0424eae1789af61f6a79da0c80079125112fd5c1b604218"}, - {file = "matplotlib-3.5.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e293b16cf303fe82995e41700d172a58a15efc5331125d08246b520843ef21ee"}, - {file = "matplotlib-3.5.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e3520a274a0e054e919f5b3279ee5dbccf5311833819ccf3399dab7c83e90a25"}, - {file = "matplotlib-3.5.1-cp37-cp37m-win32.whl", hash = "sha256:2252bfac85cec7af4a67e494bfccf9080bcba8a0299701eab075f48847cca907"}, - {file = "matplotlib-3.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:abf67e05a1b7f86583f6ebd01f69b693b9c535276f4e943292e444855870a1b8"}, - {file = "matplotlib-3.5.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6c094e4bfecd2fa7f9adffd03d8abceed7157c928c2976899de282f3600f0a3d"}, - {file = "matplotlib-3.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:506b210cc6e66a0d1c2bb765d055f4f6bc2745070fb1129203b67e85bbfa5c18"}, - {file = "matplotlib-3.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b04fc29bcef04d4e2d626af28d9d892be6aba94856cb46ed52bcb219ceac8943"}, - {file = "matplotlib-3.5.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:577ed20ec9a18d6bdedb4616f5e9e957b4c08563a9f985563a31fd5b10564d2a"}, - {file = "matplotlib-3.5.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e486f60db0cd1c8d68464d9484fd2a94011c1ac8593d765d0211f9daba2bd535"}, - {file = "matplotlib-3.5.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b71f3a7ca935fc759f2aed7cec06cfe10bc3100fadb5dbd9c435b04e557971e1"}, - {file = "matplotlib-3.5.1-cp38-cp38-win32.whl", hash = "sha256:d24e5bb8028541ce25e59390122f5e48c8506b7e35587e5135efcb6471b4ac6c"}, - {file = "matplotlib-3.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:778d398c4866d8e36ee3bf833779c940b5f57192fa0a549b3ad67bc4c822771b"}, - {file = "matplotlib-3.5.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bb1c613908f11bac270bc7494d68b1ef6e7c224b7a4204d5dacf3522a41e2bc3"}, - {file = "matplotlib-3.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:edf5e4e1d5fb22c18820e8586fb867455de3b109c309cb4fce3aaed85d9468d1"}, - {file = "matplotlib-3.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:40e0d7df05e8efe60397c69b467fc8f87a2affeb4d562fe92b72ff8937a2b511"}, - {file = "matplotlib-3.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a350ca685d9f594123f652ba796ee37219bf72c8e0fc4b471473d87121d6d34"}, - {file = "matplotlib-3.5.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3e66497cd990b1a130e21919b004da2f1dc112132c01ac78011a90a0f9229778"}, - {file = "matplotlib-3.5.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:87900c67c0f1728e6db17c6809ec05c025c6624dcf96a8020326ea15378fe8e7"}, - {file = "matplotlib-3.5.1-cp39-cp39-win32.whl", hash = "sha256:b8a4fb2a0c5afbe9604f8a91d7d0f27b1832c3e0b5e365f95a13015822b4cd65"}, - {file = "matplotlib-3.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:fe8d40c434a8e2c68d64c6d6a04e77f21791a93ff6afe0dce169597c110d3079"}, - {file = "matplotlib-3.5.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:34a1fc29f8f96e78ec57a5eff5e8d8b53d3298c3be6df61e7aa9efba26929522"}, - {file = "matplotlib-3.5.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b19a761b948e939a9e20173aaae76070025f0024fc8f7ba08bef22a5c8573afc"}, - {file = "matplotlib-3.5.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6803299cbf4665eca14428d9e886de62e24f4223ac31ab9c5d6d5339a39782c7"}, - {file = "matplotlib-3.5.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:14334b9902ec776461c4b8c6516e26b450f7ebe0b3ef8703bf5cdfbbaecf774a"}, - {file = "matplotlib-3.5.1.tar.gz", hash = "sha256:b2e9810e09c3a47b73ce9cab5a72243a1258f61e7900969097a817232246ce1c"}, -] -mypy = [ - {file = "mypy-0.931-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c5b42d0815e15518b1f0990cff7a705805961613e701db60387e6fb663fe78a"}, - {file = "mypy-0.931-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c89702cac5b302f0c5d33b172d2b55b5df2bede3344a2fbed99ff96bddb2cf00"}, - {file = "mypy-0.931-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:300717a07ad09525401a508ef5d105e6b56646f7942eb92715a1c8d610149714"}, - {file = "mypy-0.931-cp310-cp310-win_amd64.whl", hash = "sha256:7b3f6f557ba4afc7f2ce6d3215d5db279bcf120b3cfd0add20a5d4f4abdae5bc"}, - {file = "mypy-0.931-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:1bf752559797c897cdd2c65f7b60c2b6969ffe458417b8d947b8340cc9cec08d"}, - {file = "mypy-0.931-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4365c60266b95a3f216a3047f1d8e3f895da6c7402e9e1ddfab96393122cc58d"}, - {file = "mypy-0.931-cp36-cp36m-win_amd64.whl", hash = "sha256:1b65714dc296a7991000b6ee59a35b3f550e0073411ac9d3202f6516621ba66c"}, - {file = "mypy-0.931-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e839191b8da5b4e5d805f940537efcaa13ea5dd98418f06dc585d2891d228cf0"}, - {file = "mypy-0.931-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:50c7346a46dc76a4ed88f3277d4959de8a2bd0a0fa47fa87a4cde36fe247ac05"}, - {file = "mypy-0.931-cp37-cp37m-win_amd64.whl", hash = "sha256:d8f1ff62f7a879c9fe5917b3f9eb93a79b78aad47b533911b853a757223f72e7"}, - {file = "mypy-0.931-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f9fe20d0872b26c4bba1c1be02c5340de1019530302cf2dcc85c7f9fc3252ae0"}, - {file = "mypy-0.931-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1b06268df7eb53a8feea99cbfff77a6e2b205e70bf31743e786678ef87ee8069"}, - {file = "mypy-0.931-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8c11003aaeaf7cc2d0f1bc101c1cc9454ec4cc9cb825aef3cafff8a5fdf4c799"}, - {file = "mypy-0.931-cp38-cp38-win_amd64.whl", hash = "sha256:d9d2b84b2007cea426e327d2483238f040c49405a6bf4074f605f0156c91a47a"}, - {file = "mypy-0.931-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ff3bf387c14c805ab1388185dd22d6b210824e164d4bb324b195ff34e322d166"}, - {file = "mypy-0.931-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5b56154f8c09427bae082b32275a21f500b24d93c88d69a5e82f3978018a0266"}, - {file = "mypy-0.931-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8ca7f8c4b1584d63c9a0f827c37ba7a47226c19a23a753d52e5b5eddb201afcd"}, - {file = "mypy-0.931-cp39-cp39-win_amd64.whl", hash = "sha256:74f7eccbfd436abe9c352ad9fb65872cc0f1f0a868e9d9c44db0893440f0c697"}, - {file = "mypy-0.931-py3-none-any.whl", hash = "sha256:1171f2e0859cfff2d366da2c7092b06130f232c636a3f7301e3feb8b41f6377d"}, - {file = "mypy-0.931.tar.gz", hash = "sha256:0038b21890867793581e4cb0d810829f5fd4441aa75796b53033af3aa30430ce"}, -] -mypy-extensions = [ - {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, - {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, -] -nptyping = [ - {file = "nptyping-1.4.4-py3-none-any.whl", hash = "sha256:8128473b8ba0e65f3d6edc727cd99024e162edcf7e8a0ea8f9dfa6b070934d14"}, -] -numpy = [ - {file = "numpy-1.22.2-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:515a8b6edbb904594685da6e176ac9fbea8f73a5ebae947281de6613e27f1956"}, - {file = "numpy-1.22.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:76a4f9bce0278becc2da7da3b8ef854bed41a991f4226911a24a9711baad672c"}, - {file = "numpy-1.22.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:168259b1b184aa83a514f307352c25c56af111c269ffc109d9704e81f72e764b"}, - {file = "numpy-1.22.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3556c5550de40027d3121ebbb170f61bbe19eb639c7ad0c7b482cd9b560cd23b"}, - {file = "numpy-1.22.2-cp310-cp310-win_amd64.whl", hash = "sha256:aafa46b5a39a27aca566198d3312fb3bde95ce9677085efd02c86f7ef6be4ec7"}, - {file = "numpy-1.22.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:55535c7c2f61e2b2fc817c5cbe1af7cb907c7f011e46ae0a52caa4be1f19afe2"}, - {file = "numpy-1.22.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:60cb8e5933193a3cc2912ee29ca331e9c15b2da034f76159b7abc520b3d1233a"}, - {file = "numpy-1.22.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b536b6840e84c1c6a410f3a5aa727821e6108f3454d81a5cd5900999ef04f89"}, - {file = "numpy-1.22.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2638389562bda1635b564490d76713695ff497242a83d9b684d27bb4a6cc9d7a"}, - {file = "numpy-1.22.2-cp38-cp38-win32.whl", hash = "sha256:6767ad399e9327bfdbaa40871be4254d1995f4a3ca3806127f10cec778bd9896"}, - {file = "numpy-1.22.2-cp38-cp38-win_amd64.whl", hash = "sha256:03ae5850619abb34a879d5f2d4bb4dcd025d6d8fb72f5e461dae84edccfe129f"}, - {file = "numpy-1.22.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:d76a26c5118c4d96e264acc9e3242d72e1a2b92e739807b3b69d8d47684b6677"}, - {file = "numpy-1.22.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:15efb7b93806d438e3bc590ca8ef2f953b0ce4f86f337ef4559d31ec6cf9d7dd"}, - {file = "numpy-1.22.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:badca914580eb46385e7f7e4e426fea6de0a37b9e06bec252e481ae7ec287082"}, - {file = "numpy-1.22.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94dd11d9f13ea1be17bac39c1942f527cbf7065f94953cf62dfe805653da2f8f"}, - {file = "numpy-1.22.2-cp39-cp39-win32.whl", hash = "sha256:8cf33634b60c9cef346663a222d9841d3bbbc0a2f00221d6bcfd0d993d5543f6"}, - {file = "numpy-1.22.2-cp39-cp39-win_amd64.whl", hash = "sha256:59153979d60f5bfe9e4c00e401e24dfe0469ef8da6d68247439d3278f30a180f"}, - {file = "numpy-1.22.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a176959b6e7e00b5a0d6f549a479f869829bfd8150282c590deee6d099bbb6e"}, - {file = "numpy-1.22.2.zip", hash = "sha256:076aee5a3763d41da6bef9565fdf3cb987606f567cd8b104aded2b38b7b47abf"}, -] -packaging = [ - {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, - {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, -] -pandas = [ - {file = "pandas-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3dfb32ed50122fe8c5e7f2b8d97387edd742cc78f9ec36f007ee126cd3720907"}, - {file = "pandas-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0259cd11e7e6125aaea3af823b80444f3adad6149ff4c97fef760093598b3e34"}, - {file = "pandas-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:96e9ece5759f9b47ae43794b6359bbc54805d76e573b161ae770c1ea59393106"}, - {file = "pandas-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:508c99debccd15790d526ce6b1624b97a5e1e4ca5b871319fb0ebfd46b8f4dad"}, - {file = "pandas-1.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6a7bbbb7950063bfc942f8794bc3e31697c020a14f1cd8905fc1d28ec674a01"}, - {file = "pandas-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:c614001129b2a5add5e3677c3a213a9e6fd376204cb8d17c04e84ff7dfc02a73"}, - {file = "pandas-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4e1176f45981c8ccc8161bc036916c004ca51037a7ed73f2d2a9857e6dbe654f"}, - {file = "pandas-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bbb15ad79050e8b8d39ec40dd96a30cd09b886a2ae8848d0df1abba4d5502a67"}, - {file = "pandas-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6d6ad1da00c7cc7d8dd1559a6ba59ba3973be6b15722d49738b2be0977eb8a0c"}, - {file = "pandas-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:358b0bc98a5ff067132d23bf7a2242ee95db9ea5b7bbc401cf79205f11502fd3"}, - {file = "pandas-1.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6105af6533f8b63a43ea9f08a2ede04e8f43e49daef0209ab0d30352bcf08bee"}, - {file = "pandas-1.4.1-cp38-cp38-win32.whl", hash = "sha256:04dd15d9db538470900c851498e532ef28d4e56bfe72c9523acb32042de43dfb"}, - {file = "pandas-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:1b384516dbb4e6aae30e3464c2e77c563da5980440fbdfbd0968e3942f8f9d70"}, - {file = "pandas-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f02e85e6d832be37d7f16cf6ac8bb26b519ace3e5f3235564a91c7f658ab2a43"}, - {file = "pandas-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0b1a13f647e4209ed7dbb5da3497891d0045da9785327530ab696417ef478f84"}, - {file = "pandas-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:19f7c632436b1b4f84615c3b127bbd7bc603db95e3d4332ed259dc815c9aaa26"}, - {file = "pandas-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ea47ba1d6f359680130bd29af497333be6110de8f4c35b9211eec5a5a9630fa"}, - {file = "pandas-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e5a7a1e0ecaac652326af627a3eca84886da9e667d68286866d4e33f6547caf"}, - {file = "pandas-1.4.1-cp39-cp39-win32.whl", hash = "sha256:1d85d5f6be66dfd6d1d8d13b9535e342a2214260f1852654b19fa4d7b8d1218b"}, - {file = "pandas-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:3129a35d9dad1d80c234dd78f8f03141b914395d23f97cf92a366dcd19f8f8bf"}, - {file = "pandas-1.4.1.tar.gz", hash = "sha256:8db93ec98ac7cb5f8ac1420c10f5e3c43533153f253fe7fb6d891cf5aa2b80d2"}, -] -pathspec = [ - {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, - {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, -] -pillow = [ - {file = "Pillow-9.0.1-1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a5d24e1d674dd9d72c66ad3ea9131322819ff86250b30dc5821cbafcfa0b96b4"}, - {file = "Pillow-9.0.1-1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2632d0f846b7c7600edf53c48f8f9f1e13e62f66a6dbc15191029d950bfed976"}, - {file = "Pillow-9.0.1-1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b9618823bd237c0d2575283f2939655f54d51b4527ec3972907a927acbcc5bfc"}, - {file = "Pillow-9.0.1-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:9bfdb82cdfeccec50aad441afc332faf8606dfa5e8efd18a6692b5d6e79f00fd"}, - {file = "Pillow-9.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5100b45a4638e3c00e4d2320d3193bdabb2d75e79793af7c3eb139e4f569f16f"}, - {file = "Pillow-9.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:528a2a692c65dd5cafc130de286030af251d2ee0483a5bf50c9348aefe834e8a"}, - {file = "Pillow-9.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f29d831e2151e0b7b39981756d201f7108d3d215896212ffe2e992d06bfe049"}, - {file = "Pillow-9.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:855c583f268edde09474b081e3ddcd5cf3b20c12f26e0d434e1386cc5d318e7a"}, - {file = "Pillow-9.0.1-cp310-cp310-win32.whl", hash = "sha256:d9d7942b624b04b895cb95af03a23407f17646815495ce4547f0e60e0b06f58e"}, - {file = "Pillow-9.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:81c4b81611e3a3cb30e59b0cf05b888c675f97e3adb2c8672c3154047980726b"}, - {file = "Pillow-9.0.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:413ce0bbf9fc6278b2d63309dfeefe452835e1c78398efb431bab0672fe9274e"}, - {file = "Pillow-9.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80fe64a6deb6fcfdf7b8386f2cf216d329be6f2781f7d90304351811fb591360"}, - {file = "Pillow-9.0.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cef9c85ccbe9bee00909758936ea841ef12035296c748aaceee535969e27d31b"}, - {file = "Pillow-9.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d19397351f73a88904ad1aee421e800fe4bbcd1aeee6435fb62d0a05ccd1030"}, - {file = "Pillow-9.0.1-cp37-cp37m-win32.whl", hash = "sha256:d21237d0cd37acded35154e29aec853e945950321dd2ffd1a7d86fe686814669"}, - {file = "Pillow-9.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ede5af4a2702444a832a800b8eb7f0a7a1c0eed55b644642e049c98d589e5092"}, - {file = "Pillow-9.0.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:b5b3f092fe345c03bca1e0b687dfbb39364b21ebb8ba90e3fa707374b7915204"}, - {file = "Pillow-9.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:335ace1a22325395c4ea88e00ba3dc89ca029bd66bd5a3c382d53e44f0ccd77e"}, - {file = "Pillow-9.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db6d9fac65bd08cea7f3540b899977c6dee9edad959fa4eaf305940d9cbd861c"}, - {file = "Pillow-9.0.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f154d173286a5d1863637a7dcd8c3437bb557520b01bddb0be0258dcb72696b5"}, - {file = "Pillow-9.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d4b1341ac07ae07eb2cc682f459bec932a380c3b122f5540432d8977e64eae"}, - {file = "Pillow-9.0.1-cp38-cp38-win32.whl", hash = "sha256:effb7749713d5317478bb3acb3f81d9d7c7f86726d41c1facca068a04cf5bb4c"}, - {file = "Pillow-9.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:7f7609a718b177bf171ac93cea9fd2ddc0e03e84d8fa4e887bdfc39671d46b00"}, - {file = "Pillow-9.0.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:80ca33961ced9c63358056bd08403ff866512038883e74f3a4bf88ad3eb66838"}, - {file = "Pillow-9.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c3c33ac69cf059bbb9d1a71eeaba76781b450bc307e2291f8a4764d779a6b28"}, - {file = "Pillow-9.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12875d118f21cf35604176872447cdb57b07126750a33748bac15e77f90f1f9c"}, - {file = "Pillow-9.0.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:514ceac913076feefbeaf89771fd6febde78b0c4c1b23aaeab082c41c694e81b"}, - {file = "Pillow-9.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3c5c79ab7dfce6d88f1ba639b77e77a17ea33a01b07b99840d6ed08031cb2a7"}, - {file = "Pillow-9.0.1-cp39-cp39-win32.whl", hash = "sha256:718856856ba31f14f13ba885ff13874be7fefc53984d2832458f12c38205f7f7"}, - {file = "Pillow-9.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:f25ed6e28ddf50de7e7ea99d7a976d6a9c415f03adcaac9c41ff6ff41b6d86ac"}, - {file = "Pillow-9.0.1-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:011233e0c42a4a7836498e98c1acf5e744c96a67dd5032a6f666cc1fb97eab97"}, - {file = "Pillow-9.0.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:253e8a302a96df6927310a9d44e6103055e8fb96a6822f8b7f514bb7ef77de56"}, - {file = "Pillow-9.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6295f6763749b89c994fcb6d8a7f7ce03c3992e695f89f00b741b4580b199b7e"}, - {file = "Pillow-9.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a9f44cd7e162ac6191491d7249cceb02b8116b0f7e847ee33f739d7cb1ea1f70"}, - {file = "Pillow-9.0.1.tar.gz", hash = "sha256:6c8bc8238a7dfdaf7a75f5ec5a663f4173f8c367e5a39f87e720495e1eed75fa"}, -] -platformdirs = [ - {file = "platformdirs-2.5.1-py3-none-any.whl", hash = "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"}, - {file = "platformdirs-2.5.1.tar.gz", hash = "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d"}, -] -pluggy = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, -] -py = [ - {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, - {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, -] -pyparsing = [ - {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, - {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"}, -] -pytest = [ - {file = "pytest-7.0.1-py3-none-any.whl", hash = "sha256:9ce3ff477af913ecf6321fe337b93a2c0dcf2a0a1439c43f5452112c1e4280db"}, - {file = "pytest-7.0.1.tar.gz", hash = "sha256:e30905a0c131d3d94b89624a1cc5afec3e0ba2fbdb151867d8e0ebd49850f171"}, -] -python-dateutil = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, -] -pytz = [ - {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, - {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, -] -scipy = [ - {file = "scipy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87b01c7d5761e8a266a0fbdb9d88dcba0910d63c1c671bdb4d99d29f469e9e03"}, - {file = "scipy-1.8.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ae3e327da323d82e918e593460e23babdce40d7ab21490ddf9fc06dec6b91a18"}, - {file = "scipy-1.8.0-cp310-cp310-macosx_12_0_universal2.macosx_10_9_x86_64.whl", hash = "sha256:16e09ef68b352d73befa8bcaf3ebe25d3941fe1a58c82909d5589856e6bc8174"}, - {file = "scipy-1.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c17a1878d00a5dd2797ccd73623ceca9d02375328f6218ee6d921e1325e61aff"}, - {file = "scipy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937d28722f13302febde29847bbe554b89073fbb924a30475e5ed7b028898b5f"}, - {file = "scipy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:8f4d059a97b29c91afad46b1737274cb282357a305a80bdd9e8adf3b0ca6a3f0"}, - {file = "scipy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:38aa39b6724cb65271e469013aeb6f2ce66fd44f093e241c28a9c6bc64fd79ed"}, - {file = "scipy-1.8.0-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:559a8a4c03a5ba9fe3232f39ed24f86457e4f3f6c0abbeae1fb945029f092720"}, - {file = "scipy-1.8.0-cp38-cp38-macosx_12_0_universal2.macosx_10_9_x86_64.whl", hash = "sha256:f4a6d3b9f9797eb2d43938ac2c5d96d02aed17ef170c8b38f11798717523ddba"}, - {file = "scipy-1.8.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:92b2c2af4183ed09afb595709a8ef5783b2baf7f41e26ece24e1329c109691a7"}, - {file = "scipy-1.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a279e27c7f4566ef18bab1b1e2c37d168e365080974758d107e7d237d3f0f484"}, - {file = "scipy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad5be4039147c808e64f99c0e8a9641eb5d2fa079ff5894dcd8240e94e347af4"}, - {file = "scipy-1.8.0-cp38-cp38-win32.whl", hash = "sha256:3d9dd6c8b93a22bf9a3a52d1327aca7e092b1299fb3afc4f89e8eba381be7b59"}, - {file = "scipy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:5e73343c5e0d413c1f937302b2e04fb07872f5843041bcfd50699aef6e95e399"}, - {file = "scipy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:de2e80ee1d925984c2504812a310841c241791c5279352be4707cdcd7c255039"}, - {file = "scipy-1.8.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:c2bae431d127bf0b1da81fc24e4bba0a84d058e3a96b9dd6475dfcb3c5e8761e"}, - {file = "scipy-1.8.0-cp39-cp39-macosx_12_0_universal2.macosx_10_9_x86_64.whl", hash = "sha256:723b9f878095ed994756fa4ee3060c450e2db0139c5ba248ee3f9628bd64e735"}, - {file = "scipy-1.8.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:011d4386b53b933142f58a652aa0f149c9b9242abd4f900b9f4ea5fbafc86b89"}, - {file = "scipy-1.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6f0cd9c0bd374ef834ee1e0f0999678d49dcc400ea6209113d81528958f97c7"}, - {file = "scipy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3720d0124aced49f6f2198a6900304411dbbeed12f56951d7c66ebef05e3df6"}, - {file = "scipy-1.8.0-cp39-cp39-win32.whl", hash = "sha256:3d573228c10a3a8c32b9037be982e6440e411b443a6267b067cac72f690b8d56"}, - {file = "scipy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:bb7088e89cd751acf66195d2f00cf009a1ea113f3019664032d9075b1e727b6c"}, - {file = "scipy-1.8.0.tar.gz", hash = "sha256:31d4f2d6b724bc9a98e527b5849b8a7e589bf1ea630c33aa563eda912c9ff0bd"}, -] -setuptools-scm = [ - {file = "setuptools_scm-6.4.2-py3-none-any.whl", hash = "sha256:acea13255093849de7ccb11af9e1fb8bde7067783450cee9ef7a93139bddf6d4"}, - {file = "setuptools_scm-6.4.2.tar.gz", hash = "sha256:6833ac65c6ed9711a4d5d2266f8024cfa07c533a0e55f4c12f6eff280a5a9e30"}, -] -six = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] -tomli = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] -tqdm = [ - {file = "tqdm-4.62.3-py2.py3-none-any.whl", hash = "sha256:8dd278a422499cd6b727e6ae4061c40b48fce8b76d1ccbf5d34fca9b7f925b0c"}, - {file = "tqdm-4.62.3.tar.gz", hash = "sha256:d359de7217506c9851b7869f3708d8ee53ed70a1b8edbba4dbcb47442592920d"}, -] -typing-extensions = [ - {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, - {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, -] -typish = [ - {file = "typish-1.9.3-py3-none-any.whl", hash = "sha256:03cfee5e6eb856dbf90244e18f4e4c41044c8790d5779f4e775f63f982e2f896"}, -] -untokenize = [ - {file = "untokenize-0.1.1.tar.gz", hash = "sha256:3865dbbbb8efb4bb5eaa72f1be7f3e0be00ea8b7f125c69cbd1f5fda926f37a2"}, -] -xarray = [ - {file = "xarray-0.21.1-py3-none-any.whl", hash = "sha256:72605fb6e0568c285527ccfaf991485fca9ba97f708fc737dac8e71cc90551bf"}, - {file = "xarray-0.21.1.tar.gz", hash = "sha256:0cd5a17c1271d6b468fb3872bd2ca196351cd522719275c436e45cac1d1ffc8b"}, -] diff --git a/pyproject.toml b/pyproject.toml index d5a09ef..39b7f64 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,27 +1,30 @@ -[tool.poetry] +[build-system] +requires = ["setuptools", "setuptools-scm"] +build-backend = "setuptools.build_meta" + +[project] name = "blobmodel" -version = "0.1.1" +version = "1.0.0" description = "Two dimensional model of propagating blobs" -authors = ["gregordecristoforo "] -homepage = "https://github.com/uit-cosmo/2d_propagating_blobs/blob/main/" -license = "MIT" +authors = [ + { name = "gregordecristoforo", email = "gregor.decristoforo@gmail.com" } +] +license = { file = "LICENSE" } readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "numpy", + "xarray", + "tqdm", + "nptyping", + "matplotlib", + "netcdf4", + "pytest-cov", + "black", + "mypy", + "sphinx", + "sphinx-rtd-theme", +] -[tool.poetry.dependencies] -python = ">=3.10,<3.11" -xarray = "^0.21.1" -numpy = "^1.22.2" -scipy = "^1.8.0" -matplotlib = "^3.5.1" -tqdm = "^4.62.3" -pytest = "^7.0.1" -nptyping = "^1.4.4" -mypy = "^0.931" -black = "^22.1.0" -docformatter = "^1.4" - -[tool.poetry.dev-dependencies] - -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" +[tool.setuptools] +packages = ["blobmodel"] diff --git a/readme_gifs/1d_blobs.gif b/readme_files/1d_blobs.gif similarity index 100% rename from readme_gifs/1d_blobs.gif rename to readme_files/1d_blobs.gif diff --git a/readme_files/2d_blobs.gif b/readme_files/2d_blobs.gif new file mode 100644 index 0000000..a6d9b5c Binary files /dev/null and b/readme_files/2d_blobs.gif differ diff --git a/readme_files/logo.png b/readme_files/logo.png new file mode 100644 index 0000000..4ebd537 Binary files /dev/null and b/readme_files/logo.png differ diff --git a/readme_files/tmp5kfvrjp5.svg b/readme_files/tmp5kfvrjp5.svg new file mode 100644 index 0000000..76f6b91 --- /dev/null +++ b/readme_files/tmp5kfvrjp5.svg @@ -0,0 +1 @@ +pythonpython3.10, 3.113.10, 3.11 \ No newline at end of file diff --git a/readme_files/tmpp0mi4n8p.svg b/readme_files/tmpp0mi4n8p.svg new file mode 100644 index 0000000..d3e9113 --- /dev/null +++ b/readme_files/tmpp0mi4n8p.svg @@ -0,0 +1 @@ +pip installpip installblobmodelblobmodel \ No newline at end of file diff --git a/readme_gifs/2d_blobs.gif b/readme_gifs/2d_blobs.gif deleted file mode 100644 index d7ef5eb..0000000 Binary files a/readme_gifs/2d_blobs.gif and /dev/null differ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..adca622 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,136 @@ +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile --output-file=requirements.txt +# +alabaster==0.7.13 + # via sphinx +babel==2.12.1 + # via sphinx +black==23.7.0 + # via blobmodel (pyproject.toml) +certifi==2023.5.7 + # via + # netcdf4 + # requests +cftime==1.6.2 + # via netcdf4 +charset-normalizer==3.2.0 + # via requests +click==8.1.6 + # via black +contourpy==1.1.0 + # via matplotlib +coverage[toml]==7.2.7 + # via pytest-cov +cycler==0.11.0 + # via matplotlib +docutils==0.18.1 + # via + # sphinx + # sphinx-rtd-theme +fonttools==4.41.0 + # via matplotlib +idna==3.4 + # via requests +imagesize==1.4.1 + # via sphinx +iniconfig==2.0.0 + # via pytest +jinja2==3.1.2 + # via sphinx +kiwisolver==1.4.4 + # via matplotlib +markupsafe==2.1.3 + # via jinja2 +matplotlib==3.7.2 + # via blobmodel (pyproject.toml) +mypy==1.4.1 + # via blobmodel (pyproject.toml) +mypy-extensions==1.0.0 + # via + # black + # mypy +netcdf4==1.6.4 + # via blobmodel (pyproject.toml) +nptyping==2.5.0 + # via blobmodel (pyproject.toml) +numpy==1.25.1 + # via + # blobmodel (pyproject.toml) + # cftime + # contourpy + # matplotlib + # netcdf4 + # nptyping + # pandas + # xarray +packaging==23.1 + # via + # black + # matplotlib + # pytest + # sphinx + # xarray +pandas==2.0.3 + # via xarray +pathspec==0.11.1 + # via black +pillow==10.0.0 + # via matplotlib +platformdirs==3.9.1 + # via black +pluggy==1.2.0 + # via pytest +pygments==2.15.1 + # via sphinx +pyparsing==3.0.9 + # via matplotlib +pytest==7.4.0 + # via pytest-cov +pytest-cov==4.1.0 + # via blobmodel (pyproject.toml) +python-dateutil==2.8.2 + # via + # matplotlib + # pandas +pytz==2023.3 + # via pandas +requests==2.31.0 + # via sphinx +six==1.16.0 + # via python-dateutil +snowballstemmer==2.2.0 + # via sphinx +sphinx==6.2.1 + # via + # blobmodel (pyproject.toml) + # sphinx-rtd-theme + # sphinxcontrib-jquery +sphinx-rtd-theme==1.2.2 + # via blobmodel (pyproject.toml) +sphinxcontrib-applehelp==1.0.4 + # via sphinx +sphinxcontrib-devhelp==1.0.2 + # via sphinx +sphinxcontrib-htmlhelp==2.0.1 + # via sphinx +sphinxcontrib-jquery==4.1 + # via sphinx-rtd-theme +sphinxcontrib-jsmath==1.0.1 + # via sphinx +sphinxcontrib-qthelp==1.0.3 + # via sphinx +sphinxcontrib-serializinghtml==1.1.5 + # via sphinx +tqdm==4.65.0 + # via blobmodel (pyproject.toml) +typing-extensions==4.7.1 + # via mypy +tzdata==2023.3 + # via pandas +urllib3==2.0.4 + # via requests +xarray==2023.7.0 + # via blobmodel (pyproject.toml) diff --git a/tests/test_analytical.py b/tests/test_analytical.py index 4f062cc..c154bbc 100644 --- a/tests/test_analytical.py +++ b/tests/test_analytical.py @@ -42,6 +42,3 @@ def test_convergence_to_analytical_solution(): error = np.mean(abs(model_profile.values - analytical_profile)) assert error < 0.1, "Numerical error too big" - - -test_convergence_to_analytical_solution() diff --git a/tests/test_blob.py b/tests/test_blob.py index 8741290..bfd2e23 100644 --- a/tests/test_blob.py +++ b/tests/test_blob.py @@ -1,4 +1,4 @@ -from blobmodel import Blob, BlobShapeImpl +from blobmodel import Model, DefaultBlobFactory, Blob, BlobShapeImpl import numpy as np from unittest.mock import MagicMock @@ -51,7 +51,7 @@ def test_blob_non_alignment(): mesh_x, mesh_y = np.meshgrid(x, y) mock = MagicMock(return_value=mesh_x) - blob.blob_shape.get_pulse_shape_prop = mock + blob.blob_shape.get_blob_shape_prop = mock blob.discretize_blob(x=mesh_x, y=mesh_y, t=0, periodic_y=False, Ly=10) np.testing.assert_array_equal(mesh_x, mock.call_args[0][0]) @@ -174,7 +174,7 @@ def test_kwargs(): from unittest.mock import MagicMock mock_ps = BlobShapeImpl("2-exp", "2-exp") - mock_ps.get_pulse_shape_prop = MagicMock() + mock_ps.get_blob_shape_prop = MagicMock() blob_sp = Blob( blob_id=0, @@ -197,5 +197,24 @@ def test_kwargs(): mesh_x, mesh_y = np.meshgrid(x, y) blob_sp.discretize_blob(x=mesh_x, y=mesh_y, t=0, periodic_y=True, Ly=10) - - mock_ps.get_pulse_shape_prop.assert_called_with([[0]], lam=0.2) + mock_ps.get_blob_shape_prop.assert_called_with([[0]], lam=0.2) + + +def test_get_blobs(): + bf = DefaultBlobFactory(A_dist="deg", wx_dist="deg", vx_dist="deg", vy_dist="deg") + one_blob = Model( + Nx=100, + Ny=100, + Lx=10, + Ly=10, + dt=1, + T=1, + blob_shape="exp", + t_drain=1e10, + periodic_y=False, + num_blobs=3, + blob_factory=bf, + ) + ds = one_blob.make_realization() + blob_list = one_blob.get_blobs() + assert len(blob_list) == 3 diff --git a/tests/test_changing_t_drain.py b/tests/test_changing_t_drain.py index 27ee126..f300f27 100644 --- a/tests/test_changing_t_drain.py +++ b/tests/test_changing_t_drain.py @@ -27,7 +27,6 @@ def test_decreasing_t_drain(): - ds = xr.open_dataset("test_t_drain.nc") model_profile = ds.n.isel(y=0).mean(dim=("t")) @@ -43,6 +42,3 @@ def test_decreasing_t_drain(): 1 / np.sqrt(np.pi) * t_d / t_w * amp * np.exp(-x / (v_p * t_loss)) ) assert (model_profile.values[2:] < analytical_profile[2:]).all() - - -test_decreasing_t_drain() diff --git a/tests/test_drain.py b/tests/test_drain.py index 9d25e1c..3053611 100644 --- a/tests/test_drain.py +++ b/tests/test_drain.py @@ -25,6 +25,3 @@ def test_high_t_drain(): blob_values = blob_sp.discretize_blob( x=mesh_x, y=mesh_y, t=mesh_t, periodic_y=False, Ly=10 ) - - -test_high_t_drain() diff --git a/tests/test_labels.py b/tests/test_labels.py index 3e340c5..1ff6fa4 100644 --- a/tests/test_labels.py +++ b/tests/test_labels.py @@ -1,8 +1,10 @@ +import pytest from blobmodel import Model, BlobFactory, Blob, BlobShapeImpl, AbstractBlobShape import numpy as np import warnings from typing import List + # here you can define your custom parameter distributions class CustomBlobFactory(BlobFactory): def __init__(self) -> None: @@ -16,7 +18,6 @@ def sample_blobs( blob_shape: AbstractBlobShape, t_drain: float, ) -> List[Blob]: - # set custom parameter distributions _amp = np.ones(num_blobs) _width = np.ones(num_blobs) @@ -81,7 +82,8 @@ def test_bloblabels_speedup(): assert np.max(diff) < 0.00001 -def test_bloblabels(): +@pytest.mark.parametrize("labels", [("individual"), ("same")]) +def test_bloblabels(labels): warnings.filterwarnings("ignore") bf = CustomBlobFactory() bm = Model( @@ -96,7 +98,7 @@ def test_bloblabels(): num_blobs=1, blob_factory=bf, t_drain=1e10, - labels="same", + labels=labels, ) ds = bm.make_realization(speed_up=False) correct_labels = np.array( @@ -112,7 +114,3 @@ def test_bloblabels(): ) diff = ds["blob_labels"].values - correct_labels assert np.max(diff) < 0.00001 - - -test_bloblabels_speedup() -test_bloblabels() diff --git a/tests/test_one_dim.py b/tests/test_one_dim.py index 7f778a2..1070a4e 100644 --- a/tests/test_one_dim.py +++ b/tests/test_one_dim.py @@ -1,3 +1,4 @@ +import pytest from blobmodel import Model, DefaultBlobFactory import numpy as np @@ -40,4 +41,23 @@ def test_one_dim(): assert error < 0.1, "Numerical error too big" -test_one_dim() +def test_1d_warning(): + with pytest.warns(UserWarning): + for vy_dist in ["deg", "zeros"]: + bf = DefaultBlobFactory( + A_dist="deg", wx_dist="deg", vx_dist="deg", vy_dist=vy_dist + ) + one_dim_model = Model( + Nx=100, + Ny=100, + Lx=10, + Ly=10, + dt=1, + T=1000, + blob_shape="exp", + t_drain=2, + periodic_y=False, + num_blobs=1, + blob_factory=bf, + one_dimensional=True, + ) diff --git a/tests/test_pulse_shape.py b/tests/test_pulse_shape.py index cc75d5c..6de1a5b 100644 --- a/tests/test_pulse_shape.py +++ b/tests/test_pulse_shape.py @@ -1,12 +1,12 @@ import pytest -from blobmodel import BlobShapeImpl +from blobmodel import BlobShapeImpl, AbstractBlobShape, BlobShapeImpl import numpy as np def test_gauss_pulse_shape(): ps = BlobShapeImpl() x = np.arange(-10, 10, 0.1) - values = ps.get_pulse_shape_perp(x) + values = ps.get_blob_shape_perp(x) expected_values = 1 / np.sqrt(np.pi) * np.exp(-(x**2)) assert np.max(np.abs(values - expected_values)) < 1e-5, "Wrong gaussian shape" @@ -24,5 +24,41 @@ def test_kwargs(): expected_values[x >= 0] = np.exp(-x[x >= 0] / (1 - lam)) ps = BlobShapeImpl("2-exp", "2-exp") - values = ps.get_pulse_shape_perp(x, lam=0.5) + values = ps.get_blob_shape_perp(x, lam=0.5) assert np.max(np.abs(values - expected_values)) < 1e-5, "Wrong shape" + + +def test_abstract_mehtods(): + AbstractBlobShape.__abstractmethods__ = set() + + class MyShape(AbstractBlobShape): + pass + + my_obj = MyShape() + + with pytest.raises(NotImplementedError): + my_obj.get_blob_shape_prop([0, 1, 2]) + + with pytest.raises(NotImplementedError): + my_obj.get_blob_shape_perp([0, 1, 2]) + + +def test__get_double_exponential_shape(): + theta = np.array([-1, 0, 1]) + lam = 0.5 + expected_result = np.array([0.13533528, 1.0, 0.13533528]) + assert np.allclose( + BlobShapeImpl._get_double_exponential_shape(theta, lam=lam), expected_result + ) + + +def test__get_secant_shape(): + theta = np.array([1, 2, 3]) + expected_result = np.array([0.20628208, 0.08460748, 0.03161706]) + assert np.allclose(BlobShapeImpl._get_secant_shape(theta), expected_result) + + +def test__get_lorentz_shape(): + theta = np.array([1, 2, 3]) + expected_result = np.array([0.15915494, 0.06366198, 0.03183099]) + assert np.allclose(BlobShapeImpl._get_lorentz_shape(theta), expected_result) diff --git a/tests/test_show_model.py b/tests/test_show_model.py index fd24690..4e78741 100644 --- a/tests/test_show_model.py +++ b/tests/test_show_model.py @@ -18,11 +18,12 @@ # create data ds_2d = bm_2d.make_realization() + # warnings are supressed since plt complains about animation blocked @patch("matplotlib.pyplot.show") def test_plot_2d(mock_show): warnings.filterwarnings("ignore") - show_model(dataset=ds_2d, interval=100, save=False, fps=10) + show_model(dataset=ds_2d, interval=100, gif_name=None, fps=10) bm_1d = Model( @@ -40,12 +41,9 @@ def test_plot_2d(mock_show): # create data ds_1d = bm_1d.make_realization() + # warnings are supressed since plt complains about animation blocked @patch("matplotlib.pyplot.show") def test_plot_1d(mock_show): warnings.filterwarnings("ignore") - show_model(dataset=ds_1d, interval=100, save=False, fps=10) - - -test_plot_2d() -test_plot_1d() + show_model(dataset=ds_1d, interval=100, gif_name=None, fps=10) diff --git a/tests/test_stochasticality.py b/tests/test_stochasticality.py index ef1f0d6..cfe865e 100644 --- a/tests/test_stochasticality.py +++ b/tests/test_stochasticality.py @@ -1,5 +1,5 @@ import pytest -from blobmodel import DefaultBlobFactory, BlobShapeImpl +from blobmodel import DefaultBlobFactory, BlobShapeImpl, BlobFactory def test_mean_of_distribution(): @@ -30,5 +30,16 @@ def test_not_implemented_distribution(): bf.sample_blobs(1, 1, 1, BlobShapeImpl("gauss"), 1) -test_mean_of_distribution() -test_not_implemented_distribution() +def test_abstract_mehtods(): + BlobFactory.__abstractmethods__ = set() + + class MyBlobFactory(BlobFactory): + pass + + my_obj = MyBlobFactory() + + with pytest.raises(NotImplementedError): + my_obj.sample_blobs(1, 1, 1, "exp", 1) + + with pytest.raises(NotImplementedError): + my_obj.is_one_dimensional() diff --git a/tests/test_str.py b/tests/test_str.py index 7364877..04c8df5 100644 --- a/tests/test_str.py +++ b/tests/test_str.py @@ -23,7 +23,3 @@ def test_model_str(): num_blobs=1, ) assert str(bm) == "2d Blob Model with num_blobs:1 and t_drain:10" - - -test_geometry_str() -test_model_str() diff --git a/tests/test_vx_or_vy=0.py b/tests/test_vx_or_vy=0.py index 12c9d6c..9d78bff 100644 --- a/tests/test_vx_or_vy=0.py +++ b/tests/test_vx_or_vy=0.py @@ -15,7 +15,6 @@ def sample_blobs( blob_shape: AbstractBlobShape, t_drain: float, ) -> List[Blob]: - # set custom parameter distributions _amp = np.ones(num_blobs) _width = np.ones(num_blobs) @@ -59,7 +58,6 @@ def sample_blobs( blob_shape: AbstractBlobShape, t_drain: float, ) -> List[Blob]: - # set custom parameter distributions _amp = np.ones(num_blobs) _width = np.ones(num_blobs) @@ -130,7 +128,3 @@ def test_vy_0(): def test_vx_0(): assert bm_vx_0.make_realization(speed_up=True, error=1e-2) - - -test_vx_0() -test_vy_0()