def test_cbcheck_indeterminate_rb_norm2(): nas = op2.rdnas2cam("tests/nas2cam_csuper/nas2cam") se = 102 maa = nas["maa"][se] kaa = nas["kaa"][se] pv = np.any(maa, axis=0) pv = np.ix_(pv, pv) maa = maa[pv] kaa = kaa[pv] uset = nas["uset"][se] bset = n2p.mksetpv(uset, "p", "b") usetb = nas["uset"][se].iloc[bset] b = n2p.mksetpv(uset, "a", "b") q = ~b b = np.nonzero(b)[0] bref = n2p.mkdofpv(usetb, "b", [[3, 12356], [19, 3]])[0] # write to a string: with StringIO() as f: out = cb.cbcheck(f, maa, kaa, b, bref, usetb, em_filt=2, rb_norm=True) s = f.getvalue() s = s.splitlines() with open("tests/nas2cam_csuper/yeti_outputs/cbcheck_yeti_102_rbnorm.out") as f: sy = f.read().splitlines() assert s[0] == "Mass matrix is symmetric." assert s[1] == "Warning: mass matrix is not positive definite." assert s[2] == "Warning: stiffness matrix is not symmetric." compare_cbcheck_output(s, sy)
def test_cbcheck_reorder(): nas = op2.rdnas2cam("tests/nas2cam_csuper/nas2cam") se = 101 maa = nas["maa"][se] kaa = nas["kaa"][se] pv = np.any(maa, axis=0) pv = np.ix_(pv, pv) maa = maa[pv] kaa = kaa[pv] uset = nas["uset"][se] bset = n2p.mksetpv(uset, "p", "b") usetb = nas["uset"][se].iloc[bset] b = np.nonzero(n2p.mksetpv(uset, "a", "b"))[0] maa = cb.cbreorder(maa, b, last=True) kaa = cb.cbreorder(kaa, b, last=True) b += maa.shape[0] - len(b) # write to a string: with StringIO() as f: out = cb.cbcheck(f, maa, kaa, b, b[:6], usetb, em_filt=2) s = f.getvalue() s = s.splitlines() with open("tests/nas2cam_csuper/yeti_outputs/cbcheck_yeti_101.out") as f: sy = f.read().splitlines() assert s[0] == "Mass matrix is symmetric." assert s[1] == "Mass matrix is positive definite." assert s[2] == "Stiffness matrix is symmetric." compare_cbcheck_output(s, sy)
def test_cbcheck_determinate(): nas = op2.rdnas2cam("tests/nas2cam_csuper/nas2cam") se = 101 maa = nas["maa"][se] kaa = nas["kaa"][se] pv = np.any(maa, axis=0) pv = np.ix_(pv, pv) maa = maa[pv] kaa = kaa[pv] uset = nas["uset"][se] bset = n2p.mksetpv(uset, "p", "b") usetb = nas["uset"][se].iloc[bset] b = n2p.mksetpv(uset, "a", "b") q = ~b b = np.nonzero(b)[0] q = np.nonzero(q)[0] center = np.mean(usetb.iloc[::6, 1:], axis=0) rb = n2p.rbgeom_uset(usetb, center.values) # transform to single pt on centerline: # [b, q]_old = T*[b, q]_new # = [[rb, 0], [0, I]] * [b, q]_new T = np.zeros((len(b) + len(q), 6 + len(q))) T[:len(b), :6] = rb T[len(b):, 6:] = np.eye(len(q)) kaa = T.T @ kaa @ T maa = T.T @ maa @ T b = np.arange(6) # write to a string: with StringIO() as f: out = cb.cbcheck(f, maa, kaa, b, b[:6], em_filt=2) s = f.getvalue() s = s.splitlines() with open("tests/nas2cam_csuper/yeti_outputs/cbcheck_yeti_101_single.out" ) as f: sy = f.read().splitlines() assert s[0] == "Mass matrix is symmetric." assert s[1] == "Mass matrix is positive definite." assert s[2] == "Warning: stiffness matrix is not symmetric." j = [10] jy = [10] assert comptable(s, sy, j, jy, label="KBB =", skip=1) compare_cbcheck_output(s, sy)
def test_cbcoordchk2(): nas = op2.rdnas2cam("tests/nas2cam_csuper/nas2cam") se = 101 maa = nas["maa"][se] kaa = nas["kaa"][se] pv = np.any(maa, axis=0) pv = np.ix_(pv, pv) kaa = kaa[pv] uset = nas["uset"][se] b = n2p.mksetpv(uset, "a", "b") b = np.nonzero(b)[0] chk0 = cb.cbcoordchk(kaa, b, b[-6:], verbose=False) rbmodes0 = chk0.rbmodes[b] # maa = cb.cbreorder(maa, b, last=True) kaa = cb.cbreorder(kaa, b, last=True) b += kaa.shape[0] - len(b) bref = b[-6:] chk1 = cb.cbcoordchk(kaa, b, bref, verbose=False) rbmodes1 = chk1.rbmodes[b] assert np.allclose(chk1.coords, chk0.coords) assert np.allclose(rbmodes1, rbmodes0) assert np.allclose(chk1.maxerr, chk0.maxerr) assert chk0.refpoint_chk == chk1.refpoint_chk == "pass" assert abs(chk0.maxerr).max() < 1e-5 # a case where the refpoint_chk should be 'fail': chk2 = cb.cbcoordchk(kaa, b, [25, 26, 27, 31, 32, 33], verbose=False) assert chk2.refpoint_chk == "fail"
def test_calcAM(): nas = op2.rdnas2cam("tests/nas2cam_csuper/nas2cam") maa = nas["maa"][101] kaa = nas["kaa"][101] uset = nas["uset"][101] b = n2p.mksetpv(uset, "a", "b") q = ~b b = np.nonzero(b)[0] freq = np.arange(1.0, 80.0, 1.0) pv = np.any(maa, axis=0) q = q[pv] pv = np.ix_(pv, pv) maa = maa[pv] kaa = kaa[pv] baa = np.zeros_like(maa) baa[q, q] = 2 * 0.05 * np.sqrt(kaa[q, q]) nb = len(b) bdrm = np.zeros((nb, maa.shape[0])) bdrm[:nb, :nb] = np.eye(nb) AM1 = frclim.calcAM((maa, baa, kaa, b), freq) AM2 = frclim.calcAM((maa, baa, kaa, bdrm), freq) assert np.allclose(AM1, AM2)
def test_cbcheck_unit_convert(): nas = op2.rdnas2cam("tests/nas2cam_csuper/nas2cam") se = 101 maa = nas["maa"][se] kaa = nas["kaa"][se] pv = np.any(maa, axis=0) pv = np.ix_(pv, pv) maa = maa[pv] kaa = kaa[pv] uset = nas["uset"][se] bset = n2p.mksetpv(uset, "p", "b") usetb = nas["uset"][se].iloc[bset] b = n2p.mksetpv(uset, "a", "b") q = ~b b = np.nonzero(b)[0] q = np.nonzero(q)[0] # write to a string: with StringIO() as f: out = cb.cbcheck( f, maa, kaa, b, b[:6], uset=usetb, em_filt=2, conv=[1 / 25.4, 0.005710147154735817], uref=[600, 150, 150], rb_norm=False, ) s = f.getvalue() s = s.splitlines() with open("tests/nas2cam_csuper/yeti_outputs/cbcheck_yeti_101_unitconv.out" ) as f: sy = f.read().splitlines() assert s[0] == "Mass matrix is symmetric." assert s[1] == "Mass matrix is positive definite." assert s[2] == "Stiffness matrix is symmetric." compare_cbcheck_output(s, sy)
def test_wtextseout(): nas = op2.rdnas2cam("tests/nas2cam_csuper/nas2cam") se = 101 maa = nas["maa"][se] kaa = nas["kaa"][se] pv = np.any(maa, axis=0) pv = np.ix_(pv, pv) maa = maa[pv] kaa = kaa[pv] uset = nas["uset"][se] bset = n2p.mksetpv(uset, "p", "b") usetb = nas["uset"][se].iloc[bset] b = n2p.mksetpv(uset, "a", "b") q = ~b b = np.nonzero(b)[0] baa = np.zeros_like(maa) baa[q, q] = 2 * 0.05 * np.sqrt(kaa[q, q]) name = "_wtextseout_test_" pre = "tests/nas2cam_csuper/yeti_outputs/se101y" try: nastran.wtextseout( name, se=101, maa=maa, kaa=kaa, baa=baa, bset=b, uset=usetb, spoint1=9900101, ) names, mats, f, t = op4.load(name + ".op4", into="list") namesy, matsy, fy, ty = op4.load(pre + ".op4", into="list") assert names == namesy assert f == fy assert t == ty for i, (m, my) in enumerate(zip(mats, matsy)): assert np.allclose(m, my) lst = (".asm", ".pch") for ext in lst: with open(name + ext) as f: s = f.read() with open(pre + ext) as f: sy = f.read() assert s.replace(name.upper(), "SE101") == sy finally: for ext in (".asm", ".pch", ".op4"): if os.path.exists(name + ext): os.remove(name + ext) # test the additional writing of matrices: mug1 = np.arange(12).reshape(3, 4) mef1 = 10 * mug1 try: nastran.wtextseout( name, se=101, maa=maa, kaa=kaa, baa=baa, bset=b, uset=usetb, spoint1=9900101, mug1=mug1, mef1=mef1, ) names, mats, f, t = op4.load(name + ".op4", into="list") namesy, matsy, fy, ty = op4.load(pre + ".op4", into="list") assert names == namesy for i, (m, my) in enumerate(zip(mats, matsy)): if names[i] in ("mug1", "mef1"): assert np.allclose(m, eval(names[i])) else: assert f[i] == fy[i] assert t[i] == ty[i] assert np.allclose(m, my) lst = (".asm", ".pch") for ext in lst: with open(name + ext) as f: s = f.read() with open(pre + ext) as f: sy = f.read() assert s.replace(name.upper(), "SE101") == sy finally: for ext in (".asm", ".pch", ".op4", ".baa_dmig"): if os.path.exists(name + ext): os.remove(name + ext)
def test_asm2uset(): asm1 = """ $ SE101 ASSEMBLY FILE FOR RESIDUAL RUN...INCLUDE IN BULK DATA $ SEBULK 101 EXTOP4 MANUAL 101 SECONCT 101 0 NO 3 3 11 11 19 19 27 27 $ $ COORDINATE SYSTEM DATA $ $ Coordinate 10: CORD2R* 10 0 0.00000000e+00 0.00000000e+00* * 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00* * 0.00000000e+00 1.00000000e+00 0.00000000e+00 $ $ BOUNDARY GRID DATA $ GRID* 3 0 600.00000000 0.00000000 * 300.00000000 0 GRID* 11 0 600.00000000 300.00000000 * 300.00000000 10 GRID* 19 0 600.00000000 300.00000000 * 0.00000000 0 GRID* 27 0 600.00000000 0.00000000 * 0.00000000 0 $ SECONCT 101 0 NO 9900101 THRU 9900122 9900101 THRU 9900122 $ SPOINT 9900101 THRU 9900122 """ with StringIO(asm1) as f: uset1, cord1, bset1 = nastran.asm2uset(f) cords1 = nastran.rdcord2cards(f) # make the uset manually for testing: rng = range(9900101, 9900123) dof = [[3, 123456], [11, 123456], [19, 123456], [27, 123456]] + [ [i, 0] for i in rng ] nasset = np.zeros(4 + 22, np.int64) nasset[:4] = n2p.mkusetmask("b") nasset[4:] = n2p.mkusetmask("q") xyz = np.array( [ [600.0, 0.0, 300.0], [600.0, 300.0, 300.0], [600.0, 300.0, 0.0], [600.0, 0.0, 0.0], ] + [[0.0, 0.0, 0.0] for i in rng] ) uset1_man = n2p.make_uset(dof=dof, nasset=nasset, xyz=xyz) # fix up grid 11 coords: uset1_man.loc[(11, 2), "x"] = 10 uset1_man.loc[(11, 4):(11, 6), "x":"z"] = [ [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], ] # assert uset1.equals(uset1_man) assert np.allclose(uset1.reset_index(), uset1_man.reset_index()) assert (bset1 == n2p.mksetpv(uset1, "a", "b")).all() assert len(cords1) == len(cord1) for k, v in cords1.items(): assert np.allclose(cord1[k], v) asm2 = """ $ SE101 ASSEMBLY FILE FOR RESIDUAL RUN...INCLUDE IN BULK DATA $ $1111111222222223333333344444444555555556666666677777777888888889999999900000000 SEBULK 101 EXTOP4 MANUAL 101 SECONCT 101 0 NO 3 3 110 110 19 19 27 27 $ $ COORDINATE SYSTEM DATA $ $ Coordinate 10: CORD2R* 10 0 0.00000000e+00 0.00000000e+00* * 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00* * 0.00000000e+00 1.00000000e+00 0.00000000e+00 $ $ BOUNDARY GRID DATA $ GRID* 3 0 600.00000000 0.00000000 * 300.00000000 0 GRID* 19 0 600.00000000 300.00000000 * 0.00000000 0 GRID* 27 0 600.00000000 0.00000000 * 0.00000000 0 $ SPOINT 110 """ with StringIO(asm2) as f: uset2, cord2, bset2 = nastran.asm2uset(f) cords2 = nastran.rdcord2cards(f) # make the uset manually for testing: dof = [[3, 123456], [110, 0], [19, 123456], [27, 123456]] nasset = np.zeros(4, np.int64) nasset[:] = n2p.mkusetmask("b") nasset[1] = n2p.mkusetmask("q") xyz = np.array( [[600.0, 0.0, 300.0], [0.0, 0.0, 0.0], [600.0, 300.0, 0.0], [600.0, 0.0, 0.0]] ) uset2_man = n2p.make_uset(dof=dof, nasset=nasset, xyz=xyz) # assert uset2.equals(uset2_man) assert np.allclose(uset2.reset_index(), uset2_man.reset_index()) assert (bset2 == n2p.mksetpv(uset2, "a", "b")).all() assert len(cords2) == len(cord2) for k, v in cords2.items(): assert np.allclose(cord2[k], v)
def test_rbmultchk(): nas = op2.rdnas2cam("tests/nas2cam_csuper/nas2cam") se = 101 maa = nas["maa"][se] kaa = nas["kaa"][se] pv = np.any(maa, axis=0) pv = np.ix_(pv, pv) maa = maa[pv] kaa = kaa[pv] uset = nas["uset"][se] bset = n2p.mksetpv(uset, "p", "b") usetb = nas["uset"][se].iloc[bset] b = n2p.mksetpv(uset, "a", "b") q = ~b b = np.nonzero(b)[0] grids = [[11, 123456], [45, 123456], [60, 123456]] drm101, dof101 = n2p.formtran(nas, 101, grids) # write and read a file: f = tempfile.NamedTemporaryFile(delete=False) name = f.name f.close() rb = n2p.rbgeom_uset(usetb) cb.rbmultchk(name, drm101, "DRM101", rb) with open(name) as f: sfile = f.read() os.remove(name) # test rbscale and unit scale: with StringIO() as f: cb.rbmultchk(f, 0.00259 * drm101, "DRM101", 100 * rb) s = f.getvalue() pos = s.find(" which is: ") pos2 = s[pos:].find("\n") assert math.isclose(float(s[pos + 10 : pos + pos2]), 100) s = s.splitlines() table, nj1 = gettable(s, 15, 0, "Absolute Maximums", 3) sbe = np.array( [ [600, 300, 300, 0.00259], [600, 300, 300, 0.00259], [600, 300, 300, 0.00259], [150, -930, 150, 0.00259], [600, 300, 300, 0.00259], [150, -930, 150, 0.00259], ] ) assert np.allclose(table[:, 1:5], sbe) # write to a string: with StringIO() as f: cb.rbmultchk(f, drm101, "DRM101", rb) s = f.getvalue() assert sfile == s # add q-set rows to rb: nq = np.count_nonzero(q) rb2 = np.vstack((rb, np.zeros((nq, 6)))) with StringIO() as f: cb.rbmultchk(f, drm101, "DRM101", rb2) s2 = f.getvalue() assert s2 == s # check results when b-set are last: drm101_last = np.hstack((drm101[:, q], drm101[:, b])) with StringIO() as f: cb.rbmultchk(f, drm101_last, "DRM101", rb, bset="last") s2 = f.getvalue() assert s2 == s # check results when b-set are last ... using pv: with StringIO() as f: bsetpv = np.zeros((len(b) + nq), bool) bsetpv[-len(b) :] = True cb.rbmultchk(f, drm101_last, "DRM101", rb, bset=bsetpv) s2 = f.getvalue() assert s2 == s with StringIO() as f: assert_raises( ValueError, cb.rbmultchk, f, drm101, "asdf", rb, bset="bad string" ) # trim q-set columns out of drm: labels = [str(i[0]) + " " + str(i[1]) for i in dof101] with StringIO() as f: cb.rbmultchk( f, drm101[:, b], "DRM101", rb, drm2=drm101[:, b], prtnullrows=True, labels=labels, ) s2 = f.getvalue() # row 16 is now all zeros ... not comparable drm2 = drm101.copy() drm2[15] = 0 with StringIO() as f: cb.rbmultchk(f, drm2, "DRM101", rb, drm2=drm2, prtnullrows=True, labels=labels) s3 = f.getvalue() assert s2 == s3 s = s.splitlines() with open("tests/nas2cam_csuper/yeti_outputs/rbmultchk_yeti_101.out") as f: sy = f.read().splitlines() j = [2] jy = [2] assert comptable(s, sy, j, jy, label="Extreme ", skip=3, col=11) assert comptable(s, sy, j, jy, label=" Row ", skip=2, col=68) assert comptable(s, sy, j, jy, label=" Row ", skip=2) assert comptable(s, sy, j, jy, label=" Row ", skip=2)
def test_cbtf(): nas = op2.rdnas2cam("tests/nas2cam_csuper/nas2cam") maa = nas["maa"][102] kaa = nas["kaa"][102] uset = nas["uset"][102] b = n2p.mksetpv(uset, "a", "b") q = ~b b = np.nonzero(b)[0] rb = n2p.rbgeom_uset(uset.iloc[b], 3) freq = np.arange(1.0, 80.0, 1.0) a = rb[:, :1] a2 = a.dot(np.ones((1, len(freq)))) a3 = rb[:, 0] pv = np.any(maa, axis=0) q = q[pv] pv = np.ix_(pv, pv) maa = maa[pv] kaa = kaa[pv] baa1 = np.zeros_like(maa) baa1[q, q] = 2 * 0.05 * np.sqrt(kaa[q, q]) baa2 = 0.1 * np.random.randn(*maa.shape) baa2 = baa2.dot(baa2.T) bb = np.ix_(b, b) for baa in [baa1, baa2]: for delq in [False, True]: if delq: m = maa[bb] c = baa[bb] k = kaa[bb] else: m = maa c = baa k = kaa tf = cb.cbtf(m, c, k, a, freq, b) tf2 = cb.cbtf(m, c, k, a2, freq, b) save = {} tf3 = cb.cbtf(m, c, k, a3, freq, b, save) tf4 = cb.cbtf(m, c, k, a2, freq, b, save) assert np.all(freq == tf.freq) assert np.all(freq == tf2.freq) assert np.all(freq == tf3.freq) assert np.all(freq == tf4.freq) assert np.allclose(tf.frc, tf2.frc) assert np.allclose(tf.a, tf2.a) assert np.allclose(tf.d, tf2.d) assert np.allclose(tf.v, tf2.v) assert np.allclose(tf.frc, tf3.frc) assert np.allclose(tf.a, tf3.a) assert np.allclose(tf.d, tf3.d) assert np.allclose(tf.v, tf3.v) assert np.allclose(tf.frc, tf4.frc) assert np.allclose(tf.a, tf4.a) assert np.allclose(tf.d, tf4.d) assert np.allclose(tf.v, tf4.v) # confirm proper solution: O = 2 * np.pi * freq velo = 1j * O * tf.d acce = 1j * O * velo f = m.dot(acce) + c.dot(velo) + k.dot(tf.d) assert np.allclose(acce, tf.a) assert np.allclose(velo, tf.v) assert np.allclose(f[b], tf.frc) if not delq: assert np.allclose(f[q], 0) assert_raises(ValueError, cb.cbtf, maa, baa1, kaa, a2[:, :3], freq, b) assert_raises(ValueError, cb.cbtf, maa, baa1, kaa, a2[:3, :], freq, b)
def test_cbcheck_determinate(): nas = op2.rdnas2cam("tests/nas2cam_csuper/nas2cam") se = 101 maa = nas["maa"][se] kaa = nas["kaa"][se] pv = np.any(maa, axis=0) pv = np.ix_(pv, pv) maa = maa[pv] kaa = kaa[pv] uset = nas["uset"][se] bset = n2p.mksetpv(uset, "p", "b") usetb = nas["uset"][se].iloc[bset] b = n2p.mksetpv(uset, "a", "b") q = ~b b = np.nonzero(b)[0] q = np.nonzero(q)[0] center = np.mean(usetb.iloc[::6, 1:], axis=0) rb = n2p.rbgeom_uset(usetb, center.values) # transform to single pt on centerline: # [b, q]_old = T*[b, q]_new # = [[rb, 0], [0, I]] * [b, q]_new T = np.zeros((len(b) + len(q), 6 + len(q))) T[: len(b), :6] = rb T[len(b) :, 6:] = np.eye(len(q)) kaa = T.T @ kaa @ T maa = T.T @ maa @ T b = np.arange(6) # write to a string: with StringIO() as f: out = cb.cbcheck(f, maa, kaa, b, b[:6], em_filt=2) s = f.getvalue() s = s.splitlines() with open("tests/nas2cam_csuper/yeti_outputs/cbcheck_yeti_101_single.out") as f: sy = f.read().splitlines() assert s[0] == "Mass matrix is symmetric." assert s[1] == "Mass matrix is positive definite." assert s[2] == "Warning: stiffness matrix is not symmetric." j = [10] jy = [10] assert comptable(s, sy, j, jy, label="KBB =", skip=1) compare_cbcheck_output(s, sy) # check with no em filter: with StringIO() as f: out2 = cb.cbcheck(f, maa, kaa, b, b[:6]) s2 = f.getvalue() s2 = s2.splitlines() s_unique = [i for i in s if i not in s2] # ['Printing only the modes with at least 2.0% effective mass.', # 'The sum includes all modes.'] s2_unique = [i for i in s2 if i not in s] # [' 5 7.025 0.00 0.00 0.00 0.00 0.88 0.00', # ' 6 7.025 0.00 0.00 0.00 0.00 0.00 0.00', # ' 7 10.913 0.00 0.00 0.00 0.00 0.00 1.52', # ' 11 25.135 0.00 0.00 0.00 0.00 0.00 0.42', # ' 12 25.140 1.03 0.00 0.00 0.00 0.00 0.00', # ' 13 42.173 0.00 0.00 0.00 0.51 0.00 0.00', # ' 14 42.193 0.00 0.00 1.04 0.00 1.02 0.00', # ' 16 46.895 0.00 0.00 0.00 0.00 0.00 0.00', # ' 17 69.173 0.00 0.13 0.00 0.00 0.00 0.99'] assert len(s2) > len(s) assert len(s_unique) == 2 assert len(s2_unique) == 9
def test_cbcheck_indeterminate(): nas = op2.rdnas2cam("tests/nas2cam_csuper/nas2cam") se = 101 maa = nas["maa"][se] kaa = nas["kaa"][se] pv = np.any(maa, axis=0) pv = np.ix_(pv, pv) maa = maa[pv] kaa = kaa[pv] uset = nas["uset"][se] bset = n2p.mksetpv(uset, "p", "b") usetb = nas["uset"][se].iloc[bset] b = n2p.mksetpv(uset, "a", "b") q = ~b b = np.nonzero(b)[0] # write and read a file: f = tempfile.NamedTemporaryFile(delete=False) name = f.name f.close() # m, k, bset, rbs, rbg, rbe, usetconv = cb.cbcheck( out = cb.cbcheck(name, maa, kaa, b, b[:6], uset, em_filt=2) with open(name) as f: sfile = f.read() os.remove(name) assert (out.m == maa).all() assert (out.k == kaa).all() assert out.uset.equals(usetb) rbg = n2p.rbgeom_uset(out.uset) assert np.allclose(rbg, out.rbg) rbg_s = np.vstack((la.solve(rbg[:6].T, rbg.T).T, np.zeros((q[q].size, 6)))) assert abs(out.rbs - rbg_s).max() < 1e-5 assert abs(out.rbe - rbg_s).max() < 1e-5 # write to a string: with StringIO() as f: out = cb.cbcheck(f, maa, kaa, b, b[:6], usetb, em_filt=2) s = f.getvalue() assert sfile == s s = s.splitlines() with open("tests/nas2cam_csuper/yeti_outputs/cbcheck_yeti_101.out") as f: sy = f.read().splitlines() assert s[0] == "Mass matrix is symmetric." assert s[1] == "Mass matrix is positive definite." assert s[2] == "Stiffness matrix is symmetric." compare_cbcheck_output(s, sy) with StringIO() as f: out = cb.cbcheck(f, maa, kaa, b, b[:6], usetb, em_filt=2, conv="e2m") out2 = cb.cbcheck(f, out.m, out.k, b, b[:6], out.uset, em_filt=2, conv="m2e") assert np.allclose(out2.uset, usetb) assert np.allclose(maa, out2.m) assert np.allclose(kaa, out2.k) # check for error catches: with StringIO() as f: assert_raises( ValueError, cb.cbcheck, f, maa, kaa, b, b[:6], usetb.iloc[:-6], em_filt=2 )
def add(self, nas, drdefs, uf_reds=None, method="replace"): """ Add data recovery definitions for an event or set of modes. Parameters ---------- nas : dictionary This is the nas2cam dictionary: ``nas = pyyeti.nastran.op2.rdnas2cam()``. Only used if at least one category in `drdefs` is for an upstream superelement (se != 0) and has a data recovery matrix. Can be anything (like None) if not needed. drdefs : :class:`DR_Def` instance or None Contains the data recovery definitions for, typically, one superelement. See :class:`DR_Def`. If None, this routine does nothing. uf_reds : 4-element tuple or None; optional If not None, this is the uncertainty factors in "reds" order: [rigid, elastic, dynamic, static]. The values in `uf_reds` either replace or multiply the original values (see `method`). Use a value of None for a particular uncertainty value to retain the original value unmodified. This `uf_reds` option can be useful when uncertainty factors are event specific rather than data recovery category specific or you need to add in a forcing function uncertainty factor. For example, to reset the dynamic uncertainty factor to 1.1 while leaving the other values unchanged:: uf_reds=(None, None, 1.1, None) DR.add(nas, drdefs, uf_reds) For another example, to increase the rigid-body and elastic uncertainty factors by a factor of 1.05 while leaving the other two values unchanged:: uf_reds=(1.05, 1.05, None, None) DR.add(nas, drdefs, uf_reds, method='multiply') method : string or function (callable); optional Specifies how to update the "uf_reds" settings: ============ ======================================== `method` Description ============ ======================================== 'replace' Values in `uf_reds` (that are not None) replace old values. 'multiply' Values in `uf_reds` (that are not None) multiply the old values. callable Values are computed by function (or any callable). The function is only called for entries where `uf_reds` is not None. The call is: ``method(old_value, new_value)``. See examples below. ============ ======================================== Notes ----- Typically called once for each superelement where data recovery is requested. The attributes `Info`, `UF_reds` and `Vars` are all updated on each call to this routine. See :class:`DR_Def` for a discussion about how the order of data recovery is determined. In summary: :func:`DR_Event.add` determines the order of :class:`DR_Def` instances, and :func:`DR_Def.add` determines the order of data recovery categories within each :class:`DR_Def` instance. :func:`DR_Event.set_dr_order` can be used to modify the final order. Following are some examples of providing a function for the `method` parameter. Note that the function is only called when the `uf_reds` value is not None. These two calls are equivalent:: DR.add(nas, drdefs, uf_reds, 'replace') DR.add(nas, drdefs, uf_reds, lambda old, new: new) These are also equivalent:: DR.add(nas, drdefs, uf_reds, 'multiply') DR.add(nas, drdefs, uf_reds, lambda old, new: old*new) As a final example, if you wanted to add values onto the previous settings instead of multiply, you could do this:: DR.add(nas, drdefs, uf_reds, lambda old, new: old+new) Raises ------ ValueError When the there are duplicate category names. """ if drdefs is None: return for name, drminfo in drdefs.items(): if name == "_vars": continue try: active = drminfo.active except AttributeError: active = "yes" if active != "yes": continue if name in self.Info: raise ValueError( f'"{name}" data recovery category already defined') # variables for how to do data recovery: self.Info[name] = copy.copy(drdefs[name]) # reset uf_reds if input: if uf_reds is not None: self.Info[name].uf_reds = _merge_uf_reds( self.Info[name].uf_reds, uf_reds, method=method) # collect all sets of uncertainty factors together for the # apply_uf routine later: uf_reds_cur = self.Info[name].uf_reds if uf_reds_cur not in self.UF_reds: self.UF_reds.append(uf_reds_cur) se_last = -2 # apply ULVS to all drms and put in DR: for se, dct in drdefs["_vars"].drms.items(): if not dct: continue if se not in self.Vars: self.Vars[se] = {} if se not in (0, se_last): ulvs = nas["ulvs"][se] uset = nas["uset"][se] # Want bset partition from aset. But note that in the # .asm, .pch approach to SE's, it is valid in Nastran # to just put all b-set & q-set in a generic a-set. # If that's the case, find q-set by finding the # spoints: bset = n2p.mksetpv(uset, "a", "b") # bool type if bset.all(): # manually check for q-set in the a-set: aset = np.nonzero(n2p.mksetpv(uset, "p", "a"))[0] dof = uset.index.get_level_values("dof")[aset] qset = dof == 0 # spoints bset = ~qset bset = np.nonzero(bset)[0] Lb = len(bset) se_last = se for name, mat in dct.items(): if name in self.Vars[se]: raise ValueError(f'"{name}" is already in Vars[{se}]') if se == 0: self.Vars[se][name] = mat elif mat.shape[1] > Lb: self.Vars[se][name] = mat @ ulvs else: self.Vars[se][name] = mat @ ulvs[bset] # put all nondrms in DR: for se, dct in drdefs["_vars"].nondrms.items(): if se not in self.Vars: self.Vars[se] = {} for name, mat in dct.items(): if name in self.Vars[se]: raise ValueError(f'"{name}" is already in Vars[{se}]') self.Vars[se][name] = mat