# Thermal-structural analysis of exhaust manifold#

Summary: This example illustrates how to map results from a CFD analysis and perform a Finite Element (FE) analysis.

## Objective#

In this example, we will perform an FE analysis to compute the thermal stresses developed in an exhaust manifold. The manifold is made of structural steel and the temperature distribution in it is obtained from a CFD run. We import this data and map it onto FE mesh to define thermal load at each node using Gaussian interpolation kernel.

## Procedure#

• Launch MAPDL instance

• Import geometry, assign material properties, and generate FE mesh.

• Import temperature distribution and map it on FE mesh

• Define BCs and use imported temperature distribution to define thermal load.

• Solve the model and plot the results of interest.

• Numpy for using data as arrays

• Pandas to import csv file (to install use: pip install pandas)

• PyVista for performing Gauissian interpolation

## Boundary Conditions#

• Highlighted faces are fully constrained.

## Import all necessary modules and launch an instance of MAPDL#

```import numpy as np
import pandas as pd
import pyvista as pv

from ansys.mapdl.core import launch_mapdl

# start mapdl
mapdl = launch_mapdl()
print(mapdl)
```
```Product:             Ansys Mechanical Enterprise
MAPDL Version:       22.2
ansys.mapdl Version: 0.63.1
```

## Import geometry, assign material properties and generate a mesh.#

```# download the necessary files
geometry = paths["geometry"]
mapping_data = paths["mapping_data"]

# reset mapdl & import geometry
mapdl.clear()
mapdl.input(geometry)

# Define element attributes
# Second-order tetrahedral elements (SOLID187)
mapdl.prep7()
mapdl.et(1, "SOLID187")

# Define material properties of structural steel
E = 2e11  # Youngs modulus
NU = 0.3  # Poisson's ratio
CTE = 1.2e-5  # Coeff. of thermal expansion
mapdl.mp("EX", 1, E)
mapdl.mp("PRXY", 1, NU)
mapdl.mp("ALPX", 1, CTE)

# Define mesh controls and generate mesh
mapdl.esize(0.0075)
mapdl.vmesh("all")

# Save mesh as VTK object
print(mapdl.mesh)
grid = mapdl.mesh.grid  # save mesh as a VTK object
```
```ANSYS Mesh
Number of Nodes:              87637
Number of Elements:           44277
Number of Element Types:      1
Number of Node Components:    0
Number of Element Components: 0
```

## Import and map temperature data to FE mesh#

```# Import csv file and save data to a NumPy array
temperature_data = temperature_file.values  # Save data to a NumPy array
nd_temp_data = temperature_data[1:, 1:].astype(float)  # Change data type to Float

# Map temperature data to FE mesh
# Convert imported data into PolyData format
wrapped = pv.PolyData(nd_temp_data[:, :3])  # Convert NumPy array to PolyData format
wrapped["temperature"] = nd_temp_data[
:, 3
]  # Add a scalar variable 'temperature' to PolyData

# Perform data mapping
inter_grid = grid.interpolate(
)  # Map the imported data to MAPDL grid
inter_grid.plot(show_edges=False)  # Plot the interpolated data on MAPDL grid
pv.convert_array(inter_grid.active_scalars)
)  # Save temperatures interpolated to each node as NumPy array
node_num = inter_grid.point_data["ansys_node_num"]  # Save node numbers as NumPy array
```
```  0%|          [00:00<?]
Interpolating:   0%|          [00:00<?]
Interpolating: 100%|##########[00:00<00:00]
Interpolating: 100%|##########[00:00<00:00]
Interpolating: 100%|##########[00:00<00:00]
```

## Apply loads and boundary conditions and solve the model#

```# Read all nodal coords. to an array & extract the X and Y min. bounds
array_nodes = mapdl.mesh.nodes
Xmin = np.amin(array_nodes[:, 0])
Ymin = np.amin(array_nodes[:, 1])

# Enter /SOLU processor to apply loads and BCs
mapdl.finish()
mapdl.slashsolu()

# Enter non-interactive mode to assign thermal load at each node using imported data
with mapdl.non_interactive:
for node, temp in zip(node_num, temperature_load_val):
mapdl.bf(node, "TEMP", temp)
# Use the X and Y min. bounds to select nodes from five surfaces that are to be fixed and created a component and fix all DOFs.
mapdl.nsel("s", "LOC", "X", Xmin)  # Select all nodes whose X coord.=Xmin
mapdl.nsel(
"a", "LOC", "Y", Ymin
)  # Select all nodes whose Y coord.=Ymin and add to previous selection
mapdl.cm("fixed_nodes", "NODE")  # Create a nodal component 'fixed_nodes'
mapdl.allsel()  # Revert active selection to full model
mapdl.d(
"fixed_nodes", "all", 0
)  # Impose fully fixed constraint on component created earlier

# Solve the model
output = mapdl.solve()
print(output)
```
```*****  MAPDL SOLVE    COMMAND  *****

*** WARNING ***                         CP =      82.086   TIME= 06:13:22
Previous testing revealed that 123 of the 44277 selected elements
violate shape warning limits.  To review warning messages, please see
the output or error file, or issue the CHECK command.

*** NOTE ***                            CP =      82.086   TIME= 06:13:22
The model data was checked and warning messages were found.
Please review output or errors file ( /file.err ) for these warning
messages.

*** SELECTION OF ELEMENT TECHNOLOGIES FOR APPLICABLE ELEMENTS ***
---GIVE SUGGESTIONS ONLY---

ELEMENT TYPE         1 IS SOLID187. IT IS NOT ASSOCIATED WITH FULLY INCOMPRESSIBLE
HYPERELASTIC MATERIALS. NO SUGGESTION IS AVAILABLE.

*** MAPDL - ENGINEERING ANALYSIS SYSTEM  RELEASE                  22.2     ***
Ansys Mechanical Enterprise
00000000  VERSION=LINUX x64     06:13:22  AUG 03, 2022 CP=     82.108

File: D:\AICs\PyAnsys\Getting Started With PyMAPDL\Dataflow Between Python an

S O L U T I O N   O P T I O N S

PROBLEM DIMENSIONALITY. . . . . . . . . . . . .3-D
DEGREES OF FREEDOM. . . . . . UX   UY   UZ
ANALYSIS TYPE . . . . . . . . . . . . . . . . .STATIC (STEADY-STATE)
GLOBALLY ASSEMBLED MATRIX . . . . . . . . . . .SYMMETRIC

*** NOTE ***                            CP =      82.170   TIME= 06:13:22
Present time 0 is less than or equal to the previous time.  Time will
default to 1.

*** NOTE ***                            CP =      82.171   TIME= 06:13:22
The conditions for direct assembly have been met.  No .emat or .erot
files will be produced.

L O A D   S T E P   O P T I O N S

LOAD STEP NUMBER. . . . . . . . . . . . . . . .     1
TIME AT END OF THE LOAD STEP. . . . . . . . . .  1.0000
NUMBER OF SUBSTEPS. . . . . . . . . . . . . . .     1
STEP CHANGE BOUNDARY CONDITIONS . . . . . . . .    NO
PRINT OUTPUT CONTROLS . . . . . . . . . . . . .NO PRINTOUT
DATABASE OUTPUT CONTROLS. . . . . . . . . . . .ALL DATA WRITTEN
FOR THE LAST SUBSTEP

SOLUTION MONITORING INFO IS WRITTEN TO FILE= file.mntr

Range of element maximum matrix coefficients in global coordinates
Maximum = 1.562734624E+11 at element 6128.
Minimum = 304040659 at element 27522.

*** ELEMENT MATRIX FORMULATION TIMES
TYPE    NUMBER   ENAME      TOTAL CP  AVE CP

1     44277  SOLID187      5.865   0.000132
Time at end of element matrix formulation CP = 86.3691635.

SPARSE MATRIX DIRECT SOLVER.
Number of equations =      252033,    Maximum wavefront =    213

*** NOTE ***                            CP =      88.917   TIME= 06:13:27
The initial memory allocation (-m) has been exceeded.
Supplemental memory allocations are being used.
Memory allocated for solver              =  1066.936 MB
Memory required for in-core solution     =  1023.691 MB
Memory required for out-of-core solution =   355.872 MB

*** NOTE ***                            CP =      88.917   TIME= 06:13:27
The Sparse Matrix Solver is currently running in the in-core memory
mode.  This memory mode uses the most amount of memory in order to
avoid using the hard drive as much as possible, which most often
results in the fastest solution time.  This mode is recommended if
enough physical memory is present to accommodate all of the solver
data.
Sparse solver maximum pivot= 2.425504222E+11 at node 56420 UY.
Sparse solver minimum pivot= 149830610 at node 53393 UZ.
Sparse solver minimum pivot in absolute value= 149830610 at node 53393
UZ.

*** ELEMENT RESULT CALCULATION TIMES
TYPE    NUMBER   ENAME      TOTAL CP  AVE CP

1     44277  SOLID187      6.844   0.000155

TYPE    NUMBER   ENAME      TOTAL CP  AVE CP

1     44277  SOLID187      1.886   0.000043
*** LOAD STEP     1   SUBSTEP     1  COMPLETED.    CUM ITER =      1
*** TIME =   1.00000         TIME INC =   1.00000      NEW TRIANG MATRIX

*** MAPDL BINARY FILE STATISTICS
BUFFER SIZE USED= 16384
117.312 MB WRITTEN ON ASSEMBLED MATRIX FILE: file.full
41.312 MB WRITTEN ON RESULTS FILE: file.rst
```

## Post-processing#

```# Enter post-processor
mapdl.post1()
mapdl.set(1, 1)  # Select first load step
mapdl.post_processing.plot_nodal_eqv_stress()  # Plot equivalent stress
```

## Exit MAPDL instance#

```mapdl.exit()
```

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

Gallery generated by Sphinx-Gallery