Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Mailler une géométrie

Cette page est un guide de choix, pas une référence : elle compare les mailleurs entre eux et dit lequel prendre. La description de chaque opérateur, ses arguments et ses pièges vivent dans Opérateurs → Maillage.

La partie 3D viendra plus tard ; seul le 2D est traité ici.

Mailler en 2D

Quatre opérateurs remplissent l’intérieur d’un contour fermé. Ils prennent tous la même chose — un ou plusieurs contours orientés en SEG2 et une taille de maille visée — et rendent tous un maillage dont le bord est le contour, nœuds compris.

opérateurméthodetypes et optionsrend
triangulate_surfaceDelaunay contraint + raffinement de Ruppert"TRI3", "QUA4" ; sizedes TRI3 — en QUA4, des quadrangles et quelques triangles
pave_surfacefront avançant, en rangées depuis le bord"QUA4", "QUA8", "QUA9" ; size, prefer_quads, relaxdes QUA4, quelques TRI3
grid_surfacecœur en grille + bande frontale au bord"QUA4", "QUA8", "QUA9" ; size, band, prefer_quads, relaxdes QUA4, quelques TRI3
grid_surface2cœur en grille, une ligne par nœud du contour, + bande frontale au bord"QUA4", "QUA8", "QUA9" ; size, band, prefer_quads, relaxdes QUA4, quelques TRI3

Le premier argument est le contour, le deuxième le type d’élément. Les options :

  • size — la taille de maille visée ; sans elle, la longueur moyenne des arêtes du contour, domaine par domaine ;
  • prefer_quads (défaut False) — True refuse une boucle au nombre impair de segments, qu’aucun pavage en quadrangles ne remplit, puis tient le front pair jusqu’au bout. Moins de triangles, mais pas aucun : la fermeture en pose encore là où un quadrangle serait retourné. C’est une préférence, pas une garantie ;
  • relax (défaut "free") — ce que le front s’autorise entre deux rangées : "free", "along" ou "none" (voir plus bas) ;
  • band (défaut 0) — une marge, en mailles, entre le cœur en grille et le contour ; zéro est la valeur utile, à relever seulement pour un contour que la grille ne peut pas rejoindre, comme une courbe.

Comment lire les figures

Chaque figure montre le même contour maillé quatre fois. Il est construit une seule fois, puis dupliqué par translate : aucun mailleur ne bénéficie d’une discrétisation de bord différente des autres. La disposition ne change jamais — en haut triangulate_surface et pave_surface, en bas grid_surface et grid_surface2. Le contour est en bleu et ses nœuds en rouge.

Les figures et les chiffres de cette page sortent d’un seul script, examples/comparer_mailleurs_2d.py.

La qualité citée est la mean ratio du pire coin : 1 pour un coin droit à côtés égaux, 0 pour un coin plat, négatif pour une maille retournée. C’est la même mesure pour les triangles et pour les quadrangles, ce qui est la seule façon de comparer les quatre sur un pied d’égalité. On donne aussi le 5ᵉ centile, qui dit ce que valent les mailles médiocres et non la seule plus mauvaise.

En pratique cette mesure ne descend jamais à zéro dans les tableaux qui suivent, et ce n’est pas une chance : les quatre mailleurs refusent de rendre un maillage portant une maille retournée ou plate. Une telle maille a un jacobien négatif ou nul, qu’aucun code éléments finis n’intègre — ce n’est pas un maillage médiocre mais un maillage faux, et mieux vaut une erreur qui situe la maille fautive. Un mailleur qui échoue là où un autre passe est donc un résultat en soi, à lire dans les tableaux comme tel.

Une forme rectilinéaire posée sur la grille

C’est le cas le plus favorable aux mailleurs en grille, et la différence est franche.

formetriangulatepavegridgrid2
rectangle 1 × 0,63mailles286966060
pire0,4250,3890,9990,999
plaque, marche sur la grillemailles3941248080
pire0,4890,6691,0001,000

Les deux mailleurs en grille rendent le maillage qu’on dessinerait à la main : toutes les mailles sont des rectangles et il n’y a pas un seul triangle. Le paveur, lui, rend une pelure d’oignon dont les rangées se referment sur une ligne médiane, avec deux petites zones de fermeture à ses bouts — sa faiblesse est là où ses rangées se referment, et cette fermeture existe même sur un rectangle.

Une forme rectilinéaire qui ne tombe pas sur la grille

Dès que les cotes ne sont plus des multiples de la taille visée, grid_surface et grid_surface2 se séparent nettement.

formetriangulatepavegridgrid2
plaque à marche (0,53 ; 0,61)mailles3661308680
pire0,4810,5710,4050,963
L à cotes quelconquesmailles3081117670
pire0,4590,6800,4370,979
L étiré à 1,02mailles3191078174
pire0,4770,6390,3070,606
L étiré à 1,10mailles3361128074
pire0,4740,6490,4210,963

grid_surface pose une ligne sur la coordonnée où repose chaque côté aligné, puis découpe entre deux lignes d’après le côté qui les enjambe : toutes ses lignes sont droites. grid_surface2 donne à chaque nœud du contour la ligne qui le traverse et laisse ses rangées plier pour aller chercher le contour — une même rangée peut alors rejoindre deux parois qui se font face à deux hauteurs différentes, ce qu’aucune droite ne sait faire.

Le L étiré à 1,02 est le seul de la série que grid_surface2 ne règle pas — le paveur y fait mieux : les deux côtés y posent un nombre de nœuds différent sur la même portée, dix contre onze, et aucune disposition de lignes n’invente la rangée manquante. Le remède est dans le contour, pas dans le mailleur — voir la règle de discrétisation.

Un profil à sept angles rentrants

Le profil crénelé est décliné en deux versions dont seule la base change : coupée sous chaque barre, ou d’un seul tenant. C’est le meilleur révélateur de la sensibilité d’un mailleur à la discrétisation du contour.

formetriangulatepavegridgrid2
base coupéemailles2 050816456456
pire0,4120,1180,8600,916
base d’un seul tenantmailles2 089827471456
pire0,4190,4150,2870,651

grid_surface2 rend exactement le même nombre de mailles dans les deux cas. Les trois autres paient la base d’un seul tenant. C’est la propriété la plus utile de ce mailleur : il pardonne une discrétisation de contour que les autres font payer.

Une forme oblique ou courbe

Ici le classement s’inverse, et c’est le seul endroit où il le fait.

formetriangulatepavegridgrid2
maisonmailles1 723611447450
pire0,4840,5150,3650,548
carré arrondimailles1 866665418404
pire0,4740,3600,3400,467
cercle R = 1mailles1 496547312530
pire0,5270,0810,1790,444

Une grille ne peut pas suivre une oblique : elle la découpe en escalier, et tout ce qui s’en approche est rendu au paveur frontal. Sur la maison, où l’oblique ne fait que le toit, ce qui reste de rectilinéaire suffit encore à grid_surface2 ; sur le cercle, qui n’a plus rien de droit, triangulate_surface est le meilleur des quatre.

Sur une forme sans direction dominante, grid_surface2 n’est pas un candidat. Il prend l’écartement de ses lignes sur le contour, et un cercle n’en dicte aucun : selon la taille demandée, son cœur tient ou s’effondre. À la taille de la figure il rend 0,444, mais la taille voisine le fait tomber au bord de la dégénérescence. Pire maille du même cercle, selon la taille :

tailletriangulatepavegridgrid2
0,050,4240,0400,3660,011
0,060,5260,0310,2910,406
0,070,4240,0150,1370,012
0,080,4360,0390,1910,035
0,10,5270,0810,1790,444
0,120,4970,0030,3620,005

triangulate_surface ne descend jamais sous 0,42 et grid_surface jamais sous 0,13 ; les deux autres passent d’une maille correcte à une maille presque plate d’une taille à la voisine. Sur une courbe, prenez triangulate_surface si la qualité du pire élément commande, grid_surface s’il faut des quadrangles.

Le cercle mérite un mot de plus. pave_surface y tombe à 0,081 — ses rangées se referment toutes au centre, et c’est cette fermeture qui porte tout le défaut. triangulate_surface, lui, ne descend jamais sous 0,41, sur aucune des onze formes : c’est la signature d’un Delaunay raffiné, qui garantit un angle minimal et rien de plus. Il ne s’effondre jamais, mais il ne monte jamais non plus.

Ce qu’il faut retenir

Le coût en mailles est le classement le plus stable : sur les dix formes rectilinéaires ou peu obliques, les deux mailleurs en grille rendent le moins de mailles — grid_surface2 le plus souvent, grid_surface sur la maison, à trois mailles près —, puis pave_surface, puis triangulate_surface, avec un facteur quatre à cinq entre les extrêmes, à qualité égale ou meilleure (à un centième près sur le carré arrondi). Pour un calcul, c’est le facteur qui compte juste après la qualité. Le cercle est la seule exception : grid_surface2 y rend plus de mailles que grid_surface (530 contre 312), pour une qualité qui s’effondre d’une taille à l’autre — la façon la plus nette de dire qu’il n’est pas fait pour ça.

En pratique :

  • forme rectilinéaire — grid_surface2, et d’autant plus si ses côtés n’ont pas été coupés aux angles qui leur font face ;
  • forme courbe — triangulate_surface si la qualité du pire élément commande, grid_surface s’il faut des quadrangles ; jamais grid_surface2, qui y perd son cœur à la plupart des tailles ;
  • forme franchement oblique — pave_surface, dont les rangées épousent la pente ; mais tant qu’il reste des parois droites autour de l’oblique, les mailleurs en grille tiennent — la maison en est l’exemple ;
  • le moins de triangles possible — prefer_quads=True, sur les trois paveurs, refuse par une erreur claire un contour dont la parité l’interdit ; quelques triangles peuvent encore rester là où un quadrangle serait retourné ;
  • triangles voulus — triangulate_surface, seul à en produire par construction.

Le front peut garder ses angles : relax

Les chiffres de pave_surface ci-dessus sont ceux du réglage par défaut. Entre deux rangées, le front est relaxé — c’est ce qui l’empêche de se plisser — et cette relaxation est un laplacien, qui arrondit les angles. Or un front ne perd des nœuds qu’à ses coins : une fois les coins arrondis, il garde tous ses nœuds pendant que son périmètre rétrécit, et le milieu du domaine sort plus fin que la taille demandée. Un carré 20 × 20 à la taille 1 sort à 592 mailles au lieu de 400, les plus intérieures à 0,26 de l’aire visée.

relax="along" garde le même déplacement mais projeté sur le front : l’écartement s’égalise encore, la forme n’est plus rabotée, et le carré sort comme les 400 carrés exacts qu’on dessinerait. relax="none" ne relaxe pas du tout. Aucun des trois ne gagne partout. Sur les formes à angles, "along" et "none" l’emportent nettement ; sur une courbe, il n’y a pas d’angle à préserver, et aucun réglage ne protège le paveur — sur le cercle, chacun des trois passe devant ou tombe près de zéro selon la taille. Mesuré sur un carré et une bande à la taille 1, puis sur trois formes des figures ci-dessus, à leur taille :

forme"free""along""none"
carré 20 × 20592 mailles, pire 0,619400, 1,000400, 1,000
bande étroite 40 × 3123, 0,702120, 1,000123, 0,684
L à cotes quelconques111, 0,68066, 0,78066, 0,774
créneau, base coupée816, 0,118586, 0,426577, 0,546
cercle R = 1547, 0,081610, 0,281620, 0,027

Le détail du mécanisme est sur la page Mailler des opérateurs. Les deux mailleurs en grille prennent le même réglage, qui n’y gouverne que la bande : la grille est posée droite quoi qu’il arrive.

Deux limites connues

Un vide que le contour ne borde pas n’est pas maillé en grille. grid_surface2 prend l’écartement de ses lignes sur le contour ; là où le contour ne dit rien — le triangle du toit de la maison, qu’aucune paroi verticale ne borde — il coupe le vide en mailles entières tant qu’il ne dépasse pas trois fois l’écartement moyen, et l’abandonne au front au-delà. Remplir un tel vide de rangées ne crée pas du cœur : ces rangées n’existent que pour être érodées par l’oblique qui les traverse, et elles morcellent le travail du front au lieu de lui donner une région propre. Sur la maison, l’abandon ne laisse qu’un triangle (5ᵉ centile 0,725) ; quand ce seuil a été posé, le remplissage en coûtait cinq.

C’est aussi ce qui coûte le cercle, dont le contour laisse de grands vides. Aucun seuil ne sépare les deux cas — abandonner un vide abandonne a fortiori un vide plus grand — et c’est un choix assumé : grid_surface2 sert les formes rectilinéaires, grid_surface sert les courbes.

Le cercle est un objectif instable. Sur une forme sans direction dominante, un rien déplace les décisions des mailleurs : le tableau des tailles le montre, et la position compte aussi — le même cercle, maillé à l’origine au lieu de sa place dans la figure, sort de grid_surface2 à 0,459 au lieu de 0,444. Les chiffres du cercle ci-dessus sont justes mais ne se prolongent pas : ne réglez aucun paramètre dessus.

Reproduire les figures

maturin develop --features extension-module,viz
python examples/comparer_mailleurs_2d.py

# Figures du livre :
PYRUCAST_IMG_DIR=book/src/img python examples/comparer_mailleurs_2d.py

Le script tient dans une fonction : elle prend un contour, le duplique trois fois par translate, maille chaque copie par une méthode et réunit le tout sur une figure.

def comparer(nom, contour, taille, fichier, noeuds=True):
    """Maille `contour` par les quatre méthodes et trace la figure.
    / Meshes `contour` with all four methods and draws the figure.

    FR — Le contour n'est construit qu'une fois : ses trois copies viennent de
    `translate`, qui rend un maillage neuf dans les mêmes `Coords` — c'est ce
    qui permet de les réunir sur une seule figure.
    """
    points = [n.position() for sub in contour for cell in sub for n in cell]
    xs, ys = [p[0] for p in points], [p[1] for p in points]
    dx, dy = (max(xs) - min(xs)) * 1.15, (max(ys) - min(ys)) * 1.25
    coins = [(0.0, 0.0), (dx, 0.0), (0.0, -dy), (dx, -dy)]

    tout, lignes = None, []
    for (titre, mailler), coin in zip(MAILLEURS, coins):
        copie = pc.mesh.translate(contour, list(coin))
        maillage = mailler(copie, taille)
        qs = sorted(
            qualite([n.position() for n in cell]) for sub in maillage for cell in sub
        )
        comptes = dict(zip(maillage.element_types(), maillage.cell_counts()))
        lignes.append(
            f"{titre:20s} {len(qs):6d} mailles, {comptes.get('TRI3', 0):5d} tri, "
            f"pire {qs[0]:.3f}, p5 {qs[len(qs) // 20]:.3f}"
        )
        for sub in copie:
            sub.face_color = (20, 90, 200)
        bloc = maillage | copie
        if noeuds:
            points_rouges = pc.mesh.to_poi1(copie)
            for sub in points_rouges:
                sub.face_color = (220, 30, 30)
            bloc = bloc | points_rouges
        tout = bloc if tout is None else tout | bloc

    print(f"\n{nom}   (taille visée {taille:g})")
    for ligne in lignes:
        print(f"   {ligne}")
    tout.plot(
        view=VUE,
        show_axes=False,
        save=os.path.join(OUT, fichier),
        title=f"{nom} — h={taille:g} — haut : triangulate, pave — bas : grid, grid2",
    )


Mailler en 3D

À venir. En attendant, les mailleurs volumiques — triangulate_volume (tétraèdres), pave_volume (couche limite d’hexaèdres autour d’un cœur tétraédrique), extrude et sweep_solid — sont décrits dans Opérateurs → Maillage.