If I wanted to extract the Centre of Mass of bodies I selected within a named selection to a CSV file, how would I be able to do this with Ansys Mechanical scripting?
import mech_dpf import Ans.DataProcessing as dpf import os def initialization(data_source): """ Initializes the workflow: sets up mesh scoping, computes center of mass at each timestep, and writes results to a CSV file. """ my_model = dpf.Model(data_source) my_mesh_og = my_model.Mesh # Get output file location file_loc = analysis1.WorkingDir file_name = "Nodal_Results.csv" file_path = os.path.join(file_loc, file_name) # Get all time steps time_list = dpf.operators.metadata.time_freq_provider( data_sources=data_source ).outputs.gettime_freq_support().TimeFreqs.Data # Mesh scoping for named selection named_selection_string = "MYBODY" ns_op = dpf.operators.scoping.on_named_selection( requested_location='Elemental', named_selection_name=named_selection_string, data_sources=data_source ) my_mesh_scoping = ns_op.outputs.getmesh_scoping() # Scope mesh to named selection mesh_op = dpf.operators.mesh.from_scoping() mesh_op.inputs.scoping.Connect(my_mesh_scoping) mesh_op.inputs.mesh.Connect(my_mesh_og) my_mesh = mesh_op.outputs.mesh.GetData() # Prepare for COM calculation com_data = [] origin_run = True # Get displacement fields for all time steps displacement_op = dpf.operators.result.displacement( time_scoping=time_list, data_sources=data_source ) fields_container = displacement_op.outputs.fields_container.GetData() # Loop through time steps and compute COM for i, time_point in enumerate(time_list): time_index = int(time_list.IndexOf(time_point)) if origin_run: origin = list(COM(time_index, my_mesh, fields_container, origin_run)) origin.insert(0, 0) origin_run = False else: current = COM(time_index, my_mesh, fields_container, origin_run) current.insert(0, time_list[i-1]) current.append(origin[1] - current[1]) current.append(origin[2] - current[2]) current.append(origin[3] - current[3]) com_data.append(current) # Prepare headers and data headers = ["Time", "X", "Y", "Z", "UALLX", "UALLY", "UALLZ"] data = [ ["", "X", "Y", "Z"], origin, ["", "", "", ""], headers, ] file_write(data, com_data, file_path) def COM(time_index, mesh, fields_container, origin_run): """ Computes the center of mass (COM) for a given time index and mesh. If origin_run is True, uses the undeformed mesh; otherwise, applies displacement. Returns [centroid_x, centroid_y, centroid_z]. """ # Create a new mesh region for this time step created_mesh = dpf.MeshedRegion(mesh.Nodes.Count, 0) # Add nodes: displaced for deformed, original for undeformed for node in mesh.Nodes: if origin_run: coords = [node.X, node.Y, node.Z] else: displacement = fields_container[time_index].GetEntityDataById(node.Id) coords = [node.X + displacement[0], node.Y + displacement[1], node.Z + displacement[2]] created_mesh.AddNode(node.Id, coords) # Add elements to new mesh, mapping node indices appropriately createdmesh_nodeids = created_mesh.NodeIds for elem in mesh.Elements: # Map each corner node ID to index in the new mesh try: node_indices = [createdmesh_nodeids.IndexOf(nid) for nid in elem.CornerNodeIds] except Exception: # Fallback: if IndexOf not available, use .index node_indices = [createdmesh_nodeids.index(nid) for nid in elem.CornerNodeIds] created_mesh.AddSolidElement(elem.Id, node_indices) # Calculate element centroids centroids_op = dpf.Operator("compute_element_centroids") centroids_op.Connect(7, created_mesh) centroid_field = centroids_op.GetOutputAsField(0) # Compute elemental mass (using original mesh for density mapping) elemental_mass = compute_elemental_mass(mesh) # Return the mass-weighted centroid as a list [x, y, z] return calculate_mass_weighted_centroid(centroid_field, elemental_mass)
###Continued Here due to Character limit ### def compute_elemental_mass(mesh): """ Compute the elemental mass for each element in the mesh: mass = density * volume Returns a field with the mass for each element. """ # Get material property field from mesh mats = mesh.GetPropertyField("mat") #my_model = mesh.Model # Ensure model is available from mesh # Obtain material densities mat_prop_op = my_model.CreateOperator("mapdl_material_properties") mat_prop_op.inputs.materials.Connect(mats) mat_prop_op.inputs.properties_name.Connect("DENS") mat_field = mat_prop_op.outputs.properties_value.GetData()[0] # Map element ID to its material density densities = [] for eid in mesh.ElementIds: mat_id = mats.GetEntityDataById(eid) density = mat_field.GetEntityDataById(mat_id[0]) densities.append(density[0]) # Build a density field for all elements density_field = dpf.FieldsFactory.CreateScalarField( numEntities=mesh.ElementCount, location=dpf.locations.elemental ) density_field.ScopingIds = mesh.ElementIds density_field.Data = densities # Compute element volumes el_vol = dpf.operators.geo.elements_volume(mesh=mesh) # Elemental mass = density * volume (field-wise multiplication) elemental_mass = dpf.operators.math.generalized_inner_product( fieldA=el_vol, fieldB=density_field ).outputs.getfield() return elemental_mass ###########eror for mesh scoping bit######## def calculate_mass_weighted_centroid(centroid_field, mass_field): """ Calculate the mass-weighted centroid from centroid and mass fields. Returns [centroid_x, centroid_y, centroid_z]. """ # Extract x, y, z components from centroid field x_comp = dpf.operators.logic.component_selector(field=centroid_field, component_number=0).outputs.getfield().Data y_comp = dpf.operators.logic.component_selector(field=centroid_field, component_number=1).outputs.getfield().Data z_comp = dpf.operators.logic.component_selector(field=centroid_field, component_number=2).outputs.getfield().Data mass = mass_field.Data # Calculate total mass and weighted sums sum_mass = sum(mass) if sum_mass <= 0: raise ValueError("Total mass is zero or negative") centroid_x = sum(x * m for x, m in zip(x_comp, mass)) / sum_mass centroid_y = sum(y * m for y, m in zip(y_comp, mass)) / sum_mass centroid_z = sum(z * m for z, m in zip(z_comp, mass)) / sum_mass return [centroid_x, centroid_y, centroid_z] def file_write(data, com_data, file_path): """ Append the computed center of mass (com_data) to the initial data, then write everything to a CSV file at file_path. """ # Add computed COM rows to the data structure for row in com_data: data.append(row) # Write the data as CSV with open(file_path, 'w') as f: for row in data: # Convert all items to string and join with commas line = ','.join(str(item) for item in row) f.write(line + '\n') print("Done writing results") resultObject = Tree.FirstActiveObject for i in range(5): if resultObject.ToString() == "Ansys.ACT.Automation.Mechanical.Analysis": break else: try: resultObject = resultObject.Parent except: ExtAPI.Application.Messages.Add(Ansys.Mechanical.Application.Message('Please Ensure you are on the correct tree Object', MessageSeverityType.Warning)) if resultObject.ToString() == "Ansys.ACT.Automation.Mechanical.Analysis": analysis1 = resultObject #try: dataSource = dpf.DataSources(analysis1.Solution.ResultFilePath) my_model = dpf.Model(dataSource) my_mesh_og = my_model.Mesh initialization(dataSource) #except: # ExtAPI.Application.Messages.Add(Ansys.Mechanical.Application.Message('Please Ensure you are on the correct tree Object', MessageSeverityType.Warning))
Using this code will allow for the extraction of the COM to a CSV file within the working directory to all bodies within the named selection "MYBODY"