def run_degen_geom(set_index=None, set_name=None): """ Runs degen geom on input set :param set_index: set index, will take precendence if both set index and set name are specified :param set_name: name of set, will be used if set index is not specified :return: degen geom manager object """ import degen_geom as dg if set_index is None and set_name is None: raise ValueError("set_index and set_name cannot both be None") # Get set index from name, if set index was not specified if set_index is None: set_index = vsp.GetSetIndex(set_name) # Run degen geom on the input set vsp.SetAnalysisInputDefaults("DegenGeom") vsp.SetIntAnalysisInput("DegenGeom", "Set", [set_index], 0) vsp.SetIntAnalysisInput("DegenGeom", "WriteCSVFlag", [0], 0) vsp.SetIntAnalysisInput("DegenGeom", "WriteMFileFlag", [0], 0) degen_res_id = vsp.ExecAnalysis("DegenGeom") degen_objs = vsp.parse_degen_geom(degen_res_id) degen_mgr = dg.DegenGeomMgr(degen_objs) return degen_mgr
def test_parse_degen_geom(self): vsp.VSPRenew() vsp.ClearVSPModel() wing_id = vsp.AddGeom("WING") vsp.Update() vsp.SetIntAnalysisInput("DegenGeom", "WriteCSVFlag", [0], 0) vsp.SetIntAnalysisInput("DegenGeom", "WriteMFileFlag", [0], 0) degen_results_id = vsp.ExecAnalysis("DegenGeom") for degen_obj in vsp.parse_degen_geom(degen_results_id): print(degen_obj)
def test_simple_prop_degen(self): vsp.VSPRenew() vsp.ClearVSPModel() prop_id = vsp.AddGeom("PROP") vsp.Update() print(vsp.GetAnalysisInputNames("DegenGeom")) vsp.SetAnalysisInputDefaults("DegenGeom") vsp.PrintAnalysisInputs("DegenGeom") vsp.SetIntAnalysisInput("DegenGeom", "WriteCSVFlag", [0], 0) vsp.SetIntAnalysisInput("DegenGeom", "WriteMFileFlag", [0], 0) vsp.PrintAnalysisInputs("DegenGeom") self.assertTrue(True)
def test_degen_transform_mat(self): import degen_geom as dg vsp.VSPRenew() vsp.ClearVSPModel() prop_id = vsp.AddGeom("PROP") vsp.SetParmVal(prop_id, "Y_Rel_Location", "XForm", 60.0) vsp.SetParmVal(prop_id, "Y_Rel_Rotation", "XForm", 90.0) vsp.SetParmVal(prop_id, "X_Rel_Rotation", "XForm", 10.0) vsp.SetParmVal(prop_id, "Sym_Planar_Flag", "Sym", vsp.SYM_XZ) vsp.Update() vsp.SetIntAnalysisInput("DegenGeom", "WriteCSVFlag", [0], 0) vsp.SetIntAnalysisInput("DegenGeom", "WriteMFileFlag", [0], 0) degen_results_id = vsp.ExecAnalysis("DegenGeom") degen_objects = vsp.parse_degen_geom(degen_results_id) degen_mgr = dg.DegenGeomMgr(degen_objects) dg_prop_comp = degen_mgr.degen_objs[prop_id] orig_copy = dg_prop_comp.copies[0] origin = orig_copy[0].transmat.get_translations() self.assertAlmostEqual(origin[0], 0.0, places=6) self.assertAlmostEqual(origin[1], 60.0, places=6) self.assertAlmostEqual(origin[2], 0.0, places=6) angles = orig_copy[0].transmat.get_angles() self.assertAlmostEqual(angles[0], 10.0, places=6) self.assertAlmostEqual(angles[1], 90.0, places=6) self.assertAlmostEqual(angles[2], 0.0, places=6) sym_copy = dg_prop_comp.copies[1] origin = sym_copy[0].transmat.get_translations() self.assertAlmostEqual(origin[0], 0.0, places=6) self.assertAlmostEqual(origin[1], -60.0, places=6) self.assertAlmostEqual(origin[2], 0.0, places=6) angles = sym_copy[0].transmat.get_angles() self.assertAlmostEqual(angles[0], -180.0 + 10.0, places=6) self.assertAlmostEqual(angles[1], 90.0, places=6) self.assertAlmostEqual(angles[2], 0.0, places=6) self.assertTrue(True)
def export_surface_patches(export_set: int, remove_degenerate=True): """ Function that export surfaces patches of current set :param export_set: vsp set to export :param remove_degenerate: if true, degenerate surface patches are removed :return: list components with surface patches """ import numpy as np components = [] vsp.SetIntAnalysisInput("SurfacePatches", "Set", [export_set]) surf_patch_res_id = vsp.ExecAnalysis("SurfacePatches") patch_results = vsp.parse_results_object(surf_patch_res_id) comp_ids = patch_results.components for comp_id in comp_ids: comp_res = vsp.parse_results_object(comp_id) surface_ids = comp_res.surfaces surfaces = [] for surf_id in surface_ids: surf_res = vsp.parse_results_object(surf_id) patch_ids = surf_res.patches patches = [] for patch_id in patch_ids: patch_res = vsp.parse_results_object(patch_id) add_patch = True if remove_degenerate and (len(patch_res.x) <= 1 or len(patch_res.x[0]) <= 1): add_patch = False if add_patch: patches.append( SurfacePatch(patch_res.comp_id[0], patch_res.surf_index[0], patch_res.patch_index[0], np.array(patch_res.x), np.array(patch_res.y), np.array(patch_res.z), np.array(patch_res.nx), np.array(patch_res.ny), np.array(patch_res.nz))) surfaces.append( Surface(surf_res.comp_id[0], surf_res.surf_index[0], patches)) if len(surfaces) > 0: components.append( SurfaceComponent(comp_res.name[0], comp_res.id[0], surfaces)) return components
def parasitedrag_sweep(speeds, alts_ft, sref=None, length_unit=None, speed_unit=vsp.V_UNIT_MACH, set=None): """ Runs a parasite drag sweep over a range of speeds and altitudes. For subsonic data only. :param speeds: list of speeds to sweep over :param alts_ft: list of altitudes to sweep over :param speed_unit: units of speed array :param set: vsp geometry set to use for build up :param length_unit: length unit of the vsp model :param sref: reference area :return: named tuple with results """ # Reset default values to ensure values that have been read from a vsp file are used by default vsp.SetAnalysisInputDefaults('ParasiteDrag') # inputs that don't change during a sweep vsp.SetIntAnalysisInput("ParasiteDrag", "VelocityUnit", [speed_unit]) if length_unit is not None: vsp.SetIntAnalysisInput("ParasiteDrag", "LengthUnit", [length_unit]) vsp.SetStringAnalysisInput("ParasiteDrag", "FileName", ["/dev/null"]) if set is not None: vsp.SetIntAnalysisInput("ParasiteDrag", "GeomSet", [set]) if sref is not None: vsp.SetIntAnalysisInput("ParasiteDrag", "RefFlag", [0]) vsp.SetDoubleAnalysisInput("ParasiteDrag", "Sref", [float(sref)]) vsp.SetVSP3FileName('/dev/null') results = [] first_val = True for speed in speeds: for alt in alts_ft: vsp.SetDoubleAnalysisInput("ParasiteDrag", "Vinf", [float(speed)]) vsp.SetDoubleAnalysisInput("ParasiteDrag", "Altitude", [float(alt)]) if first_val: vsp.SetIntAnalysisInput("ParasiteDrag", "RecomputeGeom", [True]) first_val = False else: vsp.SetIntAnalysisInput("ParasiteDrag", "RecomputeGeom", [False]) results.append( vsp.parse_results_object(vsp.ExecAnalysis("ParasiteDrag"))) return ParasiteDragResults(results)
def create_input_from_degen_geom(degen_objects=None, degen_set=None, title="DegenAvl", mach=0.0, Sref=1.0, Bref=1.0, Cref=1.0, cgRef=(0.0, 0.0, 0.0), cdp=0.0): """ Creates an AvlInput object from a list of degen geometry objects The degen objects can be created by passing the vsp set from which to create them :param degen_objects: List of degen geom objects, these can be created from openvsp. If degen_objects is None, degen objects will be created by using OpenVSP on the input degen set :param degen_set: OpenVSP set to create degen objects from if :param degen_objects is None :param title: title of the avl geometry :param mach: mach number :param Sref: reference area :param Bref: span :param Cref: reference chord :param cgRef: moment calculation location :param cdp: fixed parasite drag value to add to computed induced drag :return: AvlInput object """ import degen_geom as dg import numpy as np header = AvlHeader(title, Mach=mach, Sref=Sref, Cref=Cref, Bref=Bref, CGref=cgRef, CDp=cdp) surfaces = [] components = {} # Create degen objects from OpenVSP if no degen objects were passed in. Throw an exception if both degen_objects # and degen_set are None if degen_objects is None and degen_set is None: raise ValueError( "degen_objects and degen_set cannot both be set to None") if degen_objects is None: # Import vsp locally to limit module dependency on openvsp import openvsp as vsp # Turn off file exports vsp.SetIntAnalysisInput("DegenGeom", "WriteCSVFlag", [0], 0) vsp.SetIntAnalysisInput("DegenGeom", "WriteMFileFlag", [0], 0) # Select the appropriate Set vsp.SetIntAnalysisInput("DegenGeom", "Set", [degen_set]) # Run DegenGeom vsp.Update() degen_results_id = vsp.ExecAnalysis("DegenGeom") # Post process the results from the vsp api into more useful objects degen_objects = vsp.parse_degen_geom(degen_results_id) for degen_obj in degen_objects: component = len(components) + 1 if degen_obj.name in components: component = components[degen_obj.name] else: components[degen_obj.name] = component for stick in degen_obj.sticks: surf = AvlSurface(name=degen_obj.name, Nchord=degen_obj.surf.num_pnts, Component=component, Nspan=None, Sspace=None) # TODO: Add support for bodies if degen_obj.type == dg.DegenTypeEnum.LIFTING: # Sort sticks such that increase in y value. If y is constant (e.g. vertical tail) then order from z+ to z- # (top to bottom) le = np.array(stick.le) te = np.array(stick.te) chord = np.array(stick.chord) u = np.array(stick.u) sort_inds = [] uniq_y = np.unique(le[:, 1]) if len(uniq_y) > 1: # y is not constant, so now sort based on y coordinate sort_inds = le[:, 1].argsort() else: sort_inds = le[:, 2].argsort()[::-1] le = le[sort_inds] te = te[sort_inds] chord = chord[sort_inds] u = u[sort_inds] nspan = 1 for i in range(len(le)): nspan += 1 if abs(round(u[i]) - u[i]) > 1.0e-10: continue # Compute ainc x_vec = np.array([1.0, 0.0, 0.0]) chord_vec = te[i, :] - le[i, :] cos_theta = np.dot(chord_vec, x_vec) / np.linalg.norm(chord_vec) rot_axis = np.cross(x_vec, chord_vec) angle_sign = 1.0 if rot_axis[np.argmax(np.abs(rot_axis))] < 0.0: angle_sign = -1.0 ainc = np.rad2deg(np.arccos(np.clip(cos_theta, -1, 1))) * angle_sign sect = AvlSection(le=le[i, :], chord=chord[i], ainc=ainc, Nspan=nspan, Sspace=1.0) surf.addSection(sect) if len(surf.sections) > 1: surf.sections[-2].Nspan = nspan nspan = 2 if degen_obj.type == dg.DegenTypeEnum.BODY: continue surfaces.append(surf) return AvlInput(header, surfaces)
def test_degen_geom(self): # Test analysis manager vsp.VSPRenew() vsp.ClearVSPModel() # Print all types print(vsp.GetGeomTypes()) prop_id = vsp.AddGeom("PROP") blank_id = vsp.AddGeom("BLANK") disk_id = vsp.AddGeom("Disk") vsp.SetParmVal(blank_id, "Point_Mass_Flag", "Mass", 1) vsp.SetParmVal(blank_id, "Point_Mass", "Mass", 5.0) wing_id = vsp.AddGeom("WING") pod_id = vsp.AddGeom("POD") vsp.AddSubSurf(pod_id, vsp.SS_RECTANGLE) vsp.AddSubSurf(wing_id, vsp.SS_CONTROL) vsp.Update() # Run Degen Geom print(vsp.FindGeoms()) print(vsp.GetAnalysisInputNames("DegenGeom")) vsp.SetAnalysisInputDefaults("DegenGeom") vsp.SetIntAnalysisInput("DegenGeom", "WriteMFileFlag", [0], 0) vsp.SetIntAnalysisInput("DegenGeom", "WriteCSVFlag", [0], 0) vsp.PrintAnalysisInputs("DegenGeom") degen_results_id = vsp.ExecAnalysis("DegenGeom") print(vsp.GetAllResultsNames()) vsp.PrintResults(degen_results_id) blank_ids = vsp.GetStringResults(degen_results_id, "Degen_BlankGeoms") degen_ids = vsp.GetStringResults(degen_results_id, "Degen_DegenGeoms") for blank_id in blank_ids: vsp.PrintResults(blank_id) for degen_id in degen_ids: vsp.PrintResults(degen_id) t = vsp.GetStringResults(degen_id, "type", 0)[0] if t == "DISK": disk_id = vsp.GetStringResults(degen_id, "disk", 0)[0] vsp.PrintResults(disk_id) surf_id = vsp.GetStringResults(degen_id, "surf", 0)[0] vsp.PrintResults(surf_id) areas = vsp.GetDoubleMatResults(surf_id, "area") plate_ids = vsp.GetStringResults(degen_id, "plates") for plate_id in plate_ids: vsp.PrintResults(plate_id) stick_ids = vsp.GetStringResults(degen_id, "sticks") for stick_id in stick_ids: vsp.PrintResults(stick_id) if t != "DISK": point_id = vsp.GetStringResults(degen_id, "point")[0] vsp.PrintResults(point_id) subsurf_ids = vsp.GetStringResults(degen_id, "subsurfs") for ss_id in subsurf_ids: vsp.PrintResults(ss_id) hinge_ids = vsp.GetStringResults(degen_id, "hinges") for hinge_id in hinge_ids: vsp.PrintResults(hinge_id) self.assertTrue(True)