Source code for moldflow.study_doc

# SPDX-FileCopyrightText: 2025 Autodesk, Inc.
# SPDX-License-Identifier: Apache-2.0

"""
Usage:
    StudyDoc Class API Wrapper
"""

from .ent_list import EntList
from .import_options import ImportOptions
from .logger import process_log
from .helper import (
    check_type,
    check_file_extension,
    check_range,
    get_enum_value,
    check_is_non_negative,
    coerce_optional_dispatch,
)
from .com_proxy import safe_com
from .common import LogMessage, MoldingProcess, MeshType
from .constants import UDM_FILE_EXT
from .vector import Vector
from .string_array import StringArray


[docs] class StudyDoc: """ Wrapper for StudyDoc class of Moldflow Synergy. """ def __init__(self, _study_doc): """ Initialize the StudyDoc with a StudyDoc instance from COM. Args: _study_doc: The StudyDoc instance. """ process_log(__name__, LogMessage.CLASS_INIT, locals(), name="StudyDoc") self.study_doc = safe_com(_study_doc)
[docs] def create_entity_list(self) -> EntList: """ Creates a new entity list. Returns: EntList: A new entity list. """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="create_entity_list") result = self.study_doc.CreateEntityList if result is None: return None return EntList(result)
@property def molding_process(self) -> str: """ Value of Molding Process. :getter: Get value of Molding Process :setter: Set value of Molding Process :type: str """ process_log(__name__, LogMessage.PROPERTY_GET, locals(), name="molding_process") return self.study_doc.MoldingProcess @molding_process.setter def molding_process(self, value: str | MoldingProcess) -> None: """ Set molding process """ process_log( __name__, LogMessage.PROPERTY_SET, locals(), name="molding_process", value=value ) value = get_enum_value(value, MoldingProcess) self.study_doc.MoldingProcess = value @property def analysis_sequence(self) -> str: """ Value of Analysis Sequence. :getter: Get value of Analysis Sequence :setter: Set value of Analysis Sequence :type: str """ process_log(__name__, LogMessage.PROPERTY_GET, locals(), name="analysis_sequence") return self.study_doc.AnalysisSequence @analysis_sequence.setter def analysis_sequence(self, value: str): """ Set analysis sequence """ process_log( __name__, LogMessage.PROPERTY_SET, locals(), name="analysis_sequence", value=value ) check_type(value, str) self.study_doc.AnalysisSequence = value @property def analysis_sequence_description(self) -> str: """ Value of Analysis Sequence Description. :getter: Get value of Analysis Sequence Description :setter: Set value of Analysis Sequence Description :type: str """ process_log( __name__, LogMessage.PROPERTY_GET, locals(), name="analysis_sequence_description" ) return self.study_doc.AnalysisSequenceDescription @property def mesh_type(self) -> str: """ Value of Mesh Type. :getter: Get value of Mesh Type :setter: Set value of Mesh Type :type: str """ process_log(__name__, LogMessage.PROPERTY_GET, locals(), name="mesh_type") return self.study_doc.MeshType @mesh_type.setter def mesh_type(self, value: MeshType | str) -> None: """ Set mesh type """ process_log(__name__, LogMessage.PROPERTY_SET, locals(), name="mesh_type", value=value) value = get_enum_value(value, MeshType) self.study_doc.MeshType = value @property def selection(self) -> EntList: """ Value of Selection. :getter: Get value of Selection :setter: Set value of Selection :type: EntList """ process_log(__name__, LogMessage.PROPERTY_GET, locals(), name="selection") result = self.study_doc.Selection if result is None: return None return EntList(result) @selection.setter def selection(self, value: EntList | None) -> None: """ Set selection """ process_log(__name__, LogMessage.PROPERTY_SET, locals(), name="selection", value=value) if value is not None: check_type(value, EntList) self.study_doc.Selection = coerce_optional_dispatch(value, "ent_list") @property def number_of_analyses(self) -> int: """ Value of Number of Analyses. :getter: Get value of Number of Analyses :type: int """ process_log(__name__, LogMessage.PROPERTY_GET, locals(), name="number_of_analysis") return self.study_doc.NumberOfAnalyses @property def study_name(self) -> str: """ Value of Study Name. :getter: Get value of Study Name :setter: Set value of Study Name :type: str """ process_log(__name__, LogMessage.PROPERTY_GET, locals(), name="study_name") return self.study_doc.StudyName
[docs] def save(self) -> bool: """ Saves the study Returns: bool: True if successful, False otherwise. """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="save") return self.study_doc.Save
[docs] def save_as(self, name: str) -> bool: """ Saves the study under a new name Args: name (str): New study name Returns: bool: True if successful, False otherwise. """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="save_as") check_type(name, str) return self.study_doc.SaveAs(name)
[docs] def close(self, show_prompt: bool = True) -> bool: """ Closes the study Args: show_prompt (bool): Prompt to save changes or not (default: None) Returns: bool: True if successful, False otherwise. """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="close") check_type(show_prompt, bool) result = self.study_doc.Close2(show_prompt) if result: self.study_doc = None return result
[docs] def undo(self, num: int) -> bool: """ Undoes a number of model edit Args: num (int): Number of undo steps Returns: bool: True if successful, False otherwise. """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="undo") check_type(num, int) return self.study_doc.Undo(num)
[docs] def redo(self, num: int) -> bool: """ Redoes a number of model editing Args: num (int): Number of redo steps Returns: bool: True if successful, False otherwise. """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="redo") check_type(num, int) return self.study_doc.Redo(num)
[docs] def add_file(self, name: str, opts: ImportOptions | None, show_logs: bool) -> bool: """ Adds a CAD model file to the current study Args: name (str): Name of the file to add opts (ImportOptions | None): Import options for the file show_logs (bool): True if display logs Returns: bool: True if successful, False otherwise. """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="add_file") check_type(name, str) if opts is not None: check_type(opts, ImportOptions) check_type(show_logs, bool) return self.study_doc.AddFile( name, coerce_optional_dispatch(opts, "import_options"), show_logs )
[docs] def analyze_now(self, check: bool, solve: bool, prompts: bool = False) -> bool: """ Runs analysis immediately Args: check (bool): True if check only solve (bool): True if solve only prompts (bool): True if display prompts Returns: bool: True if successful, False otherwise. """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="analyze_now") check_type(check, bool) check_type(solve, bool) check_type(prompts, bool) return self.study_doc.AnalyzeNow2(check, solve, prompts)
[docs] def get_first_node(self) -> EntList: """ Gets the first node in the study Returns: EntList: The first node in the study """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="get_first_node") result = self.study_doc.GetFirstNode if result is None: return None return EntList(result)
[docs] def get_next_node(self, node: EntList | None) -> EntList: """ Gets the next node in the study Args: node (EntList | None): The current node Returns: EntList: The next node in the study """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="get_next_node") if node is not None: check_type(node, EntList) result = self.study_doc.GetNextNode(coerce_optional_dispatch(node, "ent_list")) if result is None: return None return EntList(result)
[docs] def get_node_coord(self, node: EntList | None) -> Vector: """ Gets node coordinates Args: node (EntList | None): The current node Returns: Vector: The coordinates of the node """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="get_node_coord") if node is not None: check_type(node, EntList) result = self.study_doc.GetNodeCoord(coerce_optional_dispatch(node, "ent_list")) if result is None: return None return Vector(result)
[docs] def get_first_tri(self) -> EntList: """ Gets the first triangle in the study Returns: EntList: The first triangle in the study """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="get_first_tri") result = self.study_doc.GetFirstTri if result is None: return None return EntList(result)
[docs] def get_next_tri(self, tri: EntList | None) -> EntList: """ Gets the next triangle in the study Args: tri (EntList | None): The current triangle Returns: EntList: The next triangle in the study """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="get_next_tri") if tri is not None: check_type(tri, EntList) result = self.study_doc.GetNextTri(coerce_optional_dispatch(tri, "ent_list")) if result is None: return None return EntList(result)
[docs] def get_first_beam(self) -> EntList: """ Gets the first beam in the study Returns: EntList: The first beam in the study """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="get_first_beam") result = self.study_doc.GetFirstBeam if result is None: return None return EntList(result)
[docs] def get_next_beam(self, beam: EntList | None) -> EntList: """ Gets the next beam in the study Args: beam (EntList | None): The current beam Returns: EntList: The next beam in the study """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="get_next_beam") if beam is not None: check_type(beam, EntList) result = self.study_doc.GetNextBeam(coerce_optional_dispatch(beam, "ent_list")) if result is None: return None return EntList(result)
[docs] def get_first_tet(self) -> EntList: """ Gets the first tetrahedral element in the study Returns: EntList: The first tetrahedral element in the study """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="get_first_tet") result = self.study_doc.GetFirstTet if result is None: return None return EntList(result)
[docs] def get_next_tet(self, tet: EntList | None) -> EntList: """ Gets the next tetrahedral element in the study Args: tet (EntList | None): The current tetrahedral element Returns: EntList: The next tetrahedral element in the study """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="get_next_tet") if tet is not None: check_type(tet, EntList) result = self.study_doc.GetNextTet(coerce_optional_dispatch(tet, "ent_list")) if result is None: return None return EntList(result)
[docs] def get_elem_nodes(self, elem: EntList | None) -> EntList: """ Gets the nodes of an element Args: elem (EntList | None): The element to get nodes from Returns: EntList: The nodes of the element """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="get_elem_nodes") if elem is not None: check_type(elem, EntList) result = self.study_doc.GetElemNodes(coerce_optional_dispatch(elem, "ent_list")) if result is None: return None return EntList(result)
[docs] def get_entity_layer(self, ent: EntList | None) -> EntList: """ Gets the layer that the entity is assigned to Args: ent (EntList | None): The entity to get layer Returns: EntList: The layer of the entity """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="get_entity_layer") if ent is not None: check_type(ent, EntList) result = self.study_doc.GetEntityLayer(coerce_optional_dispatch(ent, "ent_list")) if result is None: return None return EntList(result)
[docs] def get_entity_id(self, ent: EntList | None) -> int: """ Gets entity ID Args: ent (EntList | None): The entity Returns: int: The ID of the entity """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="get_entity_id") if ent is not None: check_type(ent, EntList) return self.study_doc.GetEntityID(coerce_optional_dispatch(ent, "ent_list"))
[docs] def get_first_curve(self) -> EntList: """ Gets the first curve in the study Returns: EntList: The first curve in the study """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="get_first_curve") result = self.study_doc.GetFirstCurve if result is None: return None return EntList(result)
[docs] def get_next_curve(self, curve: EntList | None) -> EntList: """ Gets the next curve in the study Args: curve (EntList | None): The current curve Returns: EntList: The next curve in the study """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="get_next_curve") if curve is not None: check_type(curve, EntList) result = self.study_doc.GetNextCurve(coerce_optional_dispatch(curve, "ent_list")) if result is None: return None return EntList(result)
[docs] def get_curve_point(self, curve: EntList | None, pos_curve: float) -> Vector: """ Gets a specified point on the curve Args: curve (EntList | None): The curve to get point from pos_curve (float): The position on the curve Returns: Vector: The point on the curve """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="get_curve_point") if curve is not None: check_type(curve, EntList) check_type(pos_curve, (int, float)) check_range(pos_curve, 0, 1, True, True) result = self.study_doc.GetCurvePoint( coerce_optional_dispatch(curve, "ent_list"), pos_curve ) if result is None: return None return Vector(result)
[docs] def delete_results(self, index: int) -> bool: """ Deletes results starting from the given index Args: index (int): Start index of results to be deleted Returns: bool: True if successful, False otherwise. """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="delete_results") check_type(index, int) return self.study_doc.DeleteResults(index)
[docs] def mesh_now(self, show_prompts: bool) -> bool: """ Runs mesh immediately Args: show_prompts (bool): True if display prompts Returns: bool: True if successful, False otherwise. """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="mesh_now") check_type(show_prompts, bool) return self.study_doc.MeshNow(show_prompts)
[docs] def get_result_prefix(self, name: str) -> str: """ Gets result prefix string of a given process Args: name (str): The name of the process Returns: str: The result prefix of the process """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="get_result_prefix") check_type(name, str) return self.study_doc.GetResultPrefix(name)
[docs] def import_process_variation(self, file: str, doe: bool, show_prompt: bool) -> bool: """ Import process variation from MPX/Shotscope Args: file (str): udm file from MPX/Shotscope doe (bool): True if set up DOE analysis show_prompt (bool): True if display prompt Returns: bool: True if successful, False otherwise. """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="import_process_variation") check_type(file, str) check_type(doe, bool) check_type(show_prompt, bool) file = check_file_extension(file, UDM_FILE_EXT) return self.study_doc.ImportProcessVariation(file, doe, show_prompt)
[docs] def import_process_condition(self, file: str, show_prompt: bool) -> bool: """ Import process condition from MPX Args: file (str): udm file from MPX show_prompt (bool): True if display prompt Returns: bool: True if successful, False otherwise. """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="import_process_condition") check_type(file, str) check_type(show_prompt, bool) file = check_file_extension(file, UDM_FILE_EXT) return self.study_doc.ImportProcessCondition(file, show_prompt)
[docs] def export_analysis_log(self, file: str) -> bool: """ Export analysis log to text file Args: file (str): File name to export analysis log Returns: bool: True if successful, False otherwise. """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="export_analysis_log") check_type(file, str) # file = file if file.endswith(".log") else f"{file}.log" return self.study_doc.ExportAnalysisLog(file)
[docs] def export_mesh_log(self, file: str) -> bool: """ Export mesh log to text file Args: file (str): File name to export mesh log Returns: bool: True if successful, False otherwise. """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="export_mesh_log") check_type(file, str) return self.study_doc.ExportMeshLog(file)
[docs] def mark_analysis_summary_for_export(self, marking: bool) -> None: """ Marks the summary for export Args: marking (bool): True if mark for export Returns: bool: True if successful, False otherwise. """ process_log( __name__, LogMessage.FUNCTION_CALL, locals(), name="mark_analysis_summary_for_export" ) check_type(marking, bool) self.study_doc.MarkAnalysisSummaryForExport(marking)
[docs] def get_part_cad_names(self) -> StringArray: """ Return the names of all cad models as a string array Returns: StringArray: The names of all cad models """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="get_part_cad_names") result = self.study_doc.GetPartCadNames if result is None: return None return StringArray(result)
@property def notes(self) -> str: """ Gets study notes :getter: Get study notes :setter: Set study notes :type: str """ process_log(__name__, LogMessage.PROPERTY_GET, locals(), name="notes") return self.study_doc.GetNotes @notes.setter def notes(self, note: str) -> None: """ Sets study notes Args: note: Notes to be set Returns: bool: True if successful, False otherwise. """ process_log(__name__, LogMessage.PROPERTY_SET, locals(), name="notes", value=note) check_type(note, str) self.study_doc.SetNotes(note)
[docs] def analysis_status(self, index: int) -> str: """ Gets the status of the analysis at the given index Args: index (int): Index of the analysis Returns: str: The status of the analysis """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="analysis_status") check_type(index, int) check_is_non_negative(index) return self.study_doc.AnalysisStatus(index)
[docs] def analysis_name(self, index: int) -> str: """ Gets the name of the analysis at the given index Args: index (int): Index of the analysis Returns: str: The name of the analysis """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="analysis_name") check_type(index, int) check_is_non_negative(index) return self.study_doc.AnalysisName(index)
[docs] def mesh_status(self) -> str: """ Gets the status of the mesh at the given index Args: index: Index of the mesh Returns: str: The status of the mesh """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="mesh_status") return self.study_doc.MeshStatus
[docs] def is_analysis_running(self) -> bool: """ Checks if the analysis is currently running Returns: bool: True if the analysis is running, False otherwise """ process_log(__name__, LogMessage.FUNCTION_CALL, locals(), name="is_analysis_running") return self.study_doc.IsAnalysisRunning