Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update 0.4 release branch #449

Merged
merged 17 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci_cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ 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:2024r2_pre1
docker pull ghcr.io/ansys/pydpf-composites:2024r2_pre0
docker pull ghcr.io/ansys/pydpf-composites:2024r1_pre0
docker pull ghcr.io/ansys/pydpf-composites:2024r1
Expand Down
2 changes: 2 additions & 0 deletions doc/source/intro.rst
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ By default the DPF server is started from the latest Ansys installer. To choose

* - Server version
- ansys.dpf.composites Python module version
* - 8.1 (Ansys 2024 R2 pre1)
- 0.3.0 and later
* - 8.0 (Ansys 2024 R2 pre0)
- 0.3.0 and later
* - 7.0 (Ansys 2024 R1)
Expand Down
4 changes: 3 additions & 1 deletion examples/006_filter_composite_data_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@
)

value = stress_data[selected_indices][:, component]
local_result_field.append(value, element_id)
# value needs to be passed as list because dpf does not support numpy
# slices in the append call.
local_result_field.append(value.tolist(), element_id)

composite_model.get_mesh().plot(result_field)

Expand Down
4,567 changes: 0 additions & 4,567 deletions poetry.lock

This file was deleted.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api"
[tool.poetry]
# Check https://python-poetry.org/docs/pyproject/ for all available sections
name = "ansys-dpf-composites"
version = "0.4.0"
version = "0.4.1"
description = "Post-processing of composite structures based on Ansys DPF"
license = "MIT"
authors = ["ANSYS, Inc. <[email protected]>"]
Expand All @@ -14,7 +14,7 @@ readme = "README.rst"
repository = "https://github.com/ansys/pydpf-composites"
documentation = "https://composites.dpf.docs.pyansys.com"
classifiers = [
"Development Status :: 4 - Beta",
"Development Status :: 5 - Production/Stable",
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
Expand Down
1 change: 1 addition & 0 deletions release_checklist.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
* Add docker pull for the container with the new version tag in ci_cd.yml
* Add pytest run for the new version in tox.ini
* Update the compatibility in the docs: intro.rst / Compatibility
* Revert to released version of dpf core in the pyproject.toml file
* Follow this guide (https://dev.docs.pyansys.com/how-to/releasing.html) to create a release branch and release. Also bump version in test_metadata.py test.
60 changes: 36 additions & 24 deletions src/ansys/dpf/composites/_composite_model_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
from .server_helpers import (
upload_continuous_fiber_composite_files_to_server,
version_equal_or_later,
version_older_than,
)
from .unit_system import get_unit_system

Expand Down Expand Up @@ -498,14 +499,6 @@ def evaluate_failure_criteria(
min_container = minmax_el_op.outputs.field_min()
max_container = minmax_el_op.outputs.field_max()

converter_op = dpf.Operator("composite::failure_measure_converter")
converter_op.inputs.fields_container(min_container)
converter_op.inputs.measure_type(measure.value)
converter_op.run()

converter_op.inputs.fields_container(max_container)
converter_op.run()

min_merger.connect(merge_index, min_container)
max_merger.connect(merge_index, max_container)
merge_index = merge_index + 1
Expand All @@ -514,28 +507,47 @@ def evaluate_failure_criteria(
raise RuntimeError("No output is generated! Check the scope (element and ply IDs).")

if self._supports_reference_surface_operators():
overall_max_container = max_merger.outputs.merged_fields_container()

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()
self._map_to_reference_surface_operator.inputs.max_container(overall_max_container)

ref_surface_max_container = (
self._map_to_reference_surface_operator.outputs.max_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(),
)
converter_op = dpf.Operator("composite::failure_measure_converter")
converter_op.inputs.measure_type(measure.value)
converter_op.inputs.fields_container(overall_max_container)
converter_op.run()
converter_op.inputs.fields_container(ref_surface_max_container)
converter_op.run()

if version_older_than(self._server, "8.2"):
# For versions before 8.2, the Reference Surface suffix
# is not correctly preserved by the failure_measure_converter
# We add the suffix manually here.
for field in ref_surface_max_container:
if (
field.name.startswith("IRF")
or field.name.startswith("SF")
or field.name.startswith("SM")
):
assert not field.name.endswith(REF_SURFACE_NAME)
# Set name in field definition, because setting
# the name directly is not supported for older dpf versions
field_definition = field.field_definition
field_definition.name = field_definition.name + " " + REF_SURFACE_NAME

return _merge_containers(overall_max_container, ref_surface_max_container)
else:
if measure == FailureMeasureEnum.INVERSE_RESERVE_FACTOR:
return max_merger.outputs.merged_fields_container()
else:
return min_merger.outputs.merged_fields_container()
converter_op = dpf.Operator("composite::failure_measure_converter")
converter_op.inputs.measure_type(measure.value)
converter_op.inputs.fields_container(max_merger.outputs.merged_fields_container())
converter_op.run()
return max_container

@_deprecated_composite_definition_label
def get_sampling_point(
Expand Down
5 changes: 1 addition & 4 deletions src/ansys/dpf/composites/_composite_model_impl_2023r2.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,10 +336,7 @@ def evaluate_failure_criteria(

failure_operator.inputs.result_definition(rd.to_json())

if measure == FailureMeasureEnum.INVERSE_RESERVE_FACTOR:
return failure_operator.outputs.fields_containerMax()
else:
return failure_operator.outputs.fields_containerMin()
return failure_operator.outputs.fields_containerMax()

def get_sampling_point(
self,
Expand Down
5 changes: 5 additions & 0 deletions src/ansys/dpf/composites/server_helpers/_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ class _DpfVersionInfo:
"DPF Composites: reference surface support and \
section data from RST",
),
"8.2": _DpfVersionInfo(
"8.2",
"2024 R2 pre 2",
"DPF Composites: Failure measure conversion preserves Reference Surface suffix",
),
}


Expand Down
60 changes: 49 additions & 11 deletions tests/composite_model_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,29 @@ def check_field_size(failure_label: FailureOutput):
check_field_size(FailureOutput.MAX_SOLID_ELEMENT_ID)


def test_assembly_model(dpf_server):
_MAX_RESERVE_FACTOR = 1000.0


def _get_margin_of_safety_from_irf(irf: float) -> float:
return _get_reserve_factor_from_irf(irf) - 1.0


def _get_reserve_factor_from_irf(irf: float) -> float:
if irf > 0.0:
return min(1.0 / irf, _MAX_RESERVE_FACTOR)
else:
return _MAX_RESERVE_FACTOR


@pytest.mark.parametrize(
"failure_measure",
[
FailureMeasureEnum.INVERSE_RESERVE_FACTOR,
FailureMeasureEnum.RESERVE_FACTOR,
FailureMeasureEnum.MARGIN_OF_SAFETY,
],
)
def test_assembly_model(dpf_server, failure_measure):
"""Verify the handling of assemblies."""

timer = Timer()
Expand All @@ -201,16 +223,26 @@ def test_assembly_model(dpf_server):
failure_output = composite_model.evaluate_failure_criteria(
combined_criterion=combined_failure_criterion,
composite_scope=CompositeScope(),
measure=failure_measure,
)

timer.add("After get failure output")

def check_output(failure_label: FailureOutput, expected_output: dict[int, float]):
def check_value_output(failure_label: FailureOutput, expected_output: dict[int, float]):
for element_id, expected_value in expected_output.items():
if failure_measure == FailureMeasureEnum.MARGIN_OF_SAFETY:
expected_value = _get_margin_of_safety_from_irf(expected_value)
elif failure_measure == FailureMeasureEnum.RESERVE_FACTOR:
expected_value = _get_reserve_factor_from_irf(expected_value)
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 = {
def check_mode_or_layer_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_irf_output = {
1: 1.11311715,
2: 1.11311715,
5: 1.85777034,
Expand All @@ -220,7 +252,7 @@ def check_output(failure_label: FailureOutput, expected_output: dict[int, float]
9: 0.62122959,
10: 0.62122959,
}
check_output(FailureOutput.FAILURE_VALUE, expected_output)
check_value_output(FailureOutput.FAILURE_VALUE, expected_irf_output)

expected_modes = {
1: FailureModeEnum.s1t.value,
Expand All @@ -232,7 +264,7 @@ def check_output(failure_label: FailureOutput, expected_output: dict[int, float]
9: FailureModeEnum.s2t.value,
10: FailureModeEnum.s2t.value,
}
check_output(FailureOutput.FAILURE_MODE, expected_modes)
check_mode_or_layer_output(FailureOutput.FAILURE_MODE, expected_modes)

expected_layer_index = {
1: 2,
Expand All @@ -251,41 +283,47 @@ def check_output(failure_label: FailureOutput, expected_output: dict[int, float]
# at 0 instead of 1
expected_layer_index[element_id] -= 1

check_output(FailureOutput.MAX_LAYER_INDEX, expected_layer_index)
check_mode_or_layer_output(FailureOutput.MAX_LAYER_INDEX, expected_layer_index)

expected_output_ref_surface = {
expected_output_irf_ref_surface = {
1: 1.85777034,
2: 1.85777034,
3: 1.11311715,
4: 1.11311715,
}

if version_equal_or_later(dpf_server, "8.0"):
check_output(FailureOutput.FAILURE_VALUE_REF_SURFACE, expected_output_ref_surface)
check_value_output(FailureOutput.FAILURE_VALUE_REF_SURFACE, expected_output_irf_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)
check_mode_or_layer_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)
check_mode_or_layer_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)
check_mode_or_layer_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
Expand Down
4 changes: 2 additions & 2 deletions tests/filter_layered_data_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def get_result_field(
# Conversion to a list is a temporary workaround
# because the append method does currently not work
# reliably for slices of numpy arrays
local_result_field.append(list(values), element_id)
local_result_field.append(values.tolist(), element_id)
else:
local_result_field.append(strain_data[selected_indices, component], element_id)
return result_field
Expand Down Expand Up @@ -166,7 +166,7 @@ def test_filter_by_global_ply(dpf_server):
component = 0
value = strain_data[selected_indices][:, component]

local_result_field.append(value, element_id)
local_result_field.append(value.tolist(), element_id)

# Ply is only present in element 1 and 2
assert list(result_field.scoping.ids) == [1, 2]
Expand Down
2 changes: 1 addition & 1 deletion tests/test_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@


def test_pkg_version():
assert __version__ == "0.4.0"
assert __version__ == "0.4.1"
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ 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:} {env:PYTEST_COV_APPEND_ARG:} {posargs:-vv}
poetry run pytest --reruns 1 --license-server={env:LICENSE_SERVER:} --image-tag=2024r2_pre1 {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=2024r2_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=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}
Expand Down
Loading