Quick start

Loading the library

To use sajou simply import the library as you would usually do:

import sajou as sj

That’s it! After this, you are ready to start building your model.

Building the model

A simple frame structure as described in the figure below will be calculated.

(Source code, png, hires.png, pdf)

_images/quickstart_geom.png

Geometry

To build the model a Model has to be created:

# Initialize a Model instance of a 2D model
m = sj.Model(name='Model 1', dimensionality='2D')

The geometry of the problem can then be defined by means of Node, which is conveniently wrapped in the method Model2D.node() of the class Model:

# add nodes
n1 = m.node(0., 0.)
n2 = m.node(0., 2000.)
n3 = m.node(1500., 2500.)
n4 = m.node(3000., 2000.)
n5 = m.node(3000., 0.)

Beam elements (Beam2D) are created using a method of the class model.Model:

# add segment
b1 = m.beam(node1=n1, node2=n2)
b2 = m.beam(node1=n2, node2=n3)
b3 = m.beam(node1=n3, node2=n4)
b4 = m.beam(node1=n4, node2=n5)

Material and cross-section

For this example, the material consist of a timber glulam, with an modulus of elasticity (MOE) equals to 12 GPa. The cross-section of the beam is defined as a rectangular section.

See also

sections.BeamSection to understand how to pass different parameters

Property value units
MOE 12 GPa
width 100 mm
depth 300 mm

The material is defined by means of the Model.material() method, which creates an instance of the class Material. This is then assigned to a BeamSection instance, using the Model.beam_section() method and giving the parameter type='rectangular':

# create material
mat = m.material(name='glulam', data=(12e3, ), type='isotropic')

# create beam section
section1 = m.beam_section(name='glulam section', material=mat, data=(
    100, 300), type='rectangular')

The above created BeamSection now needs to be assigned to a Beam2D instance:

# add beam section to the beams
b1.assign_section(section1)
b2.assign_section(section1)
b3.assign_section(section1)
b4.assign_section(section1)

Applying loads and border conditions

Sajou supports the application of both concentrated loads as well as distributed loads. For this, the methods Model.load() and Beam2D.distributed_load() are used. The border conditions (BCs) are defined with the method Model.bc():

# Add border conditions
m.bc(node=n1, v1=0., v2=0.)
m.bc(node=n5, v1=0., v2=0.)

# Add load
m.load(node=n3, f2=-10e3)

# Distributed load
b1.distributed_load(p1=-1, p2=-2, direction='y', coord_system='local')
b2.distributed_load(p1=-1, direction='y', coord_system='global')
b3.distributed_load(p1=-1, direction='y', coord_system='global')

See also

Concentrated and distributed moments are also supported. See the methods Model.load() and Beam2D.distributed_moment()

End release (adding a hinge)

It is also possible to add hinges at a given node, by means of the Beam2D.release_end() method. This method adds an additional degree of freedom at the respective node, effectively uncoupling the rotation from the rest of the system:

# release end
b2.release_end(which=2)

Visualizing the model

A visual inspection of the model is crucial to easily spot problems in the model. To see the current state of the model a Display instance has to be instantiated and a Matplotlib axis has to be passed (this might change in the future):

import matplotlib.pyplot as plt
fig = plt.figure(figsize=(6., 5.5))
ax = fig.add_subplot(111)
disp = sj.Display(theme='dark')
ax = disp.plot_geometry(ax=ax, model=m)
plt.show()

A figure similar to the one shown below should be created.

(Source code, png, hires.png, pdf)

_images/quickstart_loads.png

Solving the system

For this example, the implemented static solver (StaticSolver) is used:

from sajou.solvers import StaticSolver
# Define output variables
output = ['nodal displacements', 'internal forces', 'end forces']
# Create the StaticSolver instance
solver = StaticSolver(model=m, output=output)
# Solve the system
res = solver.solve()

After this, a Result object is created (stored as res in the example), which contains the required results of the system.

Postprocessing

The previously obtained Result object is then used in the post-processing of the model. This is done by means of a Postprocess object, which defines several methods to obtain values of section forces in a specified element and to plot the results using the above mentioned Display class.

Let us begin by extracting values o the moment, shear and axial force along a specified beam (say beam No. 2):

# Postprocess the results
post = sj.Postprocess(result=res)
# get the values at the center of the beam
m_0 = post.calc_moment_at(pos=0.5, element=b2, unit_length=True)
s_0 = post.calc_shear_at(pos=0.5, element=b2, unit_length=True)
a_0 = post.calc_axial_at(pos=0.5, element=b2, unit_length=True)

As can be seen in the code above, the option unit_length is set to True, which indicates that the values given for the pos parameter must be in the range [0, 1].

Note

The pos parameter of the calc_moment_at() also accept an array-like argument, so that the result can be obtained at different points over the beam element at once. This also holds for the calc_shear_at() and calc_axial_at() methods.

Finally, nice plots can be obtained for the different section forces (moment, shear and axial force):

# create the matplotlib figures
fig1 = plt.figure(figsize=(6.5, 5.5))
fig2 = plt.figure(figsize=(6.5, 5.5))
fig3 = plt.figure(figsize=(6.5, 5.5))
fig4 = plt.figure(figsize=(6.5, 5.5))

ax1 = fig1.add_subplot(111)
ax2 = fig2.add_subplot(111)
ax3 = fig3.add_subplot(111)
ax4 = fig4.add_subplot(111)

# plot the moment along the frame elements
ax1 = disp.plot_internal_forces(ax=ax1, result=res, component='moment')
# plot the shear force the frame elements
ax2 = disp.plot_internal_forces(ax=ax2, result=res, component='shear')
# plot the axial force along the frame elements
ax3 = disp.plot_internal_forces(ax=ax3, result=res, component='axial')
# plot the deformed shape of the structure
ax4 = disp.plot_deformed_geometry(ax=ax4, result=res, show_undeformed=True,
                                scale=500)

(Source code)