def test_mass_solid_1(self): # passes model = BDF(debug=False, log=None) bdfname = os.path.join(mesh_utils_path, 'test_mass.dat') model.read_bdf(bdfname, xref=True) # hexa - psolid - nsm = 0 hexa = model.elements[7] mass = 0.2 volume = 2. # l * w * h = 1 * 1 * 2 rho = 0.1 E = 1.0 G = 2.0 nu = 3.0 centroid = np.array([0.5, 0.5, 1.0]) self.verify_psolid_element(hexa, mass, volume, centroid, rho, E, G, nu) # tetra - psolid tetra = model.elements[8] mass = 1 / 30. volume = 1 / 3. # 1/3 * b * h = 1/3 * 0.5 * 2.0 rho = 0.1 E = 1.0 G = 2.0 nu = 3.0 centroid = np.array([0.5, 0.25, 0.5]) self.verify_psolid_element(tetra, mass, volume, centroid, rho, E, G, nu) # penta - psolid penta = model.elements[9] mass = 0.1 volume = 1.0 # b * h = 0.5 * 2 rho = 0.1 E = 1.0 G = 2.0 nu = 3.0 centroid = np.array([2 / 3., 1 / 3., 1.]) self.verify_psolid_element(penta, mass, volume, centroid, rho, E, G, nu) #wtmass = 0.00259 mass, cg, I = mass_properties(model, element_ids=None, mass_ids=None, reference_point=None, sym_axis=None, scale=None) model.params['WTMASS'].values[0] = 1.0 mass2, cg, I = mass_properties(model, element_ids=None, mass_ids=None, reference_point=None, sym_axis=None, scale=None) assert np.allclose(mass, 0.005311658333), 'mass=%s' % mass assert np.allclose(mass2, 2.050833333), 'mass2=%s' % mass2
def test_conm2(self): """tests a conm2""" log = get_logger(level='warning', encoding='utf-8') model = BDF(debug=False, log=log) nid = 10 eid = 20 massi = 42. model.add_conm2(eid, nid, massi, cid=0, X=None, I=None, comment='conm2') model.add_grid(nid, [0., 0., 0.]) model.validate() model.cross_reference() model = save_load_deck(model, run_convert=False) pids_to_mass, mass_type_to_mass = model.get_mass_breakdown( property_ids=None) assert len(pids_to_mass) == 0, pids_to_mass assert mass_type_to_mass['CONM2'] == 42., mass_type_to_mass mass, cg, I = mass_properties(model, element_ids=None, mass_ids=None, reference_point=None, sym_axis=None, scale=None) assert np.allclose(mass, massi), 'massi=%s mass=%s' % (massi, mass) assert np.array_equal(cg, np.zeros(3)) assert np.array_equal(I, np.zeros(6)) mass, cg, I = mass_properties(model, element_ids=None, mass_ids=[20], reference_point=None, sym_axis=None, scale=None) assert np.allclose(mass, massi), 'massi=%s mass=%s' % (massi, mass) assert np.array_equal(cg, np.zeros(3)) assert np.array_equal(I, np.zeros(6)) mass, cg, I = mass_properties(model, element_ids=None, mass_ids=[42], reference_point=None, sym_axis=None, scale=None) ## TODO: is this reasonable behavior assert np.allclose(mass, 0.), 'massi=%s mass=%s' % (massi, mass)
def test_bdf_01(self): """checks solid_bending.dat""" bdf_filename = os.path.join(MODEL_PATH, 'solid_bending', 'solid_bending.bdf') log = get_logger(log=None, level='error', encoding='utf-8') self.run_bdf('', bdf_filename, log=log) fem1, fem2, diff_cards = self.run_bdf('', bdf_filename, xref=True, log=log) diff_cards2 = list(set(diff_cards)) diff_cards2.sort() assert len(diff_cards2) == 0, diff_cards2 for fem in [fem1, fem2]: assert len(fem.params) == 2, 'len(params) = %i' % len(fem.params) assert len(fem.coords) == 1, 'len(coords) = %i' % len(fem.coords) assert len(fem.nodes) == 72, 'len(nodes) = %i' % len(fem.nodes) assert len( fem.materials) == 1, 'len(materials) = %i' % len(fem.materials) assert len( fem.elements) == 186, 'len(elements) = %i' % len(fem.elements) assert len( fem.methods) == 0, 'len(methods) = %i' % len(fem.methods) assert len(fem.properties) == 1, 'len(properties) = %i' % len( fem.properties) mass, cg, unused_I = mass_properties(fem1) assert allclose(mass, 6.0), 'mass = %s' % mass cg_exact = array([0.5, 1., 1.5]) for i, (cgi, cgie) in enumerate(zip(cg, cg_exact)): assert allclose(cgi, cgie), 'i=%s cg=%s' % (i, str(cg)) compare_mass_cg_inertia(fem1) compare_mass_cg_inertia(fem1, reference_point=None)
def _run_mass_properties(model2, nnodes, nelements, run_mass_properties=True): """helper method""" if not (run_mass_properties and nelements): return if nelements > 1 and nnodes == 0: # pragma: no cover raise RuntimeError('no nodes exist') mass1, cg1, inertia1 = mass_properties(model2, reference_point=None, sym_axis=None) mass2, cg2, inertia2 = mass_properties_nsm(model2, reference_point=None, sym_axis=None) #if not quiet: #if model2.wtmass != 1.0: #print('weight = %s' % (mass1 / model2.wtmass)) #print('mass = %s' % mass1) #print('cg = %s' % cg1) #print('Ixx=%s, Iyy=%s, Izz=%s \nIxy=%s, Ixz=%s, Iyz=%s' % tuple(inertia1)) assert np.allclose(mass1, mass2), 'mass1=%s mass2=%s' % (mass1, mass2) assert np.allclose(cg1, cg2), 'mass=%s\ncg1=%s cg2=%s' % (mass1, cg1, cg2) if not np.allclose(inertia1, inertia2, atol=1e-5): # pragma: no cover raise ValueError( 'mass=%s cg=%s\ninertia1=%s\ninertia2=%s\ndinertia=%s' % (mass1, cg1, inertia1, inertia2, inertia1 - inertia2)) unused_mass3, unused_cg3, unused_inertia3 = mass_properties_breakdown( model2)[:3]
def end_checks(model): """various checks""" model.validate() model._verify_bdf(xref=False) model.cross_reference() model._verify_bdf(xref=True) model.uncross_reference() model.cross_reference() model.pop_xref_errors() mass, cg, inertia = mass_properties(model) assert mass > 0, 'mass=%s, cg=%s, inertia=%s' % (mass, cg, inertia)
def check_solid(self, model, eid, etype, pid, ptype, mid, mtype, nsm, rho, V): """checks that various solid methods work""" mass = rho * V element = model.elements[eid] assert max(element.node_ids) > 0 assert pid in model.properties, 'pid is missing for\n%s' % str(element) self.assertEqual(element.type, etype) self.assertEqual(element.eid, eid) self.assertEqual(element.pid_ref.type, ptype) self.assertEqual(element.Pid(), pid) self.assertEqual(element.pid_ref.mid_ref.type, mtype) self.assertEqual(element.Mid(), mid) self.assertEqual(element.Volume(), V) self.assertEqual(element.Mass(), mass) mass_mp = mass_properties(model, element_ids=eid)[0] mass_mp_nsm = mass_properties_nsm(model, element_ids=eid)[0] assert np.allclose(mass, mass_mp) assert np.allclose(mass, mass_mp_nsm)
def check_solid(self, model, eid, etype, pid, ptype, mid, mtype, nsm, rho, volume): """checks that various solid methods work""" mass = rho * volume element = model.elements[eid] assert max(element.node_ids) > 0 assert pid in model.properties, 'pid is missing for\n%s' % str(element) self.assertEqual(element.type, etype) self.assertEqual(element.eid, eid) self.assertEqual(element.pid_ref.type, ptype) self.assertEqual(element.Pid(), pid) self.assertEqual(element.pid_ref.mid_ref.type, mtype) self.assertEqual(element.Mid(), mid) self.assertEqual(element.Volume(), volume) self.assertEqual(element.Mass(), mass) mass_mp = mass_properties(model, element_ids=eid)[0] mass_mp_nsm = mass_properties_nsm(model, element_ids=eid)[0] unused_centroid, unused_xe, unused_ye, unused_ze = element.material_coordinate_system( ) assert np.allclose(mass, mass_mp) assert np.allclose(mass, mass_mp_nsm)
def compare_mass_cg_inertia(fem1, reference_point=None, sym_axis=None): unused_mass1, unused_cg1, unused_I1 = mass_properties( fem1, reference_point=reference_point, sym_axis=sym_axis)
def mass_properties(self, element_ids=None, mass_ids=None, reference_point=None, sym_axis=None, scale=None, inertia_reference='cg'): """ Calculates mass properties in the global system about the reference point. Parameters ---------- element_ids : list[int]; (n, ) ndarray, optional An array of element ids. mass_ids : list[int]; (n, ) ndarray, optional An array of mass ids. reference_point : ndarray/int, optional type : ndarray An array that defines the origin of the frame. default = <0,0,0>. type : int the node id sym_axis : str, optional The axis to which the model is symmetric. If AERO cards are used, this can be left blank. allowed_values = 'no', x', 'y', 'z', 'xy', 'yz', 'xz', 'xyz' scale : float, optional The WTMASS scaling value. default=None -> PARAM, WTMASS is used float > 0.0 inertia_reference : str; default='cg' 'cg' : inertia is taken about the cg 'ref' : inertia is about the reference point Returns ------- mass : float The mass of the model. cg : ndarray The cg of the model as an array. inertia : ndarray Moment of inertia array([Ixx, Iyy, Izz, Ixy, Ixz, Iyz]). I = mass * centroid * centroid .. math:: I_{xx} = m (dy^2 + dz^2) .. math:: I_{yz} = -m * dy * dz where: .. math:: dx = x_{element} - x_{ref} .. seealso:: http://en.wikipedia.org/wiki/Moment_of_inertia#Moment_of_inertia_tensor .. note:: This doesn't use the mass matrix formulation like Nastran. It assumes m*r^2 is the dominant term. If you're trying to get the mass of a single element, it will be wrong, but for real models will be correct. Examples -------- Mass properties of entire structure >>> mass, cg, inertia = model.mass_properties() >>> Ixx, Iyy, Izz, Ixy, Ixz, Iyz = inertia Mass properties of model based on Property ID >>> pids = list(model.pids.keys()) >>> pid_eids = self.get_element_ids_dict_with_pids(pids) >>> for pid, eids in sorted(pid_eids.items()): >>> mass, cg, inertia = model.mass_properties(element_ids=eids) """ self.deprecated( 'mass, cg, inertia = model.mass_properties(...)', 'from pyNastran.bdf.mesh_utils.mass_properties import mass_properties\n' 'mass, cg, inertia = mass_properties(model, ...)', '1.3') mass, cg, inertia = mass_properties( self, element_ids=element_ids, mass_ids=mass_ids, reference_point=reference_point, sym_axis=sym_axis, scale=scale, inertia_reference=inertia_reference) return mass, cg, inertia
def test_cfast(self): """tests a CFAST/PFAST""" log = get_logger(level='warning') model = BDF(log=log) eid1 = 10 pid = 11 model.add_grid(1, [0., 0., 0.]) model.add_grid(2, [1., 0., 0.]) model.add_grid(3, [1., 1., 0.]) model.add_grid(4, [0., 1., 0.]) model.add_cquad4(eid1, pid, [1, 2, 3, 4]) eid2 = 12 model.add_grid(11, [0., 0., 1.]) model.add_grid(12, [1., 0., 1.]) model.add_grid(13, [1., 1., 1.]) model.add_grid(14, [0., 1., 1.]) model.add_cquad4(eid2, pid, [11, 12, 13, 14]) mid = 13 model.add_pshell(pid, mid1=mid, t=0.1) E = 1e7 nu = 0.3 G = E / (2. * (1. + nu)) E = None unused_mat1 = model.add_mat1(mid, E, G, nu, rho=0.2) eid = 14 pid = 15 Type = 'ELEM' ida = eid1 idb = eid2 cfast = model.add_cfast(eid, pid, Type, ida, idb, gs=1, ga=None, gb=None, xs=None, ys=None, zs=None, comment='cfast') Type = 'fake' pid2 = None cfast2 = CFAST(eid, pid2, Type, ida, idb, gs=None, ga=None, gb=None, xs=None, ys=None, zs=None, comment='') with self.assertRaises(TypeError): cfast2.validate() cfast2.Type = 'ELEM' with self.assertRaises(ValueError): cfast2.validate() cfast2.ga = 3 cfast2.xs = 4. cfast2.ys = 4. cfast2.zs = 4. cfast2.validate() d = 1.0 kt1 = 1.0 kt2 = 1.0 kt3 = 0.1 pfast = model.add_pfast(pid, d, kt1, kt2, kt3, mcid=-1, mflag=0, kr1=0., kr2=0., kr3=0., mass=0., ge=0., comment='') model.validate() cfast.raw_fields() pfast.raw_fields() cfast.write_card() pfast.write_card() model._verify_bdf(xref=False) model.cross_reference() model.pop_xref_errors() model._verify_bdf(xref=True) cfast.raw_fields() pfast.raw_fields() cfast.write_card() pfast.write_card() model.uncross_reference() model.safe_cross_reference() mass_properties(model) save_load_deck(model, run_convert=False)
def test_mirror(self): """tests bdf mirroring""" log = SimpleLogger(level='error') pid_pshell = 10 pid_psolid = 11 mid1 = 100 model = BDF(log=log) # (log=log) model.add_grid(1, [10., 10., 10.]) model.add_grid(2, [11., 10., 10.]) model.add_grid(3, [11., 11., 10.]) model.add_grid(4, [10., 11., 10.]) model.add_grid(5, [10., 10., 11.]) model.add_grid(6, [11., 10., 11.]) model.add_grid(7, [11., 11., 11.]) model.add_grid(8, [10., 11., 11.]) model.add_cquad4(1, pid_pshell, [1, 2, 3, 4]) # mass=1 model.add_ctria3(2, pid_pshell, [1, 2, 3]) # mass=0.5 model.add_conrod(3, mid1, [1, 3], A=1.0, j=0.0, c=0.0, nsm=0.0) #model.add_ctetra(4, pid_psolid, [1, 2, 3, 5]) # penta # pyram #model.add_chexa(7, pid_psolid, [1, 2, 3, 4, 5, 6, 7, 8]) model.add_pshell(pid_pshell, mid1=mid1, t=1.) model.add_psolid(pid_psolid, mid1) E = 1.0 G = None nu = 0.3 model.add_mat1(mid1, E, G, nu, rho=1.0) model.validate() model.cross_reference() mass1, unused_cg1, unused_inertia1 = mass_properties(model) # mirror_model=None -> new model # # just a cord2r # y+ right plane = np.array([ [0., 0., 0.], [0., 0., 1.], [1., 0., 0.], ]) model, unsed_mirror_model, unused_nid_offset, unused_eid_offset = bdf_mirror_plane( model, plane, mirror_model=None, log=None, debug=True, use_nid_offset=False) #for nid, node in sorted(mirror_model.nodes.items()): #print(nid, node.xyz) out_filename = 'sym.bdf' write_bdf_symmetric(model, out_filename=out_filename, encoding=None, size=8, is_double=False, enddata=None, close=True, plane='xz') # +y/-y model2 = read_bdf(out_filename, log=log) assert len(model2.nodes) == 16, model2.nodes mass2, cg2, unused_inertia2 = mass_properties(model2) #print('cg1=%s cg2=%s' % (cg1, cg2)) assert np.allclose(mass1*2, mass2), 'mass1=%s mass2=%s' % (mass1, mass2) assert np.allclose(cg2[1], 0.), 'cg2=%s stats=%s' % (cg2, model2.get_bdf_stats()) os.remove('sym.bdf')
def test_shells_add(self): """ tests differential mass and material coordinate systems on CQUAD4/CTRIA3 elements """ pid = 10 mid1 = 100 model = BDF(debug=False) model.add_grid(1, [0., 0., 0.]) model.add_grid(2, [1., 0., 0.]) model.add_grid(3, [1., 1., 0.]) model.add_grid(4, [0., 1., 0.]) model.add_cquad4(10, pid, [1, 2, 3, 4]) model.add_ctria3(11, pid, [1, 2, 3]) mids = [100, 100, 100] thicknesses = [0.1, 0.1, 0.1] model.add_pcomp(pid, mids, thicknesses, thetas=[0., 45., 90.], souts=None, nsm=0., sb=0., ft=None, tref=0., ge=0., lam=None, z0=None, comment='') pid = 11 model.add_ctria3(12, pid, [1, 2, 3], theta_mcid=45., zoffset=0., tflag=0, T1=0.1, T2=0.1, T3=0.1, # absolute - mass=0.1*0.5=0.05 comment='') model.add_ctria3(13, pid, [1, 2, 3], theta_mcid=1, zoffset=0., tflag=0, T1=0.1, T2=0.1, T3=0.1, # absolute comment='') model.add_cquad4(14, pid, [1, 2, 3, 4], theta_mcid=45., zoffset=0., tflag=0, T1=0.1, T2=0.1, T3=0.1, T4=0.1, # absolute comment='') model.add_cquad4(15, pid, [1, 2, 3, 4], theta_mcid=1, zoffset=0., tflag=1, T1=0.1, T2=0.1, T3=0.1, T4=0.1, # relative comment='') origin = [0., 0., 0.] zaxis = [0., 0., 1.] xzplane = [1., 0., 0.] model.add_cord2r(1, origin, zaxis, xzplane, rid=0) model.add_pshell(pid, mid1=mid1, t=2.) e11 = 1.0 e22 = 2.0 nu12 = 0.3 model.add_mat8(mid1, e11, e22, nu12, rho=1.0) model.validate() model.cross_reference() model.pop_xref_errors() mass = mass_properties(model, element_ids=13)[0] bdf_file = StringIO() model.write_bdf(bdf_file) model.uncross_reference() model.cross_reference() model.pop_xref_errors() assert np.allclose(mass, 0.05), mass # t=0.1; A=0.5; nsm=0.; mass=0.05 mass = mass_properties(model, element_ids=14)[0] bdf_file = StringIO() model.write_bdf(bdf_file, close=False) bdf_file.seek(0) assert np.allclose(mass, 0.1), mass # t=0.1; A=1.0; nsm=0.; mass=0.1 csv_filename = 'mcids.csv' export_mcids(model, csv_filename=csv_filename, eids=[12, 13], export_xaxis=True, export_yaxis=True, iply=0) #with open(csv_filename, 'r') as csv_file: #lines = csv_file.readlines() #assert len(lines) > 0, 'lines=%s' % lines #for line in lines: #print(line.rstrip()) #print('-------------') export_mcids(model, csv_filename=csv_filename, eids=[14, 15], export_xaxis=True, export_yaxis=True, iply=0) model.uncross_reference() model.safe_cross_reference() model.uncross_reference() os.remove(csv_filename) #bdf_file = model.write_bdf(bdf_file) model2 = BDF(debug=False) model2.read_bdf(bdf_file, punch=True)
def test_bar_mass_1(self): """tests CBAR/PBAR mass""" model = BDF(debug=False) #model.case_control_deck = CaseControlDeck(case_control_lines) spc = ['SPC1', 123456, 123456, 1] grid1 = ['GRID', 1, None, 0., 0., 0.] grid2 = ['GRID', 2, None, 1., 0., 0.] #grid3 = ['GRID', 3, None, 1., 0., 0.] force = ['FORCE', 100, 1, 0, 2., 3., 4.] pid = 11 mid = 12 cbar = [ 'CBAR', 10, pid, 1, 2, 0., 1., 0., None, ] k1 = k2 = None area = 2.0 rho = 3. nu = 0.3 i1 = 2.1 i2 = 1.2 i12 = 0.1 j = None nsm = 0.1 pbar = [ 'PBAR', pid, mid, area, i1, i2, j, nsm, None, None, None, None, None, None, None, None, k1, k2, i12 ] mat1 = ['MAT1', mid, 3.0e7, None, nu, rho] model.add_card(grid1, 'GRID') model.add_card(grid2, 'GRID') model.add_card(cbar, 'CBAR') model.add_card(pbar, 'PBAR') model.add_card(mat1, 'MAT1') model.add_card(spc, 'SPC1') model.add_card(force, 'FORCE') model.validate() model.cross_reference() mass, unused_cg, unused_I = mass_properties( model, element_ids=None, mass_ids=None, reference_point=None, sym_axis=None, scale=None) #print('cg* =', cg) L = 1.0 mass_per_length = area * rho + nsm mass = L * mass_per_length #xcg = (0.0 * mass_a + 1.0 * mass_b) / (mass_a + mass_b) #print(mass_a, mass_b, xcg, mass_a + mass_b) #print('mass =', mass) #cbar = CBEAM() cbar = model.elements[10] pbar = model.properties[11] assert pbar.Nu() == nu, 'pbar.Nu()=%s nu=%s' % (pbar.Nu(), nu) assert pbar.Rho() == rho, 'pbar.Rho()=%s rho=%s' % (pbar.Rho(), rho) assert np.allclose(cbar.Length(), 1.0), cbar.Length() #assert np.allclose(cbar.Mass(), 10.25), cbar.Mass() #assert np.allclose(cbar.MassPerLength(), 10.25), cbar.MassPerLength() #assert np.allclose(mass, 10.25), mass case_control_lines = ( 'SOL 101\n' 'CEND\n' 'SUBCASE 1\n' ' STRESS(PLOT,SORT1,REAL) = ALL\n' ' SPC = 123456\n' ' LOAD = 100\n' 'BEGIN BULK\n' 'PARAM,GRDPNT,0\n' 'PARAM,POST,-1\n' 'PARAM POSTEXT YES\n' ) with open('cbar.bdf', 'w') as bdf_file: bdf_file.write(case_control_lines) model.write_bdf(bdf_file, enddata=True) model2 = BDF(debug=False) model2.read_bdf('cbar.bdf') model2._verify_bdf(xref=True) if not os.path.exists('cbar.op2') and 0: os.system('nastran scr=yes bat=no old=no cbar.bdf') os.remove('cbar.bdf') if 0: # pragma: no cover from pyNastran.op2.op2 import OP2 op2 = OP2() op2.read_op2('cbar.op2') #os.remove('cbar.op2') gpw = op2.grid_point_weight op2_mass = gpw.mass.max() assert np.allclose(op2_mass, mass), 'op2_mass=%s mass=%s' % (op2_mass, mass) #print('op2_mass=%s mass=%s' % (op2_mass, mass)) unused_op2_cg = gpw.cg unused_cg = np.array([0.5, 0., 0.], dtype='float32')