matto.materials#

The material contract.

A material is a free-energy density W(F; fields, stimuli). The package builds F = variable(I + grad u) once, calls energy(), and takes the first Piola-Kirchhoff stress as diff(W, F). A material says up front which design fields it reads, which stimuli it needs and what shape they have, and which parameters it takes, so a mismatch with the input file is reported at construction instead of surfacing as a KeyError inside UFL.

Subclass Material, set the class attributes, write energy(). The class can live in the package, next to the input scripts, or in the input script itself.

class matto.materials.base.Material(**parameters)[source]#

Bases: object

fields = ()#

design fields the energy reads, by name; the input file sets which of them are optimized and which are prescribed

stimuli = {}#

stimulus name -> shape, () for a scalar and (dim,) for a vector; the load cases supply the values

parameters = {}#

parameter name -> default, or None when the caller must supply it

internal_variables = {}#

history variables, name -> shape. Reserved for path-dependent models; check_requirements raises for a material that declares any, since history-dependent models are not supported.

reference = ''#

where the model comes from

energy(F, fields, stimuli)[source]#

Free-energy density as a UFL scalar.

F is ufl.variable(I + grad u), so the caller can differentiate with respect to it. fields maps each name in self.fields to its physical Function; stimuli maps each name in self.stimuli to its Constant.

check_requirements(design_variables, stimuli)[source]#

Raise if the problem does not provide what this material reads.

Hard-magnetic soft material, in 2D plane strain or 3D.

class matto.materials.hmsm.HardMagneticSoftMaterial(**parameters)[source]#

Bases: Material

Hard-magnetic soft material: a reinforced matrix with remanent magnetization.

The magnetic energy is linear in the applied flux density, -(1/mu0) phi (F B_rem) . B_app, with B_rem of fixed magnitude along the design direction theta.

Fields: rho (density), phi (particle fraction), theta (remanent direction). Stimulus: B_app, the applied flux density vector.

Works in 2D and 3D; pass dim=3 for a 3D problem. theta is one angle in both cases: in 3D the remanent magnetization lies in the x-y plane at that angle, and the applied field may point anywhere.

fields = ('rho', 'phi', 'theta')#

design fields the energy reads, by name; the input file sets which of them are optimized and which are prescribed

parameters = {'B_rem_mag': None, 'G0': None, 'dim': 2, 'eps_rho': 1e-06, 'mu0': None, 'p_rho': 3.0}#

parameter name -> default, or None when the caller must supply it

reference = 'Galloway & Jha, Model-informed joint material-structural optimization of hard-magnetic soft materials, arXiv:2607.14397'#

where the model comes from

energy(F, fields, stimuli)[source]#

Free-energy density as a UFL scalar.

F is ufl.variable(I + grad u), so the caller can differentiate with respect to it. fields maps each name in self.fields to its physical Function; stimuli maps each name in self.stimuli to its Constant.

Liquid crystal elastomer, plane strain, small-strain energy.

class matto.materials.lce.LiquidCrystalElastomer(**parameters)[source]#

Bases: Material

Liquid crystal elastomer: Saint Venant-Kirchhoff plus a nematic coupling.

The coupling is -1/2 beta dS (Q . E) with Q = 3 n n - I built on the programmed director angle theta. The stimulus is the activation, ramped from zero, which lowers the order parameter from S0: dS = S0 activation.

Fields: rho (density), phi (LCE fraction), theta (director). Stimulus: activation, scalar in [0, 1].

fields = ('rho', 'phi', 'theta')#

design fields the energy reads, by name; the input file sets which of them are optimized and which are prescribed

stimuli = {'activation': ()}#

stimulus name -> shape, () for a scalar and (dim,) for a vector; the load cases supply the values

parameters = {'E_LCE': None, 'S0': None, 'beta': None, 'eps_rho': 1e-06, 'nu': None, 'p_phi': 3.0, 'p_rho': 3.0}#

parameter name -> default, or None when the caller must supply it

reference = 'Barrera et al. 2024 (LCE energy used in the examples)'#

where the model comes from

energy(F, fields, stimuli)[source]#

Free-energy density as a UFL scalar.

F is ufl.variable(I + grad u), so the caller can differentiate with respect to it. fields maps each name in self.fields to its physical Function; stimuli maps each name in self.stimuli to its Constant.

Isotropic magneto-active elastomer in a silicone matrix, plane strain.

class matto.materials.mae.MagnetoActiveElastomer(**parameters)[source]#

Bases: Material

Isotropic magneto-active elastomer in a silicone matrix.

The second Mooney-Rivlin coefficient of the active phase stiffens with the applied field; the two phases are mixed by the design fraction phi.

Fields: rho (density), phi (MAE fraction). Stimulus: h, the applied flux density mu0 times the field magnitude, as a scalar.

fields = ('rho', 'phi')#

design fields the energy reads, by name; the input file sets which of them are optimized and which are prescribed

stimuli = {'h': ()}#

stimulus name -> shape, () for a scalar and (dim,) for a vector; the load cases supply the values

parameters = {'C1_Ga': None, 'C1_sil': None, 'C2_Ga': None, 'C2_sil': None, 'K': None, 'a1': None, 'a2': None, 'b1': None, 'b2': None, 'eps_rho': 1e-06, 'mu0': None, 'p_phi': 1.0, 'p_rho': 3.0}#

parameter name -> default, or None when the caller must supply it

reference = 'Garai & Haldar, Int. J. Mech. Sci. 286 (2025) 109860, doi:10.1016/j.ijmecsci.2024.109860'#

where the model comes from

energy(F, fields, stimuli)[source]#

Free-energy density as a UFL scalar.

F is ufl.variable(I + grad u), so the caller can differentiate with respect to it. fields maps each name in self.fields to its physical Function; stimuli maps each name in self.stimuli to its Constant.

Anisotropic magneto-active elastomer in a silicone matrix, plane strain.

class matto.materials.mae_aniso.AnisotropicMagnetoActiveElastomer(**parameters)[source]#

Bases: Material

Anisotropic magneto-active elastomer with particle chains, in silicone.

The chains lie along the design direction theta. The magnetic stiffening saturates with the field and scales with the alignment of the chains with the fixed magnetization direction theta_M. The two phases are mixed by the design fraction phi.

Fields: rho (density), phi (MAE fraction), theta (chain direction). Stimulus: h, applied field magnitude as a scalar.

fields = ('rho', 'phi', 'theta')#

design fields the energy reads, by name; the input file sets which of them are optimized and which are prescribed

stimuli = {'h': ()}#

stimulus name -> shape, () for a scalar and (dim,) for a vector; the load cases supply the values

parameters = {'A_Ak': None, 'A_sil': None, 'K_Ak': None, 'K_sil': None, 'a_Ak': None, 'a_sil': None, 'b_Ak': None, 'b_sil': None, 'delta_theta': 1e-06, 'eps_rho': 1e-06, 'hs': None, 'p_phi': 1.0, 'p_rho': 3.0, 'r': None, 's': None, 'theta_M': 0.0}#

parameter name -> default, or None when the caller must supply it

reference = 'Akbari & Khajehsaeid, Smart Mater. Struct. 30 (2021) 015008, doi:10.1088/1361-665X/abc72f'#

where the model comes from

energy(F, fields, stimuli)[source]#

Free-energy density as a UFL scalar.

F is ufl.variable(I + grad u), so the caller can differentiate with respect to it. fields maps each name in self.fields to its physical Function; stimuli maps each name in self.stimuli to its Constant.

Linear elasticity as a stored energy.

class matto.materials.linear.LinearElastic(**parameters)[source]#

Bases: Material

Small-strain isotropic linear elasticity, plane strain in 2D.

W = 1/2 lambda tr(e)^2 + mu e:e with e = sym(grad u), scaled by the SIMP density interpolation.

Fields: rho. No stimuli.

fields = ('rho',)#

design fields the energy reads, by name; the input file sets which of them are optimized and which are prescribed

stimuli = {}#

stimulus name -> shape, () for a scalar and (dim,) for a vector; the load cases supply the values

parameters = {'E': None, 'eps_rho': 1e-06, 'nu': None, 'p_rho': 3.0}#

parameter name -> default, or None when the caller must supply it

energy(F, fields, stimuli)[source]#

Free-energy density as a UFL scalar.

F is ufl.variable(I + grad u), so the caller can differentiate with respect to it. fields maps each name in self.fields to its physical Function; stimuli maps each name in self.stimuli to its Constant.

Kinematic quantities the material models share.

class matto.materials.kinematics.IsochoricInvariants(J, Cbar, I1bar, I2bar)#
Cbar#

Alias for field number 1

I1bar#

Alias for field number 2

I2bar#

Alias for field number 3

J#

Alias for field number 0

matto.materials.kinematics.plane_strain_3d(F2)[source]#

Embed an in-plane 2x2 deformation gradient as 3x3 plane strain.

matto.materials.kinematics.isochoric_invariants(F)[source]#

J, the isochoric right Cauchy-Green tensor and its two invariants.

matto.materials.kinematics.director(theta, dim=2)[source]#

Unit vector at angle theta from the first axis, in the plane.

Design-field interpolation the material models share.

matto.materials.interpolation.simp(rho, p, eps)[source]#

Solid isotropic material with penalization, eps + (1 - eps) rho^p.

matto.materials.interpolation.two_phase(W_active, W_matrix, phi_scale)[source]#

Mix an active phase into a matrix by the penalized fraction.

Consistency checks any material should pass, for use in its tests.

check_material() puts the model on a small mesh with an affine displacement, so the deformation gradient is exactly what was asked for, and checks three things at zero stimulus and at the given one.

  1. The reference configuration is stress-free: with u = 0 and no stimulus the internal-force vector vanishes.

  2. Frame indifference: W(Q F) = W(F) for a rotation Q, with any in-plane vector stimulus rotated along.

  3. A moderate stretch raises the stored energy at zero stimulus: W(F) >= W(I) for one stretch F.

Run it on a new material before running an optimization with it.

matto.materials.testing.check_material(material, field_values=None, stimulus_values=None, comm=mpi4py.MPI.COMM_WORLD, stretch=None, rotation=0.7, rel_tol=1e-08, dim=2, frame_indifference=True)[source]#

Raise AssertionError with a message naming the failed check.

Parameters:
  • field_values – name -> constant value for each field the material reads; defaults cover rho, phi, theta.

  • stimulus_values – name -> value; defaults to zero for every stimulus.

  • dim – 2 or 3, the dimension the material is meant for.

  • frame_indifference – skip check 2 for a small-strain model that is not objective by construction.