[D0035] 伝達関数による振動評価

 

伝達関数を使って、観測点の振動を評価する。

import designer

import locale
import os
import math
import cmath
import csv
import time
import datetime
import tempfile
import shutil
import sys
import traceback
import inspect
import configparser

import logging
from logging import getLogger, StreamHandler, FileHandler, Formatter

SCRIPT_NAME="VibrationEvaluationWithTransferFunction"
logger = getLogger(SCRIPT_NAME)

TRANSFER_FUNCTION_FILE_PATH = "transfer_function_csv_file_name"
TRANSFER_FUNCTION_COORDINATE_SYSTEM = "transfer_function_coordinate_system"
OUTPUT_RESULT_TYPE = "output_result_type"
# LOG_FILE_PATH = ""
USE_PROGRESS = False

app = designer.GetApplication()


def main():
	setup_logger()
	run()
	teardown_logger()

def CanUseScript():
	app = designer.GetApplication()
	studies, err_en, err_jp = GetCanUseScriptStudies(app)
	res = len(studies) > 0
	return res

def GetCanUseScriptStudies(app):
	model = app.GetCurrentModel()
	study_list = []
	err_en = str()
	err_jp = str()
	if app.NumAnalysisGroups() > 0:
		analysisGroup = app.GetCurrentAnalysisGroup()
		designTable = analysisGroup.GetDesignTable()
		err_en_list = []
		err_jp_list = []
		for i in range(analysisGroup.NumStudies()):
			study = analysisGroup.GetStudy(i)
			canUse, tmp_err_en, tmp_err_jp = CanUseScriptModelStudy(model, study, designTable)
			if canUse:
				study_list.append(study)
			else:
				err_en_list.append(f"{study.GetName()}:{tmp_err_en}")
				err_jp_list.append(f"{study.GetName()}:{tmp_err_jp}")
		if len(study_list)==0:
			err_en = "There are no runnable models or studies in the analysis group."
			err_jp = "解析グループ内に実行可能なモデル/スタディが存在しません。"
			for i in range(len(err_en_list)):
				err_en += "\n" + err_en_list[i]
				err_jp += "\n" + err_jp_list[i]
	else:
		study = app.GetCurrentStudy()
		designTable = study.GetDesignTable()
		canUse, err_en, err_jp = CanUseScriptModelStudy(model, study, designTable)
		if canUse:
			study_list.append(study)
	return (study_list, err_en, err_jp)


def CanUseScriptModelStudy(model, study, designTable):
	if (model.IsValid() == False):
		debugShowErrorMessage_expr("No model.")
		return (False,
				"There is no model.",
				"モデルがありません。")
		return False
	if (study.IsValid() == False):
		debugShowErrorMessage_expr("No study.")
		return (False,
				"There is no study.",
				"スタディがありません。")
	## Analysis Type Check
	is2DTR = study.GetScriptTypeName() == "Transient2D"
	is3DTR = study.GetScriptTypeName() == "Transient"
	if ((not is2DTR) and (not is3DTR)):
		debugShowErrorMessage_expr("Current study is unsupported analysis type.")
		return (False,
				f"The target study is neither a 2D Magnetic Field Transient Analysis nor a 3D Magnetic Field Transient Analysis.\n Target study type = {study.GetType()}",
				f"対象のスタディは2次元磁界過渡応答解析または3次元磁界過渡応答解析ではありません。\n 対象のスタディタイプ = {study.GetType()}")

	## Nodal Force Table Check
	teeth_R_utf8 = (b'\xe3\x83\x86\xe3\x82\xa3\xe3\x83\xbc\xe3\x82\xb9\x5f\x52\xe6\x88\x90\xe5\x88\x86').decode('utf-8')
	teeth_T_utf8 = (b'\xe3\x83\x86\xe3\x82\xa3\xe3\x83\xbc\xe3\x82\xb9\x5f\x54\x68\x65\x74\x61\xe6\x88\x90\xe5\x88\x86').decode('utf-8')
	teeth_Z_utf8 = (b'\xe3\x83\x86\xe3\x82\xa3\xe3\x83\xbc\xe3\x82\xb9\x5f\x5a\xe6\x88\x90\xe5\x88\x86').decode('utf-8')

	cd_R =findNodalForceCalculationDefinition_expr(study, "Radial", "ティース_R成分", "Tooth_R", teeth_R_utf8)
	cd_T =findNodalForceCalculationDefinition_expr(study, "Theta", "ティース_Theta成分", "Tooth_T", teeth_T_utf8)
	if (cd_R is None) or (cd_T is None) :
		debugShowErrorMessage_expr("Force is not found.")
		return (False,
				"There is no setting to calculate electromagnetic forces in the target study.",
				"対象のスタディに電磁力を計算する設定がありません。")
	if is3DTR:
		cd_Z =findNodalForceCalculationDefinition_expr(study, "Z", "ティース_Z成分", "Tooth_Z", teeth_Z_utf8)
		if (cd_Z is None):
			debugShowErrorMessage_expr("Force is not found.")
			return (False,
					"There is no setting to calculate electromagnetic forces in the target study.",
					"対象のスタディに電磁力を計算する設定がありません。")

	if not designTable.HasEquation("POLES"):
		debugShowErrorMessage_expr("POLES is not found.")
		return (False,
				f"There is no equation \"POLES\".",
				f"方程式\"POLES\"が存在しません。")

	if not designTable.HasEquation("OPERATING_RPM"):
		debugShowErrorMessage_expr("OPERATING_RPM is not found.")
		return (False,
				f"There is no equation \"OPERATING_RPM\".",
				f"方程式\"OPERATING_RPM\"が存在しません。")
	return (True, "", "")


def run():
	target_studies, err_en, err_jp = GetCanUseScriptStudies(app)
	if len(target_studies)==0:
		show_error_message(app, err_en, err_jp)
		return False
	study = target_studies[0]
	inputDialog = TransferFunctionInputDialog(app, app.GetCurrentModel())
	if not inputDialog.show_dialog():
		return False
	designTable = getDesignTable_expr(app, study)
	isOk, err_en, err_jp = check_transfer_function_file(designTable, inputDialog.GetFilePath())
	if not isOk:
		show_error_message(app, err_en, err_jp)
		return False
	
	if study.NumVibrationDefinitions() == 0:
		study.CreateVibrationDefinition("Vibration Calculation")
	vibration = study.GetVibrationDefinition(0)
	isOk, err_en, err_jp = set_vibration_definition(inputDialog, designTable, study, vibration)
	if not isOk:
		show_error_message(app, err_en, err_jp)
		return False

	matchCaseList, err_en, err_jp = check_transfer_function_import_result(vibration, designTable)
	if not matchCaseList:
		show_error_message(app, err_en, err_jp)
		return False
	
	return True

OUTPUT_RESULT_TYPES_EN = ["Acceleration","Velocity","Displacement"]
OUTPUT_RESULT_TYPES_JP = ["加速度","速度","変位"]

class GroupedNames:
	def __init__(self):
		self.grouped_names_dict = {} # key=group name or non group name, value=pattern index list(if non group, value is empty list)
		self.grouped_names_is_torque_dict = {} # key=group name or non group name, value=is_torque

	def add(self, name, before_grouped_index, is_torque):
		splitted = name.split(":")
		num_splitted = len(splitted)
		if num_splitted==1:
			group_name = splitted[0]
			pattern_index = 1
			component_label = ""
			self.grouped_names_dict[group_name] = [(pattern_index, before_grouped_index, component_label)]
		elif num_splitted==2:
			group_name = splitted[0]
			try:
				pattern_index = int(splitted[1])
				component_label = ""
			except ValueError:
				pattern_index = 1
				component_label = splitted[1]

			pattern_before_pair_indexes = self.grouped_names_dict.get(group_name, [])
			pattern_before_pair_indexes.append( (pattern_index, before_grouped_index, component_label) )

			self.grouped_names_dict[group_name] = pattern_before_pair_indexes
		elif num_splitted==3:
			group_name = splitted[0]
			pattern_index = int(splitted[1])
			component_label = splitted[2]

			pattern_before_pair_indexes = self.grouped_names_dict.get(group_name, [])
			pattern_before_pair_indexes.append( (pattern_index, before_grouped_index, component_label) )

			self.grouped_names_dict[group_name] = pattern_before_pair_indexes
		else:
			return (False,
				f"Incorrect name format.\n {name}",
				f"名前の書式が正しくありません。\n {name}")

		if not group_name:
			return (False,
				f"Incorrect name format.\n {name}",
				f"名前の書式が正しくありません。\n {name}")
		self.grouped_names_is_torque_dict[group_name] = is_torque

		return (True, "", "")

	def dump_to_string(self):
		dumpString = ""
		for name, pattern_before_pair_indexes in self.grouped_names_dict.items():
			dumpString += f"{name} = {pattern_before_pair_indexes}\n"

		return dumpString

	def get_grouped_name(self, grouped_index):
		grouped_names = self.get_grouped_names()
		return grouped_names[grouped_index]

	def get_grouped_names(self):
		return list(self.grouped_names_dict.keys())

	def get_grouped_values(self):
		return list(self.grouped_names_dict.values())

	def get_grouped_is_torques(self):
		return list(self.grouped_names_is_torque_dict.values())

def getParametricEquation_expr(designTable, name):
	if designTable.HasEquation(name)==False:
		return None
	return designTable.GetEquation(name)

def has_invalid_pole_expr(designTable, caseIndexList):
	if not designTable.HasEquation("POLES"):
		return True
	poleParametricEquation = getParametricEquation_expr(designTable, "POLES")
	if (poleParametricEquation is None) or (not poleParametricEquation.IsValid()):
		return True
	for caseIndex in caseIndexList:
		if poleParametricEquation.GetValue(caseIndex) < 1:
			return True
	return False

def get_pole_expr(designTable, caseIndex):
	poleParametricEquation = getParametricEquation_expr(designTable, "POLES")
	if not poleParametricEquation:
		return -1
	return int(poleParametricEquation.GetValue(caseIndex))

def get_operating_rpm_expr(designTable, caseIndex):
	rpmParametricEquation = getParametricEquation_expr(designTable, "OPERATING_RPM")
	if not rpmParametricEquation:
		return -1
	return float(rpmParametricEquation.GetValue(caseIndex))

def get_slot_expr(designTable, caseIndex):
	if designTable.HasEquation("SLOTS"):
		return int(designTable.GetEquation("SLOTS").GetValue(caseIndex))
	else:
		return 0

def getDesignTable_expr(app, study):
	if app.NumAnalysisGroups() > 0:
		return app.GetCurrentAnalysisGroup().GetDesignTable()
	else:
		return study.GetDesignTable()

def checkTitle(name, title_jp, title_en, title_utf8):
	if name == title_jp:
		return True
	elif name == title_en:
		return True
	elif name == title_utf8:
		return True
	return False


def findNodalForceCalculationDefinition_expr(study, component, title_jp, title_en, title_utf8):
	n = study.NumCalculationDefinitions()
	for i in range(n):
		calc_def = study.GetCalculationDefinition(i)
		if (calc_def.GetResultType() != "NodalForce"):
			continue
		calc_def_compo = calc_def.GetComponent()
		if (calc_def.GetComponent() != component):
			continue
		calc_def_name = calc_def.GetName()
		if checkTitle(calc_def_name, title_jp, title_en, title_utf8):
			return calc_def
	return None

def create_coordinate_system_name_list(model):
	csNames = []
	cslist = model.GetCoordinateSystemList()
	for index in range(cslist.NumCoordinateSystems()):
		cs = cslist.GetCoordinateSystem(index)
		csNames.append(cs.GetName())
	return csNames

def current_unit_index(model, name, unit_list):
	model_unit = model.GetCurrentUnit(name)
	if model_unit in unit_list:
		index = unit_list.index(model_unit)
		return index, "", ""
	else:
		index = -1
		error_en = f"Unsupported units are used as reference units for transfer functions.\n Unsupported unit = {model_unit}"
		error_jp = f"対応していない単位が伝達関数の参照単位として使用されています。\n 対応していない単位 = {model_unit}"
		return -1, error_en, error_jp

def create_input_dialog(app, model, coordinate_systems, output_types):
	coordinate_index = 0
	output_index = OUTPUT_RESULT_TYPES_EN.index("Acceleration")

	dialog = app.CreateDialogBox()
	title_en = u"Vibration evaluation with transfer function settings"
	title_jp = u"伝達関数による振動評価の設定"
	dialog.SetTranslation(title_en, title_jp)
	dialog.SetTitle(title_en)

	# file path
	inputdata_en = u"Transfer Function File:"
	inputdata_jp = u"伝達関数ファイル:"
	dialog.SetTranslation(inputdata_en, inputdata_jp)
	dialog.AddLabel(inputdata_en, 0, 1)
	previous_open_path = get_from_ini_file(INI_KEY_PREVIOUS_OPEN_PATH)
	filter = "CSV file (*.csv)"
	dialog.AddOpenFilename(TRANSFER_FUNCTION_FILE_PATH, "", previous_open_path, filter,1,1)

	# coordinate
	coordinate_system_en = "Coordinate System:"
	coordinate_system_jp = "座標系:"
	dialog.SetTranslation(coordinate_system_en, coordinate_system_jp)
	dialog.AddLabel(coordinate_system_en, 0, 1)
	dialog.AddComboBox(TRANSFER_FUNCTION_COORDINATE_SYSTEM, "", coordinate_systems, coordinate_index, 1)

	# output type
	output_type_en = "Output Type:"
	output_type_jp = "出力タイプ:"
	dialog.SetTranslation(output_type_en, output_type_jp)
	dialog.AddLabel(output_type_en, 0, 1)
	dialog.AddComboBox(OUTPUT_RESULT_TYPE, "", output_types, output_index, 1)

	return dialog

class TransferFunctionInputDialog:
	def __init__(self, app, model):
		self.coordinate_systems = create_coordinate_system_name_list(model)
		self.output_types = OUTPUT_RESULT_TYPES_JP if is_japanese(app) else OUTPUT_RESULT_TYPES_EN
		self.dialog = create_input_dialog(app, model, self.coordinate_systems, self.output_types)

	def show_dialog(self):
		if not self.dialog:
			return False
		self.dialog.Show()
		if self.dialog.WasCancelled():
			return False
		return True

	def GetFilePath(self):
		return self.dialog.GetValue(TRANSFER_FUNCTION_FILE_PATH).decode('utf-8')
	def GetCoordinateSystem(self):
		idx = self.dialog.GetValue(TRANSFER_FUNCTION_COORDINATE_SYSTEM)
		return self.coordinate_systems[idx]
	def GetOutputType(self):
		idx = self.dialog.GetValue(OUTPUT_RESULT_TYPE)
		return self.output_types[idx]
	def GetOutputTypeEn(self):
		idx = self.dialog.GetValue(OUTPUT_RESULT_TYPE)
		return OUTPUT_RESULT_TYPES_EN[idx]

def set_excitation_conditions(vibration,cd_R,cd_T,cd_Z):
	for i in range(vibration.NumExcitationPoints()):
		fp = vibration.GetExcitationName(i)
		splitted = fp.split(':')
		group_name = splitted[0].lower()
		if group_name=="teeth" or group_name=="tooth":
				pattern_index = int(splitted[1]) - 1
				vibration.SetExcitationResultDefinition(i, 0, cd_R, pattern_index)
				vibration.SetExcitationResultDefinition(i, 1, cd_T, pattern_index)
				if cd_Z is not None:
					vibration.SetExcitationResultDefinition(i, 2, cd_Z, pattern_index)

def set_vibration_definition(inputDialog : TransferFunctionInputDialog, designTable, study, vibration):
	# setting from dialog
	try:
		vibration.LoadTransferFunctionFile(inputDialog.GetFilePath())
	except Exception as e:
		return (False, str(e), str(e))

	vibration.SetCoordinate(inputDialog.GetCoordinateSystem())
	vibration.SetResultType(inputDialog.GetOutputTypeEn())

	# auto setting
	is3DTR = study.GetScriptTypeName() == "Transient"
	teeth_R_utf8 = (b'\xe3\x83\x86\xe3\x82\xa3\xe3\x83\xbc\xe3\x82\xb9\x5f\x52\xe6\x88\x90\xe5\x88\x86').decode('utf-8')
	teeth_T_utf8 = (b'\xe3\x83\x86\xe3\x82\xa3\xe3\x83\xbc\xe3\x82\xb9\x5f\x54\x68\x65\x74\x61\xe6\x88\x90\xe5\x88\x86').decode('utf-8')
	teeth_Z_utf8 = (b'\xe3\x83\x86\xe3\x82\xa3\xe3\x83\xbc\xe3\x82\xb9\x5f\x5a\xe6\x88\x90\xe5\x88\x86').decode('utf-8')
	cd_R =findNodalForceCalculationDefinition_expr(study, "Radial", "ティース_R成分", "Tooth_R",teeth_R_utf8)
	cd_T =findNodalForceCalculationDefinition_expr(study, "Theta", "ティース_Theta成分", "Tooth_T",teeth_T_utf8)
	cd_Z =findNodalForceCalculationDefinition_expr(study, "Z", "ティース_Z成分", "Tooth_Z",teeth_Z_utf8) if is3DTR else None
	cd_R.SetFullModelExpansion(True)
	cd_T.SetFullModelExpansion(True)
	if cd_Z is not None:
		cd_Z.SetFullModelExpansion(True)
	set_excitation_conditions(vibration, cd_R, cd_T, cd_Z)
	vibration.SetPoles("POLES")
	vibration.SetRevolutionSpeed("OPERATING_RPM")
	vibration.SetFourierTransformPeriodicity(1)
	#vibration.SetRevolutionSpeed(get_operating_rpm_expr(designTable, 0))
	return (True, "", "")

def check_transfer_function_file(designTable, filePath):
	if not filePath:
		return (False, 
		   		"Please set Transfer Function File.",
				"伝達関数ファイルを指定してください。")
	elif not os.path.exists(filePath):
		return (False,
		   		f"Transfer Function file does not exist.\n {filePath}",
				f"伝達関数ファイルが存在しません。\n {filePath}")
	return (True, "", "")

def check_transfer_function_import_result(vibration, designTable):
	if not vibration.IsValid(): 
		return (None, "Vibration Calculation setting is invalid.", "振動計算の設定が無効です。")
	n_force_points = vibration.NumExcitationPoints()
	force_points = []
	for i in range(n_force_points):
		force_points.append(vibration.GetExcitationName(i))
	teethSet = set()
	shaftSet = set()
	isValidFormat = True
	for fp in force_points:
		splitted = fp.split(':')
		num_splitted = len(splitted)
		group_name = splitted[0].lower()
		if group_name=="teeth" or group_name=="tooth":
			if num_splitted < 2:
				isValidFormat = False
				break
			try:
				pattern_index = int(splitted[1])
				teethSet.add(pattern_index)
			except ValueError:
				isValidFormat = False
				break
		elif group_name=="shaft":
			shaftSet.add(0)
	if not isValidFormat:
		return (None,
				f"Incorrectly formatted force point label in the transfer function.\n{fp}",
				f"不正な形式の加振点ラベルが伝達関数内にあります。\n{fp}")
	numTeeth = len(teethSet)
	numShaft = len(shaftSet)
	if numTeeth == 0:
		return (None,
		  		"Force Point \"tooth\" is not included in the transfer function.",
				"加振点 \"tooth\" が伝達関数に含まれません。")
	# if numShaft == 0:
	# 	return (None,
	# 	  		"Force Point \"shaft\" is not included in the transfer function.",
	# 			"加振点 \"shaft\" が伝達関数に含まれません。")
	if (max(teethSet) - min(teethSet) + 1) != numTeeth:
		return (None,
		  		"The numbering of Force Points \"tooth\" is invalid.",
				"加振点 \"tooth\" の番号が不正です。")

	matchCaseList = list()
	for caseIndex in range(designTable.NumCases()):
		slots = get_slot_expr(designTable, caseIndex)
		matchCaseList.append(slots == numTeeth)
	return (matchCaseList, "", "")

INI_KEY_PREVIOUS_OPEN_PATH = "previous_open_path"
INI_KEY_PREVIOUS_SAVE_PATH = "previous_save_path"

def get_jmag_designer_temp():
	user_home = os.path.expanduser('~')
	return os.path.join(user_home, "JMAGDesignerTemp")

def get_script_ini_file():
	script_temp = os.path.join(get_jmag_designer_temp(), f"ScriptTemp")
	return os.path.join(script_temp, f"{SCRIPT_NAME}.ini")

def get_from_ini_file(key):
	ini_file = get_script_ini_file()
	if not os.path.exists(ini_file):
		return ""

	config = configparser.ConfigParser()
	config.read(get_script_ini_file())
	section = configparser.DEFAULTSECT

	value = config.get(section, key)
	if not value:
		return ""

	return value

def add_to_ini_file(key, value):
	if not value or len(value)==0:
		return

	config = configparser.ConfigParser()

	ini_file = get_script_ini_file()
	if os.path.exists(ini_file):
		config.read(ini_file)

	section = configparser.DEFAULTSECT
	config.set(section, key, value)

	ini_path = os.path.dirname(ini_file)
	if not os.path.exists(ini_path):
		os.makedirs(ini_path)

	try:
		with open(ini_file, "w") as f:
			config.write(f)
	except Exception as e:
		logger_error("can't open ini file in add_to_ini_file()")

def show_error_message(app, message, message_jp):
	logger_error(f"Error: {message}")
	msgdlg = app.CreateDialogBox()
	title = "Error"
	title_jp = "エラー"
	msgdlg.SetTranslation(title, title_jp)
	msgdlg.SetTranslation(message, message_jp)
	msgdlg.SetCancelButtonVisible(False)
	msgdlg.SetTitle(title)
	msgdlg.AddLabel(message)
	msgdlg.Show()

def debugShowErrorMessage_expr(message):
	#debug.Print(message)
	#debug.Pause()
	return

def setup_logger():
	if not_in_globals('LOG_FILE_PATH'):
		return

	if not os.path.exists(LOG_FILE_PATH):
		os.makedirs(LOG_FILE_PATH)

	now = datetime.datetime.now()
	log_file_name = LOG_FILE_PATH + "/" + now.strftime('%Y%m%d_%H%M%S') + '.log'

	logger.setLevel(logging.DEBUG)
	handler_format = Formatter('%(asctime)s - %(levelname)s - %(message)s')

	file_handler = FileHandler(log_file_name, "w", encoding="utf-8")
	file_handler.setLevel(logging.DEBUG)
	file_handler.setFormatter(handler_format)
	logger.addHandler(file_handler)


def teardown_logger():
	if not_in_globals('LOG_FILE_PATH'):
		return

	handlers = logger.handlers.copy()
	for handle in handlers:
		logger.removeHandler(handle)
		handle.flush()
		handle.close()


def logger_info(message):
	if not_in_globals('LOG_FILE_PATH'):
		return

	logger.info(message)


def logger_error(message):
	if not_in_globals('LOG_FILE_PATH'):
		return

	logger.error(message)


def logger_elapsed_time(start_time, message):
	if not_in_globals('LOG_FILE_PATH'):
		return

	end_time = time.time()
	logger.info(
		"elapsed_time({0}) = {1}[sec]".format(message, (end_time - start_time))
	)

	return end_time

class ElapsedTimeLogger:
	indent_counter = 0
	stacked_times = []
	stacked_texts = []

	def start_timer(self, text):
		start_time = time.perf_counter()
		ElapsedTimeLogger.stacked_times.append(start_time)
		ElapsedTimeLogger.stacked_texts.append(text)

		text_indent = "\t"*ElapsedTimeLogger.indent_counter
		logger_info(f"{text_indent}{text} : Timer start")
		ElapsedTimeLogger.indent_counter += 1

	def stop_timer(self):
		ElapsedTimeLogger.indent_counter -= 1
		start_time = ElapsedTimeLogger.stacked_times.pop(-1)
		text = ElapsedTimeLogger.stacked_texts.pop(-1)
		text_indent = "\t"*ElapsedTimeLogger.indent_counter

		stop_time = time.perf_counter()
		logger_info(f"{text_indent}{text} : Timer stop : {stop_time - start_time}[sec]")


def log_timer_start(text):
	timeLogger = ElapsedTimeLogger()
	timeLogger.start_timer(text)

def log_timer_stop():
	timeLogger = ElapsedTimeLogger()
	timeLogger.stop_timer()

def in_globals(variable):
	return variable in globals()

def not_in_globals(variable):
	return variable not in globals()


def location(depth=0):
  frame = inspect.currentframe().f_back
  return frame.f_code.co_name, frame.f_lineno

def is_japanese(app):
	lang = app.GetPreference("Language").decode('utf-8')
	if (lang == "Japanese"):
		return True
	elif (lang == "System"):
		localeInfo = locale.getlocale()
		if ("ja" in localeInfo[0].lower()):
			return True
		else:
			return False
	return False

def progress_start(app, total_steps):
	if USE_PROGRESS==False:
		return

	progressLabel = "Running vibration evaluation with transfer function..."
	if (is_japanese(app)):
		progressLabel = "伝達関数による振動評価 実行中..."
	app.SetupUserProgress(progressLabel)
	app.SetUserProgressUseCancel(True)
	app.SetUserProgressMaxSteps(total_steps)
	app.UserProgressStart()

def progress_step(app, steps):
	if USE_PROGRESS==False:
		return

	for _ in range(steps):
		app.UserProgressStep()

def progress_finish(app):
	if USE_PROGRESS==False:
		return

	app.UserProgressFinish()

def progress_was_canceled(app):
	if USE_PROGRESS==False:
		return False

	if app.UserProgressWasCanceled():
		app.UserProgressFinish()
		return True
	return False

# --- main ---
main()

Download Python source code

ファイルご利用の注意点

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