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

Élasticité orthotrope et anisotrope

En bref

Un composite tissé, un bois, une tôle laminée ou un monocristal n’ont pas la même raideur dans toutes les directions. C’est l’option symmetry de l’élasticité, indépendante de la cinématique :

symmetryconstantesce qu’elle décrit
"isotropic"2aucune direction privilégiée
"orthotropic"9trois plans de symétrie orthogonaux
"anisotropic"21le cas général

Les variables ne changent pas : seule la matrice de Hooke \(D\) change. Les lois non linéaires (plasticité, fluage, endommagement de Mazars et Damage TC) gardent une élasticité isotrope ; la loi SiC/SiC a ses propres axes.

Théorie

La loi de comportement est \(\sigma_{ij} = C_{ijkl}\,\varepsilon_{kl}\). Les symétries de \(\sigma\) et \(\varepsilon\) et l’existence d’un potentiel élastique réduisent \(C\) à une matrice \(6\times6\) symétrique en notation de Voigt : 21 constantes dans le cas général.

Orthotropie. Dans ses axes propres, la souplesse \(S = C^{-1}\) découple les termes normaux des cisaillements :

\[ S = \begin{bmatrix} 1/E_1 & -\nu_{21}/E_2 & -\nu_{31}/E_3 & & & \\ -\nu_{12}/E_1 & 1/E_2 & -\nu_{32}/E_3 & & & \\ -\nu_{13}/E_1 & -\nu_{23}/E_2 & 1/E_3 & & & \\ & & & 1/G_{23} & & \\ & & & & 1/G_{13} & \\ & & & & & 1/G_{12} \end{bmatrix}, \qquad \frac{\nu_{ji}}{E_j} = \frac{\nu_{ij}}{E_i} . \]

Les relations de réciprocité ne laissent que neuf constantes. \(S\) doit être définie positive : un jeu de constantes qui la rend singulière est refusé, plutôt que d’assembler une raideur fausse.

Les axes matériau sont donnés par des vecteurs du champ matériau : V1X, V1Y en 2-D (le second axe est la normale dans le plan, le troisième la direction hors du plan, l’orthoradiale en axisymétrie) ; V1X…V1Z et V2X…V2Z en 3-D (le troisième est \(V_1 \times V_2\)). Ils sont orthonormalisés en interne : \(V_2\) n’a besoin d’être qu’à peu près perpendiculaire à \(V_1\). Un \(V_1\) nul, ou un \(V_2\) parallèle à \(V_1\), est refusé. Comme toute composante matériau, les axes peuvent varier d’une maille et d’un point de Gauss à l’autre : un composite bobiné, une pièce courbe.

En chaque point de Gauss, \(D\) est construit dans les axes matériau, tourné dans les axes globaux par le tenseur d’ordre 4,

\[ C'_{pqrs} = R_{pi}\,R_{qj}\,R_{rk}\,R_{sl}\,C_{ijkl}, \qquad R = \big[\,V_1\ \ V_2\ \ V_1\times V_2\,\big], \]

puis réduit à la cinématique : le bloc [xx, yy, xy] en déformations planes, sa condensation sur \(\varepsilon_{zz}\) en contraintes planes, le bloc [rr, zz, θθ, rz] en axisymétrie. En cisaillement de l’ingénieur, le passage Voigt ↔ tenseur ne porte aucun facteur, et la rotation d’ordre 4 n’a aucune convention à retenir.

Variables

symmetrymatériau requis
"isotropic"E, nu
"orthotropic"E_1, E_2, E_3, nu_12, nu_13, nu_23, G_12, G_13, G_23, et les axes : V1X, V1Y en 2-D ; V1X, V1Y, V1Z, V2X, V2Y, V2Z en 3-D
"anisotropic"C_11, C_12, C_13, C_14, C_15, C_16, C_22, C_23, C_24, C_25, C_26, C_33, C_34, C_35, C_36, C_44, C_45, C_46, C_55, C_56, C_66 : le triangle supérieur dans l’ordre [xx, yy, zz, yz, xz, xy] ; et les axes : V1X, V1Y en 2-D ; V1X, V1Y, V1Z, V2X, V2Y, V2Z en 3-D

Les neuf constantes orthotropes sont demandées même en 2-D : le tenseur est construit en 3-D avant d’être réduit. Les trois jeux de composantes sont disjoints, si bien qu’une zone isotrope et une zone orthotrope partagent un maillage sans rien consolider. L’entrée et la sortie du comportement sont celles de l’élasticité isotrope.

Exemple

Les constantes d’un matériau quatre fois plus raide selon son axe 1 :

gauche, droite, carre = _carre()
plaque = pyrucast.model.elasticity(
    pyrucast.FiniteElementSpace(carre), "plane_stress", symmetry="orthotropic"
)
print(plaque[0].material_components())
# ['E_1', 'E_2', 'E_3', 'nu_12', 'nu_13', 'nu_23', 'G_12', 'G_13', 'G_23', 'V1X', 'V1Y']
angle = 0.0  # l'axe raide, selon x
constantes = [
    ("E_1", 40e3),
    ("E_2", 10e3),
    ("E_3", 10e3),
    ("nu_12", 0.25),
    ("nu_13", 0.25),
    ("nu_23", 0.3),
    ("G_12", 5e3),
    ("G_13", 5e3),
    ("G_23", 4e3),
    ("V1X", math.cos(angle)),
    ("V1Y", math.sin(angle)),
]

Sur la plaque en traction de la page Élasticité, le fichier de tests vérifie les deux bornes : \(u_x = S/E_1\) quand l’axe raide suit la traction, \(S/E_2\) quand il lui est perpendiculaire.

Côté Rust

src/models/symmetry.rs construit les tenseurs orientés pour l’élasticité, la conduction et la diffusion ; MaterialSymmetry est l’énumération des trois symétries. Le test ci-dessous étire un carré orthotrope selon son premier axe matériau ; le même fichier nourrit une loi orthotrope de constantes isotropes, puis une loi anisotrope du tenseur isotrope, qui doivent se comporter comme l’isotrope quel que soit le repère, et refuse un repère dégénéré.

use pyrucast::aggregate::Aggregate;
use pyrucast::atoms::{ElementType, Node};
use pyrucast::containers::finite_element_space::FiniteElementSpace;
use pyrucast::containers::mesh::{Mesh, SubMesh};
use pyrucast::containers::model::Model;
use pyrucast::containers::node_field::NodeField;
use pyrucast::coords::Coords;
use pyrucast::handle::Handle;
use pyrucast::models::symmetry::MaterialSymmetry;
use pyrucast::models::tensor::Kinematics;
use pyrucast::ops::element_field::StrainMeasure;
use pyrucast::ops::model;
use pyrucast::ops::solver::solve;
use pyrucast::Result;

/// Traction on the right edge.
const S: f64 = 2.0;
/// `N×N` QUA4 grid on the unit square.
const N: usize = 2;

#[test]
fn orthotropic_square_stretches_along_its_first_material_axis() -> Result<()> {
    const E1: f64 = 200.0; // stiff direction — aligned with global x
    const E2: f64 = 50.0; // compliant transverse direction
    const NU12: f64 = 0.25;

    let (grid, fes, _coords) = unit_square()?;
    let model = clamped_model(&grid, &fes, MaterialSymmetry::Orthotropic)?;

    // The material axes travel through the material field like any other
    // coefficient: `V1` is the first orthotropy direction, here the global x.
    let materials = pyrucast::ops::element_field::material_field(
        &model,
        &[
            ("E_1", E1),
            ("E_2", E2),
            ("E_3", E2),
            ("nu_12", NU12),
            ("nu_13", NU12),
            ("nu_23", 0.25),
            ("G_12", 30.0),
            ("G_13", 30.0),
            ("G_23", 30.0),
            ("V1X", 1.0),
            ("V1Y", 0.0),
            ("phi_f_x", S),
        ],
    )?;

    let solution = solve_traction(&model, &materials)?;

    // σ_xx = S with σ_yy = σ_zz = 0 ⇒ the compliance row gives ε directly.
    let tol = 1e-10;
    let h = 1.0 / N as f64;
    for j in 0..=N {
        for i in 0..=N {
            let (x, y) = (i as f64 * h, j as f64 * h);
            let id = grid[j * (N + 1) + i].id();
            let ux = solution.value(id, "u_x")?;
            let uy = solution.value(id, "u_y")?;
            assert!((ux - S / E1 * x).abs() < tol, "u_x({x},{y}) = {ux}");
            assert!((uy + NU12 * S / E1 * y).abs() < tol, "u_y({x},{y}) = {uy}");
        }
    }
    Ok(())
}