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
+
+
+
+
-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)
+
+
+
+
+
+
+
+
+
+
## 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 @@
+
\ 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 @@
+
\ 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()