FEM Operations
FEM Operations Tutorial.
This tutorial demonstrates Finite Element Model (FEM) operations including creating materials, parts, node sets, element sets, surfaces, visualization, and exporting to various solver formats (Abaqus, Nastran, LS-DYNA, OpenFOAM, Fluent, Gmsh).
Prerequisites
- Volvicon application must be running
- A volume mesh must exist in the project (create one using SurfaceOperations.convert_to_volume_mesh()
Listing Volume Meshes​
all_volume_meshes = app.get_all_volume_mesh_names()
print(f"Available volume meshes: {all_volume_meshes}")
# Select a volume mesh to work with
# volume_mesh_name = all_volume_meshes[0] if all_volume_meshes else None
# For this tutorial, you need to import or have a volume mesh first
# Example: Import a volume mesh
# VolumeMeshOperations = app.get_volume_mesh_operations()
# volume_mesh_name = VolumeMeshOperations.import_volume_mesh_from_disk(r'C:\data\mesh.vtu')
Creating and Managing FEM Models​
# if volume_mesh_name:
# # Create FEM model (initializes FEM data on the volume mesh)
# success = FemOperations.create_fem_model(volume_mesh_name)
# print(f"FEM model created: {success}")
#
# # Check if volume mesh has FEM model
# has_fem = FemOperations.has_fem_model(volume_mesh_name)
# print(f"Has FEM model: {has_fem}")
#
# # Get model statistics
# stats = FemOperations.get_model_statistics(volume_mesh_name)
# print(f"Model statistics:")
# print(f" Nodes: {stats.node_count}")
# print(f" Elements: {stats.element_count}")
# print(f" Materials: {stats.material_count}")
# print(f" Parts: {stats.part_count}")
# print(f" Node sets: {stats.node_set_count}")
# print(f" Element sets: {stats.element_set_count}")
# print(f" Surfaces: {stats.surface_count}")
#
# # Clear all FEM data (preserves nodes/elements, removes materials/parts/sets)
# # FemOperations.clear_fem_data(volume_mesh_name)
Creating Materials​
# if volume_mesh_name:
# # Method 1: Create material from preset (easiest)
# steel_name = FemOperations.add_material_from_preset(
# volume_mesh_name,
# api.FemMaterialPreset.Steel,
# "StructuralSteel" # Custom name (optional)
# )
# print(f"Created steel material: {steel_name}")
#
# # Available presets: Steel, Aluminum, Titanium, Copper, Plastic, Rubber,
# # Concrete, CorticalBone, TrabecularBone, SoftTissue, Cartilage
#
# aluminum_name = FemOperations.add_material_from_preset(
# volume_mesh_name,
# api.FemMaterialPreset.Aluminum,
# "AluminumAlloy"
# )
#
# # Method 2: Create custom material with full parameter control
# # Setup mechanical properties
# mech_props = api.FemMechanicalProperties()
# mech_props.youngs_modulus = 210.0e9 # 210 GPa (Pa)
# mech_props.poissons_ratio = 0.28
# mech_props.yield_stress = 250.0e6 # 250 MPa (Pa)
#
# # Setup thermal properties
# thermal_props = api.FemThermalProperties()
# thermal_props.thermal_conductivity = 52.0 # W/(m·K)
# thermal_props.specific_heat = 460.0 # J/(kg·K)
# thermal_props.thermal_expansion = 11.5e-6 # 1/K
#
# # Create material parameters
# mat_params = api.FemMaterialParams()
# mat_params.name = "CustomSteel"
# mat_params.model = api.FemMaterialModel.Elastic # Elastic, Plastic, Hyperelastic, etc.
# mat_params.density = 7850.0 # kg/m³
# mat_params.color = [0.7, 0.7, 0.7, 1.0] # RGBA (0.0-1.0)
# mat_params.mechanical = mech_props
# mat_params.thermal = thermal_props
#
# custom_mat_name = FemOperations.add_material(volume_mesh_name, mat_params)
# print(f"Created custom material: {custom_mat_name}")
#
# # Update material properties
# mat_params.name = "CustomSteel"
# mat_params.mechanical.youngs_modulus = 215.0e9 # Update modulus
# FemOperations.update_material(volume_mesh_name, "CustomSteel", mat_params)
#
# # Get all materials
# all_materials = FemOperations.get_materials(volume_mesh_name)
# print(f"All materials: {[m.name for m in all_materials]}")
#
# # Get specific material by name
# mat_info = FemOperations.get_material_by_name(volume_mesh_name, "StructuralSteel")
# if mat_info.name:
# print(f"Material: {mat_info.name}")
# print(f" Density: {mat_info.density} kg/m³")
# print(f" Young's modulus: {mat_info.youngs_modulus / 1e9:.1f} GPa")
# print(f" Poisson's ratio: {mat_info.poissons_ratio}")
#
# # Remove a material
# # FemOperations.remove_material(volume_mesh_name, "CustomSteel")
Creating Parts​
# if volume_mesh_name:
# # Method 1: Create a part with solid section
# solid_section = api.FemSolidSectionParams()
# solid_section.integration = api.FemIntegrationScheme.Full # Full, Reduced, etc.
# solid_section.integrationPoints = 8
#
# part_params = api.FemPartParams()
# part_params.name = "MainBody"
# part_params.material_name = "StructuralSteel" # Assign material
# part_params.section_type = api.FemSectionType.Solid
# part_params.display_color = [0.8, 0.2, 0.2, 1.0] # Red RGBA
# part_params.solid_section = solid_section
# part_params.description = "Main structural body"
#
# part_name = FemOperations.create_part(volume_mesh_name, part_params)
# print(f"Created part: {part_name}")
#
# # Method 2: Create a part with shell section (for surface meshes)
# shell_section = api.FemShellSectionParams()
# shell_section.thickness = 2.0 # mm
# shell_section.num_integration_points = 5
# shell_section.integration = api.FemIntegrationScheme.Reduced
#
# shell_params = api.FemPartParams()
# shell_params.name = "Cover"
# shell_params.material_name = "AluminumAlloy"
# shell_params.section_type = api.FemSectionType.Shell
# shell_params.shell_section = shell_section
#
# # shell_part = FemOperations.create_part(volume_mesh_name, shell_params)
#
# # Assign elements to a part (element IDs are 1-based)
# # element_ids = [1, 2, 3, 4, 5, 10, 11, 12]
# # FemOperations.assign_elements_to_part(volume_mesh_name, "MainBody", element_ids)
#
# # Assign or change material for a part
# # FemOperations.assign_material_to_part(volume_mesh_name, "MainBody", "AluminumAlloy")
#
# # Update part properties
# # part_params.name = "MainBody"
# # part_params.display_color = [0.2, 0.8, 0.2, 1.0] # Change to green
# # FemOperations.update_part(volume_mesh_name, "MainBody", part_params)
#
# # Get all parts
# all_parts = FemOperations.get_parts(volume_mesh_name)
# print(f"All parts: {[p.name for p in all_parts]}")
#
# # Get specific part by name
# part_info = FemOperations.get_part_by_name(volume_mesh_name, "MainBody")
# if part_info.name:
# print(f"Part: {part_info.name}")
# print(f" Material: {part_info.material_name}")
# print(f" Section type: {part_info.section_type}")
# print(f" Num elements: {part_info.num_elements}")
#
# # Remove a part
# # FemOperations.remove_part(volume_mesh_name, "Cover")
Creating Node Sets​
# if volume_mesh_name:
# # Method 1: Create node set manually with specific node IDs
# nodeset_params = api.FemNodeSetParams()
# nodeset_params.name = "FixedNodes"
# nodeset_params.node_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # Node IDs (1-based)
# nodeset_params.source = api.FemSetSource.Manual
# nodeset_params.description = "Nodes for fixed boundary condition"
#
# success = FemOperations.create_node_set(volume_mesh_name, nodeset_params)
# print(f"Node set created: {success}")
#
# # Method 2: Create node set from ROI primitive
# # First create an ROI primitive in Volvicon (box, sphere, cylinder, etc.)
# # Then use it to automatically select nodes
# # success = FemOperations.create_node_set_from_roi(
# # volume_mesh_name,
# # "BoxPrimitive", # Name of the ROI primitive
# # "ROI_FixedNodes" # Name for the new node set
# # )
#
# # Add more nodes to an existing set
# # additional_nodes = [11, 12, 13, 14, 15]
# # FemOperations.add_nodes_to_set(volume_mesh_name, "FixedNodes", additional_nodes)
#
# # Remove nodes from a set
# # nodes_to_remove = [9, 10]
# # FemOperations.remove_nodes_from_set(volume_mesh_name, "FixedNodes", nodes_to_remove)
#
# # Rename a node set
# # FemOperations.rename_node_set(volume_mesh_name, "FixedNodes", "BoundaryNodes")
#
# # Get all node sets
# all_node_sets = FemOperations.get_node_sets(volume_mesh_name)
# print(f"All node sets: {[ns.name for ns in all_node_sets]}")
#
# # Get specific node set by name
# nodeset_info = FemOperations.get_node_set_by_name(volume_mesh_name, "FixedNodes")
# if nodeset_info.name:
# print(f"Node set: {nodeset_info.name}")
# print(f" Num nodes: {nodeset_info.node_count}")
# print(f" Source: {nodeset_info.source}")
#
# # Get node IDs in a set
# node_ids = FemOperations.get_node_set_node_ids(volume_mesh_name, "FixedNodes")
# print(f"Node IDs in 'FixedNodes': {node_ids[:5]}... (showing first 5)")
#
# # Remove a node set
# # FemOperations.remove_node_set(volume_mesh_name, "FixedNodes")
Creating Element Sets​
# if volume_mesh_name:
# # Method 1: Create element set manually with specific element IDs
# elemset_params = api.FemElementSetParams()
# elemset_params.name = "CoreElements"
# elemset_params.element_ids = [1, 2, 3, 4, 5, 10, 11, 12, 20, 21] # Element IDs (1-based)
# elemset_params.source = api.FemSetSource.Manual
# elemset_params.description = "Core region elements"
#
# success = FemOperations.create_element_set(volume_mesh_name, elemset_params)
# print(f"Element set created: {success}")
#
# # Method 2: Create element set from ROI primitive
# # Elements are selected if their centroid is inside the ROI
# # success = FemOperations.create_element_set_from_roi(
# # volume_mesh_name,
# # "SpherePrimitive", # Name of the ROI primitive
# # "ROI_CoreElements" # Name for the new element set
# # )
#
# # Add more elements to an existing set
# # additional_elements = [22, 23, 24, 25]
# # FemOperations.add_elements_to_set(volume_mesh_name, "CoreElements", additional_elements)
#
# # Remove elements from a set
# # elements_to_remove = [20, 21]
# # FemOperations.remove_elements_from_set(volume_mesh_name, "CoreElements", elements_to_remove)
#
# # Rename an element set
# # FemOperations.rename_element_set(volume_mesh_name, "CoreElements", "CentralElements")
#
# # Get all element sets
# all_element_sets = FemOperations.get_element_sets(volume_mesh_name)
# print(f"All element sets: {[es.name for es in all_element_sets]}")
#
# # Get specific element set by name
# elemset_info = FemOperations.get_element_set_by_name(volume_mesh_name, "CoreElements")
# if elemset_info.name:
# print(f"Element set: {elemset_info.name}")
# print(f" Num elements: {elemset_info.element_count}")
# print(f" Source: {elemset_info.source}")
#
# # Get element IDs in a set
# element_ids = FemOperations.get_element_set_element_ids(volume_mesh_name, "CoreElements")
# print(f"Element IDs in 'CoreElements': {element_ids[:5]}... (showing first 5)")
#
# # Create a part from element set
# # part_name = FemOperations.create_part_from_element_set(
# # volume_mesh_name,
# # "CoreElements", # Element set name
# # "CorePart", # New part name
# # "StructuralSteel" # Material to assign
# # )
#
# # Remove an element set
# # FemOperations.remove_element_set(volume_mesh_name, "CoreElements")
Creating Surfaces​
# if volume_mesh_name:
# # Method 1: Automatically detect boundary surfaces (external faces)
# success = FemOperations.detect_boundary_surfaces(
# volume_mesh_name,
# "ExternalBoundary" # Name for the boundary surface
# )
# print(f"Boundary surfaces detected: {success}")
#
# # Method 2: Create surface from element set boundary
# # Creates a surface from the external faces of elements in the set
# # success = FemOperations.create_surface_from_element_set(
# # volume_mesh_name,
# # "CoreElements", # Element set name
# # "CoreBoundary" # Surface name
# # )
#
# # Method 3: Create surface manually
# surface_params = api.FemSurfaceParams()
# surface_params.name = "LoadSurface"
# surface_params.type = api.FemSurfaceType.LoadApplication # External, Internal, Contact, etc.
# surface_params.source = api.FemSetSource.Manual
# surface_params.description = "Surface for load application"
#
# # success = FemOperations.create_surface(volume_mesh_name, surface_params)
#
# # Rename a surface
# # FemOperations.rename_surface(volume_mesh_name, "LoadSurface", "PressureSurface")
#
# # Get all surfaces
# all_surfaces = FemOperations.get_surfaces(volume_mesh_name)
# print(f"All surfaces: {[s.name for s in all_surfaces]}")
#
# # Get specific surface by name
# surface_info = FemOperations.get_surface_by_name(volume_mesh_name, "ExternalBoundary")
# if surface_info.name:
# print(f"Surface: {surface_info.name}")
# print(f" Type: {surface_info.type}")
# print(f" Num faces: {surface_info.face_count}")
#
# # Remove a surface
# # FemOperations.remove_surface(volume_mesh_name, "LoadingSurface")
Creating Sets from ROI Primitives (Batch Operation)​
# if volume_mesh_name:
# # Create node sets, element sets, and surfaces from ALL visible ROI primitives
# # This is a convenient batch operation for creating multiple sets at once
# success = FemOperations.create_sets_from_visible_roi(
# volume_mesh_name,
# "ROI_Nodes", # Prefix for node sets (e.g., "ROI_Nodes_Box1")
# "ROI_Elements" # Prefix for element sets (e.g., "ROI_Elements_Box1")
# )
# print(f"Sets created from visible ROIs: {success}")
Visualizing FEM Entities​
# if volume_mesh_name:
# # Show node sets in 3D view (displays as colored points)
# FemOperations.show_node_sets(
# volume_mesh_name,
# ["FixedNodes"], # List of node set names (empty list = show all)
# True # visible=True to show, False to hide
# )
#
# # Show element sets in 3D view (displays as colored semi-transparent cells)
# FemOperations.show_element_sets(
# volume_mesh_name,
# ["CoreElements"], # List of element set names (empty list = show all)
# True
# )
#
# # Show surfaces in 3D view (displays boundary surfaces)
# FemOperations.show_surfaces(
# volume_mesh_name,
# ["ExternalBoundary"], # List of surface names (empty list = show all)
# True
# )
#
# # Show parts in 3D view (displays with material colors)
# FemOperations.show_parts(
# volume_mesh_name,
# ["MainBody"], # List of part names (empty list = show all)
# True
# )
#
# # Show all entities
# # FemOperations.show_node_sets(volume_mesh_name, [], True) # Show all node sets
# # FemOperations.show_element_sets(volume_mesh_name, [], True) # Show all element sets
# # FemOperations.show_surfaces(volume_mesh_name, [], True) # Show all surfaces
# # FemOperations.show_parts(volume_mesh_name, [], True) # Show all parts
#
# # Hide specific entities
# # FemOperations.show_node_sets(volume_mesh_name, ["FixedNodes"], False)
#
# # Clear all FEM visualizations
# # FemOperations.clear_all_fem_visualizations()
Exporting to Abaqus Format (.inp)​
# if volume_mesh_name:
# # Setup common export options
# common_opts = api.FemExportOptions()
# common_opts.model_name = "MyFEMModel"
# common_opts.coordinate_precision = 8
# common_opts.use_scientific_notation = True
# common_opts.include_comments = True
# common_opts.export_materials = True
# common_opts.export_sets = True
# common_opts.export_surfaces = True
# common_opts.renumber_ids = False # Keep original IDs
#
# # Setup Abaqus-specific options
# abaqus_opts = api.FemAbaqusExportOptions()
# abaqus_opts.common = common_opts
# abaqus_opts.write_assembly = True
# abaqus_opts.write_history_output = True
# abaqus_opts.analysis_type = "Static" # Static, Dynamic, Frequency, etc.
#
# # Export to Abaqus
# result = FemOperations.export_to_abaqus(
# volume_mesh_name,
# r'C:\output\model.inp',
# abaqus_opts
# )
#
# # Check export result
# if result.success:
# print(f"Abaqus export successful!")
# print(f" Nodes exported: {result.nodes_written}")
# print(f" Elements exported: {result.elements_written}")
# print(f" Materials exported: {result.materials_written}")
# print(f" Sets exported: {result.sets_written}")
# print(f" Export time: {result.elapsed_seconds:.2f} seconds")
# else:
# print(f"Abaqus export failed: {result.error_message}")
Exporting to Nastran Format (.nas, .bdf)​
# if volume_mesh_name:
# # Setup Nastran-specific options
# nastran_opts = api.FemNastranExportOptions()
# nastran_opts.common = common_opts
# nastran_opts.field_format = "Long" # "Short" (8 chars), "Long" (16 chars), "Free"
# nastran_opts.write_executive_control = True
# nastran_opts.export_node_sets_as_spc = False # Export node sets as SPC cards
#
# # Export to Nastran
# result = FemOperations.export_to_nastran(
# volume_mesh_name,
# r'C:\output\model.nas',
# nastran_opts
# )
#
# if result.success:
# print(f"Nastran export successful!")
Exporting to LS-DYNA Format (.k, .dyn)​
# if volume_mesh_name:
# # Setup LS-DYNA-specific options
# lsdyna_opts = api.FemLsDynaExportOptions()
# lsdyna_opts.common = common_opts
# lsdyna_opts.solid_formulation = 1 # 1=default, 2=selective reduced
# lsdyna_opts.write_control_cards = True
# lsdyna_opts.termination_time = 1.0 # Simulation end time
#
# # Export to LS-DYNA
# result = FemOperations.export_to_ls_dyna(
# volume_mesh_name,
# r'C:\output\model.k',
# lsdyna_opts
# )
#
# if result.success:
# print(f"LS-DYNA export successful!")
Exporting to OpenFOAM Format (polyMesh)​
# if volume_mesh_name:
# # Setup OpenFOAM-specific options
# openfoam_opts = api.FemOpenFOAMExportOptions()
# openfoam_opts.common = common_opts
# openfoam_opts.create_case_structure = True # Create full case directory
# openfoam_opts.write_cell_zones = True # Write cellZones for parts
# openfoam_opts.case_name = "myCase"
#
# # Export to OpenFOAM
# result = FemOperations.export_to_open_foam(
# volume_mesh_name,
# r'C:\output\openfoam_case', # Directory path
# openfoam_opts
# )
#
# if result.success:
# print(f"OpenFOAM export successful!")
# print(f" Case directory created at: C:\\output\\openfoam_case")
Exporting to Fluent Format (.msh)​
# if volume_mesh_name:
# # Setup Fluent-specific options
# fluent_opts = api.FemFluentExportOptions()
# fluent_opts.common = common_opts
# fluent_opts.default_boundary_type = "wall" # wall, inlet, outlet, etc.
# fluent_opts.default_cell_type = "fluid" # fluid or solid
# fluent_opts.write_comments = True
#
# # Export to Fluent
# result = FemOperations.export_to_fluent(
# volume_mesh_name,
# r'C:\output\model.msh',
# fluent_opts
# )
#
# if result.success:
# print(f"Fluent export successful!")
Exporting to Gmsh Format (.msh)​
# if volume_mesh_name:
# # Setup Gmsh-specific options
# gmsh_opts = api.FemGmshExportOptions()
# gmsh_opts.common = common_opts
#
# # Export to Gmsh
# result = FemOperations.export_to_gmsh(
# volume_mesh_name,
# r'C:\output\model.msh',
# gmsh_opts
# )
#
# if result.success:
# print(f"Gmsh export successful!")
Generic Export (Specify Format at Runtime)​
# if volume_mesh_name:
# # Export using generic method with format selection
# result = FemOperations.export_to_format(
# volume_mesh_name,
# r'C:\output\model.inp',
# api.FemExportFormat.Abaqus, # Abaqus, Nastran, LSDYNA, OpenFOAM, Fluent, Gmsh
# common_opts
# )
#
# if result.success:
# print(f"Generic export to {api.FemExportFormat.Abaqus} successful!")
Complete Workflow Example​
# Complete workflow from volume mesh to Abaqus export:
#
# if volume_mesh_name:
# # 1. Create FEM model
# FemOperations.create_fem_model(volume_mesh_name)
#
# # 2. Add materials
# steel = FemOperations.add_material_from_preset(volume_mesh_name, api.FemMaterialPreset.Steel, "Steel")
# aluminum = FemOperations.add_material_from_preset(volume_mesh_name, api.FemMaterialPreset.Aluminum, "Aluminum")
#
# # 3. Create parts
# part_params = api.FemPartParams()
# part_params.name = "Body"
# part_params.material_name = "Steel"
# part_params.section_type = api.FemSectionType.Solid
# FemOperations.create_part(volume_mesh_name, part_params)
#
# # 4. Detect boundary surfaces
# FemOperations.detect_boundary_surfaces(volume_mesh_name, "Boundary")
#
# # 5. Create node sets for boundary conditions (using ROI if available)
# # FemOperations.create_node_set_from_roi(volume_mesh_name, "FixedRegion_ROI", "FixedNodes")
# # FemOperations.create_node_set_from_roi(volume_mesh_name, "LoadRegion_ROI", "LoadNodes")
#
# # 6. Visualize
# FemOperations.show_parts(volume_mesh_name, [], True) # Show all parts
# FemOperations.show_surfaces(volume_mesh_name, [], True) # Show all surfaces
# # FemOperations.show_node_sets(volume_mesh_name, [], True) # Show all node sets
#
# # 7. Export to Abaqus
# common_opts = api.FemExportOptions()
# common_opts.model_name = "MyModel"
# abaqus_opts = api.FemAbaqusExportOptions()
# abaqus_opts.common = common_opts
#
# result = FemOperations.export_to_abaqus(volume_mesh_name, r'C:\output\model.inp', abaqus_opts)
# if result.success:
# print("Complete FEM workflow finished successfully!")
# else:
# print(f"Export failed: {result.error_message}")
print("FEM operations tutorial completed successfully.")
print("")
print("To use this tutorial:")
print("1. Import or create a volume mesh first")
print("2. Uncomment the sections you want to test")
print("3. Adjust file paths and names as needed")
print("4. Run the script from Volvicon's Python console")
Related Resources​
- API Reference - API documentation
- Quick Reference - Common methods at a glance