def test_uset_convert(): import numpy as np from pyyeti import cb from pyyeti.nastran import n2p # node 100 in basic is @ [50, 100, 150] inches uset = n2p.addgrid(None, 100, "b", 0, [50, 100, 150], 0) ref = (100, 100, 100) uset_conv, ref_conv = cb.uset_convert(uset, ref, "e2m") assert np.allclose(uset_conv.loc[(100, 1), "x":"z"], [1.27, 2.54, 3.81]) assert np.allclose(ref_conv, [2.54, 2.54, 2.54]) uset_back, ref_back = cb.uset_convert(uset_conv, ref_conv) assert np.allclose(uset_back, uset) assert np.allclose(ref_back, ref) uset_conv2, ref_conv = cb.uset_convert(uset_conv) assert np.allclose(uset, uset_conv2) assert ref_conv is None
def test_mk_net_drms(): pth = os.path.dirname(inspect.getfile(cb)) pth = os.path.join(pth, "..") pth = os.path.join(pth, "tests") pth = os.path.join(pth, "nas2cam_csuper") # Load the mass and stiffness from the .op4 file # This loads the data into a dict: mk = op4.load(os.path.join(pth, "inboard.op4")) maa = mk["mxx"][0] kaa = mk["kxx"][0] # Get the USET table The USET table has the boundary DOF # information (id, location, coordinate system). This is needed # for superelements with an indeterminate interface. The nastran # module has the function bulk2uset which is handy for forming the # USET table from bulk data. uset, coords = nastran.bulk2uset(os.path.join(pth, "inboard.asm")) # uset[::6, [0, 3, 4, 5]] # array([[ 3., 600., 0., 300.], # [ 11., 600., 300., 300.], # [ 19., 600., 300., 0.], # [ 27., 600., 0., 0.]]) # x s/c is axial (see figure in cbtf or cbcheck tutorial) # - make z l/v axial, but pointing down # z s/c ^ y l/v # \ | / y s/c # \|/ # <------ # x l/v sccoord = [ [900, 1, 0], [0, 0, 0], [1, 1, 0], # z is 45 deg between x & y of l/v [0, 0, -1], ] # x is -z l/v c = np.cos(45 / 180 * np.pi) Tl2s = np.array([[0, 0, -1.0], [-c, c, 0], [c, c, 0]]) # Form b-set partition vector into a-set # In this case, we already know the b-set are first: n = uset.shape[0] b = np.arange(n) # array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, # 16, 17, 18, 19, 20, 21, 22, 23]) # convert s/c from mm, kg --> m, kg ref = [600, 150, 150] conv = (0.001, 1.0) g = 9.80665 u = n2p.addgrid(None, 1, "b", sccoord, [0, 0, 0], sccoord) Tsc2lv = np.zeros((6, 6)) T = u.iloc[3:, 1:] Tsc2lv[:3, :3] = T Tsc2lv[3:, 3:] = T assert np.allclose(Tl2s.T, Tsc2lv[:3, :3]) net = cb.mk_net_drms( maa, kaa, b, uset=uset, ref=ref, sccoord=sccoord, conv=conv, g=g ) usetbq, c, bset = nastran.asm2uset(os.path.join(pth, "inboard.asm")) with assert_raises(ValueError) as cm: cb.mk_net_drms( maa, kaa, b[:3], uset=usetbq, ref=ref, sccoord=Tl2s, conv=conv, g=g ) the_msg = str(cm.exception) assert 0 == the_msg.find( f"number of rows in `uset` is {uset.shape[0]}, but must " f"equal len(b-set) (3)" ) net2 = cb.mk_net_drms( maa, kaa, b, uset=usetbq, ref=ref, sccoord=Tl2s, conv=conv, g=g ) # rb modes in system units: uset2, ref2 = cb.uset_convert(uset, ref, conv) rb = n2p.rbgeom_uset(uset2, ref2) l_sc = net.ifltma_sc[:, :n] @ rb l_lv = net.ifltma_lv[:, :n] @ rb l_scd = net.ifltmd_sc[:, :n] @ rb l_lvd = net.ifltmd_lv[:, :n] @ rb a_sc = net.ifatm_sc[:, :n] @ rb a_lv = net.ifatm_lv[:, :n] @ rb c_sc = net.cgatm_sc[:, :n] @ rb c_lv = net.cgatm_lv[:, :n] @ rb sbe = np.eye(6) sbe[:3] *= 1 / g assert np.allclose(a_sc, sbe) # calc what the interface forces should be: # - acceleration = 1 m/s**2 = 1000 mm/s**2 # - the forces should be very similar to the 6x6 mass # matrix at the reference point ... which, conveniently, # is provided in the cbtf tutorial: mass = np.array( [ [1.755, 0.0, -0.0, 0.0, 0.0, 0.0], [0.0, 1.755, -0.0, -0.0, 0.0, 772.22], [-0.0, -0.0, 1.755, 0.0, -772.22, -0.0], [0.0, -0.0, 0.0, 35905.202, -0.0, -0.0], [0.0, 0.0, -772.22, -0.0, 707976.725, 109.558], [0.0, 772.22, -0.0, -0.0, 109.558, 707976.725], ] ) sbe = mass sbe[:, :3] *= 1000 # scale up translations assert abs(sbe - l_sc).max() < 0.5 assert np.allclose(Tsc2lv @ a_sc, a_lv) assert np.allclose(Tsc2lv @ c_sc, c_lv) assert abs(l_scd).max() < 1e-6 * abs(l_sc).max() assert abs(l_lvd).max() < 1e-6 * abs(l_lv).max() scale = np.array([[1000], [1000], [1000], [1000000], [1000000], [1000000]]) assert np.allclose((1 / scale) * (Tsc2lv @ l_sc), l_lv) # height and mass values from cbcheck tutorial (and then refined): m_kg = 1.75505183 h_m = 1.039998351 - 0.6 assert abs(net.height_lv - h_m) < 0.000001 assert abs(net.weight_lv - m_kg * g) < 0.000001 assert abs(net.height_sc - 1000 * h_m) < 0.000001 * 1000 assert abs(net.weight_sc - 1000 * m_kg * g) < 0.000001 * 1000 assert net.scaxial_sc == 0 assert net.scaxial_lv == 2 compare_nets(net, net2) # check the natural unit output: net3 = cb.mk_net_drms( maa, kaa, b, uset=uset, ref=ref, sccoord=Tl2s, conv=conv, g=g, tau=("mm", "m") ) for drm in ("ifatm", "cgatm"): if drm == "ifatm": # only ifatm has 12 rows drm1 = getattr(net, drm) drm3 = getattr(net3, drm) assert np.allclose(drm3[:3], drm1[:3] * g * 1000) assert np.allclose(drm3[3:6], drm1[3:6]) assert np.allclose(drm3[6:9], drm1[6:9] * g) assert np.allclose(drm3[9:], drm1[9:]) for ext, factor in (("_sc", 1000), ("_lv", 1)): drm1 = getattr(net, drm + ext) drm3 = getattr(net3, drm + ext) assert np.allclose(drm3[:3], drm1[:3] * g * factor) assert np.allclose(drm3[3:], drm1[3:]) labels3 = [i.replace("g", "mm/s^2") for i in net.ifatm_labels[:6]] + [ i.replace("g", "m/s^2") for i in net.ifatm_labels[6:] ] print(labels3) print() print(net3.ifatm_labels) assert labels3 == net3.ifatm_labels net4 = cb.mk_net_drms( maa, kaa, b, uset=uset, ref=ref, sccoord=Tl2s, conv=conv, g=g, tau=("g", "m") ) for drm in ("ifatm", "cgatm"): if drm == "ifatm": # only ifatm has 12 rows drm1 = getattr(net, drm) drm3 = getattr(net3, drm) drm4 = getattr(net4, drm) assert np.allclose(drm4[:3], drm1[:3]) assert np.allclose(drm4[3:6], drm1[3:6]) assert np.allclose(drm4[6:9], drm3[6:9]) assert np.allclose(drm4[9:], drm3[9:]) for ext, net_ in (("_sc", net), ("_lv", net3)): drm1 = getattr(net_, drm + ext) drm4 = getattr(net4, drm + ext) assert np.allclose(drm4[:3], drm1[:3]) assert np.allclose(drm4[3:], drm1[3:]) labels4 = net.ifatm_labels[:6] + net3.ifatm_labels[6:] assert labels4 == net4.ifatm_labels # test mixed b-set/q-set: na = maa.shape[0] q = np.r_[n:na] newb = np.r_[0:12, na - 12 : na] newq = np.r_[12 : na - 12] kaa_newb = np.empty((na, na)) maa_newb = np.empty((na, na)) for newr, oldr in [(newb, b), (newq, q)]: for newc, oldc in [(newb, b), (newq, q)]: maa_newb[np.ix_(newr, newc)] = maa[np.ix_(oldr, oldc)] kaa_newb[np.ix_(newr, newc)] = kaa[np.ix_(oldr, oldc)] net5 = cb.mk_net_drms( maa_newb, kaa_newb, newb, uset=uset, ref=ref, sccoord=sccoord, conv=conv, g=g, reorder=False, ) assert np.allclose(net5.ifltma[:, newb], net.ifltma[:, b]) assert np.allclose(net5.ifltma[:, newq], net.ifltma[:, q]) net6 = cb.mk_net_drms( maa_newb, kaa_newb, newb, uset=uset, ref=ref, sccoord=sccoord, conv=conv, g=g, reorder=False, rbe3_indep_dof=123456, ) assert np.allclose(net6.ifltma, net5.ifltma) # translations match: assert np.allclose(net6.ifatm_sc[:3], net5.ifatm_sc[:3]) # rotations do not: assert not np.allclose(net6.ifatm_sc[3:], net5.ifatm_sc[3:]) vec = ytools.mkpattvec([3, 4, 5], len(newb), 6).ravel() assert (net5.ifatm_sc[:, newb[vec]] == 0.0).all() assert not (net6.ifatm_sc[:, newb[vec]] == 0.0).all()