From f2b413850bf278b73af9b82dd34ba4abfdc4d620 Mon Sep 17 00:00:00 2001 From: Michael Atkinson Date: Tue, 26 Mar 2024 13:04:13 +0000 Subject: [PATCH 1/8] update: support damask v3 beta0 --- .../data/scripts/damask/generate_volume_element_voronoi.py | 4 ++-- matflow/data/scripts/damask/write_numerics.py | 1 + matflow/data/template_components/command_files.yaml | 2 +- matflow/data/template_components/task_schemas.yaml | 3 +-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/matflow/data/scripts/damask/generate_volume_element_voronoi.py b/matflow/data/scripts/damask/generate_volume_element_voronoi.py index 53228764..46ed5228 100644 --- a/matflow/data/scripts/damask/generate_volume_element_voronoi.py +++ b/matflow/data/scripts/damask/generate_volume_element_voronoi.py @@ -1,5 +1,5 @@ import numpy as np -from damask import Grid +from damask import GeomGrid from damask_parse.utils import validate_volume_element, validate_orientations @@ -11,7 +11,7 @@ def generate_volume_element_voronoi( scale_morphology, scale_update_size, ): - grid_obj = Grid.from_Voronoi_tessellation( + grid_obj = GeomGrid.from_Voronoi_tessellation( cells=np.array(VE_grid_size), size=np.array(microstructure_seeds.box_size), seeds=np.array(microstructure_seeds.position), diff --git a/matflow/data/scripts/damask/write_numerics.py b/matflow/data/scripts/damask/write_numerics.py index 10899f9d..59f1acb9 100644 --- a/matflow/data/scripts/damask/write_numerics.py +++ b/matflow/data/scripts/damask/write_numerics.py @@ -3,5 +3,6 @@ def write_numerics(path, damask_numerics): + damask_numerics = {} if damask_numerics is None else damask_numerics path = Path(path) write_numerics_(dir_path=path.parent, numerics=damask_numerics, name=path.name) diff --git a/matflow/data/template_components/command_files.yaml b/matflow/data/template_components/command_files.yaml index e7994878..be9dab37 100644 --- a/matflow/data/template_components/command_files.yaml +++ b/matflow/data/template_components/command_files.yaml @@ -18,7 +18,7 @@ name: stderr.log - label: damask_hdf5_file name: - name: geom_load.hdf5 + name: geom_load_material_numerics.hdf5 - label: damask_viz_files name: name: ((?:geom_load_inc\d+|static_outputs).vt(i|r)) diff --git a/matflow/data/template_components/task_schemas.yaml b/matflow/data/template_components/task_schemas.yaml index bd73045a..ecbacf82 100644 --- a/matflow/data/template_components/task_schemas.yaml +++ b/matflow/data/template_components/task_schemas.yaml @@ -537,10 +537,9 @@ script: <> rules: - path: inputs.damask_numerics - condition: { value.not_equal_to: null } abortable: true commands: - - command: <> --load load.yaml --geom geom.vti + - command: <> --load load.yaml --geom geom.vti --material material.yaml --numerics numerics.yaml stdout: stdout.log stderr: stderr.log output_file_parsers: From 887ec899557014d8f2ced2ef7280b78b6e7dcd48 Mon Sep 17 00:00:00 2001 From: Michael Atkinson Date: Wed, 17 Apr 2024 14:38:19 +0100 Subject: [PATCH 2/8] fix: writing empty damask numerics file --- matflow/data/scripts/damask/write_numerics.py | 7 ++++++- matflow/data/template_components/command_files.yaml | 2 +- matflow/data/template_components/task_schemas.yaml | 2 -- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/matflow/data/scripts/damask/write_numerics.py b/matflow/data/scripts/damask/write_numerics.py index 59f1acb9..39db56c3 100644 --- a/matflow/data/scripts/damask/write_numerics.py +++ b/matflow/data/scripts/damask/write_numerics.py @@ -3,6 +3,11 @@ def write_numerics(path, damask_numerics): - damask_numerics = {} if damask_numerics is None else damask_numerics path = Path(path) + + if damask_numerics is None: + with path.open('w') as f: + f.write('# empty\n') + return + write_numerics_(dir_path=path.parent, numerics=damask_numerics, name=path.name) diff --git a/matflow/data/template_components/command_files.yaml b/matflow/data/template_components/command_files.yaml index be9dab37..be67b955 100644 --- a/matflow/data/template_components/command_files.yaml +++ b/matflow/data/template_components/command_files.yaml @@ -21,7 +21,7 @@ name: geom_load_material_numerics.hdf5 - label: damask_viz_files name: - name: ((?:geom_load_inc\d+|static_outputs).vt(i|r)) + name: ((?:geom_load_material_numerics_inc\d+|static_outputs).vt(i|r)) is_regex: true - label: mtex_pole_figures name: diff --git a/matflow/data/template_components/task_schemas.yaml b/matflow/data/template_components/task_schemas.yaml index ecbacf82..eb88eab6 100644 --- a/matflow/data/template_components/task_schemas.yaml +++ b/matflow/data/template_components/task_schemas.yaml @@ -535,8 +535,6 @@ - input_file: damask_numerics_file from_inputs: [damask_numerics] script: <> - rules: - - path: inputs.damask_numerics abortable: true commands: - command: <> --load load.yaml --geom geom.vti --material material.yaml --numerics numerics.yaml From 66c3c7410b4b34f3e6e521bc9e759cf875caaf4f Mon Sep 17 00:00:00 2001 From: Michael Atkinson Date: Wed, 17 Apr 2024 14:39:13 +0100 Subject: [PATCH 3/8] feat: add multistep random loadcase with interpolation --- matflow/param_classes/load.py | 111 ++++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 6 deletions(-) diff --git a/matflow/param_classes/load.py b/matflow/param_classes/load.py index e63e659f..08ee6f9e 100644 --- a/matflow/param_classes/load.py +++ b/matflow/param_classes/load.py @@ -95,7 +95,9 @@ def __eq__(self, __value: object) -> bool: ): # check arrays: if self.stress is not None: - if __value.stress is None or not np.allclose(self.stress, __value.stress): + if __value.stress is None or not np.allclose( + self.stress, __value.stress + ): return False elif __value.stress is None: return False @@ -137,7 +139,9 @@ def _validate(self): self.target_def_grad = masked_array_from_list(self.target_def_grad) if isinstance(self.target_def_grad_rate, list): - self.target_def_grad_rate = masked_array_from_list(self.target_def_grad_rate) + self.target_def_grad_rate = masked_array_from_list( + self.target_def_grad_rate + ) if isinstance(self.target_vel_grad, list): self.target_vel_grad = masked_array_from_list(self.target_vel_grad) @@ -270,7 +274,9 @@ def uniaxial( raise ValueError(msg) dg_arr = np.ma.masked_array(np.zeros((3, 3)), mask=np.eye(3)) - stress_arr = np.ma.masked_array(np.zeros((3, 3)), mask=np.logical_not(np.eye(3))) + stress_arr = np.ma.masked_array( + np.zeros((3, 3)), mask=np.logical_not(np.eye(3)) + ) dg_arr[loading_dir_idx, loading_dir_idx] = def_grad_val dg_arr.mask[loading_dir_idx, loading_dir_idx] = False @@ -444,7 +450,8 @@ def plane_strain( strain_rate_mode = get_enum_by_name_or_val(StrainRateMode, strain_rate_mode) if ( - strain_rate_mode in (StrainRateMode.VEL_GRAD, StrainRateMode.VEL_GRAD_APPROX) + strain_rate_mode + in (StrainRateMode.VEL_GRAD, StrainRateMode.VEL_GRAD_APPROX) and target_def_grad_rate is None ): msg = ( @@ -499,7 +506,10 @@ def plane_strain( dg_arr.mask[zero_stress_dir_idx, zero_stress_dir_idx] = True stress_arr.mask[zero_stress_dir_idx, zero_stress_dir_idx] = False - if strain_rate_mode in (StrainRateMode.VEL_GRAD, StrainRateMode.VEL_GRAD_APPROX): + if strain_rate_mode in ( + StrainRateMode.VEL_GRAD, + StrainRateMode.VEL_GRAD_APPROX, + ): def_grad = None def_grad_rate = None vel_grad = dg_arr @@ -734,6 +744,47 @@ def random_3D( obj._method_args = _method_args return obj + @classmethod + def random_inc( + cls, + total_time: Union[int, float], + num_increments: int, + target_def_grad: float, + start_def_grad: Optional[np.typing.ArrayLike] = None, + dump_frequency: Optional[int] = 1, + ) -> LoadStep: + """Random load step continuing from a start point. + + Parameters + ---------- + total_time : float or int + Total simulation time. + num_increments + Number of simulation increments. + target_def_grad : float + Maximum of each deformation gradient component + start_def_grad : numpy.ndarray of shape (3, 3), optional + Starting deformation gradient of load step. Identity if not given. + dump_frequency : int, optional + By default, 1, meaning results are written out every increment. + """ + if start_def_grad is None: + start_def_grad = np.eye(3) + if start_def_grad.shape != (3, 3): + msg = "start_def_grad must be an array of shape (3, 3)" + raise ValueError(msg) + + dg_arr = np.copy(start_def_grad) + dg_arr += target_def_grad * np.where(np.random.random((3, 3)) > 0.5, 1.0, -1.0) + dg_arr /= np.cbrt(np.linalg.det(dg_arr)) + + return cls( + total_time=total_time, + num_increments=num_increments, + target_def_grad=dg_arr, + dump_frequency=dump_frequency, + ) + @classmethod def uniaxial_cyclic( cls, @@ -764,7 +815,8 @@ def uniaxial_cyclic( A = 2 * np.pi / cycle_time time = ( - np.linspace(0, 2 * np.pi, num=num_increments_per_cycle, endpoint=True) / A + np.linspace(0, 2 * np.pi, num=num_increments_per_cycle, endpoint=True) + / A ) sig = (sig_diff / 2) * np.sin(A * time) + sig_mean @@ -946,3 +998,50 @@ def multistep(cls, steps: List[Union[Dict, LoadStep]]) -> LoadCase: step_objs.append(LoadStep(**step_i)) return cls(steps=step_objs) + + @classmethod + def multistep_random_inc( + cls, + steps: List[Dict], + interpolate_steps: int, + interpolate_kind: Optional[Union[str, int]] = 3, + ) -> LoadCase: + """A load case with multiple steps. + + Parameters + ---------- + + """ + from scipy.interpolate import interp1d + + step_objs = [] + dg_arr = [np.eye(3)] + for step_i in steps: + step_i = copy.deepcopy(step_i) # don't mutate + repeats = step_i.pop("repeats", 1) + method = LoadStep.random_inc + for _ in range(repeats): + step_obj = method(**step_i, start_def_grad=dg_arr[-1]) + dg_arr.append(step_obj.target_def_grad) + step_objs.append(step_obj) + dg_arr = np.array(dg_arr) + + dg_interp = interp1d( + np.arange(len(dg_arr)) * interpolate_steps, + dg_arr, + kind=interpolate_kind, + axis=0, + ) + + step_objs_full = [] + for i, step_obj_i in enumerate(step_objs): + step_i = { + "total_time": step_obj_i.total_time / interpolate_steps, + "num_increments": int(step_obj_i.num_increments / interpolate_steps), + "dump_frequency": step_obj_i.dump_frequency, + } + for j in range(interpolate_steps): + dg = dg_interp(i * interpolate_steps + j + 1) + step_objs_full.append(LoadStep(**step_i, target_def_grad=dg)) + + return cls(steps=step_objs_full) From 1f54dd69f772ceac46e3d6cda6d15a27653abb3b Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 10 Nov 2025 12:38:03 +0000 Subject: [PATCH 4/8] fix: DAMASK command line for v3.0.2 --- matflow/data/scripts/damask/write_numerics.py | 4 ---- .../data/template_components/command_files.yaml | 4 ++-- matflow/data/template_components/task_schemas.yaml | 14 +++++++++++++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/matflow/data/scripts/damask/write_numerics.py b/matflow/data/scripts/damask/write_numerics.py index 39684d5d..a916840c 100644 --- a/matflow/data/scripts/damask/write_numerics.py +++ b/matflow/data/scripts/damask/write_numerics.py @@ -15,8 +15,4 @@ def write_numerics(path: Path | str, damask_numerics: dict): https://damask-multiphysics.org/documentation/file_formats/numerics.html """ path_ = Path(path) - if damask_numerics is None: - with path.open("w") as f: - f.write("# empty\n") - return write_numerics_(dir_path=path_.parent, numerics=damask_numerics, name=path_.name) diff --git a/matflow/data/template_components/command_files.yaml b/matflow/data/template_components/command_files.yaml index 49ac2a34..9c181f30 100644 --- a/matflow/data/template_components/command_files.yaml +++ b/matflow/data/template_components/command_files.yaml @@ -30,12 +30,12 @@ - label: damask_hdf5_file name: - name: geom_load_material_numerics.hdf5 + name: geom_load.hdf5 doc: DAMASK geometry description, as HDF5. - label: damask_viz_files name: - name: ((?:geom_load_material_numerics_inc\d+|static_outputs).vt(i|r)) + name: ((?:geom_load_inc\d+|static_outputs).vt(i|r)) is_regex: true doc: DAMASK output visualisation data pattern. diff --git a/matflow/data/template_components/task_schemas.yaml b/matflow/data/template_components/task_schemas.yaml index d64640ae..7573be99 100644 --- a/matflow/data/template_components/task_schemas.yaml +++ b/matflow/data/template_components/task_schemas.yaml @@ -701,11 +701,23 @@ - input_file: damask_numerics_file from_inputs: [damask_numerics] script: <> + rules: + - path: inputs.damask_numerics + condition: { value.not_equal_to: null } abortable: true commands: - - command: <> --load load.yaml --geom geom.vti --material material.yaml --numerics numerics.yaml + - command: <> --jobname geom_load --load load.yaml --geom geom.vti --material material.yaml --numerics numerics.yaml stdout: stdout.log stderr: stderr.log + rules: + - path: inputs.damask_numerics + condition: { value.not_equal_to: null } + - command: <> --jobname geom_load --load load.yaml --geom geom.vti --material material.yaml + stdout: stdout.log + stderr: stderr.log + rules: + - path: inputs.damask_numerics + condition: { value.equal_to: null } output_file_parsers: damask_log: from_files: [damask_stdout_file] From 8a84d1654374ee9abb7da75749eace1e5bafb165 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 10 Nov 2025 13:07:35 +0000 Subject: [PATCH 5/8] fix: update damask high-concurrency schema --- .../damask/high_concurrency/process_HDF5.py | 5 ++++ .../high_concurrency/write_input_files.py | 16 +++++++++--- .../template_components/task_schemas.yaml | 25 ++++++++++++++++--- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/matflow/data/scripts/damask/high_concurrency/process_HDF5.py b/matflow/data/scripts/damask/high_concurrency/process_HDF5.py index ed90665b..b492ee5e 100644 --- a/matflow/data/scripts/damask/high_concurrency/process_HDF5.py +++ b/matflow/data/scripts/damask/high_concurrency/process_HDF5.py @@ -9,6 +9,7 @@ def process_HDF5( damask_post_processing: list[dict], VE_response_data: dict, damask_viz: list[dict] | dict | bool | None, + remove_damask_hdf5: bool, ): """ Operate on and extract data from an HDF5 file generated by a DAMASK run. @@ -165,4 +166,8 @@ def process_HDF5( ) generate_viz(hdf5_path=damask_hdf5_file, viz_spec=damask_viz, parsed_outs=VE_response) + # remove damask HDF5 file (TODO: needs to be a better way to do this in hpcflow) + if remove_damask_hdf5: + damask_hdf5_file.unlink() + return VE_response diff --git a/matflow/data/scripts/damask/high_concurrency/write_input_files.py b/matflow/data/scripts/damask/high_concurrency/write_input_files.py index 2e98b6d9..4dfe40ca 100644 --- a/matflow/data/scripts/damask/high_concurrency/write_input_files.py +++ b/matflow/data/scripts/damask/high_concurrency/write_input_files.py @@ -1,7 +1,7 @@ from __future__ import annotations import copy from pathlib import Path -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any from damask import __version__ as damask_version from damask_parse.writers import write_geom, write_load_case, write_material @@ -20,6 +20,7 @@ def write_input_files( damask_phases: dict, single_crystal_parameters: dict | None, damask_numerics: dict | None, + initial_conditions: dict[str, Any] | None, ): """ Write all the input files to DAMASK. @@ -45,7 +46,7 @@ def write_input_files( https://damask-multiphysics.org/documentation/file_formats/numerics.html """ geom_path = Path(path) - _write_geom(geom_path, volume_element) + _write_geom(geom_path, volume_element, initial_conditions=initial_conditions) _write_load(load_case, damask_solver) _write_material( volume_element, @@ -57,8 +58,15 @@ def write_input_files( _write_numerics(damask_numerics) -def _write_geom(path: Path, volume_element: dict): - write_geom(dir_path=path.parent, volume_element=volume_element, name=path.name) +def _write_geom( + path: Path, volume_element: dict, initial_conditions: dict[str, Any] | None +): + write_geom( + dir_path=path.parent, + volume_element=volume_element, + name=path.name, + initial_conditions=initial_conditions, + ) def _write_load(load_case: LoadCase, damask_solver: dict[str, str]): diff --git a/matflow/data/template_components/task_schemas.yaml b/matflow/data/template_components/task_schemas.yaml index 7573be99..84302eff 100644 --- a/matflow/data/template_components/task_schemas.yaml +++ b/matflow/data/template_components/task_schemas.yaml @@ -770,6 +770,10 @@ default_value: null - parameter: damask_numerics default_value: null + - parameter: remove_damask_hdf5 + default_value: false + - parameter: initial_conditions + default_value: null outputs: - parameter: VE_response actions: @@ -790,18 +794,33 @@ - damask_phases - single_crystal_parameters - damask_numerics + - initial_conditions script: <> abortable: true commands: - - command: <> --load load.yaml --geom geom.vti + - command: <> --jobname geom_load --load load.yaml --geom geom.vti --material material.yaml --numerics numerics.yaml stdout: stdout.log stderr: stderr.log + rules: + - path: inputs.damask_numerics + condition: { value.not_equal_to: null } + - command: <> --jobname geom_load --load load.yaml --geom geom.vti --material material.yaml + stdout: stdout.log + stderr: stderr.log + rules: + - path: inputs.damask_numerics + condition: { value.equal_to: null } output_file_parsers: VE_response: # this generates VTK files as well if requested from_files: [damask_hdf5_file] - save_files: false + save_files: [damask_viz_files] + clean_up: [damask_viz_files] script: <> - inputs: [damask_post_processing, VE_response_data, damask_viz] + inputs: + - damask_post_processing + - VE_response_data + - damask_viz + - remove_damask_hdf5 - objective: read_tensile_test doc: Read tensile test data from CSV. From 7c28c57c6fcd9cfdd6907d618d39cfa34ee5c3f1 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 10 Nov 2025 14:49:33 +0000 Subject: [PATCH 6/8] feat: continue supporting DAMASK v3.0.0-alpha7 (requires https://github.com/hpcflow/hpcflow-new/pull/892) --- matflow/data/template_components/task_schemas.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/matflow/data/template_components/task_schemas.yaml b/matflow/data/template_components/task_schemas.yaml index 84302eff..62ad46b0 100644 --- a/matflow/data/template_components/task_schemas.yaml +++ b/matflow/data/template_components/task_schemas.yaml @@ -718,6 +718,13 @@ rules: - path: inputs.damask_numerics condition: { value.equal_to: null } + - command: <> --load load.yaml --geom geom.vti + stdout: stdout.log + stderr: stderr.log + rules: + - path: resources.environments.damask_env.version + default: false + condition: { value.equal_to: 3.0.0-alpha7 } output_file_parsers: damask_log: from_files: [damask_stdout_file] From 896b80196d48b9bdccb9de6106cdc2bb7e422d51 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 10 Nov 2025 15:27:13 +0000 Subject: [PATCH 7/8] fix: combining support for old and new DAMASK --- matflow/data/template_components/task_schemas.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/matflow/data/template_components/task_schemas.yaml b/matflow/data/template_components/task_schemas.yaml index 62ad46b0..3092324c 100644 --- a/matflow/data/template_components/task_schemas.yaml +++ b/matflow/data/template_components/task_schemas.yaml @@ -712,12 +712,18 @@ rules: - path: inputs.damask_numerics condition: { value.not_equal_to: null } + - path: resources.environments.damask_env.version + default: true + condition: { value.not_equal_to: 3.0.0-alpha7 } - command: <> --jobname geom_load --load load.yaml --geom geom.vti --material material.yaml stdout: stdout.log stderr: stderr.log rules: - path: inputs.damask_numerics condition: { value.equal_to: null } + - path: resources.environments.damask_env.version + default: true + condition: { value.not_equal_to: 3.0.0-alpha7 } - command: <> --load load.yaml --geom geom.vti stdout: stdout.log stderr: stderr.log From 8de939da1afe0fb3f18b6daa87378b4c1ecf717e Mon Sep 17 00:00:00 2001 From: hpcflow-actions Date: Mon, 10 Nov 2025 18:46:05 +0000 Subject: [PATCH 8/8] feat: bump hpcflow version --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index 4240918d..ce07925c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1313,14 +1313,14 @@ numpy = ">=1.19.3" [[package]] name = "hpcflow-new2" -version = "0.2.0a261" +version = "0.2.0a262" description = "Computational workflow management" optional = false python-versions = "<3.14,>=3.9" groups = ["main"] files = [ - {file = "hpcflow_new2-0.2.0a261-py3-none-any.whl", hash = "sha256:0ea203bb2be7e0a3aa8b531eff62b7f104f78782235f39e56f97a1b9f2e0df71"}, - {file = "hpcflow_new2-0.2.0a261.tar.gz", hash = "sha256:224d66daa5df50ebd4d8e609c466681514e978b0bcec341618ccff62b70f50a9"}, + {file = "hpcflow_new2-0.2.0a262-py3-none-any.whl", hash = "sha256:61e97fa149c37129c2fba26504d526c4c024ec857b20d5391836ceaa9c314cfb"}, + {file = "hpcflow_new2-0.2.0a262.tar.gz", hash = "sha256:3db7d58b15848d3f6dbb12687aaceb2cb8120f7e3df50c460e93e8af3a8307df"}, ] [package.dependencies] @@ -4896,4 +4896,4 @@ test = ["pytest"] [metadata] lock-version = "2.1" python-versions = ">=3.9,<3.14" -content-hash = "f14863ad8e34346ca0340c9403192a92eb9d3490d1dcefc74e480b7e8184bc55" +content-hash = "26f1a692685c342da36245e2c591899cb46886253d06e2f3636b971c487dea39" diff --git a/pyproject.toml b/pyproject.toml index affeebeb..858a9613 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ numpy = [ # copied from hpcflow, shouldn't really be needed? pytest = {version = "^7.2.0", optional = true} matplotlib = "^3.7" typing-extensions = "^4.12.2" -hpcflow-new2 = "0.2.0a261" +hpcflow-new2 = "0.2.0a262" [tool.poetry.group.dev.dependencies] pylint = "^2.12.2"