From c65eeb4ef37bacf77861c72f6b3fe08f284bf3e0 Mon Sep 17 00:00:00 2001 From: jvonrick Date: Thu, 16 Nov 2023 15:12:41 +0100 Subject: [PATCH 01/12] Add support for plots on reference surfaces --- examples/008_assembly_example.py | 12 +- .../dpf/composites/_composite_model_impl.py | 107 +- .../_composite_model_impl_2023r2.py | 3 + src/ansys/dpf/composites/composite_model.py | 9 +- src/ansys/dpf/composites/constants.py | 21 +- .../layup_info/_reference_surface.py | 36 + .../composites/server_helpers/_versions.py | 1 + tests/composite_model_test.py | 103 +- .../multiple_time_steps/MatML.xml | 1320 +++++++++++++++++ .../Setup/ACPCompositeDefinitions.h5 | Bin 0 -> 46176 bytes .../multiple_time_steps/file.rst | Bin 0 -> 393216 bytes 11 files changed, 1599 insertions(+), 13 deletions(-) create mode 100644 src/ansys/dpf/composites/layup_info/_reference_surface.py create mode 100644 tests/data/workflow_example/multiple_time_steps/MatML.xml create mode 100644 tests/data/workflow_example/multiple_time_steps/Setup/ACPCompositeDefinitions.h5 create mode 100644 tests/data/workflow_example/multiple_time_steps/file.rst diff --git a/examples/008_assembly_example.py b/examples/008_assembly_example.py index 3f67eaf44..cd32ba836 100644 --- a/examples/008_assembly_example.py +++ b/examples/008_assembly_example.py @@ -47,11 +47,21 @@ # %% # Plot IRF # ~~~~~~~~ -# Plot the maximum IRF per element. +# Plot the maximum IRF per (solid) element. output_all_elements = composite_model.evaluate_failure_criteria(combined_criterion=combined_fc) irf_field = output_all_elements.get_field({"failure_label": FailureOutput.FAILURE_VALUE}) irf_field.plot() +# %% +# Plot IRF +# ~~~~~~~~ +# Plot the maximum IRF on the reference surface +irf_field = output_all_elements.get_field( + {"failure_label": FailureOutput.FAILURE_VALUE_REF_SURFACE} +) +irf_field.plot() + + # %% # Get element information # ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/ansys/dpf/composites/_composite_model_impl.py b/src/ansys/dpf/composites/_composite_model_impl.py index dc6c0acb0..b63eb9405 100644 --- a/src/ansys/dpf/composites/_composite_model_impl.py +++ b/src/ansys/dpf/composites/_composite_model_impl.py @@ -11,6 +11,7 @@ from numpy.typing import NDArray from .composite_scope import CompositeScope +from .constants import FAILURE_LABEL, REF_SURFACE_NAME, TIME_LABEL, FailureOutput from .data_sources import ( CompositeDataSources, ContinuousFiberCompositesFiles, @@ -24,11 +25,18 @@ add_layup_info_to_mesh, get_element_info_provider, ) +from .layup_info._reference_surface import ( + _get_map_to_reference_surface_operator, + _get_reference_surface_and_mapping_field, +) from .layup_info.material_operators import MaterialOperators, get_material_operators from .layup_info.material_properties import MaterialProperty, get_constant_property_dict from .result_definition import FailureMeasureEnum from .sampling_point import SamplingPointNew -from .server_helpers import upload_continuous_fiber_composite_files_to_server +from .server_helpers import ( + upload_continuous_fiber_composite_files_to_server, + version_equal_or_later, +) from .unit_system import get_unit_system @@ -50,6 +58,66 @@ def inner(*args: Sequence[Any], **kwargs: Sequence[Any]) -> Any: return inner +def _merge_containers( + non_ref_surface_container: FieldsContainer, ref_surface_container: FieldsContainer +) -> FieldsContainer: + """ + Merge the results fields container. + + Merges the results fields container of the non-reference surface and the reference surface. + """ + assert sorted(non_ref_surface_container.labels) == sorted(ref_surface_container.labels) + + ref_surface_time_ids = ref_surface_container.get_available_ids_for_label(TIME_LABEL) + non_ref_surface_time_ids = non_ref_surface_container.get_available_ids_for_label(TIME_LABEL) + + assert sorted(ref_surface_time_ids) == sorted(non_ref_surface_time_ids) + + out_container = dpf.FieldsContainer() + out_container.labels = [TIME_LABEL, FAILURE_LABEL] + out_container.time_freq_support = non_ref_surface_container.time_freq_support + + def add_to_output_container(time_id: int, source_container: FieldsContainer) -> FieldsContainer: + fields = source_container.get_fields({TIME_LABEL: time_id}) + for field in fields: + failure_enum = _get_failure_enum_from_name(field.name) + out_container.add_field({TIME_LABEL: time_id, FAILURE_LABEL: failure_enum}, field) + + for current_time_id in ref_surface_time_ids: + add_to_output_container(current_time_id, ref_surface_container) + add_to_output_container(current_time_id, non_ref_surface_container) + + return out_container + + +def _get_failure_enum_from_name(name: str) -> FailureOutput: + if name.startswith("Failure Mode"): + if name.endswith(REF_SURFACE_NAME): + return FailureOutput.FAILURE_MODE_REF_SURFACE + else: + return FailureOutput.FAILURE_MODE + + if name.startswith("IRF") or name.startswith("SF") or name.startswith("SM"): + if name.endswith(REF_SURFACE_NAME): + return FailureOutput.FAILURE_VALUE_REF_SURFACE + else: + return FailureOutput.FAILURE_VALUE + + if name.startswith("Layer Index"): + return FailureOutput.MAX_LAYER_INDEX + + if name.startswith("Global Layer in Stack"): + return FailureOutput.MAX_GLOBAL_LAYER_IN_STACK + + if name.startswith("Local Layer in Element"): + return FailureOutput.MAX_LOCAL_LAYER_IN_ELEMENT + + if name.startswith("Solid Element Id"): + return FailureOutput.MAX_SOLID_ELEMENT_ID + + raise RuntimeError("Could not determine failure output from name: " + name) + + class CompositeModelImpl: """Provides access to the basic composite postprocessing functionality. @@ -108,6 +176,15 @@ def __init__( unit_system=self._unit_system, ) + self._reference_surface_and_mapping_field = _get_reference_surface_and_mapping_field( + data_sources=self.data_sources.composite, unit_system=self._unit_system + ) + + self._map_to_reference_surface_operator = _get_map_to_reference_surface_operator( + reference_surface_and_mapping_field=self._reference_surface_and_mapping_field, + element_layer_indices_field=self.get_mesh().property_field("element_layer_indices"), + ) + self._element_info_provider = get_element_info_provider( mesh=self.get_mesh(), stream_provider_or_data_source=self._get_rst_streams_provider(), @@ -270,7 +347,7 @@ def evaluate_failure_criteria( scope_config_reader_op.inputs.ply_ids(selected_plies_op.outputs.strings) # configure operator to chunk the scope - chunking_data_tree = dpf.DataTree({"max_chunk_size": 50000}) + chunking_data_tree = dpf.DataTree({"max_chunk_size": max_chunk_size}) if ns_in: chunking_data_tree.add({"named_selections": ns_in}) @@ -380,10 +457,30 @@ def evaluate_failure_criteria( "No output is generated! Please check the scope (element and ply ids)." ) - if measure == FailureMeasureEnum.INVERSE_RESERVE_FACTOR: - return max_merger.outputs.merged_fields_container() + # Todo we need to update this version once the prerelease version bump has happened + if version_equal_or_later(self._server, "7.1"): + self._map_to_reference_surface_operator.inputs.min_container( + min_merger.outputs.merged_fields_container() + ) + self._map_to_reference_surface_operator.inputs.max_container( + max_merger.outputs.merged_fields_container() + ) + + if measure == FailureMeasureEnum.INVERSE_RESERVE_FACTOR: + return _merge_containers( + max_merger.outputs.merged_fields_container(), + self._map_to_reference_surface_operator.outputs.max_container(), + ) + else: + return _merge_containers( + min_merger.outputs.merged_fields_container(), + self._map_to_reference_surface_operator.outputs.min_container(), + ) else: - return min_merger.outputs.merged_fields_container() + if measure == FailureMeasureEnum.INVERSE_RESERVE_FACTOR: + return max_merger.outputs.merged_fields_container() + else: + return min_merger.outputs.merged_fields_container() @_deprecated_composite_definition_label def get_sampling_point( diff --git a/src/ansys/dpf/composites/_composite_model_impl_2023r2.py b/src/ansys/dpf/composites/_composite_model_impl_2023r2.py index 9af9e6db2..aac48f719 100644 --- a/src/ansys/dpf/composites/_composite_model_impl_2023r2.py +++ b/src/ansys/dpf/composites/_composite_model_impl_2023r2.py @@ -225,6 +225,7 @@ def evaluate_failure_criteria( composite_scope: Optional[CompositeScope] = None, measure: FailureMeasureEnum = FailureMeasureEnum.INVERSE_RESERVE_FACTOR, write_data_for_full_element_scope: bool = True, + max_chunk_size: int = 50000, ) -> FieldsContainer: """Get a fields container with the evaluated failure criteria. @@ -249,6 +250,8 @@ def evaluate_failure_criteria( part of ``composite_scope.plies``. If no element scope is specified (``composite_scope.elements``), a (potentially zero) failure value is written for all elements. + max_chunk_size: + A higher value results in more memory consumption, but faster evaluation. .. note:: diff --git a/src/ansys/dpf/composites/composite_model.py b/src/ansys/dpf/composites/composite_model.py index c369601d4..0573e16d3 100644 --- a/src/ansys/dpf/composites/composite_model.py +++ b/src/ansys/dpf/composites/composite_model.py @@ -147,6 +147,7 @@ def evaluate_failure_criteria( composite_scope: Optional[CompositeScope] = None, measure: FailureMeasureEnum = FailureMeasureEnum.INVERSE_RESERVE_FACTOR, write_data_for_full_element_scope: bool = True, + max_chunk_size: int = 50000, ) -> FieldsContainer: """Get a fields container with the evaluated failure criteria. @@ -171,6 +172,8 @@ def evaluate_failure_criteria( part of ``composite_scope.plies``. If no element scope is specified (``composite_scope.elements``), a (potentially zero) failure value is written for all elements. + max_chunk_size: + A higher value results in more memory consumption, but faster evaluation. .. note:: @@ -179,7 +182,11 @@ def evaluate_failure_criteria( """ return self._implementation.evaluate_failure_criteria( - combined_criterion, composite_scope, measure, write_data_for_full_element_scope + combined_criterion, + composite_scope, + measure, + write_data_for_full_element_scope, + max_chunk_size, ) def get_sampling_point( diff --git a/src/ansys/dpf/composites/constants.py b/src/ansys/dpf/composites/constants.py index 11f59abef..e7d8f7205 100644 --- a/src/ansys/dpf/composites/constants.py +++ b/src/ansys/dpf/composites/constants.py @@ -1,8 +1,17 @@ """Collection of constants used across PyDPF Composites.""" - from enum import IntEnum -__all__ = ("Spot", "Sym3x3TensorComponent", "FailureOutput") +__all__ = ( + "Spot", + "Sym3x3TensorComponent", + "FailureOutput", + "REF_SURFACE_NAME", + "FAILURE_LABEL", + "TIME_LABEL", +) + +FAILURE_LABEL = "failure_label" +TIME_LABEL = "time" class Spot(IntEnum): @@ -33,3 +42,11 @@ class FailureOutput(IntEnum): FAILURE_MODE = 0 FAILURE_VALUE = 1 MAX_LAYER_INDEX = 2 + FAILURE_MODE_REF_SURFACE = 3 + FAILURE_VALUE_REF_SURFACE = 4 + MAX_GLOBAL_LAYER_IN_STACK = 5 + MAX_LOCAL_LAYER_IN_ELEMENT = 6 + MAX_SOLID_ELEMENT_ID = 7 + + +REF_SURFACE_NAME = "Reference Surface" diff --git a/src/ansys/dpf/composites/layup_info/_reference_surface.py b/src/ansys/dpf/composites/layup_info/_reference_surface.py new file mode 100644 index 000000000..e0a8eec58 --- /dev/null +++ b/src/ansys/dpf/composites/layup_info/_reference_surface.py @@ -0,0 +1,36 @@ +from dataclasses import dataclass + +from ansys.dpf.core import DataSources, Field, Operator, PropertyField + +from ansys.dpf.composites.unit_system import UnitSystemProvider + + +@dataclass(frozen=True) +class _ReferenceSurfaceMeshAndMappingField: + mesh: Field + mapping_field: Field + + +def _get_reference_surface_and_mapping_field( + data_sources: DataSources, unit_system: UnitSystemProvider +) -> _ReferenceSurfaceMeshAndMappingField: + ref_surface_operator = Operator("composite::reference_surface_operator") + ref_surface_operator.inputs.data_sources.connect(data_sources) + ref_surface_operator.inputs.unit_system.connect(unit_system) + return _ReferenceSurfaceMeshAndMappingField( + mesh=ref_surface_operator.outputs.mesh(), + mapping_field=ref_surface_operator.outputs.mapping_field(), + ) + + +def _get_map_to_reference_surface_operator( + reference_surface_and_mapping_field: _ReferenceSurfaceMeshAndMappingField, + element_layer_indices_field: PropertyField, +) -> Operator: + map_to_reference_surface_operator = Operator("composite::map_to_reference_surface_operator") + map_to_reference_surface_operator.inputs.mapping_field.connect( + reference_surface_and_mapping_field.mapping_field + ) + map_to_reference_surface_operator.inputs.mesh.connect(reference_surface_and_mapping_field.mesh) + map_to_reference_surface_operator.inputs.layers_per_element.connect(element_layer_indices_field) + return map_to_reference_surface_operator diff --git a/src/ansys/dpf/composites/server_helpers/_versions.py b/src/ansys/dpf/composites/server_helpers/_versions.py index 0f5542f6c..2902ec334 100644 --- a/src/ansys/dpf/composites/server_helpers/_versions.py +++ b/src/ansys/dpf/composites/server_helpers/_versions.py @@ -14,6 +14,7 @@ class _DpfVersionInfo: _DPF_VERSIONS: dict[str, _DpfVersionInfo] = { "5.0": _DpfVersionInfo("5.0", "2023 R1", "Initial release of DPF Composites."), "7.0": _DpfVersionInfo("7.0", "2024 R1", "DPF Composites plugin with sub-operators."), + "7.1": _DpfVersionInfo("7.1", "2024 R2 pre 0", "Reference surface support"), } diff --git a/tests/composite_model_test.py b/tests/composite_model_test.py index 421ba9f5b..f400ec5eb 100644 --- a/tests/composite_model_test.py +++ b/tests/composite_model_test.py @@ -4,13 +4,17 @@ import pytest from ansys.dpf.composites.composite_model import CompositeModel, CompositeScope -from ansys.dpf.composites.constants import FailureOutput +from ansys.dpf.composites.constants import FAILURE_LABEL, FailureOutput from ansys.dpf.composites.data_sources import ( CompositeDefinitionFiles, ContinuousFiberCompositesFiles, get_composite_files_from_workbench_result_folder, ) -from ansys.dpf.composites.failure_criteria import CombinedFailureCriterion, MaxStressCriterion +from ansys.dpf.composites.failure_criteria import ( + CombinedFailureCriterion, + FailureModeEnum, + MaxStressCriterion, +) from ansys.dpf.composites.layup_info import LayerProperty, get_analysis_ply_index_to_name_map from ansys.dpf.composites.layup_info.material_properties import MaterialProperty from ansys.dpf.composites.result_definition import FailureMeasureEnum @@ -100,6 +104,37 @@ def test_basic_functionality_of_composite_model(dpf_server, data_files, distribu timer.summary() +def test_model_with_multiple_timesteps(dpf_server): + TEST_DATA_ROOT_DIR = ( + pathlib.Path(__file__).parent / "data" / "workflow_example" / "multiple_time_steps" + ) + + data_files = get_composite_files_from_workbench_result_folder(TEST_DATA_ROOT_DIR) + + composite_model = CompositeModel(data_files, server=dpf_server) + + combined_failure_criterion = CombinedFailureCriterion( + "max stress", failure_criteria=[MaxStressCriterion()] + ) + + expected_data_by_time_index = { + 0: {1: 1.47927903, 2: 1.47927903, 3: 1.3673715, 4: 1.3673715}, + 1: {1: 0.09834992, 2: 0.09834992, 3: 0.06173922, 4: 0.06173922}, + } + + for time_index, time in enumerate(composite_model.get_result_times_or_frequencies()): + failure_output = composite_model.evaluate_failure_criteria( + combined_criterion=combined_failure_criterion, + composite_scope=CompositeScope(time=time), + ) + + # Note evaluate_failure_criteria supports only a single time step + irf_field = failure_output.get_field({"failure_label": FailureOutput.FAILURE_VALUE}) + + for element_id, expected_value in expected_data_by_time_index[time_index].items(): + assert irf_field.get_entity_data_by_id(element_id) == pytest.approx(expected_value) + + def test_assembly_model(dpf_server): """Verify the handling of assemblies.""" @@ -127,6 +162,12 @@ def test_assembly_model(dpf_server): ) timer.add("After get failure output") + + def check_output(failure_label: FailureOutput, expected_output: dict[int, float]): + for element_id, expected_value in expected_output.items(): + failure_field = failure_output.get_field({FAILURE_LABEL: failure_label}) + assert failure_field.get_entity_data_by_id(element_id) == pytest.approx(expected_value) + expected_output = { 1: 1.11311715, 2: 1.11311715, @@ -137,9 +178,63 @@ def test_assembly_model(dpf_server): 9: 0.62122959, 10: 0.62122959, } + check_output(FailureOutput.FAILURE_VALUE, expected_output) + + expected_modes = { + 1: FailureModeEnum.s1t.value, + 2: FailureModeEnum.s1t.value, + 5: FailureModeEnum.s2t.value, + 6: FailureModeEnum.s2t.value, + 7: FailureModeEnum.na.value, + 8: FailureModeEnum.na.value, + 9: FailureModeEnum.s2t.value, + 10: FailureModeEnum.s2t.value, + } + check_output(FailureOutput.FAILURE_MODE, expected_modes) + + expected_layer_index = { + 1: 2, + 2: 2, + 5: 2, + 6: 2, + 7: 1, + 8: 1, + 9: 1, + 10: 1, + } + check_output(FailureOutput.MAX_LAYER_INDEX, expected_layer_index) - for element_id, expected_value in expected_output.items(): - assert failure_output[1].get_entity_data_by_id(element_id) == pytest.approx(expected_value) + expected_output_ref_surface = { + 1: 1.85777034, + 2: 1.85777034, + 3: 1.11311715, + 4: 1.11311715, + } + check_output(FailureOutput.FAILURE_VALUE_REF_SURFACE, expected_output_ref_surface) + + expected_output_local_layer = { + 1: 2, + 2: 2, + 3: 2, + 4: 2, + } + check_output(FailureOutput.MAX_LOCAL_LAYER_IN_ELEMENT, expected_output_local_layer) + + expected_output_global_layer = { + 1: 2, + 2: 2, + 3: 2, + 4: 2, + } + check_output(FailureOutput.MAX_GLOBAL_LAYER_IN_STACK, expected_output_global_layer) + + expected_output_solid_element = { + 1: 5, + 2: 6, + 3: 1, + 4: 2, + } + check_output(FailureOutput.MAX_SOLID_ELEMENT_ID, expected_output_solid_element) property_dict = composite_model.get_constant_property_dict( [MaterialProperty.Stress_Limits_Xt], composite_definition_label=solid_label diff --git a/tests/data/workflow_example/multiple_time_steps/MatML.xml b/tests/data/workflow_example/multiple_time_steps/MatML.xml new file mode 100644 index 000000000..7af008ea0 --- /dev/null +++ b/tests/data/workflow_example/multiple_time_steps/MatML.xml @@ -0,0 +1,1320 @@ + + + + + + + + + Epoxy Carbon Woven (230 GPa) Wet + + Composite + + + - + Temperature + Density + + Interpolation Options + Linear Multivariate (Qhull) + True + True + Projection to the Bounding Box + AlgorithmType$$Linear Multivariate (CGAL)$$EngineeringData.CGAL + Interpolation Options + + + 1451 + Dependent + Density + + + + - + ACP + Woven + Ply Type + + + - + Orthotropic + Temperature + Orthotropic Elasticity + + Interpolation Options + Linear Multivariate (Qhull) + True + True + Projection to the Bounding Box + AlgorithmType$$Linear Multivariate (CGAL)$$EngineeringData.CGAL + Interpolation Options + + + 59160000000 + Dependent + Young's Modulus X direction + + + 59160000000 + Dependent + Young's Modulus Y direction + + + 7500000000 + Dependent + Young's Modulus Z direction + + + 0.04 + Dependent + Poisson's Ratio XY + + + 0.3 + Dependent + Poisson's Ratio YZ + + + 0.3 + Dependent + Poisson's Ratio XZ + + + 3300000000 + Dependent + Shear Modulus XY + + + 2700000000 + Dependent + Shear Modulus YZ + + + 2700000000 + Dependent + Shear Modulus XZ + + + + - + Orthotropic + Temperature + Orthotropic Strain Limits + + Interpolation Options + Linear Multivariate (Qhull) + True + True + Projection to the Bounding Box + AlgorithmType$$Linear Multivariate (CGAL)$$EngineeringData.CGAL + Interpolation Options + + + 0.0092 + Dependent + Tensile X direction + + + 0.0092 + Dependent + Tensile Y direction + + + 0.0078 + Dependent + Tensile Z direction + + + -0.0084 + Dependent + Compressive X direction + + + -0.0084 + Dependent + Compressive Y direction + + + -0.011 + Dependent + Compressive Z direction + + + 0.02 + Dependent + Shear XY + + + 0.015 + Dependent + Shear YZ + + + 0.015 + Dependent + Shear XZ + + + + - + Orthotropic + Temperature + Orthotropic Stress Limits + + Interpolation Options + Linear Multivariate (Qhull) + True + True + Projection to the Bounding Box + AlgorithmType$$Linear Multivariate (CGAL)$$EngineeringData.CGAL + Interpolation Options + + + 513000000 + Dependent + Tensile X direction + + + 513000000 + Dependent + Tensile Y direction + + + 50000000 + Dependent + Tensile Z direction + + + -437000000 + Dependent + Compressive X direction + + + -437000000 + Dependent + Compressive Y direction + + + -150000000 + Dependent + Compressive Z direction + + + 120000000 + Dependent + Shear XY + + + 55000000 + Dependent + Shear YZ + + + 55000000 + Dependent + Shear XZ + + + + - + Secant + Orthotropic + Temperature + Orthotropic Secant Coefficient of Thermal Expansion + + Interpolation Options + Linear Multivariate (Qhull) + True + True + Projection to the Bounding Box + AlgorithmType$$Linear Multivariate (CGAL)$$EngineeringData.CGAL + Interpolation Options + + + 2.2e-06 + Dependent + Coefficient of Thermal Expansion X direction + + + 2.2e-06 + Dependent + Coefficient of Thermal Expansion Y direction + + + 1e-05 + Dependent + Coefficient of Thermal Expansion Z direction + + + + - + Secant + Orthotropic + Orthotropic Zero-Thermal-Strain Reference Temperature Secant + + 20 + Dependent + Zero-Thermal-Strain Reference Temperature + + + Coefficient of Thermal Expansion + + + + - + Tsai-Wu Constants + + -1 + Dependent + Coupling Coefficient XY + + + -1 + Dependent + Coupling Coefficient YZ + + + -1 + Dependent + Coupling Coefficient XZ + + + 7.88860905221012e-31 + Independent + Temperature + + + + - + 7ab9c060-4547-4561-aab3-d3fd3c4952ed + Material Unique Id + False + + + - + Color + + 170 + Dependent + Red + + + 170 + Dependent + Green + + + 170 + Dependent + Blue + + + Appearance + + + + - + Isotropic + Temperature + Isotropic Thermal Conductivity + + Interpolation Options + Linear Multivariate + True + True + Projection to the Bounding Box + Interpolation Options + + + 2 + Dependent + Thermal Conductivity + + + 7.88860905221012e-31 + Independent + Temperature + Temperature + 22 + Program Controlled + Program Controlled + C + + + + + + + Honeycomb + + Composite + + + - + Temperature + Density + + Interpolation Options + Linear Multivariate (Qhull) + True + True + Projection to the Bounding Box + AlgorithmType$$Linear Multivariate (CGAL)$$EngineeringData.CGAL + Interpolation Options + + + 80 + Dependent + Density + + + + - + ACP + Honeycomb Core + Ply Type + + + - + Orthotropic + Temperature + Orthotropic Elasticity + + Interpolation Options + Linear Multivariate (Qhull) + True + True + Projection to the Bounding Box + AlgorithmType$$Linear Multivariate (CGAL)$$EngineeringData.CGAL + Interpolation Options + + + 1000000 + Dependent + Young's Modulus X direction + + + 1000000 + Dependent + Young's Modulus Y direction + + + 255000000 + Dependent + Young's Modulus Z direction + + + 0.49 + Dependent + Poisson's Ratio XY + + + 0.001 + Dependent + Poisson's Ratio YZ + + + 0.001 + Dependent + Poisson's Ratio XZ + + + 1 + Dependent + Shear Modulus XY + + + 37000000 + Dependent + Shear Modulus YZ + + + 70000000 + Dependent + Shear Modulus XZ + + + + - + Orthotropic + Temperature + Orthotropic Stress Limits + + Interpolation Options + Linear Multivariate (Qhull) + True + True + Projection to the Bounding Box + AlgorithmType$$Linear Multivariate (CGAL)$$EngineeringData.CGAL + Interpolation Options + + + 0 + Dependent + Tensile X direction + + + 0 + Dependent + Tensile Y direction + + + 5310000 + Dependent + Tensile Z direction + + + 0 + Dependent + Compressive X direction + + + 0 + Dependent + Compressive Y direction + + + -5310000 + Dependent + Compressive Z direction + + + 0 + Dependent + Shear XY + + + 1210000 + Dependent + Shear YZ + + + 2240000 + Dependent + Shear XZ + + + + - + 7c43386c-d57e-4169-bf28-1674ece809c5 + Material Unique Id + False + + + - + Color + + 103 + Dependent + Red + + + 192 + Dependent + Green + + + 205 + Dependent + Blue + + + Appearance + + + + - + Isotropic + Temperature + Isotropic Thermal Conductivity + + Interpolation Options + Linear Multivariate + True + True + Projection to the Bounding Box + Interpolation Options + + + 2 + Dependent + Thermal Conductivity + + + 7.88860905221012e-31 + Independent + Temperature + Temperature + 22 + Program Controlled + Program Controlled + C + + + + + + + Epoxy Carbon UD (230 GPa) Prepreg + + Composite + + + - + Temperature + Density + + Interpolation Options + Linear Multivariate (Qhull) + True + True + Projection to the Bounding Box + AlgorithmType$$Linear Multivariate (CGAL)$$EngineeringData.CGAL + Interpolation Options + + + 1490 + Dependent + Density + + + + - + ACP + Regular + Ply Type + + + - + Orthotropic + Temperature + Orthotropic Elasticity + + Interpolation Options + Linear Multivariate (Qhull) + True + True + Projection to the Bounding Box + AlgorithmType$$Linear Multivariate (CGAL)$$EngineeringData.CGAL + Interpolation Options + + + 121000000000 + Dependent + Young's Modulus X direction + + + 8600000000 + Dependent + Young's Modulus Y direction + + + 8600000000 + Dependent + Young's Modulus Z direction + + + 0.27 + Dependent + Poisson's Ratio XY + + + 0.4 + Dependent + Poisson's Ratio YZ + + + 0.27 + Dependent + Poisson's Ratio XZ + + + 4700000000 + Dependent + Shear Modulus XY + + + 3100000000 + Dependent + Shear Modulus YZ + + + 4700000000 + Dependent + Shear Modulus XZ + + + + - + Orthotropic + Temperature + Orthotropic Strain Limits + + Interpolation Options + Linear Multivariate (Qhull) + True + True + Projection to the Bounding Box + AlgorithmType$$Linear Multivariate (CGAL)$$EngineeringData.CGAL + Interpolation Options + + + 0.0167 + Dependent + Tensile X direction + + + 0.0032 + Dependent + Tensile Y direction + + + 0.0032 + Dependent + Tensile Z direction + + + -0.0108 + Dependent + Compressive X direction + + + -0.0192 + Dependent + Compressive Y direction + + + -0.0192 + Dependent + Compressive Z direction + + + 0.012 + Dependent + Shear XY + + + 0.011 + Dependent + Shear YZ + + + 0.012 + Dependent + Shear XZ + + + + - + Orthotropic + Temperature + Orthotropic Stress Limits + + Interpolation Options + Linear Multivariate (Qhull) + True + True + Projection to the Bounding Box + AlgorithmType$$Linear Multivariate (CGAL)$$EngineeringData.CGAL + Interpolation Options + + + 2231000000 + Dependent + Tensile X direction + + + 29000000 + Dependent + Tensile Y direction + + + 29000000 + Dependent + Tensile Z direction + + + -1082000000 + Dependent + Compressive X direction + + + -100000000 + Dependent + Compressive Y direction + + + -100000000 + Dependent + Compressive Z direction + + + 60000000 + Dependent + Shear XY + + + 32000000 + Dependent + Shear YZ + + + 60000000 + Dependent + Shear XZ + + + + - + Secant + Orthotropic + Temperature + Orthotropic Secant Coefficient of Thermal Expansion + + Interpolation Options + Linear Multivariate (Qhull) + True + True + Projection to the Bounding Box + AlgorithmType$$Linear Multivariate (CGAL)$$EngineeringData.CGAL + Interpolation Options + + + -4.7e-07 + Dependent + Coefficient of Thermal Expansion X direction + + + 3e-05 + Dependent + Coefficient of Thermal Expansion Y direction + + + 3e-05 + Dependent + Coefficient of Thermal Expansion Z direction + + + + - + Secant + Orthotropic + Orthotropic Zero-Thermal-Strain Reference Temperature Secant + + 20 + Dependent + Zero-Thermal-Strain Reference Temperature + + + Coefficient of Thermal Expansion + + + + - + Carbon + Temperature + Puck Constants + + Interpolation Options + Linear Multivariate (Qhull) + True + True + Projection to the Bounding Box + AlgorithmType$$Linear Multivariate (CGAL)$$EngineeringData.CGAL + Interpolation Options + + + 0.3 + Dependent + Compressive Inclination XZ + + + 0.25 + Dependent + Compressive Inclination YZ + + + 0.35 + Dependent + Tensile Inclination XZ + + + 0.25 + Dependent + Tensile Inclination YZ + + + + - + Additional Puck Constants + + 0.8 + Dependent + Interface Weakening Factor + + + 0.5 + Dependent + Degradation Parameter s + + + 0.5 + Dependent + Degradation Parameter M + + + + - + Tsai-Wu Constants + + -1 + Dependent + Coupling Coefficient XY + + + -1 + Dependent + Coupling Coefficient YZ + + + -1 + Dependent + Coupling Coefficient XZ + + + 7.88860905221012e-31 + Independent + Temperature + + + + - + e236c55c-e4b2-423c-8262-2cbd5ec4377b + Material Unique Id + False + + + - + Color + + 222 + Dependent + Red + + + 222 + Dependent + Green + + + 222 + Dependent + Blue + + + Appearance + + + + - + Isotropic + Temperature + Isotropic Thermal Conductivity + + Interpolation Options + Linear Multivariate + True + True + Projection to the Bounding Box + Interpolation Options + + + 2 + Dependent + Thermal Conductivity + + + 7.88860905221012e-31 + Independent + Temperature + Temperature + 22 + Program Controlled + Program Controlled + C + + + + + + + Options Variable + + + + Density + + + kg + + + m + + + + + Young's Modulus X direction + + + Pa + + + + + Young's Modulus Y direction + + + Pa + + + + + Young's Modulus Z direction + + + Pa + + + + + Poisson's Ratio XY + + + + Poisson's Ratio YZ + + + + Poisson's Ratio XZ + + + + Shear Modulus XY + + + Pa + + + + + Shear Modulus YZ + + + Pa + + + + + Shear Modulus XZ + + + Pa + + + + + Tensile X direction + + + + Tensile Y direction + + + + Tensile Z direction + + + + Compressive X direction + + + + Compressive Y direction + + + + Compressive Z direction + + + + Shear XY + + + + Shear YZ + + + + Shear XZ + + + + Tensile X direction + + + Pa + + + + + Tensile Y direction + + + Pa + + + + + Tensile Z direction + + + Pa + + + + + Compressive X direction + + + Pa + + + + + Compressive Y direction + + + Pa + + + + + Compressive Z direction + + + Pa + + + + + Shear XY + + + Pa + + + + + Shear YZ + + + Pa + + + + + Shear XZ + + + Pa + + + + + Coefficient of Thermal Expansion X direction + + + C + + + + + Coefficient of Thermal Expansion Y direction + + + C + + + + + Coefficient of Thermal Expansion Z direction + + + C + + + + + Zero-Thermal-Strain Reference Temperature + + + C + + + + + Coupling Coefficient XY + + + + Coupling Coefficient YZ + + + + Coupling Coefficient XZ + + + + Temperature + + + C + + + + + Red + + + + Green + + + + Blue + + + + Material Property + + + + Thermal Conductivity + + + W + + + m + + + C + + + + + Compressive Inclination XZ + + + + Compressive Inclination YZ + + + + Tensile Inclination XZ + + + + Tensile Inclination YZ + + + + Interface Weakening Factor + + + + Degradation Parameter s + + + + Degradation Parameter M + + + + + Density + + + + Ply Type + + + + Elasticity + + + + Strain Limits + + + + Stress Limits + + + + Coefficient of Thermal Expansion + + + + Material Unique Id + + + + Color + + + + Thermal Conductivity + + + + Zero-Thermal-Strain Reference Temperature + + + + Tsai-Wu Constants + + + + Puck Constants + + + + Additional Puck Constants + + + + + + + + Epoxy Carbon Woven (230 GPa) Wet + 14c6ac6f-4e65-4269-9e3a-335446a83ea5 + + + + + Honeycomb + 21084963-4dd6-484f-abe2-d1fe8fef3da3 + + + + + Epoxy Carbon UD (230 GPa) Prepreg + a1f2e775-77fe-4ad6-a822-54d353e0ea0e + + + + + + \ No newline at end of file diff --git a/tests/data/workflow_example/multiple_time_steps/Setup/ACPCompositeDefinitions.h5 b/tests/data/workflow_example/multiple_time_steps/Setup/ACPCompositeDefinitions.h5 new file mode 100644 index 0000000000000000000000000000000000000000..efc2cb71059488079c910d4aaf461f5c90b27857 GIT binary patch literal 46176 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 a&*v)q$A3P5_~PN2!-d1aM-Q?Y<^3OD2Gel> literal 0 HcmV?d00001 diff --git a/tests/data/workflow_example/multiple_time_steps/file.rst b/tests/data/workflow_example/multiple_time_steps/file.rst new file mode 100644 index 0000000000000000000000000000000000000000..9847237f6caa3b41f789feeb3130b8104e9b0c16 GIT binary patch literal 393216 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 qX`r;wse{r^X{b{_rAg8zr!Gm$q-jn)lLkr) zojNG(l!iL>Q<@}ga_W+_Oq%A@Giji-(5ZvcPHCu9Kh4j;`AO@1zQy_1KL=(1y}A-0 zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0{=(g?(w?rpT2&d=bO*V{<>Y?=jug(009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ;4cL}03L>z AYybcN literal 0 HcmV?d00001 From 40b3965173ed1d3e102da9bda7fb7c93fe2d0482 Mon Sep 17 00:00:00 2001 From: jvonrick Date: Mon, 20 Nov 2023 11:11:16 +0100 Subject: [PATCH 02/12] Check version in test --- examples/008_assembly_example.py | 15 +++++--- tests/composite_model_test.py | 64 +++++++++++++++++++------------- 2 files changed, 49 insertions(+), 30 deletions(-) diff --git a/examples/008_assembly_example.py b/examples/008_assembly_example.py index cd32ba836..70b560faa 100644 --- a/examples/008_assembly_example.py +++ b/examples/008_assembly_example.py @@ -22,7 +22,11 @@ from ansys.dpf.composites.constants import FailureOutput from ansys.dpf.composites.example_helper import get_continuous_fiber_example_files from ansys.dpf.composites.failure_criteria import CombinedFailureCriterion, MaxStressCriterion -from ansys.dpf.composites.server_helpers import connect_to_or_start_server, version_older_than +from ansys.dpf.composites.server_helpers import ( + connect_to_or_start_server, + version_equal_or_later, + version_older_than, +) # %% # Start a DPF server and copy the example files into the current working directory. @@ -56,10 +60,11 @@ # Plot IRF # ~~~~~~~~ # Plot the maximum IRF on the reference surface -irf_field = output_all_elements.get_field( - {"failure_label": FailureOutput.FAILURE_VALUE_REF_SURFACE} -) -irf_field.plot() +if version_equal_or_later(server, "7.1"): + irf_field = output_all_elements.get_field( + {"failure_label": FailureOutput.FAILURE_VALUE_REF_SURFACE} + ) + irf_field.plot() # %% diff --git a/tests/composite_model_test.py b/tests/composite_model_test.py index f400ec5eb..8115e9496 100644 --- a/tests/composite_model_test.py +++ b/tests/composite_model_test.py @@ -129,11 +129,23 @@ def test_model_with_multiple_timesteps(dpf_server): ) # Note evaluate_failure_criteria supports only a single time step - irf_field = failure_output.get_field({"failure_label": FailureOutput.FAILURE_VALUE}) + irf_field = failure_output.get_field({FAILURE_LABEL: FailureOutput.FAILURE_VALUE}) for element_id, expected_value in expected_data_by_time_index[time_index].items(): assert irf_field.get_entity_data_by_id(element_id) == pytest.approx(expected_value) + # Just check that the other fields are available + def check_field_size(failure_label: FailureOutput): + field = failure_output.get_field({FAILURE_LABEL: failure_label}) + assert len(field.scoping.ids) == 4 + + check_field_size(FailureOutput.FAILURE_MODE) + check_field_size(FailureOutput.FAILURE_MODE_REF_SURFACE) + check_field_size(FailureOutput.MAX_LAYER_INDEX) + check_field_size(FailureOutput.MAX_GLOBAL_LAYER_IN_STACK) + check_field_size(FailureOutput.MAX_LOCAL_LAYER_IN_ELEMENT) + check_field_size(FailureOutput.MAX_SOLID_ELEMENT_ID) + def test_assembly_model(dpf_server): """Verify the handling of assemblies.""" @@ -210,31 +222,33 @@ def check_output(failure_label: FailureOutput, expected_output: dict[int, float] 3: 1.11311715, 4: 1.11311715, } - check_output(FailureOutput.FAILURE_VALUE_REF_SURFACE, expected_output_ref_surface) - - expected_output_local_layer = { - 1: 2, - 2: 2, - 3: 2, - 4: 2, - } - check_output(FailureOutput.MAX_LOCAL_LAYER_IN_ELEMENT, expected_output_local_layer) - expected_output_global_layer = { - 1: 2, - 2: 2, - 3: 2, - 4: 2, - } - check_output(FailureOutput.MAX_GLOBAL_LAYER_IN_STACK, expected_output_global_layer) - - expected_output_solid_element = { - 1: 5, - 2: 6, - 3: 1, - 4: 2, - } - check_output(FailureOutput.MAX_SOLID_ELEMENT_ID, expected_output_solid_element) + if version_equal_or_later(dpf_server, "7.1"): + check_output(FailureOutput.FAILURE_VALUE_REF_SURFACE, expected_output_ref_surface) + + expected_output_local_layer = { + 1: 2, + 2: 2, + 3: 2, + 4: 2, + } + check_output(FailureOutput.MAX_LOCAL_LAYER_IN_ELEMENT, expected_output_local_layer) + + expected_output_global_layer = { + 1: 2, + 2: 2, + 3: 2, + 4: 2, + } + check_output(FailureOutput.MAX_GLOBAL_LAYER_IN_STACK, expected_output_global_layer) + + expected_output_solid_element = { + 1: 5, + 2: 6, + 3: 1, + 4: 2, + } + check_output(FailureOutput.MAX_SOLID_ELEMENT_ID, expected_output_solid_element) property_dict = composite_model.get_constant_property_dict( [MaterialProperty.Stress_Limits_Xt], composite_definition_label=solid_label From 946538080cfdbf65bd65215fb405d7ee5f9cc024 Mon Sep 17 00:00:00 2001 From: jvonrick Date: Mon, 20 Nov 2023 11:13:58 +0100 Subject: [PATCH 03/12] Check version in test --- tests/composite_model_test.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/composite_model_test.py b/tests/composite_model_test.py index 8115e9496..c59fab1f7 100644 --- a/tests/composite_model_test.py +++ b/tests/composite_model_test.py @@ -142,9 +142,11 @@ def check_field_size(failure_label: FailureOutput): check_field_size(FailureOutput.FAILURE_MODE) check_field_size(FailureOutput.FAILURE_MODE_REF_SURFACE) check_field_size(FailureOutput.MAX_LAYER_INDEX) - check_field_size(FailureOutput.MAX_GLOBAL_LAYER_IN_STACK) - check_field_size(FailureOutput.MAX_LOCAL_LAYER_IN_ELEMENT) - check_field_size(FailureOutput.MAX_SOLID_ELEMENT_ID) + + if version_equal_or_later(dpf_server, "7.1"): + check_field_size(FailureOutput.MAX_GLOBAL_LAYER_IN_STACK) + check_field_size(FailureOutput.MAX_LOCAL_LAYER_IN_ELEMENT) + check_field_size(FailureOutput.MAX_SOLID_ELEMENT_ID) def test_assembly_model(dpf_server): From ed2550ce844dfedb1886cf241639e159a7cc84ba Mon Sep 17 00:00:00 2001 From: jvonrick Date: Mon, 20 Nov 2023 11:20:00 +0100 Subject: [PATCH 04/12] Check version in test --- tests/composite_model_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/composite_model_test.py b/tests/composite_model_test.py index c59fab1f7..296598c9f 100644 --- a/tests/composite_model_test.py +++ b/tests/composite_model_test.py @@ -140,10 +140,10 @@ def check_field_size(failure_label: FailureOutput): assert len(field.scoping.ids) == 4 check_field_size(FailureOutput.FAILURE_MODE) - check_field_size(FailureOutput.FAILURE_MODE_REF_SURFACE) check_field_size(FailureOutput.MAX_LAYER_INDEX) if version_equal_or_later(dpf_server, "7.1"): + check_field_size(FailureOutput.FAILURE_MODE_REF_SURFACE) check_field_size(FailureOutput.MAX_GLOBAL_LAYER_IN_STACK) check_field_size(FailureOutput.MAX_LOCAL_LAYER_IN_ELEMENT) check_field_size(FailureOutput.MAX_SOLID_ELEMENT_ID) From 406d4f45db2413ff443fe58aa73dc677cd5174e9 Mon Sep 17 00:00:00 2001 From: jvonrick Date: Mon, 20 Nov 2023 13:25:37 +0100 Subject: [PATCH 05/12] Fix layer index that starts at zero for older versions --- tests/composite_model_test.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/composite_model_test.py b/tests/composite_model_test.py index 296598c9f..fa2d7bcbb 100644 --- a/tests/composite_model_test.py +++ b/tests/composite_model_test.py @@ -216,6 +216,13 @@ def check_output(failure_label: FailureOutput, expected_output: dict[int, float] 9: 1, 10: 1, } + + if not version_equal_or_later(dpf_server, "7.1"): + for element_id in expected_layer_index: + # Older versions of the server returned a layer index that starts + # at 0 instead of 1 + expected_layer_index[element_id] -= 1 + check_output(FailureOutput.MAX_LAYER_INDEX, expected_layer_index) expected_output_ref_surface = { From f4b193f54f1caf2775411835de5d74f95b9ad88c Mon Sep 17 00:00:00 2001 From: jvonrick Date: Mon, 20 Nov 2023 13:40:42 +0100 Subject: [PATCH 06/12] Update version and add more backward compatibility tests --- .github/workflows/ci_cd.yml | 3 +++ examples/008_assembly_example.py | 2 +- src/ansys/dpf/composites/_composite_model_impl.py | 3 +-- src/ansys/dpf/composites/server_helpers/_versions.py | 5 +++-- tests/composite_model_test.py | 4 ++-- tox.ini | 3 +++ 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index 81208842f..53c9761ff 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -73,6 +73,9 @@ jobs: # if other containers must be tested. run: | docker pull ghcr.io/ansys/pydpf-composites:${{ env.CONTAINER_TAG }} + docker pull ghcr.io/ansys/pydpf-composites:2024r1 + docker pull ghcr.io/ansys/pydpf-composites:2024r1_pre0 + docker pull ghcr.io/ansys/pydpf-composites:2023r2 docker pull ghcr.io/ansys/pydpf-composites:2023r2_pre1 - name: "Checkout the project" diff --git a/examples/008_assembly_example.py b/examples/008_assembly_example.py index 70b560faa..7723ee3b0 100644 --- a/examples/008_assembly_example.py +++ b/examples/008_assembly_example.py @@ -60,7 +60,7 @@ # Plot IRF # ~~~~~~~~ # Plot the maximum IRF on the reference surface -if version_equal_or_later(server, "7.1"): +if version_equal_or_later(server, "8.0"): irf_field = output_all_elements.get_field( {"failure_label": FailureOutput.FAILURE_VALUE_REF_SURFACE} ) diff --git a/src/ansys/dpf/composites/_composite_model_impl.py b/src/ansys/dpf/composites/_composite_model_impl.py index b63eb9405..593841d1f 100644 --- a/src/ansys/dpf/composites/_composite_model_impl.py +++ b/src/ansys/dpf/composites/_composite_model_impl.py @@ -457,8 +457,7 @@ def evaluate_failure_criteria( "No output is generated! Please check the scope (element and ply ids)." ) - # Todo we need to update this version once the prerelease version bump has happened - if version_equal_or_later(self._server, "7.1"): + if version_equal_or_later(self._server, "8.0"): self._map_to_reference_surface_operator.inputs.min_container( min_merger.outputs.merged_fields_container() ) diff --git a/src/ansys/dpf/composites/server_helpers/_versions.py b/src/ansys/dpf/composites/server_helpers/_versions.py index 2902ec334..08f71faf4 100644 --- a/src/ansys/dpf/composites/server_helpers/_versions.py +++ b/src/ansys/dpf/composites/server_helpers/_versions.py @@ -13,8 +13,9 @@ class _DpfVersionInfo: _DPF_VERSIONS: dict[str, _DpfVersionInfo] = { "5.0": _DpfVersionInfo("5.0", "2023 R1", "Initial release of DPF Composites."), - "7.0": _DpfVersionInfo("7.0", "2024 R1", "DPF Composites plugin with sub-operators."), - "7.1": _DpfVersionInfo("7.1", "2024 R2 pre 0", "Reference surface support"), + "7.0": _DpfVersionInfo("7.0", "2024 R1 pre 0", "DPF Composites plugin with sub-operators."), + "7.1": _DpfVersionInfo("7.1", "2024 R1", "Layer index starts at 1."), + "8.0": _DpfVersionInfo("8.0", "2024 R2 pre 0", "Reference surface support"), } diff --git a/tests/composite_model_test.py b/tests/composite_model_test.py index fa2d7bcbb..ee66095dc 100644 --- a/tests/composite_model_test.py +++ b/tests/composite_model_test.py @@ -142,7 +142,7 @@ def check_field_size(failure_label: FailureOutput): check_field_size(FailureOutput.FAILURE_MODE) check_field_size(FailureOutput.MAX_LAYER_INDEX) - if version_equal_or_later(dpf_server, "7.1"): + if version_equal_or_later(dpf_server, "8.0"): check_field_size(FailureOutput.FAILURE_MODE_REF_SURFACE) check_field_size(FailureOutput.MAX_GLOBAL_LAYER_IN_STACK) check_field_size(FailureOutput.MAX_LOCAL_LAYER_IN_ELEMENT) @@ -232,7 +232,7 @@ def check_output(failure_label: FailureOutput, expected_output: dict[int, float] 4: 1.11311715, } - if version_equal_or_later(dpf_server, "7.1"): + if version_equal_or_later(dpf_server, "8.0"): check_output(FailureOutput.FAILURE_VALUE_REF_SURFACE, expected_output_ref_surface) expected_output_local_layer = { diff --git a/tox.ini b/tox.ini index 744ec833d..16f8b8833 100644 --- a/tox.ini +++ b/tox.ini @@ -32,6 +32,9 @@ setenv = commands = poetry install -E test poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=latest {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {posargs:-vv} + poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=2024r1 {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {env:PYTEST_COV_APPEND_ARG:} {posargs:-vv} + poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=2024r1_pre0 {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {env:PYTEST_COV_APPEND_ARG:} {posargs:-vv} + poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=2023r2 {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {env:PYTEST_COV_APPEND_ARG:} {posargs:-vv} poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=2023r2_pre1 {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {env:PYTEST_COV_APPEND_ARG:} {posargs:-vv} [testenv:test-minimal] From 6bb7335bd053969081745dfc69f073d7cccfdc6c Mon Sep 17 00:00:00 2001 From: jvonrick Date: Mon, 20 Nov 2023 13:51:22 +0100 Subject: [PATCH 07/12] Update version and add more backward compatibility tests --- .github/workflows/ci_cd.yml | 4 ++-- tox.ini | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index 53c9761ff..1a8e63ee0 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -73,9 +73,9 @@ jobs: # if other containers must be tested. run: | docker pull ghcr.io/ansys/pydpf-composites:${{ env.CONTAINER_TAG }} - docker pull ghcr.io/ansys/pydpf-composites:2024r1 + # docker pull ghcr.io/ansys/pydpf-composites:2024r1 docker pull ghcr.io/ansys/pydpf-composites:2024r1_pre0 - docker pull ghcr.io/ansys/pydpf-composites:2023r2 + # docker pull ghcr.io/ansys/pydpf-composites:2023r2 docker pull ghcr.io/ansys/pydpf-composites:2023r2_pre1 - name: "Checkout the project" diff --git a/tox.ini b/tox.ini index 16f8b8833..189e73967 100644 --- a/tox.ini +++ b/tox.ini @@ -32,9 +32,9 @@ setenv = commands = poetry install -E test poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=latest {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {posargs:-vv} - poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=2024r1 {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {env:PYTEST_COV_APPEND_ARG:} {posargs:-vv} +# poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=2024r1 {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {env:PYTEST_COV_APPEND_ARG:} {posargs:-vv} poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=2024r1_pre0 {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {env:PYTEST_COV_APPEND_ARG:} {posargs:-vv} - poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=2023r2 {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {env:PYTEST_COV_APPEND_ARG:} {posargs:-vv} +# poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=2023r2 {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {env:PYTEST_COV_APPEND_ARG:} {posargs:-vv} poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=2023r2_pre1 {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {env:PYTEST_COV_APPEND_ARG:} {posargs:-vv} [testenv:test-minimal] From 2fa1ecdfbd50766c626b14118d392c52b54af4cd Mon Sep 17 00:00:00 2001 From: jvonrick Date: Mon, 20 Nov 2023 13:57:15 +0100 Subject: [PATCH 08/12] Fix yaml file --- .github/workflows/ci_cd.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index 1a8e63ee0..da3e45e01 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -71,11 +71,13 @@ jobs: - name: "Pull pydpf container(s)" # 2023r2_pre1 is used to test backward compatibility. Also update testenv in tox.ini # if other containers must be tested. + + # TBD: add more containers? + # docker pull ghcr.io/ansys/pydpf-composites:2023r2 + # docker pull ghcr.io/ansys/pydpf-composites:2024r1 run: | docker pull ghcr.io/ansys/pydpf-composites:${{ env.CONTAINER_TAG }} - # docker pull ghcr.io/ansys/pydpf-composites:2024r1 docker pull ghcr.io/ansys/pydpf-composites:2024r1_pre0 - # docker pull ghcr.io/ansys/pydpf-composites:2023r2 docker pull ghcr.io/ansys/pydpf-composites:2023r2_pre1 - name: "Checkout the project" From 3e69cef00f3c502e9bd7ccdb6ffa14be146b6805 Mon Sep 17 00:00:00 2001 From: jvonrick Date: Mon, 20 Nov 2023 14:29:20 +0100 Subject: [PATCH 09/12] Don't initialize ref surface operator for older versions --- src/ansys/dpf/composites/_composite_model_impl.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/ansys/dpf/composites/_composite_model_impl.py b/src/ansys/dpf/composites/_composite_model_impl.py index 593841d1f..33660e572 100644 --- a/src/ansys/dpf/composites/_composite_model_impl.py +++ b/src/ansys/dpf/composites/_composite_model_impl.py @@ -176,14 +176,15 @@ def __init__( unit_system=self._unit_system, ) - self._reference_surface_and_mapping_field = _get_reference_surface_and_mapping_field( - data_sources=self.data_sources.composite, unit_system=self._unit_system - ) + if version_equal_or_later(self._server, "8.0"): + self._reference_surface_and_mapping_field = _get_reference_surface_and_mapping_field( + data_sources=self.data_sources.composite, unit_system=self._unit_system + ) - self._map_to_reference_surface_operator = _get_map_to_reference_surface_operator( - reference_surface_and_mapping_field=self._reference_surface_and_mapping_field, - element_layer_indices_field=self.get_mesh().property_field("element_layer_indices"), - ) + self._map_to_reference_surface_operator = _get_map_to_reference_surface_operator( + reference_surface_and_mapping_field=self._reference_surface_and_mapping_field, + element_layer_indices_field=self.get_mesh().property_field("element_layer_indices"), + ) self._element_info_provider = get_element_info_provider( mesh=self.get_mesh(), From b2a9dd9814364a218a6b50628386ebc5925178d8 Mon Sep 17 00:00:00 2001 From: jvonrick Date: Mon, 20 Nov 2023 14:55:20 +0100 Subject: [PATCH 10/12] Only test material name for versions >=7.1 --- tests/composite_model_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/composite_model_test.py b/tests/composite_model_test.py index ee66095dc..329f2972b 100644 --- a/tests/composite_model_test.py +++ b/tests/composite_model_test.py @@ -87,7 +87,7 @@ def test_basic_functionality_of_composite_model(dpf_server, data_files, distribu assert [ply["id"] for ply in sampling_point.analysis_plies] == analysis_ply_ids - if version_equal_or_later(dpf_server, "7.0"): + if version_equal_or_later(dpf_server, "7.1"): ref_material_names = [ "Epoxy Carbon UD (230 GPa) Prepreg", "Epoxy Carbon Woven (230 GPa) Wet", From 0076b06db13c9421ea554a63daf143a35d76afbb Mon Sep 17 00:00:00 2001 From: jvonrick Date: Tue, 21 Nov 2023 13:51:34 +0100 Subject: [PATCH 11/12] Add 2024r1 container --- .github/workflows/ci_cd.yml | 5 +---- tox.ini | 5 ++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index da3e45e01..d481cdc19 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -71,13 +71,10 @@ jobs: - name: "Pull pydpf container(s)" # 2023r2_pre1 is used to test backward compatibility. Also update testenv in tox.ini # if other containers must be tested. - - # TBD: add more containers? - # docker pull ghcr.io/ansys/pydpf-composites:2023r2 - # docker pull ghcr.io/ansys/pydpf-composites:2024r1 run: | docker pull ghcr.io/ansys/pydpf-composites:${{ env.CONTAINER_TAG }} docker pull ghcr.io/ansys/pydpf-composites:2024r1_pre0 + docker pull ghcr.io/ansys/pydpf-composites:2024r1 docker pull ghcr.io/ansys/pydpf-composites:2023r2_pre1 - name: "Checkout the project" diff --git a/tox.ini b/tox.ini index 189e73967..05002a9ca 100644 --- a/tox.ini +++ b/tox.ini @@ -31,10 +31,9 @@ setenv = PYTEST_COV_APPEND_ARG = --cov-append commands = poetry install -E test - poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=latest {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {posargs:-vv} -# poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=2024r1 {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {env:PYTEST_COV_APPEND_ARG:} {posargs:-vv} + poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=latest {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {env:PYTEST_COV_APPEND_ARG:} {posargs:-vv} + poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=2024r1 {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {env:PYTEST_COV_APPEND_ARG:} {posargs:-vv} poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=2024r1_pre0 {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {env:PYTEST_COV_APPEND_ARG:} {posargs:-vv} -# poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=2023r2 {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {env:PYTEST_COV_APPEND_ARG:} {posargs:-vv} poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=2023r2_pre1 {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {env:PYTEST_COV_APPEND_ARG:} {posargs:-vv} [testenv:test-minimal] From fefa875434f3c481506700920ecd9eff2ea64147 Mon Sep 17 00:00:00 2001 From: jvonrick Date: Tue, 21 Nov 2023 14:09:26 +0100 Subject: [PATCH 12/12] Clarify version info and fix return value annotation. --- src/ansys/dpf/composites/_composite_model_impl.py | 2 +- src/ansys/dpf/composites/server_helpers/_versions.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ansys/dpf/composites/_composite_model_impl.py b/src/ansys/dpf/composites/_composite_model_impl.py index 33660e572..d7eae2e3e 100644 --- a/src/ansys/dpf/composites/_composite_model_impl.py +++ b/src/ansys/dpf/composites/_composite_model_impl.py @@ -77,7 +77,7 @@ def _merge_containers( out_container.labels = [TIME_LABEL, FAILURE_LABEL] out_container.time_freq_support = non_ref_surface_container.time_freq_support - def add_to_output_container(time_id: int, source_container: FieldsContainer) -> FieldsContainer: + def add_to_output_container(time_id: int, source_container: FieldsContainer) -> None: fields = source_container.get_fields({TIME_LABEL: time_id}) for field in fields: failure_enum = _get_failure_enum_from_name(field.name) diff --git a/src/ansys/dpf/composites/server_helpers/_versions.py b/src/ansys/dpf/composites/server_helpers/_versions.py index 08f71faf4..79a6d9035 100644 --- a/src/ansys/dpf/composites/server_helpers/_versions.py +++ b/src/ansys/dpf/composites/server_helpers/_versions.py @@ -14,7 +14,7 @@ class _DpfVersionInfo: _DPF_VERSIONS: dict[str, _DpfVersionInfo] = { "5.0": _DpfVersionInfo("5.0", "2023 R1", "Initial release of DPF Composites."), "7.0": _DpfVersionInfo("7.0", "2024 R1 pre 0", "DPF Composites plugin with sub-operators."), - "7.1": _DpfVersionInfo("7.1", "2024 R1", "Layer index starts at 1."), + "7.1": _DpfVersionInfo("7.1", "2024 R1", "Layer index starts at 1. Material names."), "8.0": _DpfVersionInfo("8.0", "2024 R2 pre 0", "Reference surface support"), }