0% found this document useful (0 votes)
10 views

Project 511

The document describes analyzing a truss structure using Python and Mathematica. It provides an example truss problem and shows the input data and output results from both programs. The results are then compared to check for consistency.

Uploaded by

ziaurahmanali2
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views

Project 511

The document describes analyzing a truss structure using Python and Mathematica. It provides an example truss problem and shows the input data and output results from both programs. The results are then compared to check for consistency.

Uploaded by

ziaurahmanali2
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 21

King Fahd University of Petroleum & Minerals

Civil & Environmental Engineering Department

CE 511: Advanced
Structural Analysis and Vibrations – Term Project
Second Semester 2023- (232)
Structural Analysis Program for Truss

 Group Name: Group C


 Members:
1. Ziaulrahman Ali ID: 202319630
2. Mustafa Mashhodi ID: 202319730
3. Saeed Busubul ID: 202319250
4. Saqib Hashemi ID: 202319750
Instructor:
Dr. Saheed Adekunle
Table of Contents
Introduction...........................................................................................................................................3
Abstract.................................................................................................................................................4
Program Notation..................................................................................................................................5
Preparation of Data for Plane Trusses...................................................................................................6
Solving Problems by Python and Mathematica for Comparison:..........................................................7
Example 1:.........................................................................................................................................7
a) By Mathematica............................................................................................................................7
Output from Mathematica:..............................................................................................................7
b) By Python....................................................................................................................................15
Table of input data..........................................................................................................................15
Output data from Python................................................................................................................15
Code for python...............................................................................................................................17
Conclusion...........................................................................................................................................25
Introduction

In structural engineering, truss structure analysis is important since it is used in the design
and assessment of many different civil engineering projects. Trusses are essential parts of
towers, bridges, roofs, and other load-bearing structures because of their ease of use and
effectiveness in supporting axial loads. It is essential to comprehend how trusses behave
under various loading scenarios in order to maximize design parameters and guarantee
structural integrity.

In this project, we primarily concentrate on the analysis of truss structures using the direct
stiffness method, a popular analytical methodology. Based on the concepts of compatibility
and equilibrium, the stiffness technique provides a methodical way to figure out the internal
forces and deformations in a truss structure. The stiffness technique makes it easier to
formulate equations governing the equilibrium and compatibility of the overall structure by
modeling truss components as linear elastic elements connected at nodal points.

The main goal of this project is to create a Python implementation of the truss analysis
stiffness method. Python is widely recognized for its ease of use, adaptability, and copious
scientific computing libraries, making it a perfect platform for executing intricate engineering
algorithms. Our goal is to develop a user-friendly application that will allow researchers and
engineers to properly and efficiently study truss structures by utilizing Python's computing
power.

Furthermore, the utilization of Python for implementing the stiffness method offers several
advantages over traditional methods. Python's intuitive syntax and extensive ecosystem of
libraries, such as NumPy and SciPy, streamline the implementation process and facilitate
seamless integration with other engineering analysis tools. Additionally, Python's open-
source nature fosters collaboration and knowledge sharing within the engineering
community, enabling practitioners to leverage collective expertise for solving complex
engineering problems. By adopting Python for truss analysis, engineers can benefit from the
platform's versatility, scalability, and accessibility, paving the way for more efficient and
collaborative approaches to structural engineering analysis and design.

Furthermore, the understanding of structural behavior by future engineers has been


fundamentally altered by the inclusion of Python in engineering schools. Through Python-
focused coursework, educational institutions give students practical experiences that help
them understand theoretical concepts by applying them to real-world situations. This
approach sharpens their problem-solving skills and prepares them to tackle the challenges of
modern engineering.

In this report, we will use the direct stiffness method in the Python programming language
for the analysis and evaluation of truss structures. Following a few examples, the outcomes
will be compared with computations performed by hand and Mathematica at the conclusion.
Abstract

The Python software that is provided here conducts a thorough analysis of truss
constructions using the Direct Stiffness Method (DSM). The script precisely calculates
internal forces, reactions, and displacements within truss members under various loads by
utilizing the DSM. First, the script defines the geometry of the truss, including material
parameters like Young's modulus and cross-sectional area, as well as nodes coordinates and
members connectivity. Next, using the connectivity and material attributes of each truss
component as a basis, it aggregates the stiffness contributions to create a global stiffness
matrix. The script effectively computes nodal displacements and member forces using matrix
operations after applying boundary conditions and loads. Features for visualization are added
to show the internal force distribution and distorted shape of the truss. Because of its modular
design, the script may be easily integrated with other structural analysis tools and customized
for different engineering applications. This DSM implementation in Python provides
engineers and researchers with a comprehensive and adaptable way to analyze and optimize
truss constructions.
Program Notation
The notation used in this computer program for truss structures is summarized in this section.

Identifiers Used in Computer Program

Identifier Definition
Identifier Definition

Preparation of Data for Plane Trusses


Table shows the input data required for Plane trusses. Since Plane trusses have two possible
displacements at each joint, the structural parameters required for plane trusses, except that
the Number of joints (NJ) must be specified in addition to the other items. Moreover, a set of
data (NJ lines total) is required to specify the coordinates of the joints of a truss. Each line in
this set contains a Joint number (J), the (x) coordinate X(J) of the joint, and the y coordinate
Y(J) of the joint. On each of the lines containing Member information the Member number
(I) is listed first, followed by the Joint (J) Number JJ(I) and the Joint (k) Number JK(I) for
the Two ends of the Member. The choice of which end of the member is to be the j end and
which is to be the (k) end is made arbitrarily by the programmer. The last item on each line is
the cross-sectional area AX (I) of the Member. The data for the Joint restraint list, except that
the types of restraints differ. For the Plane truss, the terms JRL(2K-l) and JRL(2K) denote
the restraints against translations in the (x) and (y) directions, respectively, at Joint (k). the
load data are symbolically the, but the applied actions AJ consist of forces in the (x) and (y)
directions, and the hinged-end actions AML consist of forces in the (XM) and (YM) directions
at the ends of the Members.

Preparation of Data for Plane Trusses


Solving Problems by Python and Mathematica for Comparison:
Example 1:
Solve the following problem if, the weight per unit of each member is ignored. Calculate
support reactions and end actions of each member. (EI is same for all members)

a) By Mathematica

Output from Mathematica


b) By Python
Table of input data

Control 1 2 1
data
a 3 4 6 3 10000
b 1 75 100
2 0 0
3 75 0
Structural data

4 150 0
c 1 2 1 10
2 1 3 10
3 1 4 10
d 2 1 1
3 1 1
4 1 1
a 1 0
b 1 20 10
Load data

c
Output data from Python

JOINT DJ1 DJ2


1 3.47E-02 4.94E-03
2 0 0
3 0 0
4 0 0
MEMBER END-ACTIONS
MEMBER AM1 AM2 AM3 AM4
1 -19.828722 0 19.828722 0
2 -4.9407115 0 4.9407115 0
3 13.5046091 0 - 0
13.5046091
SUPPORT REACTIONS
JOINT AR1 AR2
2 -11.897234 -15.862978
3 0 -4.9407115
4 -8.10276604 10.8036871

Output data from python


Code for python

#A PROGRAM FOR ANALYSIS OF PLANE TRUSS


import numpy as np
import sys

#CONTROL DATA
ITS = input("Enter ISN, ITS and NLS: ").split()
NA = int(ITS[2])#FOR INITIALIZATION OF NUMBER OF LOADING SYSTEMS
Z = 1 #FOR INITIALIZATION OF LOOP

if int(ITS[1]) == 2:
MI =(input("Enter M, NJ, NRJ and E : ")).split()
m = int(MI[0])
NJ = int(MI[1])
NRJ = int(MI[2])
E = float(MI[3])

X = [0 for i in range(NJ)]
Y = [0 for i in range(NJ)]
for i in range(NJ):
Joint_Co = input("Enter Joint(K) and Coordinates X(J) and Y(J):
").split()
X[int(Joint_Co[0]) - 1] = float(Joint_Co[1])
Y[int(Joint_Co[0]) - 1] = float(Joint_Co[2])

J = [0 for i in range(m)]
K = [0 for i in range(m)]
EL = [0 for i in range(m)]
Cx = [0 for i in range(m)]
Cy = [0 for i in range(m)]
Ax = [0 for i in range(m)]
for i in range(m):
Member_info = (input(f"For member {i + 1}, Enter J and K ends, and
Area Ax: ").split())
J[i] = Member_info[0]
K[i] = Member_info[1]
ELX = float(X[int(Member_info[1]) - 1]) -
float(X[int(Member_info[0]) - 1])
ELY = float(Y[int(Member_info[1]) - 1]) -
float(Y[int(Member_info[0]) - 1])
EL[i] = float((ELX * ELX + ELY * ELY) ** 0.5)
Cx[i] = ELX / (float(EL[i]))
Cy[i] = ELY / (float(EL[i]))
Ax[i] = float(Member_info[2])

CxCx = [0 for i in range(m)]


CyCy = [0 for i in range(m)]
CxCy = [0 for i in range(m)]
for i in range(m):
CxCx[i] = Cx[i] * Cx[i]
CyCy[i] = Cy[i] * Cy[i]
CxCy[i] = Cx[i] * Cy[i]

ND = 2*NJ
SMS = [[0 for i in range(ND)] for i in range(ND)]
Matrix = []
for i in range(m):
SCM = [[0 for i in range(ND)] for i in range(ND)]
j1 = 2 * (int(J[i])) - 2
j2 = 2 * (int(J[i])) - 1
k1 = 2 * (int(K[i])) - 2
k2 = 2 * (int(K[i])) - 1
SM = [[0 for i in range(4)] for i in range(4)]
SMi = [[0 for i in range(4)] for i in range(4)]

SM[0][0] = SCM[j1][j1] = ((float(Ax[i]) * E) / (float(EL[i]))) *


CxCx[i]
SM[1][0] = SCM[j2][j1] = ((float(Ax[i]) * E) / (float(EL[i]))) *
CxCy[i]
SM[2][0] = SCM[k1][j1] = -((float(Ax[i]) * E) / (float(EL[i]))) *
CxCx[i]
SM[3][0] = SCM[k2][j1] = -((float(Ax[i]) * E) / (float(EL[i]))) *
CxCy[i]

SM[0][1] = SCM[j1][j2] = ((float(Ax[i]) * E) / (float(EL[i]))) *


CxCy[i]
SM[1][1] = SCM[j2][j2] = ((float(Ax[i]) * E) / (float(EL[i]))) *
CyCy[i]
SM[2][1] = SCM[k1][j2] = -((float(Ax[i]) * E) / (float(EL[i]))) *
CxCy[i]
SM[3][1] = SCM[k2][j2] = -((float(Ax[i]) * E) / (float(EL[i]))) *
CyCy[i]

SM[0][2] = SCM[j1][k1] = -((float(Ax[i]) * E) / (float(EL[i]))) *


CxCx[i]
SM[1][2] = SCM[j2][k1] = -((float(Ax[i]) * E) / (float(EL[i]))) *
CxCy[i]
SM[2][2] = SCM[k1][k1] = ((float(Ax[i]) * E) / (float(EL[i]))) *
CxCx[i]
SM[3][2] = SCM[k2][k1] = ((float(Ax[i]) * E) / (float(EL[i]))) *
CxCy[i]

SM[0][3] = SCM[j1][k2] = -((float(Ax[i]) * E) / (float(EL[i]))) *


CxCy[i]
SM[1][3] = SCM[j2][k2] = -((float(Ax[i]) * E) / (float(EL[i]))) *
CyCy[i]
SM[2][3] = SCM[k1][k2] = ((float(Ax[i]) * E) / (float(EL[i]))) *
CxCy[i]
SM[3][3] = SCM[k2][k2] = ((float(Ax[i]) * E) / (float(EL[i]))) *
CyCy[i]

SMi[0][0] = (float(Ax[i]) * E) / (float(EL[i]))


SMi[0][2] = -(float(Ax[i]) * E) / (float(EL[i]))
SMi[2][0] = -(float(Ax[i]) * E) / (float(EL[i]))
SMi[2][2] = (float(Ax[i]) * E) / (float(EL[i]))

Matrix.append(SMi)
#zia alrahman # 2557774
for i in range(len(SCM)):
for j in range(len(SCM[0])):
SMS[i][j] = SMS[i][j] + SCM[i][j]

ID = [0 for i in range(ND)]
for i in range(NJ):
ID[2 * int(i + 1) - 2] = 2 * i
ID[2 * int(i + 1) - 1] = 2 * i + 1

JRL = [0 for i in range(ND)]


RJ = [0 for i in range(NRJ)]
for i in range(NRJ):
JRList = input(f"Restraint Joint(K), JRL(2K-1), (JRL(2K): ").split()
RJ[i] = JRList[0]
JRL[(2 * int(JRList[0]) - 2)] = int(JRList[1])
JRL[(2 * int(JRList[0]) - 1)] = int(JRList[2])

C = np.cumsum(np.array(JRL))

B = [0 for i in range(ND)]
NR = C[-1]
N = ND - NR
NF = N - 1
for i in range(ND):
if JRL[int(i)] == 1:
B[i] = NF + C[i]
else:
B[i] = ID[i] - C[i]

SJ = [[0 for i in range(ND)] for i in range(ND)]


for i in range(ND):
for j in range(ND):
SJ[int(B[i])][int(B[j])] = SMS[i][j]

print("")
Z = 1 # FOR INITIALIZATION OF LOOP
LN = 0 # FOR INITIALIZATION OF LOADING NUMBER
while NA != 0:
LN = LN + 1
print(f"PARAMETERS FOR LOADING NO. {LN}")
NLJM = input("Enter Number of Loaded Joint(NLJ) and Loaded
Member(NLM): ", ).split()
AJ = [0 for i in range(ND)]
NLA = [0 for i in range(int(NLJM[0]))] # FOR INDEXING
for i in range(int(NLJM[0])):
NLJT = input("Loaded Joint(K), AJX(2K-1), AJY(2K): ").split()
NLA[i] = int(NLJT[0])
AJ[(2 * int(NLJT[0]) - 2)] = int(NLJT[1])
AJ[(2 * int(NLJT[0]) - 1)] = int(NLJT[2])

RTT = []
for i in range(m):
RT = [[0 for i in range(4)] for i in range(4)]
RT[0][0] = Cx[i]
RT[1][0] = -Cy[i]
RT[2][0] = 0
RT[3][0] = 0

RT[0][1] = Cy[i]
RT[1][1] = Cx[i]
RT[2][1] = 0
RT[3][1] = 0

RT[0][2] = 0
RT[1][2] = 0
RT[2][2] = Cx[i]
RT[3][2] = -Cy[i]

RT[0][3] = 0
RT[1][3] = 0
RT[2][3] = Cy[i]
RT[3][3] = Cx[i]

RTT.append(RT)

print("")
AE = [0 for i in range(ND)]
AMLX = [[0 for i in range(4)] for i in range(m)]
NLM = [0 for i in range(int(NLJM[1]))] # FOR INDEXING
for i in range(int(NLJM[1])):
AMX = [0 for i in range(4)]
NLMT = input("Loaded Member(M), AML(2J-1), AML(2J), AML(2K-1),
AML(2K): ").split()
NLM[i] = NLMT[0]
AMX[0] = float(NLMT[1])
AMX[1] = float(NLMT[2])
AMX[2] = float(NLMT[3])
AMX[3] = float(NLMT[4])

AMS = np.matmul(np.transpose(np.array(RTT[int(NLMT[0]) - 1])),


np.array(AMX))

AE[(2 * int(J[int(NLMT[0]) - 1])) - 2] = float(AE[(2 *


int(J[int(NLMT[0]) - 1])) - 2]) - float(AMS[0])
AE[(2 * int(J[int(NLMT[0]) - 1])) - 1] = float(AE[(2 *
int(J[int(NLMT[0]) - 1])) - 1]) - float(AMS[1])
AE[(2 * int(K[int(NLMT[0]) - 1])) - 2] = float(AE[(2 *
int(K[int(NLMT[0]) - 1])) - 2]) - float(AMS[2])
AE[(2 * int(K[int(NLMT[0]) - 1])) - 1] = float(AE[(2 *
int(K[int(NLMT[0]) - 1])) - 1]) - float(AMS[3])

AMLX[int(NLMT[0]) - 1] = AMX

AC = [0 for i in range(ND)]
for i in range(ND):
AC[i] = AE[i] + AJ[i]

ACF = [0 for i in range(ND)]


for i in range(ND):
ACF[int(B[i])] = AC[i]

AFC = [0 for i in range(N)]


for i in range(N):
AFC[i] = ACF[i]

ARC = [0 for i in range(NR)]


for i in range(N, ND):
ARC[i - N] = ACF[i]

SFF = [[0 for i in range(N)] for i in range(N)]


for i in range(N):
for j in range(N):
SFF[i][j] = SJ[i][j]

SRF = [[0 for i in range(N)] for i in range(NR)]


for i in range(N, ND):
for j in range(N):
SRF[i - N][j] = SJ[i][j]

DF = np.linalg.solve(np.array(SFF), np.array(AFC))
DJ = [0 for i in range(ND)]
for i in range(N):
DJ[i] = DF[i]
DJA = [0 for i in range(ND)]
for i in range(ND):
DJA[i] = DJ[int(B[i])]

DJXX = [[0 for i in range(4)] for i in range(m)]


for i in range(m):
DJX = [0 for i in range(4)]
DJX[0] = DJA[(2 * int(J[i]) - 2)]
DJX[1] = DJA[(2 * int(J[i]) - 1)]
DJX[2] = DJA[(2 * int(K[i]) - 2)]
DJX[3] = DJA[(2 * int(K[i]) - 1)]

DJXX[i] = DJX

AR = np.add(-np.array(ARC), np.matmul(np.array(SRF), DF))

ARR = [0 for i in range(ND)]


for i in range(N, ND):
ARR[i] = AR[i - N]
ARRA = [0 for i in range(ND)]
for i in range(ND):
ARRA[i] = ARR[int(B[i])]

AMLF = [[0 for i in range(4)] for i in range(m)] # CONTAINER FOR


MEMBERS END-ACTIONS
for i in range(m):
AMLF[i] = np.add(np.array(AMLX[i]), np.matmul(np.array(Matrix[i]),
np.matmul(np.array(RTT[i]), DJXX[i])))

f1 = open('TRUSS.txt', 'a')
np.set_printoptions(precision=2)
orig_stdout = sys.stdout
sys.stdout = f1
while Z > 0:
Z = Z - 1
print(f"STRUCTURE NO. {int(ITS[0])} PLANE TRUSS")
print("NUMBER OF LOADING SYSTEMS = ", int(ITS[2]))
print("")
print("STRUCTURAL PARAMETERS\n" + f"{'M':>5}" + f"{'N':>5}" +
f"{'NJ':>5}" + f"{'NR':>5}" + f"{'NRJ':>5}" + f"{'E':^18}")
print(f"{m:>5}" + f"{N:>5}" + f"{NJ:>5}" + f"{NR:>5}" + f"{NRJ:>5}"
+ f"{E:^18}")
print("")
print(f"JOINT COORDINATES\n" + f"{'JOINT':>5}" + f"{'X':>12}" +
f"{'Y':>12}")
for i in range(NJ):
print(f"{i + 1:>5}" + f"{"{:.3F}".format(float(X[i])):>12}" +
f"{"{:.3F}".format(float(Y[i])):>12}")
print("")
print(f"MEMBER INFORMATION\n" + f"{'MEMBER':>6}" + f"{'JJ':>4}" +
f"{'JK':>5}" + f"{'AX':>12}" + f"{'EL':>12}" + f"{'CX':>12}" +
f"{'CY':>12}")
for i in range(m):
print(f"{i + 1:>5}" + f"{int(J[i]):>5}" + f"{int(K[i]):>5}" +
f"{"{:.3F}".format(float(Ax[i])):>12}" +
f"{"{:.3F}".format(float(EL[i])):>12}"+
f"{"{:.3F}".format(float(Cx[i])):>12}" +
f"{"{:.3F}".format(float(Cy[i])):>12}")
print("")
print(f"JOINT RESTRAINTS\n" + f"{'JOINT':>5}" + f"{'JR1':>5}" +
f"{'JR2':>5}")
for i in range(NRJ):
print(f"{int(RJ[i]):>5}" + f"{int(JRL[(2 * int(RJ[i]))-2]):>5}" +
f"{int(JRL[(2 * int(RJ[i]))-1]):>5}")
print("")
print(f"LOADING NO. {LN:>3} \n" + f"{'NLJ':>5}" + f"{'NLM':>5}")
print(f"{int(NLJM[0]):>5}" + f"{int(NLJM[1]):>5}")
print("")
if int(NLJM[0]) != 0:
print(f"ACTIONS AT JOINTS \n" + f"{'JOINT':>5}" + f"{'AJ1':>12}" +
f"{'AJ2':>12}")
for i in range(int(NLJM[0])):
print(
f"{int(NLA[i]):>5}" + f"{"{:.3F}".format(float(AJ[(2 * int(NLA[i]) -
2)])):>12}" + f"{"{:.3F}".format(float(AJ[(2 * int(NLA[i]) -
1)])):>12}")
print("")
if int(NLJM[1]) != 0:
print(
"ACTIONS AT END OF RESTRAINTS MEMBERS DUE TO LOADS\n" +
f"{'MEMBER':>6}" + f"{'AML1':>11}" + f"{'AML2':>12}" +
f"{'AML3':>12}" + f"{'AML4':>12}")
for i in range(int(NLJM[1])):
print(
f"{int(NLM[i]):>5}" + f"{"{:.3F}".format(float(AMLX[int(NLM[i]) - 1]
[0])):>12}" + f"{"{:.3F}".format(float(AMLX[int(NLM[i]) - 1]
[1])):>12}" + f"{"{:.3F}".format(float(AMLX[int(NLM[i]) - 1]
[2])):>12}" + f"{"{:.3F}".format(float(AMLX[int(NLM[i]) - 1]
[3])):>12}")
print("")
print(f"JOINT DISPLACEMENTS\n" + f"{'JOINT':>5}" + f"{'DJ1':>12}" +
f"{'DJ2':>12}")
for i in range(NJ):
print(
f"{i + 1:>5}" + f"{"{:.4E}".format(float(DJA[2 * i])):>12}" +
f"{"{:.4E}".format(float((DJA[2 * i + 1]))):>12}")
print("")
print("MEMBER END-ACTIONS\n" + f"{'MEMBER':>6}" + f"{'AM1':>11}" +
f"{'AM2':>12}" + f"{'AM3':>12}" + f"{'AM4':>12}")
for i in range(m):
print(
f"{i + 1:>5}" + f"{"{:.3F}".format(float(AMLF[i][0])):>12}" +
f"{"{:.3F}".format(float(AMLF[i][1])):>12}" +
f"{"{:.3F}".format(float(AMLF[i][2])):>12}" +
f"{"{:.3F}".format(float(AMLF[i][3])):>12}")
print("")
print(f"SUPPORT REACTIONS\n" + f"{'JOINT':>5}" + f"{'AR1':>12}" +
f"{'AR2':>12}")
for i in range(NRJ):
print(
f"{int(RJ[i]):>5}" + f"{"{:.3F}".format(float(ARRA[(2 * int(RJ[i]))-
2])):>12}" + f"{"{:.3F}".format(float(ARRA[(2 * int(RJ[i]))-
1])):>12}")
sys.stdout = orig_stdout
NA = NA - 1
f1.close
Conclusion
In conclusion, engineers and researchers now have a cutting-edge and adaptable way to
perform truss analysis using the Direct Stiffness Method (DSM) in Python. The tool makes
use of Python's many libraries and flexibility to offer a user-friendly platform for accurate
and efficient truss structure analysis. Productivity is increased and the analytical process is
streamlined by having the ability to design truss geometry, specify material parameters, and
view findings all within the same environment. A number of benefits emerge when
contrasting the Python implementation with conventional Fortran-based methods. Python is
more approachable to a broader spectrum of users, including those without substantial
programming knowledge, thanks to its clarity and simplicity of usage. Additionally, a wider
range of tools for deciphering and analyzing truss structures are available thanks to Python's
rich ecosystem of libraries for numerical computation, data analysis, and visualization.
Although Fortran's syntax and high learning curve make it difficult for certain users to use, it
is nonetheless a capable language for numerical calculation. All things considered, the DSM
for truss analysis implementation in Python is a noteworthy development in structural
engineering software, providing a potency, adaptability, and user-friendliness that can assist
researchers and engineers in a variety of fields. Python's contribution to structural analysis is
anticipated to increase as computational tools advance, significantly boosting engineering
practices' efficacy and efficiency.

You might also like