From 299711ba80446157d2c20b356912f9edf9cd9dd1 Mon Sep 17 00:00:00 2001 From: Guy Bowker PhD <61540494+Gbowker@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:56:48 +0000 Subject: [PATCH 1/3] Add script VE_from_laguerre.py For creating VEs with weighted dimensions. --- .../generate_volume_element_laguerre.py | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 matflow/data/scripts/damask/generate_volume_element_laguerre.py diff --git a/matflow/data/scripts/damask/generate_volume_element_laguerre.py b/matflow/data/scripts/damask/generate_volume_element_laguerre.py new file mode 100644 index 00000000..69eee396 --- /dev/null +++ b/matflow/data/scripts/damask/generate_volume_element_laguerre.py @@ -0,0 +1,127 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +import numpy as np +from numpy.typing import ArrayLike + +try: + from damask import GeomGrid as grid_cls +except ImportError: + from damask import Grid as grid_cls +from damask_parse.utils import validate_volume_element, validate_orientations + +if TYPE_CHECKING: + from matflow.param_classes.orientations import Orientations + from matflow.param_classes.seeds import MicrostructureSeeds + + +def generate_volume_element_laguerre( + microstructure_seeds: MicrostructureSeeds, + VE_grid_size: ArrayLike, + homog_label: str, + orientations: Orientations | None, + scale_morphology: ArrayLike | None, + weights: ArrayLike | None, + scale_update_size: bool, + periodic: bool, +) -> dict: + """ + Generate a volume element by Laguerre tessellation from a provided set of seeds. + + Parameters + ---------- + microstructure_seeds + Seeds for the crystals in the Laguerre tessellation. + VE_grid_size + Volume element grid size + homog_label + Homogenization scheme label. + orientations + Orientation data for the seeds. + scale_morphology + How to scale the morphology. + weights + Relative length of grains in principal directions respectively. + scale_update_size + Whether to update the grid size based on the morphology scaling. + periodic + Whether to use periodic boundary conditions on the tessellation. + Defaults to true. + """ + grid_obj = grid_cls.from_Laguerre_tessellation( + cells=np.array(VE_grid_size), + size=np.array(microstructure_seeds.box_size), + seeds=np.array(microstructure_seeds.position), + weights=np.array(weights), + periodic=periodic, + ) + + if scale_morphology is not None: + scale_morphology = np.array(scale_morphology) + + original_cells = grid_obj.cells + new_cells = original_cells * scale_morphology + grid_scaled = grid_obj.scale(new_cells) + + if scale_update_size: + original_size = grid_obj.size + new_size = original_size * scale_morphology + grid_scaled.size = new_size + + grid_obj = grid_scaled + + # TODO: this needs some more thought. + + if orientations is None: + orientations = microstructure_seeds.orientations + assert orientations is not None + # see `LatticeDirection` enum: + align_lookup = { + "A": "a", + "B": "b", + "C": "c", + "A_STAR": "a*", + "B_STAR": "b*", + "C_STAR": "c*", + } + unit_cell_alignment = { + "x": align_lookup[orientations.unit_cell_alignment.x.name], + "y": align_lookup[orientations.unit_cell_alignment.y.name], + "z": align_lookup[orientations.unit_cell_alignment.z.name], + } + type_lookup = { + "QUATERNION": "quat", + "EULER": "euler", + } + type_ = type_lookup[orientations.representation.type.name] + oris = { + "type": type_, + "unit_cell_alignment": unit_cell_alignment, + } + + if type_ == "quat": + quat_order = orientations.representation.quat_order.name.lower().replace("_", "-") + oris["quaternions"] = np.array(orientations.data) + oris["quat_component_ordering"] = quat_order + elif type_ == "euler": + oris["euler_angles"] = np.array(orientations.data) + oris["euler_degrees"] = orientations.representation.euler_is_degrees + + oris = validate_orientations(oris) + num_grains = len(microstructure_seeds.position) + const_phase_lab = np.array([microstructure_seeds.phase_label])[ + np.zeros(num_grains, dtype=int) + ] + ori_idx = np.arange(num_grains) + volume_element = { + "size": grid_obj.size.astype(float).tolist(), + "grid_size": grid_obj.cells.tolist(), + "orientations": oris, + "element_material_idx": grid_obj.material, + "constituent_material_idx": np.arange(num_grains), + "constituent_material_fraction": np.ones(num_grains), + "constituent_phase_label": const_phase_lab, + "constituent_orientation_idx": ori_idx, + "material_homog": np.full(num_grains, homog_label), + } + volume_element = validate_volume_element(volume_element) + return {"volume_element": volume_element} From aed48edae3819804e5d2868e47ab2d32f7694e5b Mon Sep 17 00:00:00 2001 From: Guy Bowker PhD <61540494+Gbowker@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:59:26 +0000 Subject: [PATCH 2/3] Add VE_from_laguerre to task schema Another option for creating VEs. --- .../template_components/task_schemas.yaml | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/matflow/data/template_components/task_schemas.yaml b/matflow/data/template_components/task_schemas.yaml index ab403464..fbc72427 100644 --- a/matflow/data/template_components/task_schemas.yaml +++ b/matflow/data/template_components/task_schemas.yaml @@ -182,6 +182,36 @@ type: any environment: damask_parse_env +- objective: generate_volume_element + doc: Generate a volume element from microstructure seeds using a Laguerre diagram. + method: from_laguerre + inputs: + - parameter: microstructure_seeds + - parameter: VE_grid_size + - parameter: homog_label + default_value: SX + - parameter: orientations + default_value: null + - parameter: scale_morphology + default_value: null + - parameter: weights + default_value: null + - parameter: scale_update_size + default_value: true + - parameter: periodic + default_value: true + outputs: + - parameter: volume_element + actions: + - script: <> + script_data_in: direct + script_data_out: direct + script_exe: python_script + environments: + - scope: + type: any + environment: damask_parse_env + - objective: visualise_VE doc: Visualise a volume element. method: VTK From 594054036eb02a55ab5f4001197069cc7abbed6b Mon Sep 17 00:00:00 2001 From: Guy Bowker PhD <61540494+Gbowker@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:00:46 +0000 Subject: [PATCH 3/3] Add weights for VE_from_laguerre method --- matflow/data/template_components/parameters.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/matflow/data/template_components/parameters.yaml b/matflow/data/template_components/parameters.yaml index 67cdc1f2..c2284950 100644 --- a/matflow/data/template_components/parameters.yaml +++ b/matflow/data/template_components/parameters.yaml @@ -454,6 +454,16 @@ - value.length.equal_to: 3 - path: [{ "type": "list_value" }] condition: { value.is_instance: [int, float] } +- type: weights + _validation: + - path: [] + doc: relative length of grains in each of the x, y(, z) directions. + condition: + and: + - value.is_instance: [list] + - value.length.in: [2, 3] + - path: [{ "type": "list_value" }] + condition: { value.is_instance: [int] } - type: resolution _validation: - path: []