Define user problems

Fedoo can be extended at two complementary levels:

  • a weak form defines the equation assembled on the mesh;

  • a constitutive law defines the material response used by a mechanical weak form.

For a linear equation, a DiffOp expression and fedoo.WeakForm are generally sufficient. For a nonlinear or history-dependent equation, derive from WeakFormBase. For a mechanical material, MechanicalUMAT is the recommended extension point; derive directly from Mechanical3D only when full control over the Fedoo constitutive lifecycle is required.

Define a weak form from differential operators

A modeling space owns the unknown fields and creates their differential operators. The virtual property selects the test-function side of a weak term. Ordinary Python arithmetic combines these objects into a DiffOp expression.

The following example defines the weak form of the Poisson equation

\[\int_\Omega \nabla \delta u \mathbin{\cdot} \nabla u\,d\Omega = 0.\]
import fedoo as fd

space = fd.ModelingSpace("2D")
space.new_variable("U")

dU_dX = space.derivative("U", "X")
dU_dY = space.derivative("U", "Y")

equation = dU_dX.virtual * dU_dX + dU_dY.virtual * dU_dY
weakform = fd.WeakForm(equation)

mesh = fd.mesh.rectangle_mesh()
assembly = fd.Assembly.create(weakform, mesh)
problem = fd.problem.Linear(assembly)

problem.bc.add("Dirichlet", "left", "U", 0)
problem.bc.add("Dirichlet", "right", "U", 1)
problem.solve()

The same construction applies to systems of equations. Declare every scalar unknown with fedoo.ModelingSpace.new_variable(), group components with fedoo.ModelingSpace.new_vector() when useful, and add the weak terms. Mixed formulations may assign different element interpolations to different variables.

Complete examples are available in poison_eq.py and fluid_mechanics.py.

State-dependent weak forms

When coefficients or residual terms depend on the current solution, derive a class from WeakFormBase. Its principal methods are:

initialize(assembly, problem)

Allocate values required by the formulation in assembly.sv.

update(assembly, problem)

Evaluate the current fields and update the residual state before assembly.

get_weak_equation(assembly, problem)

Return the linearized DiffOp, including the tangent and current residual terms.

set_start(assembly, problem)

Commit the state at the beginning of a new time increment.

to_start(assembly, problem)

Restore the beginning-of-increment state after a rejected increment.

reset()

Clear the complete problem history when necessary.

The problem may have problem.dtime == 0 during initialization. A custom weak form must not divide by dtime in that state. Time-dependent terms can be omitted until a positive increment is supplied. See navier_stokes.py for a complete nonlinear example.

Define a mechanical constitutive law

Use MechanicalUMAT for a conventional material-point update. It handles the Fedoo lifecycle, state allocation, temperature lookup, material local frames, finite-rotation increments, and the transformations of strains, stresses, and tangents. The callback only integrates the constitutive equation in the supplied corotational material coordinates.

Advanced: derive directly from Mechanical3D

Deriving from Mechanical3D provides complete control but also transfers the constitutive lifecycle to the implementation. This route is appropriate when the response cannot be expressed by the UMAT contract, needs custom assembly state, or uses a specialized tangent representation.

A derived law is generally responsible for:

  • calling super().__init__(name=name, density=density);

  • declaring is_isotropic correctly;

  • allocating its state and initial assembly.sv["TangentMatrix"] in initialize;

  • reading assembly.sv["Strain"] and assembly.sv["DStrain"] and writing assembly.sv["Stress"] and assembly.sv["TangentMatrix"] in update;

  • implementing commit, rollback, and reset behavior through set_start, to_start, and reset when it owns history variables;

  • handling plane stress explicitly when that assumption is supported;

  • using the frame-transformation helpers supplied by Mechanical3D when the law is anisotropic;

  • setting _Lt_from_F only when the tangent follows deformation-gradient rather than strain-increment kinematics.

assembly.sv_start is a shallow beginning-of-increment snapshot. Do not modify arrays shared with it in place during a trial iteration. Replace trial arrays in assembly.sv or make explicit copies so that to_start can restore the committed state.

Direct Mechanical3D laws must also tolerate initialization before a positive time increment exists. They should always provide the initial tangent required to assemble the first global system. The implementations of fedoo.constitutivelaw.ElasticAnisotropic and the pedagogical fedoo.constitutivelaw.ElastoPlasticity provide useful references; the latter uses MechanicalUMAT for its lifecycle.