def ctrls(self): if self._ctrls is None: self._ctrls = {} scta = self.scta sctb = self.sctb if self.mirror: for control in sctb.ctrls: ctrl = sctb.ctrls[control] newctrl = ctrl.duplicate(mirror=True) self._ctrls[control] = newctrl else: for control in scta.ctrls: ctrl = scta.ctrls[control] newctrl = ctrl.duplicate(mirror=False) self._ctrls[control] = newctrl for control in self.ctrls: ctrl = self._ctrls[control] if ctrl.uhvec.return_magnitude() == 0.0: pntal = Vector((ctrl.xhinge - scta.xoc) * scta.chord, 0.0, -scta.zoc * scta.chord) pnta = scta.point + scta.crdsys.vector_to_global(pntal) pntbl = Vector((ctrl.xhinge - sctb.xoc) * sctb.chord, 0.0, -sctb.zoc * sctb.chord) pntb = sctb.point + sctb.crdsys.vector_to_global(pntbl) hvec = pntb - pnta ctrl.set_hinge_vector(hvec) return self._ctrls
def vector_to_local(crd: Coordinate, vec: MatrixVector) -> MatrixVector: """Transforms a vector from global to this local coordinate system""" dirx = Vector(crd.dirx.x, crd.dirx.y, crd.dirx.z) diry = Vector(crd.diry.x, crd.diry.y, crd.diry.z) dirz = Vector(crd.dirz.x, crd.dirz.y, crd.dirz.z) x = dirx * vec y = diry * vec z = dirz * vec return MatrixVector(x, y, z)
def trefftz_velocity(self, pnt: Vector): r = Vector(0.0, pnt.y, pnt.z) ra = Vector(0.0, self.pnt1.y, self.pnt1.z) rb = Vector(0.0, self.pnt2.y, self.pnt2.z) a = r - ra b = r - rb axx = Vector(0.0, a.z, -a.y) bxx = Vector(0.0, b.z, -b.y) am2 = a * a bm2 = b * b vel = (axx / am2 - bxx / bm2) / 2 / pi return vel
def duplicate(self, mirror=True): if mirror and self.reverse: posgain, neggain = -self.neggain, -self.posgain else: posgain, neggain = self.posgain, self.neggain if mirror: uhvec = Vector(self.uhvec.x, -self.uhvec.y, self.uhvec.z) else: uhvec = Vector(self.uhvec.x, self.uhvec.y, self.uhvec.z) ctrl = PanelControl(self.name, posgain, neggain, self.xhinge) ctrl.reverse = False ctrl.set_hinge_vector(uhvec) return ctrl
def crdsys(self): if self._crdsys is None: tilt = radians(self.tilt) sintilt = sin(tilt) costilt = cos(tilt) diry = Vector(0.0, costilt, sintilt) twist = radians(self.twist) sintwist = sin(twist) costwist = cos(twist) dirx = Vector(costwist, sintwist * sintilt, -sintwist * costilt) dirz = dirx**diry self._crdsys = Coordinate(self.point, dirx, diry, dirz) return self._crdsys
def get_profile(self, offset: bool=True): num = self.cnum*2+1 profile = zero_matrix_vector((1, num), dtype=float) for i in range(self.cnum+1): n = num-i-1 j = n-num profile[0, i] = Vector(self.airfoil.xl[j], 0.0, self.airfoil.yl[j]) profile[0, n] = Vector(self.airfoil.xu[j], 0.0, self.airfoil.yu[j]) profile.z[absolute(profile.z) < tol] = 0.0 profile.z = profile.z*self.thkcor if offset: offvec = Vector(self.xoc, 0.0, self.zoc) profile = profile-offvec return profile
def add_section_constraint(self, sind: int, ksx: float = 0.0, ksy: float = 0.0, ksz: float = 0.0, gsx: float = 0.0, gsy: float = 0.0, gsz: float = 0.0): self._rbdy = None for i, strp in enumerate(self.srfc.strps): inda = 2 * i if strp.prfa is self.srfc.scts[sind]: self.pntinds[inda] = len(self.rpnts) self.rpnts.append(strp.prfa.point) self.ks.append(Vector(ksx, ksy, ksz)) self.gs.append(Vector(gsx, gsy, gsz))
def latticesystem_from_dict(sysdct: dict): from .latticesurface import latticesurface_from_json from .latticeresult import latticeresult_from_json from .latticetrim import latticetrim_from_json from pyvlm.tools import masses_from_json, masses_from_data from os.path import dirname, join, exists jsonfilepath = sysdct['source'] path = dirname(jsonfilepath) for surfdata in sysdct['surfaces']: for sectdata in surfdata['sections']: if 'airfoil' in sectdata: airfoil = sectdata['airfoil'] if airfoil[-4:] == '.dat': airfoil = join(path, airfoil) if not exists(airfoil): print(f'Airfoil {airfoil} does not exist.') del sectdata['airfoil'] else: sectdata['airfoil'] = airfoil name = sysdct['name'] sfcs = [] for surfdata in sysdct['surfaces']: sfc = latticesurface_from_json(surfdata) sfcs.append(sfc) bref = sysdct['bref'] cref = sysdct['cref'] sref = sysdct['sref'] xref = sysdct['xref'] yref = sysdct['yref'] zref = sysdct['zref'] rref = Vector(xref, yref, zref) lsys = LatticeSystem(name, sfcs, bref, cref, sref, rref) masses = {} if 'masses' in sysdct: if isinstance(sysdct['masses'], list): masses = masses_from_data(sysdct['masses']) elif isinstance(sysdct['masses'], str): if sysdct['masses'][-5:] == '.json': massfilename = sysdct['masses'] massfilepath = join(path, massfilename) masses = masses_from_json(massfilepath) lsys.masses = masses if 'cases' in sysdct and sysdct: lsys.mesh() for i in range(len(sysdct['cases'])): resdata = sysdct['cases'][i] if 'trim' in resdata: latticetrim_from_json(lsys, resdata) else: latticeresult_from_json(lsys, resdata) lsys.source = jsonfilepath return lsys
def create_trim_result(self): from ..classes import LatticeTrim ltrm = LatticeTrim(self.name, self.sys) ltrm.set_density(rho=self.density) ltrm.set_state(speed=self.speed, qco2V=self.qco2V) ltrm.set_targets(CLt=self.CL) rcg = Vector(self.mass.xcm, self.mass.ycm, self.mass.zcm) ltrm.set_cg(rcg) return ltrm
def sum(self, axis=None, dtype=None, out=None): x = self.x.sum(axis=axis, dtype=dtype, out=out) y = self.y.sum(axis=axis, dtype=dtype, out=out) z = self.z.sum(axis=axis, dtype=dtype, out=out) if isinstance(x, matrix) and isinstance(y, matrix) and isinstance( z, matrix): return MatrixVector(x, y, z) else: return Vector(x, y, z)
def __getitem__(self, key): x = self.x[key] y = self.y[key] z = self.z[key] if isinstance(x, matrix) and isinstance(y, matrix) and isinstance( z, matrix): return MatrixVector(x, y, z) else: return Vector(x, y, z)
def vector_from_dict(vectordata): x, y, z = None, None, None if 'x' in vectordata: x = vectordata['x'] if 'y' in vectordata: y = vectordata['y'] if 'z' in vectordata: z = vectordata['z'] return Vector(x, y, z)
def sign_local_z(self, pnts: MatrixVector, betx: float = 1.0): vecs = pnts - self.pnto nrm = self.nrm if betx != 1.0: vecs.x = vecs.x / betx nrm = Vector(self.nrm.x / betx, self.nrm.y, self.nrm.z) locz = vecs * nrm sgnz = ones(locz.shape, float) sgnz[locz <= 0.0] = -1.0 return sgnz
def tolist(self): lst = [] for i in range(self.shape[0]): lst.append([]) for j in range(self.shape[1]): x = self.x[i, j] y = self.y[i, j] z = self.z[i, j] lst[-1].append(Vector(x, y, z)) return lst
def baryinv(self): if self._baryinv is None: self._baryinv = [] for i in range(self.num): dirx = self.dirxab[0, i] diry = self.diryab[0, i] dirz = self.dirzab[0, i] grda = self.grdr[0, i-1] grdb = self.grdr[0, i] grdal = Vector(grda*dirx, grda*diry, grda*dirz) grdbl = Vector(grdb*dirx, grdb*diry, grdb*dirz) amat = zeros((3, 3), dtype=float) amat[0, :] = 1.0 amat[1, 1] = grdal.x amat[2, 1] = grdal.y amat[1, 2] = grdbl.x amat[2, 2] = grdbl.y self._baryinv.append(inv(amat)) return self._baryinv
def return_mirror(self): pnt = Vector(self.pnt.x, -self.pnt.y, self.pnt.z) chord = self.chord twist = self.twist sct = LatticeSection(pnt, chord, twist) sct.camber = self.camber sct.bspc = self.bspc sct.yspace = self.yspace sct.ctrls = self.ctrls sct.cdo = self.cdo sct.mirror = True return sct
def trefftz_plane_velocities(self, pnts: MatrixVector, betx: float = 1.0, bety: float = 1.0, betz: float = 1.0): # Trailing Vortex A agcs = self.relative_mach(pnts, self.grda, betx=betx, bety=bety, betz=betz) dirxa = -self.diro dirza = self.nrm dirya = dirza**dirxa alcs = MatrixVector(agcs * dirxa, agcs * dirya, agcs * dirza) alcs.x = zeros(alcs.shape, dtype=float) axx = MatrixVector(alcs.x, -alcs.z, alcs.y) am2 = square(alcs.y) + square(alcs.z) chkam2 = absolute(am2) < tol am2r = zeros(pnts.shape, dtype=float) reciprocal(am2, where=logical_not(chkam2), out=am2r) faca = -1.0 veldl = elementwise_multiply(axx, am2r) * faca veldl.x[chkam2] = 0.0 veldl.y[chkam2] = 0.0 veldl.z[chkam2] = 0.0 dirxi = Vector(dirxa.x, dirya.x, dirza.x) diryi = Vector(dirxa.y, dirya.y, dirza.y) dirzi = Vector(dirxa.z, dirya.z, dirza.z) velda = MatrixVector(veldl * dirxi, veldl * diryi, veldl * dirzi) * faca # Trailing Vortex B bgcs = self.relative_mach(pnts, self.grdb, betx=betx, bety=bety, betz=betz) dirxb = self.diro dirzb = self.nrm diryb = dirzb**dirxb blcs = MatrixVector(bgcs * dirxb, bgcs * diryb, bgcs * dirzb) blcs.x = zeros(blcs.shape, dtype=float) bxx = MatrixVector(blcs.x, -blcs.z, blcs.y) bm2 = square(blcs.y) + square(blcs.z) chkbm2 = absolute(bm2) < tol bm2r = zeros(pnts.shape, dtype=float) reciprocal(bm2, where=logical_not(chkbm2), out=bm2r) facb = 1.0 veldl = elementwise_multiply(bxx, bm2r) * facb veldl.x[chkbm2] = 0.0 veldl.y[chkbm2] = 0.0 veldl.z[chkbm2] = 0.0 dirxi = Vector(dirxb.x, diryb.x, dirzb.x) diryi = Vector(dirxb.y, diryb.y, dirzb.y) dirzi = Vector(dirxb.z, diryb.z, dirzb.z) veldb = MatrixVector(veldl * dirxi, veldl * diryi, veldl * dirzi) * facb # Add Together veld = velda + veldb return veld / twoPi
def panelsystem_from_geom(sysdct: Dict[str, any]): if 'source' in sysdct: path = dirname(sysdct['source']) for surfdata in sysdct['surfaces']: for sectdata in surfdata['sections']: if 'airfoil' in sectdata: airfoil = sectdata['airfoil'] if airfoil is not None: if airfoil[-4:] == '.dat': airfoil = join(path, airfoil) if not exists(airfoil): print(f'Airfoil {airfoil} does not exist.') del sectdata['airfoil'] else: sectdata['airfoil'] = airfoil srfcs = [] for surfdata in sysdct['surfaces']: srfcs.append(panelsurface_from_json(surfdata)) name = sysdct['name'] bref = sysdct['bref'] cref = sysdct['cref'] sref = sysdct['sref'] xref = sysdct['xref'] yref = sysdct['yref'] zref = sysdct['zref'] rref = Vector(xref, yref, zref) psys = PanelSystem(name, bref, cref, sref, rref) psys.set_geom(srfcs) masses = {} if 'masses' in sysdct: if isinstance(sysdct['masses'], list): masses = masses_from_json(sysdct['masses']) elif isinstance(sysdct['masses'], str): if sysdct['masses'][-5:] == '.json': massfilename = sysdct['masses'] massfilepath = join(path, massfilename) masses = masses_from_json(massfilepath) psys.masses = masses if 'cases' in sysdct and sysdct: panelresults_from_dict(psys, sysdct['cases']) if 'source' in sysdct: psys.source = sysdct['source'] return psys
def update(self): self.bfrc = (self.bspc[1] - self.bspc[0]) / (self.bspc[2] - self.bspc[0]) self.pnls = [] self.leni = self.pnt2 - self.pnt1 self.pnti = self.pnt1 + self.bfrc * self.leni self.lent = Vector(0.0, self.leni.y, self.leni.z) self.dyt = self.leni.y self.dzt = self.leni.z self.dst = (self.dyt**2 + self.dzt**2)**0.5 pnta = self.pnt1 + 0.25 * self.crd1 * ihat pntb = self.pnt2 + 0.25 * self.crd2 * ihat vecab = pntb - pnta self.pntq = pnta + self.bfrc * vecab
def velocity(self, pnt: Vector): r = pnt ra = self.pnta rb = self.pntb a = r - ra b = r - rb am = a.return_magnitude() bm = b.return_magnitude() vel = Vector(0.0, 0.0, 0.0) if pnt != self.pnti: axb = a**b if axb.return_magnitude() != 0.0: den = am * bm + a * b vel += axb / den * (1 / am + 1 / bm) axx = Vector(0.0, a.z, -a.y) if axx.return_magnitude() != 0.0: den = am - a.x vel += axx / den / am bxx = Vector(0.0, b.z, -b.y) if bxx.return_magnitude() != 0.0: den = bm - b.x vel -= bxx / den / bm vel = vel / fourPi return vel
def panelsection_from_json(sectdata: dict) -> PanelSection: xpos = sectdata['xpos'] ypos = sectdata['ypos'] zpos = sectdata['zpos'] point = Vector(xpos, ypos, zpos) chord = sectdata['chord'] airfoilstr = sectdata['airfoil'] if airfoilstr is not None: if airfoilstr[-4:] == '.dat': airfoil = airfoil_from_dat(airfoilstr) elif airfoilstr[0:4].upper() == 'NACA': code = airfoilstr[4:].strip() if len(code) == 4: airfoil = NACA4(code) else: raise ValueError(f'Airfoil identified by {airfoilstr:s} does not exist.') else: airfoil = None twist = 0.0 if 'twist' in sectdata: twist = sectdata['twist'] sect = PanelSection(point, chord, twist, airfoil) if 'bnum' in sectdata: sect.bnum = sectdata['bnum'] if 'bspc' in sectdata: sect.bspc = sectdata['bspc'] if 'tilt' in sectdata: sect.set_tilt(sectdata['tilt']) if 'xoc' in sectdata: sect.xoc = sectdata['xoc'] if 'zoc' in sectdata: sect.zoc = sectdata['zoc'] if 'noload' in sectdata: sect.noload = sectdata['noload'] if 'nohsv' in sectdata: sect.nohsv = sectdata['nohsv'] if 'nomesh' in sectdata: sect.nomesh = sectdata['nomesh'] if sect.nomesh: sect.noload = True # sect.nohsv = True if 'controls' in sectdata: for name in sectdata['controls']: ctrl = panelcontrol_from_dict(name, sectdata['controls'][name]) sect.add_control(ctrl) return sect
def update(self): strpres = self.pres.strpres self.frctot = Vector(0.0, 0.0, 0.0) self.momtot = Vector(0.0, 0.0, 0.0) for i, strp in enumerate(self.strc.strps): ind = strp.ind rrel = strp.point - self.rref self.frctot += strpres.stfrc[ind, 0] self.momtot += strpres.stmom[ind, 0] + rrel**strpres.stfrc[ind, 0] self.rfrc, self.rmom = self.strc.rbdy.return_reactions(self.frctot, self.momtot) self.ptfrc = zero_matrix_vector(self.strc.pnts.shape, dtype=float) self.ptmom = zero_matrix_vector(self.strc.pnts.shape, dtype=float) ptfrcb = Vector(0.0, 0.0, 0.0) ptmomb = Vector(0.0, 0.0, 0.0) for i, strp in enumerate(self.strc.strps): ind = strp.ind inda = 2*i indb = inda + 1 ptfrca = ptfrcb ptmoma = ptmomb if inda in self.strc.pntinds: ptfrca -= self.rfrc[self.strc.pntinds[inda]] ptmoma -= self.rmom[self.strc.pntinds[inda]] ptfrcb = ptfrca - strpres.stfrc[ind, 0] ptmomb = ptmoma - strpres.stmom[ind, 0] rrel = strp.point - self.strc.pnts[indb, 0] ptmomb -= rrel**strpres.stfrc[ind, 0] rrel = self.strc.pnts[indb, 0]-self.strc.pnts[inda, 0] ptmomb -= rrel**ptfrca self.ptfrc[inda, 0] = ptfrca self.ptfrc[indb, 0] = ptfrcb self.ptmom[inda, 0] = ptmoma self.ptmom[indb, 0] = ptmomb fx = self.ptfrc.x.transpose().tolist()[0] fy = self.ptfrc.y.transpose().tolist()[0] fz = self.ptfrc.z.transpose().tolist()[0] mx = self.ptmom.x.transpose().tolist()[0] my = self.ptmom.y.transpose().tolist()[0] mz = self.ptmom.z.transpose().tolist()[0] self.frcmin = Vector(min(fx), min(fy), min(fz)) self.frcmax = Vector(max(fx), max(fy), max(fz)) self.mommin = Vector(min(mx), min(my), min(mz)) self.mommax = Vector(max(mx), max(my), max(mz))
def panelcontrol_from_dict(name: str, controldata: dict): xhinge = controldata['xhinge'] posgain = 1.0 if 'posgain' in controldata: posgain = controldata['posgain'] neggain = 1.0 if 'neggain' in controldata: neggain = controldata['neggain'] ctrl = PanelControl(name, posgain, neggain, xhinge) hvec = Vector(0.0, 0.0, 0.0) if 'hvec' in controldata: hvec = vector_from_dict(controldata['hvec']) ctrl.set_hinge_vector(hvec) reverse = False if 'reverse' in controldata: reverse = controldata['reverse'] ctrl.reverse = reverse return ctrl
def latticesection_from_json(sectdata: dict): if 'xpos' in sectdata: xpos = sectdata['xpos'] else: raise ValueError() if 'ypos' in sectdata: ypos = sectdata['ypos'] else: raise ValueError() if 'zpos' in sectdata: zpos = sectdata['zpos'] else: raise ValueError() point = Vector(xpos, ypos, zpos) if 'chord' in sectdata: chord = sectdata['chord'] else: raise ValueError() if 'twist' in sectdata: twist = sectdata['twist'] else: twist = 0.0 sct = LatticeSection(point, chord, twist) if 'cdo' in sectdata: sct.set_cdo(sectdata['cdo']) if 'noload' in sectdata: sct.set_noload(sectdata['noload']) if 'airfoil' in sectdata: sct.set_airfoil(sectdata['airfoil']) if 'bnum' in sectdata and 'bspc' in sectdata: bnum = sectdata['bnum'] bspc = sectdata['bspc'] if bspc == 'equal': sct.set_span_equal_spacing(bnum) elif bspc in ('full-cosine', 'cosine'): sct.set_span_cosine_spacing(bnum) elif bspc == 'semi-cosine': sct.set_span_semi_cosine_spacing(bnum) if 'controls' in sectdata: for name in sectdata['controls']: ctrl = latticecontrol_from_json(name, sectdata['controls'][name]) sct.add_control(ctrl) return sct
def point_res(self, pnlres: matrix, pnt: Vector, ttol: float = 0.1): vecg = pnt - self.pnto gres = self.grid_res(pnlres) pres = pnlres[self.ind, 0] r = 0.0 for i in range(self.num): dirx = self.dirxab[0, i] diry = self.diryab[0, i] dirz = self.dirzab[0, i] vecl = Vector(vecg * dirx, vecg * diry, vecg * dirz) ainv = self.baryinv[i] bmat = matrix([[1.0], [vecl.x], [vecl.y]]) tmat = ainv * bmat to, ta, tb = tmat[0, 0], tmat[1, 0], tmat[2, 0] mint = min(to, ta, tb) if mint > -ttol: ro, ra, rb = pres, gres[i - 1], gres[i] r = ro * to + ra * ta + rb * tb break return r
def mirror_section_in_y(self, ymir: float=0.0): point = Vector(self.point.x, ymir-self.point.y, self.point.z) chord = self.chord twist = self.twist airfoil = self.airfoil sect = PanelSection(point, chord, twist, airfoil) sect.mirror = True sect.bnum = self.bnum sect.bspc = self.bspc sect.nomesh = self.nomesh sect.noload = self.noload sect.nohsv = self.nohsv sect.xoc = self.xoc sect.zoc = self.zoc sect.bval = self.bval sect.bpos = -self.bpos sect.ctrls = self.ctrls if self.tilt is not None: sect.set_tilt(-self._tilt) return sect
def panelsurface_from_json(surfdata: dict, display: bool=False): name = surfdata['name'] if 'mirror' in surfdata: mirror = surfdata['mirror'] else: mirror = False if 'cnum' in surfdata: cnum = surfdata['cnum'] if display: print(f'Loading Surface: {name:s}') # Read Section Variables sects = [] for sectdata in surfdata['sections']: sect = panelsection_from_json(sectdata) sects.append(sect) if sect.airfoil is not None: sect.airfoil.update(cnum) # Linear Interpolate Missing Variables x, y, z, c, a, af = [], [], [], [], [], [] for sect in sects: x.append(sect.point.x) y.append(sect.point.y) z.append(sect.point.z) c.append(sect.chord) a.append(sect.twist) af.append(sect.airfoil) if None in y and None in z: raise ValueError('Need at least ypos or zpos specified in sections.') elif None in y: y = linear_interpolate_none(z, y) elif None in z: z = linear_interpolate_none(y, z) lensects = len(sects) b = [0.0] for i in range(lensects-1): bi = b[i]+sqrt((y[i+1]-y[i])**2+(z[i+1]-z[i])**2) b.append(bi) x = linear_interpolate_none(b, x) c = linear_interpolate_none(b, c) a = linear_interpolate_none(b, a) af = linear_interpolate_airfoil(b, af) for i, sect in enumerate(sects): sect.point.x = x[i] sect.point.y = y[i] sect.point.z = z[i] sect.chord = c[i] sect.twist = a[i] sect.airfoil = af[i] # Read in Function Data funcs = {} if 'functions' in surfdata: for funcdata in surfdata['functions']: func = panelfunction_from_json(funcdata) funcs[func.var] = func # Entire Surface Position xpos, ypos, zpos = 0.0, 0.0, 0.0 if 'xpos' in surfdata: xpos = surfdata['xpos'] if 'ypos' in surfdata: ypos = surfdata['ypos'] if 'zpos' in surfdata: zpos = surfdata['zpos'] point = Vector(xpos, ypos, zpos) twist = 0.0 if 'twist' in surfdata: twist = surfdata['twist'] if 'ruled' in surfdata: ruled = surfdata['ruled'] else: ruled = False for sect in sects: sect.offset_position(xpos, ypos, zpos) sect.offset_twist(twist) sect.ruled = ruled close = True if 'close' in surfdata: close = surfdata['close'] surf = PanelSurface(name, point, twist, mirror, sects, funcs, close) surf.set_chord_spacing(cnum) return surf
def influence_coefficients(self, pnts: MatrixVector, incvel: bool=True, betx: float=1.0, bety: float=1.0, betz: float=1.0, checktol: bool=False): grdm = self.mach_grids(betx=betx, bety=bety, betz=betz) vecab = self.edge_vector(grdm) vecaxb = self.edge_cross(grdm) dirxab = vecab.to_unit() dirzab = vecaxb.to_unit() diryab = elementwise_cross_product(dirzab, dirxab) nrm = vecaxb.sum().to_unit() rgcs = self.relative_mach(pnts, self.pnto, betx=betx, bety=bety, betz=betz) locz = rgcs*nrm sgnz = ones(locz.shape, dtype=float) sgnz[locz <= 0.0] = -1.0 vecgcs = [] for i in range(self.num): vecgcs.append(self.relative_mach(pnts, self.grds[i], betx=betx, bety=bety, betz=betz)) phid = zeros(pnts.shape, dtype=float) phis = zeros(pnts.shape, dtype=float) if incvel: veld = zero_matrix_vector(pnts.shape, dtype=float) vels = zero_matrix_vector(pnts.shape, dtype=float) for i in range(self.num): # Edge Length dab = vecab[0, i].return_magnitude() # Local Coordinate System dirx = dirxab[0, i] diry = diryab[0, i] dirz = dirzab[0, i] # Vector A in Local Coordinate System veca = vecgcs[i-1] alcs = MatrixVector(veca*dirx, veca*diry, veca*dirz) if checktol: alcs.x[absolute(alcs.x) < tol] = 0.0 alcs.y[absolute(alcs.y) < tol] = 0.0 alcs.z[absolute(alcs.z) < tol] = 0.0 # Vector A Doublet Velocity Potentials phida, amag = phi_doublet_matrix(alcs, sgnz) # Vector B in Local Coordinate System vecb = vecgcs[i] blcs = MatrixVector(vecb*dirx, vecb*diry, vecb*dirz) if checktol: blcs.x[absolute(blcs.x) < tol] = 0.0 blcs.y[absolute(blcs.y) < tol] = 0.0 blcs.z[absolute(blcs.z) < tol] = 0.0 # Vector B Doublet Velocity Potentials phidb, bmag = phi_doublet_matrix(blcs, sgnz) # Edge Doublet Velocity Potentials phidi = phida - phidb # Edge Source Velocity Potentials phisi, Qab = phi_source_matrix(amag, bmag, dab, alcs, phidi) # Add Edge Velocity Potentials phid += phidi phis += phisi # Calculate Edge Velocities if incvel: # Velocities in Local Coordinate System veldi = vel_doublet_matrix(alcs, amag, blcs, bmag) velsi = vel_source_matrix(Qab, alcs, phidi) # Transform to Global Coordinate System and Add dirxi = Vector(dirx.x, diry.x, dirz.x) diryi = Vector(dirx.y, diry.y, dirz.y) dirzi = Vector(dirx.z, diry.z, dirz.z) veld += MatrixVector(veldi*dirxi, veldi*diryi, veldi*dirzi) vels += MatrixVector(velsi*dirxi, velsi*diryi, velsi*dirzi) phid = phid/fourPi phis = phis/fourPi if incvel: veld = veld/fourPi vels = vels/fourPi output = phid, phis, veld, vels else: output = phid, phis return output
def mesh(self, lsid: int, lpid: int): from pygeom.geom3d import Vector from numpy.matlib import empty nums = len(self.sects) self.shts = [] for i in range(nums - 1): a, b = i, i + 1 secta = self.sects[a] sectb = self.sects[b] self.shts.append(LatticeSheet(secta, sectb)) self.strps = [] for sht in self.shts: lsid = sht.mesh_strips(lsid) self.strps += sht.strps pnts = [strp.pnt1 for strp in self.strps] pnts.append(self.strps[-1].pnt2) crds = [strp.crd1 for strp in self.strps] crds.append(self.strps[-1].crd2) lenb = len(pnts) lenc = len(self.cspc) self.pnts = empty((lenb, lenc + 1), dtype=Vector) for i in range(lenb): minx = pnts[i].x y = pnts[i].y z = pnts[i].z c = crds[i] cd = self.cspc[0][0] x = minx + cd * c self.pnts[i, 0] = Vector(x, y, z) for j in range(1, lenc + 1): cd = self.cspc[j - 1][-1] x = minx + cd * c self.pnts[i, j] = Vector(x, y, z) self.pnls = empty((lenb - 1, lenc), dtype=LatticePanel) for i, strp in enumerate(self.strps): for j in range(lenc): pnts = [ self.pnts[i, j], self.pnts[i + 1, j], self.pnts[i, j + 1], self.pnts[i + 1, j + 1] ] cspc = self.cspc[j] pnl = LatticePanel(lpid, pnts, cspc, strp) self.pnls[i, j] = pnl lpid += 1 if self.mirror: self.sgrp = [[], []] numstrp = len(self.strps) hlfstrp = int(numstrp / 2) for i in range(hlfstrp): lstrp = self.strps[numstrp - 1 - i] mstrp = self.strps[i] self.sgrp[0].append(lstrp.lsid) self.sgrp[1].append(mstrp.lsid) else: self.sgrp = [[]] numstrp = len(self.strps) for i in range(numstrp): lstrp = self.strps[numstrp - 1 - i] self.sgrp[0].append(lstrp.lsid) bpos = [0.0] for sht in self.shts: sht.inherit_panels() sht.set_control_panels() bpos.append(bpos[-1] + sht.width) if self.mirror: numsht = len(self.shts) wmir = bpos[int(numsht / 2)] for i in range(len(bpos)): bpos[i] = bpos[i] - wmir for i, sect in enumerate(self.sects): sect.bpos = bpos[i] for sht in self.shts: sht.set_strip_bpos() bmax = max(bpos) for func in self.funcs: func.set_spline(bmax) var = func.var if var == 'twist': var = '_ang' if self.mirror: for i in range(hlfstrp): strp = self.strps[numstrp - 1 - i] mstrp = self.strps[i] bpos = strp.bpos val = func.interpolate(bpos) strp.__dict__[var] = val mstrp.__dict__[var] = val else: for strp in self.strps: bpos = strp.bpos val = func.interpolate(bpos) strp.__dict__[var] = val self.area = 0.0 for sht in self.shts: if not sht.noload: self.area += sht.area return lsid, lpid
#%% # Import Dependencies from time import perf_counter from pygeom.geom3d import Vector from pygeom.matrix3d import zero_matrix_vector from pyapm.classes.poly import Poly from pyapm.classes.horseshoe import HorseShoe from pyapm.tools.functions import mean, derivative from matplotlib.pyplot import figure from numpy.matlib import absolute #%% # Create Trailing Edge Vortex grda = Vector(-0.25, 0.75, 0.0) grdb = Vector(-1.25, -1.25, 0.0) diro = Vector(1.0, 0.25, 0.0).to_unit() hsv = HorseShoe(grda, grdb, diro) grds = [ grdb, grdb + 100*diro, grda + 100*diro, grda ] poly = Poly(grds) #%% # Mesh Points xorg = 0.0