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 Read me and fix plot bug #305

Merged
merged 7 commits into from
Mar 3, 2023
Merged
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
101 changes: 49 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,27 @@

The Data Processing Framework (DPF) is designed to provide numerical
simulation users/engineers with a toolbox for accessing and
transforming simulation data. DPF can access data from solver result
files as well as several neutral formats (csv, hdf5, vtk,
etc.). Various operators are available allowing the manipulation and
the transformation of this data.
transforming simulation data.

The Python `ansys-dpf-post` package provides a simplified Python
interface to DPF, thus enabling rapid postprocessing without ever
leaving a Python environment.
The Python `ansys-dpf-post` package provides a high level, physics oriented API for postprocessing.
Loading a simulation (defined by its result files) allows you to extract simulation metadata as well
as results and apply postprocessing operations on it.

This module leverages the DPF-Core project's ``ansys-dpf-core`` package and can
This module leverages the PyDPF-Core project's ``ansys-dpf-core`` package and can
be found by visiting [PyDPF-Core
GitHub](https://github.com/pyansys/pydpf-core). Use ``ansys-dpf-core`` for
building more advanced and customized workflows using Ansys's DPF.
building more advanced and customized workflows using Ansys DPF.


## Documentation

Visit the [DPF-Post Documentation](https://postdocs.pyansys.com) for a
detailed description of the package, or see the [Examples
Gallery](https://postdocs.pyansys.com/examples/index.html) for more
detailed examples.


### Installation
## Installation

Install this repository with:

Expand All @@ -42,58 +42,55 @@ cd pydpf-post
pip install . --user
```

### Running DPF-Post
Provided you have ANSYS 2021R1 installed, a DPF server will start
automatically once you start using DPF-Post. Should you wish to use
DPF-Post without 2020R1, see the [DPF Docker](https://dpfdocs.pyansys.com/getting_started/docker.html) documentation.

Opening and plotting a result file generated from Ansys workbench or
MAPDL is as easy as:
## Brief Demo

Provided you have ANSYS 2023 R1 installed, a DPF server will start
automatically once you start using pyDPF-Post.
Loading a simulation to extract and post-process results:

```python
```pycon
>>> from ansys.dpf import post
>>> from ansys.dpf.post import examples
>>> solution = post.load_solution(examples.multishells_rst)
>>> stress = solution.stress()
>>> stress.xx.plot_contour(show_edges=False)
>>> simulation = post.load_simulation(examples.download_crankshaft())
>>> displacement = simulation.displacement()
>>> print(displacement)
```

![Example Stress Plot](https://github.com/pyansys/dpf-post/raw/master/docs/source/images/main_example.png)


Or extract the raw data as a `numpy` array with:

```python
>>> stress.xx.get_data_at_field(0)
array([-3.37871094e+10, -4.42471752e+10, -4.13249463e+10, ...,
3.66408342e+10, 1.40736914e+11, 1.38633557e+11])
results U
set_id 3
node comp
4872 X -3.41e-05
Y 1.54e-03
Z -2.64e-06
9005 X -5.56e-05
Y 1.44e-03
Z 5.31e-06
...

```pycon
>>> displacement.plot()
```
![Example Displacement plot Crankshaft](https://github.com/pyansys/dpf-post/raw/master/docs/source/images/crankshaft_disp.png)
```pycon
>>> stress_eqv = simulation.stress_eqv_von_mises_nodal()
>>> stress_eqv.plot()
```
![Example Stress plot Crankshaft](https://github.com/pyansys/dpf-post/raw/master/docs/source/images/crankshaft_stress.png)

### Key Features


**Computational Efficiency**

The DPF-Post module is based on DPF Framework that been developed with
a data framework that localizes the loading and post-processing within
the DPF server, enabling rapid post-processing workflows as this is
written in C and FORTRAN. At the same time, the DPF-Post Python
module presents the result in Pythonic manner, allowing for the rapid
development of simple or complex post-processing scripts.


**Easy to use**
To run PyDPF-Post with Ansys versions starting from 2021 R1 to 2022 R2, use the following legacy PyDPF-Post
tools:

The API of DPF-Post module has been developed in order to make easy
post-processing steps easier by automating the use of DPF's chained
operators. This allows for fast post-processing of potentially
multi-gigabyte models in a short script. DPF-Post also details the
usage of the operators used when computing the results so you can also
build your own custom, low level scripts using the
[DPF-Core](https://github.com/pyansys/pydpf-core) module.
```pycon
>>> from ansys.dpf import post
>>> from ansys.dpf.post import examples
>>> solution = post.load_solution(examples.download_crankshaft())
>>> stress = solution.stress()
>>> stress.eqv.plot_contour(show_edges=False)
```
![Example Stress plot Crankshaft](https://github.com/pyansys/dpf-post/raw/master/docs/source/images/crankshaft_stress.png)


### License
## License

``PyDPF-Post`` is licensed under the MIT license. For more information, see the
[LICENSE](https://github.com/pyansys/dpf-post/raw/master/LICENSE).
Binary file added docs/source/images/crankshaft_disp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/images/crankshaft_stress.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
print(simulation.set_ids)

# extract displacement on given time steps or select the times steps from the already evaluated
# displacements
# displacement DataFrame
displacement = simulation.displacement(set_ids=simulation.set_ids[5:])
displacement = displacement.select(set_ids=simulation.set_ids[5:])
print(displacement)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,28 @@
# Extract displacements on named selections
# -----------------------------------------

bar1_tot_displacement = simulation.displacement(named_selections=['BAR_1'], norm=True)
bar1_tot_displacement = simulation.displacement(named_selections=["BAR_1"], norm=True)
print(bar1_tot_displacement)
bar1_tot_displacement.plot()

bar2_tot_displacement = simulation.displacement(named_selections=['BAR_2'], norm=True)
bar2_tot_displacement = simulation.displacement(named_selections=["BAR_2"], norm=True)
print(bar2_tot_displacement)
bar2_tot_displacement.plot()

# both
tot_displacement = simulation.displacement(named_selections=['BAR_1', 'BAR_2'], norm=True)
tot_displacement = simulation.displacement(
named_selections=["BAR_1", "BAR_2"], norm=True
)
print(tot_displacement)
tot_displacement.plot()

###############################################################################
# Extract stress and averaged stress on named selections
# ------------------------------------------------------
eqv_stress = simulation.stress_eqv_von_mises_nodal(named_selections=['_FIXEDSU'])
eqv_stress = simulation.stress_eqv_von_mises_nodal(named_selections=["_FIXEDSU"])
print(eqv_stress)

# without selection
elemental_stress = simulation.stress_elemental(named_selections=['BAR_1'])
elemental_stress = simulation.stress_elemental(named_selections=["BAR_1"])
print(elemental_stress)
elemental_stress.plot()
9 changes: 5 additions & 4 deletions examples/02-Detailed-Examples/02-modal-extract-sub-results.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

# To get X displacements on the first 2 modes
x_displacement = simulation.displacement(modes=[1, 2], components=["X"])
# equivalent to
# equivalent to
x_displacement = simulation.displacement(set_ids=[1, 2], components=["X"])
print(x_displacement)

Expand All @@ -54,7 +54,8 @@
###############################################################################
# Extract XX and XY elastic strain over a list modes
# --------------------------------------------------
# To get X displacements on the first 2 modes
XX_XY_elastic_strain = simulation.elastic_strain_nodal(modes=[3], components=["XX", "XY"])
# To get X displacements on the first 2 modes
XX_XY_elastic_strain = simulation.elastic_strain_nodal(
modes=[3], components=["XX", "XY"]
)
print(XX_XY_elastic_strain)

Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@

# columns
for column in displacement.columns:
print(f"Column with label \"{column.name}\" and available values {column.values}.")
print(f'Column with label "{column.name}" and available values {column.values}.')

# rows
for row in displacement.index:
print(f"Row with label \"{row.name}\" and available values {row.values}.")
print(f'Row with label "{row.name}" and available values {row.values}.')


###############################################################################
Expand Down Expand Up @@ -85,7 +85,9 @@
# Make multi selections in this DataFrame
# ---------------------------------------

real_values_for_one_set_onde_node = displacement.select(node=[3548], set_id=1, complex=0)
real_values_for_one_set_onde_node = displacement.select(
node=[3548], set_id=1, complex=0
)
print(real_values_for_one_set_onde_node)

###############################################################################
Expand Down
5 changes: 0 additions & 5 deletions examples/README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,3 @@ Examples
End-to-end examples show how you can use PyDPF-Post. If PyDPF-Post is installed
on your machine, you can download these examples as Python files or Jupyter
notebooks and run them locally.

.. note::
Some examples require additional Python packages.


16 changes: 12 additions & 4 deletions src/ansys/dpf/post/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,24 @@
from ansys.dpf.post.common import Grouping as grouping
from ansys.dpf.post.dataframe import DataFrame # noqa: F401
from ansys.dpf.post.dpf_path import create_path_on_coordinates
from ansys.dpf.post.harmonic_mechanical_simulation import ( # noqa: F401
HarmonicMechanicalSimulation,
)
from ansys.dpf.post.misc import Report
from ansys.dpf.post.modal_mechanical_simulation import ( # noqa: F401
ModalMechanicalSimulation,
)
from ansys.dpf.post.post_utility import (
load_simulation,
load_solution,
print_available_keywords,
)
from ansys.dpf.post.harmonic_mechanical_simulation import HarmonicMechanicalSimulation # noqa: F401
from ansys.dpf.post.transient_mechanical_simulation import TransientMechanicalSimulation # noqa: F401
from ansys.dpf.post.static_mechanical_simulation import StaticMechanicalSimulation # noqa: F401
from ansys.dpf.post.modal_mechanical_simulation import ModalMechanicalSimulation # noqa: F401
from ansys.dpf.post.static_mechanical_simulation import ( # noqa: F401
StaticMechanicalSimulation,
)
from ansys.dpf.post.transient_mechanical_simulation import ( # noqa: F401
TransientMechanicalSimulation,
)

# this must be after some ansys.dpf.post import
__version__ = importlib_metadata.version("ansys-dpf-post")
Expand Down
2 changes: 1 addition & 1 deletion src/ansys/dpf/post/examples/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import os

# alias files used by the core
from ansys.dpf.core.examples import * # noqa: F401
from ansys.dpf.core.examples import * # noqa: F403

# must copy files over when using docker
# running_docker = os.environ.get('DPF_DOCKER', False)
5 changes: 4 additions & 1 deletion src/ansys/dpf/post/post_utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,10 @@ def load_simulation(
simulation_type = AvailableSimulationTypes.static_mechanical
elif analysis_type == _AnalysisType.modal:
simulation_type = AvailableSimulationTypes.modal_mechanical
elif analysis_type == _AnalysisType.harmonic or analysis_type == _AnalysisType.msup:
elif (
analysis_type == _AnalysisType.harmonic
or analysis_type == _AnalysisType.msup
):
simulation_type = AvailableSimulationTypes.harmonic_mechanical
elif analysis_type == _AnalysisType.transient:
simulation_type = AvailableSimulationTypes.transient_mechanical
Expand Down
6 changes: 4 additions & 2 deletions src/ansys/dpf/post/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ class MechanicalSimulation(Simulation, ABC):
This class provides common methods and properties for all mechanical type simulations.
"""

def __init__(self, result_file: Union[PathLike,str]):
def __init__(self, result_file: Union[PathLike, str]):
"""Instantiate a mechanical type simulation."""
model = dpf.Model(result_file)
data_sources = model.metadata.data_sources
Expand Down Expand Up @@ -544,7 +544,9 @@ def _build_selection(
selection = Selection(server=self._model._server)
# Create the SpatialSelection
if named_selections:
selection.select_named_selection(named_selection=named_selections, location=location)
selection.select_named_selection(
named_selection=named_selections, location=location
)
elif element_ids is not None:
if location == locations.nodal:
selection.select_nodes_of_elements(elements=element_ids, mesh=self.mesh)
Expand Down
10 changes: 10 additions & 0 deletions tests/test_simulation.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os.path

import ansys.dpf.core as core
import numpy as np
import pytest
Expand Down Expand Up @@ -521,6 +523,14 @@ def test_elastic_strain_eqv_von_mises_elemental(self, static_simulation):
assert field.component_count == 1
assert np.allclose(field.data, field_ref.data)

def test_plot_stress_eqv_von_mises(self, static_simulation, tmp_path):
result = static_simulation.stress_eqv_von_mises_nodal()
result.plot()
d = tmp_path / "stress_eqv"
d.mkdir()
result.plot(screenshot=d / "stress.png")
os.path.exists(d / "stress.png")


class TestTransientMechanicalSimulation:
@fixture
Expand Down