def _mirror_aero(model: BDF, nid_offset: int, plane: str = 'xz'): """ Mirrors the aero cards Considers: - AEROS - doesn't consider sideslip - CAERO1 - doesn't consider sideslip - considers Cp - considers lchord/lspan/nchord/nspan - SPLINE1 - handle boxes - SET1 - handle nodes - AELIST - handle boxes - AESURF - only supports names of length 7 or less (appends an M to the name) - handles AELIST - doesn't handle coords well - doesn't handle second AESURF Doesnt consider: - AERO - AEFORCE - AEPRES - CAERO2/3/4/5 - PAERO1/2/3/4/5 - AESURFS """ is_aero = False aero_cids_set = set([]) if model.aeros is not None: is_aero = True aeros = model.aeros # The ACSID must be a rectangular coordinate system. # Flow is in the positive x-direction (T1). if aeros.acsid > 0: model.log.error( 'Sideslip coordinate system (ACSID) mirroring is not supported' ) # REFB should be full span, even on half-span models # REFS should be half area on half-span models aeros.sref *= 2. if plane == 'xz': aeros.sym_xz = 0 elif plane == 'yz': aeros.sym_yz = 0 else: model.log.error('not mirroring plane %r; only xz, yz' % plane) caero_id_offset = 0 if len(model.caeros): is_aero = True caero_id_max = max(model.caero_ids) caero_id_offset = np.max(model.caeros[caero_id_max].box_ids.flat) caeros = [] for unused_caero_id, caero in model.caeros.items(): if caero.type == 'CAERO1': # the AEFACTs are assumed to be the same on the left and right side # I think the spanwise direction will be fine lchord = caero.lchord nchord = caero.nchord lspan = caero.lspan nspan = caero.nspan p1, p4 = caero.get_leading_edge_points() p1 = p1.copy() p4 = p4.copy() x12 = caero.x12 x43 = caero.x43 if plane == 'xz': # flip the y p1[1] *= -1. p4[1] *= -1. elif plane == 'xy': p1[2] *= -1. p4[2] *= -1. else: # pragma: no cover raise NotImplementedError( 'plane=%r not supported in CAERO1' % plane) eid2 = caero.eid + caero_id_offset caero_new = CAERO1(eid2, caero.pid, caero.igroup, p1, x12, p4, x43, cp=0, nspan=nspan, lspan=lspan, nchord=nchord, lchord=lchord, comment='') # we flip the normal so if we ever use W2GJ it's going to be consistent caero_new.flip_normal() caeros.append(caero_new) else: # pragma: no cover model.log.error('skipping (only supports CAERO1):\n%s' % caero.rstrip()) for caero in caeros: model._add_caero_object(caero) nsplines = len(model.splines) sets_max = max(model.sets) if len(model.sets) else 0 if caero_id_offset == 0 and nsplines: model.log.error("cant mirror splines because CAEROs don't exist...") elif nsplines and sets_max == 0: model.log.error("cant mirror splines because SET1/3 don't exist...") elif nsplines: is_aero = True splines = [] spline_sets_to_duplicate = [] spline_max = max(model.splines) for unused_spline_id, spline in model.splines.items(): if spline.type == 'SPLINE1': eid = spline.eid + spline_max caero = spline.caero + caero_id_offset method = spline.method usage = spline.usage box1 = spline.box1 + caero_id_offset box2 = spline.box2 + caero_id_offset setg = spline.setg + sets_max dz = spline.dz melements = spline.melements nelements = spline.nelements spline_new = SPLINE1(eid, caero, box1, box2, setg, dz=dz, method=method, usage=usage, nelements=nelements, melements=melements, comment='') splines.append(spline_new) spline_sets_to_duplicate.append(spline.setg) else: # pragma: no cover model.log.error('skipping (only support SPLINE1):\n%s' % spline.rstrip()) #print("spline_sets_to_duplicate =", spline_sets_to_duplicate) msg = ', which is required to mirror:\n%s' % spline.rstrip() sets_to_add = [] for set_id in spline_sets_to_duplicate: set_card = model.Set(set_id, msg=msg) if set_card.type == 'SET1': sid = set_card.sid + sets_max ids = [nid + nid_offset for nid in set_card.ids] is_skin = set_card.is_skin set_card = SET1(sid, ids, is_skin=is_skin, comment='') sets_to_add.append(set_card) else: # pragma: no cover model.log.error('skipping (only support SET1):\n%s' % set_card.rstrip()) for spline in splines: model._add_spline_object(spline) for set_card in sets_to_add: model._add_set_object(set_card) aelist_id_offset = 0 if len(model.aelists): is_aero = True aelist_id_offset = max(model.aelists) cid_offset = max(model.coords) if len(model.coords) > 1 else 0 if len(model.aesurf): is_aero = True aesurf_id_offset = max(model.aesurf) for aelist_id, aelist in sorted(model.aelists.items()): aelist_id_new = aelist_id + aelist_id_offset elements = [eid + caero_id_offset for eid in aelist.elements] model.add_aelist(aelist_id_new, elements, comment='') for aesurf_id, aesurf in sorted(model.aesurf.items()): # TODO: doesn't handle cid2/aelist2 aesurf_id_new = aesurf_id + aesurf_id_offset label = aesurf.label + 'M' cid1 = aesurf.cid1 + cid_offset alid1 = aesurf.alid1 + aelist_id_offset if cid_offset > 0: aero_cids_set.add(aesurf.cid1) cid2 = None alid2 = None if aesurf.cid2: model.log.warning( "skipping aesurf='{aesurf.label}' second cid/aelist") # combine this into the first coordinate system # # don't mirror the coordinate system because it's antisymmetric? #cid2 = aesurf.cid1 + cid_offset * 2 # how is the second coord and aelist made? #aero_cids_set.add(aesurf.cid1) #alid2 = aesurf.alid1 + aelist_id_offset * 2 model.add_aesurf(aesurf_id_new, label, cid1, alid1, cid2=None, alid2=None, eff=aesurf.eff, ldw=aesurf.ldw, crefc=aesurf.crefc, crefs=aesurf.crefs, pllim=aesurf.pllim, pulim=aesurf.pulim, hmllim=aesurf.hmllim, hmulim=aesurf.hmulim, tqllim=aesurf.tqllim, tqulim=aesurf.tqulim, comment='') if is_aero: _asymmetrically_mirror_aero_coords(model, aero_cids_set, cid_offset, plane) model.pop_parse_errors()
def test_spline2(self): """checks the SPLINE2 card""" #| SPLINE2 | EID | CAERO | ID1 | ID2 | SETG | DZ | DTOR | CID | #| | DTHX | DTHY | None | USAGE | | | | | #+---------+------+-------+-------+-------+------+----+------+-----+ #| SPLINE2 | 5 | 8 | 12 | 24 | 60 | 0. | 1.0 | 3 | #| | 1. | | | | | | | | cid = 3 origin = [0., 0., 0.] xaxis = [1., 0., 0.] xyplane = [0., 1., 0.] coord = CORD2R.add_axes(cid, rid=0, origin=origin, xaxis=xaxis, yaxis=None, zaxis=None, xyplane=xyplane, yzplane=None, xzplane=None, comment='comment') eid = 8 pid = 10 cp = 0 nsb = 4 nint = 2 lsb = None lint = None p1 = [0., 0., 0.] x12 = 42. igid = None caero2 = CAERO2(eid, pid, igid, p1, x12, cp=cp, nsb=nsb, nint=nint, lsb=lsb, lint=lint, comment='this is a caero') #caero = CAERO2(eid, pid, cp, nsb, nint, lsb, lint, igid, p1, x12) sid = 60 ids = [7, 13] set_obj = SET1(sid, ids, is_skin=False, comment='set card') grid7 = GRID(nid=7, cp=0, xyz=[7., 0., 0.], cd=0, ps='', seid=0, comment='') grid13 = GRID(nid=13, cp=0, xyz=[13., 0., 0.], cd=0, ps='', seid=0, comment='') model = BDF(log=None) model._add_coord_object(coord) model._add_caero_object(caero2) model._add_set_object(set_obj) model._add_node_object(grid7) model._add_node_object(grid13) eid = 5 caero = 8 id1 = 12 id2 = 24 setg = 60 dz = 0. dtor = 1.0 cid = 3 dthx = 1. dthy = None usage = None card = ['SPLINE2', eid, caero, id1, id2, setg, dz, dtor, cid, dthx, dthy, None, usage] bdf_card = BDFCard(card, has_none=True) spline_a = SPLINE2.add_card(bdf_card, comment='spline2_a') spline_a.write_card() spline_b = SPLINE2(eid, caero, id1, id2, setg, dz, dtor, cid, dthx, dthy, usage, comment='spline2_b') spline_b.validate() spline_b.write_card() spline_b.cross_reference(model) spline_b.write_card()