Git Product home page Git Product logo

finitevolumetransportphenomena / pyfvtool Goto Github PK

View Code? Open in Web Editor NEW
9.0 3.0 3.0 8.69 MB

Finite volume toolbox in Python

License: GNU Lesser General Public License v2.1

Python 100.00%
transport-phenomena boundary-conditions finite-volume-method finite-volume-methods partial-differential-equations pde-solver scientific-computing-with-python advection-diffusion convection-diffusion-reaction

pyfvtool's Introduction

PyFVTool: Python toolbox for the finite volume method

This is a Python implementation of A. A. Eftekhari's Matlab/Octave FVM solver FVTool. Inspired by FiPy, it has only a fraction of FiPy's features. Boundary conditions, however, are much easier (and arguably more consistent) to implement in PyFVTool.

PyFVTool can discretize and solve the conservative form of transient convection-diffusion-reaction equation(s) with variable velocity field/diffusion coefficients and source terms:

$$\underbrace{\alpha\frac{\partial\phi}{\partial t}}_{\textrm{Transient term}}+\underbrace{\nabla \cdot \left(\mathbf{u}\phi\right)}_{\text{Advection term}}+\underbrace{\nabla \cdot (-\mathcal{D}\nabla\phi)}_{\text{Diffusion term}}+\underbrace{\beta\phi}_{\text{Linear source term}}+\underbrace{\gamma}_{\text{Constant source term}}=0$$

with the following general form of boundary conditions (specified by constants a, b, and c):

$$a\nabla\phi \cdot \mathbf{e}+b\phi=c$$

PyFVTool is limited to calculations on structured meshes (regular grids). It is oriented to calculation of heat and mass transport phenomena (diffusion-advection-reaction) for the frequent cases where the flow velocity field is already known (or where flow is absent). It is not particularly suited for fluid dynamics (solving Navier-Stokes), which requires implementation of further numerical schemes on top of the current PyFVTool (simulkade knows how). For fluid dynamics, other specialized finite-volume codes exist.

The finite-volume discretization schemes include:

  • 1D, 2D and 3D Cartesian and cylindrical grids
  • Second order (central difference) diffusion terms
  • Second order (central difference), first order (upwind), and total variation diminishing (TVD) for advection terms
  • Constant and linear source terms
  • Backward and forward Euler for transient terms
  • Dirichlet, Neumann, Robin, and periodic boundary conditions
  • (Relatively) easy linearization of nonlinear PDEs
  • Averaging methods (linear, arithmetic, geometric, harmonic, upwind, TVD)
  • Divergence and gradient terms

An important feature of PyFVTool is that it is 'pure scientific Python' (i.e. it needs only Python and the standard scientific computing libraries numpy, scipy and matplotlib to run). Further optional dependencies may appear in the future, e.g., for increasing the computational speed via optimised numerical libraries, but these will remain optional.

The code is under active development. Preliminary simulations match analytical solutions. More validation is under way, and the use of this PyFVTool toolbox in ongoing research projects will further consolidate the code and verify its validity. There is not much documentation for the code yet (help wanted!) but the example folder is the best place to start. If you know the topic, there is a good chance you will never need any documentations.

Installation

For now, install PyFVTool directly from the GitHub repository using pip. You will need Python 3.9 or higher and numpy, scipy, and matplotlib:

pip install git+https://github.com/FiniteVolumeTransportPhenomena/PyFVTool.git

If you'd like to use PyFVTool in Google Colab, you can enter the following in the first cell of a Colab Notebook:

!pip install git+https://github.com/FiniteVolumeTransportPhenomena/PyFVTool.git

This will install PyFVTool in the current Colab instance, and make it available for import in the Notebook.

Working in a conda environment

It is convenient to use the Anaconda/miniconda Python distributions and set up a specific environment for PyFVTool (we'll call the environment pyfvtool_user).

This requires three commands to be launched from the command-line prompt.

conda create --name pyfvtool_user numpy scipy matplotlib spyder jupyterlab

conda activate pyfvtool_user

pip install git+https://github.com/FiniteVolumeTransportPhenomena/PyFVTool.git

Of course, do not forget to conda activate pyfvtool_user the environment every time you run Python code that uses PyFVTool.

Development installation

If you would like to work on the source code, it is possible to install a development version using pip. See CONTRIBUTING.md

Example

Here is a simple example of a 1D transient diffusion equation:

import pyfvtool as pf

# Solving a 1D diffusion equation with a fixed concentration 
# at the left boundary and a closed boundary on the right side

Nx = 20 # number of finite volume cells
Lx = 1.0 # [m] length of the domain 
c_left = 1.0 # left boundary concentration
c_init = 0.0 # initial concentration
D_val = 1e-5 # diffusion coefficient (gas phase)
t_simulation = 7200.0 # [s] simulation time
dt = 60.0 # [s] time step
Nskip = 10 # plot every Nskip-th profile

m1 = pf.Grid1D(Nx, Lx) # mesh object
bc = pf.BoundaryConditions(m1) # Neumann boundary condition by default

# switch the left boundary to Dirichlet: fixed concentration
bc.left.a[:] = 0.0
bc.left.b[:] = 1.0
bc.left.c[:] = c_left

# create a cell variable with initial concentration
c = pf.CellVariable(m1, c_init, bc)

# assign diffusivity to cells
D_cell = pf.CellVariable(m1, D_val)
D_face = pf.geometricMean(D_cell) # average value of diffusivity at the interfaces between cells

# time loop
t = 0
nplot = 0
while t<t_simulation:
    # compose discretized terms for matrix equation
    bcterm = pf.boundaryConditionsTerm(bc)

    eqn = [ pf.transientTerm(c, dt, 1.0),
           -pf.diffusionTerm(D_face)]

    # solve PDE
    pf.solvePDE(c,
                bcterm,
                eqn)
    t+=dt

    if (nplot % Nskip == 0):
        pf.visualizeCells(c)
    nplot+=1

pyfvtool's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

pyfvtool's Issues

Moving PyFVTool to an organization

Create an organization for PyFVTool, FVTool, and JFVM.jl?
None of these tools are full featured FVM tools, so I am inclined to a name such as AdvectionDiffusionReaction , NumericalTransportPhenomena or a shorter version of them (AdvDiffReac, NumTP, etc.). What do you think @mhvwerts ?

'test_benchmark_1d.py' fails

When running pytest, the following unittest fails: tests/test_benchmark_1d.py

It fails in the following manner:

================================================= FAILURES =================================================
____________________________________ TestConvection.test_1d_convection _____________________________________

self = <tests.test_benchmark_1d.TestConvection testMethod=test_1d_convection>

    def test_1d_convection(self):
        print("\nRunning 1D convection:")
        er = conv_numerical_1d()
        eps_c = 0.001
>       self.assertLessEqual(er, eps_c)
E       AssertionError: 0.08326582704284138 not less than or equal to 0.001

tests\test_benchmark_1d.py:115: AssertionError

Testing

We should set up some simple automated testing infrastructure instead of testing by manually executing the examples, Notebooks and test scripts.

The test could involve

  • running all examples and testing if they still give the same correct results
  • running all Notebooks and seeing if they still give the same output
  • running additional tests such as those in the tests folder and fvtool_test.py
  • running the doctests that are in the docstrings

pytest may be the suitable tool. I used it once in the past, and even though the documentation looks daunting, I believe it wasn't too hard to set up basic testing, which with hindsight prevented some disastrous code changes in that project, avoided incorrect calculations and arguably saved time.

Some additional info:

`CellVariable.BC2GhostCells()` and `CellVariable.bc_to_ghost()`

          I think I implemented both `CellVariable.BC2GhostCells()` and `CellVariable.bc_to_ghost()` to have one that change the ghost cell values in place and one that creates a new cell by assigning the ghost cell values when creating a new cell variable with known boundary conditions. It is indeed an excellent idea to have boundary conditions as a property of cell values. It has several benefits specially when working with non/linear systems of equations.

Originally posted by @simulkade in #34 (comment)

Installation error due to the existence of both setup.py and pyproject.toml

I tried to install PyFVTool in a miniconda environment using pip and later python setup.py install. I received the following error with the former and a similar one with the later although the installation went through the second time. I leave it here for now. It seems that something goes wrong when we have both pyproject.toml and setup.py.

C:\Users\aaeft\miniconda3\envs\phreeqc\Lib\site-packages\setuptools\config\_apply_pyprojecttoml.py:62: _WouldIgnoreField: `license` defined outside of `pyproject.toml` would be ignored.
!!

        ********************************************************************************
        ##########################################################################
        # configuration would be ignored/result in error due to `pyproject.toml` #
        ##########################################################################

        The following seems to be defined outside of `pyproject.toml`:

        `license = 'MIT'`

        According to the spec (see the link below), however, setuptools CANNOT
        consider this value unless `license` is listed as `dynamic`.

        https://packaging.python.org/en/latest/specifications/declaring-project-metadata/

        For the time being, `setuptools` will still consider the given value (as a
        **transitional** measure), but please note that future releases of setuptools will
        follow strictly the standard.

        To prevent this warning, you can list `license` under `dynamic` or alternatively
        remove the `[project]` table from your file and rely entirely on other means of
        configuration.

        This deprecation is overdue, please update your project and remove deprecated
        calls to avoid build errors in the future.
        ********************************************************************************

!!
  _handle_missing_dynamic(dist, project_table)
C:\Users\aaeft\miniconda3\envs\phreeqc\Lib\site-packages\setuptools\config\_apply_pyprojecttoml.py:62: _WouldIgnoreField: `dependencies` defined outside of `pyproject.toml` would be ignored.
!!

        ********************************************************************************
        ##########################################################################
        # configuration would be ignored/result in error due to `pyproject.toml` #
        ##########################################################################

        The following seems to be defined outside of `pyproject.toml`:

        `dependencies = ['numpy', 'scipy>=1.8.0', 'matplotlib']`

        According to the spec (see the link below), however, setuptools CANNOT
        consider this value unless `dependencies` is listed as `dynamic`.

        https://packaging.python.org/en/latest/specifications/declaring-project-metadata/

        For the time being, `setuptools` will still consider the given value (as a
        **transitional** measure), but please note that future releases of setuptools will
        follow strictly the standard.

        To prevent this warning, you can list `dependencies` under `dynamic` or alternatively
        remove the `[project]` table from your file and rely entirely on other means of
        configuration.

        This deprecation is overdue, please update your project and remove deprecated
        calls to avoid build errors in the future.
        ********************************************************************************

!!
  _handle_missing_dynamic(dist, project_table)
running install
C:\Users\aaeft\miniconda3\envs\phreeqc\Lib\site-packages\setuptools\_distutils\cmd.py:66: SetuptoolsDeprecationWarning: setup.py install is deprecated.
!!

        ********************************************************************************
        Please avoid running ``setup.py`` directly.
        Instead, use pypa/build, pypa/installer or other
        standards-based tools.

        See https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html for details.
        ********************************************************************************

!!
  self.initialize_options()
C:\Users\aaeft\miniconda3\envs\phreeqc\Lib\site-packages\setuptools\_distutils\cmd.py:66: EasyInstallDeprecationWarning: easy_install command is deprecated.
!!

        ********************************************************************************
        Please avoid running ``setup.py`` and ``easy_install``.
        Instead, use pypa/build, pypa/installer or other
        standards-based tools.

        See https://github.com/pypa/setuptools/issues/917 for details.
        ********************************************************************************

!!

Standardize pyfvtool imports on the user side

In anticipation of future work on #15, it may be wise to define more explicitly the boundary between the 'user' ('public') side and the internal ('private') PyFVTool code. Standardizing the way PyFVTool is imported in user code will contribute to this.

For instance, the user code would only use a single import statement:

import pyfvtool as pf

and then call the public PyFVTool functions, e.g. pf.createMesh1D(), pf.createCellVariable().

All 'user' functions should thus be made available via the pyfvtool/__init__.py script. This is likely already the case.

Deeper imports and digging up 'private' PyFVTool functions should be strongly discouraged. The casual user (like myself) should (eventually) not need to consult the core PyFVTool code.

We may already start by adapting existing tests, examples and Notebooks to adhere to this import standard, a process which will reveal any user functionality still missing from pyfvtool/__init__.py (if any).

Store the boundary conditions as a property of a cell variable

In the discussion accompanying PR #34, the suggestion was made to include (a reference to) the boundary conditions (subclass of BoundaryConditionsBase) as a property of the CellVariable to which these boundary conditions apply. At present, the definition of the boundary conditions is made separately from the cell variable, and applied explicitly in the user code, which requires recalling the specific boundary conditions object every time.

User code may become more simple, readable and perhaps also more robust, if the boundary conditions were included in the cell variable. This might simply be achieved by including something like self.BC = BC in CellVariable.__init__() [1], followed by adapting any other code where BCs are now specified explicitly such that it uses the stored BC where relevant.

This should also be the opportunity to review and revise CellVariable.bc_to_ghost() and BC2GhostCells() whose functioning is not very clear. AFAICS, these two methods are not used anywhere in the entire PyFVTool code base. Also, I find it strange that their name is a reference to boundary conditions (BCs), but no explicit boundary conditions are used by their code. These methods calculate the new value for the ghost cells (= boundary cells?) [2] by taking the average of that ghost cell with neighbouring inner cell and then storing that new value in the ghost cell. Perhaps, we can simply remove these methods, since they are not used?

[1] Actually: self.BC = arg[0] / self.BC = None, depending on how it is called. The CellVariable.__init__() code requires some further cleaning up I think...

[2] Should we use consistent naming: use either the term 'boundary cells', or the term 'ghost cells' exclusively? Perhaps I am missing a subtlety here? Boundary cell is perhaps ambiguous: it may refer to the ghost cell or to the outermost inner cell?

Calling external sparse direct solvers

It is an important feature of PyFVTool that it works with "pure scientific Python" (i.e. just python, numpy, scipy, and matplotlib for visualization), especially for sharing work with students and colleagues.

However, it may be anticipated that for certain future users, it would be interesting to provide an easy method to call an external sparse solver instead of scipy.sparse.linalg.spsolve, without sacrificing the default "pure scientific Python" character of PyFVTool.

Indeed, I noticed when doing some work on more realistic models, that my PyFVTool only uses a single thread on my processor when solving . Not a serious issue now, the calculations still only take less than 5 min, and it teaches me to be thoughtful on planning calculations. BTW, the 2D cylindrical results obtained with PyFVTool are really nice, so I am happy.

Just opening this to collect ideas on how to provide for a transparent external solver calling mechanism, and which external solvers might be easily accessible. A quick search yielded, for instance, PyPardiso

more logical name for InternalCells() method

A more logical name for the internalCells() method of CellVariable might be something like internalCellValues(), since it returns the values of the internal cells. (It does not return a new CellVariable object, which would not be very useful anyway)

Terms for SphericalGrid1D not implemented

This is not very urgent. I am trying out PyFVTool and it seems that the 1D spherical mesh has not been implemented yet.

I was trying to port the example concerning 1D spherical diffusion from the original Matlab FVTool to PyFVTool, and found that the createMeshSpherical1D does not exist (yet).

For now, I will go play in a different coordinate system. Anyway, thanks for PyFVTool which is an interesting option for using the finite-volume method in teaching transport phenomena and for setting up toy(?) models for research.

Minimal version number for scipy

Unexpectedly, my conda package manager somehow downgraded the installed scipy package in my environment. I am not entirely sure why, but that is a different story.

As a result of this accidental downgrade, I discovered that PyFVTool needs at least scipy >= 1.8.0, since it usesscipy.sparse.csr_array which only became available in version 1.8.0.

After upgrading (un-downgrading...?), I am now on scipy 1.11.2 and PyFVTool happily works again.

So better add this minimal version number to the requirements. I do not readily see where these are defined in the repo.

P.S. This happened when briefly exploring [pytest_notebook]. It was actually this package that unveiled the scipy version bug, so this tool seems to work for testing PyFVTool notebooks!

Labeling of coordinates in cylindrical (and spherical) meshes

PyFVTool systematically uses the labels x, y and z to represent the first, second resp. third coordinate, irrespective of the mesh geometry (Cartesian, cylindrical, spherical). This is important especially for internal code consistency and keeping the code base simple and free from Pythonic wizardry which may generate head-aches. Once used to it, this is OK, and one writes, e.g.,

import pyfvtool as pf
msh = pf.createMeshCylindrical2D(Nr, Nz, Lr, Lz)
rr = msh.cellcenters.x
zz = msh.facecenters.y

However, it would still be nice, one day, to consider the possibilities for adapting the programming interface to cellcenters and facecenters (and createMeshCylindrical etc.) such that the user would only see and use r, z (and theta, phi) when working with cylindrical or spherical meshes. This would improve the readability of the user's code and even avoid some errors. Internally, PyFVTool would continue to use labels x, y and z, but this would be invisible to the user, and translated by the functions and methods for creating and accessing meshes.

I have some vague ideas how this could be achieved in a relatively simple manner, but already wondering if @simulkade thinks if this is somewhere remotely feasible and desirable, and what others would think of such a new feature.

Deprecation warnings from numpy 1.26.2

I needed to install a new Python stack and one of the effects is that I now have numpy version 1.26.2 (I still use Python 3.9). When running a quick pytest to see if my installation was OK for continuing to work, I discovered quite a list of new DeprecationWarnings.

I do not have time to look into this further now. I record some of the warnings here, so that we fix them in some near future.

pyfvtool\boundary.py:152: 14 warnings
tests/test_benchmark_1d.py: 3 warnings
  C:\Users\werts-moltech\Documents\GitHub-mhvwerts\PyFVTool\pyfvtool\boundary.py:152:
DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error 
in future. Ensure you extract a single element from your array before performing this operation. 
(Deprecated NumPy 1.25.)
    s[q] = BC.right.b/2 + BC.right.a/dx_end

pyfvtool\boundary.py:156: 14 warnings
tests/test_benchmark_1d.py: 3 warnings
  C:\Users\werts-moltech\Documents\GitHub-mhvwerts\PyFVTool\pyfvtool\boundary.py:156:
DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error
in future. Ensure you extract a single element from your array before performing this operation.
(Deprecated NumPy 1.25.)
    s[q] = BC.right.b/2 - BC.right.a/dx_end

pyfvtool\boundary.py:157: 14 warnings
tests/test_benchmark_1d.py: 3 warnings
  C:\Users\werts-moltech\Documents\GitHub-mhvwerts\PyFVTool\pyfvtool\boundary.py:157:
DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error
in future. Ensure you extract a single element from your array before performing this operation.
(Deprecated NumPy 1.25.)
    BCRHS[G[i]] = BC.right.c

pyfvtool\boundary.py:164: 14 warnings
tests/test_benchmark_1d.py: 3 warnings
  C:\Users\werts-moltech\Documents\GitHub-mhvwerts\PyFVTool\pyfvtool\boundary.py:164:
DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error
in future. Ensure you extract a single element from your array before performing this operation.
(Deprecated NumPy 1.25.)
    s[q] = -(BC.left.b/2 + BC.left.a/dx_1)

pyfvtool\boundary.py:168: 14 warnings
tests/test_benchmark_1d.py: 3 warnings
  C:\Users\werts-moltech\Documents\GitHub-mhvwerts\PyFVTool\pyfvtool\boundary.py:168:
DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error
in future. Ensure you extract a single element from your array before performing this operation.
(Deprecated NumPy 1.25.)
    s[q] = -(BC.left.b/2 - BC.left.a/dx_1)

pyfvtool\boundary.py:169: 14 warnings
tests/test_benchmark_1d.py: 3 warnings
  C:\Users\werts-moltech\Documents\GitHub-mhvwerts\PyFVTool\pyfvtool\boundary.py:169:
DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error
in future. Ensure you extract a single element from your array before performing this operation.
(Deprecated NumPy 1.25.)
    BCRHS[G[i]] = -BC.left.c

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.