
In this lecture, we introduce adjoint solvers and explain why they are a powerful and essential tool in CFD-based shape and topology optimization. While traditional CFD simulations help us analyze flow around a given geometry, real engineering design often requires us to optimize a shape to achieve specific objectives such as maximizing lift or minimizing drag—without running prohibitively expensive simulations for every design change.
You will learn how adjoint methods efficiently compute sensitivities of an objective function with respect to design variables, enabling systematic and computationally affordable optimization. We begin by formulating the optimization problem, introduce the concept of primal and adjoint equations, and explain both the direct sensitivity method and the Lagrange multiplier (adjoint) approach.
The lecture then dives into:
Sensitivity analysis for Navier–Stokes equations
Why adjoint methods scale independently of the number of design variables
Application to topology optimization using Brinkman penalization
Construction of the adjoint equations using integration by parts
Optimization loops and gradient-based update strategies
Practical challenges such as instability, checkerboarding, and smoothing
Key implementation insights relevant to OpenFOAM adjoint solvers, including discretization choices, boundary conditions, and ATC models
By the end of this lecture, you will have a strong theoretical foundation for adjoint-based optimization and understand why adjoint solvers are the preferred approach for large-scale CFD optimization problems.
In this lecture, we will explore the importance of Docker and why it is a valuable tool for running simulations. You will learn how to install Docker step-by-step, and then test your installation by running an example OpenFOAM simulation within the Docker environment to ensure everything is set up correctly. Ignore this if you have OpenFOAM installed.
In this lecture, we provide hands-on instructions for installing all the software used in the course (and more) on the Windows operating system. The focus of this session is solely on the installation process. This lecture ensures that Windows users can follow the course seamlessly without any interruptions. Ignore this if you have OpenFOAM installed.
In this lecture, we perform a hands-on sensitivity analysis using the adjoint solver available in OpenFOAM. Sensitivity analysis is the simplest and most fundamental application of adjoint methods and serves as a foundation for shape optimization and topology optimization, which will be covered in subsequent lectures.
Using the classic flow past a square cylinder example, you will learn how to compute the sensitivity of a cost function—such as lift—with respect to design variables. Unlike full optimization, sensitivity analysis requires only one primal solve and one adjoint solve, making it computationally efficient and ideal for understanding the adjoint workflow.
The lecture covers:
Setting up the optimizationDict for adjoint simulations
Understanding single-run vs steady optimization managers
Configuring primal and adjoint solvers for incompressible flows
Defining objective functions (lift via force-based objectives)
Selecting appropriate adjoint transport convection (ATC) models
Applying correct adjoint boundary conditions
Modifying fvSchemes, fvSolution, and controlDict for adjoint runs
Running the adjoint solver and interpreting surface sensitivity results
Understanding convergence issues due to vortex shedding
Ensuring steady-state flow conditions for reliable adjoint solutions
By the end of this lecture, you will be able to:
Run an adjoint-based sensitivity study in OpenFOAM
Interpret sensitivity fields and surface-normal gradients
Understand how sensitivities guide shape modification decisions
In this lecture, we extend the adjoint workflow from sensitivity analysis to full shape optimization using the adjoint solvers available in OpenFOAM. Building on the previous lecture, we again consider the flow past a cylinder and demonstrate how adjoint sensitivities can be used to iteratively modify the geometry to improve a target objective.
You will learn how shape optimization differs from sensitivity analysis and what additional components are required to allow the geometry to evolve. The lecture focuses on defining control points, enabling mesh motion, and coupling adjoint sensitivities with a constrained optimization strategy.
Key topics covered include:
Converting a sensitivity setup into a shape optimization case
Defining control points using dynamicMeshDict
Using the volumetric B-spline motion solver for adjoint-based mesh deformation
Understanding control-point placement, bounds, and confinement
Configuring steady optimization managers for iterative optimization
Combining aerodynamic objectives (lift) with geometric constraints (partial volume)
Defining shape design variables and selecting appropriate update methods
Applying constraint projection for stable geometry evolution
Visualizing control points and mesh deformation
Interpreting optimized shapes based on flow physics and lift generation
Common pitfalls in shape optimization, including instability due to poorly placed control points
By the end of this lecture, you will be able to:
Perform adjoint-based shape optimization in OpenFOAM
Configure and control geometry deformation using B-spline control points
Understand how adjoint sensitivities guide meaningful shape changes
Diagnose and fix common stability issues in shape optimization setups
In this lecture, we complete the adjoint optimization workflow by introducing topology optimization using adjoint solvers in OpenFOAM. After covering sensitivity analysis and shape optimization in earlier lectures, we now move to the most powerful and flexible design approach—optimizing the topology of the flow domain itself.
Unlike shape optimization, topology optimization allows material to be added or removed inside the flow domain using a porosity-based formulation. This approach is particularly suited for internal flows, where the objective is to guide the flow efficiently between an inlet and multiple outlets.
The lecture demonstrates a full end-to-end topology optimization workflow, including geometry creation, meshing, solver setup, and result interpretation.
Key topics covered include:
Why topology optimization is best suited for internal flow problems
Creating a parametric 3D geometry using FreeCAD
Preparing and labeling geometry for CFD using Gmsh
Generating a volume mesh using cfMesh
Defining inlet, outlet, and wall boundary conditions
Setting up pressure-loss (PT loss) objectives
Introducing porosity-based topology design variables
Understanding the β (beta) porosity field and its physical meaning
Creating fixed flow regions using topoSet and cellZones
Converting cell sets to zones for optimization control
Configuring optimization dictionaries for topology optimization
Running adjoint-based topology optimization loops
Visualizing flow paths, porosity evolution, and optimized layouts
Extracting the final optimized geometry using thresholding
By the end of this lecture, you will be able to:
Set up and run a porosity-based topology optimization case in OpenFOAM
Control where optimization is allowed using cell zones
Interpret the evolution of the porosity field during optimization
In this lecture, we revisit the topology optimization case from the previous video and address a critical missing component in porosity-based adjoint optimization in OpenFOAM.
When using porosity-based topology optimization, it is not sufficient to define the porosity design variable (beta) only in the optimization dictionary. To correctly influence the flow, the porosity field must also be coupled to the momentum equations through an appropriate source term. Without this coupling, the porosity may evolve numerically, but it will not physically affect the flow field.
This lecture explains what was missing, why it matters, and how to fix it.
This course is a hands-on introduction to CFD-based design optimization using OpenFOAM, created to help learners move beyond flow visualization and into systematic, simulation-driven design improvement. The focus is on understanding how optimization problems are set up in CFD and why each configuration choice matters, rather than on solving large-scale industrial problems.
The course is intentionally built for learners who do not need prior knowledge of adjoint methods. All optimization concepts are introduced from a design and engineering perspective first, making it clear what is being optimized and how CFD can guide better designs. Mathematical complexity is kept to a minimum, while practical implementation details are emphasized throughout.
All example cases used in this course are simple and intentionally low-dimensional, developed solely for demonstrating the optimization workflow and solver setup. This ensures that learners can focus on understanding the methodology rather than dealing with complex geometries or large computational costs.
For sensitivity analysis and shape optimization, a 2D flow past a square cylinder is used as the primary example. This canonical problem allows clear visualization of sensitivities, objective-function behavior, and boundary deformation while keeping the physics and mesh handling straightforward.
For topology optimization, a 3D internal flow problem with one inlet and two outlets is considered. In this case, the flow domain is optimized using a porosity-based approach, allowing material to be added or removed within the domain to guide the flow efficiently toward the outlets. The geometry and flow conditions are deliberately simplified so that the evolution of topology and porosity can be easily interpreted and visualized.
The course uses OpenFOAM v2412, and all demonstrations, case files, and dictionaries are fully compatible with this version. You will work directly with OpenFOAM solvers, optimization dictionaries, and post-processing tools, learning how to configure sensitivity analysis, shape optimization, and topology optimization in a consistent and reproducible way.
Special attention is given to common implementation pitfalls, such as missing source-term coupling in porosity-based optimization, improper constraint definitions, and unstable optimization behavior. Rather than hiding these issues, the course explains why they occur and how to fix them, helping you build confidence in diagnosing real optimization problems.
To support hands-on learning, the course includes video lectures along with additional PDF notes, fully working OpenFOAM case files, and configuration templates. These resources are designed so that you can run the cases yourself, modify parameters, and extend the examples to your own CFD problems.
By the end of this course, you will have a clear understanding of how CFD-based optimization works in practice, how to set up and run optimization cases in OpenFOAM, and how to interpret optimization results from a physical and numerical perspective. This course equips you with the tools needed to use CFD not just for analysis, but as a powerful design and decision-making framework.