Event Guide
The Femora event system is an advanced runtime API for lifecycle-sensitive work. It exists so model-owned subsystems can react to assembly and export stages without hard-coding every extension directly into the core pipeline.
Most modeling workflows do not need this package directly. If you are defining ordinary materials, elements, loads, sections, or analyses, you can usually ignore it. This guide is for the cases where timing matters: when the right thing to do depends on whether the mesh has already been assembled, whether partition ownership has been resolved, or whether an export pipeline has started.
The Idea In One Sentence
Femora emits lifecycle events, and advanced components subscribe to those events when they need to react at exactly the right runtime stage.
What Happens Under The Hood
At a high level, the runtime flow is:
- a subsystem such as the assembler reaches a lifecycle boundary
- it emits a
FemoraEvent - the model-owned event bus dispatches payload data to subscribers
- subscribers inspect that payload and react
- the runtime continues to the next stage
In practice this means the event system is less about creating objects and more about coordinating when an advanced object is allowed to inspect or modify state.
The Most Important Lifecycle Stages
The most important practical events are:
-
PRE_ASSEMBLECalled before the final assembled mesh is built. Use this when something must be prepared before the assembly pipeline commits the final mesh state. -
POST_ASSEMBLECalled after the assembled mesh exists. This is the most important hook for advanced interfaces because the full model mesh can now be inspected. -
RESOLVE_CORE_CONFLICTSCalled after assembly when partition/core ownership updates may require follow-up work. -
PRE_EXPORT/POST_EXPORTCalled around export workflows. These are mainly useful for specialized export augmentation and compatibility layers.
When You Should Use Events
Use the event system when the right behavior depends on lifecycle timing, for example:
- generating extra interface mesh after the final assembled mesh exists
- pairing constrained and retained nodes after assembly
- creating constraints only after geometry relationships have been discovered
- reacting to partition-aware updates
- injecting custom export-time behavior
When You Should Not Use Events
Do not use the event system as a replacement for ordinary model construction. If a component can be created directly through a manager or configured entirely at construction time, that is usually the better design.
Minimal Subscription Example
from femora.core.model import Model
from femora.components.event.event_bus import FemoraEvent
model = Model()
def on_post_assemble(**payload):
assembled_mesh = payload.get("assembled_mesh")
if assembled_mesh is not None:
print(f"assembled cells: {assembled_mesh.n_cells}")
model.events.subscribe(FemoraEvent.POST_ASSEMBLE, on_post_assemble)
This kind of callback is appropriate for diagnostics, inspection, or small advanced extensions.
A More Realistic Femora Workflow
The more important use case is a model-owned advanced component.
For example, an interface component may:
- subscribe to
POST_ASSEMBLE - wait until the assembled mesh exists
- inspect nearby cells or nodes
- generate extra interface geometry or constraints
- register those additions with the owning model
That is why the event package also documents lifecycle mixins such as:
Those mixins are not end-user features by themselves. They describe the kind of lifecycle work an advanced component performs.
Where To Read Next
- Read
event busfor the actual event enum and subscription API. - Read the lifecycle mixin pages when you are implementing or studying an advanced interface-like component.