Module beef.general
General purpose functions.
Expand source code
'''
General purpose functions.
'''
import numpy as np
from scipy.linalg import null_space as null
def n2d_ix(node_ixs, n_dofs=6):
'''
Convert node indices to dof indices.
Arguments
----------
node_ixs : int
list/array of indices of nodes
n_dofs : 6, optional
number of dofs per node
Returns
----------
dof_ixs : int
array of DOF indices corresponding to input node indices
'''
return np.hstack([node_ix*n_dofs+np.arange(n_dofs) for node_ix in node_ixs])
def extract_dofs(mat, dof_ix=[0,1,2], n_dofs=6, axis=0):
'''
Extract selected dofs from matrix.
Arguments
------------
mat : float
numpy array (matrix) to extract DOFs from
dof_ix : int, optional
list of DOF indices (local numbering of DOFs in node) to extract
n_dofs : 6, optional
number of DOFs per node
axis : 0, optional
axis to pick along
Returns
----------
mat_sub : float
subselection of matrix
'''
get_dofs = np.vstack([np.arange(dof, mat.shape[axis],n_dofs) for dof in dof_ix]).T.flatten()
return mat.take(get_dofs, axis=axis)
def convert_dofs(dofs_in, node_type='beam3d', sort_output=True):
'''
Convert string DOFs to indices.
Arguments
----------
dofs_in : {'all', 'trans', 'rot'} or int
string or list of indices
node_type : {'beam2d', 'beam3d'}, optional
type of nodes (defining number of DOFs per node)
sort_output : True, optional
whether or not to sort the DOF indices output
Returns
--------
dofs_out : int
array of DOF indices
'''
dof_dict = dict(beam2d=dict(all=np.arange(0,3), trans=np.arange(0,2), rot=np.arange(2,3)),
beam3d=dict(all=np.arange(0,6), trans=np.arange(0,3), rot=np.arange(3,6)))
if dofs_in in ['all', 'trans', 'rot']:
dofs_out = dof_dict[node_type][dofs_in]
else:
dofs_out = dofs_in
if sort_output:
dofs_out = np.sort(dofs_out)
return dofs_out
def convert_dofs_list(dofs_list_in, n_nodes, node_type='beam3d', sort_output=True):
'''
Convert DOFs list to correct format.
Arguments
-----------
dofs_list_in : str,int
list of strings and indices corresponding to DOFs to
n_nodes : int
number of nodes the DOFs are related to
node_type : {'beam3d', 'beam2d'}
type of nodes (defining number of DOFs per node)
sort_output : True
whether or not to sort output
Returns
-----------
dofs_list_out : int
array of DOF indices
'''
contains_strings = np.any([type(d) is str for d in dofs_list_in])
if type(dofs_list_in) is not list: # single input (all, rot or trans)
dofs_list_out = [dofs_list_in]*n_nodes
elif ~contains_strings and (len(dofs_list_in)<=6) and (np.max(dofs_list_in)<6): #
dofs_list_out = [dofs_list_in]*n_nodes
elif len(dofs_list_in)!=n_nodes:
raise TypeError('Wrong input format of "dofs"')
else:
dofs_list_out = dofs_list_in
for ix, dofs_list_out_i in enumerate(dofs_list_out):
dofs_list_out[ix] = convert_dofs(dofs_list_out_i, node_type=node_type, sort_output=sort_output)
return dofs_list_out
def transform_unit(e1, e2=None, e3=None, warnings=False):
'''
Establish transformation matrix from e1 and temporary e2 or e3 vectors.
Arguments
-----------
e1 : float
unit vector describing element longitudinal direction
e2 : float, optional
temporary unit vector describing a chosen vector that's perpendicular to the longitudinal direction (approximate y-direction)
e3 : float, optional
temporary unit vector describing a chosen vector that's perpendicular to the longitudinal direction (approximate z-direction)
if both e2 and e3 are different from None, e2 is used (e3 disregarded)
Returns
-----------
T : float
transformation matrix
Notes
-----------
Input vectors \(\{e_1\}\) and \(\{e_{2p}\}\) are used to establish a third unit vector, as the cross product of the two, as follows:
$$
\{e_3\} = \{e_1\} \\times \{e_{2p}\}
$$
Then, a final vector is created based on a second cross product:
$$
\{e_2\} = \{e_3\} \\times \{e_1\}
$$
Finally, the transformation matrix is established as follows:
$$
[T] = \\begin{bmatrix}
\{e_1\}^T \\\\
\{e_2\}^T \\\\
\{e_3\}^T
\\end{bmatrix}
$$
where the unit vectors established are the rows of the transformation matrix.
'''
e1 = np.array(e1).flatten()
if (e2 is not None) and (e3 is not None):
e3 = None
if e2 is not None:
e2 = np.array(e2).flatten()
e3_tmp = np.cross(e1, e2) # Direction of the third unit vector
if np.all(e3==0):
if warnings:
print('Warning: e1 and e2 identical. Check orientations carefully!')
e2 = e2 + 0.1
e3 = np.cross(e1, e2)
e2 = np.cross(e3_tmp, e1) # Direction of the second unit vector
e1 = e1/np.linalg.norm(e1) # Normalize the direction vectors to become unit vectors
e2 = e2/np.linalg.norm(e2)
e3 = np.cross(e1, e2)
elif e3 is not None:
e3 = np.array(e3).flatten()
e2_tmp = np.cross(e3, e1) # Direction of the third unit vector
e3 = np.cross(e1, e2_tmp)
e1 = e1/np.linalg.norm(e1) # Normalize the direction vectors to become unit vectors
e3 = e3/np.linalg.norm(e3)
e2 = np.cross(e3, e1)
if e2 is None and e3 is None:
raise ValueError('Specify either e2 or e3')
T = np.vstack([e1,e2,e3])
return T
def gdof_ix_from_nodelabels(all_node_labels, node_labels, dof_ix=[0,1,2]): # from nlfe - not debugged
'''
Get global DOF indices from node labels.
Arguments
------------
all_node_labels : int
list or array of all node labels
node_labels : int
list or array of the node labels to get the indices of
dof_ix : int
local DOF indices to use
Returns
---------
gdof_ix : int
global indices of DOFs of requested nodes
'''
if type(node_labels) is not list:
node_labels = [node_labels]
node_ix = [np.where(nl==all_node_labels)[0] for nl in node_labels]
gdof_ix = gdof_from_nodedof(node_ix, dof_ix)
return gdof_ix
def gdof_from_nodedof(node_ix, dof_ixs, n_dofs=3, merge=True):
'''
Get global DOF from node DOF.
Arguments
----------
node_ix : int
node indices to establish global DOF indices of
dof_ixs : int
local DOF indices to include
n_dofs : 3, optional
number of DOFs (all)
merge : True, optional
whether or not to merge the global DOF indices from all nodes, to a single list
Returns
---------
gdof_ix : int
global indices of DOFs of requested nodes
'''
gdof_ix = []
if type(node_ix) is not list:
node_ix = [node_ix]
if type(dof_ixs) is not list:
dof_ixs = [dof_ixs]*len(node_ix)
elif len(dof_ixs) != len(node_ix):
dof_ixs = [dof_ixs]*len(node_ix)
for ix, n in enumerate(node_ix):
gdof_ix.append(n*n_dofs + np.array(dof_ixs[ix]))
if merge:
gdof_ix = np.array(gdof_ix).flatten()
return gdof_ix
def B_to_dofpairs(B, master_val=1):
'''
Establish pairs of indices of DOFs to couple from compatibility matrix B.
Arguments
----------
B : float
Lagrange compatiblity \([B]\) matrix
master_val : float
value used to identify master DOF
Returns
----------
dof_pairs : int
indices of DOFs paired through input \([B]\) matrix
'''
n_constr, n_dofs = B.shape
dof_pairs = [None]*n_constr
for icon in range(0, n_constr):
master = np.where(B[icon,:] == master_val)[0][0]
slave = np.where(B[icon,:] == -master_val)[0]
if len(slave) != 0:
slave = slave[0]
else:
slave = None
dof_pairs[icon] = [master, slave]
dof_pairs = np.array(dof_pairs).T
return dof_pairs
def dof_pairs_to_Linv(dof_pairs, n_dofs):
'''
Establish quasi-inverse of L from dof pairs describing constraints.
Arguments
----------
dof_pairs : int
list of lists of indices of DOFs paired
n_dofs : int
number of DOFs
Returns
----------
Linv : int
Notes
----------
\([L_{inv}]\) is a constructed quantity, conventient as it can construct the constrainted u (unique, free DOFs) from the full as follows:
$$
\{u_c\} = [L_{inv}] \{u\}
$$
It is worth noting that it only works for fully hard-constrained systems (no weak connections, or similar).
'''
slave_nodes = dof_pairs[dof_pairs[:,1]!=None, 1]
grounded_nodes = dof_pairs[dof_pairs[:,1]==None, 0]
remove = np.unique(np.hstack([grounded_nodes, slave_nodes]))
all_dofs = np.arange(0,n_dofs)
primal_dofs = np.setdiff1d(all_dofs, remove)
Linv = np.zeros([len(primal_dofs), n_dofs])
for primal_dof_ix, primal_dof in enumerate(primal_dofs):
Linv[primal_dof_ix, primal_dof] = 1
return Linv
def compatibility_matrix(dof_pairs, n_dofs):
'''
Establish compatibility matrix from specified pairs of DOFs.
Arguments
----------
dof_pairs : int
list of lists of indices of DOFs paired
n_dofs : int
number of DOFs in full system; defines the number of rows of \([B]\)
Returns
----------
B : int
numpy array describing compatibility matrix \([B]\)
'''
n_constraints = dof_pairs.shape[0]
B = np.zeros([n_constraints, n_dofs])
for constraint_ix, dof_pair in enumerate(dof_pairs):
if dof_pair[1] is None: # connected dof is None --> fixed to ground
B[constraint_ix, dof_pair[0]] = 1
else:
B[constraint_ix, dof_pair[0]] = 1
B[constraint_ix, dof_pair[1]] = -1
return B
def lagrange_constrain(mat, dof_pairs, null=False):
'''
Lagrange constrain matrix from specified DOF pairs.
Arguments
-----------------
mat : float
matrix to constrain
dof_pairs : int
list of lists of indices of DOFs paired
null : False, optional
to create a 0 matrix of the correct size, this can be set to True
Returns
----------
mat_fixed : float
constrained matrix
'''
# Lagrange multiplier method - expand matrix
n_constraints = len(dof_pairs)
n_dofs = mat.shape[0]
if not null:
B = compatibility_matrix(dof_pairs, n_dofs)
else:
B = np.zeros([n_constraints, n_dofs])
O = np.zeros([n_constraints, n_constraints])
mat_fixed = np.vstack([np.hstack([mat, B.T]), np.hstack([B, O])])
return mat_fixed
def lagrange_constrain_from_B(mat, B, null=False):
'''
Lagrange constrain matrix from specified compatibility matrix.
Arguments
-----------------
mat : float
matrix to constrain
B : int
numpy array describing compatibility matrix \([B]\)
null : False, optional
to create a 0 matrix of the correct size, this can be set to True
Returns
----------
mat_fixed : float
constrained matrix
'''
# Lagrange multiplier method - expand matrix
n_constraints = B.shape[0]
O = np.zeros([n_constraints, n_constraints])
mat_fixed = np.vstack([np.hstack([mat, B.T]), np.hstack([B, O])])
return mat_fixed
def expand_vector_with_zeros(vec, n_constraints):
'''
Append vector with zeros based on number of constraints (n_constraints).
'''
vec_expanded = np.hstack([vec.flatten(), np.zeros(n_constraints)])[np.newaxis, :].T
return vec_expanded
def blkdiag(mat, n):
return np.kron(np.eye(n), mat)
def nodes_to_beam_element_matrix(node_labels, first_element_label=1):
'''
Establish element matrix definition assuming ordered node labels.
Arguments
-----------
node_labels : int
list of integer node labels
first_element_label : int
first integer used in element matrix
Returns
-----------
element_matrix : int
element definition where each row represents an element as [element_label_i, node_label_1, node_label_2]
'''
n_nodes = len(node_labels)
n_elements = n_nodes-1
element_matrix = np.empty([n_elements, 3])
element_matrix[:, 0] = np.arange(first_element_label,first_element_label+n_elements)
element_matrix[:, 1] = node_labels[0:-1]
element_matrix[:, 2] = node_labels[1:]
return element_matrix
def get_phys_modes(phi, B, lambd=None, return_as_ix=False):
'''
Get physical modes.
Arguments
-----------
phi : float
B : int
numpy array describing compatibility matrix \([B]\)
lambd : float, optional
standard value None does not
return_as_ix : False, optional
whether or not to output as indices instead of eigenvectors and eigenvalues
Returns
----------
lambd_phys : float
physical eigenvalue array
phi_phys : float
physical eigenvector array (modal transformation matrix)
phys_ix : int
indices of selected DOFs (if `return_as_ix=True` is passed)
'''
n_lagr = B.shape[0]
u_ = phi[0:-n_lagr, :] #physical dofs
l_ = phi[-n_lagr:,:] #lagr dofs
# Compatibility at interface
mask1 = np.all((B @ u_)==0, axis=0)
# Equilibrium at interface
L = null(B)
g = -B.T @ l_
mask2 = np.all((L.T @ g)==0, axis=0)
phys_ix = np.logical_and(mask1, mask1)
if return_as_ix:
return phys_ix
else:
if lambd is None:
lambd_phys = None
else:
lambd_phys = lambd[phys_ix]
phi_phys = u_[:, phys_ix]
return lambd_phys, phi_phys
def ensure_list(list_in, levels=1, increase_only=True):
'''
Ensure input variable is list.
Arguments
----------
list_in : float, int
list or scalar
levels : int
number of levels of list (nest-level)
increase_only : True, optional
if True, only increase amount of list-wrapping
Returns
----------
list_out : float, int
list
'''
dimensions = np.array(list_in).ndim
if type(list_in) is not list:
list_out = [list_in]
dimensions = dimensions+1
else:
list_out = list_in * 1
if not increase_only:
while dimensions>levels:
list_out = list_out[0]
dimensions = dimensions - 1
while dimensions<levels:
list_out = [list_out]
dimensions = dimensions + 1
return list_out
def feature_matrix(master_dofs, values, slave_dofs=None, ndofs=None, return_small=False):
'''
Arguments
---------
master_dofs : int
list of indices of master DOFs
values : float
list of amplitudes/values for features
slave_dofs : int, optional
list of indices of slave DOFs (standard value None, makes grounded connections from master_dofs)
ndofs : int, optional
number of modes used to construct full matrix (not relevant if `return_small=True`)
return_small : False, optional
whether or not to return small or full matrix - if `return_small=True`, returns small ndofs-by-ndofs matrix and corresponding indices in global matrix; if `return_small=False` returns big ndofs_global-by-ndofs_global matrix
Returns
---------
mat : float
feature matrix
dof_ixs : int
list of indices of DOFs for relevant feature connectivity (only returned if `return_small=True`)
'''
ndofs_small = len(master_dofs)
if type(values) is float or type(values) is int:
values = [float(values)]*ndofs_small
elif len(values) != len(master_dofs):
raise ValueError('Length of master_dofs and values must match')
if slave_dofs is None:
small = np.diag(values)
slave_dofs = []
else:
if len(slave_dofs) != len(master_dofs):
raise ValueError('Length of master_dofs and slave_dofs must match')
small = np.diag(np.hstack([values,values]))
for ix in range(ndofs_small):
small[ix, ix+ndofs_small] = small[ix+ndofs_small, ix] = -values[ix]
dof_ixs = np.hstack([master_dofs, slave_dofs]).astype(int)
if return_small:
return small, dof_ixs
else:
if len(set(dof_ixs)) != len(dof_ixs):
raise ValueError('Non-unique dof indices are provided')
if ndofs is None:
ndofs = np.max(dof_ixs)+1
large = np.zeros([ndofs, ndofs])
large[np.ix_(dof_ixs, dof_ixs)] = small
return large
def basic_coupled():
return np.array([[1, -1], [-1, 1]])
def generic_beam_mat(L, yy=0, yz=0, yt=0, zy=0, zz=0, zt=0, ty=0, tz=0, tt=0):
mat = np.zeros([12,12])
mat[0:6, 0:6] = np.array([
[0, 0, 0, 0, 0, 0 ],
[0, 156*yy, 156*yz, 147*yt, -22*L*yz, 22*L*yy ],
[0, 156*zy, 156*zz, 147*zt, -22*L*zz, 22*L*zy ],
[0, 147*ty, 147*tz, 140*tt, -21*L*tz, 21*L*ty ],
[0, -22*L*zy, -22*L*zz, -21*L*zt, 4*L**2*zz, -4*L**2*zy ],
[0, 22*L*yy, 22*L*yz, 21*L*yt, -4*L**2*yz, 4*L**2*yy ],
])
mat[0:6, 6:12] = np.array([
[0, 0, 0, 0, 0, 0 ],
[0, 54*yy, 54*yz, 63*yt, 13*L*yz, -13*L*yy ],
[0, 54*zy, 54*zz, 63*zt, 13*L*zz, -13*L*zy ],
[0, 63*ty, 63*tz, 70*tt, 14*L*tz, -14*L*ty ],
[0, -13*L*zy, -13*L*zz, -14*L*zt, -3*L**2*zz, 3*L**2*zy ],
[0, 13*L*yy, 13*L*yz, 14*L*yt, 3*L**2*yz, -3*L**2*yy ],
])
mat[6:12, 0:6] = np.array([
[0, 0, 0, 0, 0, 0 ],
[0, 54*yy, 54*yz, 63*yt, -13*L*yz, 13*L*yy ],
[0, 54*zy, 54*zz, 63*zt, -13*L*zz, 13*L*zy ],
[0, 63*ty, 63*tz, 70*tt, -14*L*tz, 14*L*ty ],
[0, 13*L*zy, 13*L*zz, 14*L*zt, -3*L**2*zz, 3*L**2*zy ],
[0, -13*L*yy, -13*L*yz, -14*L*yt, 3*L**2*yz, -3*L**2*yy ],
])
mat[6:12,6:12] = np.array([
[0, 0, 0, 0, 0, 0 ],
[0, 156*yy, 156*yz, 147*yt, 22*L*yz, -22*L*yy ],
[0, 156*zy, 156*zz, 147*zt, 22*L*zz, -22*L*zy ],
[0, 147*ty, 147*tz, 140*tt, 21*L*tz, -21*L*ty ],
[0, 22*L*zy, 22*L*zz, 21*L*zt, 4*L**2*zz, -4*L**2*zy ],
[0, -22*L*yy, -22*L*yz, -21*L*yt, -4*L**2*yz, 4*L**2*yy ],
])
return mat * L / 420
def bar_foundation_stiffness(L, kx, ky, kz): #only z and y currently, will be extended!
mat = np.vstack([
[kx*1/4, 0, 0, 0, 0, 0, kx*1/4, 0, 0, 0, 0, 0], #ux1
[0, ky*1/3, 0, 0, 0, 0, 0, ky*1/6, 0, 0, 0, 0], #uy1
[0, 0, kz*1/3, 0, 0, 0, 0, 0, kz*1/6, 0, 0, 0], #uz1
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], #rx1
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], #ry1
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], #rz1
[kx*1/4, 0, 0, 0, 0, 0, kx*1/4, 0, 0, 0, 0, 0], #ux2
[0, ky*1/6, 0, 0, 0, 0, 0, ky*1/3, 0, 0, 0, 0], #uy2
[0, 0, kz*1/6, 0, 0, 0, 0, 0, kz*1/3, 0, 0, 0], #uz2
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], #rx2
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], #ry2
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) * L #rz2
return mat
Functions
def B_to_dofpairs(B, master_val=1)
-
Establish pairs of indices of DOFs to couple from compatibility matrix B.
Arguments
B
:float
- Lagrange compatiblity [B] matrix
master_val
:float
- value used to identify master DOF
Returns
dof_pairs
:int
- indices of DOFs paired through input [B] matrix
def bar_foundation_stiffness(L, kx, ky, kz)
def basic_coupled()
def blkdiag(mat, n)
def compatibility_matrix(dof_pairs, n_dofs)
-
Establish compatibility matrix from specified pairs of DOFs.
Arguments
dof_pairs
:int
- list of lists of indices of DOFs paired
n_dofs
:int
- number of DOFs in full system; defines the number of rows of [B]
Returns
B
:int
- numpy array describing compatibility matrix [B]
def convert_dofs(dofs_in, node_type='beam3d', sort_output=True)
-
Convert string DOFs to indices.
Arguments
dofs_in
:{'all', 'trans', 'rot'}
orint
- string or list of indices
node_type
:{'beam2d', 'beam3d'}
, optional- type of nodes (defining number of DOFs per node)
sort_output
:True
, optional- whether or not to sort the DOF indices output
Returns
dofs_out
:int
- array of DOF indices
def convert_dofs_list(dofs_list_in, n_nodes, node_type='beam3d', sort_output=True)
-
Convert DOFs list to correct format.
Arguments
dofs_list_in
:str,int
- list of strings and indices corresponding to DOFs to
n_nodes
:int
- number of nodes the DOFs are related to
node_type
:{'beam3d', 'beam2d'}
- type of nodes (defining number of DOFs per node)
sort_output
:True
- whether or not to sort output
Returns
dofs_list_out
:int
- array of DOF indices
def dof_pairs_to_Linv(dof_pairs, n_dofs)
-
Establish quasi-inverse of L from dof pairs describing constraints.
Arguments
dof_pairs
:int
- list of lists of indices of DOFs paired
n_dofs
:int
- number of DOFs
Returns
Linv
:int
Notes
[L_{inv}] is a constructed quantity, conventient as it can construct the constrainted u (unique, free DOFs) from the full as follows:
\{u_c\} = [L_{inv}] \{u\}
It is worth noting that it only works for fully hard-constrained systems (no weak connections, or similar).
def ensure_list(list_in, levels=1, increase_only=True)
-
Ensure input variable is list.
Arguments
list_in
:float, int
- list or scalar
levels
:int
- number of levels of list (nest-level)
increase_only
:True
, optional- if True, only increase amount of list-wrapping
Returns
list_out
:float, int
- list
def expand_vector_with_zeros(vec, n_constraints)
-
Append vector with zeros based on number of constraints (n_constraints).
def extract_dofs(mat, dof_ix=[0, 1, 2], n_dofs=6, axis=0)
-
Extract selected dofs from matrix.
Arguments
mat
:float
- numpy array (matrix) to extract DOFs from
dof_ix
:int
, optional- list of DOF indices (local numbering of DOFs in node) to extract
n_dofs
:6
, optional- number of DOFs per node
axis
:0
, optional- axis to pick along
Returns
mat_sub
:float
- subselection of matrix
def feature_matrix(master_dofs, values, slave_dofs=None, ndofs=None, return_small=False)
-
Arguments
master_dofs
:int
- list of indices of master DOFs
values
:float
- list of amplitudes/values for features
slave_dofs
:int
, optional- list of indices of slave DOFs (standard value None, makes grounded connections from master_dofs)
ndofs
:int
, optional- number of modes used to construct full matrix (not relevant if
return_small=True
) return_small
:False
, optional- whether or not to return small or full matrix - if
return_small=True
, returns small ndofs-by-ndofs matrix and corresponding indices in global matrix; ifreturn_small=False
returns big ndofs_global-by-ndofs_global matrix
Returns
mat
:float
- feature matrix
dof_ixs
:int
- list of indices of DOFs for relevant feature connectivity (only returned if
return_small=True
)
def gdof_from_nodedof(node_ix, dof_ixs, n_dofs=3, merge=True)
-
Get global DOF from node DOF.
Arguments
node_ix
:int
- node indices to establish global DOF indices of
dof_ixs
:int
- local DOF indices to include
n_dofs
:3
, optional- number of DOFs (all)
merge
:True
, optional- whether or not to merge the global DOF indices from all nodes, to a single list
Returns
gdof_ix
:int
- global indices of DOFs of requested nodes
def gdof_ix_from_nodelabels(all_node_labels, node_labels, dof_ix=[0, 1, 2])
-
Get global DOF indices from node labels.
Arguments
all_node_labels
:int
- list or array of all node labels
node_labels
:int
- list or array of the node labels to get the indices of
dof_ix
:int
- local DOF indices to use
Returns
gdof_ix
:int
- global indices of DOFs of requested nodes
def generic_beam_mat(L, yy=0, yz=0, yt=0, zy=0, zz=0, zt=0, ty=0, tz=0, tt=0)
def get_phys_modes(phi, B, lambd=None, return_as_ix=False)
-
Get physical modes.
Arguments
phi
:float
B
:int
- numpy array describing compatibility matrix [B]
lambd
:float
, optional- standard value None does not
return_as_ix
:False
, optional- whether or not to output as indices instead of eigenvectors and eigenvalues
Returns
lambd_phys
:float
- physical eigenvalue array
phi_phys
:float
- physical eigenvector array (modal transformation matrix)
phys_ix
:int
- indices of selected DOFs (if
return_as_ix=True
is passed)
def lagrange_constrain(mat, dof_pairs, null=False)
-
Lagrange constrain matrix from specified DOF pairs.
Arguments
mat
:float
- matrix to constrain
dof_pairs
:int
- list of lists of indices of DOFs paired
null
:False
, optional- to create a 0 matrix of the correct size, this can be set to True
Returns
mat_fixed
:float
- constrained matrix
def lagrange_constrain_from_B(mat, B, null=False)
-
Lagrange constrain matrix from specified compatibility matrix.
Arguments
mat
:float
- matrix to constrain
B
:int
- numpy array describing compatibility matrix [B]
null
:False
, optional- to create a 0 matrix of the correct size, this can be set to True
Returns
mat_fixed
:float
- constrained matrix
def n2d_ix(node_ixs, n_dofs=6)
-
Convert node indices to dof indices.
Arguments
node_ixs
:int
- list/array of indices of nodes
n_dofs
:6
, optional- number of dofs per node
Returns
dof_ixs
:int
- array of DOF indices corresponding to input node indices
def nodes_to_beam_element_matrix(node_labels, first_element_label=1)
-
Establish element matrix definition assuming ordered node labels.
Arguments
node_labels
:int
- list of integer node labels
first_element_label
:int
- first integer used in element matrix
Returns
element_matrix
:int
- element definition where each row represents an element as [element_label_i, node_label_1, node_label_2]
def transform_unit(e1, e2=None, e3=None, warnings=False)
-
Establish transformation matrix from e1 and temporary e2 or e3 vectors.
Arguments
e1
:float
- unit vector describing element longitudinal direction
e2
:float
, optional- temporary unit vector describing a chosen vector that's perpendicular to the longitudinal direction (approximate y-direction)
e3
:float
, optional- temporary unit vector describing a chosen vector that's perpendicular to the longitudinal direction (approximate z-direction) if both e2 and e3 are different from None, e2 is used (e3 disregarded)
Returns
T
:float
- transformation matrix
Notes
Input vectors \{e_1\} and \{e_{2p}\} are used to establish a third unit vector, as the cross product of the two, as follows:
\{e_3\} = \{e_1\} \times \{e_{2p}\}
Then, a final vector is created based on a second cross product: \{e_2\} = \{e_3\} \times \{e_1\}
Finally, the transformation matrix is established as follows:
[T] = \begin{bmatrix} \{e_1\}^T \\ \{e_2\}^T \\ \{e_3\}^T \end{bmatrix}
where the unit vectors established are the rows of the transformation matrix.