This is the official code repository for the paper "MoNo: Multiscale Optimal Transport Neural Operator for Solving PDEs on General Geometries".
Transformer-based neural operators have achieved substantial progress in solving Partial Differential Equations (PDEs) by projecting spatial observations into compact latent tokens and learning physical interactions in latent spaces. However, we reveal that existing learnable projection mechanisms cannot ensure stable and balanced assignments from observation points to latent tokens, causing some latent tokens to be over-assigned while others remain underutilized. This limitation further restricts the design of hierarchical architectures, as assignment imbalance is continuously inherited and amplified across latent spaces, eventually causing severe token collapse in deeper spaces. To address these issues, we propose MoNo (Multiscale Optimal Transport Neural Operator), a progressive multiscale neural operator that efficiently solves PDEs on general geometries through stable latent-space construction. At its core is CoTAP (Cross-scale Optimal Transport Assignment and Projection), a novel latent-space construction method that formulates cross-space assignment between adjacent spaces as an entropy-regularized optimal transport problem, thereby constructing balanced bidirectional projections and stable latent spaces. CoTAP also ensures stable information transfer across multiple latent spaces, further enabling multiscale architectures on general geometries, which in turn support more efficient learning of long-range physical interactions. Extensive experiments demonstrate that MoNo outperforms existing state-of-the-art neural operators in both prediction performance and computational efficiency.
conda create --name MoNo python=3.10
conda activate MoNo
# Install uv.
pip install uv
# PyTorch 2.8.0 + CUDA 12.8.
uv pip install torch==2.8.0 torchvision==0.23.0 torchaudio==2.8.0
# Install the remaining dependencies.
uv pip install -r requirements.txtDownload the raw datasets from their original sources and place them under a local raw-data directory. The preprocessing scripts write training and test data to ./dataset by default.
| Dataset | Source |
|---|---|
| Airfoil | Google Drive |
| Darcy | Google Drive |
| Elasticity | Google Drive |
| Pipe | Google Drive |
| Plasticity | Google Drive |
| NS2d | Google Drive |
| AirfRANS | AirfRANS |
- Airfoil
/path/to/Airfoil should contain the naca directory with NACA_Cylinder_Q.npy, NACA_Cylinder_X.npy, and NACA_Cylinder_Y.npy.
python preprocess/prepare_airfoil.py --input_dir /path/to/Airfoil- Darcy
python preprocess/prepare_darcy.py --input_paths /path/to/piececonst_r421_N1024_smooth1.mat /path/to/piececonst_r421_N1024_smooth2.mat --obj_res %OBJ_RESwhere %OBJ_RES is the target resolution. Set %OBJ_RES to 85, 141, and 211 respectively to prepare the datasets used in the multi-resolution experiments.
- Elasticity
/path/to/Elasticity should contain the Meshes directory.
python preprocess/prepare_elasticity.py --input_dir /path/to/Elasticity- Pipe
Use /path/to/Pipe as the directory containing the raw Pipe dataset.
python preprocess/prepare_pipe.py --input_dir /path/to/Pipe- Plasticity
Use plas_N987_T20.mat as the raw Plasticity data file:
python preprocess/prepare_plasticity.py --input_path /path/to/plas_N987_T20.mat- NS2d
Use NavierStokes_V1e-5_N1200_T20.mat as the raw NS2d data file:
python preprocess/prepare_ns2d.py --input_path /path/to/NavierStokes_V1e-5_N1200_T20.mat- AirfRANS
python preprocess/prepare_airfrans.py --input_dir /path/to/airrans --tasks full reynolds aoaFor reproducible evaluation, download the prepared evaluation sampling sequences for the standard and OOD experiments from AirfRANS (full), AirfRANS (reynolds), and AirfRANS (aoa). Extract each archive into the corresponding preprocessed dataset directory under eval_sampling/32000/all_surface. For example, the files in AirfRANS (full) should be extracted to ./dataset/airfrans_full/eval_sampling/32000/all_surface. In this repository, airfrans_aoa denotes the OOD Angles benchmark used in the paper and result tables.
Alternatively, you can use preprocess/prepare_airfrans_eval_sampling.py to generate the AirfRANS evaluation sampling sequences locally.
python preprocess/prepare_airfrans_eval_sampling.py --tasks %TASK --subsamplings %SUBSAMPLINGwhere %TASK is one or more AirfRANS tasks selected from full, reynolds, and aoa, and %SUBSAMPLING is the number of points sampled per inference pass. Set %SUBSAMPLING to 32000 for the evaluation setting used in this project. The script reads the preprocessed datasets from ./dataset and generates the sampling files under each corresponding eval_sampling/%SUBSAMPLING/all_surface directory by default.
Note that sampling sequences generated locally may differ from those provided here due to differences in hardware and software environments, which may lead to variations in the evaluation results. To reproduce the results reported in the paper, we strongly recommend using the pre-generated evaluation sampling sequences provided above.
The pre-trained models of MoNo are available at MoNo (HuggingFace).
| Benchmark | Model | Weight Link | Log Link | Relative L2 ↓ |
|---|---|---|---|---|
| Airfoil | MoNo-Light | Download | Download | 0.0048 |
| MoNo | Download | Download | 0.0048 | |
| Pipe | MoNo-Light | Download | Download | 0.0027 |
| MoNo | Download | Download | 0.0021 | |
| Plasticity | MoNo-Light | Download | Download | 0.0010 |
| MoNo | Download | Download | 0.0006 | |
| Navier-Stokes | MoNo-Light | Download | Download | 0.0673 |
| MoNo | Download | Download | 0.0522 | |
| Elasticity | MoNo-Light | Download | Download | 0.0042 |
| MoNo | Download | Download | 0.0033 |
| Benchmark | Model | Weight Link | Log Link | Vol. ↓ | Surf. ↓ |
|---|---|---|---|---|---|
| AirfRANS (Full) | MoNo-Light | Download | Download | 0.0025 | 0.0018 |
| MoNo | Download | Download | 0.0009 | 0.0013 | |
| OOD Reynolds | MoNo-Light | Download | Download | 0.0090 | 0.0146 |
| MoNo | Download | Download | 0.0066 | 0.0121 | |
| OOD Angles | MoNo-Light | Download | Download | 0.0222 | 0.0553 |
| MoNo | Download | Download | 0.0097 | 0.0248 |
| Benchmark | Model | Weight Link | Log Link | Relative L2 ↓ |
|---|---|---|---|---|
| Darcy 85×85 | MoNo-Light | Download | Download | 0.0070 |
| MoNo | Download | Download | 0.0059 | |
| Darcy 141×141 | MoNo-Light | Download | Download | 0.0057 |
| MoNo | Download | Download | 0.0049 | |
| Darcy 211×211 | MoNo-Light | Download | Download | 0.0059 |
| MoNo | Download | Download | 0.0046 |
To reproduce the results of MoNo and MoNo-Light on all benchmarks, launch an experiment with:
python exp.py --config %CONFIG_FILEwhere %CONFIG_FILE is the path to the YAML configuration for the selected model and benchmark. The ./conf directory contains the complete configurations for all released experiments, as listed below.
| Benchmark | MoNo-Light | MoNo |
|---|---|---|
| Airfoil | mono-light_airfoil.yaml |
mono_airfoil.yaml |
| Pipe | mono-light_pipe.yaml |
mono_pipe.yaml |
| Plasticity | mono-light_plasticity.yaml |
mono_plasticity.yaml |
| Navier-Stokes | mono-light_ns2d.yaml |
mono_ns2d.yaml |
| Elasticity | mono-light_elasticity.yaml |
mono_elasticity.yaml |
| AirfRANS (Full) | mono-light_airfrans_full.yaml |
mono_airfrans_full.yaml |
| AirfRANS (OOD Reynolds) | mono-light_airfrans_reynolds.yaml |
mono_airfrans_reynolds.yaml |
| AirfRANS (OOD Angles) | mono-light_airfrans_aoa.yaml |
mono_airfrans_aoa.yaml |
| Darcy 85 | mono-light_darcy85.yaml |
mono_darcy85.yaml |
| Darcy 141 | mono-light_darcy141.yaml |
mono_darcy141.yaml |
| Darcy 211 | mono-light_darcy211.yaml |
mono_darcy211.yaml |
Training records, TensorBoard logs, checkpoints, saved arguments, and final validation metrics are written under ./outputs/<timestamp>_<experiment-name>/.
After training, exp.py automatically runs evaluation using the latest checkpoint. We do not perform any model selection.
You can also evaluate a saved experiment independently with:
python eval.py --exp_folder %EXP_FOLDERwhere %EXP_FOLDER is the experiment directory name under ./outputs or the path to a complete experiment directory. Pre-trained models downloaded from Hugging Face can be evaluated in exactly the same way by passing the local pre-trained experiment folder to %EXP_FOLDER.
By default, evaluation uses the latest numeric checkpoint. A specific epoch can instead be evaluated with --checkpoint_epoch. If an experiment contains no numeric checkpoint but provides checkpoint/last.pt, as in the released pre-trained experiments, eval.py loads last.pt automatically. Evaluation metrics are saved to <experiment>/test/res.json.
The code is released under the Apache 2.0 license as found in the LICENSE file.