A sequence of Jupyter notebooks featuring the 12 Steps to Navier-Stokes

Overview

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. 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

Running the notebook server

Once Jupyter is installed, open up a terminal and then run

jupyter notebook

This will start up a Jupyter session in your browser!

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

Comments
  • Added a top level license file

    Added a top level license file

    The course is offered under CC-BY, which is fantastic. This is not obvious from the repository (unless you dig into the iPython notebooks). A top-level license file makes this obvious both to people browsing and to search engines.

    opened by pmitros 11
  • Display equations correctly

    Display equations correctly

    Fix #40

    Use Latex split environment. Remove line breaks to display equation correctly.

    You can view the modified notebooks with Nbviewer to check the equations:

    opened by mesnardo 6
  • Division by zero on 01_Step_1.ipynb

    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!

    opened by xocd 5
  • Fixed a typo in the Step4 notebook

    Fixed a typo in the Step4 notebook

    The u[0] calculation had terms that were un[-2] in both spatial derivatives. Those should be un[-1].

    Additionally it is worth noting that the periodic conditions can all be handled correctly by the u[i] calculation as written by simply changing the range to for i in range(-1, nx-1) as below. This makes use of python negative indexing which wraps to the end of the array, effectively computing u[-1] and u[0] first.

    for n in range(nt):
        un = u.copy()
        for i in range(-1, nx-1):
            u[i] = un[i] - un[i] * dt/dx *(un[i] - un[i-1]) + nu*dt/dx**2*\
                    (un[i+1]-2*un[i]+un[i-1])
    
    opened by amcdawes 4
  • Maybe there is a bug in code of Array Operations with NumPy

    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.

    bug 
    opened by fidle 3
  • Step4: Error in periodic boundary condition ?

    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!

    opened by ghost 3
  • Use of ipython widgets

    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?!)

    opened by psychemedia 3
  • 2D PDE solving: x-y index of u arrays might be mistaken

    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.

    opened by GonzaloSaez 3
  • definition of L1 norm on Step 9: 2D Laplace Equation

    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)

    question 
    opened by bharath-kamath705 2
  • No pressure gradient in step 12?

    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...

    opened by Beramos 2
  • Typo in the Poisson equation discretization in Step 11

    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.

    opened by peterparity 2
  • Outdated dependencies

    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
    
    opened by onitake 1
  • Fixed constant typo in the periodic boundary conditions

    Fixed constant typo in the periodic boundary conditions

    Previously, there has been a typo throughout the code implementation in Step 12 in the periodic boundary conditions. As a quick example, If u_{i,j} was at the right boundary, then u_{i+1,j} was took to be at the left boundary i.e u_{0,j} (instead of u_{1,j}). This PR fixes those issues, although hardly changes the results.

    opened by michaeldavidjohnson 1
  • Bump numpy from 1.14.3 to 1.22.0

    Bump numpy from 1.14.3 to 1.22.0

    Bumps numpy from 1.14.3 to 1.22.0.

    Release notes

    Sourced from numpy's releases.

    v1.22.0

    NumPy 1.22.0 Release Notes

    NumPy 1.22.0 is a big release featuring the work of 153 contributors spread over 609 pull requests. There have been many improvements, highlights are:

    • Annotations of the main namespace are essentially complete. Upstream is a moving target, so there will likely be further improvements, but the major work is done. This is probably the most user visible enhancement in this release.
    • A preliminary version of the proposed Array-API is provided. This is a step in creating a standard collection of functions that can be used across application such as CuPy and JAX.
    • NumPy now has a DLPack backend. DLPack provides a common interchange format for array (tensor) data.
    • New methods for quantile, percentile, and related functions. The new methods provide a complete set of the methods commonly found in the literature.
    • A new configurable allocator for use by downstream projects.

    These are in addition to the ongoing work to provide SIMD support for commonly used functions, improvements to F2PY, and better documentation.

    The Python versions supported in this release are 3.8-3.10, Python 3.7 has been dropped. Note that 32 bit wheels are only provided for Python 3.8 and 3.9 on Windows, all other wheels are 64 bits on account of Ubuntu, Fedora, and other Linux distributions dropping 32 bit support. All 64 bit wheels are also linked with 64 bit integer OpenBLAS, which should fix the occasional problems encountered by folks using truly huge arrays.

    Expired deprecations

    Deprecated numeric style dtype strings have been removed

    Using the strings "Bytes0", "Datetime64", "Str0", "Uint32", and "Uint64" as a dtype will now raise a TypeError.

    (gh-19539)

    Expired deprecations for loads, ndfromtxt, and mafromtxt in npyio

    numpy.loads was deprecated in v1.15, with the recommendation that users use pickle.loads instead. ndfromtxt and mafromtxt were both deprecated in v1.17 - users should use numpy.genfromtxt instead with the appropriate value for the usemask parameter.

    (gh-19615)

    ... (truncated)

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • Initialization error in Step 9

    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!

    bug 
    opened by Bob-McCrory 1
  • Disappearing viscosity term in the discrete version of Poisson-pressure equation

    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.

    evergreen 
    opened by Beramos 10
Releases(v1.0)
Owner
Barba group
Barba group
This is the latest version of the PULP SDK

PULP-SDK This is the latest version of the PULP SDK, which is under active development. The previous (now legacy) version, which is no longer supporte

78 Dec 07, 2022
Alignment Attention Fusion framework for Few-Shot Object Detection

AAF framework Framework generalities This repository contains the code of the AAF framework proposed in this paper. The main idea behind this work is

Pierre Le Jeune 20 Dec 16, 2022
retweet 4 satoshi ⚡️

rt4sat retweet 4 satoshi This bot is the codebase for https://twitter.com/rt4sat please feel free to create an issue if you saw any bugs basically thi

6 Sep 30, 2022
Playing around with FastAPI and streamlit to create a YoloV5 object detector

FastAPI-Streamlit-based-YoloV5-detector Playing around with FastAPI and streamlit to create a YoloV5 object detector It turns out that a User Interfac

2 Jan 20, 2022
MWPToolkit is a PyTorch-based toolkit for Math Word Problem (MWP) solving.

MWPToolkit is a PyTorch-based toolkit for Math Word Problem (MWP) solving. It is a comprehensive framework for research purpose that integrates popular MWP benchmark datasets and typical deep learnin

119 Jan 04, 2023
A simple, clean TensorFlow implementation of Generative Adversarial Networks with a focus on modeling illustrations.

IllustrationGAN A simple, clean TensorFlow implementation of Generative Adversarial Networks with a focus on modeling illustrations. Generated Images

268 Nov 27, 2022
Code for "LASR: Learning Articulated Shape Reconstruction from a Monocular Video". CVPR 2021.

LASR Installation Build with conda conda env create -f lasr.yml conda activate lasr # install softras cd third_party/softras; python setup.py install;

Google 157 Dec 26, 2022
Official implementation of the article "Unsupervised JPEG Domain Adaptation For Practical Digital Forensics"

Unsupervised JPEG Domain Adaptation for Practical Digital Image Forensics @WIFS2021 (Montpellier, France) Rony Abecidan, Vincent Itier, Jeremie Boulan

Rony Abecidan 6 Jan 06, 2023
PyTorch implementation of Asymmetric Siamese (https://arxiv.org/abs/2204.00613)

Asym-Siam: On the Importance of Asymmetry for Siamese Representation Learning This is a PyTorch implementation of the Asym-Siam paper, CVPR 2022: @inp

Meta Research 89 Dec 18, 2022
Deploy a ML inference service on a budget in less than 10 lines of code.

BudgetML is perfect for practitioners who would like to quickly deploy their models to an endpoint, but not waste a lot of time, money, and effort trying to figure out how to do this end-to-end.

1.3k Dec 25, 2022
Inferring Lexicographically-Ordered Rewards from Preferences

Inferring Lexicographically-Ordered Rewards from Preferences Code author: Alihan Hüyük ([e

Alihan Hüyük 1 Feb 13, 2022
Official PyTorch implementation of Learning Intra-Batch Connections for Deep Metric Learning (ICML 2021) published at International Conference on Machine Learning

About This repository the official PyTorch implementation of Learning Intra-Batch Connections for Deep Metric Learning. The config files contain the s

Dynamic Vision and Learning Group 41 Dec 10, 2022
In this project, we create and implement a deep learning library from scratch.

ARA In this project, we create and implement a deep learning library from scratch. Table of Contents Deep Leaning Library Table of Contents About The

22 Aug 23, 2022
Rainbow DQN implementation that outperforms the paper's results on 40% of games using 20x less data 🌈

Rainbow 🌈 An implementation of Rainbow DQN which reaches a median HNS of 205.7 after only 10M frames (the original Rainbow from Hessel et al. 2017 re

Dominik Schmidt 31 Dec 21, 2022
A light and fast one class detection framework for edge devices. We provide face detector, head detector, pedestrian detector, vehicle detector......

A Light and Fast Face Detector for Edge Devices Big News: LFD, which is a big update of LFFD, now is released (2021.03.09). It is strongly recommended

YonghaoHe 1.3k Dec 25, 2022
Source code of the paper Meta-learning with an Adaptive Task Scheduler.

ATS About Source code of the paper Meta-learning with an Adaptive Task Scheduler. If you find this repository useful in your research, please cite the

Huaxiu Yao 16 Dec 26, 2022
Deep GPs built on top of TensorFlow/Keras and GPflow

GPflux Documentation | Tutorials | API reference | Slack What does GPflux do? GPflux is a toolbox dedicated to Deep Gaussian processes (DGP), the hier

Secondmind Labs 107 Nov 02, 2022
CTF challenges and write-ups for MicroCTF 2021.

MicroCTF 2021 Qualifications About This repository contains CTF challenges and official write-ups for MicroCTF 2021 Qualifications. License Distribute

Shellmates 12 Dec 27, 2022
Official Implementation of Few-shot Visual Relationship Co-localization

VRC Official implementation of the Few-shot Visual Relationship Co-localization (ICCV 2021) paper project page | paper Requirements Use python = 3.8.

22 Oct 13, 2022
Neural networks applied in recognizing guitar chords using python, AutoML.NET with C# and .NET Core

Chord Recognition Demo application The demo application is written in C# with .NETCore. As of July 9, 2020, the only version available is for windows

Andres Mauricio Rondon Patiño 24 Oct 22, 2022