Skip to content

Commit c0abb16

Browse files
authored
Add cyclic example (#1284)
* add cyclic example * update the final comment * don't show text * make codacy happy * cyclic before mesh * make codacy happy
1 parent c27105c commit c0abb16

File tree

4 files changed

+308
-3
lines changed

4 files changed

+308
-3
lines changed

doc/source/images/cyclic_disc.png

33.6 KB
Loading
Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
"""
2+
.. _ref_cyclic_analysis_example:
3+
4+
Cyclic Analysis
5+
---------------
6+
7+
This example creates a bladed disc using parametric geometry of a cyclic sector
8+
and then runs a modal analysis on that cyclic sector. We then post-process the
9+
results using the legacy `MAPDL reader <https://readerdocs.pyansys.com/>`_ and
10+
finally generate another cyclic model using our parametric modeler.
11+
12+
Our first task is to create a simple cyclic model with 7 sectors.
13+
14+
.. image:: ../../../images/cyclic_disc.png
15+
16+
First, start MAPDL as a service.
17+
18+
"""
19+
# sphinx_gallery_thumbnail_number = 3
20+
21+
import numpy as np
22+
import pyvista as pv
23+
24+
from ansys.mapdl.core import launch_mapdl
25+
26+
mapdl = launch_mapdl()
27+
28+
29+
###############################################################################
30+
# Create the Cyclic Sector
31+
# ~~~~~~~~~~~~~~~~~~~~~~~~
32+
# Create a single "sector" of our cyclic model.
33+
#
34+
35+
36+
def gen_sector(mapdl, sectors):
37+
"""Generate a single sector within MAPDL."""
38+
39+
# thickness
40+
thickness = 0.003 # meters
41+
arc_end = 2 * np.pi / sectors
42+
arc_cent = arc_end / 2
43+
44+
# radius
45+
rad = 0.01 # M
46+
arc = pv.CircularArc(
47+
[rad, 0, 0], [np.cos(arc_end) * rad, np.sin(arc_end) * rad, 0], [0, 0, 0]
48+
)
49+
50+
# interior circle
51+
kp_begin = [rad, 0, 0]
52+
kp_end = [np.cos(arc_end) * rad, np.sin(arc_end) * rad, 0]
53+
kp_center = [0, 0, 0]
54+
55+
# exterior circle in (M)
56+
out_rad = 5.2e-2
57+
58+
# solve for angle to get same arc.length at the end
59+
cent_ang = arc.length / out_rad / 2
60+
61+
# interior circle
62+
kp_beg_outer = [
63+
np.cos(arc_cent - cent_ang) * out_rad,
64+
np.sin(arc_cent - cent_ang) * out_rad,
65+
0,
66+
]
67+
kp_end_outer = [
68+
np.cos(arc_cent + cent_ang) * out_rad,
69+
np.sin(arc_cent + cent_ang) * out_rad,
70+
0,
71+
]
72+
73+
mapdl.prep7()
74+
mapdl.k(0, *kp_center)
75+
mapdl.k(0, *kp_begin)
76+
mapdl.k(0, *kp_end)
77+
mapdl.k(0, *kp_beg_outer)
78+
mapdl.k(0, *kp_end_outer)
79+
80+
# inner arc
81+
mapdl.l(1, 2) # left line
82+
mapdl.l(1, 3) # right line
83+
lnum_inter = mapdl.l(2, 3) # internal line
84+
mapdl.al("all")
85+
86+
# outer "blade"
87+
lnum = [lnum_inter, mapdl.l(4, 5), mapdl.l(2, 4), mapdl.l(3, 5)]
88+
mapdl.al(*lnum)
89+
90+
# extrude the model in the Z direction by ``thickness``
91+
mapdl.vext("all", dz=thickness)
92+
93+
94+
# generate a single sector of a 7 sector model
95+
sectors = 7
96+
gen_sector(mapdl, sectors)
97+
98+
# Volume plot
99+
mapdl.vplot()
100+
101+
102+
###############################################################################
103+
# Make the Model Cyclic
104+
# ~~~~~~~~~~~~~~~~~~~~~
105+
# Make the model cyclic by running :func:`Mapdl.cyclic`
106+
#
107+
# Note how the number of sectors matches
108+
109+
output = mapdl.cyclic()
110+
print(f"Expected Sectors: {sectors}")
111+
print(output)
112+
113+
114+
###############################################################################
115+
# Generate the mesh
116+
# ~~~~~~~~~~~~~~~~~
117+
# Generate the finite element mesh using quadritic hexahedrals, SOLID186.
118+
119+
# element size of 0.01
120+
esize = 0.001
121+
122+
mapdl.et(1, 186)
123+
mapdl.esize(esize)
124+
mapdl.vsweep("all")
125+
126+
# plot the finite element mesh
127+
mapdl.eplot()
128+
129+
130+
###############################################################################
131+
# Apply Material Properties
132+
# ~~~~~~~~~~~~~~~~~~~~~~~~~
133+
134+
# Define a material (nominal steel in SI)
135+
mapdl.mp("EX", 1, 210e9) # Elastic moduli in Pa (kg/(m*s**2))
136+
mapdl.mp("DENS", 1, 7800) # Density in kg/m3
137+
mapdl.mp("NUXY", 1, 0.3) # Poisson's Ratio
138+
139+
# apply it to all elements
140+
mapdl.emodif("ALL", "MAT", 1)
141+
142+
143+
###############################################################################
144+
# Run the Modal Analysis
145+
# ~~~~~~~~~~~~~~~~~~~~~~
146+
# Let's get the first 10 modes. Note that this will actually compute
147+
# ``(sectors/2)*nmode`` based on the cyclic boundary conditions.
148+
149+
output = mapdl.modal_analysis(nmode=10, freqb=1)
150+
print(output)
151+
152+
153+
###############################################################################
154+
# Get the Results of the Cyclic Modal Analysis
155+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
156+
# Visualize a traveling wave from the modal analysis.
157+
#
158+
# For more details, see `Validation of a Modal Work Approach for Forced
159+
# Response Analysis of Bladed Disks
160+
# <https://www.mdpi.com/2076-3417/11/12/5437/pdf>`_, or the `Cyclic Symmetry
161+
# Analysis Guide
162+
# <https://ansyshelp.ansys.com/Views/Secured/corp/v222/en/pdf/Ansys_Mechanical_APDL_Cyclic_Symmetry_Analysis_Guide.pdf>`_
163+
#
164+
# .. note::
165+
# This uses the legacy result reader, which will be deprecated at some point
166+
# in favor of DPF, but we can use this for now for some great animations.
167+
#
168+
# For more details regarding cyclic result post processing, see:
169+
# - `Understanding Nodal Diameters from a Cyclic Model Analysis <https://readerdocs.pyansys.com/examples/01-cyclic_results/academic_sector_nd.html>`_
170+
# - `Modal Cyclic Symmetry Example <https://dpfdocs.pyansys.com/examples/02-modal-harmonic/01-modal_cyclic.html>`_
171+
172+
# grab the result object from MAPDL
173+
result = mapdl.result
174+
print(result)
175+
176+
177+
###############################################################################
178+
# List the Table of Harmonic Indices
179+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
180+
# This is the table of harmonic indices. This table provides the corresponding
181+
# harmonic index for each cumulative mode.
182+
print("C. Index Harmonic Index")
183+
for i, hindex in zip(range(result.n_results), result.harmonic_indices):
184+
print(f"{i:3d} {hindex:3d}")
185+
186+
187+
###############################################################################
188+
# Generate an Animation of a Traveling Wave
189+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
190+
# Here's the nodal diameter 1 of first bend on our cyclic analysis.
191+
#
192+
# We can get the first mode (generally first bend for a bladed rotor) for nodal
193+
# diameter 1 with:
194+
#
195+
# ``mode_num = np.nonzero(result.harmonic_indices == 1)[0][0]``
196+
#
197+
198+
pv.global_theme.background = "w"
199+
200+
_ = result.animate_nodal_displacement(
201+
11,
202+
displacement_factor=5e-4,
203+
movie_filename="traveling_wave11.gif",
204+
n_frames=30,
205+
off_screen=True,
206+
loop=False,
207+
add_text=False,
208+
show_scalar_bar=False,
209+
cmap="jet",
210+
)
211+
212+
###############################################################################
213+
# And here's 1st torsional for nodal diameter 3.
214+
215+
_ = result.animate_nodal_displacement(
216+
36,
217+
displacement_factor=2e-4,
218+
movie_filename="traveling_wave36.gif",
219+
n_frames=30,
220+
off_screen=True,
221+
loop=False,
222+
add_text=False,
223+
show_scalar_bar=False,
224+
cmap="jet",
225+
)
226+
227+
228+
###############################################################################
229+
# Parametric Geometry
230+
# ~~~~~~~~~~~~~~~~~~~
231+
# Since our geometry creation is scripted, we can create a structure with any
232+
# number of "sectors". Let's make a more interesting one with 20 sectors.
233+
#
234+
# First, be sure to clear MAPDL so we start from scratch.
235+
236+
mapdl.clear()
237+
mapdl.prep7()
238+
239+
# Generate a single sector of a 20 sector model
240+
gen_sector(mapdl, 20)
241+
242+
# make it cyclic
243+
mapdl.cyclic()
244+
245+
# Mesh it
246+
esize = 0.001
247+
mapdl.et(1, 186)
248+
mapdl.esize(esize)
249+
mapdl.vsweep("all")
250+
251+
# apply materials
252+
mapdl.mp("EX", 1, 210e9) # Elastic moduli in Pa (kg/(m*s**2))
253+
mapdl.mp("DENS", 1, 7800) # Density in kg/m3
254+
mapdl.mp("NUXY", 1, 0.3) # Poisson's Ratio
255+
mapdl.emodif("ALL", "MAT", 1)
256+
257+
# Run the modal analysis
258+
output = mapdl.modal_analysis(nmode=6, freqb=1)
259+
260+
# grab the result object from MAPDL
261+
result = mapdl.result
262+
print(result)
263+
264+
265+
###############################################################################
266+
# List the Table of Harmonic Indices
267+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
268+
# Note how the harmonic indices of these modes goes up to 10, or N/2 where N is
269+
# the number of sectors.
270+
#
271+
272+
print("C. Index Harmonic Index")
273+
for i, hindex in zip(range(result.n_results), result.harmonic_indices):
274+
print(f"{i:3d} {hindex:3d}")
275+
276+
277+
###############################################################################
278+
# Plot Nodal First Bend for Nodal Diameter 2
279+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
280+
# Note how you can clearly see two nodal lines for this mode shape since it's
281+
# nodal diameter 2.
282+
283+
result.plot_nodal_displacement(
284+
12, cpos="xy", cmap="jet", show_scalar_bar=False, add_text=False
285+
)
286+
287+
288+
###############################################################################
289+
# Animate Nodal First Bend for Nodal Diameter 2
290+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
291+
# Let's end this example by animating mode 12, which corresponds to first bend
292+
# 2nd nodal diameter for this example.
293+
294+
_ = result.animate_nodal_displacement(
295+
12,
296+
displacement_factor=2e-4,
297+
movie_filename="traveling_wave12.gif",
298+
n_frames=30,
299+
off_screen=True,
300+
loop=False,
301+
add_text=False,
302+
show_scalar_bar=False,
303+
cmap="jet",
304+
)

ignore_words.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ struc
1919
emiss
2020
vise
2121
sur
22+

requirements/requirements_docs.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
Sphinx==5.0.2
22
ansys-mapdl-reader==0.51.14
3+
ansys-sphinx-theme==0.4.2
4+
grpcio==1.43.0
35
imageio-ffmpeg==0.4.7
46
imageio==2.19.5
57
jupyter_sphinx==0.4.0
@@ -8,11 +10,10 @@ matplotlib==3.5.2
810
numpydoc==1.4.0
911
pandas==1.4.3
1012
plotly==5.9.0
11-
ansys-sphinx-theme==0.4.2
1213
pypandoc==1.8.1
1314
pytest-sphinx==0.4.0
1415
pythreejs==2.3.0
15-
https://github.com/pyvista/pyvista/archive/main.zip # need latest
16+
pyvista==0.35.2
1617
sphinx-autobuild==2021.3.14
1718
sphinx-autodoc-typehints==1.18.3
1819
sphinx-copybutton==0.5.0
@@ -21,4 +22,3 @@ sphinx-notfound-page==0.8.3
2122
sphinxcontrib-websupport==1.2.4
2223
sphinxemoji==0.2.0
2324
vtk==9.0.3
24-
grpcio==1.43.0

0 commit comments

Comments
 (0)