anastruct
anastruct
Release 1.0
Ritchie Vink
i
1.9.3 Range of node displacements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
1.9.4 Element results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
1.9.5 Range of element results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
1.10 Element/ node interaction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
1.10.1 Find node id based on coordinates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
1.10.2 Find nearest node id based on coordinates . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
1.10.3 Query node coordinates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
1.11 Vertex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
1.12 Saving . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
1.13 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.13.1 Simple example - Truss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.14 Intermediate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
1.15 Advanced . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Index 57
ii
CHAPTER
ONE
• genindex
• modindex
• search
1.1 Installation
You will need Python and a few packages as pre-requisites of the anaStruct on your system.
Linux
Python is normally delivered on any Linux distribution. So you basically just need to call the python keyword which is
stored on your operating system’s path. To call version 3 of python on Linux you can use python3 in the terminal. You
can check installation status and version of the python on your system.
python3 --version
In case you are missing the python on your system, you can install it from the repositories of your system. For instance,
on Ubuntu, you can easily install python 3.9 with the following commands:
Windows
On windows (and for other OS’s too) you can download the installation source of the version you prefer from the
Python’s website. You can choose between the various versions and cpu architectures.
1
anaStruct Documentation, Release 1.0
Mac
You will need the NumPy and SciPy. packages to be able to use the anaStruct package. However, if you are using the
pip to install the package, it will take care of all dependencies and their versions.
You can install anaStruct with pip! If you like to use the computational backend of the package without having the
plotting features, simply run the code below in the terminal. Pip will install a headless version of anaStruct (with no
plotting abilities).
Otherwise you can have a full installation using the following code in your terminal.
In case you need a specific version of the package, that’s possible too. Simple declare the version condition over the
code in terminal.
Alternatively, you can build the package from the source by cloning the source from the git repository. Updates are made
regularly released on PyPi, and if you’d like the bleeding edge newest features and fixes, or if you’d like to contribute
to the development of anaStruct, then install from github.
anaStruct is a Python implementation of the 2D Finite Element method for structures. It allows you to do structural
analysis of frames and frames. It helps you to compute the forces and displacements in the structural elements.
Besides linear calculations, there is also support for non-linear nodes and geometric non linearity.
You start a model by instantiating a SystemElements object. All the models state, i.e. elements, materials and forces
are kept by this object.
class anastruct.fem.system.SystemElements(figsize=(12, 8), EA=15000.0, EI=5000.0, load_factor=1.0,
mesh=50)
Modelling any structure starts with an object of this class.
Variables
• EA – Standard axial stiffness of elements, default=15,000
• EI – Standard bending stiffness of elements, default=5,000
• figsize – (tpl) Matplotlibs standard figure size
• element_map – (dict) Keys are the element ids, values are the element objects
• node_map – (dict) Keys are the node ids, values are the node objects.
• node_element_map – (dict) maps node ids to element objects.
• loads_point – (dict) Maps node ids to point loads.
• loads_q – (dict) Maps element ids to q-loads.
• loads_moment – (dict) Maps node ids to moment loads.
• loads_dead_load – (set) Element ids that have a dead load applied.
__init__(figsize=(12, 8), EA=15000.0, EI=5000.0, load_factor=1.0, mesh=50)
• E = Young’s modulus
• A = Area
• I = Moment of Inertia
Parameters
• figsize (Tuple[float, float]) – Set the standard plotting size.
• EA (float) – Standard E * A. Set the standard values of EA if none provided when gener-
ating an element.
• EI (float) – Standard E * I. Set the standard values of EA if none provided when gener-
ating an element.
• load_factor (float) – Multiply all loads with this factor.
• mesh (int) – Plotting mesh. Has no influence on the calculation.
Example
This ss object now has access to several methods which modify the state of the model. We can for instance create a
structure.
Now we have elements, we need to define the supporting conditions of our structure.
ss.add_support_hinged(node_id=1)
ss.add_support_fixed(node_id=3)
Finally we can add a load on the structure and compute the results.
ss.q_load(element_id=2, q=-10)
ss.solve()
We can take a look at the results of the calculation by plotting different units we are interested in.
ss.show_structure()
ss.show_reaction_force()
ss.show_axial_force()
ss.show_shear_force()
ss.show_bending_moment()
ss.show_displacement()
1.3 Elements
The SystemElements class has several methods that help you model a structure. These methods are;
add_truss_element
add_element
add_multiple_elements
discretize
1.3. Elements 9
anaStruct Documentation, Release 1.0
Standard elements have bending and axial stiffness and therefore will implement shear force, bending moment, axial
force, extension, and deflection. Standard elements can be added with the following methods.
Parameters
• location (Union[Sequence[Sequence[float]], Sequence[Vertex],
Sequence[float], Vertex]) – The two nodes of the element or the next node of the
element.
Example
• EA (Optional[float]) – EA
• EI (Optional[float]) – EI
• g (float) – Weight per meter. [kN/m] / [N/m]
• mp (Optional[Dict[int, float]]) –
Set a maximum plastic moment capacity. Keys are integers representing
the nodes. Values are the bending moment capacity.
Example
mp={1: 210e3,
2: 180e3}
spring={1: k
2: k}
Return type
int
Returns
Elements ID.
Example
ss = SystemElements(EA=15000, EI=5000)
ss.add_element(location=[[0, 0], [0, 5]])
ss.add_element(location=[[0, 5], [5, 5]])
ss.add_element(location=[[5, 5], [5, 0]])
ss.show_structure()
1.3. Elements 11
anaStruct Documentation, Release 1.0
Returns
(list) Element IDs
Example add_multiple_elements
ss = SystemElements(EI=5e3, EA=1e5)
ss.add_multiple_elements([[0, 0], [0, 10]], 10)
ss.show_structure()
1.3. Elements 13
anaStruct Documentation, Release 1.0
Example add_element_grid
# <3
t = np.linspace(-1, 1)
x = np.sin(t) * np.cos(t) * np.log(np.abs(t))
y = np.abs(t)**0.3 * np.cos(t)**0.5 + 1
# Scaling to positive interval
x = (x - x.min()) / (x - x.min()).max()
y = (y - y.min()) / (y - y.min()).max()
ss = SystemElements()
ss.add_element_grid(x, y)
ss.show_structure()
Truss elements don’t have bending stiffness and will therefore not implement shear force, bending moment and deflec-
tion. It does model axial force and extension.
add_truss_element
• EA (Optional[float]) – EA
Return type
int
Returns
Elements ID.
1.3.3 Discretization
You can discretize an element in multiple smaller elements with the discretize method.
SystemElements.discretize(n=10)
Takes an already defined SystemElements object and increases the number of elements.
Parameters
n (int) – Divide the elements into n sub-elements.
Most of the nodes are defined when creating an element by passing the vertices (x, y coordinates) as the location
parameter. It is also to add a node to elements that already exist via the insert_node method.
SystemElements.insert_node(element_id, location=None, factor=None)
Insert a node into an existing structure. This can be done by adding a new Vertex at any given location, or by
setting a factor of the elements length. E.g. if you want a node at 40% of the elements length, you pass factor =
0.4.
Note: this method completely rebuilds the SystemElements object and is therefore slower then building a model
with add_element methods.
Parameters
1.3. Elements 15
anaStruct Documentation, Release 1.0
• element_id (int) – Id number of the element you want to insert the node.
• location (Union[Sequence[float], Vertex, None]) – The nodes of the element or the
next node of the element.
Example
location=[x, y]
location=Vertex
Param
factor: Value between 0 and 1 to determine the new node location.
1.4 Supports
1.4.1 add_support_hinged
SystemElements.add_support_hinged(node_id)
Model a hinged support at a given node.
Parameters
node_id (Union[int, Sequence[int]]) – Represents the nodes ID
Example
ss.add_element(location=[5, 1])
ss.add_support_hinged(node_id=[1, 2])
ss.show_structure()
1.4.2 add_support_roll
1.4. Supports 17
anaStruct Documentation, Release 1.0
Example
ss.add_element(location=[5, 5])
ss.add_support_roll(node_id=2, direction=1)
ss.add_support_roll(node_id=1, direction=2)
ss.show_structure()
1.4.3 add_support_fixed
SystemElements.add_support_fixed(node_id)
Add a fixed support at a given node.
Parameters
node_id (Union[Sequence[int], int]) – Represents the nodes ID
Example
ss.add_element(location=[0, 2.5])
ss.add_support_fixed(node_id=1)
ss.show_structure()
1.4.4 add_support_spring
Example
ss.add_element(location=[5, 5])
ss.add_support_spring(node_id=1, translation=3, k=1000)
ss.add_support_spring(node_id=-1, translation=2, k=1000)
ss.show_structure()
1.4. Supports 19
anaStruct Documentation, Release 1.0
1 = translation in x
2 = translation in z
3 = rotation in y
1.5 Loads
anaStruct allows the following loads on a structure. There are loads on nodes and loads on elements. Element loads
are implicitly placed on the loads and recalculated during post processing.
Point loads
Point loads are defined in x- and/ or y-direction, or by defining a load with an angle.
SystemElements.point_load(node_id, Fx=0.0, Fy=0.0, rotation=0)
Apply a point load to a node.
Parameters
• node_id (Union[int, Sequence[int]]) – Nodes ID.
• Fx (Union[float, Sequence[float]]) – Force in global x direction.
• Fy (Union[float, Sequence[float]]) – Force in global x direction.
• rotation (Union[float, Sequence[float]]) – Rotate the force clockwise. Rotation is in
degrees.
Example
ss.add_element(location=[0, 1])
ss.point_load(ss.id_last_node, Fx=10, rotation=45)
ss.show_structure()
1.5. Loads 21
anaStruct Documentation, Release 1.0
Bending moments
Example
ss.add_element([5, 0])
ss.moment_load(node_id=ss.id_last_node, Ty=20)
ss.show_structure()
Q-loads are distributed loads. They can act perpendicular to the elements direction, parallel to the elements direction,
and in global x and y directions.
q-loads
1.5. Loads 23
anaStruct Documentation, Release 1.0
Example
ss.add_element([5, 0])
ss.q_load(q=-1, element_id=ss.id_last_element, direction='element')
ss.show_structure()
SystemElements.remove_loads(dead_load=False)
Remove all the applied loads from the structure.
Parameters
dead_load (bool) – Remove the dead load.
1.6 Plotting
The SystemElements object implements several plotting methods for retrieving standard plotting results. Every plotting
method has got the same parameters. The plotter is based on a Matplotlib backend and it is possible to get the figure
and do modifications of your own. The x and y coordinates of the model should all be positive value for the plotter to
work properly.
Note that plotting capabilities do require that anaStruct be installed with the “plot” sub-module (e.g. pip install anas-
truct[plot] )
1.6.1 Structure
1.6. Plotting 25
anaStruct Documentation, Release 1.0
1.6.6 Displacements
When the show parameter is set to False a Matplotlib figure is returned and the figure can be saved with proper titles.
x = np.arange(0, 10)
y = np.sin(x)
ss = SystemElements()
ss.add_element_grid(x, y)
ss.add_support_hinged(node_id=[1, -1])
fig = ss.show_structure(show=False)
plt.title('A sine wave')
plt.savefig('my-figure.png')
1.6. Plotting 27
anaStruct Documentation, Release 1.0
1.7 Calculation
Once all the elements, supports and loads are in place, solving the calculation is as easy as calling the solve method.
SystemElements.solve(force_linear=False, verbosity=0, max_iter=200, geometrical_non_linear=False,
**kwargs)
Compute the results of current model.
Parameters
• force_linear (bool) – Force a linear calculation. Even when the system has non linear
nodes.
• verbosity (int) –
0. Log calculation outputs. 1. silence.
• max_iter (int) – Maximum allowed iterations.
• geometrical_non_linear (int) – Calculate second order effects and determine the buck-
ling factor.
Returns
Displacements vector.
Development **kwargs:
param naked
Whether or not to run the solve function without doing post processing.
param discretize_kwargs
When doing a geometric non linear analysis you can reduce or increase the number of ele-
ments created that are used for determining the buckling_factor
The model will automatically do a non linear calculation if there are non linear nodes present in the SystemElements
state. You can however force the model to do a linear calculation with the force_linear parameter.
To start a geometrical non linear calculation you’ll need to set the geometrical_non_linear to True. It is also wise to
pass a discretize_kwargs dictionary.
ss.solve(geometrical_non_linear=True, discretize_kwargs=dict(n=20))
With this dictionary you can set the amount of discretization elements generated during the geometrical non linear
calculation. This calculation is an approximation and gets more accurate with more discretization elements.
You can group different loads in a single load case and add these to a SystemElements object. Let’s look at an example.
First we create a frame girder.
ss = SystemElements()
height = 10
x = np.cumsum([0, 4, 7, 7, 4])
y = np.zeros(x.shape)
x = np.append(x, x[::-1])
y = np.append(y, y + height)
ss.add_element_grid(x, y)
ss.add_element([[0, 0], [0, height]])
ss.add_element([[4, 0], [4, height]])
ss.add_element([[11, 0], [11, height]])
ss.add_element([[18, 0], [18, height]])
ss.add_support_hinged([1, 5])
ss.show_structure()
lc_wind = LoadCase('wind')
lc_wind.q_load(q=-1, element_id=[10, 11, 12, 13, 5])
print(lc_wind)
output
Loadcase wind:
{'q_load-1': {'direction': 'element',
'element_id': [10, 11, 12, 13, 5],
'q': -1}}
We can also combine load cases in a load combination with the LoadCombination class. First remove the previous load
case from the system, create a LoadCombination object and add the LoadCase objects to the LoadCombination object.
combination = LoadCombination('ULS')
combination.add_load_case(lc_wind, 1.5)
combination.add_load_case(lc_cables, factor=1.2)
Now we can make a separate calculation for every load case and for the whole load combination. We solve the com-
bination by calling the solve method and passing our SystemElements model. The solve method returns a dictionary
where the keys are the load cases and the values are the unique SystemElement objects for every load case. There is
also a key combination in the results dictionary.
results = combination.solve(ss)
for k, ss in results.items():
(continues on next page)
Combination
class anastruct.fem.util.load.LoadCase(name)
Group different loads in a load case
__init__(name)
Parameters
name – (str) Name of the load case
dead_load(element_id, g)
Apply a dead load in kN/m on elements.
Parameters
• element_id – (int/ list) representing the element ID
• g – (flt/ list) Weight per meter. [kN/m] / [N/m]
moment_load(node_id, Ty)
Apply a moment on a node.
Parameters
• node_id – (int/ list) Nodes ID.
• Ty – (flt/ list) Moments acting on the node.
class anastruct.fem.util.load.LoadCombination(name)
__init__(name)
add_load_case(lc, factor)
Add a load case to the load combination.
Parameters
• lc – (anastruct.fem.util.LoadCase)
• factor – (flt) Multiply all the loads in this LoadCase with this factor.
solve(system, force_linear=False, verbosity=0, max_iter=200, geometrical_non_linear=False, **kwargs)
Evaluate the Load Combination.
Parameters
• system – (anastruct.fem.system.SystemElements) Structure to apply loads on.
• force_linear – (bool) Force a linear calculation. Even when the system has non linear
nodes.
• verbosity – (int) 0: Log calculation outputs. 1: silence.
• max_iter – (int) Maximum allowed iterations.
• geometrical_non_linear – (bool) Calculate second order effects and determine the
buckling factor.
Returns
(ResultObject)
Development **kwargs:
param naked
(bool) Whether or not to run the solve function without doing post processing.
param discretize_kwargs
When doing a geometric non linear analysis you can reduce or increase the number of
elements created that are used for determining the buckling_factor
Besides plotting the result, it is also possible to query numerical results. We’ll go through them with a simple example.
ss = SystemElements()
element_type = 'truss'
# create triangles
x = np.arange(1, 10) * np.pi
y = np.cos(x)
y -= y.min()
ss.add_element_grid(x, y, element_type=element_type)
# supports
ss.add_support_hinged(1)
ss.add_support_roll(-1, 2)
# loads
ss.point_load(node_id=np.arange(2, 9, 2), Fy=-100)
ss.solve()
ss.show_structure()
SystemElements.get_node_results_system(node_id=0)
These are the node results. These are the opposite of the forces and displacements working on the elements and
may seem counter intuitive.
Parameters
node_id (int) – representing the node’s ID. If integer = 0, the results of all nodes are returned
Return type
Union[List[Tuple[Any, Any, Any, Any, Any, Any, Any]], Dict[str, Union[int, float]]]
Returns
if node_id == 0:
[(id, Fx, Fy, Ty, ux, uy, phi_y), (id, Fx, Fy...), () .. ]
if node_id > 0:
Example
We can use this method to query the reaction forces of the supports.
print(ss.get_node_results_system(node_id=1)['Fy'], ss.get_node_results_system(node_id=-
˓→1)['Fy'])
output
199.9999963370603 200.00000366293816
SystemElements.get_node_displacements(node_id=0)
Parameters
node_id (int) – Represents the node’s ID. If integer = 0, the results of all nodes are returned.
Return type
Union[List[Tuple[Any, Any, Any, Any]], Dict[str, Any]]
Returns
if node_id == 0:
[(id, ux, uy, phi_y), (id, ux, uy, phi_y), ... (id, ux, uy, phi_y) ]
Example
We can also query node displacements on a node level (So not opposite, as with the system node results.) To get the
maximum displacements at node 5 (the middle of the girder) we write.
print(ss.get_node_displacements(node_id=5))
output
SystemElements.get_node_result_range(unit)
Query a list with node results.
Return type
List[float]
Example
To get the deflection of all nodes in the girder, we use the get_node_result_range method.
deflection = ss.get_node_result_range('uy')
print(deflection)
plt.plot(deflection)
plt.show()
output
SystemElements.get_element_results(element_id=0, verbose=False)
Parameters
• element_id (int) – representing the elements ID. If elementID = 0 the results of all ele-
ments are returned.
• verbose (bool) – If set to True the numerical results for the deflection and the bending
moments are returned.
Return type
Union[List[Dict[str, Any]], Dict[str, Any]]
Returns
if node_id == 0:
[(id, length, alpha, u, N_1, N_2), (id, length, alpha, u, N_1, N_2),
... (id, length, alpha, u, N_1, N_2)]
Example
Axial force, shear force and extension are properties of the elements and not of the nodes. To get this information, we
need to query the results from the elements.
Let’s find the value of the maximum axial compression force, which is in element 10.
print(ss.get_element_results(element_id=10)['N'])
output
-417.395490645013
SystemElements.get_element_result_range(unit)
Useful when added lots of elements. Returns a list of all the queried unit.
Parameters
unit (str) –
• ‘shear’
• ’moment’
• ’axial’
Return type
List[float]
Example
We can of course think of a structure where we do not know where the maximum axial compression force will occur.
So let’s check if our assumption is correct and that the maximum force is indeed in element 10.
We query all the axial forces. The returned item is an ordered list. Because Python starts counting from zero, and our
elements start counting from one, we’ll need to add one to get the right element. Here we’ll see that the minimum force
(compression is negative) is indeed in element 10.
print(np.argmin(ss.get_element_result_range('axial')) + 1)
output
10
Once you structures will get more and more complex, it will become harder to keep count of element id and node ids.
The SystemElements class therefore has several methods that help you:
• Find a node id based on a x- and y-coordinate
• Find the nearest node id based on a x- and y-coordinate
• Get all the coordinates of all nodes.
SystemElements.find_node_id(vertex)
Retrieve the ID of a certain location.
Parameters
vertex (Union[Vertex, Sequence[float]]) – Vertex_xz, [x, y], (x, y)
Return type
Optional[int]
Returns
id of the node at the location of the vertex
SystemElements.nearest_node(dimension, val)
Retrieve the nearest node ID.
Parameters
• dimension (str) – “both”, ‘x’, ‘y’ or ‘z’
• val (Union[float, Sequence[float]]) – Value of the dimension.
Return type
Optional[int]
Returns
ID of the node.
SystemElements.nodes_range(dimension)
Retrieve a list with coordinates x or z (y).
Parameters
dimension (str) – “both”, ‘x’, ‘y’ or ‘z’
Return type
List[Union[float, Tuple[float, float], None]]
1.11 Vertex
Besides coordinates as a list such as [[x1, y1], [x2, y2]] anaStruct also has a utility node class called Vertex Objects
from this class can used to model elements and allow simple arithmetic on coordinates. Modelling with Vertex objects
can make it easier to model structures.
point_1 = Vertex(0, 0)
point_2 = point_1 + [10, 0]
point_3 = point_2 + [-5, 5]
ss = SystemElements()
ss.add_element([point_1, point_2])
ss.add_element(point_3)
ss.add_element(point_1)
ss.show_structure()
1.11. Vertex 43
anaStruct Documentation, Release 1.0
1.12 Saving
What do you need to save? You’ve got a script that represents your model. Just run it!
If you do need to save a model, you can save it with standard python object pickling.
import pickle
from anastruct import SystemElements
ss = SystemElements()
# save
with open('my_structure.pkl', 'wb') as f:
pickle.dump(ss, f)
# load
with open('my_structure.pkl', 'rb') as f:
ss = pickle.load(f)
1.13 Examples
Examples below a side variety of the structures which aim to show capabilities of the package. The same as any other
packages, anaStruct should be called and imported.
And for a mater of minimalism and making calls and coding more efficient, different classes can be called separately.
1 anas.LoadCase
2 anas.LoadCombination
3 anas.SystemElements
4 anas.Vertex
1 ss = SystemElements(EA=5000)
2 ss.add_truss_element(location=[[0, 0], [0, 5]])
3 ss.add_truss_element(location=[[0, 5], [5, 5]])
4 ss.add_truss_element(location=[[5, 5], [5, 0]])
5 ss.add_truss_element(location=[[0, 0], [5, 5]], EA=5000 * math.sqrt(2))
6
7 ss.add_support_hinged(node_id=1)
8 ss.add_support_hinged(node_id=4)
9
10 ss.point_load(Fx=10, node_id=2)
11
12 ss.solve()
13 ss.show_structure()
14 ss.show_reaction_force()
15 ss.show_axial_force()
16 ss.show_displacement(factor=10)
1.13. Examples 45
anaStruct Documentation, Release 1.0
1.13. Examples 47
anaStruct Documentation, Release 1.0
1.14 Intermediate
4 ss = SystemElements()
5 element_type = 'truss'
6
7 # Create 2 towers
8 width = 6
9 span = 30
10 k = 5e3
11
12 # create triangles
13 y = np.arange(1, 10) * np.pi
14 x = np.cos(y) * width * 0.5
15 x -= x.min()
16
21 # add triangles
22 ss.add_element_grid(x + length, y, element_type=element_type)
23 # add vertical elements
24 ss.add_element_grid(x_left_column, y[::2], element_type=element_type)
25 ss.add_element_grid(x_right_column, np.r_[y[0], y[1::2], y[-1]], element_
˓→type=element_type)
26
27 ss.add_support_spring(
28 node_id=ss.find_node_id(vertex=[x_left_column[0], y[0]]),
29 translation=2,
30 k=k)
31 ss.add_support_spring(
32 node_id=ss.find_node_id(vertex=[x_right_column[0], y[0]]),
33 translation=2,
34 k=k)
35
43 for el in ss.element_map.values():
44 # apply wind load on elements that are vertical
45 if np.isclose(np.sin(el.angle), 1):
46 ss.q_load(
47 q=1,
48 element_id=el.id,
49 direction='x'
(continues on next page)
52 ss.show_structure()
53 ss.solve()
54 ss.show_displacement(factor=2)
55 ss.show_bending_moment()
1.14. Intermediate 49
anaStruct Documentation, Release 1.0
1.15 Advanced
Take a look at this blog post. Here anaStruct was used to do a non linear water accumulation analysis. Water accumu-
lation blog post.
1 # import dependencies
2 import matplotlib.pyplot as plt
3 from anastruct.basic import converge
4 from anastruct.material.profile import HEA, IPE
5 from anastruct.fem.system import SystemElements, Vertex
6 from anastruct.material.units import to_kNm2, to_kN
7
8 # constants
9 E = 2.1e5 # Construction steels Young's modulus
10 b = 5 # c.t.c distance portals
11 q_water = 10
12
21 # beam spans
22 span_1 = span_2 = 21.9
23 span_3 = 8.9
24
33 def structure():
34 """
35 Build the structure from left to right, starting at axis 1.
36
37 variables:
38 EA = Young's modulus * Area
39 EI = Young's modulus * moment of Inertia
40 g = Weight [kN/ m]
41 elements = reference of the element id's that were created
42 dl = c.t.c distance different nodes.
43 """
44
45 dl = 0.2
46
47
48 ## SPAN 1 AND 2
(continues on next page)
1.15. Advanced 51
anaStruct Documentation, Release 1.0
55 # New system.
56 ss = SystemElements(mesh=3, plot_backend="mpl")
57
58 # span 1
59 first = dict(
60 spring={1: 9e3},
61 mp={1: 70},
62 )
63
67 # span 2
68 first = dict(
69 spring={1: 40e3},
70 mp={1: 240}
71 )
72 elements += ss.add_multiple_elements(location=p4, dl=dl, first=first, EA=EA, EI=EI,␣
˓→g=g)
75
76 ## SPAN 3
77
78 # span 3
79 # different IPE
80 g = IPE[240]['G'] / 100
81 EA = to_kN(E * IPE[240]['A'])
82 EI = to_kNm2(E * IPE[240]["Iy"])
83 first = dict(
84 spring={1: 15e3},
85 mp={1: 25},
86 )
87
93
94 ## COLUMNS
95
96 # column height
97 h = 7.2
(continues on next page)
99 # left column
100 EA = to_kN(E * IPE[220]['A'])
101 EI = to_kNm2(E * HEA[220]["Iy"])
102 left = ss.add_element([[0, 0], [0, -h]], EA=EA, EI=EI)
103
109
110 ## SUPPORTS
111
117 # Add supports. The location of the supports is defined with the nodes id.
118 ss.add_support_hinged((id_left, id_btm_right))
119
131 ss = structure()
132 ss.show_structure(verbosity=1, scale=0.6)
133
1.15. Advanced 53
anaStruct Documentation, Release 1.0
155 cubics = 0
156 n = force_water.shape[0]
157 for k in ss.node_map:
158 if k > n:
159 break
160 point_load = force_water[k - 1]
161
173 """
174 wh = 0.1
175
184 wh *= factor
185
189 a = 0
190 deflection = None
191 max_water_level = 0
192
195 for cubic in range(80, 150, 5): # This loop computes the results per m3 of storaged␣
˓→water.
196 wh = 0.05
197 lastwh = 0.2
198 cubic /= 10
199
202 c = 1
203 for _ in range(100): # This loop redistributes the water until the water level␣
˓→converges.
204
222 lastwh = wh
223 c += 1
224
234 a = 0
235 plt.plot([0, p6.x], [a, a], color="black")
236
237 c = "red"
238 a = 240
239 plt.plot([p3.x - 5, p3.x + 5], [a, a], color=c)
240 a = 25
241 plt.plot([p5.x - 5, p5.x + 5], [a, a], color=c)
242 a = 70
243 plt.plot([p1.x - 5, p1.x + 5], [a, a], color=c)
244
1.15. Advanced 55
anaStruct Documentation, Release 1.0
251
Symbols F
__init__() (anastruct.fem.system.SystemElements find_node_id() (anastruct.fem.system.SystemElements
method), 3 method), 42
__init__() (anastruct.fem.util.load.LoadCase method),
35 G
__init__() (anastruct.fem.util.load.LoadCombination get_element_result_range() (anas-
method), 36 truct.fem.system.SystemElements method),
42
A get_element_results() (anas-
add_element() (anastruct.fem.system.SystemElements truct.fem.system.SystemElements method),
method), 10 41
add_element_grid() (anas- get_node_displacements() (anas-
truct.fem.system.SystemElements method), truct.fem.system.SystemElements method),
13 39
add_load_case() (anas- get_node_result_range() (anas-
truct.fem.util.load.LoadCombination method), truct.fem.system.SystemElements method),
36 40
add_multiple_elements() (anas- get_node_results_system() (anas-
truct.fem.system.SystemElements method), truct.fem.system.SystemElements method),
11 38
add_support_fixed() (anas-
truct.fem.system.SystemElements method), I
18 insert_node() (anastruct.fem.system.SystemElements
add_support_hinged() (anas- method), 15
truct.fem.system.SystemElements method),
16 L
add_support_roll() (anas- LoadCase (class in anastruct.fem.util.load), 35
truct.fem.system.SystemElements method), LoadCombination (class in anastruct.fem.util.load), 36
17
add_support_spring() (anas- M
truct.fem.system.SystemElements method),
moment_load() (anastruct.fem.system.SystemElements
20
method), 22
add_truss_element() (anas-
moment_load() (anastruct.fem.util.load.LoadCase
truct.fem.system.SystemElements method),
method), 35
15
D N
dead_load() (anastruct.fem.util.load.LoadCase nearest_node() (anastruct.fem.system.SystemElements
method), 35 method), 43
discretize() (anastruct.fem.system.SystemElements nodes_range() (anastruct.fem.system.SystemElements
method), 15 method), 43
57
anaStruct Documentation, Release 1.0
P
point_load() (anastruct.fem.system.SystemElements
method), 21
point_load() (anastruct.fem.util.load.LoadCase
method), 35
Q
q_load() (anastruct.fem.system.SystemElements
method), 23
q_load() (anastruct.fem.util.load.LoadCase method), 36
R
remove_loads() (anastruct.fem.system.SystemElements
method), 24
S
show_axial_force() (anas-
truct.fem.system.SystemElements method),
25
show_bending_moment() (anas-
truct.fem.system.SystemElements method),
25
show_displacement() (anas-
truct.fem.system.SystemElements method),
27
show_reaction_force() (anas-
truct.fem.system.SystemElements method),
26
show_shear_force() (anas-
truct.fem.system.SystemElements method),
26
show_structure() (anas-
truct.fem.system.SystemElements method),
25
solve() (anastruct.fem.system.SystemElements method),
28
solve() (anastruct.fem.util.load.LoadCombination
method), 36
SystemElements (class in anastruct.fem.system), 3
58 Index