Create and manipulate a DPF dataframe#

This example shows how to generate a dataframe by extracting a result from a static simulation. It also shows different dataframe viewing and manipulation possibilities.

Perform required imports#

Perform required imports. This example uses a supplied file that you can get by importing the DPF examples package.

from ansys.dpf import post
from ansys.dpf.post import examples

Get the Simulation object#

Get the Simulation object that allows access to the result. The Simulation object must be instantiated with the path for the result file. For example, "C:/Users/user/my_result.rst" on Windows or "/home/user/my_result.rst" on Linux.

example_path = examples.download_crankshaft()
# to automatically detect the simulation type, use:
simulation = post.load_simulation(example_path)

# to enable auto-completion, use the equivalent:
simulation = post.StaticMechanicalSimulation(example_path)

# print the simulation to get an overview of what's available
print(simulation)
Static Mechanical Simulation.


Data Sources
------------------------------
/opt/hostedtoolcache/Python/3.10.16/x64/lib/python3.10/site-packages/ansys/dpf/core/examples/result_files/crankshaft/crankshaft.rst

DPF Model
------------------------------
Static analysis
Unit system: MKS: m, kg, N, s, V, A, degC
Physics Type: Mechanical
Available results:
     -  displacement: Nodal Displacement
     -  velocity: Nodal Velocity
     -  acceleration: Nodal Acceleration
     -  reaction_force: Nodal Force
     -  stress: ElementalNodal Stress
     -  elemental_volume: Elemental Volume
     -  stiffness_matrix_energy: Elemental Energy-stiffness matrix
     -  artificial_hourglass_energy: Elemental Hourglass Energy
     -  thermal_dissipation_energy: Elemental thermal dissipation energy
     -  kinetic_energy: Elemental Kinetic Energy
     -  co_energy: Elemental co-energy
     -  incremental_energy: Elemental incremental energy
     -  elastic_strain: ElementalNodal Strain
     -  element_euler_angles: ElementalNodal Element Euler Angles
     -  structural_temperature: ElementalNodal Structural temperature
------------------------------
DPF  Meshed Region:
  69762 nodes
  39315 elements
  Unit: m
  With solid (3D) elements
------------------------------
DPF  Time/Freq Support:
  Number of sets: 3
Cumulative     Time (s)       LoadStep       Substep
1              1.000000       1              1
2              2.000000       1              2
3              3.000000       1              3

Get a Dataframe object#

Extract a result as a dataframe.

displacement_dataframe = simulation.displacement(all_sets=True)

# The dataframe is displayed as a table, with row and column labels to identify the data.
print(displacement_dataframe)
            results       U (m)
            set_ids           1           2           3
node_ids components
    4872          X  5.6781e-06 -5.9469e-06 -3.4137e-05
                  Y  5.1667e-04  1.0318e-03  1.5417e-03
                  Z -3.2535e-06 -4.1346e-06 -2.6398e-06
    9005          X -2.6323e-06 -2.1432e-05 -5.5625e-05
                  Y  4.8445e-04  9.6717e-04  1.4448e-03
                  Z -4.9795e-07  1.2790e-06  5.3134e-06
     ...        ...         ...         ...         ...

Explore Index objects#

The data labels are each defined by an Index object or one of its specialized subtypes.

# The dataframe's column labels are defined in ``Dataframe.columns```.
print(displacement_dataframe.columns)
MultiIndex<[ResultIndex<['U (m)']>, SetIndex<values=[1, 2, 3]>]>

A ResultIndex index defines the result stored in the dataframe.

print(displacement_dataframe.columns[0])
# print(displacement_dataframe.columns.results_index)  # equivalent
ResultsIndex "results" with 1 values of <class 'str'> type

You can check values available for an index.

print(displacement_dataframe.columns[0].values)
['U (m)']

A SetIndex index defines the available set IDs available. A set ID is a unique identifier associated to each time-step, step and substep, or frequency available in a simulation. As shown next, an index has a name and a list of values of a given type.

print(displacement_dataframe.columns[1])
print(displacement_dataframe.columns[1].values)
SetIndex "set_ids" with 3 values of <class 'int'> type
[1, 2, 3]

The dataframe’s row labels are defined in dataframe.index.

print(displacement_dataframe.index)
MultiIndex<[MeshIndex<name="node_ids", dtype=<class 'int'>>, CompIndex<name="components", dtype=<class 'str'>>]>

A MeshIndex defines the mesh entities that data is available for. It can store node IDs, element IDs, or face IDs.

print(displacement_dataframe.index[0])
# print(displacement_dataframe.index.mesh_index)  # equivalent
MeshIndex "node_ids" with uncounted values of <class 'int'> type

Because the list of possible values can be long and querying it can be costly, the list of available values might not be determined unless explicitly asked.

print(displacement_dataframe.index[0].values)
[ 4872  9005  9373 ... 34314 19123 19114]

The MeshIndex is then updated to display the actual number of entities available.

print(displacement_dataframe.index[0])
# IMPORTANT: Note that the mesh entity IDs ordered based on the internal data storage structure,
# they are not by ascending order by default!
MeshIndex "node_ids" with 69762 values of <class 'int'> type

A CompIndex defines the result components that data is available for.

print(displacement_dataframe.index[1])
print(displacement_dataframe.index[1].values)
CompIndex "components" with 3 values of <class 'str'> type
['X', 'Y', 'Z']

Change the dataframe print#

Options exist to configure the way a dataframe is shown. You can change the number of data rows shown:

displacement_dataframe.display_max_rows = 9
print(displacement_dataframe)
            results       U (m)
            set_ids           1           2           3
node_ids components
    4872          X  5.6781e-06 -5.9469e-06 -3.4137e-05
                  Y  5.1667e-04  1.0318e-03  1.5417e-03
                  Z -3.2535e-06 -4.1346e-06 -2.6398e-06
    9005          X -2.6323e-06 -2.1432e-05 -5.5625e-05
                  Y  4.8445e-04  9.6717e-04  1.4448e-03
                  Z -4.9795e-07  1.2790e-06  5.3134e-06
    9373          X -2.6475e-05 -6.9632e-05 -1.2845e-04
                  Y  4.9502e-04  9.8751e-04  1.4741e-03
                  Z  6.9526e-06  1.6184e-05  2.7631e-05
     ...        ...         ...         ...         ...

You can change the number of data columns shown:

displacement_dataframe.display_max_columns = 2
print(displacement_dataframe)
# Notice that the ``...`` symbols specify that the Dataframe is truncated in that direction.
            results       U (m)             ...
            set_ids           1           2 ...
node_ids components                         ...
    4872          X  5.6781e-06 -5.9469e-06 ...
                  Y  5.1667e-04  1.0318e-03 ...
                  Z -3.2535e-06 -4.1346e-06 ...
    9005          X -2.6323e-06 -2.1432e-05 ...
                  Y  4.8445e-04  9.6717e-04 ...
                  Z -4.9795e-07  1.2790e-06 ...
    9373          X -2.6475e-05 -6.9632e-05 ...
                  Y  4.9502e-04  9.8751e-04 ...
                  Z  6.9526e-06  1.6184e-05 ...
     ...        ...         ...         ... ...

See node number in element’s connectivity#

When dealing with results located on each node of each element (which is known as ElementalNodal results, an ElementNodeIndex index is added at creation to specify the node number in the element’s connectivity.

stress = simulation.stress()
print(stress)
print(stress.columns[2])
                results      S (Pa)
                set_ids           3
                   node           0           1           2           3
 element_ids components
       18357         XX  4.6183e+06 -1.5497e+06 -1.8339e+06 -5.5596e+06
                     YY  5.9405e+07  4.6302e+07  1.2961e+08 -1.2675e+07
                     ZZ  2.2825e+07  4.1579e+07  1.4117e+08 -1.4662e+08
                     XY -3.5088e+05  2.7884e+07  1.5350e+08  1.6123e+08
                     YZ -5.9452e+08 -4.9103e+08 -5.1941e+08 -4.5894e+08
                     XZ  7.6945e+06  2.3978e+07  3.2925e+07 -2.2203e+07
         ...        ...         ...         ...         ...         ...

ElementNodeIndex "node" with 1 values of <class 'int'> type

Select data#

To select specific columns or rows, use the index names as arguments for the DataFrame.select() method, which takes lists of values:

disp_X_1 = displacement_dataframe.select(
    set_ids=[1], node_ids=[4872, 9005], components=["X"]
)
print(disp_X_1)
            results       U (m)
            set_ids           1
node_ids components
    4872          X  5.6781e-06
    9005            -2.6323e-06

You can also select along an index using a zero-based position with the Dataframe.iselect() method:

disp_Y_9005_3 = displacement_dataframe.iselect(
    set_ids=[2], node_ids=[1], components=[1]
)
print(disp_Y_9005_3)
            results      U (m)
            set_ids          3
node_ids components
    9005          Y 1.4448e-03

Extract data#

Once the dataframe contains the specific data you require, extract it as an array:

print(disp_X_1.array)
# IMPORTANT: Note that for the extraction of the Dataframe's data as an array to make sense,
# you must first filter the columns label values to a unique combination of values.
# The exception is for ElementalNodal data, which is returned as a 2D array.
print(stress.array.shape)
[ 5.67807472e-06 -2.63230351e-06]
(157260, 6)

Plot a dataframe#

displacement_dataframe.plot()
00 dataframe manipulation

Animate a transient dataframe#

displacement_dataframe.animate()
00 dataframe manipulation

Total running time of the script: (0 minutes 2.394 seconds)

Gallery generated by Sphinx-Gallery