Multi-points (MPC)
En bref
Impose une relation linéaire entre plusieurs inconnues : deux nœuds à la même
température, une périodicité, une liaison affine. Avec sense, une borne :
une liaison à jeu.
| opérateur | pyrucast.model.mpc(terms, target, sense="=") |
| tag | constraint et celui de la cible ; constraint seul si la relation lie deux physiques |
| type | contrainte (label() : "Mpc") |
| support | un maillage POI1 par terme |
terms est une liste de termes (maillage, variable, coefficient). Les
maillages des termes sont appariés maille par maille : la relation \(r\)
relie la maille \(r\) de chacun. Une périodicité entre deux surfaces de
\(N\) nœuds est donc \(N\) relations d’un coup. L’ordre des mailles est à
la charge de l’appelant ; la contrainte vérifie que tout est POI1, sur un
même Coords, avec le même nombre de mailles par zone. target donne à
chaque variable sa duale (Model.dual_of) ; une relation entre deux physiques
se pose sur leur union.
Théorie
Chaque relation s’écrit
\[ \sum_k a_k\,u(n_k, v_k) = g \qquad (\text{ou } \ge,\ \le\ g). \]
C’est Dirichlet à plusieurs termes et coefficients quelconques.
Chaque terme apporte une paire de blocs de coefficient \(a_k\) :
\(C\), ligne (multiplicateur, imposed), colonne (n_k, v_k) ; et
\(C^{\mathsf T}\), ligne (n_k, duale de v_k), colonne
(multiplicateur, lambda). Tous les termes d’une relation partagent son nœud
multiplicateur et sa ligne imposed, ce qui les additionne en une équation.
La réaction, la force que la relation exerce sur la pièce, est
\(-a_k\,\lambda\) au nœud de chaque terme.
Le nœud multiplicateur de chaque relation est créé à la position du nœud de
son premier terme. Le second membre \(g\) s’écrit au chargement, à la
composante imposed du nœud multiplicateur, par
constraint_rhs([(un_noeud_de_la_relation, g)]), ou par
constraint_rhs_by_index([(r, g)]) quand un nœud appartient à plusieurs
relations. Une relation absente du chargement impose 0.
Les coefficients sont un par terme, les mêmes pour toutes ses mailles. Des coefficients qui varient d’un nœud à l’autre sont le cas du baignage.
Variables
| primale | lambda |
| duale | imposed |
| ce qu’elle contraint | les variables des termes, inconnues de la cible |
| matériau, comportement | aucun |
Ce qu’elle produit
| raideur | une paire \(C\), \(C^{\mathsf T}\) par terme et par zone |
| masse, géométrique | — |
| tangente | = raideur |
| forces internes | \(C^{\mathsf T}\lambda\) sur les duales, \(C\,u\) sur les lignes imposed |
| forces externes | aucune |
Exemple
Sur une barre en conduction, \(T(0) = 0\) par Dirichlet et \(T(1) - T(0) = 1\) par une MPC : d’où \(T = x\).
import pyrucast
c = pyrucast.Coords(dim=1)
nodes = [c.add_node([i / 4.0]) for i in range(5)]
mesh = pyrucast.Mesh(c, "SEG2")
for i in range(4):
mesh.unit().add_cell([nodes[i], nodes[i + 1]])
fes = pyrucast.FiniteElementSpace(mesh)
base = pyrucast.model.heat_conduction(fes)
dual = base.dual_of("T") # "q"
# Dirichlet T(0) = 0.
imposed0 = pyrucast.mesh.poi1_from_nodes([nodes[0]])
dirichlet = pyrucast.model.dirichlet(imposed0, base, "T")
# MPC 1·T(dernier) − 1·T(0) = 1.
mesh_last = pyrucast.mesh.poi1_from_nodes([nodes[-1]])
mesh_first = pyrucast.mesh.poi1_from_nodes([nodes[0]])
mpc = pyrucast.model.mpc(
[(mesh_last, "T", 1.0), (mesh_first, "T", -1.0)],
base,
)
model = base | dirichlet | mpc
materials = pyrucast.element_field.material_field(model, [("k", 1.0)])
# Chargement : valeur imposée de Dirichlet + second membre g de la MPC. Le
# `constraint_rhs` désigne chaque relation par un nœud (le nœud imposé pour
# Dirichlet, un nœud d'un terme pour la MPC) et trouve son nœud multiplicateur ;
# la composante est `imposed` pour les deux. Les deux se réunissent par `|`.
rhs = dirichlet.constraint_rhs([(nodes[0], 0.0)]) | mpc.constraint_rhs(
[(nodes[-1], 1.0)]
)
solution = pyrucast.solver.solve(pyrucast.matrix.stiffness(model, materials), rhs)
assert abs(solution.value(nodes[2], "T") - 0.5) < 1e-10
examples/mpc_periodicite.py pose une périodicité.
Côté Rust
Mpc (src/models/mpc.rs) implémente Constraint. Ses blocs sortent du même
constraint_block_pair que Dirichlet, avec le coefficient \(a_k\) au lieu de
1.