Source code for RCAIDE.Framework.External_Interfaces.OpenVSP.write_vsp_mesh

# write_vsp_mesh.py
# 
# Created:  Oct 2016, T. MacDonald
# Modified: Jan 2017, T. MacDonald
#           Feb 2017, T. MacDonald
#           Jan 2019, T. MacDonald
#           Jan 2020, T. MacDonald

# ----------------------------------------------------------------------------------------------------------------------
#  IMPORT
# ----------------------------------------------------------------------------------------------------------------------  
# RCAIDE imports 
try:
    import vsp as vsp
except ImportError:
    try:
        import openvsp as vsp
    except ImportError:
        # This allows RCAIDE to build without OpenVSP
        pass
import numpy as np
import time
import fileinput

# ---------------------------------------------------------------------------------------------------------------------- 
# write_vsp_mesh
# ---------------------------------------------------------------------------------------------------------------------- 
[docs] def write_vsp_mesh(geometry,tag,half_mesh_flag,growth_ratio,growth_limiting_flag): """This create an .stl surface mesh based on a vehicle stored in a .vsp3 file. Assumptions: None Source: N/A Inputs: geometry. - Also passed to set_sources wings.main_wing.chords.mean_aerodynamic [m] half_mesh_flag <boolean> determines if a symmetry plane is created growth_ratio [-] growth ratio for the mesh growth_limiting_flag <boolean> determines if 3D growth limiting is used Outputs: <tag>.stl Properties Used: N/A """ # Reset OpenVSP to avoid including a previous vehicle vsp.ClearVSPModel() if 'turbofan' in geometry.networks: print('Warning: no meshing sources are currently implemented for the nacelle') # Turn on symmetry plane splitting to improve robustness of meshing process if half_mesh_flag == True: f = fileinput.input(tag + '.vsp3',inplace=1) for line in f: if 'SymmetrySplitting' in line: print(line[0:34] + '1' + line[35:-1]) else: print(line) vsp.ReadVSPFile(tag + '.vsp3') # Set output file types and what will be meshed file_type = vsp.CFD_STL_TYPE + vsp.CFD_KEY_TYPE set_int = vsp.SET_ALL vsp.SetComputationFileName(vsp.CFD_STL_TYPE, tag + '.stl') vsp.SetComputationFileName(vsp.CFD_KEY_TYPE, tag + '.key') # Set to create a tagged STL mesh file vehicle_cont = vsp.FindContainer('Vehicle',0) STL_multi = vsp.FindParm(vehicle_cont, 'MultiSolid', 'STLSettings') vsp.SetParmVal(STL_multi, 1.0) vsp.SetCFDMeshVal(vsp.CFD_FAR_FIELD_FLAG,1) if half_mesh_flag == True: vsp.SetCFDMeshVal(vsp.CFD_HALF_MESH_FLAG,1) # Figure out the size of the bounding box vehicle_id = vsp.FindContainersWithName('Vehicle')[0] xlen = vsp.GetParmVal(vsp.FindParm(vehicle_id,"X_Len","BBox")) ylen = vsp.GetParmVal(vsp.FindParm(vehicle_id,"Y_Len","BBox")) zlen = vsp.GetParmVal(vsp.FindParm(vehicle_id,"Z_Len","BBox")) # Max length max_len = np.max([xlen,ylen,zlen]) far_length = 10.*max_len vsp.SetCFDMeshVal(vsp.CFD_FAR_SIZE_ABS_FLAG,1) vsp.SetCFDMeshVal(vsp.CFD_FAR_LENGTH,far_length) vsp.SetCFDMeshVal(vsp.CFD_FAR_WIDTH,far_length) vsp.SetCFDMeshVal(vsp.CFD_FAR_HEIGHT,far_length) vsp.SetCFDMeshVal(vsp.CFD_FAR_MAX_EDGE_LEN, max_len) vsp.SetCFDMeshVal(vsp.CFD_GROWTH_RATIO, growth_ratio) if growth_limiting_flag == True: vsp.SetCFDMeshVal(vsp.CFD_LIMIT_GROWTH_FLAG, 1.0) # Set the max edge length so we have on average 50 elements per chord length MAC = geometry.wings.main_wing.chords.mean_aerodynamic min_len = MAC/50. vsp.SetCFDMeshVal(vsp.CFD_MAX_EDGE_LEN,min_len) # vsp.AddDefaultSources() set_sources(geometry) vsp.Update() vsp.WriteVSPFile(tag + '_premesh.vsp3') print('Starting mesh for ' + tag + ' (This may take several minutes)') ti = time.time() vsp.ComputeCFDMesh(set_int,file_type) tf = time.time() dt = tf-ti print('VSP meshing for ' + tag + ' completed in ' + str(dt) + ' s')
# ---------------------------------------------------------------------------------------------------------------------- # set_sources # ----------------------------------------------------------------------------------------------------------------------
[docs] def set_sources(geometry): """This sets meshing sources in a way similar to the OpenVSP default. Some source values can also be optionally specified as below. Assumptions: None Source: https://github.com/OpenVSP/OpenVSP (with some modifications) Inputs: geometry. wings.*. (passed to add_segment_sources()) tag <string> Segments.*.percent_span_location [-] (.1 is 10%) Segments.*.root_chord_percent [-] (.1 is 10%) chords.root [m] chords.tip [m] vsp_mesh (optional) - This holds settings that are used in add_segment_sources fuselages.*. tag <string> vsp_mesh. (optional) length [m] radius [m] lengths.total (only used if vsp_mesh is not defined for the fuselage) Outputs: <tag>.stl Properties Used: N/A """ # Extract information on geometry type (for some reason it seems VSP doesn't have a simple # way to do this) comp_type_dict = dict() comp_dict = dict() for wing in geometry.wings: comp_type_dict[wing.tag] = 'wing' comp_dict[wing.tag] = wing for fuselage in geometry.fuselages: comp_type_dict[fuselage.tag] = 'fuselage' comp_dict[fuselage.tag] = fuselage # network sources have not been implemented #for network in geometry.networks: #comp_type_dict[network.tag] = 'turbojet' #comp_dict[network.tag] = network components = vsp.FindGeoms() # The default source values are (mostly) based on the OpenVSP scripts, wing for example: # https://github.com/OpenVSP/OpenVSP/blob/a5ac5302b320e8e318830663bb50ba0d4f2d6f64/src/geom_core/WingGeom.cpp for comp in components: comp_name = vsp.GetGeomName(comp) if comp_name not in comp_dict: continue comp_type = comp_type_dict[comp_name] # Nacelle sources are not implemented #if comp_name[0:8] == 'turbofan': #comp_type = comp_type_dict[comp_name[0:8]] #else: #comp_type = comp_type_dict[comp_name] if comp_type == 'wing': wing = comp_dict[comp_name] if len(wing.segments) == 0: # check if segments exist num_secs = 1 use_base = True else: if wing.segments[0].percent_span_location == 0.: # check if first segment starts at the root num_secs = len(wing.segments) use_base = False else: num_secs = len(wing.segments) + 1 use_base = True u_start = 0. base_root = wing.chords.root base_tip = wing.chords.tip for ii in range(0,num_secs): if (ii==0) and (use_base == True): # create sources on root segment cr = base_root if len(wing.segments) > 0: ct = base_root * wing.segments[0].root_chord_percent seg = wing.segments[ii] else: if 'vsp_mesh' in wing: custom_flag = True else: custom_flag = False ct = base_tip seg = wing # extract CFD source parameters if len(wing.segments) == 0: wingtip_flag = True else: wingtip_flag = False add_segment_sources(comp,cr, ct, ii, u_start, num_secs, custom_flag, wingtip_flag,seg) elif (ii==0) and (use_base == False): cr = base_root * wing.segments[0].root_chord_percent if num_secs > 1: ct = base_root * wing.segments[1].root_chord_percent else: ct = base_tip # extract CFD source parameters seg = wing.segments[ii] if 'vsp_mesh' in wing.segments[ii]: custom_flag = True else: custom_flag = False wingtip_flag = False add_segment_sources(comp,cr, ct, ii, u_start, num_secs, custom_flag, wingtip_flag,seg) elif ii < num_secs - 1: if use_base == True: jj = 1 else: jj = 0 cr = base_root * wing.segments[ii-jj].root_chord_percent ct = base_root * wing.segments[ii+1-jj].root_chord_percent seg = wing.segments[ii-jj] if 'vsp_mesh' in wing.segments[ii-jj]: custom_flag = True else: custom_flag = False wingtip_flag = False add_segment_sources(comp,cr, ct, ii, u_start, num_secs, custom_flag, wingtip_flag,seg) else: if use_base == True: jj = 1 else: jj = 0 cr = base_root * wing.segments[ii-jj].root_chord_percent ct = base_tip seg = wing.segments[ii-jj] if 'vsp_mesh' in wing.segments[ii-jj]: custom_flag = True else: custom_flag = False wingtip_flag = True add_segment_sources(comp,cr, ct, ii, u_start, num_secs, custom_flag, wingtip_flag,seg) pass elif comp_type == 'fuselage': fuselage = comp_dict[comp_name] if 'vsp_mesh' in fuselage: len1 = fuselage.vsp_mesh.length rad1 = fuselage.vsp_mesh.radius else: len1 = 0.1 * 0.5 # not sure where VSP is getting this value rad1 = 0.2 * fuselage.lengths.total uloc = 0.0 wloc = 0.0 vsp.AddCFDSource(vsp.POINT_SOURCE,comp,0,len1,rad1,uloc,wloc) uloc = 1.0 vsp.AddCFDSource(vsp.POINT_SOURCE,comp,0,len1,rad1,uloc,wloc) pass
# This is a stub for the nacelle implementation. It will create sources # as is but they will not be appropriate for the nacelle shape. #elif comp_type == 'turbofan': #network = comp_dict[comp_name[0:8]] #if network.has_key('vsp_mesh'): #len1 = network.vsp_mesh.length #rad1 = network.vsp_mesh.radius #else: #len1 = 0.1 * 0.5 # not sure where VSP is getting this value #uloc = 0.0 #wloc = 0.0 #vsp.AddCFDSource(vsp.POINT_SOURCE,comp,0,len1,rad1,uloc,wloc) #uloc = 1.0 #vsp.AddCFDSource(vsp.POINT_SOURCE,comp,0,len1,rad1,uloc,wloc) #pass # ---------------------------------------------------------------------------------------------------------------------- # add_segment_sources # ----------------------------------------------------------------------------------------------------------------------
[docs] def add_segment_sources(comp,cr,ct,ii,u_start,num_secs,custom_flag,wingtip_flag,seg): """This sets meshing sources for the wing segments according to their size and position. Assumptions: None Source: https://github.com/OpenVSP/OpenVSP (with some modifications) Inputs: comp <string> - OpenVSP component ID cr [m] - root chord ct [m] - tip chord ii [-] - segment index u_start [-] - OpenVSP parameter determining the u dimensional start point num_secs [-] - number of segments on the corresponding wing custom_flag <boolean> - determines if custom source settings are to be used wingtip_flag <boolean> - indicates if the current segment is a wingtip seg.vsp_mesh. (only used if custom_flag is True) inner_length [m] - length of inboard element edge outer_length [m] - length of outboard element edge inner_radius [m] - radius of influence for inboard source outer_radius [m] - radius of influence for outboard source Outputs: None - sources are added to OpenVSP instance Properties Used: N/A """ if custom_flag == True: len1 = seg.vsp_mesh.inner_length len2 = seg.vsp_mesh.outer_length rad1 = seg.vsp_mesh.inner_radius rad2 = seg.vsp_mesh.outer_radius else: len1 = 0.01 * cr len2 = 0.01 * ct rad1 = 0.2 * cr rad2 = 0.2 * ct uloc1 = ((ii+1)+u_start-1 +1)/(num_secs+2) # index additions are shown explicitly for cross-referencing with VSP code wloc1 = 0.5 uloc2 = ((ii+1)+u_start +1)/(num_secs+2) wloc2 = 0.5 vsp.AddCFDSource(vsp.LINE_SOURCE,comp,0,len1,rad1,uloc1,wloc1,len2,rad2,uloc2,wloc2) wloc1 = 0. wloc2 = 0. TE_match = True if (custom_flag == True) and ('matching_TE' in seg.vsp_mesh): if seg.vsp_mesh.matching_TE == False: # use default values if so vsp.AddCFDSource(vsp.LINE_SOURCE,comp,0,0.01 * cr,0.2 * cr,uloc1,wloc1,0.01 * ct,0.2 * ct,uloc2,wloc2) TE_match = False else: vsp.AddCFDSource(vsp.LINE_SOURCE,comp,0,len1,rad1,uloc1,wloc1,len2,rad2,uloc2,wloc2) else: vsp.AddCFDSource(vsp.LINE_SOURCE,comp,0,len1,rad1,uloc1,wloc1,len2,rad2,uloc2,wloc2) if wingtip_flag == True: len1 = len2 rad1 = rad2 wloc1 = 0.0 wloc2 = 0.5 uloc1 = uloc2 if TE_match == False: # to match not custom TE if indicated len1 = 0.01 * ct rad1 = 0.2 * ct vsp.AddCFDSource(vsp.LINE_SOURCE,comp,0,len1,rad1,uloc1,wloc1,len2,rad2,uloc2,wloc2)
if __name__ == '__main__': write_vsp_mesh(tag,True)