Tutorial 3: How to select the best settings and advanced options

Outline

  1. Avoid large size differences between neighboring cells

  2. Controlling the uniformity of the grid

  3. Accelerating the refinement process for large 3D datasets

In this tutorial, we will learn about how to avoid large size differences between neighboring cells as encountered in the previous tutorial. Then we will look at some important parameters, which can be customized to control the topology of the grid. We will lastly see how we can use these parameters for large grids in combination with STL files for geometry objects.

In this tutorial we will again use the cylinder2D from the first tutorial since it is easy and fast to execute and publicly available for everybody.

1. Avoid large size differences between neighboring cells

For some applications, e.g., when computing gradients or in case a good resolution of the geometry has to be ensured, large size differences between two neighboring cells may cause problems. We need to ensure smooth transitions within cell sizes across the grid in these cases. \(S^3\) provides an additional argument, which can be set to ensure a max. level difference between two neighboring cells of one. The cell level refers here to the number of refinement we have to employ to get to this specific cell size.

To activate this criterion, we have to set max_delta_level=True when instantiating the s_cube object. This constraint will lead to smooth transitions, but also to longer execution times and mesh sizes, so it is recommended to only activate it when necessary.

[1]:
import sys
import torch as pt

from os import environ
from os.path import join

environ["sparseSpatialSampling"] = join("..", "..", "..")
sys.path.insert(0, environ["sparseSpatialSampling"])

from sparseSpatialSampling.export import ExportData
from sparseSpatialSampling.sparse_spatial_sampling import SparseSpatialSampling
from sparseSpatialSampling.geometry import CubeGeometry, SphereGeometry
from sparseSpatialSampling.utils import load_foam_data
Warning: TecplotDataloader can't be loaded. Most likely, the 'paraview' module is missing.
Refer to the installation instructions at https://github.com/FlowModelingControl/flowtorch
If you are not using the TecplotDataloader, ignore this warning.
[2]:
# define load paths to the CFD data, assuming they are in the top-level of the repository
load_path = join("..", "..", "..", "flowTorch_Workshop_2025", "cylinder_2D_Re100")

# define the path to where we want to save the results and the name of the file
save_path = join("..", "..", "..", "run", "tutorials", "tutorial_3")

# define boundaries of the masked domain for the cylinder, here we want to load the full domain
bounds = [[0, 0], [2.2, 0.41]]  # [[xmin, ymin], [xmax, ymax]]

# load the CFD data, we want to compute the metric based on the velocity in the quasi-steady state, so omit the first 8 seconds
field, coord, _, write_times = load_foam_data(load_path, bounds, field_name="U", t_start=8, scalar=False)
[2026-02-19 15:38:32] INFO     Loading precomputed cell centers and volumes from processor0/constant
[2026-02-19 15:38:32] INFO     Loading precomputed cell centers and volumes from processor1/constant
[3]:
# now we compute a metric. in this case, we just use the temporal mean of the abs. velocity vector
metric = pt.mean(field.abs().sum(1), 1)

# create geometry objects for the domain and the cylinder
# we don't want to refine the domain boundaries, so keep all the optional arguments as default
domain = CubeGeometry("domain", True, bounds[0], bounds[1])

# we explicitly increase the resolution of the cylinder to cause large level differences when the constraint is not activated
geometry = SphereGeometry("cylinder", False, [0.2, 0.2], 0.05, refine=True, min_refinement_level=12)
[4]:
# now we artificially create poor grid containing large level differences
s_cube = SparseSpatialSampling(coord, metric, [domain, geometry], save_path, "cylinder2D_nodeltaLevel_constraint", "cylinder2D",
                               min_metric=0.5, n_jobs=4)
s_cube.execute_grid_generation()

# export only the last time step for demonstration purposes
export = ExportData(s_cube, write_times="10")
export.export(coord, field[:, :, -1].unsqueeze(-1), "U")
[2026-02-19 15:38:33] INFO     Selecting min. approximation of the metric as stopping criterion.
[2026-02-19 15:38:33] INFO
        Selected settings:
                pre_select           :  False
                n_jobs               :  4
                max_delta_level      :  False
                geometry             :  ['domain', 'cylinder']
                min_metric           :  0.5
                min_level            :  5
                cells_per_iter_start :  9
                cells_per_iter_end   :  9
                cells_per_iter       :  9
                cells_per_iter_last  :  1000000000.0
                reach_at_least       :  0.75
                n_dimensions         :  2
                n_cells_orig         :  9800
                relTol               :  0.001
[2026-02-19 15:38:33] INFO     Starting grid generation.
[2026-02-19 15:38:33] INFO     Starting uniform refinement.
        Starting iteration no. 0, N_cells = 1
Warning: TecplotDataloader can't be loaded. Most likely, the 'paraview' module is missing.
Refer to the installation instructions at https://github.com/FlowModelingControl/flowtorch
If you are not using the TecplotDataloader, ignore this warning.
Warning: TecplotDataloader can't be loaded. Most likely, the 'paraview' module is missing.
Refer to the installation instructions at https://github.com/FlowModelingControl/flowtorch
If you are not using the TecplotDataloader, ignore this warning.
Warning: TecplotDataloader can't be loaded. Most likely, the 'paraview' module is missing.
Refer to the installation instructions at https://github.com/FlowModelingControl/flowtorch
If you are not using the TecplotDataloader, ignore this warning.
Warning: TecplotDataloader can't be loaded. Most likely, the 'paraview' module is missing.
Refer to the installation instructions at https://github.com/FlowModelingControl/flowtorch
If you are not using the TecplotDataloader, ignore this warning.
        Starting iteration no. 1, N_cells = 4
        Starting iteration no. 2, N_cells = 8
        Starting iteration no. 3, N_cells = 16
        Starting iteration no. 4, N_cells = 64
[2026-02-19 15:38:38] INFO     Finished uniform refinement.
[2026-02-19 15:38:38] INFO     Starting metric-based refinement.
        Starting iteration no. 0, captured metric: 13.64 %, N_cells = 192
        Starting iteration no. 1, captured metric: 14.5 %, N_cells = 217
        Starting iteration no. 2, captured metric: 15.03 %, N_cells = 244
        Starting iteration no. 3, captured metric: 15.55 %, N_cells = 271
        Starting iteration no. 4, captured metric: 16.13 %, N_cells = 298
        Starting iteration no. 5, captured metric: 16.37 %, N_cells = 325
        Starting iteration no. 6, captured metric: 16.52 %, N_cells = 352
        Starting iteration no. 7, captured metric: 16.65 %, N_cells = 379
        Starting iteration no. 8, captured metric: 16.9 %, N_cells = 406
        Starting iteration no. 9, captured metric: 17.45 %, N_cells = 433
        Starting iteration no. 10, captured metric: 18.37 %, N_cells = 459
        Starting iteration no. 11, captured metric: 18.99 %, N_cells = 486
        Starting iteration no. 12, captured metric: 19.58 %, N_cells = 513
        Starting iteration no. 13, captured metric: 20.31 %, N_cells = 540
        Starting iteration no. 14, captured metric: 21.01 %, N_cells = 567
        Starting iteration no. 15, captured metric: 21.71 %, N_cells = 594
        Starting iteration no. 16, captured metric: 22.66 %, N_cells = 621
        Starting iteration no. 17, captured metric: 23.54 %, N_cells = 648
        Starting iteration no. 18, captured metric: 24.35 %, N_cells = 674
        Starting iteration no. 19, captured metric: 25.03 %, N_cells = 701
        Starting iteration no. 20, captured metric: 25.58 %, N_cells = 728
        Starting iteration no. 21, captured metric: 26.14 %, N_cells = 755
        Starting iteration no. 22, captured metric: 26.75 %, N_cells = 782
        Starting iteration no. 23, captured metric: 27.54 %, N_cells = 809
        Starting iteration no. 24, captured metric: 27.94 %, N_cells = 836
        Starting iteration no. 25, captured metric: 28.2 %, N_cells = 863
        Starting iteration no. 26, captured metric: 28.54 %, N_cells = 890
        Starting iteration no. 27, captured metric: 28.97 %, N_cells = 917
        Starting iteration no. 28, captured metric: 29.42 %, N_cells = 944
        Starting iteration no. 29, captured metric: 29.78 %, N_cells = 971
        Starting iteration no. 30, captured metric: 30.16 %, N_cells = 998
        Starting iteration no. 31, captured metric: 30.78 %, N_cells = 1025
        Starting iteration no. 32, captured metric: 31.05 %, N_cells = 1052
        Starting iteration no. 33, captured metric: 31.18 %, N_cells = 1079
        Starting iteration no. 34, captured metric: 31.5 %, N_cells = 1106
        Starting iteration no. 35, captured metric: 31.74 %, N_cells = 1133
        Starting iteration no. 36, captured metric: 32.06 %, N_cells = 1160
        Starting iteration no. 37, captured metric: 32.36 %, N_cells = 1187
        Starting iteration no. 38, captured metric: 32.66 %, N_cells = 1214
        Starting iteration no. 39, captured metric: 32.76 %, N_cells = 1241
        Starting iteration no. 40, captured metric: 32.79 %, N_cells = 1268
        Starting iteration no. 41, captured metric: 32.93 %, N_cells = 1295
        Starting iteration no. 42, captured metric: 33.13 %, N_cells = 1322
        Starting iteration no. 43, captured metric: 33.47 %, N_cells = 1349
        Starting iteration no. 44, captured metric: 33.61 %, N_cells = 1376
        Starting iteration no. 45, captured metric: 33.93 %, N_cells = 1403
        Starting iteration no. 46, captured metric: 34.09 %, N_cells = 1430
        Starting iteration no. 47, captured metric: 34.18 %, N_cells = 1457
        Starting iteration no. 48, captured metric: 34.44 %, N_cells = 1484
        Starting iteration no. 49, captured metric: 34.57 %, N_cells = 1511
        Starting iteration no. 50, captured metric: 34.72 %, N_cells = 1538
        Starting iteration no. 51, captured metric: 35.12 %, N_cells = 1565
        Starting iteration no. 52, captured metric: 35.46 %, N_cells = 1592
        Starting iteration no. 53, captured metric: 35.7 %, N_cells = 1619
        Starting iteration no. 54, captured metric: 35.94 %, N_cells = 1646
        Starting iteration no. 55, captured metric: 36.14 %, N_cells = 1673
        Starting iteration no. 56, captured metric: 36.28 %, N_cells = 1700
        Starting iteration no. 57, captured metric: 36.52 %, N_cells = 1727
        Starting iteration no. 58, captured metric: 36.85 %, N_cells = 1754
        Starting iteration no. 59, captured metric: 37.1 %, N_cells = 1781
        Starting iteration no. 60, captured metric: 37.4 %, N_cells = 1808
        Starting iteration no. 61, captured metric: 37.75 %, N_cells = 1835
        Starting iteration no. 62, captured metric: 38.0 %, N_cells = 1862
        Starting iteration no. 63, captured metric: 38.21 %, N_cells = 1889
        Starting iteration no. 64, captured metric: 38.51 %, N_cells = 1916
        Starting iteration no. 65, captured metric: 38.85 %, N_cells = 1943
        Starting iteration no. 66, captured metric: 39.13 %, N_cells = 1970
        Starting iteration no. 67, captured metric: 39.34 %, N_cells = 1997
        Starting iteration no. 68, captured metric: 39.8 %, N_cells = 2024
        Starting iteration no. 69, captured metric: 40.03 %, N_cells = 2051
        Starting iteration no. 70, captured metric: 40.27 %, N_cells = 2078
        Starting iteration no. 71, captured metric: 40.59 %, N_cells = 2105
        Starting iteration no. 72, captured metric: 40.92 %, N_cells = 2132
        Starting iteration no. 73, captured metric: 41.27 %, N_cells = 2159
        Starting iteration no. 74, captured metric: 41.63 %, N_cells = 2186
        Starting iteration no. 75, captured metric: 41.94 %, N_cells = 2212
        Starting iteration no. 76, captured metric: 42.3 %, N_cells = 2239
        Starting iteration no. 77, captured metric: 42.7 %, N_cells = 2266
        Starting iteration no. 78, captured metric: 43.05 %, N_cells = 2293
        Starting iteration no. 79, captured metric: 43.43 %, N_cells = 2320
        Starting iteration no. 80, captured metric: 43.71 %, N_cells = 2347
        Starting iteration no. 81, captured metric: 44.12 %, N_cells = 2374
        Starting iteration no. 82, captured metric: 44.52 %, N_cells = 2401
        Starting iteration no. 83, captured metric: 44.81 %, N_cells = 2428
        Starting iteration no. 84, captured metric: 45.19 %, N_cells = 2455
        Starting iteration no. 85, captured metric: 45.59 %, N_cells = 2482
        Starting iteration no. 86, captured metric: 46.0 %, N_cells = 2509
        Starting iteration no. 87, captured metric: 46.38 %, N_cells = 2536
        Starting iteration no. 88, captured metric: 46.73 %, N_cells = 2563
        Starting iteration no. 89, captured metric: 47.13 %, N_cells = 2590
        Starting iteration no. 90, captured metric: 47.54 %, N_cells = 2617
        Starting iteration no. 91, captured metric: 47.91 %, N_cells = 2644
        Starting iteration no. 92, captured metric: 48.3 %, N_cells = 2671
        Starting iteration no. 93, captured metric: 48.57 %, N_cells = 2698
        Starting iteration no. 94, captured metric: 48.92 %, N_cells = 2725
        Starting iteration no. 95, captured metric: 49.24 %, N_cells = 2752
        Starting iteration no. 96, captured metric: 49.51 %, N_cells = 2779
        Starting iteration no. 97, captured metric: 49.73 %, N_cells = 2806
        Starting iteration no. 98, captured metric: 49.83 %, N_cells = 2831
[2026-02-19 15:38:43] INFO     Finished metric-based refinement.
[2026-02-19 15:38:43] INFO     Starting geometry refinement.
[2026-02-19 15:38:43] INFO     Starting refining geometry cylinder.
[2026-02-19 15:38:43] INFO     Found a minimum cell level of 6. Target level is 12.
                                                                        Refining level 7 / 12.
                                                                        Refining level 8 / 12.
                                                                        Refining level 9 / 12.
                                                                        Refining level 10 / 12.
                                                                        Refining level 11 / 12.
                                                                        Refining level 12 / 12.
[2026-02-19 15:38:44] INFO     Finished geometry refinement.
[2026-02-19 15:38:44] INFO     Starting renumbering final mesh.
[2026-02-19 15:38:47] INFO     Finished refinement in 14.5280 s
                                                                (99 iterations).
                                                                Time for uniform refinement: 5.4432 s
                                                                Time for metric-based refinement: 4.8844 s
                                                                Time for geometry refinement: 1.0879 s
                                                                Time for renumbering the final mesh: 3.0965 s

                                    Number of cells: 4301
                                    Minimum ref. level: 6
                                    Maximum ref. level: 12
                                    Captured metric of original grid: 50.06 %

[2026-02-19 15:38:47] INFO     Initializing KNN and computing interpolation weights.
[2026-02-19 15:38:47] INFO     Starting interpolation and export of field U.
[2026-02-19 15:38:47] INFO     Writing HDF5 file for field U.
[2026-02-19 15:38:47] INFO     Writing XDMF file for file cylinder2D_nodeltaLevel_constraint.h5
[2026-02-19 15:38:47] INFO     Finished export of field U in 0.039s.
[5]:
# now we activate the max_delta_level constraint to see how the grid quality improves
s_cube = SparseSpatialSampling(coord, metric, [domain, geometry], save_path, "cylinder2D_deltaLevel_constraint", "cylinder2D",
                               min_metric=0.5, n_jobs=4, max_delta_level=True)
s_cube.execute_grid_generation()

export = ExportData(s_cube, write_times="10")
export.export(coord, field[:, :, -1].unsqueeze(-1), "U")
[2026-02-19 15:38:47] INFO     Selecting min. approximation of the metric as stopping criterion.
[2026-02-19 15:38:47] INFO
        Selected settings:
                pre_select           :  False
                n_jobs               :  4
                max_delta_level      :  True
                geometry             :  ['domain', 'cylinder']
                min_metric           :  0.5
                min_level            :  5
                cells_per_iter_start :  9
                cells_per_iter_end   :  9
                cells_per_iter       :  9
                cells_per_iter_last  :  1000000000.0
                reach_at_least       :  0.75
                n_dimensions         :  2
                n_cells_orig         :  9800
                relTol               :  0.001
[2026-02-19 15:38:47] INFO     Starting grid generation.
[2026-02-19 15:38:47] INFO     Starting uniform refinement.
        Starting iteration no. 0, N_cells = 1
Warning: TecplotDataloader can't be loaded. Most likely, the 'paraview' module is missing.
Refer to the installation instructions at https://github.com/FlowModelingControl/flowtorch
If you are not using the TecplotDataloader, ignore this warning.
Warning: TecplotDataloader can't be loaded. Most likely, the 'paraview' module is missing.
Refer to the installation instructions at https://github.com/FlowModelingControl/flowtorch
If you are not using the TecplotDataloader, ignore this warning.Warning: TecplotDataloader can't be loaded. Most likely, the 'paraview' module is missing.
Refer to the installation instructions at https://github.com/FlowModelingControl/flowtorch
If you are not using the TecplotDataloader, ignore this warning.

Warning: TecplotDataloader can't be loaded. Most likely, the 'paraview' module is missing.
Refer to the installation instructions at https://github.com/FlowModelingControl/flowtorch
If you are not using the TecplotDataloader, ignore this warning.
        Starting iteration no. 1, N_cells = 4
        Starting iteration no. 2, N_cells = 8
        Starting iteration no. 3, N_cells = 16
        Starting iteration no. 4, N_cells = 64
[2026-02-19 15:38:53] INFO     Finished uniform refinement.
[2026-02-19 15:38:53] INFO     Starting metric-based refinement.
        Starting iteration no. 0, captured metric: 13.64 %, N_cells = 192
        Starting iteration no. 1, captured metric: 14.5 %, N_cells = 217
        Starting iteration no. 2, captured metric: 15.03 %, N_cells = 244
        Starting iteration no. 3, captured metric: 15.55 %, N_cells = 271
        Starting iteration no. 4, captured metric: 16.37 %, N_cells = 301
        Starting iteration no. 5, captured metric: 16.61 %, N_cells = 328
        Starting iteration no. 6, captured metric: 16.75 %, N_cells = 355
        Starting iteration no. 7, captured metric: 16.89 %, N_cells = 382
        Starting iteration no. 8, captured metric: 17.13 %, N_cells = 409
        Starting iteration no. 9, captured metric: 17.68 %, N_cells = 436
        Starting iteration no. 10, captured metric: 18.44 %, N_cells = 465
        Starting iteration no. 11, captured metric: 19.06 %, N_cells = 492
        Starting iteration no. 12, captured metric: 19.65 %, N_cells = 519
        Starting iteration no. 13, captured metric: 20.38 %, N_cells = 546
        Starting iteration no. 14, captured metric: 21.07 %, N_cells = 573
        Starting iteration no. 15, captured metric: 21.89 %, N_cells = 603
        Starting iteration no. 16, captured metric: 22.9 %, N_cells = 630
        Starting iteration no. 17, captured metric: 23.77 %, N_cells = 657
        Starting iteration no. 18, captured metric: 24.46 %, N_cells = 683
        Starting iteration no. 19, captured metric: 25.12 %, N_cells = 710
        Starting iteration no. 20, captured metric: 25.82 %, N_cells = 737
        Starting iteration no. 21, captured metric: 26.35 %, N_cells = 764
        Starting iteration no. 22, captured metric: 27.03 %, N_cells = 791
        Starting iteration no. 23, captured metric: 27.69 %, N_cells = 818
        Starting iteration no. 24, captured metric: 27.99 %, N_cells = 845
        Starting iteration no. 25, captured metric: 28.35 %, N_cells = 872
        Starting iteration no. 26, captured metric: 28.74 %, N_cells = 899
        Starting iteration no. 27, captured metric: 29.16 %, N_cells = 926
        Starting iteration no. 28, captured metric: 29.71 %, N_cells = 956
        Starting iteration no. 29, captured metric: 30.24 %, N_cells = 983
        Starting iteration no. 30, captured metric: 30.81 %, N_cells = 1013
        Starting iteration no. 31, captured metric: 31.25 %, N_cells = 1040
        Starting iteration no. 32, captured metric: 31.46 %, N_cells = 1067
        Starting iteration no. 33, captured metric: 31.52 %, N_cells = 1094
        Starting iteration no. 34, captured metric: 31.7 %, N_cells = 1121
        Starting iteration no. 35, captured metric: 32.11 %, N_cells = 1148
        Starting iteration no. 36, captured metric: 32.36 %, N_cells = 1175
        Starting iteration no. 37, captured metric: 32.56 %, N_cells = 1202
        Starting iteration no. 38, captured metric: 32.67 %, N_cells = 1229
        Starting iteration no. 39, captured metric: 32.77 %, N_cells = 1256
        Starting iteration no. 40, captured metric: 32.83 %, N_cells = 1283
        Starting iteration no. 41, captured metric: 33.26 %, N_cells = 1313
        Starting iteration no. 42, captured metric: 33.34 %, N_cells = 1340
        Starting iteration no. 43, captured metric: 33.65 %, N_cells = 1367
        Starting iteration no. 44, captured metric: 33.93 %, N_cells = 1394
        Starting iteration no. 45, captured metric: 34.12 %, N_cells = 1421
        Starting iteration no. 46, captured metric: 34.27 %, N_cells = 1448
        Starting iteration no. 47, captured metric: 34.38 %, N_cells = 1475
        Starting iteration no. 48, captured metric: 34.66 %, N_cells = 1502
        Starting iteration no. 49, captured metric: 34.82 %, N_cells = 1529
        Starting iteration no. 50, captured metric: 35.04 %, N_cells = 1556
        Starting iteration no. 51, captured metric: 35.39 %, N_cells = 1583
        Starting iteration no. 52, captured metric: 35.74 %, N_cells = 1610
        Starting iteration no. 53, captured metric: 35.92 %, N_cells = 1637
        Starting iteration no. 54, captured metric: 36.11 %, N_cells = 1664
        Starting iteration no. 55, captured metric: 36.27 %, N_cells = 1691
        Starting iteration no. 56, captured metric: 36.42 %, N_cells = 1718
        Starting iteration no. 57, captured metric: 36.68 %, N_cells = 1745
        Starting iteration no. 58, captured metric: 37.05 %, N_cells = 1772
        Starting iteration no. 59, captured metric: 37.33 %, N_cells = 1799
        Starting iteration no. 60, captured metric: 37.62 %, N_cells = 1826
        Starting iteration no. 61, captured metric: 37.91 %, N_cells = 1853
        Starting iteration no. 62, captured metric: 38.12 %, N_cells = 1880
        Starting iteration no. 63, captured metric: 38.46 %, N_cells = 1907
        Starting iteration no. 64, captured metric: 38.71 %, N_cells = 1934
        Starting iteration no. 65, captured metric: 39.07 %, N_cells = 1961
        Starting iteration no. 66, captured metric: 39.23 %, N_cells = 1988
        Starting iteration no. 67, captured metric: 39.72 %, N_cells = 2015
        Starting iteration no. 68, captured metric: 39.95 %, N_cells = 2042
        Starting iteration no. 69, captured metric: 40.17 %, N_cells = 2069
        Starting iteration no. 70, captured metric: 40.48 %, N_cells = 2096
        Starting iteration no. 71, captured metric: 40.84 %, N_cells = 2123
        Starting iteration no. 72, captured metric: 41.15 %, N_cells = 2150
        Starting iteration no. 73, captured metric: 41.5 %, N_cells = 2177
        Starting iteration no. 74, captured metric: 41.86 %, N_cells = 2204
        Starting iteration no. 75, captured metric: 42.17 %, N_cells = 2230
        Starting iteration no. 76, captured metric: 42.59 %, N_cells = 2257
        Starting iteration no. 77, captured metric: 42.94 %, N_cells = 2284
        Starting iteration no. 78, captured metric: 43.3 %, N_cells = 2311
        Starting iteration no. 79, captured metric: 43.63 %, N_cells = 2338
        Starting iteration no. 80, captured metric: 44.03 %, N_cells = 2365
        Starting iteration no. 81, captured metric: 44.38 %, N_cells = 2392
        Starting iteration no. 82, captured metric: 44.69 %, N_cells = 2419
        Starting iteration no. 83, captured metric: 45.06 %, N_cells = 2446
        Starting iteration no. 84, captured metric: 45.45 %, N_cells = 2473
        Starting iteration no. 85, captured metric: 45.86 %, N_cells = 2500
        Starting iteration no. 86, captured metric: 46.3 %, N_cells = 2527
        Starting iteration no. 87, captured metric: 46.61 %, N_cells = 2554
        Starting iteration no. 88, captured metric: 47.02 %, N_cells = 2581
        Starting iteration no. 89, captured metric: 47.41 %, N_cells = 2608
        Starting iteration no. 90, captured metric: 47.77 %, N_cells = 2635
        Starting iteration no. 91, captured metric: 48.18 %, N_cells = 2662
        Starting iteration no. 92, captured metric: 48.51 %, N_cells = 2689
        Starting iteration no. 93, captured metric: 48.83 %, N_cells = 2716
        Starting iteration no. 94, captured metric: 49.14 %, N_cells = 2743
        Starting iteration no. 95, captured metric: 49.39 %, N_cells = 2770
        Starting iteration no. 96, captured metric: 49.62 %, N_cells = 2797
        Starting iteration no. 97, captured metric: 49.79 %, N_cells = 2822
        Starting iteration no. 98, captured metric: 49.96 %, N_cells = 2849
[2026-02-19 15:38:58] INFO     Finished metric-based refinement.
[2026-02-19 15:38:58] INFO     Starting geometry refinement.
[2026-02-19 15:38:58] INFO     Starting refining geometry cylinder.
[2026-02-19 15:38:58] INFO     Found a minimum cell level of 6. Target level is 12.
                                                                        Refining level 7 / 12.
                                                                        Refining level 8 / 12.
                                                                        Refining level 9 / 12.
                                                                        Refining level 10 / 12.
                                                                        Refining level 11 / 12.
                                                                        Refining level 12 / 12.
[2026-02-19 15:38:59] INFO     Finished geometry refinement.
[2026-02-19 15:38:59] INFO     Starting renumbering final mesh.
[2026-02-19 15:38:59] INFO     Finished refinement in 11.5554 s
                                                                (99 iterations).
                                                                Time for uniform refinement: 5.0861 s
                                                                Time for metric-based refinement: 5.0659 s
                                                                Time for geometry refinement: 1.3162 s
                                                                Time for renumbering the final mesh: 0.0720 s

                                    Number of cells: 5891
                                    Minimum ref. level: 6
                                    Maximum ref. level: 12
                                    Captured metric of original grid: 50.18 %

[2026-02-19 15:38:59] INFO     Initializing KNN and computing interpolation weights.
[2026-02-19 15:38:59] INFO     Starting interpolation and export of field U.
[2026-02-19 15:38:59] INFO     Writing HDF5 file for field U.
[2026-02-19 15:38:59] INFO     Writing XDMF file for file cylinder2D_deltaLevel_constraint.h5
[2026-02-19 15:38:59] INFO     Finished export of field U in 0.041s.

As already discussed in the introduction, we can see that the number of cells increased from \(4301\) to \(5891\) when activating the constraint. Now let’s load the data into ParaView and compare the grids.

First we take a look at the grid without the constraint:

grid_noDeltaLevel_constraint.png

Here, we can already see large level differences at the domain boundaries and near the cylinder. We can zoom in the region near the cylinder to see it better:

grid_noDeltaLevel_constraint_zoomed.png

As explained, these differences within the cell size can cause problems, e.g. when computing gradients on that grid. As a comparison we can now take a look athe the grid which was created with the delta level constraint:

grid_withDeltaLevel_constraint.png

When we zoom in the same region as before we can see that the grid quality improved significantly:

grid_deltaLevel_constraint_zoomed.png

2. Controlling the uniformity of the grid

The next parameter we want to look at is uniform_levels, which controls the number of uniform grid levels. \(S^3\) starts by creating a uniform background grid before starting the adaptive refinement in order to accelerate the grid generation process.

A rule of thumb is: when increasing the number uniform levels, the grid will become more uniform but the execution time decreases and vice versa. In general it is only sensible to adjust this parameter if the grid is expected to be very coarse (then uniform_levels has to be decreased), or if the number of grid levels is expected to be large. In the latter case, the number of uniform levels can be increased.

Since this parameter is quite intuitive, we will briefly show what happens if it gets increased in the following.

[6]:
# execute for higher n_uniform levels
# The default is 5 uniform levels, but the min_level is already 6 so we don't expect the grid to be adaptive
s_cube = SparseSpatialSampling(coord, metric, [domain, geometry], save_path, "cylinder2D_6_uniform_levels", "cylinder2D",
                               min_metric=0.5, n_jobs=4, uniform_levels=7)
s_cube.execute_grid_generation()

# export
export = ExportData(s_cube, write_times="10")
export.export(coord, field[:, :, -1].unsqueeze(-1), "U")
[2026-02-19 15:38:59] INFO     Selecting min. approximation of the metric as stopping criterion.
[2026-02-19 15:38:59] INFO
        Selected settings:
                pre_select           :  False
                n_jobs               :  4
                max_delta_level      :  False
                geometry             :  ['domain', 'cylinder']
                min_metric           :  0.5
                min_level            :  7
                cells_per_iter_start :  9
                cells_per_iter_end   :  9
                cells_per_iter       :  9
                cells_per_iter_last  :  1000000000.0
                reach_at_least       :  0.75
                n_dimensions         :  2
                n_cells_orig         :  9800
                relTol               :  0.001
[2026-02-19 15:38:59] INFO     Starting grid generation.
[2026-02-19 15:38:59] INFO     Starting uniform refinement.
        Starting iteration no. 0, N_cells = 1
Warning: TecplotDataloader can't be loaded. Most likely, the 'paraview' module is missing.
Refer to the installation instructions at https://github.com/FlowModelingControl/flowtorch
If you are not using the TecplotDataloader, ignore this warning.
Warning: TecplotDataloader can't be loaded. Most likely, the 'paraview' module is missing.
Refer to the installation instructions at https://github.com/FlowModelingControl/flowtorch
If you are not using the TecplotDataloader, ignore this warning.
Warning: TecplotDataloader can't be loaded. Most likely, the 'paraview' module is missing.
Refer to the installation instructions at https://github.com/FlowModelingControl/flowtorch
If you are not using the TecplotDataloader, ignore this warning.
Warning: TecplotDataloader can't be loaded. Most likely, the 'paraview' module is missing.
Refer to the installation instructions at https://github.com/FlowModelingControl/flowtorch
If you are not using the TecplotDataloader, ignore this warning.
        Starting iteration no. 1, N_cells = 4
        Starting iteration no. 2, N_cells = 8
        Starting iteration no. 3, N_cells = 16
        Starting iteration no. 4, N_cells = 64
        Starting iteration no. 5, N_cells = 192
        Starting iteration no. 6, N_cells = 766
[2026-02-19 15:39:05] INFO     Finished uniform refinement.
[2026-02-19 15:39:05] INFO     Starting metric-based refinement.
        Starting iteration no. 0, captured metric: 54.73 %, N_cells = 3056
[2026-02-19 15:39:05] INFO     Finished metric-based refinement.
[2026-02-19 15:39:05] INFO     Starting geometry refinement.
[2026-02-19 15:39:05] INFO     Starting refining geometry cylinder.
[2026-02-19 15:39:05] INFO     Found a minimum cell level of 7. Target level is 12.
                                                                        Refining level 8 / 12.
                                                                        Refining level 9 / 12.
                                                                        Refining level 10 / 12.
                                                                        Refining level 11 / 12.
                                                                        Refining level 12 / 12.
[2026-02-19 15:39:06] INFO     Finished geometry refinement.
[2026-02-19 15:39:06] INFO     Starting renumbering final mesh.
[2026-02-19 15:39:06] INFO     Finished refinement in 7.1241 s
                                                                (1 iterations).
                                                                Time for uniform refinement: 6.0477 s
                                                                Time for metric-based refinement: 0.0646 s
                                                                Time for geometry refinement: 0.8870 s
                                                                Time for renumbering the final mesh: 0.1054 s

                                    Number of cells: 4538
                                    Minimum ref. level: 7
                                    Maximum ref. level: 12
                                    Captured metric of original grid: 55.06 %

[2026-02-19 15:39:06] INFO     Initializing KNN and computing interpolation weights.
[2026-02-19 15:39:06] INFO     Starting interpolation and export of field U.
[2026-02-19 15:39:06] INFO     Writing HDF5 file for field U.
[2026-02-19 15:39:06] INFO     Writing XDMF file for file cylinder2D_6_uniform_levels.h5
[2026-02-19 15:39:06] INFO     Finished export of field U in 0.041s.

As we expected, the resulting grid is much more uniform than the grid using the default value of uniform_levels=5:

grid_7uniformLevels.png

This happens because our grid using uniform_levels=5 has a minimum refinement level of \(6\). So if we increase uniform_levelsto \(7\) the adaptive refinement is never activated.

3. Accelerating the refinement process for large 3D datasets

For large grids and in case STL file(s) are used as geometry objects, there are three more parameters which we can adjust in order to accelerate the refienment process. However, since our cylinder2D test case is too simple to see an actual effect, we will just explain the usage of these parameters briefly in the following.

The first two parameters are n_cells_iter_start and n_cells_iter_end. These parameters control how many cells are generated each iteration. By default n_cells_iter_start=0.001 n_cells_original_grid with n_cells_original_grid denoting the number of cells in the mesh from the simulation and n_cells_iter_end = n_cells_iter_start. Each iteration, the number of cells to refine is computed based on properties of the current grid.

When increasing n_cells_iter_start and/or n_cells_iter_end, this leads to generating more cells per iteration and therefore a more uniform grid. Decreasing them analogously leads to a more adaptive grid, however, it also increases the runtime of \(S^3\). In general, these parameters have a more complex influence on the runtime and resulting grid than, e.g., uniform_levels, so usually it should be avoided to modify them. But it may be helpful in some special cases.

The last parameter is pre_select, which is useful when STL files are used as geometry objects. Especially if the expected number of grid points is large and the STL file has a high resolution (contains many points). To accelerate the grid generation, the class GeometrySTL3D provides an additional parameter reduce_by, which compresses the STL file by \(x\%\). The optimal compression ratio depends on the application, but values up to reduce_by=0.9 generally shouldn’t cause any problems. If that is still not able to decrease the required runtime significantly, the parameter pre_selectcan be set to True when instantiating the s_cube object. Since this parameter determines possible cells in the vicinity of the geometry much faster than the ‘standard’ way when dealing with STL files, this can significantly accelerate the refinement process.

Note: The parameter pre_select works best if the edges of a box drawn around the STL file have nearly the same length, meaning that the shape of the STL file is nearly cubic. For STL files which have a dominant length, e.g. aircraft with high aspect ratio wings, setting pre_select=True may even increase the required runtime!

This concludes the third tutorial. The next tutorial presents different options when exporting the data to HDF5.

[6]: