# Setup # ------------------------------------------------------------------- # filenames config_filename = 'config_NACA0012.cfg' design_filename = 'design_NACA0012.pkl' project_filename = 'project_NACA0012.pkl' # load project The_Project = libSU2.load_data(project_filename) # update project folder The_Project.folder_self = os.getcwd() # read config config_data = libSU2.Get_ConfigParams(config_filename) n_DV = len(config_data['DEFINITION_DV']['KIND']) # design variable to change i_DV = 9 # lower surface, half-chord # design variable values DV_vals = numpy.linspace(-0.02, 0.02, 11) # setup config changes config_delta = [] for X in DV_vals: DV_X = numpy.zeros(n_DV) DV_X[i_DV] = X config_delta.append({'VARIABLES': DV_X})
def process_surface_adjoint(config_filename, filter_type='LAPLACE', marker_name='airfoil', chord_length=1.0): print('') print( '-------------------------------------------------------------------------' ) print( '| SU2 Suite (Process Surface Adjoint) |' ) print( '-------------------------------------------------------------------------' ) print('') # some other defaults c_clip = 0.01 # percent chord to truncate fft_copy = 5 # number of times to copy the fft signal smth_len = 0.05 # percent chord smoothing window length lapl_len = 1e-4 # laplace smoothing parameter # read config file config_data = libSU2.Get_ConfigParams(config_filename) surface_filename = config_data['SURFACE_ADJ_FILENAME'] + '.csv' print surface_filename mesh_filename = config_data['MESH_FILENAME'] gradient = config_data['ADJ_OBJFUNC'] print('Config filename = %s' % config_filename) print('Surface filename = %s' % surface_filename) print('Filter Type = %s' % filter_type) # read adjoint data adj_data = np.genfromtxt(surface_filename, dtype=float, delimiter=',', skip_header=1) # read mesh data mesh_data = libSU2_mesh.Read_Mesh(mesh_filename) # proces adjoint data P = map(int, adj_data[:, 0]) X = adj_data[:, 6].copy() Y = adj_data[:, 7].copy() Sens = adj_data[:, 1].copy() PsiRho = adj_data[:, 2].copy() I = range(0, len(P)) # important - for unsorting durring write # store in dict by point index adj_data_dict = dict(zip(P, zip(X, Y, Sens, PsiRho, I))) # sort airfoil points iP_sorted, _ = libSU2_mesh.sort_Airfoil(mesh_data, marker_name) assert (len(iP_sorted) == len(P)) # rebuild airfoil loop i = 0 for this_P in iP_sorted: # the adjoint data entry this_adj_data = adj_data_dict[this_P] # re-sort P[i] = this_P X[i] = this_adj_data[0] Y[i] = this_adj_data[1] Sens[i] = this_adj_data[2] PsiRho[i] = this_adj_data[3] I[i] = this_adj_data[4] # next i = i + 1 #: for each point # calculate arc length S = np.sqrt(np.diff(X)**2 + np.diff(Y)**2) / chord_length S = np.cumsum(np.hstack([0, S])) # tail trucating, by arc length I_clip_lo = S < S[0] + c_clip I_clip_hi = S > S[-1] - c_clip S_clip = S.copy() Sens_clip = Sens.copy() Sens_clip[I_clip_hi] = Sens_clip[I_clip_hi][0] Sens_clip[I_clip_lo] = Sens_clip[I_clip_lo][-1] # some edge length statistics dS_clip = np.diff(S_clip) min_dS = np.min(dS_clip) mean_dS = np.mean(dS_clip) max_dS = np.max(dS_clip) #print 'min_dS = %.4e ; mean_dS = %.4e ; max_dS = %.4e' % ( min_dS , mean_dS , max_dS ) # -------------------------------------------- # APPLY FILTER if filter_type == 'FOURIER': Freq_notch = [1 / max_dS, np.inf] # the notch frequencies Sens_filter, Frequency, Power = fft_filter(S_clip, Sens_clip, Freq_notch, fft_copy) #Sens_filter = smooth(S_clip,Sens_filter, 0.03,'blackman') # post smoothing elif filter_type == 'WINDOW': Sens_filter = window(S_clip, Sens_clip, smth_len, 'blackman') elif filter_type == 'LAPLACE': Sens_filter = laplace(S_clip, Sens_clip, lapl_len) elif filter_type == 'SHARPEN': Sens_smooth = smooth(S_clip, Sens_clip, smth_len / 5, 'blackman') # pre smoothing Sens_smoother = smooth(S_clip, Sens_smooth, smth_len, 'blackman') Sens_filter = Sens_smooth + (Sens_smooth - Sens_smoother) # sharpener else: raise Exception, 'unknown filter type' # -------------------------------------------- # PLOTTING if pylab_imported: # start plot fig = plt.figure(gradient) plt.clf() #if not fig.axes: # for comparing two filter calls #plt.subplot(1,1,1) #ax = fig.axes[0] #if len(ax.lines) == 4: #ax.lines.pop(0) #ax.lines.pop(0) # SENSITIVITY plt.plot(S, Sens, color='b') # original plt.plot(S_clip, Sens_filter, color='r') # filtered plt.xlim(-0.1, 2.1) plt.ylim(-5, 5) plt.xlabel('Arc Length') plt.ylabel('Surface Sensitivity') #if len(ax.lines) == 4: #seq = [2, 2, 7, 2] #ax.lines[0].set_dashes(seq) #ax.lines[1].set_dashes(seq) plot_filename = os.path.splitext(surface_filename)[0] + '.png' plt.savefig('Sens_' + plot_filename, dpi=300) # zoom in plt.ylim(-0.4, 0.4) plt.savefig('Sens_zoom_' + plot_filename, dpi=300) # SPECTRAL if filter_type == 'FOURIER': plt.figure('SPECTRAL') plt.clf() plt.plot(Frequency, Power) #plt.xlim(0,Freq_notch[0]+10) plt.xlim(0, 200) plt.ylim(0, 0.15) plt.xlabel('Frequency (1/C)') plt.ylabel('Surface Sensitivity Spectal Power') plt.savefig('Spectral_' + plot_filename, dpi=300) #: if spectral plot #: if plot # -------------------------------------------- # SAVE SURFACE FILE # reorder back to input surface points Sens_out = np.zeros(len(S)) Sens_out[I] = Sens_filter # left over from sort adj_data[:, 1] = Sens_out # get surface header surface_orig = open(surface_filename, 'r') header = surface_orig.readline() surface_orig.close() # get list of prefix names prefix_names = libSU2.get_AdjointPrefix(None) prefix_names = prefix_names.values() # add filter prefix, before adjoint prefix surface_filename_split = surface_filename.rstrip('.csv').split('_') if surface_filename_split[-1] in prefix_names: surface_filename_split = surface_filename_split[0:-1] + [ 'filtered' ] + [surface_filename_split[-1]] else: surface_filename_split = surface_filename_split + ['filtered'] surface_filename_new = '_'.join(surface_filename_split) + '.csv' # write filtered surface file (only updates Sensitivity) surface_new = open(surface_filename_new, 'w') surface_new.write(header) for row in adj_data: for i, value in enumerate(row): if i > 0: surface_new.write(', ') if i == 0: surface_new.write('%i' % value) else: surface_new.write('%.16e' % value) surface_new.write('\n') surface_new.close() print('') print( '----------------- Exit Success (Process Surface Adjoint) ----------------' ) print('') return
def mesh_adaptation(filename, partitions=0, cycles=1, overwrite=False, save_all=False): # General and default parameters Config_INP_filename = filename Config_CFD_filename = "config_CFD_" + Config_INP_filename Config_MAC_filename = "config_MAC_" + Config_INP_filename #Mesh_MAC_filename = "mesh_MAC_" + filename.replace(".cfg",".su2") finest_mesh_filename = "mesh_finest.su2" finest_flow_filename = "restart_flow_finest.dat" finest_lin_filename = "restart_lin_finest.dat" finest_adj_filename = "restart_adj_finest.dat" # assumes serial with partitions = 1 if partitions == 1: partitions = 0 # Get parameters params_get = libSU2.Get_ConfigParams(Config_INP_filename) kind_adapt = params_get['KIND_ADAPT'] objfunc = params_get['ADJ_OBJFUNC'] restart_flow_file = params_get['RESTART_FLOW_FILENAME'] restart_adj_file = params_get['RESTART_ADJ_FILENAME'] original_mesh_file = params_get['MESH_FILENAME'] #output_mesh_file = params_get['MESH_OUT_FILENAME'] Mesh_MAC_filename = params_get['MESH_OUT_FILENAME'] cadj_prefix = libSU2.get_AdjointPrefix(objfunc) # Get solution file names volume_flow_file = params_get['VOLUME_FLOW_FILENAME'] volume_adj_file = params_get['VOLUME_ADJ_FILENAME'] surface_flow_file = params_get['SURFACE_FLOW_FILENAME'] surface_adj_file = params_get['SURFACE_ADJ_FILENAME'] history_file = params_get['CONV_FILENAME'] # Get mesh filenames and filetypes mesh_filetype = params_get['MESH_FORMAT'] if mesh_filetype == "CGNS": error_str = "Currently cannot support mesh adaptation with CGNS grid files. Please convert your CGNS mesh to SU2 format using the CGNS_TO_SU2 flag in the configuration file, re-specify the mesh file to the native .su2 file and set the MESH_FORMAT flag to SU2." print "\n*****\n" + error_str + "\n*****\n" return 1 elif mesh_filetype == "NETCDF_ASCII": error_str = "Currently cannot support mesh adaptation with NETCDF_ASCII grid files. Please convert your mesh to SU2 format, re-specify the mesh file to the native .su2 file and set the MESH_FORMAT flag to SU2." print "\n*****\n" + error_str + "\n*****\n" return 1 # Get output solution filetypes output_filetype = params_get['OUTPUT_FORMAT'] if output_filetype == "TECPLOT": vol_file_ext = ".plt" elif output_filetype == "PARAVIEW": vol_file_ext = ".vtk" if ((kind_adapt == "ROBUST") or (kind_adapt == "COMPUTABLE_ROBUST")): restart_lin_file = params_get['RESTART_LIN_FILENAME'] # Loop over number of adaptation cycles for iAdaptCycle in range(cycles): # Copy original input file to working files shutil.copy(Config_INP_filename, Config_MAC_filename) shutil.copy(Config_INP_filename, Config_CFD_filename) # Run direct flow simulation # For iAdaptCycle == 0, store restart file, objective function and original mesh file params_set = {'MATH_PROBLEM': 'DIRECT'} if iAdaptCycle > 0: params_set.update({ 'RESTART_SOL': 'YES', 'ADJ_OBJFUNC': objfunc, 'RESTART_FLOW_FILENAME': restart_flow_file, 'RESTART_ADJ_FILENAME': restart_adj_file, 'SOLUTION_FLOW_FILENAME': restart_flow_file, 'MESH_FILENAME': Mesh_MAC_filename }) if ((kind_adapt == "ROBUST") or kind_adapt == ("COMPUTABLE_ROBUST")): params_set.update({'RESTART_LIN_FILENAME': restart_lin_file}) # Load the new config file options and run the direct problem libSU2.Set_ConfigParams(Config_CFD_filename, params_set) if partitions > 1: parallel_computation(Config_CFD_filename, partitions) else: libSU2_run.SU2_CFD(Config_CFD_filename, partitions) # Copy flow solution & history file if save_all: print "Saving cycle " + str( iAdaptCycle) + " flow solution and history files..." print "Saving " + volume_flow_file + "_cycle" + str( iAdaptCycle) + vol_file_ext print "Saving " + surface_flow_file + "_cycle" + str( iAdaptCycle) + vol_file_ext print "Saving " + history_file + "_flow_cycle" + str( iAdaptCycle) + vol_file_ext shutil.move( volume_flow_file + vol_file_ext, volume_flow_file + "_cycle" + str(iAdaptCycle) + vol_file_ext) shutil.move( surface_flow_file + vol_file_ext, surface_flow_file + "_cycle" + str(iAdaptCycle) + vol_file_ext) shutil.move( surface_flow_file + ".csv", surface_flow_file + "_cycle" + str(iAdaptCycle) + ".csv") shutil.move( history_file + vol_file_ext, history_file + "_flow_cycle" + str(iAdaptCycle) + vol_file_ext) # If needed, run the adjoint simulation # For the first adaption cycle, use the filenames of the orignal .cfg file if (kind_adapt == "GRAD_ADJOINT" or kind_adapt == "GRAD_FLOW_ADJ" or kind_adapt == "ROBUST" or kind_adapt == "COMPUTABLE_ROBUST" or kind_adapt == "COMPUTABLE" or kind_adapt == "REMAINING"): params_set = { 'MATH_PROBLEM': 'ADJOINT', 'SOLUTION_FLOW_FILENAME': restart_flow_file } if iAdaptCycle > 0: params_set.update({ 'RESTART_SOL': 'YES', 'SOLUTION_ADJ_FILENAME': restart_adj_file, 'MESH_FILENAME': Mesh_MAC_filename }) # Load the new config file options and run the adjoint problem libSU2.Set_ConfigParams(Config_CFD_filename, params_set) if partitions > 1: parallel_computation(Config_CFD_filename, partitions) else: libSU2_run.SU2_CFD(Config_CFD_filename, partitions) # Copy adjoint solution & history file if save_all: print "Saving cycle " + str( iAdaptCycle) + " adjoint solution and history files..." print "Saving " + volume_adj_file + "_cycle" + str( iAdaptCycle) + vol_file_ext print "Saving " + surface_adj_file + "_adj_cycle" + str( iAdaptCycle) + vol_file_ext print "Saving " + history_file + "_flow_cycle" + str( iAdaptCycle) + vol_file_ext shutil.move( volume_adj_file + vol_file_ext, volume_adj_file + "_cycle" + str(iAdaptCycle) + vol_file_ext) shutil.move( surface_adj_file + vol_file_ext, surface_adj_file + "_cycle" + str(iAdaptCycle) + vol_file_ext) shutil.move( surface_adj_file + ".csv", surface_adj_file + "_cycle" + str(iAdaptCycle) + ".csv") shutil.move( history_file + vol_file_ext, history_file + "_adj_cycle" + str(iAdaptCycle) + vol_file_ext) # If needed, change the parameters to run the first linear simulation # For the first adaptation cycle, use the filenames from the original .cfg file if kind_adapt == "COMPUTABLE_ROBUST": params_set = { 'MATH_PROBLEM': 'LINEARIZED', 'SOLUTION_FLOW_FILENAME': restart_flow_file } if iAdaptCycle > 0: params_set.update({ 'RESTART_SOL': 'YES', 'RESTART_LIN_FILENAME': restart_lin_file, 'MESH_FILENAME': Mesh_MAC_filename }) # Load the new config file options and run the linearized problem libSU2.Set_ConfigParams(Config_CFD_filename, params_set) if partitions > 1: parallel_computation(Config_CFD_filename, partitions) else: libSU2_run.SU2_CFD(Config_CFD_filename, partitions) # Change the parameters to do a direct and adjoint iteration over a fine grid if ((kind_adapt == "ROBUST" or kind_adapt == "COMPUTABLE" or kind_adapt == "COMPUTABLE_ROBUST" or kind_adapt == "REMAINING") and (iAdaptCycle < cycles - 1 or cycles == 1)): # Create the fine grid and interpolate the flow solution from coarse to refined grid params_set = { 'KIND_ADAPT': "FULL_FLOW", 'SOLUTION_FLOW_FILENAME': restart_flow_file, 'RESTART_FLOW_FILENAME': finest_flow_filename, 'MESH_FILENAME': original_mesh_file, 'MESH_OUT_FILENAME': finest_mesh_filename } if iAdaptCycle > 0: params_set.update({'MESH_FILENAME': Mesh_MAC_filename}) # Run the mesh adaptation module libSU2.Set_ConfigParams(Config_MAC_filename, params_set) libSU2_run.SU2_MAC(Config_MAC_filename, partitions) # Create the fine grid and interpolate the adjoint solution from coarse to refined grid params_set = { 'KIND_ADAPT': "FULL_ADJOINT", 'SOLUTION_FLOW_FILENAME': restart_flow_file, 'SOLUTION_ADJ_FILENAME': restart_adj_file, 'RESTART_FLOW_FILENAME': finest_flow_filename, 'RESTART_ADJ_FILENAME': finest_adj_filename, 'MESH_FILENAME': original_mesh_file, 'MESH_OUT_FILENAME': finest_mesh_filename } if iAdaptCycle > 0: params_set.update({'MESH_FILENAME': Mesh_MAC_filename}) # Run the mesh adaptation module libSU2.Set_ConfigParams(Config_MAC_filename, params_set) libSU2_run.SU2_MAC(Config_MAC_filename, partitions) # Create the fine grid and interpolate the linear solution from coarse to refined grid if kind_adapt == "COMPUTABLE_ROBUST": params_set = { 'KIND_ADAPT': "FULL_LINEAR", 'SOLUTION_FLOW_FILENAME': restart_flow_file, 'SOLUTION_LIN_FILENAME': restart_lin_file, 'RESTART_FLOW_FILENAME': finest_flow_filename, 'RESTART_ADJ_FILENAME': finest_lin_filename, 'MESH_FILENAME': original_mesh_file, 'MESH_OUT_FILENAME': finest_mesh_filename } if iAdaptCycle > 0: params_set.update({'MESH_FILENAME': Mesh_MAC_filename}) # Run the mesh adaptation module libSU2.Set_ConfigParams(Config_MAC_filename, params_set) libSU2_run.SU2_MAC(Config_MAC_filename, partitions) # Change the parameters to do one iteration of the flow solver on the finest grid # Always start from the interpolated solution and store the residual in the solution file for finest grid # No multigrid or convergence acceleration params_set = { 'MATH_PROBLEM': 'DIRECT', 'EXT_ITER': 2, 'RESTART_SOL': 'YES', 'SOLUTION_FLOW_FILENAME': finest_flow_filename, 'STORE_RESIDUAL': 'YES', 'RESTART_FLOW_FILENAME': finest_flow_filename, 'MESH_FILENAME': finest_mesh_filename, 'FULLMG': 'NO', 'MGLEVEL': 0, 'MGCYCLE': 0, 'MG_PRE_SMOOTH': '( 0 )', 'MG_POST_SMOOTH': '( 0 )', 'MG_CORRECTION_SMOOTH': '( 0 )' } libSU2.Set_ConfigParams(Config_CFD_filename, params_set) if partitions > 1: parallel_computation(Config_CFD_filename, partitions) else: libSU2_run.SU2_CFD(Config_CFD_filename, partitions) # Change the parameters to do one iteration of the adjoint solver on the finest grid # Always start from the interpolated solution and store the residual in the solution file for finest grid # No multigrid or convergence acceleration params_set = { 'MATH_PROBLEM': 'ADJOINT', 'EXT_ITER': 2, 'RESTART_SOL': 'YES', 'SOLUTION_FLOW_FILENAME': finest_flow_filename, 'SOLUTION_ADJ_FILENAME': finest_adj_filename, 'MESH_FILENAME': finest_mesh_filename, 'FULLMG': 'NO', 'MGLEVEL': 0, 'MGCYCLE': 0, 'MG_PRE_SMOOTH': '( 0 )', 'MG_POST_SMOOTH': '( 0 )', 'MG_CORRECTION_SMOOTH': '( 0 )' } libSU2.Set_ConfigParams(Config_CFD_filename, params_set) if partitions > 1: parallel_computation(Config_CFD_filename, partitions) else: libSU2_run.SU2_CFD(Config_CFD_filename, partitions) # Change the parameters to do one iteration of the linear solver on the finest grid # Always start from the interpolated solution and store the residual in the solution file for finest grid # No multigrid or convergence acceleration if kind_adapt == "COMPUTABLE_ROBUST": params_set = { 'MATH_PROBLEM': 'LINEARIZED', 'EXT_ITER': 2, 'RESTART_SOL': 'YES', 'SOLUTION_FLOW_FILENAME': finest_flow_filename, 'SOLUTION_LIN_FILENAME': finest_lin_filename, 'RESTART_LIN_FILENAME': finest_lin_filename, 'MESH_FILENAME': finest_mesh_filename, 'FULLMG': 'NO', 'MGLEVEL': 0, 'MGCYCLE': 0, 'MG_PRE_SMOOTH': '( 0 )', 'MG_POST_SMOOTH': '( 0 )', 'MG_CORRECTION_SMOOTH': '( 0 )' } libSU2.Set_ConfigParams(Config_CFD_filename, params_set) if partitions > 1: parallel_computation(Config_CFD_filename, partitions) else: libSU2_run.SU2_CFD(Config_CFD_filename, partitions) # Perform adaptation using above solution files if ((kind_adapt == "GRAD_FLOW") or (kind_adapt == "GRAD_ADJOINT") or (kind_adapt == "GRAD_FLOW_ADJ")): params_set = { 'SOLUTION_FLOW_FILENAME': restart_flow_file, 'SOLUTION_ADJ_FILENAME': restart_adj_file } elif ((kind_adapt == "COMPUTABLE") or (kind_adapt == "REMAINING")): params_set = { 'SOLUTION_FLOW_FILENAME': finest_flow_filename, 'SOLUTION_ADJ_FILENAME': finest_adj_filename, 'RESTART_FLOW_FILENAME': restart_flow_file, 'RESTART_ADJ_FILENAME': restart_adj_file } elif ((kind_adapt == "ROBUST") or (kind_adapt == "COMPUTABLE_ROBUST")): params_set = { 'SOLUTION_FLOW_FILENAME': finest_flow_filename, 'SOLUTION_ADJ_FILENAME': finest_adj_filename, 'SOLUTION_LIN_FILENAME': finest_lin_filename, 'RESTART_FLOW_FILENAME': restart_flow_file, 'RESTART_ADJ_FILENAME': restart_adj_file, 'RESTART_LIN_FILENAME': restart_lin_file } params_set.update({ 'KIND_ADAPT': kind_adapt, 'MESH_OUT_FILENAME': Mesh_MAC_filename }) if iAdaptCycle > 0: params_set.update({'MESH_FILENAME': Mesh_MAC_filename}) # Run the mesh adaptation module libSU2.Set_ConfigParams(Config_MAC_filename, params_set) libSU2_run.SU2_MAC(Config_MAC_filename, partitions) # Copy cycle mesh file if save_all: print "Saving cycle " + str(iAdaptCycle) + " mesh file..." shutil.copy( Mesh_MAC_filename, Mesh_MAC_filename.replace(".su2", "_cycle" + str(iAdaptCycle) + ".su2")) # Clean up if overwrite: os.rename(Mesh_MAC_filename, original_mesh_file) if ((kind_adapt == "ROBUST") or (kind_adapt == "COMPUTABLE") or (kind_adapt == "COMPUTABLE_ROBUST") or (kind_adapt == "REMAINING")): os.remove(finest_mesh_filename) os.remove(finest_flow_filename) if kind_adapt == "COMPUTABLE_ROBUST": os.remove(finest_lin_filename) if save_all: os.remove(Mesh_MAC_filename) os.remove(Config_MAC_filename) os.remove(Config_CFD_filename)