%%html
<!--Script block to left align Markdown Tables-->
<style>
  table {margin-left: 0 !important;}
</style>

Making an ordinary homework problem into a computational thinking exercise

Engineering Mechanics (Statics)

Prerequesites (for this example)

Methodology for Problem (and Solution)

A typical static truss analysis problem goes like

"The figure below is a simply supported, statically determinate truss with pin connections (zero moment transfer connections).   Find the forces in each member for the loading shown."

This example will leverage linear systems solver(s) to analyze the truss. The approach uses concepts from statics and computational thinking.

From statics

From computational thinking

Problem Solving Protocol

Recall the problem solving protocols in ENGR-1330-S2021-Cleveland

  1. Define the problem (problem statement)
  2. Gather information (identify known and unknown values, and governing equations)
  3. Generate and evaluate potential solutions
  4. Refine and implement a solution
  5. Verify and test the solution.

We can stipulate that Step 1 is already done,

Known Values:

Unknown Values

Governing Principles

These are going to be problem and discipline specific; in this case two-force memebrs are assumed (stipulated), and the network is statically determinate. The ability to construct and find solutions to a non-singular linear system is assumed. The solution of linear systems is presented in ENGR-1330 in the following contexts:

Abstraction -- The Free-Body Diagram

Before even contemplating writing/using a program we need to build a mathematical model of the truss and assemble the system of linear equations that result from the model. A fundamental abstraction is to sketch a free-body-diagram as below and build a node naming convention (a type of pattern matching) and force names(abstraction with intent to replicate/automate).

Decomposition -- Node-by-Node Analysis

Next we will write the force balance for each of the six nodes (-), which will produce a total of 12 equations in the 12 unknowns (the 9 member forces, and 3 reactions). This is fundamentally a decomposition activity. While specific to this geometry, we could extend the analysis to allow for an external force at all nodes considered, and be able to solve for nearly any loading condition.

The figure below is the force balance for node , the two force equations (for the horizontal, , direction and the vertical, , direction) are listed below the figure.

The equation above is the force balance equation pair for the node. The component equation will later be named to indicate it arises from Node 1, component equation. A similar notation convention will also be adopted for the component equation. There will be an equation pair for each node.

Below is a sketch of the force balance for node , the two force equations (for the horizontal, , direction and the vertical, , direction) are listed below the figure.

Below is a sketch of the force balance for node , the two force equations (for the horizontal, , direction and the vertical, , direction) are listed below the figure.

Above is the force balance equation pair for node .

Below is a sketch of the force balance for node , the two force equations (for the horizontal, , direction and the vertical, , direction) are listed below the figure.

Above is the force balance equation pair for node .

Below is a sketch of the force balance for node , the two force equations (for the horizontal, , direction and the vertical, , direction) are listed below the figure.

Above is the force balance equation pair for node .

Below is a sketch of the force balance for node , the two force equations (for the horizontal, , direction and the vertical, , direction) are listed below the figure.

Above is the force balance equation pair for node .

System Integration - Assemble the Network Equations

The CT principle of system integration (not listed above but a legitimate component) as part of algorithm development is to gather the equation pairs into a single system of linear equations.

We will move the known loads to the right hand side and essentially construct the matrix equation .

The system below is a matrix representation of the equation pairs with the forces moved to the right hand side .

In the system, the rows are labeled on the left-most column with their node-related equation name.

Thus each row of the matrix corresponds to an equation derived from a node.

The columns are labeled with their respective unknown force (except the last column, which represents the right-hand-side of the system of linear equations).
Thus the coefficient in each column corresponds to a force in each node equation.
The sign of the coefficient refers to the assumed direction the force acts.

In the analysis all the members were assumed to be in tension (except for the reaction forces).
If a coefficient has a value of zero in a particular row, then that force does no act at the node to which the row corresponds.

From this representation the transition to the formal vector-matrix representation is straightforward.

First the coefficient matrix that is the result of the decomposition and node-by-node analysis.


Then the vector (numpy array) of unknowns that are identified by decomposition and node-by-node analysis.


And the right-hand side of forcing values, in this case three non-zero values


Algorithm (Initial Steps)

The supervisory algorithm at this point is straightforward, we want to solve

for

The various matrices above are entered into text files named A.txt and B.txt, we can examine the file contents using the

# list contents of the A matrix, uses call to OS host (replace `cat` with `type` if on a windoze Machine)
!(cat A.txt)
0.707106781 1   0   0   0   0   0   0   0   1   0   0
0.707106781 0   0   0   0   0   0   0   0   0   1   0
0   -1  0   0   0   1   0   0   0   0   0   0
0   0   1   0   0   0   0   0   0   0   0   0
0   0   0   0   -0.866  -1  0   1   0   0   0   0
0   0   0   0   0.5 0   1   0   0   0   0   0
0   0   0   0   0   0   0   -1  -0.707106781    0   0   0
0   0   0   0   0   0   0   0   0.707106781 0   0   1
-0.707106781    0   0   1   0.866   0   0   0   0   0   0   0
-0.707106781    0   -1  0   -0.5    0   0   0   0   0   0   0
0   0   0   -1  0   0   0   0   0.707106781 0   0   0
0   0   0   0   0   0   -1  0   -0.707106781    0   0   0
# list contents of RHS (AKA b) vector
!(cat B.txt)
0.0
0.0
0.0
0.0
0.0
500.0
0.0
0.0
0.0
1000.0
0.0
-500.0

Now we use our solver tools,

import numpy # load the numpy module

amatrix = [] # null list to store matrix reads
bvector = [] # null list to store matrix reads
rowNumA = 0  # a counter, needed to parse input files
colNumA = 0  # a counter, needed to parse input files
rowNumB = 0  # a counter, needed to parse input files

afile = open("A.txt","r")  # connect and read file for MATRIX A 
for line in afile:
    amatrix.append([float(n) for n in line.strip().split()])
    rowNumA += 1
afile.close() # Disconnect the file

afile = open("B.txt","r")  # connect and read file for VECTOR B 
for line in afile:
    bvector.append(float(line))  # vector read different -- just float the line
    rowNumB += 1
afile.close() # Disconnect the file

A = numpy.array(amatrix)  # create A
b = numpy.array(bvector)  # create b
x = numpy.linalg.solve(A, b) # solve for x

for i in range(0,len(x)):  # rudimentary output
    print(x[i])
-1035.2710218174145
732.0471596998927
0.0
-267.9528403001072
-535.9056806002143
732.0471596998927
767.9528403001071
267.95284030010714
-378.94254092877543
-3.9202487786118276e-14
732.0471596998927
267.95284030010714

Algorithm (Refinement)

To refine the algorithm, the obvious step is to label the output

labels =['F1','F2','F3','F4','F5','F6','F7','F8','F9','Ax','Ay','By'] #a list of labels, should automate as needed
for i in range(0,len(x)):  # rudimentary output
    print(labels[i]," = ",round(x[i],3),' pounds(force)')
F1  =  -1035.271  pounds(force)
F2  =  732.047  pounds(force)
F3  =  0.0  pounds(force)
F4  =  -267.953  pounds(force)
F5  =  -535.906  pounds(force)
F6  =  732.047  pounds(force)
F7  =  767.953  pounds(force)
F8  =  267.953  pounds(force)
F9  =  -378.943  pounds(force)
Ax  =  -0.0  pounds(force)
Ay  =  732.047  pounds(force)
By  =  267.953  pounds(force)

Conclusion/Suggested Extensions


References

Johnson, J. (2020). Python Numpy Tutorial (with Jupyter and Colab). Retrieved September 15, 2020, from https://cs231n.github.io/python-numpy-tutorial/

Willems, K. (2019). (Tutorial) Python NUMPY Array TUTORIAL. Retrieved September 15, 2020, from https://www.datacamp.com/community/tutorials/python-numpy-tutorial?utm_source=adwords_ppc

Willems, K. (2017). NumPy Cheat Sheet: Data Analysis in Python. Retrieved September 15, 2020, from https://www.datacamp.com/community/blog/python-numpy-cheat-sheet

W3resource. (2020). NumPy: Compare two given arrays. Retrieved September 15, 2020, from https://www.w3resource.com/python-exercises/numpy/python-numpy-exercise-28.php

Sorting https://www.programiz.com/python-programming/methods/list/sort

Overland, B. (2018). Python Without Fear. Addison-Wesley ISBN 978-0-13-468747-6.

Grus, Joel (2015). Data Science from Scratch: First Principles with Python O’Reilly Media. Kindle Edition.

Precord, C. (2010) wxPython 2.8 Application Development Cookbook Packt Publishing Ltd. Birmingham , B27 6PA, UK ISBN 978-1-849511-78-0.

# Preamble script block to identify host, user, and kernel
import sys
! hostname
! whoami
print(sys.executable)
print(sys.version)
print(sys.version_info)
atomickitty
compthink
/opt/jupyterhub/bin/python3
3.8.5 (default, Jul 28 2020, 12:59:40) 
[GCC 9.3.0]
sys.version_info(major=3, minor=8, micro=5, releaselevel='final', serial=0)