Dynamic Load Effect on a Supported Thick Plate#

This example demonstrates how to perform a random vibration analysis using PyMAPDL.

This example is based on the ANSYS Verification Manual, problem 203 (VM203).

Description#

A simply-supported thick square plate of length L, thickness t, and mass per unit area m is subject to random uniform pressure power spectral density. Determine the peak one-sigma displacement at undamped natural frequency.

A frequency range of 1.0 Hz to 80 Hz is used as an approximation of the white noise PSD forcing function frequency. The PSD curve is a constant $$(1E6 N/m^2)^2 / Hz$$.

The model is solved using SHELL281 elements and generic materials.

Import modules#

import matplotlib.pyplot as plt
from tabulate import tabulate

from ansys.mapdl.core import launch_mapdl

mapdl = launch_mapdl()

mapdl.clear()
mapdl.prep7()
mapdl.units("mks")
MKS UNITS SPECIFIED FOR INTERNAL
  LENGTH        (l)  = METER (M)
  MASS          (M)  = KILOGRAM (KG)
  TIME          (t)  = SECOND (SEC)
  TEMPERATURE   (T)  = CELSIUS (C)
  TOFFSET            = 273.0
  CHARGE        (Q)  = COULOMB
  FORCE         (f)  = NEWTON (N) (KG-M/SEC2)
  HEAT               = JOULE (N-M)

  PRESSURE           = PASCAL (NEWTON/M**2)
  ENERGY        (W)  = JOULE (N-M)
  POWER         (P)  = WATT (N-M/SEC)
  CURRENT       (i)  = AMPERE (COULOMBS/SEC)
  CAPACITANCE   (C)  = FARAD
  INDUCTANCE    (L)  = HENRY
  MAGNETIC FLUX      = WEBER
  RESISTANCE    (R)  = OHM
  ELECTRIC POTENTIAL = VOLT

 INPUT  UNITS ARE ALSO SET TO MKS

Parameters#

Loading parameters

LOAD_PRES = -1e6
DAMPING_RATIO = 0.02

Set up the FE model#

Set the element type to SHELL281, which is a 3D structural high-order shell element.

thickness = 1

mapdl.et(1, "SHELL281")
mapdl.sectype(1, "SHELL")
mapdl.secdata(1, thickness, 0, 5)
Shell Section ID=        1 Number of layers=    1  Total Thickness=     1.000000

Set material properties#

Units are in the international unit system.

EX = 200e9
PR = 0.3
DENS = 8000

mapdl.mp("EX", 1, EX)
mapdl.mp("NUXY", 1, PR)
mapdl.mp("DENS", 1, DENS)
MATERIAL          1     DENS =   8000.000

Create geometry#

Create the model geometry.

L1 = 10

mapdl.n(1, 0, 0, 0)
mapdl.n(9, 0, L1, 0)
mapdl.fill()
mapdl.ngen(5, 40, 1, 9, 1, L1 / 4)
mapdl.n(21, L1 / 8, 0, 0)
mapdl.n(29, L1 / 8, 10, 0)
mapdl.fill(21, 29, 3)
mapdl.ngen(4, 40, 21, 29, 2, L1 / 4)
mapdl.en(1, 1, 41, 43, 3, 21, 42, 23, 2)
mapdl.egen(4, 2, 1)
mapdl.egen(4, 40, 1, 4)
GENERATE       4 TOTAL SETS OF ELEMENTS WITH NODE INCREMENT OF        40
   SET IS SELECTED ELEMENTS IN RANGE         1 TO         4 IN STEPS OF       1

 MAXIMUM ELEMENT NUMBER=        16

Loads and boundary conditions#

Define loads and boundary conditions.

Apply a uniform pressure load of 1,000,000 N/m^2

mapdl.sfe("ALL", "", "PRES", "", LOAD_PRES)
SPECIFIED SURFACE LOAD PRES FOR ALL SELECTED ELEMENTS  LKEY =  1   KVAL = 1
     VALUES =   -0.10000E+07   -0.10000E+07   -0.10000E+07   -0.10000E+07

Apply constraints UX, UY, ROTZ DOFs all fixed

mapdl.d("ALL", "UX", 0, "", "", "", "UY", "ROTZ")
SPECIFIED CONSTRAINT UX   FOR SELECTED NODES            1 TO         169 BY           1
 REAL=  0.00000000       IMAG=  0.00000000
 ADDITIONAL DOFS=  UY    ROTZ

Simply supported on the four corners

mapdl.d(1, "UZ", 0, 0, 9, 1, "ROTX")
mapdl.d(161, "UZ", 0, 0, 169, 1, "ROTX")
mapdl.d(1, "UZ", 0, 0, 161, 20, "ROTY")
mapdl.d(9, "UZ", 0, 0, 169, 20, "ROTY")
SPECIFIED CONSTRAINT UZ   FOR SELECTED NODES            9 TO         169 BY          20
 REAL=  0.00000000       IMAG=  0.00000000
 ADDITIONAL DOFS=  ROTY

Solve the model#

Solve the modal analysis using the PCG Lanczos solver to find and expand the first two modes of the model.

n_modes = 2
mapdl.solution()
mapdl.antype("MODAL")
mapdl.modopt("LANPCG", n_modes)
mapdl.mxpand(n_modes, "", "", "YES")

mapdl.solve()
# Getting frequency of the first mode
f0 = mapdl.get_value("MODE", 1, "FREQ")

mapdl.finish()
FINISH SOLUTION PROCESSING


 ***** ROUTINE COMPLETED *****  CP =         0.000

PSD Spectrum analysis#

Now let’s perform PSD spectrum analysis using the two solved modes:

mapdl.slashsolu()
mapdl.antype("SPECTR")
mapdl.spopt("PSD", n_modes, "ON")
USE PSD RESPONSE SPECTRUM
  USE THE FIRST    2 MODES FROM THE MODAL ANALYSIS
  INCLUDE STRESS RESPONSES IN THE CALCULATIONS
  PSD INTEGRATION WILL BE PERFORMED IN CLOSED FORM

Define the PSD spectrum

mapdl.psdunit(1, "PRES")
PSD TYPE FOR TABLE NUMBER  1 IS PRES

Applying proportional damping

mapdl.dmprat(DAMPING_RATIO)
DAMPING RATIO =      0.0200

PSD frequency value table 1 to 80 Hz

freqA = 1.0
freqB = 80.0

mapdl.psdfrq(1, 1, freq1=freqA, freq2=freqB)
mapdl.psdval(1, 1.0, 1.0)
PSD VALUES (DIAGONAL) FOR TABLE  1
   PSDVAL =    1.0000        1.0000

Define the PSD load vector generated at modal analysis

mapdl.sfedele("ALL", "", "PRES")
mapdl.lvscale(1)
mapdl.pfact(1, "NODE")
COMPUTE PARTICIPATION FACTORS FOR TABLE   1
  FOR NODAL EXCITATION

 *****  MAPDL PFACT    COMMAND  *****

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

 ELEMENT TYPE         1 IS SHELL281. IT IS ASSOCIATED WITH ELASTOPLASTIC
 MATERIALS ONLY. KEYOPT(8)=2 IS SUGGESTED.


   *****MAPDL VERIFICATION RUN ONLY*****
     DO NOT USE RESULTS FOR PRODUCTION

                       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   ROTX ROTY ROTZ
   ANALYSIS TYPE . . . . . . . . . . . . . . . . .SPECTRUM
      SPECTRUM TYPE. . . . . . . . . . . . . . . .PSD
   NUMBER OF MODES TO BE USED. . . . . . . . . . .     2
   ELEMENT RESULTS CALCULATION . . . . . . . . . .ON
   GLOBALLY ASSEMBLED MATRIX . . . . . . . . . . .SYMMETRIC

 *** NOTE ***                            CP =       0.000   TIME= 00:00:00
 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. . . . . . . . . . . . . . . .     2
   MODAL DAMPING RATIO . . . . . . . . . . . . . . 0.20000E-01
   PRINT OUTPUT CONTROLS . . . . . . . . . . . . .NO PRINTOUT
   DATABASE OUTPUT CONTROLS. . . . . . . . . . . .ALL DATA WRITTEN

   *****MAPDL VERIFICATION RUN ONLY*****
     DO NOT USE RESULTS FOR PRODUCTION


  ***** PARTICIPATION FACTORS FOR NODAL EXCITATION *****    TABLE NO.    1

  MODE   VALUE      MODE   VALUE      MODE   VALUE      MODE   VALUE

    1  -90096.        2   2.4549

Write out the displacement result

mapdl.psdres("DISP", "REL")
# set for PSD mode combination method
mapdl.psdcom()
mapdl.solve()

mapdl.finish()
FINISH SOLUTION PROCESSING


 ***** ROUTINE COMPLETED *****  CP =         0.000

Post-processing#

Now we can plot the results of the one-sigma displacement solution. We will plot the Z displacement of the nodes.

mapdl.post1()
# One Sigma Displacement Solution Results
mapdl.set(3, 1)
mapdl.post_processing.plot_nodal_displacement("Z", cmap="jet", cpos="iso")
mapdl.finish()
psd vm203
EXIT THE MAPDL POST1 DATABASE PROCESSOR


 ***** ROUTINE COMPLETED *****  CP =         0.000

Use post26 to capture then plot the response psd and the max value

number_frequencies = 2
mapdl.post26()
mapdl.store("PSD", number_frequencies)

node85_uz = mapdl.nsol(2, 85, "U", "Z")
rpsduz = mapdl.rpsd(3, 2, "", 1, 2)

While you can use the extrem command to get the maximum and minimum values:

print(mapdl.extrem(2, 3))
POST26 SUMMARY OF VARIABLE EXTREME VALUES
 VARI TYPE    IDENTIFIERS   NAME     MINIMUM    AT TIME    MAXIMUM   AT TIME

   2 NSOL    85 UZ        UZ       -0.1269E-007  0.000      0.1017       0.000
   3 OPER     3 RPSD      3          0.000       0.000      0.3595E-002  0.000

You can also use Numpy methods to find the max value of the response psd.

print(
    tabulate(
        [
            ["", "Maximum", "Minimum"],
            ["Z-displacement on node 85", node85_uz.max(), node85_uz.min()],
            ["Response power spectral density", rpsduz.max(), rpsduz.min()],
        ],
        headers="firstrow",
        tablefmt="grid",
        floatfmt=".4e",
        numalign="center",
        stralign="right",
    )
)
+---------------------------------+------------+-------------+
|                                 |  Maximum   |   Minimum   |
+=================================+============+=============+
|       Z-displacement on node 85 | 1.0171e-01 | -1.2690e-08 |
+---------------------------------+------------+-------------+
| Response power spectral density | 3.5954e-03 | 0.0000e+00  |
+---------------------------------+------------+-------------+

To get the maximum value of the response psd you can use the get_value ( wrapper of *GET) method with the EXTREM option:

Pmax = mapdl.get_value("VARI", 3, "EXTREM", "VMAX")

However, you can also use the numpy methods here as well:

Pmax = rpsduz.max()

plot the response psd

freqs = mapdl.vget("FREQS", 1)

# Remove the last two values as they are zero
plt.plot(freqs[:-2], rpsduz[:-2], label="RPSD UZ")

plt.xlabel("Frequency Hz")
plt.ylabel(r"RPSD $\left( \dfrac{M^2}{Hz}\right)$")
plt.legend()
plt.tight_layout()
plt.show()
psd vm203

Compare and print results to manual values

manual = [45.9, 3.4018e-3]

arr = [
    ["", "Manual", "Calculated", "Ratio"],
    ["Frequency (Hz)", manual[0], f0, abs(f0 / manual[0])],
    ["Peak Deflection PSD (m^2/Hz)", manual[1], Pmax, abs(Pmax / manual[1])],
]

print(tabulate(arr, headers="firstrow", tablefmt="grid"))
+------------------------------+------------+--------------+---------+
|                              |     Manual |   Calculated |   Ratio |
+==============================+============+==============+=========+
| Frequency (Hz)               | 45.9       |   45.9596    | 1.0013  |
+------------------------------+------------+--------------+---------+
| Peak Deflection PSD (m^2/Hz) |  0.0034018 |    0.0035954 | 1.05691 |
+------------------------------+------------+--------------+---------+

Exit MAPDL

mapdl.exit()

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