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
Code for "Learning Skeletal Graph Neural Networks for Hard 3D Pose Estimation" ICCV'21

Skeletal-GNN Code for "Learning Skeletal Graph Neural Networks for Hard 3D Pose Estimation" ICCV'21 Various deep learning techniques have been propose

37 Oct 23, 2022
Dynamic Divide-and-Conquer Adversarial Training for Robust Semantic Segmentation (ICCV2021)

Dynamic Divide-and-Conquer Adversarial Training for Robust Semantic Segmentation This is a pytorch project for the paper Dynamic Divide-and-Conquer Ad

DV Lab 29 Nov 21, 2022
Using this you can control your PC/Laptop volume by Hand Gestures (pinch-in, pinch-out) created with Python.

Hand Gesture Volume Controller Using this you can control your PC/Laptop volume by Hand Gestures (pinch-in, pinch-out). Code Firstly I have created a

Tejas Prajapati 16 Sep 11, 2021
FLAVR is a fast, flow-free frame interpolation method capable of single shot multi-frame prediction

FLAVR is a fast, flow-free frame interpolation method capable of single shot multi-frame prediction. It uses a customized encoder decoder architecture with spatio-temporal convolutions and channel ga

Tarun K 280 Dec 23, 2022
Hierarchical User Intent Graph Network for Multimedia Recommendation

Hierarchical User Intent Graph Network for Multimedia Recommendation This is our Pytorch implementation for the paper: Hierarchical User Intent Graph

6 Jan 05, 2023
Invertible conditional GANs for image editing

Invertible Conditional GANs This is the implementation of the IcGAN model proposed in our paper: Invertible Conditional GANs for image editing. Novemb

Guim 278 Dec 12, 2022
PyTorch implementation of the Flow Gaussian Mixture Model (FlowGMM) model from our paper

Flow Gaussian Mixture Model (FlowGMM) This repository contains a PyTorch implementation of the Flow Gaussian Mixture Model (FlowGMM) model from our pa

Pavel Izmailov 124 Nov 06, 2022
This is the PyTorch implementation of GANs N’ Roses: Stable, Controllable, Diverse Image to Image Translation

Official PyTorch repo for GAN's N' Roses. Diverse im2im and vid2vid selfie to anime translation.

1.1k Jan 01, 2023
A system for quickly generating training data with weak supervision

Programmatically Build and Manage Training Data Announcement The Snorkel team is now focusing their efforts on Snorkel Flow, an end-to-end AI applicat

Snorkel Team 5.4k Jan 02, 2023
QuanTaichi evaluation suite

QuanTaichi: A Compiler for Quantized Simulations (SIGGRAPH 2021) Yuanming Hu, Jiafeng Liu, Xuanda Yang, Mingkuan Xu, Ye Kuang, Weiwei Xu, Qiang Dai, W

Taichi Developers 120 Jan 04, 2023
This repo contains the official code of our work SAM-SLR which won the CVPR 2021 Challenge on Large Scale Signer Independent Isolated Sign Language Recognition.

Skeleton Aware Multi-modal Sign Language Recognition By Songyao Jiang, Bin Sun, Lichen Wang, Yue Bai, Kunpeng Li and Yun Fu. Smile Lab @ Northeastern

Isen (Songyao Jiang) 128 Dec 08, 2022
nnFormer: Interleaved Transformer for Volumetric Segmentation

nnFormer: Interleaved Transformer for Volumetric Segmentation Code for paper "nnFormer: Interleaved Transformer for Volumetric Segmentation ". Please

jsguo 610 Dec 28, 2022
codes for paper Combining Dynamic Local Context Focus and Dependency Cluster Attention for Aspect-level sentiment classification

DLCF-DCA codes for paper Combining Dynamic Local Context Focus and Dependency Cluster Attention for Aspect-level sentiment classification. submitted t

15 Aug 30, 2022
This is the official implement of paper "ActionCLIP: A New Paradigm for Action Recognition"

This is an official pytorch implementation of ActionCLIP: A New Paradigm for Video Action Recognition [arXiv] Overview Content Prerequisites Data Prep

268 Jan 09, 2023
Keras + Hyperopt: A very simple wrapper for convenient hyperparameter optimization

This project is now archived. It's been fun working on it, but it's time for me to move on. Thank you for all the support and feedback over the last c

Max Pumperla 2.1k Jan 03, 2023
Visual Tracking by TridenAlign and Context Embedding

Visual Tracking by TridentAlign and Context Embedding (TACT) Test code for "Visual Tracking by TridentAlign and Context Embedding" Janghoon Choi, Juns

Janghoon Choi 32 Aug 25, 2021
Python scripts form performing stereo depth estimation using the CoEx model in ONNX.

ONNX-CoEx-Stereo-Depth-estimation Python scripts form performing stereo depth estimation using the CoEx model in ONNX. Stereo depth estimation on the

Ibai Gorordo 8 Dec 29, 2022
Physics-Aware Training (PAT) is a method to train real physical systems with backpropagation.

Physics-Aware Training (PAT) is a method to train real physical systems with backpropagation. It was introduced in Wright, Logan G. & Onodera, Tatsuhiro et al. (2021)1 to train Physical Neural Networ

McMahon Lab 230 Jan 05, 2023
Lbl2Vec learns jointly embedded label, document and word vectors to retrieve documents with predefined topics from an unlabeled document corpus.

Lbl2Vec Lbl2Vec is an algorithm for unsupervised document classification and unsupervised document retrieval. It automatically generates jointly embed

sebis - TUM - Germany 61 Dec 20, 2022
Code for Boundary-Aware Segmentation Network for Mobile and Web Applications

BASNet Boundary-Aware Segmentation Network for Mobile and Web Applications This repository contain implementation of BASNet in tensorflow/keras. comme

Hamid Ali 8 Nov 24, 2022