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

Enable split of results by element property #606

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
46 changes: 27 additions & 19 deletions src/ansys/dpf/post/selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
class _WfNames:
data_sources = "data_sources"
scoping = "scoping"
time_scoping = "time_scoping"
mesh_scoping = "mesh_scoping"
final_scoping = "final_scoping"
scoping_a = "scoping_a"
scoping_b = "scoping_b"
Expand Down Expand Up @@ -93,7 +95,7 @@ def select_time_freq_sets(self, time_freq_sets: List[int]) -> None:
)
op = operators.utility.forward(sets, server=self._server)
self._selection.add_operator(op)
self._selection.set_output_name(_WfNames.scoping, op.outputs.any)
self._selection.set_output_name(_WfNames.time_scoping, op.outputs.any)

def select_load_steps(self, load_steps: List[int]) -> None:
"""Select a list of load steps (one-based indexing).
Expand All @@ -106,7 +108,7 @@ def select_load_steps(self, load_steps: List[int]) -> None:
sets = time_freq_scoping_factory.scoping_by_load_steps(load_steps=load_steps)
op = operators.utility.forward(sets, server=self._server)
self._selection.add_operator(op)
self._selection.set_output_name(_WfNames.scoping, op.outputs.any)
self._selection.set_output_name(_WfNames.time_scoping, op.outputs.any)

def select_with_scoping(self, scoping: Scoping):
"""Directly sets the scoping as the time/freq selection.
Expand All @@ -124,7 +126,7 @@ def select_with_scoping(self, scoping: Scoping):

op = operators.utility.forward(scoping, server=self._server)
self._selection.add_operator(op)
self._selection.set_output_name(_WfNames.scoping, op.outputs.any)
self._selection.set_output_name(_WfNames.time_scoping, op.outputs.any)

def select_time_freq_values(
self, time_freq_values: Union[List[float], ndarray, Field]
Expand All @@ -147,7 +149,7 @@ def select_time_freq_values(
values = time_freq_field
op = operators.utility.forward(values, server=self._server)
self._selection.add_operator(op)
self._selection.set_output_name(_WfNames.scoping, op.outputs.any)
self._selection.set_output_name(_WfNames.time_scoping, op.outputs.any)

def _evaluate_on(self, simulation: Simulation) -> Union[Scoping, None]:
"""Returns what is evaluated from the selections made on a given Simulation.
Expand Down Expand Up @@ -178,7 +180,7 @@ def _evaluate_on(self, simulation: Simulation) -> Union[Scoping, None]:
_WfNames.data_sources, simulation._model.metadata.data_sources
)

return self._selection.get_output(_WfNames.scoping, types.scoping)
return self._selection.get_output(_WfNames.time_scoping, types.scoping)

def apply_to(self, simulation: Simulation) -> List[int]:
"""Performs the currently defined selection on the given Simulation.
Expand Down Expand Up @@ -253,7 +255,9 @@ def select_named_selection(
# self._selection.set_input_name(
# _WfNames.streams, op.inputs.streams_container
# )
self._selection.set_output_name(_WfNames.scoping, op.outputs.mesh_scoping)
self._selection.set_output_name(
_WfNames.mesh_scoping, op.outputs.mesh_scoping
)
else:
op = operators.utility.merge_scopings(server=self._server)
forward_ds = operators.utility.forward(any=None, server=self._server)
Expand All @@ -273,7 +277,9 @@ def select_named_selection(
mesh_scoping_op.connect(3, forward_sc.outputs.any)
mesh_scoping_op.connect(4, forward_ds.outputs.any)
op.connect(pin, mesh_scoping_op.outputs.mesh_scoping)
self._selection.set_output_name(_WfNames.scoping, op.outputs.merged_scoping)
self._selection.set_output_name(
_WfNames.mesh_scoping, op.outputs.merged_scoping
)

def select_external_layer(
self,
Expand Down Expand Up @@ -365,11 +371,11 @@ def select_external_layer(
self._selection.set_output_name(_WfNames.external_layer, op.outputs.mesh)
if location == locations.nodal:
self._selection.set_output_name(
_WfNames.scoping, op.outputs.nodes_mesh_scoping
_WfNames.mesh_scoping, op.outputs.nodes_mesh_scoping
)
elif location == locations.elemental or location == locations.elemental_nodal:
self._selection.set_output_name(
_WfNames.scoping, op.outputs.elements_mesh_scoping
_WfNames.mesh_scoping, op.outputs.elements_mesh_scoping
)

def select_skin(
Expand Down Expand Up @@ -463,7 +469,7 @@ def select_skin(
self._selection.set_output_name(_WfNames.skin, op.outputs.mesh)
if location == locations.nodal and result_native_location == locations.nodal:
self._selection.set_output_name(
_WfNames.scoping, op.outputs.nodes_mesh_scoping
_WfNames.mesh_scoping, op.outputs.nodes_mesh_scoping
)

elif not _is_model_cyclic(is_model_cyclic) and (
Expand All @@ -478,7 +484,7 @@ def select_skin(
_WfNames.initial_mesh, transpose_op.inputs.meshed_region
)
self._selection.set_output_name(
_WfNames.scoping, transpose_op.outputs.mesh_scoping_as_scoping
_WfNames.mesh_scoping, transpose_op.outputs.mesh_scoping_as_scoping
)

def select_with_scoping(self, scoping: Scoping):
Expand All @@ -497,7 +503,7 @@ def select_with_scoping(self, scoping: Scoping):

op = operators.utility.forward(scoping, server=self._server)
self._selection.add_operator(op)
self._selection.set_output_name(_WfNames.scoping, op.outputs.any)
self._selection.set_output_name(_WfNames.mesh_scoping, op.outputs.any)

def select_nodes(self, nodes: Union[List[int], Scoping]) -> None:
"""Select nodes using their IDs or a nodal mesh scoping.
Expand Down Expand Up @@ -546,7 +552,7 @@ def select_nodes_of_elements(
)
self._selection.add_operator(op)
self._selection.set_output_name(
_WfNames.scoping, op.outputs.mesh_scoping_as_scoping
_WfNames.mesh_scoping, op.outputs.mesh_scoping_as_scoping
)

def select_nodes_of_faces(
Expand Down Expand Up @@ -576,7 +582,7 @@ def select_nodes_of_faces(
)
self._selection.add_operator(op)
self._selection.set_output_name(
_WfNames.scoping, op.outputs.mesh_scoping_as_scoping
_WfNames.mesh_scoping, op.outputs.mesh_scoping_as_scoping
)

def select_faces_of_elements(
Expand Down Expand Up @@ -608,7 +614,7 @@ def select_faces_of_elements(
)
self._selection.add_operator(op)
self._selection.set_output_name(
_WfNames.scoping, op.outputs.mesh_scoping_as_scoping
_WfNames.mesh_scoping, op.outputs.mesh_scoping_as_scoping
)

def select_faces(self, faces: Union[List[int], Scoping]) -> None:
Expand Down Expand Up @@ -665,10 +671,12 @@ def intersect(
new_wf.add_operator(intersect_op)
new_wf.set_input_name(_WfNames.scoping_a, intersect_op.inputs.scopingA)
new_wf.set_input_name(_WfNames.scoping_b, intersect_op.inputs.scopingB)
new_wf.set_output_name(_WfNames.scoping, intersect_op.outputs.intersection)
new_wf.connect_with(self._selection, {_WfNames.scoping: _WfNames.scoping_a})
new_wf.set_output_name(_WfNames.mesh_scoping, intersect_op.outputs.intersection)
new_wf.connect_with(
self._selection, {_WfNames.mesh_scoping: _WfNames.scoping_a}
)
new_wf.connect_with(
spatial_selection._selection, {_WfNames.scoping: _WfNames.scoping_b}
spatial_selection._selection, {_WfNames.mesh_scoping: _WfNames.scoping_b}
)
self._selection = new_wf

Expand Down Expand Up @@ -704,7 +712,7 @@ def _evaluate_on(self, simulation: Simulation) -> Union[Scoping, None]:
_WfNames.data_sources, simulation._model.metadata.data_sources
)

return self._selection.get_output(_WfNames.scoping, types.scoping)
return self._selection.get_output(_WfNames.mesh_scoping, types.scoping)

def apply_to(self, simulation: Simulation) -> List[int]:
"""Performs the currently defined selection on the given Simulation.
Expand Down
63 changes: 56 additions & 7 deletions src/ansys/dpf/post/static_mechanical_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def _get_result_workflow(
selection: Union[Selection, None] = None,
expand_cyclic: Union[bool, List[Union[int, List[int]]]] = True,
phase_angle_cyclic: Union[float, None] = None,
split_by: Union[str, None] = None,
) -> (core.Workflow, Union[str, list[str], None], str):
"""Generate (without evaluating) the Workflow to extract results."""
comp, to_extract, _ = self._create_components(base_name, category, components)
Expand All @@ -47,12 +48,12 @@ def _get_result_workflow(
# Its output is selected as future workflow output for now
out = result_op.outputs.fields_container
# Its inputs are selected as workflow inputs for merging with selection workflows
wf.set_input_name("time_scoping", result_op.inputs.time_scoping)
wf.set_input_name("mesh_scoping", result_op.inputs.mesh_scoping)
wf.set_input_name(_WfNames.time_scoping, result_op.inputs.time_scoping)
wf.set_input_name(_WfNames.mesh_scoping, result_op.inputs.mesh_scoping)

wf.connect_with(
selection.time_freq_selection._selection,
output_input_names=("scoping", "time_scoping"),
output_input_names=(_WfNames.time_scoping, _WfNames.time_scoping),
)
if selection.requires_mesh:
mesh_wf = core.Workflow(server=self._model._server)
Expand All @@ -65,10 +66,50 @@ def _get_result_workflow(
output_input_names={_WfNames.initial_mesh: _WfNames.initial_mesh},
)

wf.connect_with(
selection.spatial_selection._selection,
output_input_names={"scoping": "mesh_scoping"},
)
if split_by:
split_wf = core.Workflow(server=self._model._server)
outputs_to_inputs = {}
if split_by in [
core.common.elemental_properties.material,
core.common.elemental_properties.element_shape,
]:
split_op = core.operators.scoping.split_on_property_type(
label1=split_by,
requested_location=location,
server=self._model._server,
)
if (
_WfNames.mesh_scoping
in selection.spatial_selection._selection.output_names
):
split_wf.set_input_name(
_WfNames.mesh_scoping, split_op.inputs.mesh_scoping
)
outputs_to_inputs[_WfNames.mesh_scoping] = _WfNames.mesh_scoping
if _WfNames.mesh in selection.spatial_selection._selection.output_names:
split_wf.set_input_name(_WfNames.mesh, split_op.inputs.mesh)
outputs_to_inputs[_WfNames.mesh] = _WfNames.mesh
else:
split_op.inputs.mesh.connect(self.mesh._meshed_region)
split_wf.set_output_name(
_WfNames.mesh_scoping, split_op.outputs.mesh_scoping
)
split_wf.add_operator(split_op)

split_wf.connect_with(
selection.spatial_selection._selection,
output_input_names=outputs_to_inputs,
)

wf.connect_with(
split_wf,
output_input_names={_WfNames.mesh_scoping: _WfNames.mesh_scoping},
)
else:
wf.connect_with(
selection.spatial_selection._selection,
output_input_names={_WfNames.mesh_scoping: _WfNames.mesh_scoping},
)

# Treat cyclic cases
wf = self._treat_cyclic(expand_cyclic, phase_angle_cyclic, wf)
Expand Down Expand Up @@ -187,6 +228,7 @@ def _get_result(
phase_angle_cyclic: Union[float, None] = None,
external_layer: Union[bool, List[int]] = False,
skin: Union[bool, List[int]] = False,
split_by: Union[str, None] = None,
) -> DataFrame:
"""Extract results from the simulation.

Expand Down Expand Up @@ -254,6 +296,8 @@ def _get_result(
is computed over list of elements (not supported for cyclic symmetry). Getting the
skin on more than one result (several time freq sets, split data...) is only
supported starting with Ansys 2023R2.
split_by:
Property to split the result on ("mat", "elshape", "part").

Returns
-------
Expand Down Expand Up @@ -299,6 +343,7 @@ def _get_result(
selection=selection,
expand_cyclic=expand_cyclic,
phase_angle_cyclic=phase_angle_cyclic,
split_by=split_by,
)

# Evaluate the workflow
Expand Down Expand Up @@ -336,6 +381,7 @@ def displacement(
phase_angle_cyclic: Union[float, None] = None,
external_layer: Union[bool, List[int]] = False,
skin: Union[bool, List[int]] = False,
split_by: Union[str, None] = None,
) -> DataFrame:
"""Extract displacement results from the simulation.

Expand Down Expand Up @@ -392,6 +438,8 @@ def displacement(
is computed over list of elements (not supported for cyclic symmetry). Getting
the skin on more than one result (several time freq sets, split data...) is
only supported starting with Ansys 2023R2.
split_by:
Property to split the result on ("mat", "elshape", "part").

Returns
-------
Expand All @@ -416,6 +464,7 @@ def displacement(
phase_angle_cyclic=phase_angle_cyclic,
external_layer=external_layer,
skin=skin,
split_by=split_by,
)

def stress(
Expand Down
Loading