#--------------------------------------------------------------------- #Name: d0024_nvh_force_export.py #Menu-en: NVH Force Export (Nodal Force) #Menu-ja: NVH用の電磁力出力(節点力) #Type: Python #Create: February 25, 2019 JSOL Corporation #Comment-en: Export toque and force to the CSV file for motor NVH. #Comment-ja: モータNVH用にトルク、電磁力をCSVファイル出力する。 #Copyright: (c) JSOL Corporation. All Rights Reserved. #--------------------------------------------------------------------- import locale import os import designer import math from bisect import bisect_left def CanUseScript(): app = designer.GetApplication() studies = GetCanUseScriptStudies(app, False) res = len(studies) > 0 return res def GetCanUseScriptStudies(app, onlyHasResult): model = app.GetCurrentModel() study_list = [] if app.NumAnalysisGroups() > 0: analysisGroup = app.GetCurrentAnalysisGroup() designTable = analysisGroup.GetDesignTable() start_study = app.GetCurrentStudy() for i in range(analysisGroup.NumStudies()): study = analysisGroup.GetStudy(i) app.SetCurrentStudy(study.GetName()) if CanUseScriptModelStudy(model, study, designTable): study_list.append(study) app.SetCurrentStudy(start_study.GetName()) else: study = app.GetCurrentStudy() designTable = study.GetDesignTable() if CanUseScriptModelStudy(model, study, designTable): study_list.append(study) if not onlyHasResult: return study_list has_result_list = [] for i in range(len(study_list)): if study_list[i].AnyCaseHasResult(): has_result_list.append(study_list[i]) return has_result_list def CanUseScriptModelStudy(model, study, designTable): if (model.IsValid() == False): debugShowErrorMessage_expr("No model.") return False if (study.IsValid() == False): debugShowErrorMessage_expr("No study.") return False ## 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 ## Motion Check motion = get_valid_motion(study) if motion is None: debugShowErrorMessage_expr("Current study has no rotation motion condition with constant velocity.") return False caseIndexList = get_active_case_indices_expr(study) ## Pole Check if has_invalid_pole_expr(designTable, caseIndexList): debugShowErrorMessage_expr("There is the case that the parametric variable \"POLES\" does not exist or has an incorrect value.") return False ## Torque Condition Check torqueCond= findTorqueCondition_expr(study) if (torqueCond is None): debugShowErrorMessage_expr("Current study has no torque condition.") return False ## Nodal Force Table Check if is2DTR: cd_R =findNodalForceCalculationDefinition_expr(study, "Radial") cd_T =findNodalForceCalculationDefinition_expr(study, "Theta") cd_X =findNodalForceCalculationDefinition_expr(study, "X") cd_Y =findNodalForceCalculationDefinition_expr(study, "Y") if (cd_R is None) or (cd_T is None) or (cd_X is None) or (cd_Y is None) : debugShowErrorMessage_expr("NodalForce graph is not found.") return False elif is3DTR: cd_R =findNodalForceCalculationDefinition_expr(study, "Radial") cd_T =findNodalForceCalculationDefinition_expr(study, "Theta") cd_X =findNodalForceCalculationDefinition_expr(study, "X") cd_Y =findNodalForceCalculationDefinition_expr(study, "Y") cd_Z =findNodalForceCalculationDefinition_expr(study, "Z") if (cd_R is None) or (cd_T is None) or (cd_X is None) or (cd_Y is None) or (cd_Z is None) : debugShowErrorMessage_expr("NodalForce graph is not found.") return False return True CSV_VERSION = "1.0.0" OUTPUT_FILE_PATH = "outputFilePath" SET_PREFIX = "prefix" TORQUE_COND_TITLE = "condition_title" NUM_POLES = "numPoles" COORD_TYPE = "coord_type" USE_COPY_CYCLE = "use_copy_cycle" OUTPUT_FORMAT_TYPE = "output_format_type" OUTPUT_CASE_TYPE = "output_case_type" SPECIFIED_CASES = "specified_cases" EPSILON = 0.000001 OUTPUT_DIMENSION = 3 app = designer.GetApplication() def main_designer(): app.SetShowProgressDialog(False) if (check_model(app) == False): return parameters = get_parameters_from_dialog(app) if (check_dialog_parameters(app, parameters) == False): return output_csv(app, parameters) def check_model(app): model = app.GetCurrentModel() study = app.GetCurrentStudy() if (model.IsValid() == False): message = "No model." message_jp = "モデルがありません。" show_error_message(message, message_jp) return False setList = model.GetSetList() if (setList.NumSet()<1): message = "There is no set." message_jp = "セットがありません。" show_error_message(message, message_jp) return False if (study.IsValid() == False): message = "No study." message_jp = "スタディがありません。" show_error_message(message, message_jp) return False motionList = get_conditions(study, "RotationMotion") if (len(motionList)<1): message = "Current study has no rotation motion condition." message_jp = "現スタディは回転運動条件がありません。" show_error_message(message, message_jp) return False torqueList = get_conditions(study, "Torque") if (len(torqueList)<1): message = "Current study has no torque condition." message_jp = "現スタディはトルク条件がありません。" show_error_message(message, message_jp) return False forceList = get_conditions(study, "Force") if (len(forceList)<1): message = "Current study has no force condition." message_jp = "現スタディは電磁力条件がありません。" show_error_message(message, message_jp) return False if (study.AnyCaseHasResult() == False): message = "Current study has no result." message_jp = "現スタディは結果がありません。" show_error_message(message, message_jp) return False if (has_zero_speed(app)==True): message = "There is the case that rotation speed is zero. Please review setting." message_jp = "回転速度がゼロのケースがあります。設定を見直してください。" show_error_message(message, message_jp) return False return True def show_error_message(message, message_jp): 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 show_warning_message(message, message_jp): msgdlg = app.CreateDialogBox() title = "Warning" title_jp = "警告" msgdlg.SetTranslation(title, title_jp) msgdlg.SetTranslation(message, message_jp) msgdlg.SetCancelButtonVisible(False) msgdlg.SetTitle(title) msgdlg.AddLabel(message) msgdlg.Show() def get_parameters_from_dialog(app): dialog = app.CreateDialogBox() setup_param_input_dialog(app, dialog) dialog.Show() return dialog def setup_param_input_dialog(app, dialog): dialogTitle = "JMAG-Designer: NVH Force Export Setting" dialogTitle_jp = "JMAG-Designer: NVH電磁力出力設定" dialog.SetTranslation(dialogTitle, dialogTitle_jp) label_1 = "Output File:" label_1_jp = "出力ファイル:" dialog.SetTranslation(label_1, label_1_jp) label_2 = "Set Prefix:" label_2_jp = "セットの先頭文字:" dialog.SetTranslation(label_2, label_2_jp) label_3 = "Torque Condition:" label_3_jp = "トルク条件:" dialog.SetTranslation(label_3, label_3_jp) label_4 = "Number of Poles:" label_4_jp = "極数:" dialog.SetTranslation(label_4, label_4_jp) # label_5 = "Force Coordinates:" # label_5_jp = "節点力の座標系:" # dialog.SetTranslation(label_5, label_5_jp) label_5 = "Cycle:" label_5_jp = "周期:" dialog.SetTranslation(label_5, label_5_jp) label_6 = "Rectangular" label_6_jp = "直交座標系" dialog.SetTranslation(label_6, label_6_jp) # label_7 = "Cylindrical" # label_7_jp = "円筒座標系" # dialog.SetTranslation(label_7, label_7_jp) label_8 = "Copy 1 electrical cycle to mechanical cycle" label_8_jp = "電気角1周期分をコピーして機械角1周期分にする" dialog.SetTranslation(label_8, label_8_jp) label_9 = "Output Cases:" label_9_jp = "出力ケース:" dialog.SetTranslation(label_9, label_9_jp) label_10 = "All Cases" label_10_jp = "全ケース" dialog.SetTranslation(label_10, label_10_jp) label_11 = "Specified Cases (Example: 1, 2, 5-8)" label_11_jp = "指定ケース(例: 1, 2, 5-8)" dialog.SetTranslation(label_11, label_11_jp) label_12 = "Output Format:" label_12_jp = "出力フォーマット:" dialog.SetTranslation(label_12, label_12_jp) label_13 = "Single File Including Torque(Force Coordinates=Cylindrical)" label_13_jp = "トルクデータ含む1ファイル出力(節点力の座標系=円筒座標系)" dialog.SetTranslation(label_13, label_13_jp) #label_16 = "Single File Including Torque(Force Coordinates=Cylindrical)[v22.2 and earlier]" #label_16_jp = "トルクデータ含む1ファイル出力(節点力の座標系=円筒座標系)[v22.2以前の形式]" #dialog.SetTranslation(label_16, label_16_jp) label_14 = "File Per Case: Time Domain Tooth Forces(Force Coordinates=Rectangular)" label_14_jp = "ケースごとにファイル出力:時刻依存性ティース電磁力(節点力の座標系=直交座標系)" dialog.SetTranslation(label_14, label_14_jp) label_15 = "File Per Case: Frequency Domain Tooth Forces(Force Coordinates=Rectangular)" label_15_jp = "ケースごとにファイル出力:周波数依存性ティース電磁力(節点力の座標系=直交座標系)" dialog.SetTranslation(label_15, label_15_jp) dialog.SetTitle(dialogTitle) dialog.AddLabel(label_1, 0, 1) dialog.AddSaveFilename(OUTPUT_FILE_PATH, "", "", "*.csv", 1, 1) dialog.AddLabel(label_2, 0, 1) dialog.AddString(SET_PREFIX, "", "TOOTH", 1, 1) dialog.AddLabel(label_3, 0, 1) dialog.AddComboBox(TORQUE_COND_TITLE, "", torque_condition_title_list(app), 0, 1) dialog.AddLabel(label_4, 0, 1) dialog.AddInteger(NUM_POLES, "", 4, 1, 1) dialog.AddLabel(label_5) #dialog.AddRadio(COORD_TYPE, label_7, 1, 1) #dialog.AddRadio(COORD_TYPE, label_6, 0, 1) dialog.AddCheckBox(USE_COPY_CYCLE, label_8, True, 1, 1) dialog.AddLabel("", 0, 1) dialog.AddLabel(label_12, 0, 1) dialog.AddRadio(OUTPUT_FORMAT_TYPE, label_13, 0, 1) #dialog.AddRadio(OUTPUT_FORMAT_TYPE, label_16, 1, 1) dialog.AddRadio(OUTPUT_FORMAT_TYPE, label_14, 1, 1) dialog.AddRadio(OUTPUT_FORMAT_TYPE, label_15, 2, 1) dialog.AddLabel("", 0, 1) dialog.AddLabel(label_9, 0, 1) dialog.AddRadio(OUTPUT_CASE_TYPE, label_10, 0, 1) dialog.AddRadio(OUTPUT_CASE_TYPE, label_11, 1, 1) dialog.AddLabel("", 0, 1) dialog.AddIntegerList(SPECIFIED_CASES, "", "1", 1, 1) def check_dialog_parameters(app, parameters): if (parameters.WasCancelled()): return False if (parameters.GetValue(OUTPUT_FILE_PATH)==""): message = "Output file path is invalid." message_jp = "出力ファイルパスが不正です。" show_error_message(message, message_jp) return False model = app.GetCurrentModel() setList = model.GetSetList() targetSetList = get_target_set(model, parameters) if (len(targetSetList)<1): message = "Can not find set by the specified prefix." message_jp = "指定された頭文字ではセットが見つかりませんでした。" show_error_message(message, message_jp) return False if (parameters.GetValue(NUM_POLES) % 2 != 0): message = "The number of poles is invalid. Please set even number." message_jp = "極数が不正です。偶数を設定してください。" show_error_message(message, message_jp) return False outputCaseType = parameters.GetValue(OUTPUT_CASE_TYPE) if (outputCaseType == 1): # Specified Cases study = app.GetCurrentStudy() caseNoList = parameters.GetValueAsIntegerList(SPECIFIED_CASES) caseIndexList = get_caseIndexList_from_caseNoList(study, caseNoList) if (len(caseIndexList)==0): message = "There is no valid case. Please review the setting on Specified Cases." message_jp = "有効なケースがありません。指定ケースの設定を見直してください。" show_error_message(message, message_jp) return False hasNot1CycleStepCases = False hasNot1CycleStepCases = check_has_not_1cycle_step_cases(app, parameters) if (hasNot1CycleStepCases): message = "Insufficient number of result time steps. The file output must have more than one cycle mechanical angle or more than one cycle electrical angle time step number. Please check the results of the specified cases." message_jp = "結果の時間ステップ数が不十分です。ファイル出力には1周期機械角分または1周期電気角分の時間ステップ数以上の結果が必要です。指定ケースの結果を見直してください。" show_error_message(message, message_jp) return False return True def output_csv(app, dialog): outputFormatType = dialog.GetValue(OUTPUT_FORMAT_TYPE) if (outputFormatType == 0): output_single_file_including_torque(app, dialog, True) elif (outputFormatType == 1): output_time_domain_tooth_forces(app, dialog) elif (outputFormatType == 2): output_frequency_domain_tooth_forces(app, dialog) def get_case_table(study, is2D, caseIndexList, nSet): numTeethList = [] modelThicknessList = [] numSliceList = [] startCase = study.GetCurrentCase() for i in range(len(caseIndexList)): caseIndex = caseIndexList[i] study.SetCurrentCase(caseIndex) periodicity = get_periodicity(study) numTeethList.append(nSet * periodicity) if is2D: modelThicknessList.append(study.GetStudyProperties().GetValueWithUnit("ModelThickness", "mm")) else: modelThicknessList.append(0.0) if is2D and use_multi_slice(study): numSliceList.append(get_slice_number(study)) else: numSliceList.append(0) study.SetCurrentCase(startCase) return (numTeethList, modelThicknessList, numSliceList) def output_single_file_including_torque(app, dialog, is100Format): isJapanese = is_japanese(app) is2D = (app.GetCurrentModel().GetDimension() == 2) targetSetList = get_target_set(app.GetCurrentModel(), dialog) study = app.GetCurrentStudy() (caseIndexList, noResultCaseIndexList, speedList, avTorqList, startIndices, outX, outYT) = create_torque_data(app, dialog) (numTeethList, modelThicknessList, numSliceList) = get_case_table(study, is2D, caseIndexList, len(targetSetList)) outputPath = dialog.GetValue(OUTPUT_FILE_PATH) file = open(outputPath.decode('utf-8'), 'w') if is100Format: write_header_100(file, numTeethList[0], is2D, modelThicknessList[0], max(numSliceList) > 1 , numSliceList[0]) else: write_header_110(file, is2D, caseIndexList, speedList, avTorqList, numTeethList, modelThicknessList, numSliceList) write_torque(file, caseIndexList, speedList, avTorqList, outX, outYT, is100Format) wasCanceled = write_force(file, app, dialog, caseIndexList, speedList, avTorqList, startIndices, outX, is100Format) file.close() ShowFinishMessage(app, wasCanceled) def output_time_domain_tooth_forces(app, dialog): ## Get app data isJap = is_japanese(app) targetStudy = app.GetCurrentStudy() targetModel = app.GetCurrentModel() ## Get dialog values useElectricCycle = dialog.GetValue(USE_COPY_CYCLE) numPoles = dialog.GetValue(NUM_POLES) coordType = 0 # Fixed to Global Rectangular targetSetList = get_target_set(targetModel, dialog) setPrefix = dialog.GetValue(SET_PREFIX).decode('utf-8') ## Setup parameters outputDimension = OUTPUT_DIMENSION modelDimension = targetModel.GetDimension() is2D = (modelDimension == 2) thickness = 0 useMultiSlice = False numSlice = 1 if (is2D): thickness = targetStudy.GetStudyProperties().GetValueWithUnit("ModelThickness", "m") useMultiSlice = use_multi_slice(targetStudy) numSlice = get_slice_number(targetStudy) if (useMultiSlice): thickness = 1.0*thickness/numSlice caseIndexList = get_case_index_list(dialog, targetStudy) periodicity = get_periodicity(targetStudy) needConvertTwice = (not is2D) and has_symmetry_boundary_on_XYPlane(targetStudy) ## Setup progress dialog setup_progress(app, outputDimension, caseIndexList, numSlice, targetSetList) wasCanceled = False ## Case loop numCases = len(caseIndexList) for caseLoopIndex in range(numCases): caseIndex = caseIndexList[caseLoopIndex] targetStudy.SetCurrentCase(caseIndex) removedList = get_removed_node_list_on_boundary(targetStudy, targetSetList) if (targetStudy.CaseHasResult(caseIndex) == False): continue ## Slice loop for sliceIndex in range(numSlice): # Write file outputPath = create_file_name(dialog.GetValue(OUTPUT_FILE_PATH), numCases, caseIndex+1, useMultiSlice, sliceIndex+1) file = open(outputPath.decode('utf-8'), 'w') ## Write header write_header_for_time_domain_tooth_force_only(file, setPrefix, len(targetSetList)*periodicity) ## Get start index for last 1 cycle torqResultName = get_torq_result_name(app) dataset = targetStudy.GetDataSet(torqResultName, caseIndex+1) startIndex = get_last_1_cycle_start_index(dialog, targetStudy, dataset) timeData = list(dataset.GetColumn(0)) timeData = timeData[startIndex:] timeData = create_1_electric_cycle_time_to_1_mechanical_cycle_time(useElectricCycle, numPoles, timeData) ## Each Tooth loop partialModelF = [] for setIndex in range(len(targetSetList)): eachSetF = [] ## Component loop for compIndex in range(outputDimension): if (app.UserProgressWasCanceled()): app.UserProgressFinish() wasCanceled = True break ##Setup probe title = "Probe" probe = create_probe(title, targetStudy, useMultiSlice, sliceIndex, isJap, coordType, compIndex) [data, wasCanceled] = calc_force(targetStudy, removedList[setIndex], probe) ## Considering 1/2 model lengthwise if symmetry boundary is set on XY plane convertedData = convert_twice(needConvertTwice, data) ## Get last 1 cycle data lastCycleF = convertedData[startIndex:] ##Copy 1 electric cycle to 1 mechanical cycle lastCycleF = copy_1_electric_cycle_to_1_mechanical_cycle(useElectricCycle, numPoles, lastCycleF) ##If 2D model times thickness if is2D: lastCycleF = [f * thickness for f in lastCycleF] ##Add each component data eachSetF.append(lastCycleF) if (wasCanceled == False): app.UserProgressStep() targetStudy.DeleteProbe(title) partialModelF.append(eachSetF) fullModelF = [] ##Add Time fullModelF.append(timeData) ##Copy partial model teeth to full model for i in range (periodicity): if i==0: fullModelF.append(partialModelF) else: rad = math.radians(360.0 * i / periodicity) cos = math.cos(rad) sin = math.sin(rad) rotPartial = [] for setIndex in range(len(targetSetList)): rotEachSet = [] rotfx = [cos * x - sin * y for x,y in zip(partialModelF[setIndex][0], partialModelF[setIndex][1])] rotfy = [sin * x + cos * y for x,y in zip(partialModelF[setIndex][0], partialModelF[setIndex][1])] rotEachSet.append(rotfx) rotEachSet.append(rotfy) rotEachSet.append(partialModelF[setIndex][2]) rotPartial.append(rotEachSet) fullModelF.append(rotPartial) ##Write TOOTH value of full model WriteByAllComponentsInSetForOneCase(file, fullModelF) file.close() app.UserProgressFinish() ShowFinishMessage(app, wasCanceled) def output_frequency_domain_tooth_forces(app, dialog): ## Get app data isJap = is_japanese(app) targetStudy = app.GetCurrentStudy() targetModel = app.GetCurrentModel() dataManager = app.GetDataManager() ## Get dialog values numPoles = dialog.GetValue(NUM_POLES) coordType = 0 # Fixed to Global Rectangular targetSetList = get_target_set(targetModel, dialog) setPrefix = dialog.GetValue(SET_PREFIX).decode('utf-8') ## Setup parameters outputDimension = OUTPUT_DIMENSION modelDimension = targetModel.GetDimension() is2D = (modelDimension == 2) thickness = 0 useMultiSlice = False numSlice = 1 if (is2D): thickness = targetStudy.GetStudyProperties().GetValueWithUnit("ModelThickness", "m") useMultiSlice = use_multi_slice(targetStudy) numSlice = get_slice_number(targetStudy) if (useMultiSlice): thickness = 1.0*thickness/numSlice caseIndexList = get_case_index_list(dialog, targetStudy) periodicity = get_periodicity(targetStudy) needConvertTwice = (not is2D) and has_symmetry_boundary_on_XYPlane(targetStudy) ## Setup progress dialog setup_progress(app, outputDimension, caseIndexList, numSlice, targetSetList) wasCanceled = False ## Case loop numCases = len(caseIndexList) for caseLoopIndex in range(numCases): caseIndex = caseIndexList[caseLoopIndex] targetStudy.SetCurrentCase(caseIndex) removedList = get_removed_node_list_on_boundary(targetStudy, targetSetList) if (targetStudy.CaseHasResult(caseIndex) == False): continue ## Slice loop for sliceIndex in range(numSlice): ## Write file outputPath = create_file_name(dialog.GetValue(OUTPUT_FILE_PATH), numCases, caseIndex+1, useMultiSlice, sliceIndex+1) file = open(outputPath.decode('utf-8'), 'w') ## Write header write_header_for_frequency_domain_tooth_force_only(file, setPrefix, len(targetSetList)*periodicity) ## Get start index for last 1 cycle torqResultName = get_torq_result_name(app) dataset = targetStudy.GetDataSet(torqResultName, caseIndex+1) startIndex = get_last_1_cycle_start_index(dialog, targetStudy, dataset) ## Each Tooth loop partialModelF = [] freqData = [] for setIndex in range(len(targetSetList)): eachSetF = [] ## Component loop for compIndex in range(outputDimension): if (app.UserProgressWasCanceled()): app.UserProgressFinish() wasCanceled = True break ## Setup probe title = "Probe" probe = create_probe(title, targetStudy, useMultiSlice, sliceIndex, isJap, coordType, compIndex) dataSetTitle = "fft_for_nvf_force_export" [fftDataSet, wasCanceled] = calc_force_with_FFT(dataManager, targetStudy, removedList[setIndex], probe, dataSetTitle, needConvertTwice, startIndex, is2D, thickness) ## Real/Imaginary Loop numFFTColmuns = fftDataSet.GetCols() if (numFFTColmuns < 3): continue for realImagIndex in range(1, numFFTColmuns): data = list(fftDataSet.GetColumn(realImagIndex)) ## Add each component data eachSetF.append(data) if (setIndex == 0 and compIndex == 0): freqData = list(fftDataSet.GetColumn(0)) if (wasCanceled == False): app.UserProgressStep() targetStudy.DeleteProbe(title) dataManager.DeleteDataSet(dataSetTitle) partialModelF.append(eachSetF) fullModelF = [] ## Add Time/Frequency fullModelF.append(freqData) ## Copy partial model teeth to full model for i in range (periodicity): if i==0: fullModelF.append(partialModelF) else: rad = math.radians(360.0 * i / periodicity) cos = math.cos(rad) sin = math.sin(rad) rotPartial = [] for setIndex in range(len(targetSetList)): rotEachSet = [] rotfxr = [cos * x - sin * y for x,y in zip(partialModelF[setIndex][0], partialModelF[setIndex][2])] rotfyr = [sin * x + cos * y for x,y in zip(partialModelF[setIndex][0], partialModelF[setIndex][2])] rotfxi = [cos * x - sin * y for x,y in zip(partialModelF[setIndex][1], partialModelF[setIndex][3])] rotfyi = [sin * x + cos * y for x,y in zip(partialModelF[setIndex][1], partialModelF[setIndex][3])] rotEachSet.append(rotfxr) rotEachSet.append(rotfxi) rotEachSet.append(rotfyr) rotEachSet.append(rotfyi) rotEachSet.append(partialModelF[setIndex][4]) rotEachSet.append(partialModelF[setIndex][5]) rotPartial.append(rotEachSet) fullModelF.append(rotPartial) ## Write TOOTH value of full model WriteByAllComponentsInSetForOneCase(file, fullModelF) file.close() app.UserProgressFinish() ShowFinishMessage(app, wasCanceled) def write_header_100(file, numTeeth, is2D, modelThickness, useMultiSlice, numSlice): dimString = "" if (is2D): dimString = "2D" else: dimString = "3D" write_line2(file, "CSV Version", "1.0.0") write_line2(file, "Dimension", dimString) write_line2(file, "Coordinate", get_coordName(1)) write_line2(file, "Teeth", str(numTeeth)) if (is2D): write_line2(file, "StackLength(mm)", str(modelThickness)) if useMultiSlice: write_line2(file, "Slice", str(numSlice)) else: write_line2(file, "Slice", "1") file.write("\n") def write_header_110(file, is2D, caseIndexList, speedList, avTorqList, numTeethList, modelThicknessList, numSliceList): dimString = "" if (is2D): dimString = "2D" else: dimString = "3D" write_line2(file, "CSV Version", "1.1.0") write_line2(file, "Dimension", dimString) write_line2(file, "Coordinate", get_coordName(1)) write_line2(file, "Number of Cases", str(len(caseIndexList))) file.write("\n") write_line(file, "*Case Table") file.write("Case,Speed(RPM),Torque(Nm),Teeth,StackLength(mm),Slice\n") for i in range(len(caseIndexList)): line = str(caseIndexList[i] + 1) line += "," + str(speedList[i]) line += "," + str(avTorqList[i]) line += "," + str(numTeethList[i]) line += "," + str(modelThicknessList[i]) line += "," + str(numSliceList[i]) write_line(file, line) file.write("\n") def write_header(file, app, dialog): targetModel = app.GetCurrentModel() targetStudy = app.GetCurrentStudy() is2D = (targetModel.GetDimension()==2) setList = targetModel.GetSetList() targetSetList = get_target_set(targetModel, dialog) numPoles = dialog.GetValue(NUM_POLES) dimString = "3D" coordString = get_coordName(1) # Fixed to cylindrical in V18.1 periodicity = get_periodicity(targetStudy) numTeeth = int(len(targetSetList)*periodicity) modelThickness = 0 numSlice = 1 if (is2D): dimString = "2D" modelThickness = targetStudy.GetStudyProperties().GetValueWithUnit("ModelThickness", "mm") numSlice = get_slice_number(targetStudy) write_line2(file, "CSV Version", CSV_VERSION) write_line2(file, "Dimension", dimString) write_line2(file, "Coordinate", coordString) write_line2(file, "Teeth", str(numTeeth)) if (is2D): write_line2(file, "StackLength(mm)", str(modelThickness)) write_line2(file, "Slice", str(numSlice)) file.write("\n") def calc_ave_torque(lastCycleTorq): return sum(lastCycleTorq[1:]) / (len(lastCycleTorq)-1) def create_torque_data(app, dialog): ##Initialize speedList = [] avTorqList = [] startIndices = [] caseIndexList = [] noResultCaseIndexList = [] outX = [] outYT = [] ##Get dialog parameters useElectricCycle = dialog.GetValue(USE_COPY_CYCLE) numPoles = dialog.GetValue(NUM_POLES) outputCaseType = dialog.GetValue(OUTPUT_CASE_TYPE) caseNoList = dialog.GetValueAsIntegerList(SPECIFIED_CASES) ##Get app data targetStudy = app.GetCurrentStudy() torqResultName = get_torq_result_name(app) ##Create output case list numCases = targetStudy.GetDesignTable().NumCases() if (outputCaseType == 0): # Output all cases caseIndexList = range(numCases) elif (outputCaseType == 1): # Output specified cases caseIndexList = get_caseIndexList_from_caseNoList(targetStudy, caseNoList) ##Create each case data for caseIndex in caseIndexList: if (targetStudy.CaseHasResult(caseIndex) == False): noResultCaseIndexList.append(caseIndex) continue ##Calculate 1 mechanical cycle time from rotation speed targetStudy.SetCurrentCase(caseIndex) speed = get_speed(targetStudy) if (useElectricCycle): T = 60.0/speed/numPoles*2 else : T = 60.0/speed ##Get torque data for 1 last cycle lastCycleTorq = [] dataset = targetStudy.GetDataSet(torqResultName, caseIndex+1) numSteps = dataset.GetRows() if (dataset.GetCols() < 2 or numSteps==0): noResultCaseIndexList.append(caseIndex) continue time = list(dataset.GetColumn(0)) torque = get_target_torque(dataset, dialog) lastCycleStartTime = time[-1] - T + EPSILON*(time[-1] - time[-2]) index = len(time)-1 t = time[index] while t > lastCycleStartTime: lastCycleTorq.insert(0, torque[index]) index -= 1 if (index < 0 or len(time) <= index): break t = time[index] ##Calculate average torque aveTorq = calc_ave_torque(lastCycleTorq) ##Copy 1 electric cycle to 1 mechanical cycle lastCycleTorq = copy_1_electric_cycle_to_1_mechanical_cycle(useElectricCycle, numPoles, lastCycleTorq,True) ##Create angle data angleData = [] deltaAngle = 360.0/(len(lastCycleTorq)) for i in range(len(lastCycleTorq)): angleData.append(deltaAngle*i) ##Set each case data speedList.append(speed) avTorqList.append(aveTorq) startIndices.append(index+1) outX.append(angleData) outYT.append(lastCycleTorq) ##Remove no result case for index in noResultCaseIndexList: caseIndexList.remove(index) return (caseIndexList, noResultCaseIndexList, speedList, avTorqList, startIndices, outX, outYT) def write_torque(file, caseIndexList, speed, aveTorq, outX, outYT, is100Format): ##Write torque header write_line(file, "*Torque") ##Write torque data per case for i in range(len(caseIndexList)): if is100Format: write_line2(file, "Speed(RPM)", str(speed[i])) write_line2(file, "Torque(Nm)", str(aveTorq[i])) else: write_line2(file, "Case", str(caseIndexList[i] + 1)) for j in range(len(outX[i])): write_line2(file, str(outX[i][j]), str(outYT[i][j])) file.write("\n") def write_force(file, app, dialog, caseIndexList, speedList, avTorqList, startIndices, outX, is100Format): ##Get Study value targetModel = app.GetCurrentModel() targetStudy = app.GetCurrentStudy() isJap = is_japanese(app) is2D = (targetModel.GetDimension()==2) thickness = 0 if (is2D): thickness = targetStudy.GetStudyProperties().GetValueWithUnit("ModelThickness", "m") periodicity = get_periodicity(targetStudy) useMultiSlice = use_multi_slice(targetStudy) numSlice = 1 if (useMultiSlice): numSlice = get_slice_number(targetStudy) thickness = 1.0*thickness/numSlice needConvertTwice = (not is2D) and has_symmetry_boundary_on_XYPlane(targetStudy) ##Get dialog parameters useElectricCycle = dialog.GetValue(USE_COPY_CYCLE) numPoles = dialog.GetValue(NUM_POLES) coordType = 1 # Fixed to cylindrical in V18.1 ##Pick up target set list targetSetList = get_target_set(targetModel, dialog) ##Create data for each component and each case dimension = app.GetCurrentModel().GetDimension() numCases = targetStudy.GetDesignTable().NumCases() ##Setup progress dialog setup_progress(app, dimension, caseIndexList, numSlice, targetSetList) wasCanceled = False componentLabels = ["Radius", "Theta", "Z"] for compIndex in range(dimension): if is100Format: write_line2(file, "*Force", str(compIndex+1)) elif (not is100Format) and compIndex == 0: write_line(file, "*Force") for outputIndex in range(len(caseIndexList)): caseIndex = caseIndexList[outputIndex] targetStudy.SetCurrentCase(caseIndex) ##Get nodeIds on each set removedList = get_removed_node_list_on_boundary(targetStudy, targetSetList) if is100Format: write_line2(file, "Speed(RPM)", str(speedList[outputIndex])) write_line2(file, "Torque(Nm)", str(avTorqList[outputIndex])) else: write_line2(file, "Case", str(caseIndex + 1)) write_line2(file, "Component", str(componentLabels[compIndex])) fullModelF=[] for sliceIndex in range(numSlice): ##Set probe title = "Probe" probe = create_probe(title, targetStudy, useMultiSlice, sliceIndex, isJap, coordType, compIndex) ##Calculate TOOTH value partialModelF = [] for setIndex in range(len(targetSetList)): if (app.UserProgressWasCanceled()): app.UserProgressFinish() file.close() return True [data, wasCanceled] = calc_force(targetStudy, removedList[setIndex], probe) ##Considering 1/2 model lengthwise if symmetry boundary is set on XY plane convertedData = convert_twice(needConvertTwice, data) ##Get last 1 cycle data lastCycleF = convertedData[startIndices[outputIndex]:] ##Copy 1 electric cycle to 1 mechanical cycle lastCycleF = copy_1_electric_cycle_to_1_mechanical_cycle(useElectricCycle, numPoles, lastCycleF,True) ##If 2D model times thickness (How about multi-slice model?) if is2D: lastCycleF = [f * thickness for f in lastCycleF] ##Add each set data partialModelF.append(lastCycleF) if (wasCanceled == False): app.UserProgressStep() ##Copy partial model teeth to full model for i in range (periodicity): for j in range (len(targetSetList)): fullModelF.append(partialModelF[j]) targetStudy.DeleteProbe(title) if (wasCanceled): file.close() return True ##Write TOOTH value for i in range(len(outX[outputIndex])): file.write(str(outX[outputIndex][i]) + ",") for j in range(len(fullModelF)): file.write(str(fullModelF[j][i])) if j == len(fullModelF)-1: file.write("\n") else: file.write(",") file.write("\n") app.UserProgressFinish() return wasCanceled def write_line(file, str1): file.write(str1) file.write("\n") def write_line2(file, str1, str2): file.write(str1) file.write(",") file.write(str2) file.write("\n") def write_lineList(file, str1, numList): line = str1 for i in range(len(numList)): line += ("," + str(numList[i])) file.write(line) file.write("\n") def get_speed(targetStudy): result = 0; motionList = get_conditions(targetStudy, "RotationMotion") motion = motionList[0] return motion.GetValue("AngularVelocity") def torque_condition_title_list(app): result = [] torqueList = get_conditions(app.GetCurrentStudy(), "Torque") for cond in torqueList: result.append(cond.GetName()) return result def get_periodicity(targetStudy): cond = get_first_condition(targetStudy, "RotationPeriodicBoundary") if (not cond is None) and (cond.IsValid()) and (not cond.GetValue("AutoPeriodicFromWinding")): return 360//int(cond.GetValue(u"Angle")) designTable = targetStudy.GetDesignTable() if designTable.HasEquation("MODEL_DIVISION"): modelDiv = designTable.GetEquation("MODEL_DIVISION").GetValue() if modelDiv > 0: return modelDiv if designTable.HasEquation("POLES") and designTable.HasEquation("SLOTS"): poles = int(designTable.GetEquation("POLES").GetValue()) slots = int(designTable.GetEquation("SLOTS").GetValue()) if poles > 0 and slots > 0: return math.gcd(poles, slots) return 1 def get_coordName(coordType): result = "Global Rectangular" if (coordType == 0): # 0: Rectangular result = "Global Rectangular" elif (coordType == 1): # 1: Cylindrical result = "Cylindrical" return result def get_component(coordType, compIndex): result = "X" if (coordType == 0): # 0: Rectangular if (compIndex==0): result = "X" elif (compIndex==1): result = "Y" elif (compIndex==2): result = "Z" elif (coordType == 1): # 1: Cylindrical if (compIndex==0): result = "Radial" elif (compIndex==1): result = "Theta" elif (compIndex==2): result = "Z" return result def get_caseIndexList_from_caseNoList(targetStudy, caseNoList): result = [] numCases = targetStudy.GetDesignTable().NumCases() for no in caseNoList: index = no-1 if (index>-1 and index1): tmp = list(dataProbe.GetColumn(1)) if (i==0): result = tmp else : result = [x+y for (x,y) in zip(result, tmp)] return (result, wasCanceled) def calc_force_with_FFT(dataManager, targetStudy, removed, probe, dataSetTitle, needConvertTwice, startIndex, is2D, thickness): wasCanceled = False forceData = [] ##Set probe on the nodeIds if (len(removed)<1): return (probe.GetDataSet(), wasCanceled) tmp = [] for i in range(len(removed)): if (app.UserProgressWasCanceled()): wasCanceled = True return (probe.GetDataSet(), wasCanceled) id = removed[i] probe.ClearPoints() probe.SetId(0, id) probe.RenamePoint(0, "Node_"+str(id)) probe.Build() dataProbe = probe.GetDataSet() ##Sum on all nodes if (dataProbe.GetCols()>1): tmp = list(dataProbe.GetColumn(1)) if (i==0): forceData = tmp else : forceData = [x+y for (x,y) in zip(forceData, tmp)] ## Considering 1/2 model lengthwise if symmetry boundary is set on XY plane convertedForceData = convert_twice(needConvertTwice, forceData) ## Get last 1 cycle data lastCycleF = convertedForceData[startIndex:] timeData = list(dataProbe.GetColumn(0)) lastCycleT = timeData[startIndex:] ## If 2D model times thickness if is2D: lastCycleF = [f * thickness for f in lastCycleF] xData = lastCycleT yData = lastCycleF xyPairList = [] xyPair = [] for i in range(len(xData)): xyPair = [xData[i],yData[i]] xyPairList.append(xyPair) dataSet = dataManager.CreateFromDataSet(dataSetTitle, "xtitle", "ytitle", xyPairList) fftDataSet = dataManager.CreateFFT(dataSet, 0, "RealAndImaginary", 0, xData[0], xData[-1]) return (fftDataSet, wasCanceled) def remove_nodes_on_boundary(study, nodeIds): condList = get_conditions(study, "RotationPeriodicBoundary") if (len(condList)==0): return nodeIds result = [] cond = condList[0] for id in nodeIds: if (cond.NodeIsOnTarget(id)==False): result.append(id) return result def get_first_condition(study, condScriptTypeName): for i in range(study.NumConditions()): cond = study.GetCondition(i) typeName = cond.GetScriptTypeName() if (typeName == condScriptTypeName): return cond return None def get_conditions(study, condScriptTypeName): result = [] for i in range(study.NumConditions()): cond = study.GetCondition(i) typeName = cond.GetScriptTypeName() if (typeName == condScriptTypeName): result.append(cond) return result def use_multi_slice(study): condList = get_ms_conditions(study) return len(condList) > 0 def get_ms_conditions(study): result = [] for i in range(study.NumConditions()): cond = study.GetCondition(i) typeName = cond.GetScriptTypeName() if (typeName == "MultiSlice"): result.append(cond) return result def get_slice_number(study): result = 1 condList = get_ms_conditions(study) if (len(condList)>0): cond = condList[0] if (cond.IsValid()): result = int(cond.GetValue("NumberOfSlices")) return result def get_target_set(targetModel, dialog): targetSetList = [] prefix = dialog.GetValue(SET_PREFIX).decode('utf-8') setList = targetModel.GetSetList() if (setList.IsValid() == False): return targetSetList for i in range(setList.NumSet()): set = setList.GetSet(i) if set.IsValid(): setName = set.GetName() if sys.version_info.major == 2: setName = setName.decode('utf-8') if setName.startswith(prefix): targetSetList.append(set) return targetSetList 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 get_target_torque(dataset, dialog): result = [] selectedIndex = dialog.GetValue(TORQUE_COND_TITLE) titleList = torque_condition_title_list(app) targetName = titleList[selectedIndex] for i in range(dataset.GetCols()): if (dataset.GetColumnName(i)==targetName): result = list(dataset.GetColumn(i)) return result def has_zero_speed(app): targetStudy = app.GetCurrentStudy() numCases = targetStudy.GetDesignTable().NumCases() for caseIndex in range(numCases): targetStudy.SetCurrentCase(caseIndex) if (targetStudy.HasResult()==False): continue motionList = get_conditions(targetStudy, "RotationMotion") motion = motionList[0] speed = motion.GetValue("AngularVelocity") if (speed==0.0): return True return False def has_symmetry_boundary_on_XYPlane(study): condList = get_conditions(study, "SymmetryBoundary") for symmetry in condList: if symmetry.HasTargetOnXYPlane(): return True return False def get_case_index_list(dialog, targetStudy): caseIndexList = [] caseNoList = dialog.GetValueAsIntegerList(SPECIFIED_CASES) outputCaseType = dialog.GetValue(OUTPUT_CASE_TYPE) numCases = targetStudy.GetDesignTable().NumCases() if (outputCaseType == 0): # Output all cases caseIndexList = range(numCases) elif (outputCaseType == 1): # Output specified cases caseIndexList = get_caseIndexList_from_caseNoList(targetStudy, caseNoList) return caseIndexList def check_has_not_1cycle_step_cases(app, parameters): result = False useElectricCycle = parameters.GetValue(USE_COPY_CYCLE) numPoles = parameters.GetValue(NUM_POLES) targetStudy = app.GetCurrentStudy() torqResultName = get_torq_result_name(app) caseIndexList = get_case_index_list(parameters, targetStudy) for caseIndex in caseIndexList: if (targetStudy.CaseHasResult(caseIndex) == False): continue ##Calculate 1 mechanical cycle time from rotation speed targetStudy.SetCurrentCase(caseIndex) speed = get_speed(targetStudy) T = get_1_mechanical_cycle_time(speed, useElectricCycle, numPoles) ##Get torque data for 1 last cycle lastCycleTorq = [] dataset = targetStudy.GetDataSet(torqResultName, caseIndex+1) numSteps = dataset.GetRows() if (dataset.GetCols()!=2 or numSteps==0): continue time = list(dataset.GetColumn(0)) if (len(time)<=1): result = True break lastCycleStartTime = time[-1] - T + time[1] timeScale = time[1] if (lastCycleStartTime < -EPSILON * T): result = True break return result def get_torq_result_name(app): targetStudy = app.GetCurrentStudy() useMultiSlice = use_multi_slice(targetStudy) result = "Torque" numSlice = 1 if (useMultiSlice): numSlice = get_slice_number(targetStudy) if (is_japanese(app)): result = "トルク <モデル全体>" else: result = "Torque " return result def get_removed_node_list_on_boundary(targetStudy, targetSetList): removedList = [] for curset in targetSetList: selectedIds = [] sel = curset.GetSelection() if sel.NumEdges()>0: for i in range(sel.NumEdges()): selectedIds.append(sel.EdgeID(i)) elif sel.NumFaces()>0: for i in range(sel.NumFaces()): selectedIds.append(sel.FaceID(i)) nodeIds = [] for entityId in selectedIds: if sel.NumEdges()>0: nodeIds.extend(targetStudy.GetNodeIdsOnEdge(entityId)) elif sel.NumFaces()>0: nodeIds.extend(targetStudy.GetNodeIdsOnFace(entityId)) ##Remove duplicate nodes nodeIds = list(set(nodeIds)) ##Remove nodes on boundary removedList.append(remove_nodes_on_boundary(targetStudy, nodeIds)) return removedList def create_file_name(originalFilePath, numCases, caseNo, useMultiSlice, sliceNo): if (useMultiSlice): if (numCases > 1): absFilePathWithoutExt = os.path.splitext(originalFilePath)[0] postFixLabel = b"_Case%d_Slice%d.csv" % (caseNo, sliceNo) return (absFilePathWithoutExt + postFixLabel) else: absFilePathWithoutExt = os.path.splitext(originalFilePath)[0] sliceLabel = b"_Slice%d.csv" % sliceNo return (absFilePathWithoutExt + sliceLabel) else: if (numCases > 1): absFilePathWithoutExt = os.path.splitext(originalFilePath)[0] caseLabel = b"_Case%d.csv" % caseNo return (absFilePathWithoutExt + caseLabel) else: return originalFilePath def get_1_mechanical_cycle_time(speed, useElectricCycle, numPoles): if (speed == 0.0 or numPoles == 0): return 0 if (useElectricCycle): T = 60.0/speed/numPoles*2 else : T = 60.0/speed return T def setup_progress(app, dimension, caseIndexList, numSlice, targetSetList): progressLabel = "Exporting to CSV File..." if (is_japanese(app)): progressLabel = "CSVファイルへ出力中..." app.SetupUserProgress(progressLabel) app.SetUserProgressUseCancel(True) maxSteps = dimension * len(caseIndexList) * numSlice * len(targetSetList) app.SetUserProgressMaxSteps(maxSteps) app.UserProgressStart() def create_probe(title, targetStudy, useMultiSlice, sliceIndex, isJap, coordType, compIndex): probe = targetStudy.CreateProbe(title) probe.SetAutoRecalculate(False) subTitle = "" if (useMultiSlice): if (isJap): subTitle = " <断面 " + str(sliceIndex+1) + ">" else: subTitle = " " probe.SetResultType("NodalForce", subTitle) probe.SetResultCoordinate(get_coordName(coordType)) probe.SetComponent(get_component(coordType, compIndex)) probe.ClearPoints() probe.SetProbeType(1) probe.SetUseElementValue(True) probe.SetMoveWithPart(True) return probe def convert_twice(needConvertTwice, data): convertedData = [] if needConvertTwice: convertedData = [n*2 for n in data] else: convertedData = data return convertedData def copy_1_electric_cycle_to_1_mechanical_cycle(useElectricCycle, numPoles, originalData,includeFirst = False): result = [] if (useElectricCycle): for i in range(numPoles//2): if (i == 0) or (includeFirst == True): result.extend(originalData) else: result.extend(originalData[1:]) else: result = originalData return result def create_1_electric_cycle_time_to_1_mechanical_cycle_time(useElectricCycle, numPoles, originalData): result = [] offsetData = [] numSize = len(originalData) if (numSize) < 2: return result deltaT = originalData[1] - originalData[0] startTime = originalData[0] offsetData = [] for i in range(len(originalData)): offsetData.append(i*deltaT) lastT = offsetData[-1] if (useElectricCycle): for i in range(numPoles//2): tmp = [] if (i == 0): tmp = offsetData else: offsetTime = lastT + deltaT tmp = [n + offsetTime for n in offsetData][:-1] lastT = tmp[-1] result.extend(tmp) else: result = originalData return result def WriteByAllComponentsInSetForOneCase(file, fullModelF): for timeIndex in range(len(fullModelF[0])): for periodicIndex in range(len(fullModelF)): if (periodicIndex == 0): # 0 is time column file.write(str(fullModelF[periodicIndex][timeIndex])) file.write(",") else: for eachSetIndex in range(len(fullModelF[periodicIndex])): for eachCompIndex in range(len(fullModelF[periodicIndex][eachSetIndex])): file.write(str(fullModelF[periodicIndex][eachSetIndex][eachCompIndex][timeIndex])) if (periodicIndex == len(fullModelF)-1 and eachSetIndex == len(fullModelF[periodicIndex])-1 and eachCompIndex == len(fullModelF[periodicIndex][eachSetIndex])-1): file.write("\n") else: file.write(",") def get_last_1_cycle_start_index(dialog, targetStudy, dataset): startIndex = 0 ##Get dialog parameters useElectricCycle = dialog.GetValue(USE_COPY_CYCLE) numPoles = dialog.GetValue(NUM_POLES) ##Calculate 1 mechanical cycle time from rotation speed speed = get_speed(targetStudy) T = get_1_mechanical_cycle_time(speed, useElectricCycle, numPoles) ##Get torque data for 1 last cycle lastCycleTorq = [] numSteps = dataset.GetRows() if (dataset.GetCols()!=2 or numSteps==0): return 0 time = list(dataset.GetColumn(0)) ##Search last 1 cycle start index lastCycleStartTime = time[-1] - T index = len(time)-1 t = time[index] while t > lastCycleStartTime - EPSILON: index -= 1 if (index < 0 or len(time) <= index): break t = time[index] startIndex = index + 1 return startIndex def write_header_for_time_domain_tooth_force_only(file, setPrefix, numFullModelSets): numComponents = OUTPUT_DIMENSION file.write(",") ##Write a line for set names for setIndex in range(numFullModelSets): for componentIndex in range(numComponents): if (componentIndex == 0): setName = setPrefix + " " + str(setIndex+1) file.write(setName) file.write(",") elif (setIndex == numFullModelSets-1 and componentIndex == numComponents-1): file.write("\n") else: file.write(",") ##Write a line for time and each set components file.write("Time") file.write(",") for setIndex in range(numFullModelSets): for componentIndex in range(numComponents): componentName = "F" + get_component(0, componentIndex).lower() file.write(componentName) if (setIndex == numFullModelSets-1 and componentIndex == numComponents-1): file.write("\n") else: file.write(",") def write_header_for_frequency_domain_tooth_force_only(file, setPrefix, numFullModelSets): numComponents = OUTPUT_DIMENSION file.write(",") ##Write a line for set names for setIndex in range(numFullModelSets): for componentIndex in range(numComponents): for realImagIndex in range(2): if (componentIndex == 0 and realImagIndex == 0): setName = setPrefix + " " + str(setIndex+1) file.write(setName) file.write(",") elif (setIndex == numFullModelSets-1 and componentIndex == numComponents-1 and realImagIndex == 1): file.write("\n") else: file.write(",") ##Write a line for time and each set components file.write("Frequency") file.write(",") for setIndex in range(numFullModelSets): for componentIndex in range(numComponents): coordComponentName = "F" + get_component(0, componentIndex).lower() for realImagIndex in range(2): if (realImagIndex == 0): componentName = coordComponentName + "(real)" else: componentName = coordComponentName + "(imag)" file.write(componentName) if (setIndex == numFullModelSets-1 and componentIndex == numComponents-1 and realImagIndex == 1): file.write("\n") else: file.write(",") def ShowFinishMessage(app, wasCanceled): message = "The csv file was created.\n" message_jp = "CSVファイルが作成されました。" if (wasCanceled==True): message = "The csv file export was canceled.\n" message_jp = "CSVファイル出力がキャンセルされました。" confirmation = app.CreateDialogBox() confirmation.SetTranslation(message, message_jp) confirmation.AddLabel(message, 0, 2) confirmation.SetCancelButtonVisible(False) confirmation.Show() #--------------------------------------------------------------- # for express #--------------------------------------------------------------- SCENARIO_TITLE_expr = "scnario_title" CSV_VERSION_expr = "1.1.0" def get_valid_motion(study): motionList = get_conditions(study, "RotationMotion") if (len(motionList)<1): return False for i in range(len(motionList)): motion_type = motionList[i].GetValue("MotionGroupType") if motion_type == 0: return motionList[i] return None def has_zero_speed_expr(study, caseIndexList): startCase = study.GetCurrentCase() res = False for i in range(len(caseIndexList)): caseIndex = caseIndexList[i] study.SetCurrentCase(caseIndex) speed = get_speed(study) if (speed==0.0): res = True break study.SetCurrentCase(startCase) return res def getPoleParametricEquation_expr(designTable): return designTable.GetEquation("POLES") def has_invalid_pole_expr(designTable, caseIndexList): if not designTable.HasEquation("POLES"): return True poleParametricEquation = getPoleParametricEquation_expr(designTable) if (poleParametricEquation is None) or (not poleParametricEquation.IsValid()): return True for i in range(len(caseIndexList)): if poleParametricEquation.GetValue(caseIndexList[i]) < 1: return True return False def get_pole_expr(designTable, caseIndex): poleParametricEquation = getPoleParametricEquation_expr(designTable) return int(poleParametricEquation.GetValue(caseIndex)) def get_slot_expr(designTable, caseIndex): if designTable.HasEquation("SLOTS"): return int(designTable.GetEquation("SLOTS").GetValue(caseIndex)) else: return 0 def findNodalForceCalculationDefinition_expr(study, component): 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): return calc_def return None def getTargetTorqueResultName_expr(isMultiSlice, isJapanese): if not isMultiSlice: return "Torque" elif isJapanese: return "トルク <モデル全体>" else: return "Torque " def checkTargetTorqueConditionTitle_expr(condName): targetTorqueConditionTitleJp = "トルク" targetTorqueConditionTitleEn = "Torque" targetTorqueConditionTitleUtf8 = (b'\xe3\x83\x88\xe3\x83\xab\xe3\x82\xaf').decode('utf-8') if condName == targetTorqueConditionTitleJp: return True elif condName == targetTorqueConditionTitleEn: return True elif condName ==targetTorqueConditionTitleUtf8: return True return False def findTorqueCondition_expr(study): torqConditions = get_conditions(study, "Torque") for i in range(len(torqConditions)): condName = torqConditions[i].GetName() if checkTargetTorqueConditionTitle_expr(condName): return torqConditions[i] return None def findTorqueDataSet_expr(study, caseIndex, isJapanese): isMultiSlice = not (get_first_condition(study, "MultiSlice") is None) torqResultName = getTargetTorqueResultName_expr(isMultiSlice, isJapanese) dataSet = study.GetDataSet(torqResultName, caseIndex+1) if (dataSet is None): return [None, -1] elif (not dataSet.IsValid()): return [None, -1] for i in range(dataSet.GetCols()): column_name = dataSet.GetColumnName(i) if checkTargetTorqueConditionTitle_expr(column_name): return [dataSet, i] return [None, -1] def debugShowErrorMessage_expr(message): #debug.Print(message) #show_error_message(message, message) return def copy_cycles_expr(originalData, numExtendCycle): result = [] for i in range(numExtendCycle): if (i == 0): result.extend(originalData) else: result.extend(originalData[1:]) return result def extend_cycles_expr(timeData, numExtendCycle): result = [] incremental = timeData[-1] - timeData[0] for i in range(numExtendCycle): if (i == 0): result.extend(timeData) else: ext = timeData[1:] ext = [t + incremental * i for t in ext] result.extend(ext) return result def get_1_cycle_time_expr(speed, numPoles, useElectricCycle): if (speed == 0.0 or numPoles == 0): return 0 if useElectricCycle: T = 60.0/speed/numPoles*2 else: T = 60.0/speed return T def find_nearest_index(fullTime, startTime): index = bisect_left(fullTime, startTime) if index==0: return 0 if index == len(fullTime): return len(fullTime) - 1 prev = startTime - fullTime[index-1] tmp = fullTime[index] - startTime if prev <= tmp: return index-1 else: return index def getUseElectricCycleCheckBoxLabel_expr(isJapanese): if isJapanese: return "電気角1周期分または1/2周期分をコピーして機械角1周期分にする" else: return "Copy 1 or 1/2 electrical cycle to mechanical cycle" def get_last_cycle_start_index_expr(speed, numPoles, useElectricCycle, fullTime): ##Calculate 1 electric cycle time from rotation speed full_time_range = fullTime[-1] - fullTime[0] cycle_time = get_1_cycle_time_expr(speed, numPoles, useElectricCycle) lastCycleStartTime = 0.0 numExtendCycle = 1 if useElectricCycle: isFullCycle = (full_time_range > cycle_time - EPSILON) isHalfCycle = ((not isFullCycle) and full_time_range > cycle_time/2 - EPSILON) if isFullCycle: lastCycleStartTime = fullTime[-1] - cycle_time numExtendCycle = numPoles//2 elif isHalfCycle: lastCycleStartTime = fullTime[-1] - cycle_time / 2.0 numExtendCycle = numPoles//2 * 2 else: message = "Insufficient number of result time steps. The file output must have more than the half cycle electrical angle time step number. Please check the results of the specified cases." message_jp = "結果の時間ステップ数が不十分です。ファイル出力には半周期電気角分の時間ステップ数以上の結果が必要です。指定ケースの結果を見直してください。" show_error_message(message, message_jp) return (-1, 0) else: if (full_time_range > cycle_time - EPSILON): lastCycleStartTime = fullTime[-1] - cycle_time numExtendCycle = 1 else: message = "Insufficient number of result time steps. The file output must have more than one cycle mechanical angle time step number.\n"\ "If the target scenario is torque ripple or the custom scenario that calculates more than half a period of electrical angles,\n"\ "Please check the box ["+getUseElectricCycleCheckBoxLabel_expr(False) +"]." message_jp = "結果の時間ステップ数が不十分です。ファイル出力には1周期機械角分の時間ステップ数以上の結果が必要です。\n"\ "対象シナリオがトルクリップルまたは電気角半周期分以上を計算しているカスタムシナリオの場合、\n"\ "["+getUseElectricCycleCheckBoxLabel_expr(True) + "]にチェックを入れてください。" show_error_message(message, message_jp) return (-1, 0) index = find_nearest_index(fullTime, lastCycleStartTime) return (index, numExtendCycle) def create_torque_data_expr(study, designTable, useElectricCycle, caseIndexList, isJapanese): ##Initialize speedList = [] avTorqList = [] startIndices = [] numExtendCycleList = [] insufficientResultCaseIndexList = [] outX = [] outYT = [] startCase = study.GetCurrentCase() ##Create each case data for caseIndex in caseIndexList: if check_progress_wascanceled_expr(app): break if (study.CaseHasResult(caseIndex) == False): insufficientResultCaseIndexList.append(caseIndex) continue study.SetCurrentCase(caseIndex) speed = get_speed(study) numPoles = get_pole_expr(designTable, caseIndex) ##Calculate 1 electric or mechanical cycle time from rotation speed T = get_1_cycle_time_expr(speed, numPoles, useElectricCycle) ##Get torque data for 1 last cycle lastCycleTorq = [] [dataset, torqueColumn]= findTorqueDataSet_expr(study, caseIndex, isJapanese) time = list(dataset.GetColumn(0)) torque = list(dataset.GetColumn(torqueColumn)) (start_index, numExtendCycle) = get_last_cycle_start_index_expr(speed, numPoles, useElectricCycle, time) if start_index < 0: insufficientResultCaseIndexList.append(caseIndex) break lastCycleTorq = torque[start_index:] ##Calculate average torque aveTorq = calc_ave_torque(lastCycleTorq) ##Copy 1 electric cycle to 1 mechanical cycle if numExtendCycle > 1: lastCycleTorq = copy_cycles_expr(lastCycleTorq, numExtendCycle) ##Create angle data angleData = [] deltaAngle = 360.0/(len(lastCycleTorq)) for i in range(len(lastCycleTorq)): angleData.append(deltaAngle*i) ##Set each case data speedList.append(speed) avTorqList.append(aveTorq) startIndices.append(start_index) numExtendCycleList.append(numExtendCycle) outX.append(angleData) outYT.append(lastCycleTorq) study.SetCurrentCase(startCase) return (caseIndexList, insufficientResultCaseIndexList, speedList, avTorqList, startIndices, numExtendCycleList, outX, outYT) def get_thickness_factor_expr(study, dimension, numSlice): thickness_factor = 1.0 #if (dimension == 2): # thickness_factor = study.GetStudyProperties().GetValueWithUnit("ModelThickness", "m") #else: # if (has_symmetry_boundary_on_XYPlane(study)): # thickness_factor = 2.0 #if (numSlice > 1): # thickness_factor /= numSlice return thickness_factor def create_partial_force_data_expr(study, componentKey, lastCycleStartIndex, numExtendCycle): ##Create data for selected component and selected case dataTable =findNodalForceCalculationDefinition_expr(study, componentKey).GetDataSet() rows = dataTable.GetRows() nSet = dataTable.GetCols() - 1 partialModelF=[] ##Calculate TOOTH value for setIndex in range(nSet): lastCycleF = [] ##Get last 1 cycle data for i in range(lastCycleStartIndex, rows): lastCycleF.append(dataTable.GetValue(i, setIndex+1)) ##Copy 1 electric cycle to 1 mechanical cycle if numExtendCycle > 1: lastCycleF = copy_cycles_expr(lastCycleF, numExtendCycle) ##Add each set data partialModelF.append(lastCycleF) return partialModelF def create_fft_force_data_expr(study, dataManager, componentKey, dimension, lastCycleStartIndex): ##Create data for selected component and selected case dataTable =findNodalForceCalculationDefinition_expr(study, componentKey).GetDataSet() rows = dataTable.GetRows() lastCycleTF = [] for i in range(lastCycleStartIndex, rows): lastCycleTF.append([dataTable.GetValue(i, 0)]) tmin = lastCycleTF[0][0] tmax = lastCycleTF[-1][0] nSet = dataTable.GetCols() - 1 freqList=[] dataSetTitle = "fft_for_nvf_force_export" ##Calculate TOOTH value partialModelRealF = [] partialModelImageF = [] for setIndex in range(nSet): # update lastCycleTF for i in range(lastCycleStartIndex, rows): lastCycleTF[i-lastCycleStartIndex].append(dataTable.GetValue(i, setIndex+1)) dataSetTF = dataManager.CreateFromDataSet(dataSetTitle, "xtitle", "ytitle", lastCycleTF) for i in range(1, dataSetTF.GetCols()): fftDataSet = dataManager.CreateFFT(dataSetTF, i-1, "RealAndImaginary", 0, tmin, tmax) if len(freqList)==0: freqList = fftDataSet.GetColumn(0) partialModelRealF.append(fftDataSet.GetColumn(1)) partialModelImageF.append(fftDataSet.GetColumn(2)) dataManager.DeleteDataSetObject(fftDataSet) dataManager.DeleteDataSetObject(dataSetTF) return (freqList, partialModelRealF, partialModelImageF) def create_time_data_expr(speed, numPoles, useElectricCycle, dataSetForHeader): fullTimeData = dataSetForHeader.GetColumn(0) (lastCycleStartIndex, numExtendCycle) = get_last_cycle_start_index_expr(speed, numPoles, useElectricCycle, fullTimeData) oneCycleTimeData = fullTimeData[lastCycleStartIndex:] if numExtendCycle > 1: oneCycleTimeData = extend_cycles_expr(oneCycleTimeData, numExtendCycle) return (lastCycleStartIndex, numExtendCycle, oneCycleTimeData) def write_format1_force_expr(file, study, designTable, dimension, useElectricCycle, caseIndexList, speedList, avTorqList, startIndices, numExtendCycleList, outX, is100Format): ##Get Study value startCase = study.GetCurrentCase() ##Write data for each component componentKeys = ["Radial", "Theta", "Z"] componentLabels = ["Radius", "Theta", "Z"] for compIndex in range(dimension): if check_progress_wascanceled_expr(app): break if is100Format: write_line2(file, "*Force", str(compIndex+1)) elif (not is100Format) and compIndex == 0: write_line(file, "*Force") componentKey = componentKeys[compIndex] ##Write data for each case for outputIndex in range(len(caseIndexList)): if check_progress_wascanceled_expr(app): break else: app.UserProgressStep() caseIndex = caseIndexList[outputIndex] lastCycleStartIndex = startIndices[outputIndex] numExtendCycle = numExtendCycleList[outputIndex] study.SetCurrentCase(caseIndex) slots = get_slot_expr(designTable, caseIndex) partialModelF = create_partial_force_data_expr(study, componentKey, lastCycleStartIndex, numExtendCycle) periodicity = slots // len(partialModelF) fullModelF = partialModelFToFullModelFWithCopy_expr(partialModelF, periodicity) if is100Format: write_line2(file, "Speed(RPM)", str(speedList[outputIndex])) write_line2(file, "Torque(Nm)", str(avTorqList[outputIndex])) else: write_line2(file, "Case", str(caseIndex + 1)) write_line2(file, "Component", str(componentLabels[compIndex])) ##Write TOOTH value for i in range(len(outX[outputIndex])): file.write(str(outX[outputIndex][i]) + ",") for j in range(len(fullModelF)): file.write(str(fullModelF[j][i])) if j == len(fullModelF)-1: file.write("\n") else: file.write(",") file.write("\n") study.SetCurrentCase(startCase) def get_active_case_indices_expr(study): designTable = study.GetDesignTable() numCase = designTable.NumCases() caseIndexList = [] for i in range(numCase): if designTable.IsActive(i) and study.CaseHasResult(i): caseIndexList.append(i) return caseIndexList def get_param_from_input_dialog_expr(app): dialog = app.CreateDialogBox() scenario_titles = [s.GetName() for s in GetCanUseScriptStudies(app, True)] setup_param_input_dialog_expr(dialog, scenario_titles) dialogShowResponse = dialog.Show() useElectricCycle = dialog.GetValue(USE_COPY_CYCLE) outputPath = dialog.GetValue(OUTPUT_FILE_PATH) outputFormatType = dialog.GetValue(OUTPUT_FORMAT_TYPE) selectedStudyListIndex = dialog.GetValue(SCENARIO_TITLE_expr) return (dialogShowResponse, selectedStudyListIndex, useElectricCycle, outputPath, outputFormatType) def setup_param_input_dialog_expr(dialog, scenario_titles): dialogTitle = "JMAG-Designer: NVH Force Export Setting" dialogTitle_jp = "JMAG-Designer: NVH電磁力出力設定" dialog.SetTranslation(dialogTitle, dialogTitle_jp) label_1 = "Output File:" label_1_jp = "出力ファイル:" dialog.SetTranslation(label_1, label_1_jp) label_3 = "Target:" label_3_jp = "対象:" dialog.SetTranslation(label_3, label_3_jp) label_8 = getUseElectricCycleCheckBoxLabel_expr(False) label_8_jp = getUseElectricCycleCheckBoxLabel_expr(True) dialog.SetTranslation(label_8, label_8_jp) label_12 = "Output Format:" label_12_jp = "出力フォーマット:" dialog.SetTranslation(label_12, label_12_jp) label_13 = "Single File Including Torque(Force Coordinates=Cylindrical)" label_13_jp = "トルクデータ含む1ファイル出力(節点力の座標系=円筒座標系)" dialog.SetTranslation(label_13, label_13_jp) #label_16 = "Single File Including Torque(Force Coordinates=Cylindrical)[v22.2 and earlier]" #label_16_jp = "トルクデータ含む1ファイル出力(節点力の座標系=円筒座標系)[v22.2以前の形式]" #dialog.SetTranslation(label_16, label_16_jp) label_14 = "File Per Case: Time Domain Tooth Forces(Force Coordinates=Rectangular)" label_14_jp = "ケースごとにファイル出力:時刻依存性ティース電磁力(節点力の座標系=直交座標系)" dialog.SetTranslation(label_14, label_14_jp) label_15 = "File Per Case: Frequency Domain Tooth Forces(Force Coordinates=Rectangular)" label_15_jp = "ケースごとにファイル出力:周波数依存性ティース電磁力(節点力の座標系=直交座標系)" dialog.SetTranslation(label_15, label_15_jp) dialog.SetTitle(dialogTitle) dialog.AddLabel(label_1, 0, 1) dialog.AddSaveFilename(OUTPUT_FILE_PATH, "", "", "*.csv", 1, 1) dialog.AddLabel(label_3, 0, 1) dialog.AddComboBox(SCENARIO_TITLE_expr, "", scenario_titles, 0, 1) dialog.AddCheckBox(USE_COPY_CYCLE, label_8, True, 1, 1) dialog.AddLabel("", 0, 1) dialog.AddLabel(label_12, 0, 1) dialog.AddRadio(OUTPUT_FORMAT_TYPE, label_13, 0, 1) #dialog.AddRadio(OUTPUT_FORMAT_TYPE, label_16, 1, 1) dialog.AddRadio(OUTPUT_FORMAT_TYPE, label_14, 1, 1) dialog.AddRadio(OUTPUT_FORMAT_TYPE, label_15, 2, 1) def get_case_table_expr(study, designTable, is2D, caseIndexList): numTeethList = [] modelThicknessList = [] numSliceList = [] startCase = study.GetCurrentCase() for i in range(len(caseIndexList)): caseIndex = caseIndexList[i] study.SetCurrentCase(caseIndex) slots = get_slot_expr(designTable, caseIndex) numTeethList.append(slots) if is2D: modelThicknessList.append(study.GetStudyProperties().GetValueWithUnit("ModelThickness", "mm")) else: modelThicknessList.append(0.0) if is2D and use_multi_slice(study): numSliceList.append(get_slice_number(study)) else: numSliceList.append(0) study.SetCurrentCase(startCase) return (numTeethList, modelThicknessList, numSliceList) def getStudyAndDesignTable_expr(app, selectedStudyListIndex): study = GetCanUseScriptStudies(app, True)[selectedStudyListIndex] if app.NumAnalysisGroups() > 0: return (study, app.GetCurrentAnalysisGroup().GetDesignTable()) else: return (study, study.GetDesignTable()) def output_single_file_including_torque_expr(app, selectedStudyListIndex, useElectricCycle, outputPath, is100Format): isJapanese = is_japanese(app) dimension = app.GetCurrentModel().GetDimension() is2D = (dimension == 2) startStudy = app.GetCurrentStudy() (study, designTable) = getStudyAndDesignTable_expr(app, selectedStudyListIndex) app.SetCurrentStudy(study.GetName()) caseIndexList = get_active_case_indices_expr(study) start_progress_expr(app, len(caseIndexList) * dimension) (caseIndexList, insufficientResultCaseIndexList, speedList, avTorqList, startIndices, numExtendCycleList, outX, outYT) = create_torque_data_expr(study, designTable, useElectricCycle, caseIndexList, isJapanese) if len(insufficientResultCaseIndexList) > 0: return False if check_progress_wascanceled_expr(app): return False (numTeethList, modelThicknessList, numSliceList) = get_case_table_expr(study, designTable, is2D, caseIndexList) if check_progress_wascanceled_expr(app): return False result = True try: file = open(outputPath.decode('utf-8'), 'w') if is100Format: write_header_100(file, numTeethList[0], is2D, modelThicknessList[0], max(numSliceList) > 1 , numSliceList[0]) else: write_header_110(file, is2D, caseIndexList, speedList, avTorqList, numTeethList, modelThicknessList, numSliceList) if not check_progress_wascanceled_expr(app): write_torque(file, caseIndexList, speedList, avTorqList, outX, outYT, is100Format) if not check_progress_wascanceled_expr(app): write_format1_force_expr(file, study, designTable, dimension, useElectricCycle, caseIndexList, speedList, avTorqList, startIndices, numExtendCycleList, outX, is100Format) file.close() except Exception as e: app.UserProgressFinish() show_error_message(str(e), str(e)) result = False app.SetCurrentStudy(startStudy.GetName()) return result def getColumnTitles(calcDefForHeader, periodicity): dataSetForHeader =calcDefForHeader.GetDataSet() n_set = dataSetForHeader.GetCols() - 1 titles = [] isAllDefault = True isSequencial = True setName0 = dataSetForHeader.GetColumnName(1) tmpPrefix = "" if len(setName0) > 1: tmpPrefix = setName0[0:-1] for setIndex in range(n_set): setName = dataSetForHeader.GetColumnName(setIndex+1) titles.append(setName) if isAllDefault: if setName!="合計" and setName!="Sum": isAllDefault = False if isSequencial: sequencialName = tmpPrefix + str(setIndex+1) if setName != sequencialName: isSequencial = False if isAllDefault: titles = [] prefix = "SET" if calcDefForHeader.NumSets() > 0: prefix = calcDefForHeader.GetSet(0).GetName() for i in range(n_set * periodicity): titles.append(prefix + str(i+1)) elif isSequencial: titles = [] for i in range(n_set * periodicity): titles.append(tmpPrefix + str(i+1)) else: for periodicityIndex in range(1, periodicity): for setIndex in range(n_set): titles.append(titles[setIndex] + "_" + str(periodicityIndex)) return titles def partialModelFToFullModelFWithCopy_expr(partialModelF, periodicity): fullModelF = [] for periodicIndex in range(periodicity): fullModelF.extend(partialModelF) return fullModelF def partialModelFToFullModelFWithRotate_expr(partialModelF_X, partialModelF_Y, periodicity): n_set = len(partialModelF_X) fullModelF_X = partialModelF_X fullModelF_Y = partialModelF_Y for periodicIndex in range(1, periodicity): rad = math.radians(360.0 * periodicIndex / periodicity) cos = math.cos(rad) sin = math.sin(rad) for setIndex in range(n_set): rotfx = [cos * x - sin * y for x,y in zip(partialModelF_X[setIndex], partialModelF_Y[setIndex])] rotfy = [sin * x + cos * y for x,y in zip(partialModelF_X[setIndex], partialModelF_Y[setIndex])] fullModelF_X.append(rotfx) fullModelF_Y.append(rotfy) return (fullModelF_X, fullModelF_Y) def output_time_domain_tooth_forces_expr(app, selectedStudyListIndex, useElectricCycle, outputPath): isJapanese = is_japanese(app) dimension = app.GetCurrentModel().GetDimension() startStudy = app.GetCurrentStudy() (study, designTable) = getStudyAndDesignTable_expr(app, selectedStudyListIndex) app.SetCurrentStudy(study.GetName()) caseIndexList = get_active_case_indices_expr(study) coordType = 0 # Fixed to Global Rectangular #targetSetList = get_target_set(targetModel, dialog) #setPrefix = dialog.GetValue(SET_PREFIX).decode('utf-8') ## Setup parameters useMultiSlice = False numSlice = 1 if (dimension==2): numSlice = get_slice_number(study) useMultiSlice = numSlice > 1 ## Case loop result = True startCase = study.GetCurrentCase() numCases = len(caseIndexList) start_progress_expr(app, numCases) for caseLoopIndex in range(numCases): if check_progress_wascanceled_expr(app): break else: app.UserProgressStep() caseIndex = caseIndexList[caseLoopIndex] study.SetCurrentCase(caseIndex) ##Get last 1 cycle times calcDefForHeader = findNodalForceCalculationDefinition_expr(study, "X") dataSetForHeader = calcDefForHeader.GetDataSet() n_set = dataSetForHeader.GetCols() - 1 speed = get_speed(study) numPoles = get_pole_expr(designTable, caseIndex) numSlots = get_slot_expr(designTable, caseIndex) periodicity = numSlots//n_set (lastCycleStartIndex, numExtendCycle, oneCycleTimeData) = create_time_data_expr(speed, numPoles, useElectricCycle, dataSetForHeader) if lastCycleStartIndex < 0: result = False break partialModelF_X = create_partial_force_data_expr(study, "X", lastCycleStartIndex, numExtendCycle) partialModelF_Y = create_partial_force_data_expr(study, "Y", lastCycleStartIndex, numExtendCycle) (fullModelF_X, fullModelF_Y) = partialModelFToFullModelFWithRotate_expr(partialModelF_X, partialModelF_Y, periodicity) fullModelF_Z = [] if (dimension==3): partialModelF_Z = create_partial_force_data_expr(study, "Z", lastCycleStartIndex, numExtendCycle) fullModelF_Z = partialModelFToFullModelFWithCopy_expr(partialModelF_Z, periodicity) ##make the 1st line for set names header_1st = "" columnTitles = getColumnTitles(calcDefForHeader, periodicity) for i in range(len(columnTitles)): header_1st += "," + columnTitles[i] + ",," ##make the 2nd line for time and each set components header_2nd = "Time" for periodicIndex in range(periodicity): for setIndex in range(n_set): setName = dataSetForHeader.GetColumnName(setIndex+1) header_2nd += ",Fx,Fy,Fz" ## Slice loop for sliceIndex in range(numSlice): # Write file dividedOutputPath = create_file_name(outputPath, numCases, caseIndex+1, useMultiSlice, sliceIndex+1) try: file = open(dividedOutputPath.decode('utf-8'), 'w') ## Write header file.write(header_1st) file.write("\n") file.write(header_2nd) file.write("\n") ##Write the all TOOTH value of the model for i in range(len(oneCycleTimeData)): line=str(oneCycleTimeData[i]) for j in range(n_set*periodicity): line += "," line += str(fullModelF_X[j][i]) line += "," line += str(fullModelF_Y[j][i]) line += "," if dimension==3: line += str(fullModelF_Z[j][i]) else: line += "0.0" file.write(line) file.write("\n") file.close() except Exception as e: app.UserProgressFinish() show_error_message(str(e), str(e)) result = False if not result: break if not result: break study.SetCurrentCase(startCase) app.SetCurrentStudy(startStudy.GetName()) return result def output_frequency_domain_tooth_forces_expr(app, selectedStudyListIndex, useElectricCycle, outputPath): isJapanese = is_japanese(app) dimension = app.GetCurrentModel().GetDimension() dataManager = app.GetDataManager() startStudy = app.GetCurrentStudy() (study, designTable) = getStudyAndDesignTable_expr(app, selectedStudyListIndex) app.SetCurrentStudy(study.GetName()) caseIndexList = get_active_case_indices_expr(study) coordType = 0 # Fixed to Global Rectangular #targetSetList = get_target_set(targetModel, dialog) #setPrefix = dialog.GetValue(SET_PREFIX).decode('utf-8') ## Setup parameters useMultiSlice = False numSlice = 1 if (dimension==2): numSlice = get_slice_number(study) useMultiSlice = numSlice > 1 ## Case loop startCase = study.GetCurrentCase() numCases = len(caseIndexList) start_progress_expr(app, numCases) result = True for caseLoopIndex in range(numCases): if check_progress_wascanceled_expr(app): break else: app.UserProgressStep() caseIndex = caseIndexList[caseLoopIndex] study.SetCurrentCase(caseIndex) ##Get last 1 cycle times calcDefForHeader = findNodalForceCalculationDefinition_expr(study, "X") dataSetForHeader = calcDefForHeader.GetDataSet() n_set = dataSetForHeader.GetCols() - 1 numSlots = get_slot_expr(designTable, caseIndex) periodicity = numSlots//n_set (lastCycleStartIndex, numExtendCycle) = get_last_cycle_start_index_expr(get_speed(study), get_pole_expr(designTable, caseIndex), useElectricCycle, dataSetForHeader.GetColumn(0)) if lastCycleStartIndex < 0: result = False break (freqList, partialModelF_Xr, partialModelF_Xi) = create_fft_force_data_expr(study, dataManager, "X", dimension, lastCycleStartIndex) (freqList, partialModelF_Yr, partialModelF_Yi) = create_fft_force_data_expr(study, dataManager, "Y", dimension, lastCycleStartIndex) (fullModelF_Xr, fullModelF_Yr) = partialModelFToFullModelFWithRotate_expr(partialModelF_Xr, partialModelF_Yr, periodicity) (fullModelF_Xi, fullModelF_Yi) = partialModelFToFullModelFWithRotate_expr(partialModelF_Xi, partialModelF_Yi, periodicity) fullModelF_Zr = [] fullModelF_Zi = [] if (dimension==3): (freqList, partialModelF_Zr, partialModelF_Zi) = create_fft_force_data_expr(study, useElectricCycle, "Z", dimension, lastCycleStartIndex) for periodicIndex in range(periodicity): fullModelF_Zr.extend(partialModelF_Zr) fullModelF_Zi.extend(partialModelF_Zi) ##make the 1st line for set names header_1st = "" columnTitles = getColumnTitles(calcDefForHeader, periodicity) for i in range(len(columnTitles)): header_1st += "," + columnTitles[i] + ",,,,," ##make the 2nd line for time and each set components header_2nd = "Frequency" for periodicIndex in range(periodicity): for setIndex in range(n_set): header_2nd += ",Fx(real),Fx(imag),Fy(real),Fy(imag),Fz(real),Fz(imag)" ## Slice loop slice_start = 0 for sliceIndex in range(numSlice): # Write file dividedOutputPath = create_file_name(outputPath, numCases, caseIndex+1, useMultiSlice, sliceIndex+1) try: file = open(dividedOutputPath.decode('utf-8'), 'w') ## Write header file.write(header_1st) file.write("\n") file.write(header_2nd) file.write("\n") ##Write the all TOOTH value of the model slice_start = sliceIndex * n_set * periodicity * 2 slice_end = (sliceIndex+1) * n_set * periodicity * 2 for i in range(len(freqList)): line=str(freqList[i]) for j in range(n_set*periodicity): line += "," line += str(fullModelF_Xr[j][i]) line += "," line += str(fullModelF_Xi[j][i]) line += "," line += str(fullModelF_Yr[j][i]) line += "," line += str(fullModelF_Yi[j][i]) line += "," if dimension==3: line += str(fullModelF_Zr[j][i]) line += "," line += str(fullModelF_Zi[j+1][i]) else: line += "0.0,0.0" file.write(line) file.write("\n") file.close() except Exception as e: app.UserProgressFinish() show_error_message(str(e), str(e)) result = False slice_start += n_set*2 if not result: break if not result: break study.SetCurrentCase(startCase) app.SetCurrentStudy(startStudy.GetName()) return result def hasActiveCase_expr(study): caseIndexList = get_active_case_indices_expr(study) return len(caseIndexList) > 0 def pre_scenario_mode_work(): if CanUseScript(): return True else: show_error_message("Unsuppoerted Synario", "未対応のシナリオです。") return False def check_post_state_expr(app): for study in GetCanUseScriptStudies(app, True): caseIndexList = get_active_case_indices_expr(study) if len(caseIndexList) > 0: return (True, "", "") return (False, "No case is selected for which the result exists.", "結果が存在するケースが選択されていません。") def setup_progress_expr(app): progressLabel = "Exporting to CSV File..." if (is_japanese(app)): progressLabel = "CSVファイルへ出力中..." app.SetupUserProgress(progressLabel) app.SetUserProgressUseCancel(True) def start_progress_expr(app, maxSteps): #return app.SetUserProgressMaxSteps(maxSteps) app.UserProgressStart() def end_progress_expr(app, resFlg): #ShowFinishMessage(app, not resFlg) wasCanceled = app.UserProgressWasCanceled() app.UserProgressFinish() ShowFinishMessage(app, wasCanceled or (not resFlg)) def check_progress_wascanceled_expr(app): #return False return app.UserProgressWasCanceled() def post_scenario_mode_work(): app = designer.GetApplication() (resCheck, error_msg_en, error_msg_jp) = check_post_state_expr(app) if not resCheck: show_error_message(error_msg_en, error_msg_jp) return (dialogShowResponse, selectedStudyListIndex, useElectricCycle, outputPath, outputFormatType) = get_param_from_input_dialog_expr(app) if dialogShowResponse != 1: return elif len(outputPath)==0: show_error_message("Output file path is invalid.","出力ファイルパスが不正です。") return setup_progress_expr(app) resFlg = False if outputFormatType==0: resFlg = output_single_file_including_torque_expr(app, selectedStudyListIndex, useElectricCycle, outputPath, True) elif outputFormatType==1: resFlg = output_time_domain_tooth_forces_expr(app, selectedStudyListIndex, useElectricCycle, outputPath) elif outputFormatType==2: resFlg = output_frequency_domain_tooth_forces_expr(app, selectedStudyListIndex, useElectricCycle, outputPath) end_progress_expr(app, resFlg) def run_scenario_mode(): startStudy = designer.GetApplication().GetCurrentStudy() if pre_scenario_mode_work(): post_scenario_mode_work() designer.GetApplication().SetCurrentStudy(startStudy.GetName()) def run_prefix_tooth_set_mode(): main_designer() # 0: prefix_tooth_set_mode (designer) # 1: scenario_mode (express) #-1: quit def selectMode(app): if app.IsExpressMode(): return 1 if CanUseScript(): return 1 if check_model(app): return 0 return -1 mode = selectMode(app) if mode==0: run_prefix_tooth_set_mode() elif mode==1: run_scenario_mode()