Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/origin/main' into feat/section_…
Browse files Browse the repository at this point in the history
…data_from_rst

# Conflicts:
#	src/ansys/dpf/composites/server_helpers/_versions.py
  • Loading branch information
roosre committed Nov 23, 2023
2 parents 88770bd + d38293f commit 28c53bd
Show file tree
Hide file tree
Showing 14 changed files with 1,638 additions and 20 deletions.
2 changes: 1 addition & 1 deletion .ci/minimum_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Contains minimum requirements that we support
numpy == 1.22.0
matplotlib == 3.5.0
ansys-dpf-core == 0.7.3
ansys-dpf-core == 0.8.0
pyvista == 0.36.1
2 changes: 2 additions & 0 deletions .github/workflows/ci_cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ 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_pre0
docker pull ghcr.io/ansys/pydpf-composites:2024r1
docker pull ghcr.io/ansys/pydpf-composites:2023r2_pre1
- name: "Checkout the project"
Expand Down
19 changes: 17 additions & 2 deletions examples/008_assembly_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -47,11 +51,22 @@
# %%
# 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
if version_equal_or_later(server, "8.0"):
irf_field = output_all_elements.get_field(
{"failure_label": FailureOutput.FAILURE_VALUE_REF_SURFACE}
)
irf_field.plot()


# %%
# Get element information
# ~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
107 changes: 102 additions & 5 deletions src/ansys/dpf/composites/_composite_model_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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


Expand All @@ -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) -> None:
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.
Expand Down Expand Up @@ -109,6 +177,16 @@ def __init__(
rst_stream_provider=self._get_rst_streams_provider()
)

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._element_info_provider = get_element_info_provider(
mesh=self.get_mesh(),
stream_provider_or_data_source=self._get_rst_streams_provider(),
Expand Down Expand Up @@ -272,7 +350,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})

Expand Down Expand Up @@ -384,10 +462,29 @@ 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()
if version_equal_or_later(self._server, "8.0"):
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(
Expand Down
3 changes: 3 additions & 0 deletions src/ansys/dpf/composites/_composite_model_impl_2023r2.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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::
Expand Down
9 changes: 8 additions & 1 deletion src/ansys/dpf/composites/composite_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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::
Expand All @@ -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(
Expand Down
21 changes: 19 additions & 2 deletions src/ansys/dpf/composites/constants.py
Original file line number Diff line number Diff line change
@@ -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):
Expand Down Expand Up @@ -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"
36 changes: 36 additions & 0 deletions src/ansys/dpf/composites/layup_info/_reference_surface.py
Original file line number Diff line number Diff line change
@@ -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
7 changes: 4 additions & 3 deletions src/ansys/dpf/composites/server_helpers/_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ 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."),
"8.0": _DpfVersionInfo("8.0", "2024 R2", "DPF Composites with plot on reference surface \
and section data from RST."),
"7.0": _DpfVersionInfo("7.0", "2024 R1 pre 0", "DPF Composites plugin with sub-operators."),
"7.1": _DpfVersionInfo("7.1", "2024 R1", "DPF Composites: layer index starts at 1. Material names."),
"8.0": _DpfVersionInfo("8.0", "2024 R2 pre 0", "DPF Composites: reference surface support and \
and section data from RST"),
}

def _check_key(ver: str) -> None:
Expand Down
Loading

0 comments on commit 28c53bd

Please sign in to comment.