pyyeti.nastran.n2p.find_xyz_triples¶
- pyyeti.nastran.n2p.find_xyz_triples(drmrb, get_trans=False, mats=None, inplace=False, tol=0.01)[source]¶
Find x, y, z triples in rigid-body motion matrix.
Warning
This routine can be tricked and return incorrect results when only 1 or 2 (and not all 3) translational DOF for a node are present. See example.
- Parameters:
drmrb (2d array_like, n x 6) – Rigid-body modes or, for example,
drmrb = ATM @ rb.get_trans (bool; optional) – If True, return list of 3x3 transforms that converts each triplet of xyz rows to the coordinate system of the reference node for the rigid-body modes.
mats (dictionary or None; optional) – Dictionary of matrices (2d ndarrays) that will have rows that correspond to the triplet rows in drmrb transformed by the 3x3 transforms derived from drmrb. These transforms are optionally returned in Ts. mats is ignored if None, though you can still transform matrices afterwards by setting get_trans to True and using the return value Ts.
inplace (bool; optional) – If True, the mats dictionary and matrices will be changed in place.
tol (scalar; optional) – Tolerance; default is 0.01 to accept up to 1% errors.
- Returns:
A SimpleNamespace with the members
pv (1d ndarray) – Bool array with True values indicating the rows in drmrb where xyz triples were found, if any.
coords (2d ndarray) – Contains coordinates of each xyz triplet relative to the reference of the rigid-body modes. Size is n x 3 where n is the number of rows in drmrb. The coordinates of each triplet is repeated 3 times; other, non-triplet rows are filled with
np.nan.scales (1d ndarray) – Length n array containing the scale of each triplet. Non-triplet rows are filled with
np.nan. scales is used to handle different output units.model_scale (scalar) – The maximum model dimension found:
model_scale = abs(coords).max()Ts (list of 2d ndarrays; optional) – Only returned if get_trans is True. List of 3x3 transforms that converts each triplet of xyz rows to the coordinate system of the reference node for the rigid-body modes. Unlike other outputs, Ts does not contain any information for non xyz triplet rows.
outmats (dictionary; optional) – The transformed version of mats.
Examples
Show how this routine can be tricked into returning incorrect results:
>>> import numpy as np >>> from pyyeti.nastran import n2p >>> >>> # make a rigid-body mode shape matrix with two nodes on the X >>> # axis (one at (2, 0, 0) and the other at (5, 0, 0)): >>> xyz = np.array( ... [ ... [1.0, 0.0, 0.0, 0.0, 0.0, 0.0], ... [0.0, 1.0, 0.0, 0.0, 0.0, 2.0], ... [0.0, 0.0, 1.0, 0.0, -2.0, 0.0], ... [1.0, 0.0, 0.0, 0.0, 0.0, 0.0], ... [0.0, 1.0, 0.0, 0.0, 0.0, 5.0], ... [0.0, 0.0, 1.0, 0.0, -5.0, 0.0], ... ] ... ) >>> n2p.find_xyz_triples(xyz).coords array([[ 2., 0., 0.], [ 2., 0., 0.], [ 2., 0., 0.], [ 5., 0., 0.], [ 5., 0., 0.], [ 5., 0., 0.]])
In this case, the 4th row is the same as the 1st row, so if we delete the first row, the routine will still find a perfectly valid triple indicating there is a node at (2, 0, 0), but in a rotated coordinate system. However, it won’t find the node at (5, 0, 0) at all:
>>> n2p.find_xyz_triples(xyz[1:]).coords array([[ 2., 0., 0.], [ 2., 0., 0.], [ 2., 0., 0.], [ nan, nan, nan], [ nan, nan, nan]])
For another example showing more features, a rigid-body mode shape matrix with two identical nodes is defined by hand. Then, the second node will be transformed into a different coordinate system and scaled up by 10.0. Also, note that the 3 rotation rows for the second grid are not included.
>>> import numpy as np >>> from pyyeti.nastran import n2p >>> >>> # define rb mode shape matrix for two nodes, both at >>> # (5, 10, 15) in basic: >>> rb = np.array([ ... [1., 0., 0., 0., 15., -10.], ... [0., 1., 0., -15., 0., 5.], ... [0., 0., 1., 10., -5., 0.], ... [0., 0., 0., 1., 0., 0.], ... [0., 0., 0., 0., 1., 0.], ... [0., 0., 0., 0., 0., 1.], ... [1., 0., 0., 0., 15., -10.], ... [0., 1., 0., -15., 0., 5.], ... [0., 0., 1., 10., -5., 0.], ... ]) >>> >>> # change coordinate system and scale for second node, just to >>> # test routine: >>> c = 1 / np.sqrt(2) # a 45 degree angle >>> T = np.array([[1., 0., 0.], ... [0., c, c], ... [0., -c, c]]) >>> rb[-3:] = 10 * T @ rb[-3:] >>> np.set_printoptions(linewidth=60, precision=2, suppress=True) >>> rb array([[ 1. , 0. , 0. , 0. , 15. , -10. ], [ 0. , 1. , 0. , -15. , 0. , 5. ], [ 0. , 0. , 1. , 10. , -5. , 0. ], [ 0. , 0. , 0. , 1. , 0. , 0. ], [ 0. , 0. , 0. , 0. , 1. , 0. ], [ 0. , 0. , 0. , 0. , 0. , 1. ], [ 10. , 0. , 0. , 0. , 150. , -100. ], [ 0. , 7.07, 7.07, -35.36, -35.36, 35.36], [ 0. , -7.07, 7.07, 176.78, -35.36, -35.36]])
Call n2p.find_xyz_triples to transform rb internally (it will also be transformed “by-hand” below):
>>> mats = {'rb': rb} >>> trips = n2p.find_xyz_triples(rb, get_trans=True, mats=mats)
Check results:
>>> np.set_printoptions(linewidth=60, precision=4, suppress=True) >>> trips.pv array([ True, True, True, False, False, False, True, True, True], dtype=bool) >>> trips.coords array([[ 5., 10., 15.], [ 5., 10., 15.], [ 5., 10., 15.], [ nan, nan, nan], [ nan, nan, nan], [ nan, nan, nan], [ 5., 10., 15.], [ 5., 10., 15.], [ 5., 10., 15.]]) >>> trips.scales array([ 1., 1., 1., nan, nan, nan, 10., 10., 10.]) >>> len(trips.Ts) 2 >>> >>> # Show both transforms ... note that scale is included: >>> trips.Ts[0] + 0 # transform for first node array([[ 1., 0., 0.], [ 0., 1., 0.], [ 0., 0., 1.]]) >>> trips.Ts[1] + 0 # transform for second node array([[ 0.1 , 0. , 0. ], [ 0. , 0.0707, -0.0707], [ 0. , 0.0707, 0.0707]]) >>> >>> # The transformed rb modes: >>> np.allclose(trips.outmats['rb'], ... [[ 1., 0., 0., 0., 15., -10.], ... [ 0., 1., 0., -15., 0., 5.], ... [ 0., 0., 1., 10., -5., 0.], ... [ 0., 0., 0., 1., 0., 0.], ... [ 0., 0., 0., 0., 1., 0.], ... [ 0., 0., 0., 0., 0., 1.], ... [ 1., 0., 0., 0., 15., -10.], ... [ 0., 1., 0., -15., 0., 5.], ... [ 0., 0., 1., 10., -5., 0.]]) True
Transform “rb” back into basic coordinates and to unity scale by using pv & Ts together:
>>> pv = trips.pv.nonzero()[0] >>> for j, Tcurr in enumerate(trips.Ts): ... pvcurr = pv[j * 3:j * 3 + 3] ... rb[pvcurr] = Tcurr @ rb[pvcurr] >>> np.allclose(rb, ... [[ 1., 0., 0., 0., 15., -10.], ... [ 0., 1., 0., -15., 0., 5.], ... [ 0., 0., 1., 10., -5., 0.], ... [ 0., 0., 0., 1., 0., 0.], ... [ 0., 0., 0., 0., 1., 0.], ... [ 0., 0., 0., 0., 0., 1.], ... [ 1., 0., 0., 0., 15., -10.], ... [ 0., 1., 0., -15., 0., 5.], ... [ 0., 0., 1., 10., -5., 0.]]) True