Contents Menu Expand Light mode Dark mode Auto light/dark, in light mode Auto light/dark, in dark mode Skip to content
opstool 1.0.20 documentation
Light Logo Dark Logo

Quick Start

  • Installation
  • Known Issues
  • Quick Start
    • Quick Model and Eigen Visualization
    • Two-Dimensional Moment Frame Analysis

User Guide

  • Pre-Processing
    • Fiber Section Mesh
    • Converting GMSH to OpenSeesPy
    • Convert Tcl code to OpenSeesPy commands
    • Automatic Unit Conversion
    • Quickly apply gravity loads and obtain mass and stiffness matrices
    • Loads Processing
    • Model mass generation
  • Post-Processing
    • Eigenvalue Analysis
    • Node Responses
    • Frame Responses
    • Fiber Section Responses
    • Truss Responses
    • Shell Responses
    • Plane response
    • Brick Responses
    • Sensitivity Analysis Responses
    • Unit conversion in post-processing
  • Visualization
    • Model Geometry (Plotly)
    • Eigen (Plotly)
    • Nodal Responses (Plotly)
    • Frame Responses (Plotly)
    • Truss Responses (Plotly)
    • Shell Responses (Plotly)
    • Plane Responses (Plotly)
    • Brick Responses (Plotly)
    • Model Geometry (Pyvista)
    • Eigen (Pyvista)
    • Nodal Responses (Pyvista)
    • Frame Responses (Pyvista)
    • Truss Responses (Pyvista)
    • Shell Responses (Pyvista)
    • Plane Responses (Pyvista)
    • Brick Responses (Pyvista)
  • Analysis
    • Smart Analysis
    • Moment Curvature Analysis of Section
    • Linear Buckling Analysis

Examples

  • Fiber Section Mesh
    • Hollow Rectangular RC Section
    • Steel-Concrete Composite Section Meshing
    • Concrete-Filled Steel Tube (CFST) Section Meshing
    • Bridge Superstructure Section
    • Interaction with sectionproperties
  • Gmsh to OpenSeesPy
    • Gmsh2OPS: Case 1
    • Gmsh2OPS: Case 2
    • Gmsh2OPS: Case 3
    • Gmsh2OPS: Case 4
  • Visualization
    • 606 m Mega-tall Building
    • Double-Layer Shallow Dome
  • Post-processing
    • Two-Dimensional Moment Frame Analysis
    • 3D Nonlinear beam-column elements Gravity load analysis followed by transient analysis
    • Excavation Supported by Cantilevered Sheet Pile Wall
    • Modal analysis of a cooling tower
    • Soil–Structure Interaction
    • Fluid-structure interaction
    • Displacement-controlled sensitivity analysis
    • Cantilever Bending Roll-up (corotational)

API Reference

  • Global Functions
    • load_ops_examples
    • add_ops_hints_file
    • run_model
    • print_version
  • Preprocessing
    • Fiber Section Mesh
      • FiberSecMesh
      • SecMesh
      • create_material
      • create_polygon_patch
      • create_circle_patch
      • create_patch_from_dxf
      • create_polygon_points
      • create_circle_points
      • offset
      • line_offset
      • poly_offset
      • set_patch_material
      • vis_fiber_sec_real
      • opstool.pre.section.section
      • opstool.pre.section.fiber
      • opstool.pre.section.patch
      • opstool.pre.section.layer
      • opstool.pre.section.plot_fiber_sec_cmds
    • tcl2py
    • Gmsh2OPS
    • UnitSystem
    • create_gravity_load
    • gen_grav_load
    • transform_beam_uniform_load
    • transform_beam_point_load
    • transform_surface_uniform_load
    • apply_load_distribution
    • get_node_coord
    • get_node_mass
    • get_mck
    • ModelMass
    • find_void_nodes
    • remove_void_nodes
  • Postprocessing
    • set_odb_path
    • update_unit_system
    • reset_unit_system
    • save_model_data
    • save_eigen_data
    • save_linear_buckling_data
    • CreateODB
    • get_model_data
    • get_eigen_data
    • get_linear_buckling_data
    • get_nodal_responses
    • get_element_responses
    • get_sensitivity_responses
  • Visualization
    • set_plot_props
    • set_plot_colors
    • plot_model
    • plot_eigen
    • plot_eigen_animation
    • plot_eigen_table
    • plot_nodal_responses
    • plot_nodal_responses_animation
    • plot_truss_responses
    • plot_truss_responses_animation
    • plot_frame_responses
    • plot_frame_responses_animation
    • plot_unstruct_responses
    • plot_unstruct_responses_animation
    • set_plot_props
    • set_plot_colors
    • plot_model
    • plot_eigen
    • plot_eigen_animation
    • plot_nodal_responses
    • plot_nodal_responses_animation
    • plot_truss_responses
    • plot_truss_responses_animation
    • plot_frame_responses
    • plot_frame_responses_animation
    • plot_unstruct_responses
    • plot_unstruct_responses_animation
    • get_nodal_responses_dataset
    • get_unstruct_responses_dataset
  • Analysis
    • SmartAnalyze
    • MomentCurvature
yexiang92/opstool 1.0.20
Back to top
View this page
Edit this page

Modal analysis of a cooling tower¶

Gmsh model¶

You can find modeling instructions at: Creating quadrilateral surface meshes with gmsh

image1.png

[1]:
import gmsh
import sys
import math
import json
[2]:
# Initialize gmsh
gmsh.initialize()

gmsh.model.add("forma11c_gmsh")

forma11c_profile.json can be downloaded from here

[3]:
# Read the profile coordinates
file_id = open("forma11c_profile.json", "r")
coords = json.load(file_id)
file_id.close()
[4]:
# Set a default element size
el_size = 1.0

# Add profile points
v_profile = []
for coord in coords:
    v = gmsh.model.occ.addPoint(coord[0], coord[1], coord[2], el_size)
    v_profile.append(v)
[5]:
# Add spline going through profile points
l1 = gmsh.model.occ.addBSpline(v_profile)
# Create copies and rotate
l2 = gmsh.model.occ.copy([(1, l1)])
l3 = gmsh.model.occ.copy([(1, l1)])
l4 = gmsh.model.occ.copy([(1, l1)])

# Rotate the copy
gmsh.model.occ.rotate(l2, 0, 0, 0, 0, 0, 1, math.pi / 2)
gmsh.model.occ.rotate(l3, 0, 0, 0, 0, 0, 1, math.pi)
gmsh.model.occ.rotate(l4, 0, 0, 0, 0, 0, 1, 3 * math.pi / 2)
[6]:
# Sweep the lines
surf1 = gmsh.model.occ.revolve([(1, l1)], 0, 0, 0, 0, 0, 1, math.pi / 2)
surf2 = gmsh.model.occ.revolve(l2, 0, 0, 0, 0, 0, 1, math.pi / 2)
surf3 = gmsh.model.occ.revolve(l3, 0, 0, 0, 0, 0, 1, math.pi / 2)
surf4 = gmsh.model.occ.revolve(l4, 0, 0, 0, 0, 0, 1, math.pi / 2)
[7]:
# Join the surfaces
surf5 = gmsh.model.occ.fragment(surf1, surf2)
surf6 = gmsh.model.occ.fragment(surf3, surf4)
surf7 = gmsh.model.occ.fragment(surf5[0], surf6[0])
[8]:
gmsh.model.occ.remove_all_duplicates()
gmsh.model.occ.synchronize()
[9]:
num_nodes_circ = 15
for curve in gmsh.model.occ.getEntities(1):
    gmsh.model.mesh.setTransfiniteCurve(curve[1], num_nodes_circ)
[10]:
num_nodes_vert = 32
vertical_curves = [7, 10, 13, 17]
for curve in vertical_curves:
    gmsh.model.mesh.setTransfiniteCurve(curve, num_nodes_vert)
[11]:
for surf in gmsh.model.occ.getEntities(2):
    gmsh.model.mesh.setTransfiniteSurface(surf[1])
[12]:
gmsh.option.setNumber("Mesh.RecombineAll", 1)
gmsh.option.setNumber("Mesh.RecombinationAlgorithm", 1)
gmsh.option.setNumber("Mesh.Recombine3DLevel", 2)
gmsh.option.setNumber("Mesh.ElementOrder", 1)
[13]:
# Important:
# Note that we use names to distinguish groups, so please do not overlook this!
# We use the "Boundary" group to include 4 lines
gmsh.model.addPhysicalGroup(dim=1, tags=[6, 9, 12, 15], tag=1, name="Boundary")
[13]:
1
[14]:
# Generate mesh
gmsh.model.mesh.generate(dim=2)
[15]:
gmsh.option.setNumber("Mesh.SaveAll", 1)
gmsh.write("forma11c.msh")
[16]:
gmsh.fltk.run()

To OpenSeesPy Model¶

[17]:
import openseespy.opensees as ops
import opstool as opst
[18]:
ops.wipe()
ops.model("basic", "-ndm", 3, "-ndf", 6)
E, nu, rho = 2.76e10, 0.166, 2244.0  # Pa, kg/m3
ops.nDMaterial("ElasticIsotropic", 1, E, nu, rho)
secTag = 11
ops.section("PlateFiber", secTag, 1, 0.305)
[19]:
GMSH2OPS = opst.pre.Gmsh2OPS(ndm=3, ndf=6)
[20]:
GMSH2OPS.read_gmsh_file("forma11c.msh")
Info:: 1 Physical Names.
Info:: 1821 Nodes; MaxNodeTag 1821; MinNodeTag 1.
Info:: 2009 Elements; MaxEleTag 2009; MinEleTag 1.
Info:: Geometry Information >>>
53 Entities: 37 Point; 12 Curves; 4 Surfaces; 0 Volumes.

Info:: Physical Groups Information >>>
1 Physical Groups.
Physical Group names: ['Boundary']

Info:: Mesh Information >>>
1821 Nodes; MaxNodeTag 1821; MinNodeTag 1.
1972 Elements; MaxEleTag 2009; MinEleTag 1.

[21]:
# Create OpenSeesPy node commands based on all nodes defined in the GMSH file
node_tags = GMSH2OPS.create_node_cmds()
[22]:
dim_entity_tags = GMSH2OPS.get_dim_entity_tags()
dim_entity_tags_2D = [item for item in dim_entity_tags if item[0] == 2]
[23]:
# Create OpenSeesPy element commands for specific entities
ele_tags_n4 = GMSH2OPS.create_element_cmds(
    ops_ele_type="ASDShellQ4",  # OpenSeesPy element type
    ops_ele_args=[secTag],  # Additional arguments for the element (e.g., section tag)
    dim_entity_tags=dim_entity_tags_2D,
)
Using ASDShellQ4 - Developed by: Massimo Petracca, Guido Camata, ASDEA Software Technology
[24]:
boundary_dim_tags = GMSH2OPS.get_boundary_dim_tags(physical_group_names="Boundary", include_self=True)
boundary_dim_tags
[24]:
[(0, 55), (0, 59), (0, 61), (0, 63), (1, 6), (1, 9), (1, 12), (1, 15)]
[25]:
fix_ntags = GMSH2OPS.create_fix_cmds(dim_entity_tags=boundary_dim_tags, dofs=[1] * 6)
[26]:
removed_node_tags = opst.pre.remove_void_nodes()
Info:: Free nodes with tags [57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
78, 79, 80, 81, 82, 83, 84, 85] have been removed!
[27]:
opst.vis.pyvista.set_plot_props(notebook=True)
opst.vis.pyvista.plot_model(show_outline=True).show(jupyter_backend="jupyterlab")
OPSTOOL ::  Model data has been saved to _OPSTOOL_ODB/ModelData-None.nc!
../../../_images/examples_post_forma11c_test_forma11c_32_1.png
[28]:
opst.post.save_eigen_data(odb_tag="eigen", mode_tag=60)
Using DomainModalProperties - Developed by: Massimo Petracca, Guido Camata, ASDEA Software Technology
OPSTOOL ::  Eigen data has been saved to _OPSTOOL_ODB/EigenData-eigen.nc!
[34]:
fig = opst.vis.pyvista.plot_eigen(mode_tags=12, odb_tag="eigen", subplots=True)
fig.show(jupyter_backend="jupyterlab")
OPSTOOL ::  Loading eigen data from _OPSTOOL_ODB/EigenData-eigen.nc ...
../../../_images/examples_post_forma11c_test_forma11c_34_1.png
[30]:
modal_props, eigen_vectors = opst.post.get_eigen_data(odb_tag="eigen")
modal_props = modal_props.to_pandas()
modal_props.head()
OPSTOOL ::  Loading eigen data from _OPSTOOL_ODB/EigenData-eigen.nc ...
[30]:
Properties eigenLambda eigenOmega eigenFrequency eigenPeriod partiFactorMX partiFactorMY partiFactorRMZ partiFactorMZ partiFactorRMX partiFactorRMY ... partiMassRatiosRMZ partiMassRatiosMZ partiMassRatiosRMX partiMassRatiosRMY partiMassRatiosCumuMX partiMassRatiosCumuMY partiMassRatiosCumuRMZ partiMassRatiosCumuMZ partiMassRatiosCumuRMX partiMassRatiosCumuRMY
modeTags
1 51.13809 7.151090 1.138131 0.878633 2.133296e-10 6.395783e-11 -5.687698e-10 2.489633e-11 -2.639758e-10 6.281351e-09 ... 7.347386e-28 2.546785e-27 1.156468e-28 6.548041e-26 1.869924e-25 1.680773e-26 7.347386e-28 2.546785e-27 1.156468e-28 6.548041e-26
2 51.13809 7.151090 1.138131 0.878633 4.024028e-10 -5.398455e-11 -8.745127e-10 -9.774598e-12 -1.394169e-09 1.480870e-08 ... 1.736969e-27 3.925721e-28 3.225792e-27 3.639476e-25 8.523324e-25 2.878232e-26 2.471707e-27 2.939357e-27 3.341439e-27 4.294281e-25
3 53.64215 7.324080 1.165664 0.857880 3.396294e-10 -4.563913e-10 3.302614e-09 -1.937277e-12 1.743117e-08 1.145287e-08 ... 2.477282e-26 1.542073e-29 5.042644e-25 2.176878e-25 1.326282e-24 8.846298e-25 2.724453e-26 2.954778e-27 5.076058e-25 6.471158e-25
4 53.64215 7.324080 1.165664 0.857880 -6.006892e-11 -2.575128e-10 -1.834748e-10 -4.978899e-12 9.513005e-09 -2.254505e-09 ... 7.645618e-29 1.018564e-28 1.501899e-25 8.435437e-27 1.341108e-24 1.157100e-24 2.732098e-26 3.056634e-27 6.577957e-25 6.555512e-25
5 59.58843 7.719354 1.228573 0.813952 4.042192e-10 6.548266e-10 5.770587e-10 1.697122e-12 -2.767511e-08 1.639054e-08 ... 7.563098e-28 1.183444e-29 1.271112e-24 4.458529e-25 2.012468e-24 2.918972e-24 2.807729e-26 3.068468e-27 1.928908e-24 1.101404e-24

5 rows × 34 columns

[31]:
modal_props.loc[[1, 47, 48, 60], "eigenFrequency"]
[31]:
modeTags
1     1.138131
47    2.875771
48    2.875771
60    3.196797
Name: eigenFrequency, dtype: float64

You can compare this with Code-Aster, which uses DKT shell elements. See ~ Model C: Modal analysis of a cooling tower¶

image2.png

Next
Soil–Structure Interaction
Previous
Excavation Supported by Cantilevered Sheet Pile Wall
Copyright © 2025, Yexiang Yan
Made with Sphinx and @pradyunsg's Furo
On this page
  • Modal analysis of a cooling tower
    • Gmsh model
    • To OpenSeesPy Model