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

Introduction

pyrucast est une librairie d’éléments finis dont le cœur est écrit en Rust et qui expose une API Python. Elle s’inspire des principes de Cast3M : un noyau d’objets typés, accompagné de fonctions opérant sur ces objets.

📖 Référence API Rust (rustdoc). Cette documentation couvre les principes, l’architecture et les exemples ; la référence par item (signatures, types, modules) est générée par rustdoc et publiée à côté de ce book : https://pyrucast.github.io/pyrucast/rust/.

Philosophie

  • Simplicité avant tout. Le code doit rester maintenable et éditable par un humain non expert ; on évite la sophistication gratuite.
  • Dépendances minimales. Tout ajout de dépendance externe (Rust ou Python) requiert un accord explicite.
  • Vérification continue. Chaque objet est livré avec des tests unitaires Rust, des doctests, des tests Python et un chapitre de cette documentation.

Modèle d’objets (arbre de dépendances)

Chaque structure ne dépend que des structures qui la précèdent. La plupart viennent par paire zone / agrégat (SubMesh/Mesh…) — c’est le motif Agrégat, avec sa composition par union |.

Coords ── Node                          (NodeId u32 stable ; Node = accesseur RAII)
   │
   └── Mesh  (agrège des SubMesh, + ElementType)   géométrie
          ├── NodeField  (agrège des SubNodeField, support POI1)   valeurs par nœud × composante
          └── FiniteElementSpace  (agrège des SubFiniteElementSpace)
                 │                  (+ Interpolation, QuadratureRule)
                 ├── ElementField  (agrège des SubElementField)   valeurs aux Gauss
                 └── Model  (agrège des SubModel : physiques + contraintes)
                        └── ops::matrix ──► Matrix   (matrice creuse, DOFs nommés)

Evolution  (agrège des SubEvolution)    scalaire, NodeField ou ElementField
                                        tabulé vs une variable

Model + ElementField (matériau) ──► stiffness ──► Matrix
Matrix + NodeField (second membre) ──► solve ──► NodeField (solution)

Deux traits transverses factorisent le comportement commun : Aggregate (accès len/[i], union — | en Python, union en Rust) et Field/SubField (composantes nommées, min/max, arithmétique), partagés entre NodeField et ElementField.

Résumé des rôles :

StructureRôle
CoordsRéférentiel de coordonnées de nœuds (plusieurs configurations)
NodeAccesseur utilisateur d’un nœud, avec protection GC automatique
SubMesh / MeshCellules d’un même ElementType / union de sous-maillages
SubNodeField / NodeFieldValeurs par nœud × composante (zone / agrégat)
SubFiniteElementSpace / FiniteElementSpaceFormulation EF (interpolation + quadrature) / union
SubElementField / ElementFieldValeurs par cellule × point de Gauss × composante
SubModel / ModelPhysique ou contrainte locale / problème complet
SubMatrix / MatrixMatrice creuse dont les lignes/colonnes sont des DOFs nommés (NodeId, inconnue), par ex. l’inconnue "UX" d’un nœud
SubEvolution / EvolutionValeur (scalaire ou champ) tabulée vs une variable, interpolée linéairement (zone / agrégat)

Premiers pas

Exemple minimal en Rust :

#[test]
fn un_maillage_minimal() -> Result<()> {
    let coords = Handle::new(Coords::new(2)?);
    let a = Node::create_in(coords.clone(), &[0.0, 0.0])?;
    let b = Node::create_in(coords.clone(), &[1.0, 0.0])?;

    let mesh = mesh::line(&a, &b, 10, ElementType::SEG2)?;
    println!("{}", mesh); // Mesh: 1 submesh(es) [#…], 10 cell(s) total
    Ok(())
}

En Python, il suffit d’installer le paquet :

pip install pyrucast

Exemple équivalent en Python :

import pyrucast

c = pyrucast.Coords(dim=2)
a = c.add_node([0.0, 0.0])
b = c.add_node([1.0, 0.0])

mesh = pyrucast.mesh.line(a, b, 10)
print(mesh)  # Mesh: 1 submesh(es) [#…], 10 cell(s) total