def trim(self, show=True): ''' ''' if not any(self.ICs): raise Exception for half, h, IC in zip((0, 1), self.wing.halves, self.ICs): if not self.half in (2, half): continue U, V = h.U if not self.tip: jnc1 = self.wing.junctions[1] if (not jnc1) or (jnc1 and not jnc1.ICs[half]): P0 = IC.cobj.cpts[ 0] P1 = IC.cobj.cpts[-1] P2 = Point(U[-1], V[-1]) P3 = Point(U[ 0], V[-1]) C0 = IC C1 = make_linear_curve(P1, P2) C2 = make_linear_curve(P2, P3) C3 = make_linear_curve(P3, P0) else: IC1 = jnc1.ICs[half] P0 = IC.cobj.cpts[ 0] P1 = IC.cobj.cpts[-1] P2 = IC1.cobj.cpts[-1] P3 = IC1.cobj.cpts[ 0] C0 = IC C1 = make_linear_curve(P1, P2) C2 = IC1.reverse() C3 = make_linear_curve(P3, P0) else: jnc0 = self.wing.junctions[0] if (not jnc0) or (jnc0 and not jnc0.ICs[half]): P0 = Point(U[ 0], V[0]) P1 = Point(U[-1], V[0]) P2 = IC.cobj.cpts[-1] P3 = IC.cobj.cpts[ 0] C0 = make_linear_curve(P0, P1) C1 = make_linear_curve(P1, P2) C2 = IC C3 = make_linear_curve(P3, P0) else: IC0 = jnc0.ICs[half] P0 = IC0.cobj.cpts[ 0] P1 = IC0.cobj.cpts[-1] P2 = IC.cobj.cpts[-1] P3 = IC.cobj.cpts[ 0] C0 = IC0 C1 = make_linear_curve(P1, P2) C2 = IC.reverse() C3 = make_linear_curve(P3, P0) IC = make_composite_curve([C0, C1, C2, C3], remove=False) h.trim(IC) if show: return draw(self.S, self.wing)
def setup(self, nlcpt=50, cap=True, show=True): ''' Setup the NURBS representation of the initial bullet head cylinder. Analogous to modelling clay, it is this NURBS Surface that will be successively shaped by molders. Parameters ---------- nlcpt = the number of longitudinal control points used to represent the cylinder with cap = whether or not to close the rear-end gap with a rounded Surface; for geometries destined for inviscid flow simulations this flag should be set to False show = whether or not to draw the newly setup cylinder Returns ------- fig = a Figure ''' R, BL, NL = self.R, self.BL, self.NL O, X, Y = [0, 0, 0], [-1, 0, 0], [0, 0, -1] args = (O, X, Y, NL, R, 0, np.pi / 2.0) P0, P1 = Point(0, 0, -R), Point(BL, 0, -R) nose = make_ellipse(*args) body = make_linear_curve(P0, P1) for c in nose, body: reparam_arc_length_curve(c) n = make_composite_curve([nose, body]) n = refit_curve(n, nlcpt, num=50000) n2, = n.cobj.n for i in xrange(n2 + 1): Pw = n.cobj.Pw[i] if Pw[0] > 0 or Pw[2] < -R: Pw[2] = -R if cap: P2 = Point(BL, 0, 0) rear = make_linear_curve(P1, P2) reparam_arc_length_curve(rear) n = make_composite_curve([n, rear]) n = make_revolved_surface_nrat(n, O, [1, 0, 0], 180) if not cap: n.cobj.Pw[:, -1, 1] = 0.0 self.nurbs = n self.molders = [] self.clamp() if show: return draw(self)
def read_grid(self, plot3d_file='grid.g', endian='big_endian', show=False): ''' Pre: None ''' self.blk = [] try: open_file(plot3d_file, endian) nblk = read_nblk() jkmmax = np.zeros((3, nblk), dtype='i', order='F') read_header(jkmmax, nblk) for ib in xrange(nblk): nxyz = np.append(jkmmax[:,ib], 3) xyz = np.zeros(nxyz, order='F') read_one_block(jkmmax[:,ib], 3, xyz) P0 = Point(*xyz[ 0, 0, 0]) P1 = Point(*xyz[ 0, 0,-1]) P2 = Point(*xyz[ 0,-1, 0]) P3 = Point(*xyz[ 0,-1,-1]) P4 = Point(*xyz[-1, 0, 0]) P5 = Point(*xyz[-1, 0,-1]) P6 = Point(*xyz[-1,-1, 0]) P7 = Point(*xyz[-1,-1,-1]) cvol = ControlVolume([[[P0, P1], [P2, P3]], [[P4, P5], [P6, P7]]]) blk = Block(cvol, (1,1,1)) blk.indx, blk.xyz = ib + 1, xyz self.blk.append(blk) nnode = sum([blk.xyz.size for blk in self.blk]) / 3 print('{} has {} nonunique nodes.'.format(plot3d_file, nnode)) finally: close_file() if show: return draw(self)
def _setup_control_volume(self, R, zs): C = make_linear_curve(Point(), Point(z=R)) C = C.elevate(2) args = C, (0, 0, 0), (-1, 0, 0), 180, 3, 1e-4 S = make_revolved_surface_nrat(*args) Ps = [S.cobj.Pw[:, :, :-1][:, :, np.newaxis, :]] for z in zs[1:]: P = Ps[0].copy() P[..., 0] += z Ps.append(P) P = np.concatenate(Ps, axis=2) Pw = obj_mat_to_4D(P) Pw[0, ..., 1] = Pw[-1, ..., 1] = 0.0 return ControlVolume(Pw=Pw)
def sharpen(self, l=0.05, show=True): ''' Sharpen the Airfoil's TE by (1) extending its extremities with curvature-continuous B-spline Curves and (2) finding where they intersect. Upon success an intersection Point is created and set on the Airfoil.intersection attribute. This Point will be automatically included when the Airfoil is refitted with any of the available fitting techniques, after which point the Airfoil should be sharp. Should you later desire to discard the intersection Point, simply reset Airfoil.intersection equal to None. Parameters ---------- l = the length of the two extensions (for phase 1) show = whether or not to draw the new set of data Points Returns ------- fig = a Figure ''' def dist(us): try: return distance(n0.eval_point(us[0]), n1.eval_point(us[1])) except KnotOutsideKnotVectorRange: return np.inf n = self.nurbs if not n: raise UnfitAirfoil() if self.issharp: raise AlreadySharpAirfoil() u = arc_length_to_param(n, l) n0, n1 = [n.extend(u, end=end) for end in (False, True)] U0, = n0.U n0.colorize() U1, = n1.U n1.colorize() bnds = [(U0[0], U0[-1]), (U1[0], U1[-1])] us = brute(dist, bnds, finish=None) u0, u1 = fmin(dist, us, xtol=0.0, ftol=0.0, disp=False) x0, x1 = (n0.eval_point(u0), n1.eval_point(u1)) l2n = distance(x1, x0) if l2n > 1e-8: draw(n, n0, n1, stride=0.1) raise NoIntersectionFoundAirfoil(l2n) i = np.average([x0, x1], axis=0) if self.issymmetric: i[2] = 0.0 i = Point(*i) i.colorize() print('geom.airfoil.Airfoil.sharpen :: ' 'intersection Point found ({})'.format(i.xyz)) self.intersection = i if show: d = [n, n0, n1, i] d += self.data['lo'] + self.data['up'] fig = draw(*d, stride=0.1) fig.c.setup_preset('xz') return fig
def read(si, npt): nr = 0 while True: xz = fh.readline().strip() if not xz: continue nr += 1 x, z = xz.split() x, z = float(x), float(z) pt = Point(x=x, z=z) self.data[si].append(pt) if nr == npt: break
def _split(self, Bk, Gk): ''' Split all boundary Curves at their parametric midpoint. ''' for BG in zip(Bk, Gk): CD = make_curves_compatible1(BG)[3] C, D = CD self.Ck.append(C) self.Dk.append(D) self.CLRk, self.DLRk, Mk, self.DMk = split_nsided_region( self.Ck, self.Dk) CLRk0 = None if not len(self.Ck) == 2 else self.CLRk[0] C = find_central_point_nsided_region(Mk, self.DMk) CN = find_normal_vec_nsided_region(C, Mk, self.DMk, CLRk0) self.C = Point(*C) self.C.originate = self._originate self.CN = Point(*CN) self.CN.innerize = self._innerize self.Mk = [Point(*mk) for mk in Mk]
def __init__(self, Bk, Gk): ''' Form a Filler from a set of N boundary curves and associated cross-derivative fields. These are usually picked interactively whilst in plot.mode.ExtractCrossBoundariesMode. There are many subtleties involved in designing a Filler. Some of them are pointed out nurbs.surface.make_nsided_region and many more in the reference cited therein. For best results, all the boundary Curves should be about the same arc length. Parameters ---------- Bk = the boundary Curves Gk = the cross-derivative Curves ''' self.C = Point() self.CN = Point() self.Mk = [] self.DMk = np.array([[]]) self.Ck = [] self.Dk = [] self.CLRk = [] self.DLRk = [] self.CIk = [] self.BLRk = [] self.nurbs = [] self.O = None # originating and deoriginating self._split(Bk, Gk)
def _setup(self): def transform_ffd(R): O, D, S, Pw = R._O, R._D, R._S, R._Pw D_new = distance(O, R.xyz) sf = D_new / D if np.allclose(sf, 1.0): return scale(Pw, sf, R.line[0], R.line[1]) R._D = D_new if S and not np.allclose(S.xyz[2], R.xyz[2]): args = S.line[0], S.line[1], R.xyz, [0, 1, 0] xyz = intersect_3D_lines(*args) S._xyzw[1:3] = xyz[1:3] S.transform_ffd(S) super(FairingMolder, self)._setup() Ps = [] for i in xrange(self.cobj.n[0] + 1): Pw = self.cobj.Pw[i, :, 1] R = Pw[-1].copy() O = Pw[0, :3] L = Pw[-1, :3] - O scale(R, 1.3, O, L) # knob R = Point(*R) Ps.append(R) R._O = O R._D = distance(O, R.xyz) R._S = None R._Pw = Pw R.line = O, L R.transform_ffd = transform_ffd R.ffd = self Ps[0]._S = Ps[1] Ps[1]._S = Ps[0] Ps[-2]._S = Ps[-1] Ps[-1]._S = Ps[-2] self.pilot_points = Ps self.glued = Ps + [self]
def _setup(self): def transform_ffd0(O): R, D, Pw = O._R, O._D, O._Pw sf = O.xyz[1] / D if not np.allclose(sf, 1.0): scale(Pw, sf, L=[0, 1, 0]) dz = O.xyz[2] - Pw[0, 0, 2] if not np.allclose(dz, 0.0): Om = [r._xyzw for r in R] + [Pw] for o in Om: translate(o, [0, 0, dz]) O._D = O.xyz[1] def transform_ffd1(R): O, D, Pw = R._O, R._D, R._Pw z0 = O.xyz[2] sf = (R.xyz[2] - z0) / D if not np.allclose(sf, 1.0): x = R.xyz[0] scale(Pw, sf, [x, 0, z0], [0, 0, 1]) R._D = R.xyz[2] - z0 super(FuselageMolder, self)._setup() n, dummy, l = self.cobj.n Ps = [] for k in xrange(l + 1): Pw = self.cobj.Pw[:, :, k] O = Pw[n / 2, 0, :3] R = Pw[n / 2, -1].copy() R[2] = O[2] L = R[:3] - O scale(R, 1.3, O, L) # knob R = Point(*R) Ps.append(R) R._D = R.xyz[1] R._Pw = Pw R.plane = O, [1, 0, 0] R.transform_ffd = transform_ffd0 O = Pw[-1, 0, :3] R = Pw[-1, -1].copy() L = R[:3] - O scale(R, 1.3, O, L) # knob R = Point(*R) Ps.append(R) R._D = R.xyz[2] - O[2] R._Pw = Pw[n / 2:] R.line = O, [0, 0, 1] R.transform_ffd = transform_ffd1 O = Pw[0, 0, :3] R = Pw[0, -1].copy() L = R[:3] - O scale(R, 1.3, O, L) # knob R = Point(*R) Ps.append(R) R._D = R.xyz[2] - O[2] R._Pw = Pw[:n / 2] R.line = O, [0, 0, 1] R.transform_ffd = transform_ffd1 O, R0, R1 = Ps[-3:] O._R = (R0, R1) R0._O = O R1._O = O for p in Ps: p.ffd = self self.pilot_points = Ps self.glued = Ps + [self]