Skip to content

Commit

Permalink
run pre-commit hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
roosre committed Sep 5, 2024
1 parent 94f2a22 commit 771b299
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 71 deletions.
61 changes: 23 additions & 38 deletions examples/013_thermal_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@
method to obtain the input files.
PyDPF Composites can also be used to post-process thermal analyses.
In this case, the simulation is a two-step analysis. The results of the thermal analysis
are used as input for a structural analysis. The result file of the structural analysis is
post-processed. It also includes the temperatures of the thermal analysis.
The example mimics a PCB which was modeled with Ansys Composites PrePost (ACP).
The solid model feature of ACP is used to generate the volume mesh.
Afterward, a thermal analysis is coupled with a static structural analysis.
This examples shows how to extract the temperatures for a specific ply,
and material.
where the solid model feature of ACP is used to generate the volume mesh.
In detail, the example shows how to extract the temperatures for a specific ply,
and a specific material.
"""


# %%
# Set up analysis
# ~~~~~~~~~~~~~~~
Expand All @@ -55,29 +55,13 @@
from ansys.dpf.composites.composite_model import CompositeModel
from ansys.dpf.composites.constants import TEMPERATURE_COMPONENT
from ansys.dpf.composites.example_helper import get_continuous_fiber_example_files
from ansys.dpf.composites.layup_info import AnalysisPlyInfoProvider, get_all_analysis_ply_names
from ansys.dpf.composites.layup_info import get_all_analysis_ply_names
from ansys.dpf.composites.ply_wise_data import SpotReductionStrategy, get_ply_wise_data
from ansys.dpf.composites.select_indices import (
get_selected_indices,
get_selected_indices_by_analysis_ply,
get_selected_indices_by_dpf_material_ids,
)
from ansys.dpf.composites.server_helpers import connect_to_or_start_server, version_equal_or_later
from ansys.dpf.composites.data_sources import get_composite_files_from_workbench_result_folder
from ansys.dpf.composites.select_indices import get_selected_indices_by_dpf_material_ids
from ansys.dpf.composites.server_helpers import connect_to_or_start_server

server = connect_to_or_start_server()
#composite_files = get_continuous_fiber_example_files(server, "thermal_solid")


# Folder that opens after clicking "Open Solver Files Directory"
result_folder = r"D:\ANSYSDev\acp_test_model_data\model_data\postprocessing\temperature\solids\thermal_solids_files\dp0\SYS-4\MECH"
# result_folder = r"D:\ANSYSDev\acp_test_model_data\model_data\class40\class40_files\dp0\SYS-4\MECH"

# Create the composite files object that contains
# the results file, the material properties file, and the
# composite definitions
composite_files = get_composite_files_from_workbench_result_folder(result_folder)

composite_files = get_continuous_fiber_example_files(server, "thermal_solid")

# %%
# Initialize the model
Expand All @@ -87,8 +71,8 @@
composite_model = CompositeModel(composite_files, server)

# %%
# Get Temperatures
# ~~~~~~~~~~~~~~~~
# Get Results - Temperatures
# ~~~~~~~~~~~~~~~~~~~~~~~~~~
# The temperatures are stored under structural_temperature
temp_op = composite_model.core_model.results.structural_temperature()
temperatures_fc = temp_op.outputs.fields_container()
Expand All @@ -97,14 +81,14 @@
# Ply-wise results
# ~~~~~~~~~~~~~~~~
# Ply-wise results can be easily extracted using the function
# :func:`.get_ply_wise_data` and passing the ply name.
# :func:`.get_ply_wise_data` and by passing the ply name.

all_ply_names = get_all_analysis_ply_names(composite_model.get_mesh())
print(all_ply_names)

nodal_values = get_ply_wise_data(
field=temperatures_fc,
ply_name='P1L1__ModelingPly.8',
ply_name="P1L1__ModelingPly.8",
mesh=composite_model.get_mesh(),
component=TEMPERATURE_COMPONENT,
spot_reduction_strategy=SpotReductionStrategy.MAX,
Expand All @@ -117,26 +101,27 @@
# Material-wise results
# ~~~~~~~~~~~~~~~~~~~~~
# It is also possible to filter the results by material
# The maximum temperature per element is extracted
# for the UD Resin Epoxy/E-Glass material
# In this example the element-wise maximum temperature
# is extracted for the material `Honeycomb Aluminum Alloy`.
print(composite_model.material_names)
material_id = composite_model.material_names["Honeycomb Aluminum Alloy"]

ud_material_id = composite_model.material_names["UD Resin Epoxy/E-Glass"]
# get the last result field
temperatures_field = temperatures_fc[-1]

material_result_field = dpf.field.Field(location=dpf.locations.elemental, nature=dpf.natures.scalar)
# performance optimization: use a local field instead of a field which is pushed to the server
with material_result_field.as_local_field() as local_result_field:
element_ids = temperatures_field.scoping.ids

for element_id in element_ids:
element_info = composite_model.get_element_info(element_id)
assert element_info is not None
if ud_material_id in element_info.dpf_material_ids:
if material_id in element_info.dpf_material_ids:
temp_data = temperatures_field.get_entity_data_by_id(element_id)
selected_indices = get_selected_indices_by_dpf_material_ids(
element_info, [ud_material_id]
)
selected_indices = get_selected_indices_by_dpf_material_ids(element_info, [material_id])

value = np.max(temp_data[selected_indices])
local_result_field.append([value], element_id)

composite_model.get_mesh().plot(material_result_field)
composite_model.get_mesh().plot(material_result_field)
10 changes: 7 additions & 3 deletions src/ansys/dpf/composites/_indexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,16 @@ def by_id(self, entity_id: int) -> Optional[NDArray[np.int64]]:


def _has_data_pointer(field: PropertyField | Field) -> bool:
if field._data_pointer is not None and field._data_pointer.any():
if (
field._data_pointer is not None and field._data_pointer.any()
): # pylint: disable=protected-access
return True
return False


def get_property_field_indexer(field: PropertyField, no_bounds_check: bool) -> PropertyFieldIndexerSingleValue | PropertyFieldIndexerArrayValue:
def get_property_field_indexer(
field: PropertyField, no_bounds_check: bool
) -> PropertyFieldIndexerSingleValue | PropertyFieldIndexerArrayValue:
"""Get indexer for a property field.
Parameters
Expand All @@ -89,13 +93,13 @@ def get_property_field_indexer(field: PropertyField, no_bounds_check: bool) -> P
return PropertyFieldIndexerNoDataPointer(field)



class FieldIndexSingleValueProtocol(Protocol):
"""Protocol for single value field indexer."""

def by_id(self, entity_id: int) -> Optional[np.double]:
"""Get index by id."""


# General comment for all Indexer:
# The .data call accesses the actual data. This sends the data over grpc which takes some time
# It looks like it returns a DpfArray for non-local fields and an numpy array for local fields.
Expand Down
2 changes: 1 addition & 1 deletion src/ansys/dpf/composites/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"REF_SURFACE_NAME",
"FAILURE_LABEL",
"TIME_LABEL",
"TEMPERATURE_COMPONENT"
"TEMPERATURE_COMPONENT",
)

FAILURE_LABEL = "failure_label"
Expand Down
29 changes: 21 additions & 8 deletions src/ansys/dpf/composites/example_helper/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
EXAMPLE_REPO = "https://github.com/ansys/example-data/raw/master/pydpf-composites/"


# Example URL to run the examples locally
# EXAMPLE_REPO = "file:////D:/Development/pyansys-example-data/pydpf-composites/"


@dataclass
class _ContinuousFiberCompositeFiles:
definition: str
Expand All @@ -62,7 +66,7 @@ class _ShortFiberCompositesExampleFilenames:

@dataclass
class _ContinuousFiberExampleLocation:
"""Location of the a given continuous fiber example in the example_data repo.
"""Location of a given continuous fiber example in the example_data repo.
Parameters
----------
Expand Down Expand Up @@ -151,6 +155,16 @@ class _ShortFiberExampleLocation:
},
),
),
"thermal_solid": _ContinuousFiberExampleLocation(
directory="thermal_solid",
files=_ContinuousFiberCompositesExampleFilenames(
rst=["file.rst"],
engineering_data="MatML.xml",
composite={
"shell": _ContinuousFiberCompositeFiles(definition="ACPSolidModel_SM.h5"),
},
),
),
}

_short_fiber_examples: dict[str, _ShortFiberExampleLocation] = {
Expand All @@ -168,7 +182,7 @@ def _get_file_url(directory: str, filename: str) -> str:


def _download_and_upload_file(
directory: str, filename: str, tmpdir: str, server: dpf.server
directory: str, filename: str, tmpdir: str, server: dpf.server
) -> str:
"""Download example file from example_data repo and upload it the dpf server."""
file_url = _get_file_url(directory, filename)
Expand All @@ -182,8 +196,8 @@ def _download_and_upload_file(


def get_short_fiber_example_files(
server: dpf.server,
example_key: str,
server: dpf.server,
example_key: str,
) -> ShortFiberCompositesFiles:
"""Get short fiber example file by example key.
Expand All @@ -197,7 +211,6 @@ def get_short_fiber_example_files(
"""
example_files = _short_fiber_examples[example_key]
with tempfile.TemporaryDirectory() as tmpdir:

def get_server_path(filename: str) -> str:
return _download_and_upload_file(example_files.directory, filename, tmpdir, server)

Expand All @@ -210,9 +223,9 @@ def get_server_path(filename: str) -> str:


def get_continuous_fiber_example_files(
server: dpf.server,
example_key: str,
skip_acp_layup_files: bool = False,
server: dpf.server,
example_key: str,
skip_acp_layup_files: bool = False,
) -> ContinuousFiberCompositesFiles:
"""Get continuous fiber example file by example key.
Expand Down
14 changes: 5 additions & 9 deletions src/ansys/dpf/composites/layup_info/_layup_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@
import numpy as np
from numpy.typing import NDArray

from .._indexer import (
get_field_indexer,
get_property_field_indexer
)
from .._indexer import get_field_indexer, get_property_field_indexer
from ..server_helpers import version_equal_or_later, version_older_than
from ._enums import LayupProperty

Expand Down Expand Up @@ -398,7 +395,6 @@ def __init__(
# focused on the most important properties. We can add different providers
# for other properties (such as thickness and angles)


# Has to be always with bounds checks because it does not contain
# data for all the elements

Expand All @@ -412,7 +408,9 @@ def __init__(

self.mesh = mesh
self.corner_nodes_by_element_type = _get_corner_nodes_by_element_type_array()
self.apdl_material_indexer = get_property_field_indexer(self.mesh.elements.materials_field, no_bounds_checks)
self.apdl_material_indexer = get_property_field_indexer(
self.mesh.elements.materials_field, no_bounds_checks
)

self.solver_material_to_dpf_id = {}
if solver_material_ids is not None:
Expand Down Expand Up @@ -463,9 +461,7 @@ def get_element_info(self, element_id: int) -> Optional[ElementInfo]:
dpf_material_ids = self.layer_materials.by_id(element_id)
assert dpf_material_ids is not None
if not isinstance(dpf_material_ids, np.ndarray):
dpf_material_ids = np.array(
[dpf_material_ids], dtype=np.int64
)
dpf_material_ids = np.array([dpf_material_ids], dtype=np.int64)

assert layer_data[0] + 1 == len(layer_data), "Invalid size of layer data"
n_layers = layer_data[0]
Expand Down
6 changes: 5 additions & 1 deletion src/ansys/dpf/composites/select_indices.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,11 @@ def get_selected_indices(
# Todo: Use numpy. Probably use ravel_multi_index method.
current_index = 0

num_nodes_per_spot = element_info.number_of_nodes_per_spot_plane if element_info.is_layered else element_info.n_corner_nodes
num_nodes_per_spot = (
element_info.number_of_nodes_per_spot_plane
if element_info.is_layered
else element_info.n_corner_nodes
)

for layer_index in layer_indices:
layer_start_index = layer_index * num_nodes_per_spot * element_info.n_spots
Expand Down
34 changes: 23 additions & 11 deletions tests/element_info_output_all_element_types_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
from collections.abc import Collection
from dataclasses import dataclass
import pathlib
import numpy as np

import ansys.dpf.core as dpf
from ansys.dpf.core import Field, MeshedRegion, PropertyField
import numpy as np
import pytest

from ansys.dpf.composites.constants import Spot
Expand Down Expand Up @@ -223,9 +223,7 @@ def get_element_info_provider_for_rst(rst_file, server):
mesh: MeshedRegion = mesh_provider.outputs.mesh()

with pytest.raises(RuntimeError) as exc_info:
layup_info = get_element_info_provider(
mesh, stream_provider_or_data_source=rst_data_source
)
layup_info = get_element_info_provider(mesh, stream_provider_or_data_source=rst_data_source)
assert str(exc_info.value).startswith("Missing property field in mesh")
material_property_field, layer_indices_property_field = get_layup_property_fields()
mesh.set_property_field("element_layered_material_ids", material_property_field)
Expand All @@ -235,7 +233,9 @@ def get_element_info_provider_for_rst(rst_file, server):

def test_document_error_cases_indices(dpf_server):

layup_info = get_element_info_provider_for_rst("model_with_all_element_types_minimal_output.rst", dpf_server)
layup_info = get_element_info_provider_for_rst(
"model_with_all_element_types_minimal_output.rst", dpf_server
)

for element_id in get_element_ids().layered:
with pytest.raises(RuntimeError) as exc_info:
Expand All @@ -253,7 +253,9 @@ def test_document_error_cases_indices(dpf_server):
"Computation of indices is not supported for non-layered elements."
)

layup_info = get_element_info_provider_for_rst("model_with_all_element_types_all_output.rst", dpf_server)
layup_info = get_element_info_provider_for_rst(
"model_with_all_element_types_all_output.rst", dpf_server
)

for element_id in get_element_ids().non_layered:
with pytest.raises(RuntimeError) as exc_info:
Expand Down Expand Up @@ -284,7 +286,9 @@ def test_document_error_cases_indices(dpf_server):
selected_indices = get_selected_indices_by_dpf_material_ids(element_info, [5])
assert len(selected_indices) == 0

layup_info = get_element_info_provider_for_rst("model_with_all_element_types_all_except_mid_output.rst", dpf_server)
layup_info = get_element_info_provider_for_rst(
"model_with_all_element_types_all_except_mid_output.rst", dpf_server
)

for element_id in get_element_ids().layered:
with pytest.raises(RuntimeError) as exc_info:
Expand Down Expand Up @@ -317,23 +321,29 @@ def test_select_indices_all_element_types(dpf_server):
51: np.array([0, 1, 2, 3, 4, 5]), # 6 node solid190
}

element_info_provider = get_element_info_provider_for_rst("model_with_all_element_types_all_output.rst", dpf_server)
element_info_provider = get_element_info_provider_for_rst(
"model_with_all_element_types_all_output.rst", dpf_server
)
element_ids = get_element_ids()
for elem_id in element_ids.all:
element_info = element_info_provider.get_element_info(elem_id)
# get_selected_indices is only supported for layered elements
if element_info.is_layered:
# All indices of the first layer
indices = get_selected_indices(element_info, layers=[0])
assert (indices == ref_indices_layer_0[elem_id]).all(), f"{element_info}, {indices} != {ref_indices_layer_0[elem_id]}"
assert (
indices == ref_indices_layer_0[elem_id]
).all(), f"{element_info}, {indices} != {ref_indices_layer_0[elem_id]}"

# All indices of the second layer via it's material ID
material_id = element_info.dpf_material_ids[1] # this is equivalent to the second layer
indices = get_selected_indices_by_dpf_material_ids(element_info, list([material_id]))

# Offset indices for the second layer
ref_2nd_layer = ref_indices_layer_0[elem_id] + max(ref_indices_layer_0[elem_id]) + 1
assert (indices == ref_2nd_layer).all(), f"{element_info}, i{indices} != {ref_2nd_layer}"
assert (
indices == ref_2nd_layer
).all(), f"{element_info}, i{indices} != {ref_2nd_layer}"

# Indices of the second layer and the top spot
indices = get_selected_indices(element_info, layers=[1], spots=[Spot.TOP])
Expand All @@ -345,4 +355,6 @@ def test_select_indices_all_element_types(dpf_server):
else:
# Layered solids have only bottom and top.
ref_2nd_layer_top = ref_2nd_layer[-num_indices:]
assert (indices == ref_2nd_layer_top).all(), f"{element_info}, {indices} != {ref_2nd_layer_top}"
assert (
indices == ref_2nd_layer_top
).all(), f"{element_info}, {indices} != {ref_2nd_layer_top}"

0 comments on commit 771b299

Please sign in to comment.