:fireworks: Major Changes
- Removed `geometry` and `physics` modules
- Removed use of `Geometry` and `Physics` objects
- Moved plot functions from `topotools` to a new `visualization` module
- Removed `materials` and `metrics` modules in favor of creating detailed examples
- Removed the term Generic from all class names to improve readability \api
:rocket: New features
- Added a `solvers` module containing classes that define a generic api for using arbitrary numerical solvers
- Added an `integrators` module containing classes that define the api for transient solvers
- Added a wrapper to leverage the `scipy.integrate.ivp_solve` function for transient problems
- Added `Demo` network generator which includes geometry models already assigned and ready for instant use
- Added official support for mixtures, including pore-scale models for first-approximation calculations of pure and mixture properties
- Added `topotools.find_interface_throats` to find throats between two sets of pores
- Added `SteadyStateSolution` class for storing the results of steady state algorithms
- Added `TransientSolution` class for storing results of transient algorithms at each time step, including ability to interpolate between times
- Added mechanism to declare any property to be variable (i.e. a function of the solved quantity)
- Added a `params` attribute to all objects for storing scalar values and constants
- Added support to the dictionary objects for `pn['param.foo']` which looks up values from `pn.params['foo']` in a way that works seamlessly with existing pore-scale models
- Added `x` as a property to `Transport` classes for easy access to the solved quantity
- Added ability to compute the physical properties of arbitrary pure gases and liquids using correlations from the [chemicals](https://chemicals.readthedocs.io/) package
- Added a framework for computing properties of mixtures as a function of composition using correlations from the [chemicals](https://chemicals.readthedocs.io/) package
- Added `generate_voxel_image` to `visualization` module
- Added a set of pore-scale topology models under `models.network`
- Added `plot_network_jupyter` function to visualization module which creates an interactive visualization using Plotly
- Created a `contrib` folder/module for putting experimental and beta features, and well as contributions before they are adopted into the main code base
- Added `TransientMultiPhysics` class to the `contrib` folder
- Added new `plot_network` function based on [vispy](https://vispy.org/) to `contrib` folder
- Revised the `settings` attribute on objects to work more like python's `dataclasses` with settings as attributes, while also enforcing their type
:cake: Enhancements
- Adopted [rich](https://rich.readthedocs.io/en/latest/) package for formatting logger messages
- Added `ScipyCG` to the solvers module (uses `scipy.sparse.linalg.cg`)
- Added `intersecting_cones/pyramids` size factor models, as well as hybrid `cones_and_cylinders` which adopt intersecting cones/pyramids as needed
- Re-implemented the percolation algorithms for better consistency between them
- Added `call` method to `ModelWrapper` so they can run themselves directly with zero effort by user
- Enhanced BV formulations to allow variable number of electrons
- Created `openpnm.models.collections` containing dict files of preset models for all sub-classes to simplify instantiation
- Allowed setting of default solver in the `workspace.settings`
- Enhance `_validate_data_health` to account for throats without an assigned conductance model
- Augmented `getitem` on dictionaries to return a numeric value if used as a key, so pn[1.0] returns 1.0. This allows passing in scalar values to pore-scale models with no need to assign that scalar to all locations first
- Add [tqdm](https://tqdm.github.io/) progress bar for Newton iterations in ReactiveTransport
- Added `asmask` argument to neighbor lookup functions
- Added ability to delete nested/hierarchical keys simultaneously (i.e. del obj\['pore.nested'\])
- Added a pore-scale model function for generating values according to a given a histogram
- Added a check for stall in `ReactiveTransport`
- Relaxed convergence checks in `ReactiveTransport` to facilitate iterative solves
- Project, models, and settings are now pretty-printed when evaluated at REPL (IPython console)
- Updated math functions in misc to accept an array of props instead of individual args
- added `get_conduit_data` method to Base class
- Enhanced versioning so that dev builds get their own "build number" as X.Y.Z.devN
:wrench: Maintenance
- Got code coverage to 90%
- Removed several minor dependencies including flatdict which is no longer maintained
- The dependencies in requirements.txt are now synced with those in setup.py
- Stopped getting logger from root level to prevent interfering with other packages' outputs
- Fixed exporting transient data to paraview to work with new TransientSolution class
- Settings are applied after calling super().**init** and they are no longer passed up the init chain
- Moved iterative props machinery to `Algorithm`
- Fixed string splitting at dots to work better with multi-dot name
- Improved handling of missing keys on `Phase` objects for cleaner tracebacks when autointerpolation is enables
- Major refactor of `topotools` module into library of functions requiring no openpnm specific classes
- Modules/submodules in setup.py are now automatically filled using setuptools package
- Replaced for-loop with `numpy` `unbuffered` operations in surface area models
- Reorganized `openpnm.models.misc/phase/physics` modules to keep namespace clean
- Removed `relaxation_source` from ReactiveTransportSettings as we no longer apply relaxation to source term
- Leveraged `__all__` functionality throughout code to control imports of functions
- Added a runtime check to see if x0 contains infs/nans
- Refactored `Transport` to put boundary condition functions in a mixin
- Added unit tests for Salome, COMSOL, and STL I/O classes
- Changed `regenerate_models` to work when models lack `regen_mode` argument
- Removed `cache_b`, changed `cache_A` to `cache` since b is very small
- Removed [numba](https://numba.pydata.org/) deprecation warning
- Updated list of rules to be ignored by flake8 style check
- Removed `freeze_models` option from `ModelsMixin`
- Deleted many unused functions from `utils.misc`
- Added style check workflow to actions
- Refactor `Transport` and subclassed algorithms' run method
- Switched to `scipy`'s convergence checker
- Refactor of `set_label`
- Removed "internal" label from `Bravais` and `CubicDual`
- Broke up `Base` class into several mixins for more control of inheritance \maint
:warning: API changes
- Complete removal of `Geometry` and `Physics` objects, in favor of `Network` and `Phase` handling all related data and models directly
- Renamed `models.topology` to `models.network`
- Removed PETSc solver wrapper (needs to be revisited)
- Removed `MixedInvasionPercolation(Coop)` and `OrdinaryPercolation` algorithms until they can be better supported
- Replaced `target` keyword with `network` or `phase` throughout all pore-scale models, except ones that are truly general
- Conduit properties and now stored as Nt-by-3 arrays instead of dicts
- Changed how source terms are tracked from `obj.settings['sources']` to `obj[pore.sources']` to be consistent with how boundary conditions are tracked (i.e. `alg['pore.bc.rate']`)
- Changed the behavior of the `mode` argument when adding boundary conditions
- Converted the `Project` class to a minimal pseudo-list, with no extraneous methods inherited from list cluttering the namespace
- Initialization of `Base2` objects no longer accepts settings
- Exposed `iterative_props`, removed `set_variable_props`
- Removed `ModelsMixin` from `Algorithm` since algorithms don't typically need models
- Removed prefix and name from settings
- Refined the Butler-Volmer model formulations to match Newman's book
- Created `Drainage` class in algorithms with more limited scope to replace `OrdinaryPercolation` and `Porosimetry`
- Removed `nlin_max_iter` from `ReactiveTransportSettings` in favor of `newton_maxiter`
- Move `Multiphase` to `contrib` folder to indicate it is experimental
- Transport algorithms' `run` method now returns one or more Solution objects inside dictionary named according to the quantity they contain
- Made `network` a mandatory argument on `phase` and `algorithm` objects
- Renamed `tomask` and `toindices` to `to_mask` and `to_indices` since the underscore is the common convention in other packages like `pandas`
- Moved `get_domain_area` and `get_domain_length` from attributes on transport algorithms to `topotools`, for more general use
- Made `phase` a mandatory argument in algorithms instead of allowing it to be set in settings after the fact
- Removed old multiphysics algorithms (PNP) in preparation for new approach
- Removed effective property calculation methods from `Transport` since these can be computed by users themselves
- Complete rewrite/redesign of linear solvers and transient algorithms
- Added a `Solution` object for returning data from algorithms
- Added a `Solver` class to handle matrix math which is passed as an argument to run methods
- Removed `StickAndBall` geometry class (use `SpheresAndCylinders` instead)
- Removed `classic_ordinary_diffusion` and `classic_hagen_poiseuille` conductance models
- Refactored conductance models to work with size factors rather than shape factors
- Removed redundant `sympy` source models and made generic one much easier to use
- Removed `num_points` argument from `Delaunay/Voronoi` classes in favor `points=int`
- Removed `spacing` and `shape` attribute from `Cubic` and moved to `topotools` as functions
- Removed `setup` method from algorithms in favor of adding to settings attribute directly
- Deprecated `models.geometry.pore_area/throat_area` in favour of `pore/throat_cross_sectional_area`
:bug: Bugfixes
- Calling `regenerate_models` on a mixture now first regenerates each component
- Fixed a critical bug in `duplicate_throats`
- Fixed `color_by` argument in `plot_coordinates/connections` to accept partial list of values if pores/throats specified
- Fixed `ReactiveTransport`'s run method to accept instantiated solver, not the class itself
- Fixed a bug in XDMF output where dimensions were reversed
- Fixed bug in `lens` and `pendular_ring` models
- Fixed bug in `Transport` to properly check for connected network including connections with boundary conditions
- Fixed regex bug in setup.cfg that broke the 4th digit counter
:green\_book: Documentation
- Reorganized examples folder and documentation website
- Refactored and automated generation of the documentation
- Completely rewrote examples to form comprehensive tutorials and reference docs
- Fixed module docstrings to satisfy sphinx
- Updated list of options in docstrings to use tables
- Applied [docrep](https://docrep.readthedocs.io/en/latest/) and matplotlib's `substituion` throughout the package to make docstrings more consistent
- Removed tables of classes, methods and attributes from docstrings, and moved to sphinx docs instead
- Fixed hydraulic conductance equation in docstring