[D0028] 最適化の寸法範囲の探索

 

最適化のパラメータ変数範囲の最大値と最小値を探索する。

import designer
import csv
import subprocess

app = designer.GetApplication()

class DialogData:
	def __init__(self):
		self.num_trials = 20
		self.csv_file_name = ""
		self.is_open_csv = False
		self.is_update_range = False
		self.is_add_cases = False
		self.is_valid = False

class RangeData:
	def __init__(self):
		self.name = ""
		self.optimization_range= 0
		self.param_index = 0
		self.init_value = 0

def main():
	data = get_data_from_input_dialog()

	if data.is_valid == False:
		return

	if search_size_range_in_optimization_table(data)==False:
		return

	show_normal_exit_message()

def get_data_from_input_dialog():
	dialog = create_input_dialog()
	return show_input_dialog(dialog)

def create_input_dialog():
	dialog = app.CreateDialogBox()

	title_jp = "最適化の寸法範囲の探索"
	title_en = "Search Size Range in Optimization Table"
	inputlbl_jp = "入力:"
	inputlbl_en = "Input:"
	outputlbl_jp = "出力:"
	outputlbl_en = "Output:"
	optionlbl_jp = "オプション:"
	optionlbl_en = "Option:"
	numtrialslbl_jp = "探索回数:"
	numtrialslbl_en = "Number of Search:"
	noteslbl_jp = "1寸法あたりの探索回数は上限側/下限側合わせて、探索回数*2になります"
	noteslbl_en = "Number of searches per dimension is equal to number of search times * 2 with upper limit side / lower limit side combined"
	csvfile_jp = "結果ファイル:"
	csvfile_en = "Result File:"
	updatevallbl_jp = "最適化ダイアログの寸法値の最大値/最小値を更新する"
	updatevallbl_en = "Update Max/Min of The Dimensions in Optimization Dialog"
	leavecaseslbl_jp = "探索で形状を生成したケースを追加する"
	leavecaseslbl_en = "Add Cases that Generated Shapes in Search"

	dialog.SetTranslation(title_en, title_jp)
	dialog.SetTranslation(inputlbl_en, inputlbl_jp)
	dialog.SetTranslation(outputlbl_en, outputlbl_jp)
	dialog.SetTranslation(optionlbl_en, optionlbl_jp)
	dialog.SetTranslation(numtrialslbl_en, numtrialslbl_jp)
	dialog.SetTranslation(noteslbl_en, noteslbl_jp)
	dialog.SetTranslation(csvfile_en, csvfile_jp)
	dialog.SetTranslation(updatevallbl_en, updatevallbl_jp)
	dialog.SetTranslation(leavecaseslbl_en, leavecaseslbl_jp)

	dialog.SetTitle(title_en)
	dialog.AddLabel(inputlbl_en)
	dialog.AddInteger("num_trials", numtrialslbl_en, 20)
	dialog.SetTooltip("num_trials", noteslbl_en)
	dialog.AddLine()
	dialog.AddLabel(outputlbl_en)
	dialog.AddSaveFilename("csv_file_name", csvfile_en, "", "CSV file (*.csv)")
	dialog.AddLine()
	dialog.AddLabel(optionlbl_en)
	dialog.AddCheckBox("is_update_range", updatevallbl_en, False)
	dialog.AddCheckBox("is_add_cases", leavecaseslbl_en, False)

	return dialog

def show_input_dialog(dialog):
	dialog.Show()
	
	if dialog.WasCancelled() == False:
		data = get_values_from_input_dialog(dialog)
		if data.is_valid == False:
			return show_input_dialog(dialog)
		return data
	return DialogData()

def get_values_from_input_dialog(dialog):
	data = DialogData()

	if dialog.GetValue("num_trials") <= 0:
		message_en = "The number of trials must be greater than 0."
		message_jp = "探索回数は0より大きな値を入力してください。"
		show_error_exit_message(message_en, message_jp)
		return data
	if dialog.GetValue("csv_file_name") == "":
		message_en = "Please specify result file name."
		message_jp = "結果ファイル名を指定してください。"
		show_error_exit_message(message_en, message_jp)
		return data

	data.num_trials = dialog.GetValue("num_trials")
	data.is_update_range = dialog.GetValue("is_update_range")
	data.is_add_cases = dialog.GetValue("is_add_cases")
	data.csv_file_name = dialog.GetValue("csv_file_name")
	data.is_valid = True

	return data

def search_size_range_in_optimization_table(data):
	range_list = []

	if check_optimization_range(range_list) == False:
		return False

	if app.GetCurrentModel().IsCadLinkOpen() == False:
		app.GetCurrentModel().RestoreCadLink()

	app.GetCurrentStudy().SetCurrentCase(0)

	geomApp = app.CreateGeometryEditor()
	geomDoc = geomApp.GetDocument()

	if geomDoc.NumBuildMessages() > 0:
		show_error_exit_message("Initial case has error.", "初期ケースにエラーがあります。")
		return False

	initialTopologyKey = geomDoc.GetTopologyHashKey()
	designTable = app.GetCurrentStudy().GetDesignTable()
	num_case = designTable.NumCases()

	result_list = []

	for range_data in range_list:
		optimizationRange = range_data.optimization_range

		result = []
		result.append(range_data.name)
		result.append(search_size_range(range_data, optimizationRange.GetMin(), geomDoc, initialTopologyKey, data.num_trials))
		result.append(search_size_range(range_data, optimizationRange.GetMax(), geomDoc, initialTopologyKey, data.num_trials))
		result_list.append(result)

		if data.is_update_range == True:
			set_range_to_optimization_table(optimizationRange, result[1], result[2])

		if data.is_add_cases == False:
			remove_temp_cases(num_case)

	output_csv_file(result_list, data.csv_file_name)

	return True

def check_optimization_range(range_list):
	designTable = app.GetCurrentStudy().GetDesignTable()
	optimizationTable = app.GetCurrentStudy().GetOptimizationTable()
	numParam = designTable.NumParameters()

	for i in range(numParam):
		if is_optimization_item(i) == False:
			continue

		name = designTable.ParameterName(i)
		optimizationRange = optimizationTable.GetParametricItemByParameterName(name)
		ini = designTable.GetValue(0, i)

		if app.HasError():
			app.ClearError()
			optimizationTable.AddParametricItem(name)
			optimizationRange = optimizationTable.GetParametricItemByParameterName(name)
			optimizationRange.SetMin(ini)
			optimizationRange.SetMax(ini)

		min = optimizationRange.GetMin()
		max = optimizationRange.GetMax()

		if max < min:
			message_en = "Maximum value of {0} in optimization dialog must be greater than or equal to minimum value.".format(name)
			message_jp = "最適化ダイアログの {0} の最大値は最小値以上の値を入力してください。".format(name)
			show_error_exit_message(message_en, message_jp)
			return False
		if min > ini:
			message_en = "Minimum value of {0} in optimization dialog must be less than or equal to that of initial case.".format(name)
			message_jp = "最適化ダイアログの {0} の最小値は初期ケースの値以下の値を入力してください。".format(name)
			show_error_exit_message(message_en, message_jp)
			return False
		if max < ini:
			message_en = "Maximum value of {0} in optimization dialog must be greater than or equal to that of initial case.".format(name)
			message_jp = "最適化ダイアログの {0} の最大値は初期ケースの値以上の値を入力してください。".format(name)
			show_error_exit_message(message_en, message_jp)
			return False

		data = RangeData()
		data.name = name
		data.optimization_range = optimizationRange
		data.param_index = i
		data.init_value = ini
		range_list.append(data)

	return True

def is_optimization_item(index):
	designTable = app.GetCurrentStudy().GetDesignTable()

	if designTable.IsCadParameter(index):
		if designTable.ParameterTypeName(index) == "Real":
			return True
	return False

def search_size_range(range_data, limit, geomDoc, initialTopologyKey, num_trials):
	designTable = app.GetCurrentStudy().GetDesignTable()
	ini = range_data.init_value
	paramIndex = range_data.param_index

	shift = 0.0
	shift = abs(limit - ini) / 2
	if shift == 0:
		return limit
	elif limit > ini:
		sign = 1
	else:
		sign = -1

	binary = 0.0
	binary = limit
	for i in range(num_trials):
		designTable.AddCase()
		lastIndex = designTable.NumCases() - 1
		for j in range(designTable.NumParameters()):
			designTable.SetValue(lastIndex, j, designTable.GetValue(0, j))

		designTable.SetValue(lastIndex, paramIndex, binary)
		app.GetCurrentStudy().SetCurrentCase(lastIndex)
		if geomDoc.NumBuildMessages() > 0 or geomDoc.GetTopologyHashKey() != initialTopologyKey:
			binary = designTable.GetValue(lastIndex, paramIndex) - sign * shift
		else:
			if designTable.GetValue(lastIndex, paramIndex) == limit:
				return limit
			binary = designTable.GetValue(lastIndex, paramIndex) + sign * shift
		shift /= 2
	return designTable.GetValue(lastIndex, paramIndex)

def set_range_to_optimization_table(optimizationRange, min, max):
	if optimizationRange.GetMin() != min:
		optimizationRange.SetMin(min)
	if optimizationRange.GetMax() != max:
		optimizationRange.SetMax(max)

def remove_temp_cases(num_case):
	designTable = app.GetCurrentStudy().GetDesignTable()

	while num_case < designTable.NumCases():
		index = designTable.NumCases() - 1
		designTable.RemoveCase(index)

def output_csv_file(range_list, csv_file_name):
	f = open(csv_file_name.decode('utf-8'), 'w')
	writer = csv.writer(f, lineterminator='\n')
	writer.writerow(["ParameterName", "Min", "Max"])

	for line in range_list:
		writer.writerow(line)

	f.close()

def show_normal_exit_message():
	title_en = "Search Finished"
	title_jp = "探索終了"
	message_en = "Search of Dimension Range is Finished."
	message_jp = "寸法範囲の探索が終了しました。"

	show_message(title_en, title_jp, message_en, message_jp)

def show_error_exit_message(message_en, message_jp):
	title_en = "Error"
	title_jp = "エラー"

	show_message(title_en, title_jp, message_en, message_jp)

def show_message(title_en, title_jp, message_en, message_jp):
	msgdlg = app.CreateDialogBox()

	msgdlg.SetTranslation(title_en, title_jp)
	msgdlg.SetTranslation(message_en, message_jp)

	msgdlg.SetCancelButtonVisible(False)
	msgdlg.SetTitle(title_en)
	msgdlg.AddLabel(message_en)
	msgdlg.Show()

main()

Download Python source code

ファイルご利用の注意点

JMAGスクリプトライブラリをご利用されるに際し、以下の利用規約をよくお読みいただき、ご同意の上ご利用下さるようお願い申し上げます。