import openseespy.opensees as ops
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.tri as tri
from .settings import *
from . import defo as opsvdefo
def extrapolate_ip_to_node_quad(yip):
"""
Exprapolate values from 4 integration points to 4 nodes of a quad element.
Integration points of Gauss quadrature.
Usefull for : stress and strain components (sxx, syy, sxy)
yip - either a single vector (4,) or array (4,3) /sxx syy sxy/
or array (4, n)
"""
xep = 0.8660254037844386
W = np.array([[1. + xep, -1 / 2., 1. - xep, -1 / 2.],
[-1 / 2., 1. + xep, -1 / 2., 1. - xep],
[1. - xep, -1 / 2., 1. + xep, -1 / 2.],
[-1 / 2., 1. - xep, -1 / 2., 1. + xep]])
ynp = W @ yip
return ynp
def extrapolate_ip_to_node_quad8n(yip):
"""
Exprapolate values from 8 integration points to 8 nodes of a quad element.
Integration points of Gauss quadrature.
Usefull for : stress and strain components (sxx, syy, sxy)
yip - either a single vector (4,) or array (4,3) /sxx syy sxy/
or array (4, n)
"""
W = np.array([[2.0758287072798374, 0.1666666666666666, -0.075828707279838, 0.1666666666666666, -0.7636648162452683, 0.0969981495786018, 0.0969981495786018, -0.7636648162452683, 0.], # noqa: E501
[0.1666666666666666, 2.0758287072798374, 0.1666666666666666, -0.075828707279838, -0.7636648162452683, -0.7636648162452683, 0.0969981495786018, 0.0969981495786018, 0.], # noqa: E501
[-0.075828707279838, 0.1666666666666666, 2.0758287072798374, 0.1666666666666666, 0.0969981495786018, -0.7636648162452683, -0.7636648162452683, 0.0969981495786018, 0.], # noqa: E501
[0.1666666666666666, -0.075828707279838, 0.1666666666666666, 2.0758287072798374, 0.0969981495786018, 0.0969981495786018, -0.7636648162452683, -0.7636648162452683, 0.], # noqa: E501
[0.1666666666666666, 0.1666666666666666, 0.1666666666666666, 0.1666666666666666, 1.1454972243679027, -0.3333333333333333, -0.1454972243679028, -0.3333333333333333, 0.], # noqa: E501
[0.1666666666666666, 0.1666666666666666, 0.1666666666666666, 0.1666666666666666, -0.3333333333333333, 1.1454972243679027, -0.3333333333333333, -0.1454972243679028, 0.], # noqa: E501
[0.1666666666666666, 0.1666666666666666, 0.1666666666666666, 0.1666666666666666, -0.1454972243679028, -0.3333333333333333, 1.1454972243679027, -0.3333333333333333, 0.], # noqa: E501
[0.1666666666666666, 0.1666666666666666, 0.1666666666666666, 0.1666666666666666, -0.3333333333333333, -0.1454972243679028, -0.3333333333333333, 1.1454972243679027, 0.]]) # noqa: E501
ynp = W @ yip
return ynp
def extrapolate_ip_to_node_quad9n(yip):
"""
Exprapolate values at 9 integration points to 9 nodes of a quad element.
Integration points of Gauss quadrature.
Usefull for : stress components (sxx, syy, sxy)
yip - either a single vector (4,) or array (4,3) /sxx syy sxy/
or array (4, n)
"""
W = np.array([[2.1869398183909485, 0.2777777777777778, 0.0352824038312731, 0.2777777777777778, -0.9858870384674904, -0.1252240726436203, -0.1252240726436203, -0.9858870384674904, 0.4444444444444444], # noqa: E501
[0.2777777777777778, 2.1869398183909485, 0.2777777777777778, 0.0352824038312731, -0.9858870384674904, -0.9858870384674904, -0.1252240726436203, -0.1252240726436203, 0.4444444444444444], # noqa: E501
[0.0352824038312731, 0.2777777777777778, 2.1869398183909485, 0.2777777777777778, -0.1252240726436203, -0.9858870384674904, -0.9858870384674904, -0.1252240726436203, 0.4444444444444444], # noqa: E501
[0.2777777777777778, 0.0352824038312731, 0.2777777777777778, 2.1869398183909485, -0.1252240726436203, -0.1252240726436203, -0.9858870384674904, -0.9858870384674904, 0.4444444444444444], # noqa: E501
[0., 0., 0., 0., 1.4788305577012359, 0., 0.1878361089654305, 0., -0.6666666666666667], # noqa: E501
[0., 0., 0., 0., 0., 1.4788305577012359, 0., 0.1878361089654305, -0.6666666666666667], # noqa: E501
[0., 0., 0., 0., 0.1878361089654305, 0., 1.4788305577012359, 0., -0.6666666666666667], # noqa: E501
[0., 0., 0., 0., 0., 0.1878361089654305, 0., 1.4788305577012359, -0.6666666666666667], # noqa: E501
[0., 0., 0., 0., 0., 0., 0., 0., 1.]])
ynp = W @ yip
return ynp
def extrapolate_ip_to_node_tri6n(yip):
"""Exprapolate from 3 integration points to 6 nodes of a tri6n element.
The integration points are at (2/3, 1/6), (1/6, 2/3), (1/6, 1/6).
Other possible 3 Gauss points are (1/2, 1/2), (1/2, 0), (0, 1/2).
Integration points of Gauss quadrature.
Usefull for : stress components (sxx, syy, sxy)
yip - either a single vector (6,) or array (6,3) /sxx syy sxy/
or array (6, n)
"""
W = np.array([[1.6666666666666667, -0.3333333333333333, -0.3333333333333333], # noqa: E501
[-0.3333333333333333, 1.6666666666666667, -0.3333333333333333], # noqa: E501
[-0.3333333333333333, -0.3333333333333333, 1.6666666666666667], # noqa: E501
[0.6666666666666667, 0.6666666666666667, -0.3333333333333333], # noqa: E501
[-0.3333333333333333, 0.6666666666666667, 0.6666666666666667], # noqa: E501
[0.6666666666666667, -0.3333333333333333, 0.6666666666666667]]) # noqa: E501
ynp = W @ yip
return ynp
def ele_tags_stress_related(ele_tags):
EleClasstagsForStress = set([EleClassTag.tri3n,
EleClassTag.tri6n,
EleClassTag.quad4n,
EleClassTag.quad8n,
EleClassTag.quad9n,
EleClassTag.ShellMITC4,
EleClassTag.ShellMITC9,
EleClassTag.ASDShellQ4,
EleClassTag.FourNodeTetrahedron,
EleClassTag.TenNodeTetrahedron,
EleClassTag.TenNodeTetrahedronSK,
EleClassTag.brick8n,
EleClassTag.brick20n])
ele_classtags = ops.getEleClassTags()
idx = [i for i, e in enumerate(ele_classtags) if e in EleClasstagsForStress]
ele_tags_for_stress = [ele_tags[i] for i in idx]
return ele_tags_for_stress
[docs]
def sig_out_per_node(how_many='all'):
"""Return a 2d numpy array of stress components per OpenSees node.
Three first stress components (sxx, syy, sxy) are calculated and
extracted from OpenSees, while the rest svm (Huber-Mieses-Hencky),
two principal stresses (s1, s2) and directional angle are calculated
as postprocessed quantities.
Args:
how_many (str): supported options are: 'all' - all components,
'sxx', 'syy', 'sxy', 'svm' (or 'vmis'), 's1', 's2', 'angle'.
Returns:
sig_out (ndarray): a 2d array of stress components per node with
the following components: sxx, syy, sxy, svm, s1, s2, angle.
Size (n_nodes x 7).
Examples:
sig_out = opsv.sig_out_per_node()
Notes:
s1, s2: principal stresses
angle: angle of the principal stress s1
"""
ele_tags = ops.getEleTags()
node_tags = ops.getNodeTags()
n_nodes = len(node_tags)
ele_classtag = ops.getEleClassTags(ele_tags[0])[0]
# initialize helper arrays
sig_out = np.zeros((n_nodes, 7))
nodes_tag_count = np.zeros((n_nodes, 2), dtype=int)
nodes_tag_count[:, 0] = node_tags
nen = np.shape(ops.eleNodes(ele_tags[0]))[0]
for i, ele_tag in enumerate(ele_tags):
ele_node_tags = ops.eleNodes(ele_tag)
tmp_list = [0]*nen
for j, ele_node_tag in enumerate(ele_node_tags):
tmp_list[j] = node_tags.index(ele_node_tag)
nodes_tag_count[tmp_list, 1] += 1
if ele_classtag == EleClassTag.SSPquad:
sig_ip_el = ops.eleResponse(ele_tag, 'stress')
# sigM_nd = sigM_ip
sigM_np = np.tile(sig_ip_el, (nen, 1))
else:
sig_nd_el = ops.eleResponse(ele_tag, 'stressAtNodes')
sigM_nd = np.reshape(sig_nd_el, (-1, 3))
# sxx yy xy components
sig_out[tmp_list, 0] += sigM_nd[:nen, 0]
sig_out[tmp_list, 1] += sigM_nd[:nen, 1]
sig_out[tmp_list, 2] += sigM_nd[:nen, 2]
indxs, = np.where(nodes_tag_count[:, 1] > 1)
# n_indxs < n_nodes: e.g. 21<25 (bous), 2<6 (2el) etc.
n_indxs = np.shape(indxs)[0]
# divide summed stresses by the number of common nodes
sig_out[indxs, :] = \
sig_out[indxs, :]/nodes_tag_count[indxs, 1].reshape(n_indxs, 1)
if how_many == 'all' or how_many == 'svm' or how_many == 'vmis':
# warning reshape from (pts,ncomp) to (ncomp,pts)
vm_out = vm_stress(np.transpose(sig_out[:, :3]))
sig_out[:, 3] = vm_out
if (how_many == 'all' or how_many == 's1' or how_many == 's2' or how_many == 'angle'): # noqa: E501
princ_sig_out = princ_stress(np.transpose(sig_out[:, :3]))
sig_out[:, 4:7] = np.transpose(princ_sig_out)
print('-- WARNING!!! full sig_out matrix calculated here --')
return sig_out
def sig_component_per_node(stress_str, nu):
"""Return a 2d numpy array of stress components per node.
Three first stress components (sxx, syy, sxy) are calculated and
extracted from OpenSees, while the rest svm (Huber-Mieses-Hencky),
two principal stresses (s1, s2) and directional angle are calculated
as postprocessed quantities.
Args:
how_many (str): supported options are: 'all' - all components,
'sxx', 'syy', 'sxy', 'svm' (or 'vmis'), 's1', 's2', 'angle'.
Returns:
sig_out (ndarray): a 2d array of stress components per node with
the following components: sxx, syy, sxy, svm, s1, s2, angle.
Size (n_nodes x 7).
Examples:
sig_out = opsv.sig_out_per_node()
Notes:
s1, s2: principal stresses
angle: angle of the principal stress s1
"""
ele_tags_all = ops.getEleTags()
ele_tags = ele_tags_stress_related(ele_tags_all)
ele_classtag = ops.getEleClassTags(ele_tags[0])[0]
node_tags = ops.getNodeTags()
n_nodes = len(node_tags)
sig_out = np.zeros((n_nodes, 4))
nodes_tag_count = np.zeros((n_nodes, 2), dtype=int)
nodes_tag_count[:, 0] = node_tags
nen = np.shape(ops.eleNodes(ele_tags[0]))[0]
for i, ele_tag in enumerate(ele_tags):
ele_node_tags = ops.eleNodes(ele_tag)
tmp_list = [0]*nen
for j, ele_node_tag in enumerate(ele_node_tags):
tmp_list[j] = node_tags.index(ele_node_tag)
nodes_tag_count[tmp_list, 1] += 1
if ele_classtag == EleClassTag.SSPquad:
sig_ip_el = ops.eleResponse(ele_tag, 'stress')
sigM_np = np.tile(sig_ip_el, (nen, 1))
else:
sig_nd_el = ops.eleResponse(ele_tag, 'stressAtNodes')
sigM_nd = np.reshape(sig_nd_el, (-1, 3))
# sxx yy xy components
sig_out[tmp_list, 0] += sigM_nd[:nen, 0]
sig_out[tmp_list, 1] += sigM_nd[:nen, 1]
sig_out[tmp_list, 2] += sigM_nd[:nen, 2]
indxs, = np.where(nodes_tag_count[:, 1] > 1)
n_indxs = np.shape(indxs)[0]
sig_out[indxs, :] = \
sig_out[indxs, :] / nodes_tag_count[indxs, 1].reshape(n_indxs, 1)
if stress_str == 'sxx':
sig_out_vec = sig_out[:, 0]
elif stress_str == 'syy':
sig_out_vec = sig_out[:, 1]
elif stress_str == 'sxy':
sig_out_vec = sig_out[:, 2]
elif stress_str == 'szz':
sig_out_vec = nu * (sig_out[:, 0] + sig_out[:, 1])
elif stress_str == 'svm' or stress_str == 'vmis':
sig_out_vec = vm_stress(np.transpose(sig_out[:, :3]))
elif (stress_str == 's1' or stress_str == 's2' or stress_str == 'angle'):
princ_sig_out = princ_stress(np.transpose(sig_out[:, :3]))
if stress_str == 's1':
sig_out_vec = princ_sig_out[0, :]
elif stress_str == 's2':
sig_out_vec = princ_sig_out[1, :]
elif stress_str == 'angle':
sig_out_vec = princ_sig_out[2, :]
return sig_out_vec
def eps_component_per_node(strain_str, nu):
"""Return a 2d numpy array of strain components per node.
Strain components (exx, eyy, exy) are extracted from OpenSees.
Args:
how_many (str): supported options are: 'all' - all components,
'exx', 'eyy', 'exy', 'ezz'.
Returns:
eps_out (ndarray): a 2d array of strain components per node with
the following components: exx, eyy, exy, szz.
Size (n_nodes x 4).
"""
ele_tags_all = ops.getEleTags()
ele_tags = ele_tags_stress_related(ele_tags_all)
ele_classtag = ops.getEleClassTags(ele_tags[0])[0]
node_tags = ops.getNodeTags()
n_nodes = len(node_tags)
eps_out = np.zeros((n_nodes, 4))
nodes_tag_count = np.zeros((n_nodes, 2), dtype=int)
nodes_tag_count[:, 0] = node_tags
nen = np.shape(ops.eleNodes(ele_tags[0]))[0]
for i, ele_tag in enumerate(ele_tags):
ele_node_tags = ops.eleNodes(ele_tag)
tmp_list = [0]*nen
for j, ele_node_tag in enumerate(ele_node_tags):
tmp_list[j] = node_tags.index(ele_node_tag)
nodes_tag_count[tmp_list, 1] += 1
if ele_classtag == EleClassTag.quad4n:
eps_ip_el = ops.eleResponse(ele_tag, 'strain')
epsM_ip = np.reshape(eps_ip_el, (-1, 3))
epsM_np = extrapolate_ip_to_node_quad(epsM_ip)
elif ele_classtag == EleClassTag.quad8n:
eps_ip_el = ops.eleResponse(ele_tag, 'strain')
epsM_ip = np.reshape(eps_ip_el, (-1, 3))
epsM_np = extrapolate_ip_to_node_quad8n(epsM_ip)
elif ele_classtag == EleClassTag.quad9n:
eps_ip_el = ops.eleResponse(ele_tag, 'strain')
epsM_ip = np.reshape(eps_ip_el, (-1, 3))
epsM_np = extrapolate_ip_to_node_quad9n(epsM_ip)
elif ele_classtag == EleClassTag.tri3n:
eps_ip_el = ops.eleResponse(ele_tag, 'strain')
epsM_np = np.tile(eps_ip_el, (nen, 1))
elif ele_classtag == EleClassTag.tri6n:
eps_ip_el = ops.eleResponse(ele_tag, 'strain')
epsM_ip = np.reshape(eps_ip_el, (-1, 3))
epsM_np = extrapolate_ip_to_node_tri6n(epsM_ip)
elif ele_classtag == EleClassTag.SSPquad:
eps_ip_el = ops.eleResponse(ele_tag, 'strain')
epsM_np = np.tile(eps_ip_el, (nen, 1))
# exx eyy exy components
eps_out[tmp_list, 0] += epsM_np[:nen, 0]
eps_out[tmp_list, 1] += epsM_np[:nen, 1]
eps_out[tmp_list, 2] += epsM_np[:nen, 2]
indxs, = np.where(nodes_tag_count[:, 1] > 1)
n_indxs = np.shape(indxs)[0]
eps_out[indxs, :] = \
eps_out[indxs, :] / nodes_tag_count[indxs, 1].reshape(n_indxs, 1)
if strain_str == 'exx':
eps_out_vec = eps_out[:, 0]
elif strain_str == 'eyy':
eps_out_vec = eps_out[:, 1]
elif strain_str == 'exy':
eps_out_vec = eps_out[:, 2]
elif strain_str == 'ezz':
eps_out_vec = - (nu / (1 - nu)) * (eps_out[:, 0] + eps_out[:, 1])
return eps_out_vec
def princ_stress(sig):
"""Return a tuple (s1, s2, angle): principal stresses (plane stress) and angle
Args:
sig (ndarray): input array of stresses at nodes: sxx, syy, sxy (tau)
Returns:
out (ndarray): 1st row is first principal stress s1, 2nd row is second
principal stress s2, 3rd row is the angle of s1
"""
sx, sy, tau = sig[0], sig[1], sig[2]
ds = (sx-sy)/2
R = np.sqrt(ds**2 + tau**2)
s1 = (sx+sy)/2. + R
s2 = (sx+sy)/2. - R
angle = np.arctan2(tau, ds)/2
out = np.vstack((s1, s2, angle))
return out
def vm_stress(sig):
n_sig_comp, n_pts = np.shape(sig)
if n_sig_comp > 3:
x, y, z, xy, xz, yz = sig
else:
x, y, xy = sig
z, xz, yz = 0., 0., 0.
_a = 0.5*((x-y)**2 + (y-z)**2 + (z-x)**2 + 6.*(xy**2 + xz**2 + yz**2))
return np.sqrt(_a)
def quads_to_4tris(quads_conn, nds_crd, nds_val, disps=None):
"""
Get triangles connectivity, coordinates and new values at quad centroids.
Args:
quads_conn (ndarray):
nds_crd (ndarray):
nds_val (ndarray):
Returns:
tris_conn, nds_c_crd, nds_c_val (tuple):
Notes:
Triangles connectivity array is based on
quadrilaterals connectivity.
Each quad is split into four triangles.
New nodes are created at the quad centroid.
See also:
function: quads_to_8tris_9n, quads_to_8tris_8n
"""
n_quads, _ = quads_conn.shape
n_nds, ndm = nds_crd.shape
# coordinates and values at quad centroids _c_
nds_c_crd = np.zeros((n_quads, 2))
nds_c_val = np.zeros(n_quads)
disps_c = None # for pyvista on maps on deformed model
if disps is not None:
disps_c = np.zeros((n_quads, ndm))
tris_conn = np.zeros((4*n_quads, 3), dtype=int)
for i, quad_conn in enumerate(quads_conn):
j = 4*i
n0, n1, n2, n3 = quad_conn
# quad centroids
nds_c_crd[i] = np.array([np.sum(nds_crd[[n0, n1, n2, n3], 0])/4.,
np.sum(nds_crd[[n0, n1, n2, n3], 1])/4.])
nds_c_val[i] = np.sum(nds_val[[n0, n1, n2, n3]])/4.
# triangles connectivity
tris_conn[j] = np.array([n0, n1, n_nds+i])
tris_conn[j+1] = np.array([n1, n2, n_nds+i])
tris_conn[j+2] = np.array([n2, n3, n_nds+i])
tris_conn[j+3] = np.array([n3, n0, n_nds+i])
if disps is not None:
disps_c[i] = np.sum(disps[[n0, n1, n2, n3]], axis=0) / 4.
return tris_conn, nds_c_crd, nds_c_val, disps_c
def bricks_to_24tris(bricks_conn, nds_crd, nds_val, disps=None):
"""
Get triangles connectivity, coordinates and new vals at brick face centroids.
Args:
bricks_conn (ndarray):
nds_crd (ndarray):
nds_val (ndarray):
Returns:
tris_conn, nds_c_crd, nds_c_val (tuple):
Notes:
Triangles connectivity array is based on
stdBricks connectivity.
Each of 6 brick faces is split into four triangles.
New nodes are created at the face centroid.
See also:
function: bricks_to_8tris_9n, bricks_to_8tris_8n
"""
n_bricks, _ = bricks_conn.shape
n_nds, _ = nds_crd.shape
# coordinates and values at brick centroids _c_
nds_c_crd = np.zeros((n_bricks*6, 3))
nds_c_val = np.zeros(n_bricks*6)
disps_c = None
if disps is not None:
disps_c = np.zeros((n_bricks*6, 3))
tris_conn = np.zeros((24*n_bricks, 3), dtype=int)
for i, brick_conn in enumerate(bricks_conn):
j = 24*i
n0, n1, n2, n3, n4, n5, n6, n7 = brick_conn
# brick centroids
nds_c_crd[i*6] = np.array([np.sum(nds_crd[[n0, n1, n5, n4], 0])/4.,
np.sum(nds_crd[[n0, n1, n5, n4], 1])/4.,
np.sum(nds_crd[[n0, n1, n5, n5], 2])/4.])
nds_c_crd[i*6+1] = np.array([np.sum(nds_crd[[n1, n2, n6, n5], 0])/4.,
np.sum(nds_crd[[n1, n2, n6, n5], 1])/4.,
np.sum(nds_crd[[n1, n2, n6, n5], 2])/4.])
nds_c_crd[i*6+2] = np.array([np.sum(nds_crd[[n2, n3, n7, n6], 0])/4.,
np.sum(nds_crd[[n2, n3, n7, n6], 1])/4.,
np.sum(nds_crd[[n2, n3, n7, n6], 2])/4.])
nds_c_crd[i*6+3] = np.array([np.sum(nds_crd[[n3, n0, n4, n7], 0])/4.,
np.sum(nds_crd[[n3, n0, n4, n7], 1])/4.,
np.sum(nds_crd[[n3, n0, n4, n7], 2])/4.])
nds_c_crd[i*6+4] = np.array([np.sum(nds_crd[[n4, n5, n6, n7], 0])/4.,
np.sum(nds_crd[[n4, n5, n6, n7], 1])/4.,
np.sum(nds_crd[[n4, n5, n6, n7], 2])/4.])
nds_c_crd[i*6+5] = np.array([np.sum(nds_crd[[n0, n1, n2, n3], 0])/4.,
np.sum(nds_crd[[n0, n1, n2, n3], 1])/4.,
np.sum(nds_crd[[n0, n1, n2, n3], 2])/4.])
nds_c_val[6*i] = np.sum(nds_val[[n0, n1, n5, n4]])/4.
nds_c_val[6*i+1] = np.sum(nds_val[[n1, n2, n6, n5]])/4.
nds_c_val[6*i+2] = np.sum(nds_val[[n2, n3, n7, n6]])/4.
nds_c_val[6*i+3] = np.sum(nds_val[[n3, n0, n4, n7]])/4.
nds_c_val[6*i+4] = np.sum(nds_val[[n4, n5, n6, n7]])/4.
nds_c_val[6*i+5] = np.sum(nds_val[[n0, n1, n2, n3]])/4.
# triangles connectivity
tris_conn[j] = np.array([n0, n1, n_nds+i*6])
tris_conn[j+1] = np.array([n1, n5, n_nds+i*6])
tris_conn[j+2] = np.array([n5, n4, n_nds+i*6])
tris_conn[j+3] = np.array([n4, n0, n_nds+i*6])
tris_conn[j+4] = np.array([n1, n2, n_nds+i*6+1])
tris_conn[j+5] = np.array([n2, n6, n_nds+i*6+1])
tris_conn[j+6] = np.array([n6, n5, n_nds+i*6+1])
tris_conn[j+7] = np.array([n5, n1, n_nds+i*6+1])
tris_conn[j+8] = np.array([n2, n3, n_nds+i*6+2])
tris_conn[j+9] = np.array([n3, n7, n_nds+i*6+2])
tris_conn[j+10] = np.array([n7, n6, n_nds+i*6+2])
tris_conn[j+11] = np.array([n6, n2, n_nds+i*6+2])
tris_conn[j+12] = np.array([n3, n0, n_nds+i*6+3])
tris_conn[j+13] = np.array([n0, n4, n_nds+i*6+3])
tris_conn[j+14] = np.array([n4, n7, n_nds+i*6+3])
tris_conn[j+15] = np.array([n7, n3, n_nds+i*6+3])
tris_conn[j+16] = np.array([n4, n5, n_nds+i*6+4])
tris_conn[j+17] = np.array([n5, n6, n_nds+i*6+4])
tris_conn[j+18] = np.array([n6, n7, n_nds+i*6+4])
tris_conn[j+19] = np.array([n7, n4, n_nds+i*6+4])
tris_conn[j+20] = np.array([n0, n1, n_nds+i*6+5])
tris_conn[j+21] = np.array([n1, n2, n_nds+i*6+5])
tris_conn[j+22] = np.array([n2, n3, n_nds+i*6+5])
tris_conn[j+23] = np.array([n3, n0, n_nds+i*6+5])
if disps is not None:
disps_c[6*i] = np.sum(disps[[n0, n1, n5, n4]], axis=0)/4.
disps_c[6*i+1] = np.sum(disps[[n1, n2, n6, n5]], axis=0)/4.
disps_c[6*i+2] = np.sum(disps[[n2, n3, n7, n6]], axis=0)/4.
disps_c[6*i+3] = np.sum(disps[[n3, n0, n4, n7]], axis=0)/4.
disps_c[6*i+4] = np.sum(disps[[n4, n5, n6, n7]], axis=0)/4.
disps_c[6*i+5] = np.sum(disps[[n0, n1, n2, n3]], axis=0)/4.
return tris_conn, nds_c_crd, nds_c_val, disps_c
# brick20n bricks to tris
def bricks_to_48tris(bricks_conn, nds_crd, nds_val, disps=None):
"""
Get triangles connectivity, coordinates and new vals at brick face centroids,
for brick20n
Args:
bricks_conn (ndarray):
nds_crd (ndarray):
nds_val (ndarray):
Returns:
tris_conn, nds_c_crd, nds_c_val (tuple):
Notes:
Triangles connectivity array is based on
stdBricks connectivity.
Each of 6 brick faces is split into four triangles.
New nodes are created at the face centroid.
See also:
function: bricks_to_24tris
"""
n_bricks, _ = bricks_conn.shape
n_nds, _ = nds_crd.shape
# coordinates and values at brick centroids _c_
nds_c_crd = np.zeros((n_bricks*6, 3))
nds_c_val = np.zeros(n_bricks*6)
disps_c = None
if disps is not None:
disps_c = np.zeros((n_bricks*6, 3))
tris_conn = np.zeros((48*n_bricks, 3), dtype=int)
for i, brick_conn in enumerate(bricks_conn):
j = 48*i
n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, \
n14, n15, n16, n17, n18, n19 = brick_conn
# brick centroids
nds_c_crd[i*6] = np.array([np.sum(nds_crd[[n0, n1, n5, n4], 0])/4.,
np.sum(nds_crd[[n0, n1, n5, n4], 1])/4.,
np.sum(nds_crd[[n0, n1, n5, n5], 2])/4.])
nds_c_crd[i*6+1] = np.array([np.sum(nds_crd[[n1, n2, n6, n5], 0])/4.,
np.sum(nds_crd[[n1, n2, n6, n5], 1])/4.,
np.sum(nds_crd[[n1, n2, n6, n5], 2])/4.])
nds_c_crd[i*6+2] = np.array([np.sum(nds_crd[[n2, n3, n7, n6], 0])/4.,
np.sum(nds_crd[[n2, n3, n7, n6], 1])/4.,
np.sum(nds_crd[[n2, n3, n7, n6], 2])/4.])
nds_c_crd[i*6+3] = np.array([np.sum(nds_crd[[n3, n0, n4, n7], 0])/4.,
np.sum(nds_crd[[n3, n0, n4, n7], 1])/4.,
np.sum(nds_crd[[n3, n0, n4, n7], 2])/4.])
nds_c_crd[i*6+4] = np.array([np.sum(nds_crd[[n4, n5, n6, n7], 0])/4.,
np.sum(nds_crd[[n4, n5, n6, n7], 1])/4.,
np.sum(nds_crd[[n4, n5, n6, n7], 2])/4.])
nds_c_crd[i*6+5] = np.array([np.sum(nds_crd[[n0, n1, n2, n3], 0])/4.,
np.sum(nds_crd[[n0, n1, n2, n3], 1])/4.,
np.sum(nds_crd[[n0, n1, n2, n3], 2])/4.])
nds_c_val[6*i] = np.sum(nds_val[[n0, n1, n5, n4]])/4.
nds_c_val[6*i+1] = np.sum(nds_val[[n1, n2, n6, n5]])/4.
nds_c_val[6*i+2] = np.sum(nds_val[[n2, n3, n7, n6]])/4.
nds_c_val[6*i+3] = np.sum(nds_val[[n3, n0, n4, n7]])/4.
nds_c_val[6*i+4] = np.sum(nds_val[[n4, n5, n6, n7]])/4.
nds_c_val[6*i+5] = np.sum(nds_val[[n0, n1, n2, n3]])/4.
# triangles connectivity
tris_conn[j] = np.array([n0, n8, n_nds+i*6])
tris_conn[j+1] = np.array([n8, n1, n_nds+i*6])
tris_conn[j+2] = np.array([n1, n17, n_nds+i*6])
tris_conn[j+3] = np.array([n17, n5, n_nds+i*6])
tris_conn[j+4] = np.array([n5, n12, n_nds+i*6])
tris_conn[j+5] = np.array([n12, n4, n_nds+i*6])
tris_conn[j+6] = np.array([n4, n16, n_nds+i*6])
tris_conn[j+7] = np.array([n16, n0, n_nds+i*6])
tris_conn[j+8] = np.array([n1, n9, n_nds+i*6+1])
tris_conn[j+9] = np.array([n9, n2, n_nds+i*6+1])
tris_conn[j+10] = np.array([n2, n18, n_nds+i*6+1])
tris_conn[j+11] = np.array([n18, n6, n_nds+i*6+1])
tris_conn[j+12] = np.array([n6, n13, n_nds+i*6+1])
tris_conn[j+13] = np.array([n13, n5, n_nds+i*6+1])
tris_conn[j+14] = np.array([n5, n17, n_nds+i*6+1])
tris_conn[j+15] = np.array([n17, n1, n_nds+i*6+1])
tris_conn[j+16] = np.array([n2, n10, n_nds+i*6+2])
tris_conn[j+17] = np.array([n10, n3, n_nds+i*6+2])
tris_conn[j+18] = np.array([n3, n19, n_nds+i*6+2])
tris_conn[j+19] = np.array([n19, n7, n_nds+i*6+2])
tris_conn[j+20] = np.array([n7, n14, n_nds+i*6+2])
tris_conn[j+21] = np.array([n14, n6, n_nds+i*6+2])
tris_conn[j+22] = np.array([n6, n18, n_nds+i*6+2])
tris_conn[j+23] = np.array([n18, n2, n_nds+i*6+2])
tris_conn[j+24] = np.array([n3, n11, n_nds+i*6+3])
tris_conn[j+25] = np.array([n11, n0, n_nds+i*6+3])
tris_conn[j+26] = np.array([n0, n16, n_nds+i*6+3])
tris_conn[j+27] = np.array([n16, n4, n_nds+i*6+3])
tris_conn[j+28] = np.array([n4, n15, n_nds+i*6+3])
tris_conn[j+29] = np.array([n15, n7, n_nds+i*6+3])
tris_conn[j+30] = np.array([n7, n19, n_nds+i*6+3])
tris_conn[j+31] = np.array([n19, n3, n_nds+i*6+3])
tris_conn[j+32] = np.array([n4, n12, n_nds+i*6+4])
tris_conn[j+33] = np.array([n12, n5, n_nds+i*6+4])
tris_conn[j+34] = np.array([n5, n13, n_nds+i*6+4])
tris_conn[j+35] = np.array([n13, n6, n_nds+i*6+4])
tris_conn[j+36] = np.array([n6, n14, n_nds+i*6+4])
tris_conn[j+37] = np.array([n14, n7, n_nds+i*6+4])
tris_conn[j+38] = np.array([n7, n15, n_nds+i*6+4])
tris_conn[j+39] = np.array([n15, n4, n_nds+i*6+4])
tris_conn[j+40] = np.array([n0, n8, n_nds+i*6+5])
tris_conn[j+41] = np.array([n8, n1, n_nds+i*6+5])
tris_conn[j+42] = np.array([n1, n9, n_nds+i*6+5])
tris_conn[j+43] = np.array([n9, n2, n_nds+i*6+5])
tris_conn[j+44] = np.array([n2, n10, n_nds+i*6+5])
tris_conn[j+45] = np.array([n10, n3, n_nds+i*6+5])
tris_conn[j+46] = np.array([n3, n11, n_nds+i*6+5])
tris_conn[j+47] = np.array([n11, n0, n_nds+i*6+5])
if disps is not None:
disps_c[6*i] = np.sum(disps[[n0, n1, n5, n4,
n8, n17, n12, n16]], axis=0)/4.
disps_c[6*i+1] = np.sum(disps[[n1, n2, n6, n5,
n9, n18, n13, n17]], axis=0)/4.
disps_c[6*i+2] = np.sum(disps[[n2, n3, n7, n6,
n10, n19, n14, n18]], axis=0)/4.
disps_c[6*i+3] = np.sum(disps[[n3, n0, n4, n7,
n11, n16, n15, n19]], axis=0)/4.
disps_c[6*i+4] = np.sum(disps[[n4, n5, n6, n7,
n12, n13, n14, n15]], axis=0)/4.
disps_c[6*i+5] = np.sum(disps[[n0, n1, n2, n3,
n8, n9, n10, n11]], axis=0)/4.
return tris_conn, nds_c_crd, nds_c_val, disps_c
def tetra4n_to_4tris(tetras4n_conn):
"""Get triangles connectivity.
Four-node tetrahedron is subdivided into four triangles
Args:
tetra4n_conn (ndarray):
Returns:
tris_conn_subdiv (ndarray):
"""
n_tetras, _ = tetras4n_conn.shape
# n_nds, _ = nds_crd.shape
tris_conn_subdiv = np.zeros((4*n_tetras, 3), dtype=int)
for i, tetra4n_conn in enumerate(tetras4n_conn):
j = 4*i
n0, n1, n2, n3 = tetra4n_conn
# triangles connectivity
tris_conn_subdiv[j] = np.array([n0, n1, n2])
tris_conn_subdiv[j+1] = np.array([n0, n3, n1])
tris_conn_subdiv[j+2] = np.array([n0, n2, n3])
tris_conn_subdiv[j+3] = np.array([n1, n2, n3])
return tris_conn_subdiv
def tetra10n_to_16tris(tetras10n_conn):
"""Get triangles connectivity.
Six-node triangle is subdivided into four triangles
Args:
tetra10n_conn (ndarray):
Returns:
tris_conn_subdiv (ndarray):
"""
n_tetras, _ = tetras10n_conn.shape
# n_nds, _ = nds_crd.shape
tris_conn_subdiv = np.zeros((16*n_tetras, 3), dtype=int)
for i, tetra10n_conn in enumerate(tetras10n_conn):
j = 16*i
n0, n1, n2, n3, n4, n5, n6, n7, n8, n9 = tetra10n_conn
# triangles connectivity
tris_conn_subdiv[j] = np.array([n0, n4, n6])
tris_conn_subdiv[j+1] = np.array([n1, n5, n4])
tris_conn_subdiv[j+2] = np.array([n4, n5, n6])
tris_conn_subdiv[j+3] = np.array([n2, n6, n5])
tris_conn_subdiv[j+4] = np.array([n0, n7, n4])
tris_conn_subdiv[j+5] = np.array([n4, n7, n8])
tris_conn_subdiv[j+6] = np.array([n1, n4, n8])
tris_conn_subdiv[j+7] = np.array([n3, n8, n7])
tris_conn_subdiv[j+8] = np.array([n0, n6, n7])
tris_conn_subdiv[j+9] = np.array([n6, n9, n7])
tris_conn_subdiv[j+10] = np.array([n2, n9, n6])
tris_conn_subdiv[j+11] = np.array([n3, n7, n9])
tris_conn_subdiv[j+12] = np.array([n1, n5, n8])
tris_conn_subdiv[j+13] = np.array([n5, n9, n8])
tris_conn_subdiv[j+14] = np.array([n2, n9, n5])
tris_conn_subdiv[j+15] = np.array([n3, n8, n9])
return tris_conn_subdiv
def tris6n_to_4tris(tris_conn):
"""Get triangles connectivity.
Six-node triangle is subdivided into four triangles
Args:
tris_conn (ndarray):
Returns:
tris_conn_subdiv (ndarray):
"""
n_tris, _ = tris_conn.shape
# n_nds, _ = nds_crd.shape
tris_conn_subdiv = np.zeros((4*n_tris, 3), dtype=int)
for i, tri_conn in enumerate(tris_conn):
j = 4*i
n0, n1, n2, n3, n4, n5 = tri_conn
# triangles connectivity
tris_conn_subdiv[j] = np.array([n0, n3, n5])
tris_conn_subdiv[j+1] = np.array([n3, n1, n4])
tris_conn_subdiv[j+2] = np.array([n3, n4, n5])
tris_conn_subdiv[j+3] = np.array([n5, n4, n2])
return tris_conn_subdiv
# def plot_mesh_2d(nds_crd, eles_conn, lw=0.4, ec='k', ax=False):
def plot_mesh_2d(nds_crd, eles_conn, lw=0.4, ec='k'):
"""
Plot 2d mesh (quads or triangles) outline.
"""
nen = np.shape(eles_conn)[1]
if nen == 3 or nen == 4:
for ele_conn in eles_conn:
x = nds_crd[ele_conn, 0]
y = nds_crd[ele_conn, 1]
plt.fill(x, y, edgecolor=ec, lw=lw, fill=False)
elif nen == 6:
for ele_conn in eles_conn:
x = nds_crd[[ele_conn[0], ele_conn[3], ele_conn[1], ele_conn[4],
ele_conn[2], ele_conn[5]], 0]
y = nds_crd[[ele_conn[0], ele_conn[3], ele_conn[1], ele_conn[4],
ele_conn[2], ele_conn[5]], 1]
plt.fill(x, y, edgecolor=ec, lw=lw, fill=False)
elif nen == 9:
for ele_conn in eles_conn:
x = nds_crd[[ele_conn[0], ele_conn[4], ele_conn[1], ele_conn[5],
ele_conn[2], ele_conn[6], ele_conn[3], ele_conn[7]],
0]
y = nds_crd[[ele_conn[0], ele_conn[4], ele_conn[1], ele_conn[5],
ele_conn[2], ele_conn[6], ele_conn[3], ele_conn[7]],
1]
plt.fill(x, y, edgecolor=ec, lw=lw, fill=False)
elif nen == 8:
for ele_conn in eles_conn:
x = nds_crd[[ele_conn[0], ele_conn[4], ele_conn[1], ele_conn[5],
ele_conn[2], ele_conn[6], ele_conn[3], ele_conn[7]],
0]
y = nds_crd[[ele_conn[0], ele_conn[4], ele_conn[1], ele_conn[5],
ele_conn[2], ele_conn[6], ele_conn[3], ele_conn[7]],
1]
plt.fill(x, y, edgecolor=ec, lw=lw, fill=False)
[docs]
def plot_stress_2d(nds_val, mesh_outline=1, cmap='turbo', levels=50,
fig_wi_he=False, fig_lbrt=False, sfac=False, ax=False):
"""
Plot stress distribution of a 2d elements of a 2d model.
Args:
nds_val (ndarray): the values of a stress component, which can
be extracted from sig_out array (see sig_out_per_node
function)
mesh_outline (int): 1 - mesh is plotted, 0 - no mesh plotted.
cmap (str): Matplotlib color map (default is 'turbo')
Usage:
See demo_quads_4x4.py example.
"""
node_tags, ele_tags_all = ops.getNodeTags(), ops.getEleTags()
ele_tags = ele_tags_stress_related(ele_tags_all)
n_nodes, n_eles = len(node_tags), len(ele_tags)
ele_classtag = ops.getEleClassTags(ele_tags[0])[0]
if (ele_classtag == EleClassTag.tri3n):
nen = 3
elif (ele_classtag == EleClassTag.tri6n):
nen = 6
elif (ele_classtag == EleClassTag.quad4n):
nen = 4
elif (ele_classtag == EleClassTag.quad8n):
nen = 8
elif (ele_classtag == EleClassTag.quad9n):
nen = 9
nds_crd = np.zeros((n_nodes, 2))
nds_uxy = np.zeros((n_nodes, 2))
for i, node_tag in enumerate(node_tags):
nds_crd[i] = ops.nodeCoord(node_tag)
for i, node_tag in enumerate(node_tags):
nds_uxy[i] = ops.nodeDisp(node_tag)[:2]
if not sfac:
sfac = opsvdefo.defo_scale(0, node_tags, ratio=0.05)
nds_crd = nds_crd + sfac * nds_uxy
eles_conn = np.zeros((n_eles, nen), dtype=int)
for i, ele_tag in enumerate(ele_tags):
ele_node_tags = ops.eleNodes(ele_tag)
for j, ele_node_tag in enumerate(ele_node_tags):
eles_conn[i, j] = node_tags.index(ele_node_tag)
if (ele_classtag == EleClassTag.tri3n):
tris_conn = eles_conn
nds_crd_all = nds_crd
nds_val_all = nds_val
elif (ele_classtag == EleClassTag.quad4n):
tris_conn, nds_c_crd, nds_c_val, disps_c = \
quads_to_4tris(eles_conn, nds_crd, nds_val)
nds_crd_all = np.vstack((nds_crd, nds_c_crd))
nds_val_all = np.hstack((nds_val, nds_c_val))
elif (ele_classtag == EleClassTag.tri6n):
tris_conn = tris6n_to_4tris(eles_conn)
nds_crd_all = nds_crd
nds_val_all = nds_val
elif (ele_classtag == EleClassTag.quad8n):
tris_conn, nds_c_crd, nds_c_val = quads_to_8tris_8n(eles_conn,
nds_crd, nds_val)
nds_crd_all = np.vstack((nds_crd, nds_c_crd))
nds_val_all = np.hstack((nds_val, nds_c_val))
elif (ele_classtag == EleClassTag.quad9n):
tris_conn = quads_to_8tris_9n(eles_conn)
nds_crd_all = nds_crd
nds_val_all = nds_val
# 1. plot contour maps
triangulation = tri.Triangulation(nds_crd_all[:, 0],
nds_crd_all[:, 1],
tris_conn)
plt.tricontourf(triangulation, nds_val_all, levels=levels, cmap=cmap)
# 2. plot original mesh (quad) without subdivision into triangles
if mesh_outline:
plot_mesh_2d(nds_crd, eles_conn)
plt.colorbar()
plt.axis('equal')
plt.grid(False)
# see also quads_to_8tris_9n
def quads_to_8tris_8n(quads_conn, nds_crd, nds_val):
"""
Get triangles connectivity, coordinates and new values at quad centroids.
Args:
quads_conn (ndarray):
nds_crd (ndarray):
nds_val (ndarray):
Returns:
tris_conn, nds_c_crd, nds_c_val (tuple):
Notes:
Triangles connectivity array is based on
quadrilaterals connectivity.
Each quad is split into eight triangles.
New nodes are created at the quad centroid.
See also:
function: quads_to_8tris_9n, quads_to_4tris
"""
n_quads, _ = quads_conn.shape
n_nds, _ = nds_crd.shape
# coordinates and values at quad centroids _c_
nds_c_crd = np.zeros((n_quads, 2))
nds_c_val = np.zeros(n_quads)
tris_conn = np.zeros((8*n_quads, 3), dtype=int)
for i, quad_conn in enumerate(quads_conn):
j = 8*i
n0, n1, n2, n3, n4, n5, n6, n7 = quad_conn
# quad centroids
# nds_c_crd[i] = np.array([np.sum(nds_crd[[n0, n1, n2, n3], 0])/4.,
# np.sum(nds_crd[[n0, n1, n2, n3], 1])/4.])
# nds_c_val[i] = np.sum(nds_val[[n0, n1, n2, n3]])/4.
nds_c_crd[i] = quad8n_val_at_center(nds_crd[[n0, n1, n2, n3,
n4, n5, n6, n7]])
nds_c_val[i] = quad8n_val_at_center(nds_val[[n0, n1, n2, n3,
n4, n5, n6, n7]])
# triangles connectivity
tris_conn[j] = np.array([n0, n4, n_nds+i])
tris_conn[j+1] = np.array([n4, n1, n_nds+i])
tris_conn[j+2] = np.array([n1, n5, n_nds+i])
tris_conn[j+3] = np.array([n5, n2, n_nds+i])
tris_conn[j+4] = np.array([n2, n6, n_nds+i])
tris_conn[j+5] = np.array([n6, n3, n_nds+i])
tris_conn[j+6] = np.array([n3, n7, n_nds+i])
tris_conn[j+7] = np.array([n7, n0, n_nds+i])
return tris_conn, nds_c_crd, nds_c_val
# see also quads_to_8tris_8n
def quads_to_8tris_9n(quads_conn):
"""
Get triangles connectivity, coordinates and new values at quad centroids.
Args:
quads_conn (ndarray):
nds_crd (ndarray):
nds_val (ndarray):
Returns:
tris_conn, nds_c_crd, nds_c_val (tuple):
Notes:
Triangles connectivity array is based on
quadrilaterals connectivity.
Each quad is split into eight triangles.
New nodes are created at the quad centroid.
See also:
function: quads_to_8tris_8n, quads_to_4tris
"""
n_quads, _ = quads_conn.shape
# n_nds, _ = nds_crd.shape
tris_conn = np.zeros((8*n_quads, 3), dtype=int)
for i, quad_conn in enumerate(quads_conn):
j = 8*i
n0, n1, n2, n3, n4, n5, n6, n7, n8 = quad_conn
# center nodeds already present in quad 9n
# triangles connectivity
tris_conn[j] = np.array([n0, n4, n8])
tris_conn[j+1] = np.array([n4, n1, n8])
tris_conn[j+2] = np.array([n1, n5, n8])
tris_conn[j+3] = np.array([n5, n2, n8])
tris_conn[j+4] = np.array([n2, n6, n8])
tris_conn[j+5] = np.array([n6, n3, n8])
tris_conn[j+6] = np.array([n3, n7, n8])
tris_conn[j+7] = np.array([n7, n0, n8])
# return tris_conn, nds_c_crd, nds_c_val
return tris_conn
def quad8n_val_at_center(vals):
"""
Calculate values at the center of 8-node quad element.
"""
val_c1 = -np.mean(vals[[0, 1, 2, 3]], axis=0) + 2*np.mean(vals[[4, 5, 6, 7]], axis=0) # noqa: E501
# val_c1 = -np.sum(vals[[0, 1, 2, 3]], axis=0)/4 + np.sum(vals[[4, 5, 6, 7]], axis=0)/2 # noqa: E501
# val_c2 = -np.sum(vals[[0, 1, 2, 3]], axis=0)/4 + np.sum(vals[[4, 5, 6, 7]], axis=0)/2 # noqa: E501
# val_c3 = np.mean(vals[[4, 5, 6, 7]], axis=0)
# val_c4 = np.mean(vals[[0, 1, 2, 3]], axis=0)
# val_c5 = np.mean(vals, axis=0)
# return val_c1, val_c2, val_c3, val_c4, val_c5
return val_c1
[docs]
def plot_stress(stress_str, mesh_outline=1, cmap='turbo', levels=50,
fig_wi_he=False, fig_lbrt=False, sfac=False, nu=0., ax=False):
"""Plot stress distribution of the model.
Args:
stress_str (string): stress component. Available options are:
'sxx', 'syy', 'sxy', 'vmis', 's1', 's2', 'alpha'
mesh_outline (int): 1 - mesh is plotted, 0 - no mesh plotted.
cmap (str): Matplotlib color map (default is 'turbo')
levels (int): number and positions of the contour lines / regions.
Usage:
::
opsv.plot_stress('vmis')
plt.xlabel('x [m]')
plt.ylabel('y [m]')
plt.show()
See also:
:ref:`opsvis_sig_out_per_node`
"""
ndim = ops.getNDM()[0]
if ndim == 2:
ax = _plot_stress_2d(stress_str, mesh_outline, cmap, levels,
fig_wi_he, fig_lbrt, sfac, nu, ax)
else:
print(f'\nWarning! ndim: {ndim} not implemented yet.')
return ax
[docs]
def plot_strain(strain_str, mesh_outline=1, cmap='turbo', levels=50,
fig_wi_he=False, fig_lbrt=False, sfac=False, nu=0., ax=False):
"""Plot strain distribution of the model.
Args:
strain_str (string): strain component. Available options are:
'exx', 'eyy', 'exy', 'ezz'
mesh_outline (int): 1 - mesh is plotted, 0 - no mesh plotted.
cmap (str): Matplotlib color map (default is 'turbo')
levels (int): number and positions of the contour lines / regions.
Usage:
::
opsv.plot_strain('exx')
plt.xlabel('x [m]')
plt.ylabel('y [m]')
plt.show()
"""
ndim = ops.getNDM()[0]
if ndim == 2:
ax = _plot_strain_2d(strain_str, mesh_outline, cmap, levels,
fig_wi_he, fig_lbrt, sfac, nu, ax)
else:
print(f'\nWarning! ndim: {ndim} not implemented yet.')
return ax
def _plot_stress_2d(stress_str, mesh_outline, cmap, levels, fig_wi_he,
fig_lbrt, sfac, nu, ax):
"""See documentation for plot_stress command"""
nds_val = sig_component_per_node(stress_str, nu)
ax = plot_stress_2d(nds_val, mesh_outline, cmap, levels,
fig_wi_he, fig_lbrt, sfac, ax)
return ax
def _plot_strain_2d(strain_str, mesh_outline, cmap, levels, fig_wi_he,
fig_lbrt, sfac, nu, ax):
"""See documentation for plot_strain command"""
nds_val = eps_component_per_node(strain_str, nu)
ax = plot_stress_2d(nds_val, mesh_outline, cmap, levels,
fig_wi_he, fig_lbrt, sfac, ax)
return ax