Skip to content

Commit

Permalink
Implement StaticMechanicalSimulation results (#261)
Browse files Browse the repository at this point in the history
* Pseudocode for mechanical static analysis type

* Pseudocode for mechanical transient analysis type

* Pseudocode for mechanical modal analysis type

* Pseudocode for mechanical harmonic analysis type

* Improve the Simulation time_freq_support access API

* Add Mesh API section

* Improve static_analysis.py

* Improve static_analysis.py

* Improve static_analysis.py

* Improve static_analysis.py

* Improve static_analysis.py

* Improve transient_analysis.py

* Improve static_analysis.py

* Improve static_analysis.py

* Improve static_analysis.py

* Improve static_analysis.py

* Improve static_analysis.py

* Make static_analysis.py runnable

* Update static_analysis.py

* Update static_analysis.py

* Update static_analysis.py

* static_analysis.md

* Update static_analysis.md

* Update static_analysis.md

* meetng discussions

* Add StaticMechanicalSimulation, TransientMechanicalSimulation, ModalMechanicalSimulation and HarmonicMechanicalSimulation

* Link each mechanical simulation type in load_simulation()

* Add Simulation.geometries property

* Add Simulation.boundary_conditions and refactor Simulation.geometries

* Add Simulation.loads

* Add Simulation.named_selections

* Add StaticMechanicalSimulation.steps

* Simulation.results now returns the list of string representations of available results

* Add Simulation.plot

* Add Simulation.plot with geometry

* Fix Simulation.activate_selection

* Add load_simulation tests

* Add AvailableSimulationTypes
Add test_load_simulation.py
Refactor load_simulation's simulation type logic
transient_rst example is not loaded as transient by default

* Switched test_load_simulation_transient_mechanical to use plate_msup which is recognized as transient.

* Add test_simulation.py

* Improve typehinting

* Improve coverage for load_simulation

* Improve Simulation.mesh docstring

* Add Simulation.active_selection property

* Solution -> Simulation in selection.py

* Add test_simulation_active_selection and improve imports

* Remove StaticMechanicalSimulation.steps property.

* Add a basic test_simulation_plot

* Change docs/src/api/index.rst to include old and new APIs.

* Clean-up simulation.py

* Clean-up simulation.py

* Improve docstrings

* Fix doctest simulation.mesh

* Take into account meeting recommendations

* Fix typehinting of load_simulation

* Clean MechanicalSimulation.displacement

* Add components logic for result extraction
Add time_scoping building logic for static_analysis.py

* Add TestStaticMechanicalSimulation.test_displacement

* Add TestStaticMechanicalSimulation.test_displacement with named_selection

* Add Simulation._build_op_names_from_principal_components

* Add Simulation._build_op_names_from_principal_components

* Allow for single values for set_ids, times, load_steps, and sub-steps.
A location argument can be given to the MechanicalSimulation._build_mesh_scoping method

* Location transpose works for both elemental and nodal

* Fixed "elements" argument for displacement (or any nodal based result)

* Refactor with a common _get_result

* switch test_simulation to static_rst instead of simple_bar

* Add stress()

* Refactor naming

* Add stress_eqv_von_mises_elemental

* Add stress_eqv_von_mises_nodal

* Treat case with no spatial input

* Add elastic and plastic strain

* Add case of invalid category requested

* Make _build_time_freq_scoping and _build_mesh_scoping abstract and mandatory

* Add reaction_force and update tests to be consistent with results using pydpf-core directly.

* Add elemental_volume (needs a bug fix server-side)

* Fix mesh_scoping when None is given (to work on the real complete mesh with hidden elements)

* Add several new results to StaticMechanicalSimulation

* Add element_nodal_forces

* Add element_nodal_forces_nodal and element_nodal_forces_elemental

* Switch to an "extract all components+select" logic

* Move element_nodal_forces apis back into static

* Add norm argument, remove rogue print

* Add norm argument to other vectorial results

* Allow str for simulation_type argument of load_simulation.

* components argument for result queries becomes "component_ids"

* components argument for result queries becomes "component_ids"

* Raise warning when returning an empty dataframe, with column names indicating which request it was.

* Raise warning when returning an empty dataframe, with column names indicating which request it was.

* Raise warning when returning an empty dataframe, with column names indicating which request it was.

* fix dosctrings according to new result extraction APIs

* fix dosctrings according to new result extraction APIs

* Add stress_eqv_von_mises

* Fix stress_eqv_von_mises* docstrings

* Fix stress* docstrings

* Refactor result categories and workflow construction to decompose it more. Principals not working

* Fix principals

* Test different principal components

* Add elastic_strain_principal and _eqv

* Add plastic_strain_principal and _eqv

* Add creep strain

* Add hydrostatic_pressure, elemental_mass, elemental_heat_generation, element_orientations, element_centroids, thickness, nodal_moment, nodal_force, plastic_state_variable

* Add static_mechanical overview example from Guillem's PR

* Update 02-get_data_from_static_simulation.py with currently working code

* Update pseudo-code for dpf.load_simulation

* Rename Simulation.geometries to Simulation.constructed_geometries

* Update Simulation.plot to take a constructed_geometries argument

* Update Selection pseudo-code according to comments

* Add main case of Selection creation via tools.create_selection

* Apply suggestions from code review

Co-authored-by: Maxime Rey <[email protected]>

* Delete pseudo-code from code PR

---------

Co-authored-by: Camille Bellot <[email protected]>
Co-authored-by: Maxime Rey <[email protected]>
  • Loading branch information
3 people committed Mar 8, 2023
1 parent 78713d8 commit 03dc0d8
Show file tree
Hide file tree
Showing 6 changed files with 4,309 additions and 118 deletions.
100 changes: 100 additions & 0 deletions examples/00-Overview/02-get_data_from_static_simulation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
"""
.. _ref_get_data_from_static_simulation:
Get data from static simulation
===============================
This example shows how to request data from a previously stored static simulation.
The available results can be listed to see what results can be retrieved.
"""

###############################################################################
# Imports and loading simulation
# ------------------------------
import ansys.dpf.post as dpf
from ansys.dpf.post import examples

simulation = dpf.load_simulation(examples.static_rst)
print(simulation)

###############################################################################
# Get and plot displacements
# --------------------------
displacement = simulation.displacement()

###############################################################################
# Print information
print(displacement._fc)

###############################################################################
# Plot displacements
displacement._fc[0].plot()

###############################################################################
# Get and plot stresses
# ---------------------
# Request "XY" stress component averaged on nodes
stress = simulation.stress_nodal(component_ids="XY")

###############################################################################
# Print information
print(stress._fc)

###############################################################################
# Plot available stresses.
stress._fc[0].plot()

###############################################################################
# Get stresses at only 5 nodes
# ------------------------------
# Request stress only at the first 5 nodes using their IDs.
stress_nodes = simulation.stress_nodal(nodes=range(1, 6))

###############################################################################
# Print information
print(stress_nodes._fc)

###############################################################################
# Plot stresses
stress_nodes._fc[0].plot()

###############################################################################
# Get stresses in a named selection
# ---------------------------------
# Get the name of the first named selection in the simulation
ns = simulation.named_selections[0]
# Request nodal stresses for this named selection
stress_named_sel = simulation.stress_nodal(named_selection=ns)

###############################################################################
# Print information
print(stress_named_sel._fc)

###############################################################################
# Plot stresses
stress_named_sel._fc[0].plot()

###############################################################################
# Get stresses in a few elements
# ------------------------------
# Request stress only for a few elements selected by their ID
stress_elements = simulation.stress_nodal(elements=[1, 2, 3])

###############################################################################
# Print information
print(stress_elements._fc)

###############################################################################
# Plot stresses
stress_elements._fc[0].plot()

###############################################################################
# Get elemental stress and raw stresses
# -------------------------------------
# Request elemental stresses and print information
stress_elements = simulation.stress_elemental()
print(stress_elements._fc)

###############################################################################
# Request raw stresses ("ElementalNodal") and print information
stress_raw = simulation.stress()
print(stress_raw._fc)
16 changes: 12 additions & 4 deletions src/ansys/dpf/post/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,15 @@ class _PhysicsType:
class AvailableSimulationTypes:
"""Contains available simulation types to give the :func:`load_simulation` function."""

static_mechanical = StaticMechanicalSimulation
transient_mechanical = TransientMechanicalSimulation
modal_mechanical = ModalMechanicalSimulation
harmonic_mechanical = HarmonicMechanicalSimulation
static_mechanical = "static mechanical" # StaticMechanicalSimulation
transient_mechanical = "transient mechanical" # TransientMechanicalSimulation
modal_mechanical = "modal mechanical" # ModalMechanicalSimulation
harmonic_mechanical = "harmonic mechanical" # HarmonicMechanicalSimulation


simulation_type_str_to_class = {
AvailableSimulationTypes.static_mechanical: StaticMechanicalSimulation,
AvailableSimulationTypes.transient_mechanical: TransientMechanicalSimulation,
AvailableSimulationTypes.modal_mechanical: ModalMechanicalSimulation,
AvailableSimulationTypes.harmonic_mechanical: HarmonicMechanicalSimulation,
}
6 changes: 3 additions & 3 deletions src/ansys/dpf/post/data_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ def as_data_frame(self, columns=None, **kwargs):
>>> from ansys.dpf.post import examples
>>> simulation = post.load_simulation(examples.multishells_rst)
>>> # Export the displacements vector field at step 1 as a DataFrame
>>> displacement = simulation.displacement(steps=[1], nodes=[1, 2, 3])
>>> displacement = simulation.displacement(load_steps=[1], nodes=[1, 2, 3])
>>> df = displacement.as_data_frame()
>>> print(df)
X Y Z
UX UY UZ
1 0.398320 -13.797378 -0.163767
2 0.233114 -13.797652 -0.153190
3 0.367542 -13.808151 -0.163739
Expand Down Expand Up @@ -113,7 +113,7 @@ def as_array(self):
>>> from ansys.dpf.post import examples
>>> simulation = post.load_simulation(examples.multishells_rst)
>>> # Export the displacements vector field at step 1 as a DataFrame
>>> displacement = simulation.displacement(steps=[1], nodes=[1, 2, 3])
>>> displacement = simulation.displacement(load_steps=[1], nodes=[1, 2, 3])
>>> arr = displacement.as_array()
>>> print(arr)
[[ 0.39831985 -13.79737819 -0.16376683]
Expand Down
27 changes: 13 additions & 14 deletions src/ansys/dpf/post/post_utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
This module is used for the initialization of DPF-Post objects.
"""
from typing import TypeVar, Union
import warnings

from ansys.dpf.core.model import Model
Expand All @@ -11,16 +12,11 @@
_AnalysisType,
_AvailableKeywords,
_PhysicsType,
simulation_type_str_to_class,
)
from ansys.dpf.post.harmonic_analysis import HarmonicAnalysisSolution
from ansys.dpf.post.modal_analysis import ModalAnalysisSolution
from ansys.dpf.post.simulation import (
HarmonicMechanicalSimulation,
ModalMechanicalSimulation,
Simulation,
StaticMechanicalSimulation,
TransientMechanicalSimulation,
)
from ansys.dpf.post.simulation import Simulation
from ansys.dpf.post.static_analysis import (
StaticAnalysisSolution,
ThermalStaticAnalysisSolution,
Expand Down Expand Up @@ -112,10 +108,13 @@ def load_solution(data_sources, physics_type=None, analysis_type=None):
raise ValueError(f"Unknown physics type '{physics_type}.")


SimulationType = TypeVar("SimulationType", bound=Simulation)


def load_simulation(
data_sources,
simulation_type: AvailableSimulationTypes = None,
) -> Simulation:
simulation_type: Union[AvailableSimulationTypes, str] = None,
) -> SimulationType:
"""Loads a simulation and returns a :class:`ansys.dpf.post.simulation.Simulation` object.
This class provides the main interface to explore and manipulate results, meshes, geometries,
Expand Down Expand Up @@ -196,13 +195,13 @@ def load_simulation(
or physics_type == _PhysicsType.mechanical
):
if analysis_type == _AnalysisType.static:
simulation_type = StaticMechanicalSimulation
simulation_type = AvailableSimulationTypes.static_mechanical
elif analysis_type == _AnalysisType.modal:
simulation_type = ModalMechanicalSimulation
simulation_type = AvailableSimulationTypes.modal_mechanical
elif analysis_type == _AnalysisType.harmonic:
simulation_type = HarmonicMechanicalSimulation
simulation_type = AvailableSimulationTypes.harmonic_mechanical
elif analysis_type == _AnalysisType.transient:
simulation_type = TransientMechanicalSimulation
simulation_type = AvailableSimulationTypes.transient_mechanical
else:
raise ValueError(
f"Unknown analysis type '{analysis_type}' for mechanical."
Expand All @@ -213,7 +212,7 @@ def load_simulation(
if simulation_type in [
getattr(AvailableSimulationTypes, x) for x in vars(AvailableSimulationTypes)
]:
return simulation_type(data_sources, _model)
return simulation_type_str_to_class[simulation_type](data_sources, _model)
else:
raise ValueError(
f"Simulation type '{simulation_type}' is not a recognized simulation type."
Expand Down
Loading

0 comments on commit 03dc0d8

Please sign in to comment.