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

Baignage (embedded)

En bref

Lie chaque nœud d’un maillage immergé à l’interpolation d’un maillage hôte au même point : une barre d’armature baignée dans un béton, qui suit ses déplacements sans partager ses nœuds.

opérateurpyrucast.model.embedded(immersed, host, target, variables, tol=1e-6)
tagconstraint et celui de la cible
typecontrainte (label() : "Embedded")
supportles nœuds du maillage immergé, et les mailles de l’hôte

variables sont les inconnues liées (["u_x", "u_y", "u_z"]), toutes inconnues de la cible. Les deux maillages partagent un même Coords. L’hôte peut être de tout type de maille à domaine de référence (segments, triangles, quadrangles, tétraèdres, prismes, hexaèdres, linéaires et quadratiques) ; le maillage immergé n’est lu que par ses nœuds.

Théorie

Pour un nœud immergé \(p\) logé dans la maille hôte de fonctions de forme \(N_i\), et pour chaque variable \(c\) :

\[ u_c(p) - \sum_i N_i(\xi_p)\,u_c(\text{hôte}_i) = g_c , \]

\(g_c = 0\) étant la liaison rigide. C’est une MPC dont les coefficients, \(+1\) sur le nœud immergé et \(-N_i(\xi_p)\) sur chaque nœud hôte, varient d’un nœud à l’autre.

Les poids sont calculés une fois, à la construction, en localisant chaque nœud immergé dans l’hôte : un Newton sur \(x - \sum_i N_i(\xi)\,X_i\), avec un test d’appartenance au domaine de référence de la maille, à tol près. Les mailles hôtes sont parcourues une à une, filtrées par leur boîte englobante. Un nœud immergé qui ne tombe dans aucune maille hôte est refusé.

Chaque relation (un nœud immergé et une variable) a son nœud multiplicateur, placé au nœud immergé ; multiplier_mesh() porte une zone par variable. Le second membre \(g_c\) s’écrit au chargement par constraint_rhs ; absent, il vaut 0.

Variables

primalelambda, la force de liaison
dualeimposed
ce qu’elle contraintles variables, au nœud immergé et aux nœuds hôtes
matériau, comportementaucun

Ce qu’elle produit

raideurune paire \(C\), \(C^{\mathsf T}\) par variable
masse, géométrique—
tangente= raideur
forces internes\(C^{\mathsf T}\lambda\) sur les duales, \(C\,u\) sur les lignes imposed
forces externesaucune

Exemple

Un cube HEX8 en conduction, ses coins tenus au champ linéaire \(T = 1 + 2x + 3y + 4z\), que l’interpolation trilinéaire reproduit exactement ; un nœud immergé au cœur prend la valeur de l’hôte en ce point.

import pyrucast

corners = [
    [0, 0, 0],
    [1, 0, 0],
    [1, 1, 0],
    [0, 1, 0],
    [0, 0, 1],
    [1, 0, 1],
    [1, 1, 1],
    [0, 1, 1],
]
field = lambda c: 1.0 + 2.0 * c[0] + 3.0 * c[1] + 4.0 * c[2]

c = pyrucast.Coords(dim=3)
corner_nodes = [c.add_node(x) for x in corners]

host = pyrucast.Mesh(c, "HEX8")
host.unit().add_cell(corner_nodes)
fes = pyrucast.FiniteElementSpace(host)
base = pyrucast.model.heat_conduction(fes)

# Les coins tenus au champ linéaire (Dirichlet).
corner_mesh = pyrucast.mesh.poi1_from_nodes(corner_nodes)
dirichlet = pyrucast.model.dirichlet(corner_mesh, base, "T")

# Le nœud immergé, lié à l'hôte.
p = c.add_node([0.3, 0.6, 0.2])
bar = pyrucast.mesh.poi1_from_nodes([p])
embedded = pyrucast.model.embedded(bar, host, base, ["T"])
emb_mult = embedded.multiplier_mesh().node(0, 0, 0)

model = base | dirichlet | embedded
materials = pyrucast.element_field.material_field(model, [("k", 1.0)])

# Chargement : la valeur du champ à chaque coin, g = 0 (la liaison) au nœud immergé.
rhs = dirichlet.constraint_rhs([(n, field(x)) for n, x in zip(corner_nodes, corners)])
rhs = rhs | embedded.constraint_rhs([(p, 0.0)])

solution = pyrucast.solver.solve(pyrucast.matrix.stiffness(model, materials), rhs)
assert abs(solution.value(p, "T") - field([0.3, 0.6, 0.2])) < 1e-9  # 4.2

examples/barre_baignee_elastique.py baigne une barre dans un volume élastique, sur les trois déplacements.

Côté Rust

Embedded (src/models/embedded.rs) implémente Constraint. La localisation passe par ops::geom::locate_points, l’inversion de la transformation de référence.