Moldflow API#
Overview#
Moldflow API is a Python wrapper library for the Synergy API, designed to simplify interactions with Autodesk Moldflow Synergy. This library provides a clean, pythonic interface to Moldflow’s simulation capabilities, making it easier to integrate Moldflow functionality into your Python applications.
Requirements#
Windows 10/11
Python 3.10.x - 3.13.x
Autodesk Moldflow Synergy 2026.0.1 or later
Installation#
From PyPI#
The easiest way to install Moldflow API is using pip:
pip install moldflow
From Source#
If you want to install from source or contribute to the project:
git clone https://github.com/Autodesk/moldflow-api.git
cd moldflow-api
python -m pip install -r requirements.txt
Quick Start#
Here’s a simple example to get you started:
from moldflow import Synergy
# Initialize the API
synergy = Synergy()
# Example: Get version information
version = synergy.version
build = synergy.build
print(f"Moldflow Synergy version: {version}")
print(f"Build: {build}")
Usage Examples#
Simulation Workflow#
This example shows a complete simulation setup from CAD import to analysis:
import os
from moldflow import Synergy
from moldflow.common import MeshType, MoldingProcess
# Initialize Synergy
synergy = Synergy()
# Create new project and study
synergy.new_project("test", "C:\\temp\\new_project")
project = synergy.project
project.new_study("injection_molding_analysis")
# Get study document and set basic parameters
study_doc = synergy.study_doc
study_doc.molding_process = MoldingProcess.THERMOPLASTIC_INJECTION_MOLDING
study_doc.mesh_type = MeshType.MESH_FUSION
# Import CAD file (example)
cad_file = "C:\\path\\to\\your\\part.stp"
if os.path.exists(cad_file):
import_opts = synergy.import_options
study_doc.add_file(cad_file, import_opts, show_logs=True)
# Set up mesh generation
mesh_generator = synergy.mesh_generator
mesh_editor = synergy.mesh_editor
# Generate and validate mesh
mesh_generator.generate()
mesh_editor.auto_fix()
mesh_editor.purge_nodes()
# Get mesh diagnostics
diagnosis_mgr = synergy.diagnosis_manager
mesh_summary = diagnosis_mgr.get_mesh_summary(element_only=True)
print(f"Mesh Quality Report:")
print(f" Elements: {mesh_summary.triangles_count}")
print(f" Nodes: {mesh_summary.nodes_count}")
# Save the configured study
project.save_all()
print("Simulation setup complete, running analysis...")
study_doc.analyze_now(check=False, solve=True)
Material Management#
Find and analyze materials with specific properties:
from moldflow import Synergy
from moldflow.common import MaterialDatabase, MaterialDatabaseType
synergy = Synergy()
material_finder = synergy.material_finder
# Search through different material databases
databases = [
(MaterialDatabase.THERMOPLASTIC, "Thermoplastics"),
(MaterialDatabase.THERMOSET_MATERIAL, "Thermoset Materials"),
(MaterialDatabase.UNDERFILL_ENCAPSULANT, "Underfill Encapsulants")
]
material_catalog = {}
for db_type, db_name in databases:
print(f"\n=== {db_name} Materials ===")
material_finder.set_data_domain(db_type, MaterialDatabaseType.SYSTEM)
materials = []
material = material_finder.get_first_material()
count = 0
while material and count < 10: # Limit for example
materials.append({
'id': material.id,
'name': material.name,
'type': material.type
})
print(f" {material.name} (ID: {material.id})")
material = material_finder.get_next_material(material)
count += 1
material_catalog[db_name] = materials
print(f"\nTotal material categories found: {len(material_catalog)}")
Mesh Analysis#
Perform detailed mesh quality analysis and diagnostics:
from moldflow import Synergy
synergy = Synergy()
diagnosis_mgr = synergy.diagnosis_manager
mesh_editor = synergy.mesh_editor
# Get comprehensive mesh summary
mesh_summary = diagnosis_mgr.get_mesh_summary(
element_only=False,
inc_beams=True,
inc_match=True,
recalculate=True
)
# Detailed mesh quality report
print("=== Comprehensive Mesh Analysis ===")
print(f"Geometry:")
print(f" Triangles: {mesh_summary.triangles_count:,}")
print(f" Tetrahedra: {mesh_summary.tetras_count:,}")
print(f" Beams: {mesh_summary.beams_count:,}")
print(f" Nodes: {mesh_summary.nodes_count:,}")
print(f"\nQuality Metrics:")
print(f" Aspect Ratio - Min: {mesh_summary.min_aspect_ratio:.3f}")
print(f" Aspect Ratio - Max: {mesh_summary.max_aspect_ratio:.3f}")
print(f" Aspect Ratio - Avg: {mesh_summary.ave_aspect_ratio:.3f}")
print(f" Max Dihedral Angle: {mesh_summary.max_dihedral_angle:.1f}°")
print(f" Max Volume Ratio: {mesh_summary.max_volume_ratio:.3f}")
print(f"\nMesh Integrity:")
print(f" Free Edges: {mesh_summary.free_edges_count}")
print(f" Manifold Edges: {mesh_summary.manifold_edges_count}")
print(f" Non-Manifold Edges: {mesh_summary.non_manifold_edges_count}")
print(f" Connectivity Regions: {mesh_summary.connectivity_regions}")
print(f"\nMesh Issues:")
print(f" Intersection Elements: {mesh_summary.intersection_elements}")
print(f" Overlap Elements: {mesh_summary.overlap_elements}")
print(f" Zero Triangles: {mesh_summary.zero_triangles}")
print(f" Zero Beams: {mesh_summary.zero_beams}")
print(f" Unoriented Elements: {mesh_summary.unoriented}")
# Perform mesh diagnostics and repairs
if mesh_summary.intersection_elements > 0:
print(f"\n⚠️ Found {mesh_summary.intersection_elements} intersection elements")
print("Running auto-fix...")
fixed_elements = mesh_editor.auto_fix()
print(f"Fixed {fixed_elements} elements")
# Additional mesh operations
entity_list = mesh_editor.create_entity_list()
print(f"Created entity list for further operations")
# Assess overall mesh quality
if mesh_summary.ave_aspect_ratio > 10:
print("⚠️ Average aspect ratio is high - consider mesh refinement")
if mesh_summary.free_edges_count > mesh_summary.triangles_count * 0.1:
print("⚠️ High number of free edges detected - check mesh integrity")
print(f"\n✓ Mesh analysis complete")
Project and Study Management#
Project management with multiple studies and configurations:
from moldflow import Synergy
from moldflow.common import MoldingProcess, MeshType
synergy = Synergy()
project = synergy.project
# Create multiple studies for different scenarios
study_configs = [
("thermoplastic_study", MoldingProcess.THERMOPLASTIC_INJECTION_MOLDING, "Standard thermoplastic injection"),
("gas_assisted_study", MoldingProcess.GAS_ASSISTED_INJECTION_MOLDING, "Gas-assisted injection molding"),
("overmolding_study", MoldingProcess.THERMOPLASTICS_OVERMOLDING, "Thermoplastic overmolding"),
("compression_study", MoldingProcess.THERMOPLASTICS_INJECTION_COMPRESSION_MOLDING, "Injection-compression molding")
]
created_studies = []
for study_name, process, description in study_configs:
print(f"Creating study: {study_name}")
# Create new study
success = project.new_study(study_name)
if success:
study_doc = synergy.study_doc
study_doc.molding_process = process
# Set mesh type based on study type
if "compression" in study_name:
study_doc.mesh_type = MeshType.MESH_3D
else:
study_doc.mesh_type = MeshType.MESH_MIDPLANE
created_studies.append({
'name': study_name,
'process': process,
'mesh_type': study_doc.mesh_type,
'description': description
})
print(f" ✓ {study_name} configured with {process.value}")
else:
print(f" ✗ Failed to create {study_name}")
# Save all studies
project.save_all()
print(f"\nProject Summary:")
print(f"Successfully created {len(created_studies)} studies:")
for study in created_studies:
print(f" - {study['name']}: {study['description']}")
Batch Processing Example#
Process multiple files or configurations automatically:
import os
import glob
from moldflow import Synergy
def process_cad_files(file_pattern):
"""Process multiple CAD files through Moldflow analysis setup."""
synergy = Synergy()
cad_files = glob.glob(file_pattern)
if not cad_files:
print(f"No files found matching pattern: {file_pattern}")
return
print(f"Found {len(cad_files)} CAD files to process")
results = []
for i, cad_file in enumerate(cad_files, 1):
filename = os.path.basename(cad_file)
study_name = f"auto_{os.path.splitext(filename)[0]}"
print(f"\n[{i}/{len(cad_files)}] Processing: {filename}")
try:
# Create new study
project = synergy.project
project.new_study(study_name)
# Import CAD file
import_opts = synergy.import_options
study_doc = synergy.study_doc
success = study_doc.add_file(cad_file, import_opts, show_logs=False)
if success:
# Quick mesh setup
mesh_generator = synergy.mesh_generator
mesh_generator.generate()
mesh_editor = synergy.mesh_editor
mesh_editor.auto_fix()
# Get basic mesh info
diagnosis_mgr = synergy.diagnosis_manager
mesh_summary = diagnosis_mgr.get_mesh_summary(element_only=True)
result = {
'file': filename,
'study': study_name,
'elements': mesh_summary.triangles_count,
'nodes': mesh_summary.nodes_count,
'quality': mesh_summary.ave_aspect_ratio,
'status': 'Success'
}
print(f" ✓ Mesh: {mesh_summary.triangles_count:,} elements")
print(f" ✓ Quality: {mesh_summary.ave_aspect_ratio:.2f} avg aspect ratio")
else:
result = {
'file': filename,
'study': study_name,
'status': 'Failed - Import Error'
}
print(f" ✗ Failed to import CAD file")
results.append(result)
except Exception as e:
print(f" ✗ Error processing {filename}: {str(e)}")
results.append({
'file': filename,
'status': f'Error: {str(e)}'
})
# Save all work
synergy.project.save_all()
# Summary report
print(f"\n=== Batch Processing Summary ===")
successful = len([r for r in results if r.get('status') == 'Success'])
print(f"Successfully processed: {successful}/{len(results)} files")
for result in results:
if result.get('status') == 'Success':
print(f" ✓ {result['file']}: {result['elements']:,} elements")
else:
print(f" ✗ {result['file']}: {result['status']}")
return results
# Example usage:
results = process_cad_files("C:\\CAD_Files\\*.stp", "C:\\Moldflow_Results\\")
Advanced Utilities#
Unit Conversion#
from moldflow import Synergy
from moldflow.common import SystemUnits
synergy = Synergy()
uc = synergy.unit_conversion # UnitConversion
si = uc.convert_to_si("mm", 25.4)
inch = uc.convert_to_unit("in", SystemUnits.ENGLISH, si)
desc = uc.get_unit_description("mm", SystemUnits.METRIC)
print(f"25.4 mm in SI: {si}")
print(f"SI back to inches: {inch}")
print(f"Unit description (Metric): {desc}")
Create Plot by Dataset and Export Results#
from moldflow import Synergy
from moldflow.common import PlotType, SystemUnits
synergy = Synergy()
pm = synergy.plot_manager # PlotManager
# Derive a dataset id from the first available plot (avoids hard-coding)
plot = pm.get_first_plot()
if plot:
ds_id = plot.data_id
plot = pm.create_plot_by_ds_id(ds_id, PlotType.PLOT_DEFAULT_PLOT_FOR_DATA_ID)
if plot:
print(f"Plot created: {plot.name}")
# Inspect data display format
fmt = pm.get_data_display_format(plot.data_id)
print(f"Display format: {fmt}")
# Save result data as XML
ok = pm.save_result_data_in_xml(plot.data_id, "results.xml", SystemUnits.STANDARD)
print(f"Saved XML: {ok}")
Viewer Controls and Screenshot#
from moldflow import Synergy
from moldflow.common import ViewModes, StandardViews
synergy = Synergy()
viewer = synergy.viewer
viewer.reset()
viewer.set_view_mode(ViewModes.PERSPECTIVE_PROJECTION)
viewer.fit()
viewer.go_to_standard_view(StandardViews.ISOMETRIC)
viewer.save_image("C:\\temp\\snapshot.png", x=1920, y=1080, result=True, legend=True, axis=True)
Iterate Plots and Export Overlays#
from moldflow import Synergy
synergy = Synergy()
pm = synergy.plot_manager
viewer = synergy.viewer
plot = pm.get_first_plot()
while plot:
print(f"Plot: {plot.name}")
try:
viewer.save_plot_scale_image(f"C:\\temp\\{plot.name}_scale.png")
viewer.save_axis_image(f"C:\\temp\\{plot.name}_axis.png")
except Exception as e:
print(f"Overlay export not available: {e}")
plot = pm.get_next_plot(plot)
More Advanced Examples#
Derived results from existing plots (absolute temperature)#
from moldflow import Synergy
from moldflow.common import UserPlotType, TransformScalarOperations
synergy = Synergy()
pm = synergy.plot_manager
dt = synergy.data_transform
# Absolute temperature:K = Bulk temperature:13 + 273
ds_id = pm.find_dataset_id_by_name("Bulk temperature")
all_times = synergy.create_double_array()
pm.get_indp_values(ds_id, all_times)
target_time = 13.0
closest_time = min(all_times.to_list(), key=lambda t: abs(t - target_time))
indp = synergy.create_double_array()
indp.add_double(closest_time)
ent = synergy.create_integer_array()
vals = synergy.create_double_array()
pm.get_scalar_data(ds_id, indp, ent, vals)
dt.scalar(ent, vals, TransformScalarOperations.ADD, 273.0, ent, vals)
up = pm.create_user_plot()
up.set_name("Absolute Temperature")
up.set_data_type(UserPlotType.ELEMENT_DATA)
up.set_dept_unit_name("K")
up.set_scalar_data(ent, vals)
up.build()
Vector difference with absolute value#
from moldflow import Synergy
from moldflow.common import TransformOperations, TransformFunctions, UserPlotType
synergy = Synergy()
pm = synergy.plot_manager
dt = synergy.data_transform
name = "Average velocity" # 3-component vector
ds_id = pm.find_dataset_id_by_name(name)
times = synergy.create_double_array()
pm.get_indp_values(ds_id, times)
t1, t2 = 1.1, 2.0
c1 = min(times.to_list(), key=lambda t: abs(t - t1))
c2 = min(times.to_list(), key=lambda t: abs(t - t2))
def get_vec_at(t):
indp = synergy.create_double_array()
indp.add_double(t)
ent = synergy.create_integer_array()
vx = synergy.create_double_array()
vy = synergy.create_double_array()
vz = synergy.create_double_array()
pm.get_vector_data(ds_id, indp, ent, vx, vy, vz)
return ent, (vx, vy, vz)
ent1, (v1x, v1y, v1z) = get_vec_at(c1)
ent2, (v2x, v2y, v2z) = get_vec_at(c2)
vdx = synergy.create_double_array()
vdy = synergy.create_double_array()
vdz = synergy.create_double_array()
for a, b, out in [(v1x, v2x, vdx), (v1y, v2y, vdy), (v1z, v2z, vdz)]:
dt.op(ent1, a, TransformOperations.SUBTRACT, ent2, b, ent1, out)
dt.func(TransformFunctions.ABSOLUTE, ent1, out, ent1, out)
up = pm.create_user_plot()
up.set_name("Difference in Velocity")
up.set_data_type(UserPlotType.ELEMENT_DATA)
up.set_vector_as_displacement(False)
up.set_dept_unit_name("m/s")
up.set_vector_data(ent1, vdx, vdy, vdz)
up.build()
Operate on current plot#
from moldflow import Synergy
from moldflow.common import TransformFunctions, UserPlotType
synergy = Synergy()
pm = synergy.plot_manager
viewer = synergy.viewer
dt = synergy.data_transform
active = viewer.active_plot
if active is None:
raise RuntimeError("No active plot")
ds_id = active.data_id
cols = pm.get_data_nb_components(ds_id)
dtype = pm.get_data_type(ds_id)
times = synergy.create_double_array()
pm.get_indp_values(ds_id, times)
indp = None
if times.size > 0:
indp = synergy.create_double_array()
indp.add_double(times.to_list()[0])
ent = synergy.create_integer_array()
arrs = [synergy.create_double_array() for _ in range(max(cols, 1))]
if cols == 1:
pm.get_scalar_data(ds_id, indp, ent, arrs[0])
elif cols == 3:
pm.get_vector_data(ds_id, indp, ent, arrs[0], arrs[1], arrs[2])
elif cols == 6:
pm.get_tensor_data(ds_id, indp, ent, *arrs)
else:
raise RuntimeError("Unsupported component count")
for a in arrs[:cols]:
dt.func(TransformFunctions.ABSOLUTE, ent, a, ent, a)
up = pm.create_user_plot()
up.set_name("ABS of current plot")
up.set_data_type(UserPlotType.ELEMENT_DATA if dtype == "ELDT" else UserPlotType.NODE_DATA)
up.set_vector_as_displacement(dtype == "NDDT")
if cols == 1:
up.set_scalar_data(ent, arrs[0])
elif cols == 3:
up.set_vector_data(ent, arrs[0], arrs[1], arrs[2])
elif cols == 6:
up.set_tensor_data(ent, *arrs[:6])
up.build()
Normalize by max at a time#
from moldflow import Synergy
from moldflow.common import TransformScalarOperations, UserPlotType
synergy = Synergy()
pm = synergy.plot_manager
dt = synergy.data_transform
name = "Pressure"
ds_id = pm.find_dataset_id_by_name(name)
times = synergy.create_double_array()
pm.get_indp_values(ds_id, times)
target_time = 3.5
closest = min(times.to_list(), key=lambda t: abs(t - target_time))
indp = synergy.create_double_array()
indp.add_double(closest)
ent = synergy.create_integer_array()
vals = synergy.create_double_array()
pm.get_scalar_data(ds_id, indp, ent, vals)
max_v = max(vals.to_list())
out = synergy.create_double_array()
dt.scalar(ent, vals, TransformScalarOperations.DIVIDE, max_v, ent, out)
up = pm.create_user_plot()
up.set_name("Pre/Max")
up.set_data_type(UserPlotType.ELEMENT_DATA)
up.set_dept_unit_name("%")
up.set_scalar_data(ent, out)
up.build()
Average/min/max diagnostics to console#
from moldflow import Synergy
synergy = Synergy()
diag = synergy.diagnosis_manager
ent = synergy.create_integer_array()
vals = synergy.create_double_array()
count = diag.get_aspect_ratio_diagnosis(0.0, 0.0, True, False, ent, vals)
if count > 0:
data = vals.to_list()
ave = sum(data) / len(data)
print(f"Average aspect ratio: {ave:.3f}")
Entity selection strings#
from moldflow import Synergy
synergy = Synergy()
el = synergy.study_doc.create_entity_list()
el.select_from_string("N1:2 N5 N8:9")
print(el.size)
print(el.convert_to_string())
Configure Import Options Before CAD Import#
from moldflow import Synergy
from moldflow.common import MeshType, ImportUnits, MDLKernel
synergy = Synergy()
io = synergy.import_options # ImportOptions
# Set import preferences
io.mesh_type = MeshType.MESH_FUSION
io.units = ImportUnits.MM
io.use_mdl = True
io.mdl_kernel = MDLKernel.PARASOLID
io.mdl_mesh = True
io.mdl_surfaces = True
io.mdl_auto_edge_select = True
# Use with study import
study_doc = synergy.study_doc
ok = study_doc.add_file("C:\\models\\part.stp", io, show_logs=True)
print(f"Import success: {ok}")
Tune Plot Appearance and Export#
from moldflow import Synergy
synergy = Synergy()
pm = synergy.plot_manager
# Create or fetch a plot without hard-coded ids
plot = pm.get_first_plot()
if plot:
# Adjust plot attributes
plot.name = "Analysis Plot"
plot.number_of_frames = 30
plot.number_of_contours = 12
plot.mesh_fill = 0.35
# Regenerate and export results data as XML
plot.regenerate()
pm.save_result_data_in_xml(plot.data_id, "results.xml", "Metric")
Viewer: Animation, Clipping Planes, and Bookmarks#
from moldflow import Synergy
from moldflow.common import AnimationSpeed, StandardViews, ViewModes
synergy = Synergy()
viewer = synergy.viewer
# Camera setup
viewer.reset()
viewer.set_view_mode(ViewModes.PERSPECTIVE_PROJECTION)
viewer.fit()
viewer.go_to_standard_view(StandardViews.ISOMETRIC)
# Save a quick animation
viewer.save_animation("C:\\temp\\turntable.mp4", AnimationSpeed.MEDIUM, prompts=False)
# Create a default clipping plane (avoids needing an id)
viewer.create_default_clipping_plane()
# Create a bookmark for the current view (vectors can be None to use current state)
viewer.add_bookmark(
name="IsoView",
normal_view=None,
up_view=None,
focal_point=None,
eye_position=None,
clipping_range_min=0.0,
clipping_range_max=1.0,
view_angle=30.0,
parallel_scale=1.0,
)
API Coverage Examples#
Boundary Conditions#
from moldflow import Synergy
from moldflow.common import AnalysisType
synergy = Synergy()
bc = synergy.boundary_conditions
entity_list = synergy.study_doc.get_first_node()
# Create pin constraints for WARP
created = bc.create_pin_constraints(entity_list, AnalysisType.WARP)
print(f"Pin constraints created: {created}")
Circuit Generator#
from moldflow import Synergy
synergy = Synergy()
cg = synergy.circuit_generator
cg.diameter = 4.0
cg.distance = 3.0
cg.spacing = 12.0
cg.num_channels = 4
cg.delete_old = True
cg.use_hoses = True
ok = cg.generate()
print(f"Circuit generated: {ok}")
Data Transform#
from moldflow import Synergy
from moldflow.common import TransformScalarOperations
synergy = Synergy()
dt = synergy.data_transform
ia = synergy.create_integer_array()
ia.from_list([1, 2, 3])
da = synergy.create_double_array()
da.from_list([0.5, 1.5, 2.5])
ib = synergy.create_integer_array()
db = synergy.create_double_array()
ok = dt.scalar(ia, da, TransformScalarOperations.MULTIPLY, 2.0, ib, db)
print(f"Scalar transform ok: {ok}")
Folder Manager#
from moldflow import Synergy
synergy = Synergy()
fm = synergy.folder_manager
root = fm.create_entity_list()
fm.create_child_folder(root)
fm.create_child_layer(root)
first = fm.get_first()
while first:
print("Folder/Layer found")
first = fm.get_next(first)
Layer Manager#
from moldflow import Synergy
synergy = Synergy()
lm = synergy.layer_manager
lm.create_layer_by_name("MyLayer")
lyr = lm.get_first()
while lyr:
print("Layer found")
lyr = lm.get_next(lyr)
Material Selector#
from moldflow import Synergy
from moldflow.common import MaterialIndex
synergy = Synergy()
ms = synergy.material_selector
# Query current material file for first molding material
print(ms.get_material_file(MaterialIndex.FIRST))
Mesh Generator#
from moldflow import Synergy
synergy = Synergy()
mg = synergy.mesh_generator
mg.edge_length = 2.0
mg.merge_tolerance = 0.05
mg.match = True
ok = mg.generate()
print(f"Mesh generated: {ok}")
Model Duplicator#
from moldflow import Synergy
synergy = Synergy()
md = synergy.model_duplicator
md.num_cavities = 2
md.by_columns = True
md.num_cols = 2
md.num_rows = 1
md.x_spacing = 50.0
md.y_spacing = 40.0
ok = md.generate()
print(f"Model duplicated: {ok}")
Modeler#
from moldflow import Synergy
synergy = Synergy()
modeler = synergy.modeler
v = synergy.create_vector()
v.set_xyz(0.0, 0.0, 0.0)
node_list = modeler.create_node_by_xyz(v)
print("Created node list")
Mold Surface Generator#
from moldflow import Synergy
synergy = Synergy()
msg = synergy.mold_surface_generator
msg.centered = True
dim = synergy.create_vector()
dim.set_xyz(100.0, 80.0, 60.0)
msg.dimensions = dim
ok = msg.generate()
print(f"Mold surface generated: {ok}")
Predicate Manager#
from moldflow import Synergy
synergy = Synergy()
pmgr = synergy.predicate_manager
pmgr.create_thickness_predicate(0.5, 3.0)
print("Created thickness predicate")
Runner Generator#
from moldflow import Synergy
synergy = Synergy()
rg = synergy.runner_generator
rg.sprue_x = 0.0
rg.sprue_y = 0.0
rg.sprue_length = 30.0
rg.sprue_diameter = 6.0
rg.sprue_taper_angle = 2.0
ok = rg.generate()
print(f"Runner generated: {ok}")
Build PowerPoint Report (using python-pptx)#
This example emulates a report workflow directly from Python, using python-pptx to author a PPTX. See python-pptx on PyPI: https://pypi.org/project/python-pptx
import os
import tempfile
from moldflow import Synergy
from moldflow.common import StandardViews
# pip install python-pptx
from pptx import Presentation
from pptx.util import Inches, Pt
synergy = Synergy()
sd = synergy.study_doc
pm = synergy.plot_manager
viewer = synergy.viewer
project = synergy.project
# Ensure a visible viewport for captures
viewer.set_view_size(1600, 900)
# Result overlay flags
PLOT_RESULT = True
PLOT_LEGEND = True
PLOT_AXIS = True
PLOT_ROTATION = True
PLOT_SCALE_BAR = True
PLOT_PLOT_INFO = True
PLOT_STUDY_TITLE = True
PLOT_RULER = True
PLOT_LOGO = True
def capture_plot_image(plot, orientation: str | None, width_px=1600, height_px=900) -> str:
# Apply orientation and fit the view
if orientation and orientation.upper() != "CURRENT":
target = orientation.title() if isinstance(orientation, str) else orientation
viewer.go_to_standard_view(target)
# Show plot (if provided) or ensure geometry-only capture
if plot is not None:
viewer.show_plot(plot)
# Ensure plot is generated and a valid frame is visible
try:
plot.regenerate()
except Exception:
pass
try:
# Show the last frame if available
frames = viewer.get_number_frames_by_name(plot.name)
if isinstance(frames, int) and frames > 0:
viewer.show_plot_frame(plot, frames - 1)
except Exception:
pass
else:
# Hide any active plot to avoid empty result layer when capturing geometry
ap = viewer.active_plot
if ap is not None:
viewer.hide_plot(ap)
viewer.fit()
tmp = tempfile.NamedTemporaryFile(prefix="mf_plot_", suffix=".png", delete=False)
tmp.close()
# Use full overlay flags when capturing results; turn them off for geometry-only
if plot is not None:
viewer.save_image(
tmp.name,
x=width_px,
y=height_px,
result=PLOT_RESULT,
legend=PLOT_LEGEND,
axis=PLOT_AXIS,
rotation=PLOT_ROTATION,
scale_bar=PLOT_SCALE_BAR,
plot_info=PLOT_PLOT_INFO,
study_title=PLOT_STUDY_TITLE,
ruler=PLOT_RULER,
logo=PLOT_LOGO,
)
else:
viewer.save_image(tmp.name, x=width_px, y=height_px, result=False, legend=False, axis=False)
return tmp.name
prs = Presentation()
title_layout = prs.slide_layouts[0]
title_only_layout = prs.slide_layouts[5]
def add_title(slide, text: str):
if slide.shapes.title is not None:
slide.shapes.title.text = text
slide.shapes.title.text_frame.paragraphs[0].font.size = Pt(28)
def add_picture_centered(slide, image_path: str, max_width_in=10.0, top_in=1.5):
pic = slide.shapes.add_picture(image_path, Inches(0), Inches(top_in))
page_w = prs.slide_width
max_w = Inches(max_width_in)
if pic.width > max_w:
scale = max_w / pic.width
pic.width = int(pic.width * scale)
pic.height = int(pic.height * scale)
pic.left = int((page_w - pic.width) / 2)
return pic
slide = prs.slides.add_slide(title_layout)
add_title(slide, f"Report: {sd.study_name}")
if slide.placeholders and len(slide.placeholders) > 1:
slide.placeholders[1].text = f"Project: {project.path}"
geo_slide = prs.slides.add_slide(title_only_layout)
add_title(geo_slide, "Geometry Overview")
viewer.reset()
viewer.go_to_standard_view(StandardViews.ISOMETRIC)
viewer.fit()
geo_img = capture_plot_image(plot=None, orientation="CURRENT")
add_picture_centered(geo_slide, geo_img)
diag = synergy.diagnosis_manager
summary = diag.get_mesh_summary(element_only=False)
mesh_slide = prs.slides.add_slide(title_only_layout)
add_title(mesh_slide, "Mesh Summary")
tf = mesh_slide.shapes.add_textbox(Inches(1), Inches(1.5), Inches(8), Inches(3)).text_frame
tf.word_wrap = True
lines = [
f"Nodes: {summary.nodes_count}",
f"Triangles: {summary.triangles_count}",
f"Tetras: {summary.tetras_count}",
f"Beams: {summary.beams_count}",
f"AspectRatio avg/min/max: {summary.ave_aspect_ratio:.3f} / {summary.min_aspect_ratio:.3f} / {summary.max_aspect_ratio:.3f}",
]
for i, line in enumerate(lines):
p = tf.add_paragraph() if i else tf.paragraphs[0]
p.text = line
p.font.size = Pt(16)
def add_plot_slide(plot_obj, title: str, orientation: str = "ISOMETRIC"):
slide = prs.slides.add_slide(title_only_layout)
add_title(slide, title)
img = capture_plot_image(plot_obj, orientation)
if img:
add_picture_centered(slide, img)
try:
os.remove(img)
except Exception:
pass
else:
tx = slide.shapes.add_textbox(Inches(1), Inches(1.5), Inches(8), Inches(1.0)).text_frame
tx.text = "Skipped non-mesh/unsupported plot for 3D capture"
tx.paragraphs[0].font.size = Pt(14)
def add_plot_four_views(plot_obj, title: str):
slide = prs.slides.add_slide(title_only_layout)
add_title(slide, f"{title} - Four Views")
views = ["ISOMETRIC", "FRONT", "LEFT", "TOP"]
cols = 2
x0, y0 = Inches(0.7), Inches(1.3)
cell_w, cell_h = Inches(4.5), Inches(3.2)
for idx, v in enumerate(views):
img = capture_plot_image(plot_obj, v, width_px=1000, height_px=600)
col = idx % cols
row = idx // cols
left = x0 + col * (cell_w + Inches(0.2))
top = y0 + row * (cell_h + Inches(0.2))
if img:
pic = slide.shapes.add_picture(img, left, top)
if pic.width > cell_w:
scale = cell_w / pic.width
pic.width = int(pic.width * scale)
pic.height = int(pic.height * scale)
if pic.height > cell_h:
scale = cell_h / pic.height
pic.width = int(pic.width * scale)
pic.height = int(pic.height * scale)
try:
os.remove(img)
except Exception:
pass
plot = pm.get_first_plot()
count = 0
while plot:
name = plot.name
add_plot_slide(plot, name, orientation="ISOMETRIC")
if count < 2:
add_plot_four_views(plot, name)
plot = pm.get_next_plot(plot)
count += 1
out_path = os.path.join(project.path, f"{os.path.splitext(sd.study_name)[0]}_report.pptx")
prs.save(out_path)
print(f"Report saved: {out_path}")
Study Document#
from moldflow import Synergy
synergy = Synergy()
sd = synergy.study_doc
print(f"Study name: {sd.study_name}")
saved = sd.save()
print(f"Saved: {saved}")
System Messages#
from moldflow import Synergy
from moldflow.common import SystemUnits
synergy = Synergy()
sm = synergy.system_message
sa = synergy.create_string_array()
sa.from_list(["Diameter", "Length"])
da = synergy.create_double_array()
da.from_list([6.0, 30.0])
msg = sm.get_data_message(100, sa, da, SystemUnits.METRIC)
print(msg)
Arrays and Geometry Helpers#
from moldflow import Synergy
synergy = Synergy()
ia = synergy.create_integer_array()
ia.from_list([1, 2, 3])
print(ia.size)
da = synergy.create_double_array()
da.from_list([0.1, 0.2])
sa = synergy.create_string_array()
sa.from_list(["A", "B"])
vec = synergy.create_vector()
vec.set_xyz(1.0, 2.0, 3.0)
va = synergy.create_vector_array()
API Reference#
For detailed API documentation, see the API Reference section.
Development Setup#
If you’re interested in contributing to the project:
# Clone the repository
git clone https://github.com/Autodesk/moldflow-api.git
cd moldflow-api
# Install development dependencies
python -m pip install -r requirements.txt
# Run tests
python run.py test
# Run linting
python run.py lint
# Format code
python run.py format
Available Commands#
The project includes a run.py script with several useful commands:
python run.py build- Build the packagepython run.py test- Run testspython run.py lint- Run code lintingpython run.py format- Format code with blackpython run.py build-docs- Build documentation
Contributing#
We welcome contributions! Please see our Contributing Guide for details on how to contribute to this project.
Reporting Issues#
If you encounter any problems or have feature requests, please file an issue on our GitHub Issues page.
For security vulnerabilities, please see our Security Policy.
License#
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Links#
GitHub Repository: Autodesk/moldflow-api
PyPI Package: https://pypi.org/project/moldflow
Issue Tracker: Autodesk/moldflow-api#issues
Moldflow Synergy