Skip to content

Commit 3f3f2f5

Browse files
Refactor and unify result workflows (#684)
This commit is pure refactoring of the result workflows in dpf post. The goal is to centralize building the workflow for the different simulation types. Before this PR there was a lot of code duplication in the different simulation types. The old code was quite hard to follow, because the creation of the sub-workflows and their connection was mixed. To simplify the code I took the following approach: Convert all the sub-steps (averaging, principal, equivalent etc) into workflows. This simplifies the connection of the different sub-workflows. Previously a mix of operators, list of operators and (sub)workflows was used. The creation of the overall workflow is split into two steps: Create all the sub-workflows and put them into a ResultWorkflows object. sub-workflows that are not needed are None, Connect the sub-workflows to get a single big workflow Everything is moved to free functions so it is easy to reuse different parts of the workflow. Moved component related logic from Simulation class to free functions.
1 parent 1c61ca5 commit 3f3f2f5

15 files changed

+1173
-924
lines changed

src/ansys/dpf/post/dataframe.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -273,12 +273,14 @@ def select(self, **kwargs) -> DataFrame:
273273

274274
# # Treat selection on components
275275
if ref_labels.components in axis_kwargs.keys():
276-
from ansys.dpf.post.simulation import component_label_to_index
276+
from ansys.dpf.post.result_workflows._component_helper import (
277+
_component_label_to_index,
278+
)
277279

278280
comp_to_extract = axis_kwargs[ref_labels.components]
279281
if not isinstance(comp_to_extract, list):
280282
comp_to_extract = [comp_to_extract]
281-
component_indexes = [component_label_to_index[c] for c in comp_to_extract]
283+
component_indexes = [_component_label_to_index[c] for c in comp_to_extract]
282284
selector_fc = dpf.operators.logic.component_selector_fc(
283285
fields_container=input_fc,
284286
component_number=component_indexes,

src/ansys/dpf/post/fluid_simulation.py

+63-41
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,25 @@
77
from os import PathLike
88
from typing import List, Union
99

10+
from ansys.dpf.core import Workflow
1011
from ansys.dpf.core.server_types import BaseServer
1112

1213
from ansys.dpf import core as dpf
1314
from ansys.dpf.post import locations
1415
from ansys.dpf.post.dataframe import DataFrame
1516
from ansys.dpf.post.mesh_info import FluidMeshInfo
1617
from ansys.dpf.post.phase import PhasesDict
17-
from ansys.dpf.post.selection import Selection
18-
from ansys.dpf.post.simulation import ResultCategory, Simulation
18+
from ansys.dpf.post.result_workflows._component_helper import (
19+
ResultCategory,
20+
_create_components,
21+
)
22+
from ansys.dpf.post.result_workflows._connect_workflow_inputs import (
23+
_connect_initial_results_inputs,
24+
)
25+
from ansys.dpf.post.result_workflows._sub_workflows import _create_norm_workflow
26+
from ansys.dpf.post.result_workflows._utils import _append_workflows
27+
from ansys.dpf.post.selection import Selection, _WfNames
28+
from ansys.dpf.post.simulation import Simulation
1929
from ansys.dpf.post.species import SpeciesDict
2030

2131

@@ -223,16 +233,37 @@ def _get_result_workflow(
223233
qualifiers: Union[dict, None] = None,
224234
) -> (dpf.Workflow, Union[str, list[str], None], str):
225235
"""Generate (without evaluating) the Workflow to extract results."""
226-
comp, to_extract, columns = self._create_components(
227-
base_name, category, components
236+
comp, to_extract, columns = _create_components(base_name, category, components)
237+
238+
initial_result_workflow = Workflow(server=self._model._server)
239+
240+
initial_result_op = self._model.operator(name=base_name)
241+
initial_result_workflow.set_input_name(_WfNames.mesh, initial_result_op, 7)
242+
initial_result_workflow.set_input_name(_WfNames.location, initial_result_op, 9)
243+
244+
initial_result_workflow.add_operator(initial_result_op)
245+
initial_result_workflow.set_output_name(
246+
_WfNames.output_data, initial_result_op, 0
247+
)
248+
initial_result_workflow.set_input_name(
249+
"time_scoping", initial_result_op.inputs.time_scoping
250+
)
251+
initial_result_workflow.set_input_name(
252+
"mesh_scoping", initial_result_op.inputs.mesh_scoping
228253
)
229254

230-
# Initialize a workflow
231-
wf, result_op = self._build_result_workflow(
232-
name=base_name,
233-
location=location,
255+
_connect_initial_results_inputs(
256+
initial_result_workflow=initial_result_workflow,
234257
force_elemental_nodal=False,
258+
location=location,
259+
selection=selection,
260+
expand_cyclic=False,
261+
phase_angle_cyclic=None,
262+
mesh=self.mesh._meshed_region,
263+
streams_provider=self._model.metadata.streams_provider,
264+
data_sources=self._model.metadata.data_sources,
235265
)
266+
236267
query_regions_meshes = False
237268
lists = []
238269
lists_labels = []
@@ -268,7 +299,7 @@ def _get_result_workflow(
268299
label_space = {}
269300
for j, label in enumerate(lists_labels):
270301
label_space[label] = c[j]
271-
result_op.connect(1000 + i, label_space)
302+
initial_result_op.connect(1000 + i, label_space)
272303
# Its output is selected as future workflow output for now
273304
# print(result_op)
274305

@@ -277,44 +308,35 @@ def _get_result_workflow(
277308
# A MeshesProvider is required to give meshes as input of the source operator
278309
meshes_provider_op = self._model.operator("meshes_provider")
279310
meshes_provider_op.connect(25, query_regions_meshes)
280-
result_op.connect(7, meshes_provider_op.outputs.meshes)
281-
wf.add_operator(meshes_provider_op)
311+
initial_result_workflow.connect(
312+
_WfNames.mesh, meshes_provider_op.outputs.meshes
313+
)
314+
315+
initial_result_workflow.add_operator(meshes_provider_op)
282316
else:
283317
# Results have been queried on the whole mesh,
284318
# A MeshProvider is required to give the mesh as input of the source operator
285319
mesh_provider_op = self._model.operator("mesh_provider")
286-
result_op.connect(7, mesh_provider_op.outputs.mesh)
287-
wf.add_operator(mesh_provider_op)
288-
289-
out = result_op.outputs.fields_container
290-
# Its inputs are selected as workflow inputs for merging with selection workflows
291-
wf.set_input_name("time_scoping", result_op.inputs.time_scoping)
292-
wf.set_input_name("mesh_scoping", result_op.inputs.mesh_scoping)
293-
294-
wf.connect_with(
295-
selection.time_freq_selection._selection,
296-
output_input_names=("scoping", "time_scoping"),
297-
)
298-
wf.connect_with(
299-
selection.spatial_selection._selection,
300-
output_input_names=("scoping", "mesh_scoping"),
301-
)
302-
303-
# Connect data_sources and streams_container inputs of selection if necessary
304-
if "streams" in wf.input_names:
305-
wf.connect("streams", self._model.metadata.streams_provider)
306-
if "data_sources" in wf.input_names:
307-
wf.connect("data_sources", self._model.metadata.data_sources)
320+
initial_result_workflow.connect(
321+
_WfNames.mesh, mesh_provider_op.outputs.mesh
322+
)
323+
initial_result_workflow.add_operator(mesh_provider_op)
308324

309-
# Add an optional norm operation if requested
325+
output_wf = initial_result_workflow
310326
if norm:
311-
wf, out, comp, base_name = self._append_norm(wf, out, base_name)
327+
norm_workflow, base_name = _create_norm_workflow(
328+
create_operator_callable=self._model.operator,
329+
base_name=base_name,
330+
server=self._model._server,
331+
)
332+
333+
output_wf = _append_workflows(
334+
[norm_workflow], current_output_workflow=initial_result_workflow
335+
)
312336

313-
# Set the workflow output
314-
wf.set_output_name("out", out)
315-
wf.progress_bar = False
337+
output_wf.progress_bar = False
316338

317-
return wf, comp, base_name
339+
return output_wf, comp, base_name
318340

319341
def _get_result(
320342
self,
@@ -510,14 +532,14 @@ def _get_result(
510532
)
511533

512534
# Evaluate the workflow
513-
fc = wf.get_output("out", dpf.types.fields_container)
535+
fc = wf.get_output(_WfNames.output_data, dpf.types.fields_container)
514536
# print(fc)
515537
if location is None and len(fc) > 0:
516538
location = fc[0].location
517539
if location == locations.elemental:
518540
location = "cells"
519541

520-
_, _, columns = self._create_components(base_name, category, components)
542+
_, _, columns = _create_components(base_name, category, components)
521543
return self._create_dataframe(
522544
fc, location, columns, comp, base_name.split("::")[-1], None
523545
)

0 commit comments

Comments
 (0)