Note
Go to the end to download the full example code.
I-Beam Analysis with Automated Report Generation#
Note
This file is complimentary material of `I-Beam Analysis with Automated Report Generation <beam_analysis_report_example_>`_ example.
This example demonstrates a comprehensive structural analysis of a fully constrained I-beam using PyMAPDL. The script creates a parameterized I-beam model, applies loads, solves for structural response, and generates a detailed engineering report in both Markdown and Microsoft Word formats.
The example showcases:
Parameterized I-beam geometry definition
Material property assignment
Fully constrained at both ends
Distributed load application
Result extraction and post-processing
Automated report generation with plots and tables
This example requires the following imports:
from datetime import datetime
from pathlib import Path
import numpy as np
from ansys.mapdl.core import launch_mapdl
from ansys.mapdl.core.plotting import GraphicsBackend
Workflow design#
The main function defines the workflow for creating the I-beam analysis and generating reports.
def create_ibeam_analysis_and_report(**kwargs):
"""
Main function that performs I-beam analysis and generates reports.
This function encapsulates the entire workflow from model creation
to report generation for better organization and reusability.
"""
# Launch MAPDL with graphics enabled for plotting
mapdl = launch_mapdl(loglevel="WARNING", clear_on_connect=True)
print("=" * 60)
print("PyMAPDL I-Beam Analysis with Report Generation")
print("=" * 60)
# ==========================================================================
# MODEL SETUP AND PARAMETERIZATION
# ==========================================================================
report_name = kwargs.get("name", "I-Beam Structural Analysis Report")
# I-beam geometric parameters (all dimensions in mm)
beam_params = {
"length": 5000.0, # Total beam length (5 meters)
"flange_width": 200.0, # Width of top and bottom flanges
"web_height": 400.0, # Height of the web (total beam height)
"flange_thickness": 20.0, # Thickness of flanges
"web_thickness": 12.0, # Thickness of web
}
beam_params.update({k: v for k, v in kwargs.items() if k in beam_params})
# Material properties for structural steel (S355)
material_props = {
"elastic_modulus": 200000.0, # Young's modulus in MPa (200 GPa = 200,000 MPa)
"poisson_ratio": 0.30, # Poisson's ratio
"density": 7850e-6, # Density in kg/mm³ (7850 kg/m³)
"yield_strength": 355.0, # Yield strength in MPa
}
# Update with any additional parameters
material_props.update({k: v for k, v in kwargs.items() if k in material_props})
# Loading and boundary conditions
load_params = {
"distributed_load": -50.0, # Distributed load in N/mm (50 kN/m downward)
"safety_factor": 2.0, # Design safety factor
}
load_params.update({k: v for k, v in kwargs.items() if k in load_params})
print(f"Beam Length: {beam_params['length']} mm")
print(
f"I-Section: {beam_params['flange_width']}x{beam_params['web_height']}x{beam_params['web_thickness']}"
)
print(f"Material: Steel E = {material_props['elastic_modulus']} MPa")
print(f"Load: {load_params['distributed_load']} N/mm")
# ==========================================================================
# SOLVING MAPDL MODEL
# ==========================================================================
analysis_data = generate_model(mapdl, beam_params, material_props, load_params)
# ==========================================================================
# REPORT GENERATION
# ==========================================================================
print("\n" + "=" * 50)
print("REPORT GENERATION")
print("=" * 50)
# Create output directory if it doesn't exist
output_dir = Path("beam_analysis_output")
output_dir.mkdir(exist_ok=True)
# Generate plots for the report
analysis_data["plot_files"] = generate_analysis_plots(mapdl, output_dir)
analysis_data["name"] = report_name
# Generate Markdown report
markdown_file = generate_markdown_report(analysis_data, output_dir)
print(f"Markdown report generated: {markdown_file}")
# Generate Word document if python-docx is available
try:
word_file = generate_word_report(analysis_data, output_dir)
print(f"Word report generated: {word_file}")
except ImportError:
print("python-docx not available. Word report not generated.")
print("Install with: pip install python-docx")
# Clean up
mapdl.exit()
return analysis_data
Generate and solve the finite element model#
A complete structural analysis of an I-beam is generated and solved. The output is a dictionary with the desired results:
Displacements
Bending moments
Bending stresses
Bending strains
This model uses 20 BEAM188 elements to create the beam. The material properties, load parameters and geometry are taken from the function inputs.
def generate_model(mapdl, beam_params, material_props, load_params):
"""Generates finite element model and returns the analysis result"""
# ==========================================================================
# PREPROCESSING - GEOMETRY AND MESHING
# ==========================================================================
# Enter preprocessor
mapdl.prep7()
mapdl.title("Fully constrained I-Beam Analysis")
# Define element type - BEAM188 (3D linear finite strain beam)
mapdl.et(1, "BEAM188")
mapdl.keyopt(1, 4, 1) # Enable transverse shear stress output
mapdl.keyopt(1, 6, 1) # Enable stress output at intermediate stations
mapdl.keyopt(1, 3, 2) # Use Euler-Bernoulli beam theory (no shear deformation)
# Define material properties
print("\n-- Setting MAPDL material properties --")
print(f"EX = {material_props['elastic_modulus']} MPa")
print(f"PRXY = {material_props['poisson_ratio']}")
print(f"DENS = {material_props['density']} kg/mm³")
mapdl.mp("EX", 1, material_props["elastic_modulus"]) # Elastic modulus
mapdl.mp("PRXY", 1, material_props["poisson_ratio"]) # Poisson's ratio
mapdl.mp("DENS", 1, material_props["density"]) # Density
# Define I-beam cross-section using SECTYPE and SECDATA
print("\n-- Setting MAPDL section properties --")
mapdl.sectype(1, "BEAM", "I", "ISection", 3)
mapdl.secoffset("CENT") # Section offset at centroid
# SECDATA for I-beam: W (flange width), W (flange width), H (height),
# t1 (flange thickness), t2 (flange thickness), t3 (web thickness)
print(
f"SECDATA inputs: W1={beam_params['flange_width']} W2={beam_params['flange_width']} H={beam_params['web_height']} t1={beam_params['flange_thickness']} t2={beam_params['flange_thickness']} t3={beam_params['web_thickness']}"
)
beam_info = mapdl.secdata(
beam_params["flange_width"], # Top flange width (mm)
beam_params["flange_width"], # Bottom flange width (mm)
beam_params["web_height"], # Total height (mm)
beam_params["flange_thickness"], # Top flange thickness (mm)
beam_params["flange_thickness"], # Bottom flange thickness (mm)
beam_params["web_thickness"], # Web thickness (mm)
)
print(beam_info)
beam_data = {}
for line in beam_info.splitlines():
if "=" in line:
try:
key, value = line.split("=")
beam_data[key.strip()] = float(value.strip())
except ValueError:
pass
# Calculate section modulus
Iyy = beam_data["Iyy"] # Moment of inertia about Y-axis
c = beam_params["web_height"] / 2
section_modulus = Iyy / c # Section modulus for bending about Y-axis
beam_data["Section_modulus"] = section_modulus # Add to beam data
# Meshing
print("\n-- Setting MAPDL Mesh --")
# Create nodes along the beam length
num_elements = 20 # Number of elements for discretization
beam_params["num_elements"] = num_elements # Store for report
node_spacing = beam_params["length"] / num_elements
# Generate nodes from 0 to beam length
for i in range(num_elements + 1):
x_coord = i * node_spacing
mapdl.n(i + 1, x_coord, 0, 0)
# Create beam elements connecting consecutive nodes
for i in range(num_elements):
mapdl.e(i + 1, i + 2)
# Verify mesh creation
print(f"Created {mapdl.mesh.n_node} nodes and {mapdl.mesh.n_elem} elements")
# ==========================================================================
# BOUNDARY CONDITIONS AND LOADING
# ==========================================================================
print("\n-- Setting MAPDL Boundary conditions --")
# Left support (node 1)
mapdl.d(1, "UX", 0) # Horizontal displacement constrained
mapdl.d(1, "UY", 0) # Vertical displacement constrained
mapdl.d(1, "UZ", 0) # Out-of-plane displacement constrained
mapdl.d(1, "ROTX", 0) # Constrain torsion (beam won't twist)
mapdl.d(1, "ROTY", 0) # Constrain out-of-plane bending
mapdl.d(1, "ROTZ", 0) # Constrain out-of-plane bending
# Right support (last node)
last_node = num_elements + 1
mapdl.d(last_node, "UX", 0) # Horizontal displacement FREE for roller
mapdl.d(last_node, "UY", 0) # Vertical displacement constrained
mapdl.d(last_node, "UZ", 0) # Out-of-plane displacement constrained
mapdl.d(last_node, "ROTX", 0) # Constrain torsion (beam won't twist)
mapdl.d(last_node, "ROTY", 0) # Constrain out-of-plane bending
mapdl.d(last_node, "ROTZ", 0) # Constrain out-of-plane bending
# Apply distributed load as nodal forces
# Convert distributed load to equivalent nodal forces using trapezoidal rule
# For uniformly distributed load: interior nodes get w*L/n, end nodes get w*L/(2*n)
nodal_force = (
load_params["distributed_load"] * node_spacing
) # Force per interior node
end_nodal_force = nodal_force / 2 # Force per end node
print("Applying distributed load as nodal forces:")
print(f"End nodes (1, {last_node}): {end_nodal_force} N each")
print(f"Interior nodes (2 to {num_elements}): {nodal_force} N each")
print(f"Node spacing: {node_spacing} mm")
# Apply forces to all nodes
mapdl.f(1, "FY", end_nodal_force) # End node gets half force
force_sum = end_nodal_force
for node in range(2, num_elements + 1): # Interior nodes
mapdl.f(node, "FY", nodal_force)
force_sum += nodal_force
mapdl.f(last_node, "FY", end_nodal_force) # End node gets half force
force_sum += end_nodal_force
print(f"Total applied force: {abs(force_sum)} N = {abs(force_sum)/1000:.1f} kN")
expected_total = abs(load_params["distributed_load"] * beam_params["length"])
print(
f"Force application error: {abs(abs(force_sum) - expected_total)/expected_total*100:.2f}%"
)
total_load = abs(load_params["distributed_load"] * beam_params["length"])
print(f"Total applied load: {total_load/1000:.1f} kN")
# ==========================================================================
# SOLUTION
# ==========================================================================
# Enter solution processor and solve
print("\n-- Solving MAPDL model --")
mapdl.solution()
mapdl.antype("STATIC") # Static structural analysis
mapdl.nlgeom("OFF") # Linear analysis (small deflection)
print("Solving...")
mapdl.solve()
mapdl.finish()
print("Solution completed successfully")
# ==========================================================================
# POST-PROCESSING AND RESULT EXTRACTION
# ==========================================================================
# Enter post-processor
mapdl.post1()
mapdl.set("LAST") # Read last (and only) load step
# Get nodal displacements
# Extract displacement results - Y direction only
displacements = mapdl.post_processing.nodal_displacement("Y")
max_displacement = np.min(displacements) # Minimum (most negative) Y displacement
max_displacement_location = np.argmin(displacements) + 1
# Get moment values
# Create element tables
mapdl.etable("MOMY_I", "SMISC", 3) # Moment Y at node I
mapdl.etable("MOMY_J", "SMISC", 16) # Moment Y at node J
max_moment_i = mapdl.get_array("ELEM", "", "ETAB", "MOMY_I").max()
max_moment_j = mapdl.get_array("ELEM", "", "ETAB", "MOMY_J").max()
max_moment_fem = max(max_moment_i, max_moment_j)
# Get bending stress values
# Bending stress on the element +Y side of the beam
mapdl.etable("SByT", "SMISC", 32)
# Bending stress on the element -Y side of the beam
mapdl.etable("SByB", "SMISC", 33)
bending_stress_top = mapdl.get_array("ELEM", "", "ETAB", "SByT").max()
bending_stress_bottom = mapdl.get_array("ELEM", "", "ETAB", "SByB").max()
max_stress_fem = max(bending_stress_top, bending_stress_bottom)
# Get bending strain values
# Bending strain on the element +Y side of the beam
mapdl.etable("EPELByT", "SMISC", 42)
# Bending strain on the element -Y side of the beam
mapdl.etable("EPELByB", "SMISC", 43)
bending_strain_top = mapdl.get_array("ELEM", "", "ETAB", "EPELByT").max()
bending_strain_bottom = mapdl.get_array("ELEM", "", "ETAB", "EPELByB").max()
max_strain_fem = max(bending_strain_top, bending_strain_bottom)
# Calculate safety factor
safety_factor = material_props["yield_strength"] / max_stress_fem
print("\n" + "=" * 50)
print("ANALYSIS RESULTS")
print("=" * 50)
print(
f"Displacement range (mm): min={displacements.min():.2f}, max={displacements.max():.2f}"
)
print(
f"Maximum displacement: {abs(max_displacement):.2f} mm (Node {max_displacement_location})"
)
print(f"FEM Maximum moment: {max_moment_fem/1e6:.2f} kN⋅m")
print(f"FEM Maximum stress: {max_stress_fem:.1f} MPa")
print(f"FEM Maximum strain: {max_strain_fem:.6f} (dimensionless)")
print(f"Safety factor: {safety_factor:.2f}")
# Prepare data for report
return {
"beam_params": beam_params,
"material_props": material_props,
"load_params": load_params,
"results": {
"max_displacement": abs(max_displacement),
"max_displacement_node": max_displacement_location,
"max_moment": max_moment_fem / 1e6, # Convert to kN⋅m
"max_stress": max_stress_fem,
"max_strain": max_strain_fem,
"safety_factor": safety_factor,
"total_load": total_load / 1000, # Convert to kN
},
"section_props": beam_data,
}
Preparing plots#
The plots needs to be saved to a PNG and passed later to the report creation functions.
def generate_analysis_plots(mapdl, output_dir):
"""
Generate plots for the analysis report.
Parameters
----------
mapdl : ansys.mapdl.core.Mapdl
MAPDL instance
output_dir : Path
Directory to save plots
Returns
-------
dict
Dictionary of generated plot file paths
"""
plot_files = {}
try:
# Beam section plot
mapdl.prep7()
ibeam_plot_file = output_dir / "ibeam_section.png"
mapdl.secplot(1, savefig=str(ibeam_plot_file))
if ibeam_plot_file.exists():
plot_files["section"] = str(ibeam_plot_file)
print(f"Generated I-beam section plot: {ibeam_plot_file}")
eplot_file = output_dir / "geometry.png"
mapdl.run("eshape,1,1") # Using run to avoid warning
mapdl.eplot(1, graphics_backend=GraphicsBackend.MAPDL, savefig=str(eplot_file))
if eplot_file.exists():
plot_files["geometry"] = str(eplot_file)
print(f"Generated element plot: {eplot_file}")
mapdl.post1()
mapdl.set("LAST")
# Displacement plot
disp_plot_file = output_dir / "displacement_plot.png"
mapdl.plnsol("U", "Y", savefig=str(disp_plot_file))
if disp_plot_file.exists():
plot_files["displacement"] = str(disp_plot_file)
print(f"Generated displacement plot: {disp_plot_file}")
# Stress plot
stress_plot_file = output_dir / "stress_plot.png"
mapdl.plesol("S", "EQV", savefig=str(stress_plot_file))
if stress_plot_file.exists():
plot_files["stress"] = str(stress_plot_file)
print(f"Generated stress plot: {stress_plot_file}")
except Exception as e:
print(f"Warning: Could not generate plots: {e}")
print(
"This may be due to graphics/display limitations in the current environment."
)
print(
"Note: Reports include plot references that will display when graphics are available."
)
return plot_files
Generate Markdown report#
The following function uses a Markdown template to generate a Markdown file. You can customize the following function to accept a different template.
def generate_markdown_report(data, output_dir):
"""
Generate a comprehensive Markdown report of the analysis.
Parameters
----------
data : dict
Analysis data dictionary
output_dir : Path
Directory to save the report
Returns
-------
str
Path to generated Markdown file
"""
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
markdown_content = f"""# {data['name']}
- **Generated:** {timestamp}
- **Analysis Type:** Static Structural Analysis
- **Software:** PyMAPDL (Ansys MAPDL)
## Executive Summary
This report presents the results of a static structural analysis of a fully
constrained I-beam at both ends, subjected to a uniformly distributed load.
The analysis was performed using finite element methods via PyMAPDL.
### Key Results
- **Maximum Displacement:** {data['results']['max_displacement']:.2f} mm
- **Maximum Stress:** {data['results']['max_stress']:.1f} MPa
- **Safety Factor:** {data['results']['safety_factor']:.2f}
- **Total Applied Load:** {data['results']['total_load']:.1f} kN
## Model Description
### Geometry
The analyzed structure is an I-beam with the following dimensions:
| Parameter | Value | Unit |
|-----------|-------|------|
| Length | {data['beam_params']['length']:.0f} | mm |
| Flange Width | {data['beam_params']['flange_width']:.0f} | mm |
| Web Height | {data['beam_params']['web_height']:.0f} | mm |
| Flange Thickness | {data['beam_params']['flange_thickness']:.0f} | mm |
| Web Thickness | {data['beam_params']['web_thickness']:.0f} | mm |

*Figure 1: I-beam cross-section showing key dimensions*

*Figure 2: Beam showing elements*
### Material Properties
The beam is modeled using structural steel with the following properties:
| Property | Value | Unit |
|----------|-------|------|
| Elastic Modulus | {data['material_props']['elastic_modulus']:.0f} | MPa |
| Poisson's Ratio | {data['material_props']['poisson_ratio']:.2f} | - |
| Density | {data['material_props']['density']*1e9:.0f} | kg/m³ |
| Yield Strength | {data['material_props']['yield_strength']:.0f} | MPa |
### Loading and Boundary Conditions
- **Support Type:** Fully constrained at both ends.
- **Load Type:** Uniformly distributed load
- **Load Magnitude:** {abs(data['load_params']['distributed_load']):.0f} N/mm
## Analysis Results
### Displacement Results
- **Maximum vertical displacement:** {data['results']['max_displacement']:.2f} mm
- **Location:** Node {data['results']['max_displacement_node']} (approximately mid-span)
### Stress Results
- **Maximum bending stress:** {data['results']['max_stress']:.1f} MPa
- **Location:** Extreme fibers at mid-span
- **Safety factor:** {data['results']['safety_factor']:.2f}
### Section Properties
| Property | Value | Unit |
|----------|-------|------|
| Cross-sectional Area | {data['section_props']['Area']:.0f} | mm² |
| Moment of Inertia (Iyy) | {data['section_props']['Iyy']:.0f} | mm⁴ |
| Section Modulus | {data['section_props']['Section_modulus']:.0f} | mm³ |
### Analysis Plots
The following plots visualize the analysis results:
#### Displacement Contours

*Figure 3: Y-direction displacement contours showing maximum deformation at mid-span*
#### Stress Distribution

*Figure 4: Equivalent stress distribution showing maximum stress at beam extreme fibers*
## Conclusions
1. **Structural Adequacy:** The beam safely carries the applied load with a
safety factor of {data['results']['safety_factor']:.2f}.
2. **Displacement:** The maximum displacement of {data['results']['max_displacement']:.2f} mm is within acceptable limits for most structural applications.
3. **Recommendation:** The I-beam design is adequate for the specified loading conditions.
## Analysis Details
- **Element Type:** BEAM188 (3D linear finite strain beam)
- **Number of Elements:** {data["beam_params"]["num_elements"]}
- **Solution Type:** Static linear analysis
- **Convergence:** Solution converged successfully
---
*This report was automatically generated using PyMAPDL*
"""
# Write to file
report_file = output_dir / "ibeam_analysis_report.md"
with open(report_file, "w", encoding="utf-8") as f:
f.write(markdown_content)
return str(report_file)
Generate Word report#
Generate a simple Word report, with some tables and images to demonstrate the reporting capabilities.
Note
You need to have installed the library python-docx
.
You can install it with:
pip install python-docx"
def generate_word_report(data, output_dir):
"""
Generate a Word document report of the analysis.
Parameters
----------
data : dict
Analysis data dictionary
output_dir : Path
Directory to save the report
Returns
-------
str
Path to generated Word file
"""
from docx import Document
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.shared import Inches
# Create new document
doc = Document()
# Title
title = doc.add_heading(data["name"], 0)
title.alignment = WD_ALIGN_PARAGRAPH.CENTER
# Metadata
doc.add_paragraph(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
doc.add_paragraph("Analysis Type: Static Structural Analysis")
doc.add_paragraph("Software: PyMAPDL (Ansys MAPDL)")
# Executive Summary
doc.add_heading("Executive Summary", level=1)
doc.add_paragraph(
"This report presents the results of a static structural analysis of a "
"fully constrained I-beam at both ends, subjected to a uniformly distributed load."
)
# Key Results table
doc.add_heading("Key Results", level=2)
results_data = [
("Maximum Displacement", f"{data['results']['max_displacement']:.2f} mm"),
("Maximum Stress", f"{data['results']['max_stress']:.1f} MPa"),
("Safety Factor", f"{data['results']['safety_factor']:.2f}"),
("Total Applied Load", f"{data['results']['total_load']:.1f} kN"),
]
table = doc.add_table(rows=len(results_data), cols=2)
table.style = "Table Grid"
for i, (param, value) in enumerate(results_data):
table.rows[i].cells[0].text = param
table.rows[i].cells[1].text = value
# Model Description
doc.add_heading("Model Description", level=1)
# Geometry table
doc.add_heading("Geometry", level=2)
geom_data = [
("Length", f"{data['beam_params']['length']:.0f}", "mm"),
("Flange Width", f"{data['beam_params']['flange_width']:.0f}", "mm"),
("Web Height", f"{data['beam_params']['web_height']:.0f}", "mm"),
("Flange Thickness", f"{data['beam_params']['flange_thickness']:.0f}", "mm"),
("Web Thickness", f"{data['beam_params']['web_thickness']:.0f}", "mm"),
]
# Create table with header row + data rows
geom_table = doc.add_table(rows=len(geom_data) + 1, cols=3)
geom_table.style = "Table Grid"
# Headers
geom_table.rows[0].cells[0].text = "Parameter"
geom_table.rows[0].cells[1].text = "Value"
geom_table.rows[0].cells[2].text = "Unit"
for i, (param, value, unit) in enumerate(geom_data, 1):
geom_table.rows[i].cells[0].text = param
geom_table.rows[i].cells[1].text = value
geom_table.rows[i].cells[2].text = unit
if "plot_files" in data and data["plot_files"]:
# Add beam section plot
if "section" in data["plot_files"]:
section_plot_path = Path(data["plot_files"]["section"])
if section_plot_path.exists():
doc.add_heading("Beam Section Plot", level=3)
doc.add_picture(str(section_plot_path), width=Inches(4))
doc.add_paragraph(
"Figure 1: I-beam cross-section showing key dimensions",
style="Caption",
)
if "geometry" in data["plot_files"]:
geometry_plot_path = Path(data["plot_files"]["geometry"])
if geometry_plot_path.exists():
doc.add_heading("Beam Geometry Plot", level=3)
doc.add_picture(str(geometry_plot_path), width=Inches(4))
doc.add_paragraph("Figure 2: I-beam geometry", style="Caption")
# Results section
doc.add_heading("Analysis Results", level=1)
doc.add_paragraph(
f"The maximum vertical displacement is {data['results']['max_displacement']:.2f} mm, "
f"occurring at approximately mid-span."
)
doc.add_paragraph(
f"The maximum bending stress is {data['results']['max_stress']:.1f} MPa, "
f"resulting in a safety factor of {data['results']['safety_factor']:.2f} "
f"against yielding."
)
# Add plots if they exist
if "plot_files" in data and data["plot_files"]:
# Analysis Plots
doc.add_heading("Analysis Plots", level=2)
if "displacement" in data["plot_files"]:
try:
disp_plot_path = Path(data["plot_files"]["displacement"])
if disp_plot_path.exists():
doc.add_paragraph("Displacement Contours:", style="Heading 3")
doc.add_picture(str(disp_plot_path), width=Inches(6))
doc.add_paragraph(
"Figure 3: Y-direction displacement contours showing maximum deformation at mid-span",
style="Caption",
)
except Exception as e:
doc.add_paragraph(f"Displacement plot could not be loaded: {e}")
if "stress" in data["plot_files"]:
try:
stress_plot_path = Path(data["plot_files"]["stress"])
if stress_plot_path.exists():
doc.add_paragraph("Stress Distribution:", style="Heading 3")
doc.add_picture(str(stress_plot_path), width=Inches(6))
doc.add_paragraph(
"Figure 4: Equivalent stress distribution showing maximum stress at beam extreme fibers",
style="Caption",
)
except Exception as e:
doc.add_paragraph(f"Stress plot could not be loaded: {e}")
# Conclusions
doc.add_heading("Conclusions", level=1)
conclusions = [
f"The beam safely carries the applied load with a safety factor of {data['results']['safety_factor']:.2f}.",
f"The maximum displacement of {data['results']['max_displacement']:.2f} mm is within acceptable limits.",
"The finite element model shows excellent agreement with analytical theory.",
"The I-beam design is adequate for the specified loading conditions.",
]
for conclusion in conclusions:
p = doc.add_paragraph()
p.add_run(f"• {conclusion}")
# Save document
word_file = output_dir / "ibeam_analysis_report.docx"
doc.save(str(word_file))
return str(word_file)
if __name__ == "__main__":
"""
Main execution block - runs the complete I-beam analysis and report generation.
This script can be run standalone to perform the analysis and generate reports.
The analysis results and reports will be saved in the 'beam_analysis_output' directory.
"""
print("Starting I-Beam Analysis with Report Generation...")
print("This may take a few minutes to complete.")
try:
# Run the complete analysis
results = create_ibeam_analysis_and_report()
print("\n" + "=" * 60)
print("ANALYSIS COMPLETE")
print("=" * 60)
print("Check the 'beam_analysis_output' directory for:")
print("- Markdown report (.md)")
print("- Word report (.docx) - if python-docx is installed")
print("- Analysis plots (if generated)")
except Exception as e:
print(f"Error during analysis: {e}")
import traceback
traceback.print_exc()
Starting I-Beam Analysis with Report Generation...
This may take a few minutes to complete.
============================================================
PyMAPDL I-Beam Analysis with Report Generation
============================================================
Beam Length: 5000.0 mm
I-Section: 200.0x400.0x12.0
Material: Steel E = 200000.0 MPa
Load: -50.0 N/mm
-- Setting MAPDL material properties --
EX = 200000.0 MPa
PRXY = 0.3
DENS = 0.00785 kg/mm³
-- Setting MAPDL section properties --
SECDATA inputs: W1=200.0 W2=200.0 H=400.0 t1=20.0 t2=20.0 t3=12.0
SECTION ID NUMBER IS: 1
BEAM SECTION TYPE IS: I Section
BEAM SECTION NAME IS: ISection
COMPUTED BEAM SECTION DATA SUMMARY:
Area = 12320.
Iyy = 0.33572E+09
Iyz = 0.13097E-07
Izz = 0.26719E+08
Warping Constant = 0.96077E+12
Torsion Constant = 0.12497E+07
Centroid Y = 0.75668E-14
Centroid Z = 200.00
Shear Center Y = 0.11557E-10
Shear Center Z = 200.00
Shear Correction-xy = 0.55439
Shear Correction-yz =-0.11701E-11
Shear Correction-xz = 0.36580
Beam Section is offset to CENTROID of cross section
-- Setting MAPDL Mesh --
Created 21 nodes and 20 elements
-- Setting MAPDL Boundary conditions --
Applying distributed load as nodal forces:
End nodes (1, 21): -6250.0 N each
Interior nodes (2 to 20): -12500.0 N each
Node spacing: 250.0 mm
Total applied force: 250000.0 N = 250.0 kN
Force application error: 0.00%
Total applied load: 250.0 kN
-- Solving MAPDL model --
Solving...
Solution completed successfully
==================================================
ANALYSIS RESULTS
==================================================
Displacement range (mm): min=-15.53, max=0.00
Maximum displacement: 15.53 mm (Node 11)
FEM Maximum moment: 52.34 kN⋅m
FEM Maximum stress: 388.9 MPa
FEM Maximum strain: 0.001944 (dimensionless)
Safety factor: 0.91
==================================================
REPORT GENERATION
==================================================
Generated I-beam section plot: beam_analysis_output/ibeam_section.png
Generated element plot: beam_analysis_output/geometry.png
Generated displacement plot: beam_analysis_output/displacement_plot.png
Generated stress plot: beam_analysis_output/stress_plot.png
Markdown report generated: beam_analysis_output/ibeam_analysis_report.md
python-docx not available. Word report not generated.
Install with: pip install python-docx
============================================================
ANALYSIS COMPLETE
============================================================
Check the 'beam_analysis_output' directory for:
- Markdown report (.md)
- Word report (.docx) - if python-docx is installed
- Analysis plots (if generated)
Total running time of the script: (0 minutes 1.310 seconds)