How to Use Block2D

Although the mesh commands outlined in previous posts (here and here) are more powerful, the block2D and block3D commands remain useful, especially if you want to use quadrilateral or brick elements.

Ed C++ Love based the OpenSees block commands on the meshing functionality in FEAP. So, if you are familiar with FEAP, these commands should look familiar. This post will focus on block2D.

The basic idea is to define corner points for the block, then the command creates nodes and elements from the user-specified number of elements in the block. The command takes element specific arguments that are passed into each element the block creates. For example, to create a 10×6 mesh of quad elements with node and element tags each starting at 1, use the following code.

import openseespy.opensees as ops

L = 20
b = 10
t = 1.0

E = 29000.0
v = 0.3

ops.wipe()
ops.model('basic','-ndm',2,'-ndf',2)

ops.nDMaterial('ElasticIsotropic',1,E,v)

eleArgs = [t,'PlaneStress',1]
points = [1,0,0,
          2,L,0,
          3,L,b,
          4,0,b]
ops.block2D(10,6,1,1,'quad',*eleArgs,*points)

This produces the model shown below (plotted using opsvis) with 77 nodes and 60 elements.

You can also define curved meshes by supplying edge points 5-8 and/or point 9 in the block2D command. The wiki page has a good explanation of points 5 through 9.

# Points 5 and 6 to curve edge 1-2 and 2-3, respectively
points = [1,0,0,
          2,L,0,
          3,L,b,
          4,0,b,
          5,L/2,-2,
          6,L+4,b-4]
ops.block2D(10,6,1,1,'quad',*eleArgs,*points)

# Point 9 to curve the interior mesh
points = [1,0,0,
          2,L,0,
          3,L,b,
          4,0,b,
          9,L/2-2,b-6]
ops.block2D(10,6,1,1,'quad',*eleArgs,*points)

The above meshes show general features, but usually you will define regular meshes in layers using multiple calls to the block2D command. In this case, you need to ensure you pass starting node and element tags that will not cause a conflict. Instead of a magic number, pass in one more than the largest tag already defined.

points = [1,0,0,
          2,L,0,
          3,L,b/2,
          4,0,b/2]
ops.block2D(10,2,1,1,'quad',*eleArgs,*points)

eleStart = max(ops.getEleTags()) + 1
nodeStart = max(ops.getNodeTags()) + 1
points = [1,0,b/2,
          2,L,b/2,
          3,L,b,
          4,0,b]
ops.block2D(10,2,nodeStart,eleStart,'quad',*eleArgs,*points)

# fix along X=0
ops.fixX(0,1,1)

Notice in the above mesh there are collocated nodes along the mesh boundary. Without further model adjustments, applying a load, e.g., at the free end, leads to an incompatible solution.

The nodes along the block interface must be joined. Unlike FEAP, there is no tie command in OpenSees–you have to do it yourself.

Below is generic Python code to perform the tie operation with a tolerance on the internodal distance. The first if-statement in the inner loop ensures we don’t tie a node to itself and that we don’t tie nodes to each other twice.

import numpy as np

for ndI in ops.getNodeTags():
    XYZI = np.array(ops.nodeCoord(ndI))
    for ndJ in ops.getNodeTags():
        if ndI <= ndJ:
            continue
        XYZJ = np.array(ops.nodeCoord(ndJ))
        if np.linalg.norm(XYZJ-XYZI) < 1e-8:
            ops.equalDOF(ndI,ndJ,1,2)

Note that this code will work for any model, but adjust the equalDOF command accordingly.

For this model, the resulting solution with tied blocks is shown below. Much better!

I’ll do a separate post on block3D.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.