Installing on an Apple-silicon Mac

DAFoam runs only on Linux. On a Mac the route that has been run end to end is a Linux VM: Lima runs Ubuntu 24.04 for ARM64 under Apple’s hypervisor, so the guest executes ARM64 instructions directly on the Mac’s cores. There is no emulation and CPU-bound work runs at close to native speed. DAFoam is then built from source inside the VM.

This page is the exact procedure that produced the verified results in Verification status. Where a step was run by hand rather than by a script, it says so.

What you need

Mac

Apple silicon (M-series), macOS 13 or later (verified on macOS 26)

Homebrew

to install Lima

RAM

the VM reserves 32 GiB in the shipped config; edit memory: in scripts/vm/lima-dafoam.yaml for a smaller Mac (the build itself is happy with 16 GiB; fewer cores means a longer build)

Disk

160 GiB virtual disk, grows on demand; the finished install is about 11 GB

Time

about 2 hours of unattended build on 12 cores (measured on an M5 Max: Python 1 min, PETSc 20, OpenFOAM v2506 40, OpenFOAM-AD 40, Hisa4DAFoam + DAFoam 7)

Network

the build downloads about 1 GB of sources

1. Create the VM

brew install lima
git clone https://github.com/LSDOlab/csdl_dafoam && cd csdl_dafoam
limactl start --name=dafoam scripts/vm/lima-dafoam.yaml     # answer "Proceed"; first start downloads the Ubuntu image
limactl shell dafoam uname -m                               # should print aarch64

The config installs DAFoam’s documented Ubuntu prerequisites on first boot (the same list as scripts/vm/install_prereqs_ubuntu.sh). No host folder is mounted into the VM: files go in with limactl copy.

Warning

Never add a Lima mount written as {{.Dir}}/../... In Lima {{.Dir}} is the instance directory, so that path is your home directory. An earlier version of this config did exactly that and exposed the whole home folder (read-only) to the VM before it was caught. tests/test_vm_scripts.py now fails if the config has any mount.

Start the VM from one terminal only. A second limactl start (or limactl shell offering to start it) races the first and one of them fails with “another hostagent may already be running”.

2. Build DAFoam (about 2 hours)

limactl copy scripts/vm/install_dafoam_ubuntu.sh dafoam:~/
limactl shell dafoam -- sudo systemd-run --unit=dafoam-build --uid=$(id -u) --gid=$(id -g) \
    --setenv=HOME=$HOME --working-directory=$HOME --collect bash -c 'bash install_dafoam_ubuntu.sh > install.out 2>&1'

systemd-run makes the build a detached service inside the VM, so it survives closing your terminal (a plain limactl shell ... & can be killed with the session). Follow it, and check it is still alive:

limactl shell dafoam -- tail -f dafoam/build.log                          # Ctrl-C leaves the build running
limactl shell dafoam -- systemctl is-active dafoam-build                  # "active" while building
limactl shell dafoam -- ls dafoam/.stages                                 # finished stages
limactl shell dafoam -- ls dafoam/DONE dafoam/FAILED                      # one of these exists at the end

Stages, in order: 1-python, 2-petsc, 2b-petsc4py, 3-openfoam, 4-openfoam-ad, 5a-pyofm, 5b-hisa4dafoam, 5-dafoam. The script is resumable: if a stage fails, fix the cause and launch it again; finished stages are skipped.

What the script pins, so the build is repeatable: OpenFOAM v2506, PETSc 3.21.6, mpi4py 4.1.1, DAFoam 5.1.1, pyOFM 1.2.3, OpenFOAM-AD at commit 2e519c1, Hisa4DAFoam at commit 73ced10, and the Python packages numpy 2.3.5, scipy 1.18.1, Cython 3.0.5, OpenMDAO 3.45.1. What it does not pin: the Ubuntu packages (the 24.04 release as of build; compilers were gcc 13.3, OpenMPI 4.1.6). scripts/vm/pip-freeze-ubuntu2404-aarch64.txt records the full verified Python environment.

3. Check DAFoam

limactl shell dafoam bash -c '. ~/dafoam/loadDAFoam.sh && python -c "import dafoam; print(dafoam.__file__)" && which simpleFoam simpleFoamADR'

Every shell that runs DAFoam must first . ~/dafoam/loadDAFoam.sh (it sets the OpenFOAM environment).

4. Install csdl_dafoam and its Python stack in the VM

tar --exclude=.git -czf /tmp/csdl_dafoam.tgz . && limactl copy /tmp/csdl_dafoam.tgz dafoam:~/
limactl shell dafoam bash -c '
  mkdir -p csdl_dafoam && tar xzf csdl_dafoam.tgz -C csdl_dafoam
  . ~/dafoam/loadDAFoam.sh
  pip install -r csdl_dafoam/requirements-verified.txt
  pip install pyslsqp qpsolvers quadprog highspy jax pytest matplotlib
  pip install -e csdl_dafoam --no-deps
  python -m csdl_dafoam.doctor'

requirements-verified.txt pins csdl_alpha, modopt and idwarp-jax to the commits that were verified together. The doctor prints [ok] for every row except the optional Fortran IDWarp.

5. Run

limactl shell dafoam bash -c '. ~/dafoam/loadDAFoam.sh && cd csdl_dafoam && pytest -m dafoam'              # real-solver tests, about 1 min
limactl shell dafoam bash -c '. ~/dafoam/loadDAFoam.sh && cd csdl_dafoam && mpirun -np 4 python examples/airfoil_analysis.py'
limactl shell dafoam bash -c '. ~/dafoam/loadDAFoam.sh && cd csdl_dafoam && mpirun -np 4 python examples/airfoil_optimization.py --maxiter 40'

Results land in run/ inside the VM (set with --workdir). Copy figures back to the Mac to look at them:

limactl copy dafoam:csdl_dafoam/run/optimization.png .      # path as printed by the example

Managing the VM

limactl stop dafoam                    # free the RAM; the install stays on its disk
limactl start dafoam                   # resume (no config file needed after the first start)
limactl delete dafoam                  # remove the VM and the 11 GB

Problems met while building this, and their fixes

Symptom

Cause

Fix (already in the script)

petsc4py wheel fails: execute() got an unexpected keyword argument 'dry_run'

petsc4py 3.21’s build script needs an old setuptools

pip install "setuptools<70"

boxTurb / noise fail to link: undefined reference to fftw_...

OpenFOAM only adds ThirdParty FFTW to the library path if it exists when etc/bashrc is sourced, and it is built during the first Allwmake

run Allwmake, re-source the environment, run it again (quick)

DAFoam fails: fatal error: writeFields.H / characteristicBase.H: No such file

the guide builds Hisa4DAFoam between OpenFOAM and DAFoam, and DAFoam’s include path reads it

stage 5b-hisa4dafoam before 5-dafoam

a resumed run fails OpenFOAM environment not found

the script regenerates loadDAFoam.sh on each start and dropped the OpenFOAM lines when that stage was skipped

the loader now always includes them when OpenFOAM is installed

a failure marker appears but the build is fine

an ERR trap fires on commands inside OpenFOAM’s etc/bashrc that return non-zero by design

the trap is now EXIT-only

limactl shell seems to hang

it waits for the VM’s processes

run long work under systemd-run, as above

pkill -f kills your own command

the pattern appears in your shell’s command line

use systemctl stop <unit>