External Mesh Morphing Integration#

This integration sends volume meshes to an external mesh morphing tool and returns deformed node coordinates to EMSolution. Separate from the general Python API list, this page describes the data contract, execution sequence, and constraints.

Warning

This function is at the proof-of-concept stage with schema versions 1 and 2. It is not a stable API until integration testing and compatibility policy for external tools are established. External tools must check the schema version and stop processing when they receive an unsupported version.

Overview#

For DEFORM regions, EMSolution passes the static volume mesh required by the external tool and node states for each step to Python. The external tool returns global absolute coordinates that already reflect RIGID motion. EMSolution uses these coordinates to assemble the deformation matrix.

  • Coordinate units are always m.

  • Coordinates use the global Cartesian XYZ coordinate system.

  • Return absolute coordinates after deformation, not displacement from reference coordinates.

  • For a step supplied with an external payload, the existing set_deformed_node_position() is not applied in addition.

Execution flow#

Immediately after initialization, obtain the static topology once and cache it in the external tool. At each step, obtain the current deformation state and return a payload. Use CoupledSession rather than module-level functions to manage the lifecycle.

import pyemsol

with pyemsol.CoupledSession(input_json, str(run_directory)) as session:
    # セッション中に変わらない体積メッシュ。最初のstepより前に1回だけ取得する。
    topology = session.describe_deformation_mesh()

    for end_time, delta_time, motion_state in time_steps:
        description = session.describe_deformation()
        deformation = morph_deformation(
            description, topology, motion_state, time=end_time
        )
        result = session.step(
            time=end_time,
            delta_time=delta_time,
            deformation=deformation,
        )

current_coordinates in describe_deformation() is updated after each step. The static topology does not need to be retrieved again until the session ends when immutable_during_session is True.

Python APIs used#

class CoupledSession(inputJson, run_directory)#

This is a session for external step analysis. When used in a with statement, close() is called at exit. Running multiple active analyses in the same process is not supported.

CoupledSession.describe_deformation() → dict#

Returns reference coordinates, target coordinates from existing linear deformation, and current coordinates for each DEFORM region. The current schema version is 1.

CoupledSession.describe_deformation_mesh() → dict#

Returns the static volume mesh and boundary roles for external morphing. The current schema version is 2.

CoupledSession.step(time, delta_time, inputs={}, deformation=None) → dict#

Executes one transient step. time is the previous end time plus delta_time, and delta_time must be positive and finite. When electrical coupling is also used, specify port inputs in inputs.

linear_deformation(description, position, *, mesh_revision=None) → dict#

This reference helper creates an absolute-coordinate payload equivalent to existing linear deformation rules. It can verify connection to an external tool, but general mesh morphing replaces it with an external-tool adapter. For one region, pass a numeric position; for multiple regions, pass {deform_id: position}.

Static mesh topology (schema version 2)#

Top-level structure returned by describe_deformation_mesh().

{
    "schema_version": 2,
    "enabled": True,
    "mesh_revision": 0,
    "unit": "m",
    "coordinate_frame": "global",
    "immutable_during_session": True,
    "regions": [...],
}
  • Each item in regions contains deform_id, motion_id, reference and target motion positions, return_node_ids, and mesh.

  • return_node_ids are the node IDs returned in the step payload, in the same order as node_ids for the same region in describe_deformation().

  • mesh.nodes contains ids, reference_coordinates, and roles; the same index identifies the same node.

  • mesh.volume_elements contains element_id, element_type_id, element_type, material_id, role, and node_ids. node_ids preserves EMSolution local node ordering.

There are three node roles:

  • deformable: volume region that deforms (internal MOTION_DEFORM).

  • rigid: region that moves while retaining its shape (internal MOTION_RIGID).

  • fixed: boundary node kept stationary by existing processing because it is shared with an outer fixed region.

Elements include only deformable and rigid roles; fixed elements for the entire model are not passed. Shared boundary nodes are included with the fixed role so the external tool can recognize fixed conditions. element_type is an EMSolution abbreviated name (for example, H1 or PR1). When converting to an external-tool-specific element type, map it in the adapter using element_type_id, node count, and local node order.

Dynamic deformation description (schema version 1)#

describe_deformation() returns node states used at each step.

{
    "schema_version": 1,
    "enabled": True,
    "mode": "absolute",
    "unit": "m",
    "coordinate_frame": "global_after_rigid",
    "regions": [
        {
            "deform_id": 1,
            "motion_id": 1,
            "position_pre_geom": 0.0,
            "position_deform_mesh": 0.24,
            "node_ids": [10, 11, 12],
            "reference_coordinates": [[...], [...], [...]],
            "target_coordinates": [[...], [...], [...]],
            "current_coordinates": [[...], [...], [...]],
        },
    ],
}

node_ids, reference_coordinates, target_coordinates, and current_coordinates use the same index for the same node. target_coordinates are target values for linear deformation by existing deform_mesh; they are not constraints on all nodes. Pass motion positions to the external tool from an external solver, a time function evaluated in Python, or higher-level coupling control code.

Payload returned by the external tool#

The external tool returns regions containing each DEFORM region exactly once.

deformation = {
    "mode": "absolute",
    "unit": "m",
    "coordinate_frame": "global_after_rigid",
    "mesh_revision": 25,  # 任意。結果へそのまま返される。
    "regions": [
        {
            "deform_id": 1,
            "node_ids": [10, 11, 12],
            "coordinates": [
                [-0.15, 0.50, 0.00],
                [-0.09, 0.51, 0.00],
                [-0.03, 0.50, 0.00],
            ],
        },
    ],
}

coordinates are global absolute coordinates with shape (N, 3). node_ids[i] and coordinates[i] identify the same node. Input order is arbitrary, but retain the order returned by description for debuggability and compatibility. Partial updates, renumbering node IDs, and returning displacements are not supported.

Even when NumPy is used internally, convert values to Python built-in types immediately before passing them to pyemsol.

region_payload = {
    "deform_id": int(deform_id),
    "node_ids": node_ids.astype(int).tolist(),
    "coordinates": coordinates.astype(float).tolist(),
}

Results and validation#

On success, the return value from step() includes deformation information such as the following.

result["deformation"] == {
    "mode": "absolute",
    "coordinate_frame": "global_after_rigid",
    "region_count": 1,
    "node_count": 548,
    "mesh_revision": 25,
}

EMSolution validates all regions before updating node coordinates. In the following cases, it raises an exception without advancing coordinates or analysis time.

  • There are no DEFORM regions, or the region count or deform_id values do not match.

  • mode, unit, or coordinate_frame differs from its specified value.

  • The length, target IDs, or number of XYZ components in node_ids or coordinates is invalid.

  • Duplicate, missing, or unknown node IDs; coordinates containing NaN or Inf; or values other than Python built-in types.

  • A model containing gap elements, or a model using Slide motion and external Deform simultaneously.

External-tool acceptance checks#

An adapter implementation must at least verify the following.

  1. Do not modify received description or topology destructively.

  2. For every deform_id, return all return_node_ids with no omissions or duplicates.

  3. Coordinates are finite global absolute coordinates in m and satisfy boundaries after RIGID motion and fixed boundaries.

  4. Return deterministic results for the same input.

  5. Return the expected shape in the reference state and complete the 40-step integration test using Deform_sample.

Calling describe_deformation() again after a step and comparing current_coordinates with the transmitted coordinates verifies coordinate transfer.

Current limitations#

  • Surface elements, periodic boundaries and sliding surfaces, and element quality metrics are not included in the topology API.

  • Element inversion, negative Jacobians, and volume changes are not checked for external coordinates.

  • Complete rollback on solver calculation failure and coordinate history for post-processing replay of nonlinear morphing are not implemented.

  • Coordinates for all applicable nodes must be returned at every step.