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()
def test_mk_net_drms_6dof(): # same as above, but reduced to single point interface 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") mk = op4.load(os.path.join(pth, "inboard.op4")) maa = mk["mxx"][0] kaa = mk["kxx"][0] uset, coords = nastran.bulk2uset(os.path.join(pth, "inboard.asm")) n = uset.shape[0] b = np.arange(n) q = np.arange(n, maa.shape[0]) ttl = maa.shape[0] # reduce to single point interface: rb = n2p.rbgeom_uset(uset, [600, 150, 150]) # old = {b_24} = {rb.T @ b_6} = [rb.T 0_6?] {b_6} # {q_?} {q_?} [0_?6 I??] {q_?} trans = np.zeros((len(q) + 6, ttl)) trans[:6, :n] = rb.T trans[6:, n:] = np.eye(len(q)) maa = trans @ maa @ trans.T kaa = trans @ kaa @ trans.T # no conversion, no coordinate change: g = 9.80665 n = 6 b = np.arange(n) net = cb.mk_net_drms(maa, kaa, b, g=g) net2 = cb.mk_net_drms(maa, kaa, b, g=g, bsubset=b) l_sc = net.ifltma_sc[:, :n] l_lv = net.ifltma_lv[:, :n] l_scd = net.ifltmd_sc[:, :n] l_lvd = net.ifltmd_lv[:, :n] a_sc = net.ifatm_sc[:, :n] a_lv = net.ifatm_lv[:, :n] c_sc = net.cgatm_sc[:, :n] c_lv = net.cgatm_lv[:, :n] sbe = np.eye(6) sbe[:3] *= 1 / g assert np.allclose(a_sc, sbe) 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 assert abs(sbe - l_sc).max() < 0.0005 Tsc2lv = np.eye(6) 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() assert np.allclose((Tsc2lv @ l_sc), l_lv) # height and mass values from cbcheck tutorial (and then refined): m_kg = 1.75505183 h_m = 1039.998351 - 600 assert abs(net.height_lv - h_m) < 0.0001 assert abs(net.weight_lv - m_kg * g) < 0.0001 assert abs(net.height_sc - h_m) < 0.0001 assert abs(net.weight_sc - m_kg * g) < 0.0001 assert net.scaxial_sc == 0 assert net.scaxial_lv == 0 compare_nets(net, net2)
def test_cglf_moment_signs(): pth = os.path.dirname(inspect.getfile(cb)) pth = os.path.join(pth, "..") pth = os.path.join(pth, "tests") pth = os.path.join(pth, "cla_test_data") se = 101 uset, coords = nastran.bulk2uset(os.path.join(pth, "outboard.asm")) dct = op4.read(os.path.join(pth, "outboard.op4")) maa = dct["mxx"] kaa = dct["kxx"] atm = dct["mug1"] ltm = dct["mef1"] pch = os.path.join(pth, "outboard.pch") atm_labels = [ "Grid {:4d}-{:1d}".format(grid, dof) for grid, dof in nastran.rddtipch(pch) ] ltm_labels = [ "CBAR {:4d}-{:1d}".format(cbar, arg) for cbar, arg in nastran.rddtipch(pch, "tef1") ] nb = uset.shape[0] nq = maa.shape[0] - nb bset = np.arange(nb) qset = np.arange(nq) + nb ref = [600.0, 150.0, 150.0] g = 9806.65 # use addgrid to get coordinate transformations from lv to sc: cid = [1, 0, 0] A = [0, 0, 0] # define sc in terms of lv coords: # (all drawn out by hand) BC = [ [[0, 0, 1.0], [1.0, 0, 0]], # lv x is up [[0, 0, -1.0], [0, 1.0, 0]], # lv y is up [[-1.0, 0, 0.0], [0, 0, 1.0]], # lv z is up [[0, 0, -1.0], [-1.0, 0, 0]], # lv x is down [[0, 0, 1.0], [0, -1.0, 0]], # lv y is down [[0, -1.0, 0], [0, 0, -1.0]], # lv z is down ] Ts = [] nets = [] rb = n2p.rbgeom_uset(uset, ref) rbcglfa = [] for bc in BC: CI = n2p.mkusetcoordinfo([cid, A, *bc], None, {}) T = CI[2:] Ts.append(T) net = cb.mk_net_drms(maa, kaa, bset, uset=uset, ref=ref, g=g, sccoord=T) nets.append(net) rba = net.cglfa[:, :24] @ rb rbcglfa.append(rba) # sc rows: assert np.all(np.sign(rba[1, [1, 5]]) == np.sign(rba[3, [1, 5]])) assert np.all(np.sign(rba[2, [2, 4]]) == np.sign(rba[4, [2, 4]])) # lv rows: assert np.all(np.sign(rba[6, [1, 5]]) == np.sign(rba[8, [1, 5]])) assert np.all(np.sign(rba[7, [2, 4]]) == np.sign(rba[9, [2, 4]])) wh_sc = nets[0].weight_sc * nets[0].height_sc wh_lv = nets[0].weight_lv * nets[0].height_lv n = nets[0].cgatm_sc.shape[1] # x is down: cgdrm = np.vstack( ( # 5 s/c rows nets[0].cgatm_sc[:3], -nets[0].ifltma_sc[5] / wh_sc, nets[0].ifltma_sc[4] / wh_sc, # 5 l/v rows nets[0].cgatm_lv[:3], -nets[0].ifltma_lv[5] / wh_lv, nets[0].ifltma_lv[4] / wh_lv, # 4 RSS rows ... filled in during data recovery np.zeros((4, n)), ) ) assert np.allclose(cgdrm, nets[0].cglfa)
return ["{} {:4d}-{:1d}".format(lbl, g, i) for g, i in id_dof] atm_labels = getlabels("Grid", nastran.rddtipch(pch, "tug1")) # ltm_labels = getlabels('CBAR', nastran.rddtipch(pch, 'tef1')) iflabels = getlabels("Grid", uset[:, :2].astype(int)) # setup CLA parameters: mission = "Micro Space Station" nb = uset.shape[0] nq = maa.shape[0] - nb bset = np.arange(nb) qset = np.arange(nq) + nb ref = [600.0, 150.0, 150.0] g = 9806.65 net = cb.mk_net_drms(maa, kaa, bset, uset=uset, ref=ref, g=g) # run cbcheck: chk = cb.cbcheck("outboard_cbcheck.out", maa, kaa, bset, bref=np.arange(6), uset=uset, uref=ref) # define some defaults for data recovery: defaults = dict(se=se, uf_reds=(1, 1, 1.25, 1), srsfrq=np.arange(0.1, 50.1, 0.1), srsQs=(10, 33))