Code Monkey home page Code Monkey logo

cfdpython's Introduction

CFD Python

Please cite as: Barba, Lorena A., and Forsyth, Gilbert F. (2018). CFD Python: the 12 steps to Navier-Stokes equations. Journal of Open Source Education, 1(9), 21, https://doi.org/10.21105/jose.00021

DOI

CFD Python, a.k.a. the 12 steps to Navier-Stokes, is a practical module for learning the foundations of Computational Fluid Dynamics (CFD) by coding solutions to the basic partial differential equations that describe the physics of fluid flow. The module was part of a course taught by Prof. Lorena Barba between 2009 and 2013 in the Mechanical Engineering department at Boston University (Prof. Barba since moved to the George Washington University).

The module assumes only basic programming knowledge (in any language) and some background in partial differential equations and fluid mechanics. The "steps" were inspired by ideas of Dr. Rio Yokota, who was a post-doc in Prof. Barba's lab until 2011, and the lessons were refined by Prof. Barba and her students over several semesters teaching the CFD course. We wrote this set of Jupyter notebooks in 2013 to teach an intensive two-day course in Mendoza, Argentina.

Guiding students through these steps (without skipping any!), they learn many valuable lessons. The incremental nature of the exercises means they get a sense of achievement at the end of each assignment, and they feel they are learning with low effort. As they progress, they naturally practice code re-use and they incrementally learn programming and plotting techniques. As they analyze their results, they learn about numerical diffusion, accuracy and convergence. In about four weeks of a regularly scheduled course, they become moderately proficient programmers and are motivated to start discussing more theoretical matters.

How to use this module

In a regular-session university course, students can complete the CFD Python lessons in 4 to 5 weeks. As an intensive tutorial, the module can be completed in two or three full days, depending on the learner's prior experience. The lessons can also be used for self study. In all cases, learners should follow along the worked examples in each lesson by re-typing the code in a fresh Jupyter notebook, maybe taking original notes as they try things out.

Lessons

Launch an interactive session with this module using the Binder service: Binder

Steps 1–4 are in one spatial dimension. Steps 5–10 are in two dimensions (2D). Steps 11–12 solve the Navier-Stokes equation in 2D. Three "bonus" notebooks cover the CFL condition for numerical stability, array operations with NumPy, and defining functions in Python.

  • Quick Python Intro —For Python novices, this lesson introduces the numerical libraries (NumPy and Matplotlib), Python variables, use of whitespace, and slicing arrays.
  • Step 1 —Linear convection with a step-function initial condition (IC) and appropriate boundary conditions (BCs).
  • Step 2 —With the same IC/BCs, nonlinear convection.
  • CFL Condition —Exploring numerical stability and the Courant-Friedrichs-Lewy (CFL) condition.
  • Step 3 —With the same IC/BCs, diffusion only.
  • Step 4 —Burgers’ equation, with a saw-tooth IC and periodic BCs (with an introduction to Sympy).
  • Array Operations with NumPy
  • Step 5 —Linear convection in 2D with a square-function IC and appropriate BCs.
  • Step 6 —With the same IC/BCs, nonlinear convection in 2D.
  • Step 7 —With the same IC/BCs, diffusion in 2D.
  • Step 8 —Burgers’ equation in 2D
  • Defining Functions in Python
  • Step 9 —Laplace equation with zero IC and both Neumann and Dirichlet BCs.
  • Step 10 —Poisson equation in 2D.
  • Step 11 —Solves the Navier-Stokes equation for 2D cavity flow.
  • Step 12 —Solves the Navier-Stokes equation for 2D channel flow.

Dependencies

To use these lessons, you need Python 3, and the standard stack of scientific Python: NumPy, Matplotlib, SciPy, Sympy. And of course, you need Jupyter—an interactive computational environment that runs on a web browser.

This mini-course is built as a set of Jupyter notebooks containing the written materials and worked-out solutions on Python code. To work with the material, we recommend that you start each lesson with a fresh new notebook, and follow along, typing each line of code (don't copy-and-paste!), and exploring by changing parameters and seeing what happens.

Installing via Anaconda
We *highly* recommend that you install the [Anaconda Python Distribution](http://docs.continuum.io/anaconda/install). It will make your life so much easier. You can download and install Anaconda on Windows, OSX and Linux.

After installing, to ensure that your packages are up to date, run the following commands in a terminal:

conda update conda
conda update jupyter numpy sympy scipy matplotlib

If you prefer Miniconda (a mini version of Anaconda that saves you disk space), install all the necessary libraries to follow this course by running the following commands in a terminal:

conda update conda
conda install jupyter
conda install numpy scipy sympy matplotlib
Without Anaconda
If you already have Python installed on your machine, you can install Jupyter using pip:
pip install jupyter

Please also make sure that you have the necessary libraries installed by running

pip install numpy scipy sympy matplotlib

How to contribute to CFD Python

We accept contributions via pull request—in fact, several users have already submitted pull requests making corrections or small improvements. You can also open an issue if you find a bug, or have a suggestion.

Copyright and License

(c) 2017 Lorena A. Barba, Gilbert F. Forsyth. All content is under Creative Commons Attribution CC-BY 4.0, and all code is under BSD-3 clause (previously under MIT, and changed on March 8, 2018).

We are happy if you re-use the content in any way!

License License: CC BY 4.0

cfdpython's People

Contributors

ahmadia avatar bryant1410 avatar gforsyth avatar jazzalin avatar labarba avatar mesnardo avatar petebachant avatar porcuquine avatar slink avatar tingyu66 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cfdpython's Issues

Initialization error in Step 9

In the fourth code cell in 12_Step_9.ipynb, dy is set to 2 / (ny - 1). To be consistent with the y array, this should be 1 / (ny - 1).

Correcting this has several effects. First, convergence slows. With the current version, laplace2d() stops iterating at 1,133 steps; after applying the correction, it takes 2,043 steps. Second, the revision affects how close laplace2d() comes to the analytic solution. I use sum(p) as a rough comparison among different results from laplace2d(). The current version (2/(ny - 1)) produces a sum of 231.8 when iteration stops at 1,133 steps. The corrected initialization (1/(ny - 1)) produces 220.2 at 2,043 steps. Compare these with the analytic solution sum of 240.25.

I'm translating to Julia as I work through the Steps. My Julia versions of Step 9 come up with the same results as the revised Python version. In addition, it shows that if you iterate the Julia version of laplace2d() for 5,000 steps, you come up pretty close the analytic solution (sum of 239.5 vs. the 240.25 noted above).

Hope this helps. Thanks again for all your work on this. In addition, thank you for keeping it current.

On to Step 10!

Initialization error in Step 7

I believe the initialization in the Step 7 diffuse() function is incomplete: Only the nodes with an initial value of 2 are reset; all other nodes are left as they were after the last call to diffuse(). For example, if you run diffuse(10) twice in succession and look at statistics such as the maximum and minimum value of u, you will see that the results differ in the two runs. This occurs because the initial values outside of [0.5, 1.0], [0.5, 1.0] have not been reset to 1.0.

This can be remedied by adding "u = numpy.ones((ny, nx)) as the first statement in diffuse().

Thanks for putting these steps to CFD together; they have been very helpful to me. I hope this is a little helpful for you.

Bob

Step4: Error in periodic boundary condition ?

Hey, when handling the periodic boundary conditions in Step 4, after the second for loop of code snippet #10, you have
u[-1] = un[-1] - un[-1] * dt / dx * (un[-1] - un[-2]) + nu * dt / dx**2 * (un[0] - 2 * un[-1] + un[-2])
where in the last set of parentheses you obtained un[i + 1] = un[-1 + 1] = un[0].

Given the boundary u(0) = u(2*pi), shouldn't it be un[i + 1] = un[0 + 1] = un[1] instead of un[0] ?

Thanks in advance!

Outdated dependencies

The Python module versions in requirements.txt are a bit outdated.

I installed all the dependencies using my system's package manager, and while those packages aren't all at the latest version, some of them are quite far ahead of those in requirements.txt.
These are the versions I have tested:
numpy: 1.21.5
matplotlib: 3.5.2
scipy: 1.8.1
sympy: 1.10.1

There weren't any issues, except for a deprecation in matplotlib 3.6 (changelog is here):

MatplotlibDeprecationWarning: Calling gca() with keyword arguments was deprecated in Matplotlib 3.4. Starting two minor releases later, gca() will take no keyword arguments. The gca() function should only be used to get the current axes, or if no axes exist, create new axes with default keyword arguments. To create a new axes with non-default arguments, use plt.axes() or plt.subplot().
  ax = fig.gca(projection='3d')

The fix for this actually quite easy: Replace

ax = fig.gca(projection='3d')

with

ax = fig.add_subplot(projection='3d')

Also, when I checked the matplotlib 2.2.x documentation, it didn't even mention the projection argument on the gca() function.

Please update the dependency list to more recent versions.

You could also use compatible versions instead of exact versions. For example:

# requirements.txt
ipywidgets ~=8.0
jupyter ~=1.0.0
numpy ~=1.23
matplotlib ~=3.6.0
scipy ~=1.9
sympy ~=1.11

Rearranging lesson order and implementing JSAnimation

I'd like to move the lesson on defining functions up the stack so student see it sooner.

So we'll introduce 1d linear and non-linear convection, then introduce functions and show off a JSAnimation example. Then when we get to 1d diffusion and burgers, we can embed animations to better show the behavior of the discretizations.

Step 8 transpose equations typo

Looking at 10_Step_8.
In the third set of equations when solving for the next time step and

The last terms for both equations need to change one of the indices to . Like this:

Thank you!

CD Derivation - Step 3

I noticed what I think is a mistake in the derivation for central difference scheme for the 2nd order derivative in Step 3:

It is stated that the 4th order terms are negligible and can be discarded, however this term remains in the next equation. I believe these terms remain until we divide all terms in the equation by dx ^ 2 , thus leaving the remaining 4th order terms to 2nd order terms, yielding the scheme 2nd order accurate.

Hope this makes sense :)

Lesson 14 build_up_b

Could be wring, but I don't think the 'dt' term belongs there. The poisson pressure equation doesn't have a 'dt' term.

2D PDE solving: x-y index of u arrays might be mistaken

Dear BarbaGroud,

Thank you for sharing your work, it's awesome. But I'm having a hard time understanding your 2D implementation. In every of the notebooks I can see that the u is initialised as:

u = np.ones((ny,nx))

This means that the rows of the u array are related to the y direction and the columns are related to the x direction.

Furthermore when (for example) the 2D linear burger equation is solved you are using the following expression:

c_dt/dx_(un[i,j] - un[i-1,j])

To evaluate the derivative in the x-direction. As far as I'm concerned the rows of un, do have the information of the y axis, and thus you should be using dy instead of dx. This problem is not raised up because you are using the same dimensions and subdivisions for the x and y axis, but whenever this is changed there will be some errors.

The problem could be solved changing the u initialisation to:

u = np.ones((nx,ny))

Although the plots should be using the transposed of u in order to get the right axis.

Hope I'm wrong with my comments, but I've been thinking about this for a long time and I just cannot see if I'm making a mistake.

Thank you very much.

Clarify / revisit boundary conditions in Step 4

There have been a few issues around the periodic boundary conditions in Step 4.
At the very least, they need further clarification, especially if we treat u[0] == u[-1] (which we do, for the moment)

Enter "c" in equation for dt, even though c=1

It's minor, but the formula for getting dt is already assuming c=1, which could cause someone to trip over this …

def linearconv(nx):
    dx = 2./(nx-1)
    nt = 20    #nt is the number of timesteps we want to calculate
    c = 1
    sigma = .1

    dt = sigma*dx

(submitted by email by Richard Galvez, Physics PhD Candidate, Syracuse University)

definition of L1 norm on Step 9: 2D Laplace Equation

According to the link below, the L1 norm of a matrix is calculated by summing up absolute values in each column, and then taking the maximum
https://en.wikipedia.org/wiki/Matrix_norm

The notebook for Step 9 calculates the norm by summing up the absolute values of all the elements in the matrix. Also the link provided to read up further on the L1 norm leads to the wiki page for L1 norm of a vector (which I understand is different from the L1 norm of a matrix)

Pressure is -ve in 11th step

In the 11th step, the solution of the pressure equation is -ve , which is physically invalid. And in the Pressure Poisson equation's discretization, there is no time variable so, how the term containing dt arrives

Use of ipython widgets

Looking at one of the early notebooks, you have a call to action: What do you observe about the evolution of the hat function under the non-linear convection equation? What happens when you change the numerical parameters and run again?

I wondered if you had considered making an interactive out of this using ipywidgets? (Or maybe you did and discounted it because it can detract from purposeful exploration and engagement with the code in favour of letting students just play with the interactive shiny bits?!)

Maybe there is a bug in code of Array Operations with NumPy

In . There is a little bug in sentence:
u[1:, 1:] = un[1:, 1:] - ((c * dt / dx * (un[1:, 1:] - un[1:, 0:-1])) -
(c * dt / dy * (un[1:, 1:] - un[0:-1, 1:])))

The bold left bracket "(" is in a wrong place. It should follow "=" . Correct code should be:
u[1:, 1:] = ( un[1:, 1:] -(c * dt / dx * (un[1:, 1:] - un[1:, 0:-1])) -
(c * dt / dy * (un[1:, 1:] - un[0:-1, 1:])))
This little bug make cell5 and cell6 show a different result which suppose to be same.

Step 1: indexing hack will confuse beginners

cell[3] : 
u[.5/dx : 1/dx+1]=2  #setting u = 2 between 0.5 and 1 as per our I.C.s

Floating point used as indices implies a cast to integer which is probably too much for beginners.

Statement of need could be more clear about the target audience

The statement of need in paper.md does a good job describing the effectiveness of the lessons, but doesn't clearly explain who would benefit from these lessons and why. For example, is this geared towards graduate students in mechanical engineering, physics, math, etc.?

A statement of need: Do the authors clearly state the need for this module and who the target audience is?

openjournals/jose-reviews#21

About equation 4 in step11

This CFDPython lessons is the best leasons I 've ever token about CFD. I follow every step until step11. But I got stuck in equation 4 of step11 :

∂2p/∂x2+∂2p/∂y2=−ρ(∂u/∂x∂u/∂x+2∂u/∂y∂v/∂x+∂v/∂y*∂v/∂y)

where did the Poisson equation come from. And How to derive this equation.

I have been confused for month about this equation.

Typo in Step 11

In code section "In [4]" BC determination:

p[:, -1] = p[:, -2] ##dp/dy = 0 at x = 2

In fact it is ##dp/dx = 0 at x = 2

No pressure gradient in step 12?

If you plot the pressure profile after convergence of the Navier-Stokes equations coupled with the pressure-poisson equation there is no pressure gradient, is this an artifact of the periodic boundary conditions?

The pressure field does not change at all during iteration...

Step #4 Initial Conditions

When plotting the numerical solution at step 4, initial conditions of the equation was taken from analytical solution (by using un = u.copy() at the beginning of the FD loop, array u is the analytical solution of function at t=0 in our code). I think we need to use initial conditions below in the picture.

resim_2023-09-15_164022302

Disappearing viscosity term in the discrete version of Poisson-pressure equation

Thank you for this great course! I have been using this course to teach CFD-concepts in Belgium.

I'm stuck with the following question. In video lecture 11, a poisson equation is obtained to correct for the divergence in the velocity.

image

However in notebook 14 the discretised pressure-Poisson equation looks completely different than the one obtained
in the video lecture: https://youtu.be/ZjfxA3qq2Lg?t=1647

My question is: what happened in between the curved brackets in the video lecture and equation 13 in the notebook.

Division by zero on 01_Step_1.ipynb

Running 01_Step_1.ipynb I get a division by zero error. The error goes away by setting
dx = 2.0/(nx-1) instead of dx = 2/(nx-1). I am using anaconda Python 2.7.11 :: Anaconda 2.5.0 (x86_64).

Thanks!

Periodic boundary condition in Burgers' equation

In line #435-#437 in _05_Step_4.ipynb_, when i=0, it will use u[-1]as its left-hand-side point. However, with periodic boundary condition, because u[0] = u[-1], hence u[-2] instead of u[-1] is the correct left-hand-side point of u[0] .

11 step, d(div(U))/dt term

Hello, please someone answere me, wherefrom the 1/delta(t)*div(U) term is appearing in Poisson eq? In previous steps was used that div(U) = 0 .... just don't get it

Typo in the Poisson equation discretization in Step 11

There is a strange (1 / Delta t) term in the discretized Poisson equation that is present in the written equation, the Python code (in the build_up_b function), and the corresponding Youtube video. This seems to make the solution unstable for small time steps. I think this may be due to a misapplication of discretization to a time derivative of div v. For an incompressible fluid, div v = 0 so this term should vanish. In any case, just tacking on a (1 / Delta t) is not the correct way to discretize a time derivative.

Step 5: matplotlib error

gca() with keyword arguments was deprecated in Matplotlib 3.4
usingsubplot() or add_subplot()may resolve the question

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.