How should I use the mapping workflow of DPF in Mechanical?

Options
Pierre Thieffry
Pierre Thieffry Member, Moderator, Employee Posts: 98
First Anniversary Ansys Employee Solution Developer Community of Practice Member Photogenic

I want to map some data onto a mesh using DPF's mapping workflow. How can I do this?

Answers

  • Pierre Thieffry
    Pierre Thieffry Member, Moderator, Employee Posts: 98
    First Anniversary Ansys Employee Solution Developer Community of Practice Member Photogenic
    Options

    Here's a sample code to use in a Python Code.

    To insert commands just prior to the ANSYS SOLVE command, use solver_input_file.WriteLine("!Your command")
    Global Helpers:
        this -- the datamodel object instance of the python code object you are currently editing in the tree
        solver_input_file  -- file stream that allows you to inject commands into the solver input file
        solver_data -- data stucture that allows you to access information from the model such as current step, contact pair ids, etc.
    """
    
    # To access properties created using the Property Provider, please use the following command.
    # this.GetCustomPropertyByPath("your_property_group_name/your_property_name")
    
    # To access scoping properties use the following to access geometry scoping and named selection respectively:
    # this.GetCustomPropertyByPath("your_property_group_name/your_property_name/Geometry Selection")
    # this.GetCustomPropertyByPath("your_property_group_name/your_property_name/Named Selection")
    import mech_dpf
    import Ans.DataProcessing as dpf
    import os
    
    def GetDpfMeshFromMechMesh(ExtAPI, BodyIds=None):
        """
        Get a DPF mesh region from a mechanical mesh
        Args:
            BodyIds (list of int) (optional): Ids for GeoBodies to get region
        Returns:
            dpf.MeshedRegion
        """
        MechMesh=ExtAPI.DataModel.MeshDataByName("Global")
        #Get the node ids
        if BodyIds!=None:
            NdIds=set()
            for Id in BodyIds:
                Region=MechMesh.MeshRegionById(Id)
                NdIds.update(Region.NodeIds)
        else:
            NdIds=set(MechMesh.NodeIds)
        #convet to elem. ids.
        ElIds=MechMesh.ElementIdsFromNodeIds(NdIds)
        #Convert to Dpf MeshRegion
        DpfMesh=dpf.MeshedRegion(0,0)
        NdIndexByIds={}
        i=0
        for NdId in NdIds:
            N=MechMesh.NodeById(NdId)
            NdIndexByIds[N.Id]=i
            DpfMesh.AddNode(N.Id, [N.X, N.Y, N.Z])
            i+=1
        for ElId in ElIds:
            E=MechMesh.ElementById(ElId)
            DpfMesh.AddSolidElement(E.Id,[NdIndexByIds[N.Id] for N in E.Nodes])
        return DpfMesh
    
    def readDataToMap(filename,scale_factor=1.):
        # Filename: file to read from. Assumes a tab separated file with
        # node_id X Y Z temperature and a first line to be ignored
        # Scale factor used to match mechanical mesh unit (m) and file contents unit
        with open(filename,'r') as f:
            lines=f.readlines()
    
        mapping_nodes=dpf.FieldsFactory.Create3DVectorField(len(lines)-1)
        mapping_field=dpf.FieldsFactory.CreateScalarField(len(lines)-1)
    
        idx=1
        for line in lines[1:]:
            line_sp=line.split('\t')
            coord=[float(line_sp[i])*scale_factor for i in range(1,4)]
            value=float(line_sp[4])
            mapping_nodes.Add(idx,coord)
            mapping_field.Add(idx,[value])
            idx+=1
    
        return mapping_nodes, mapping_field
    
    # Convert Mechanical mesh to DPF mesh
    mech_dpf.setExtAPI(ExtAPI)
    dpf_mesh = GetDpfMeshFromMechMesh(ExtAPI)
    
    # Get user_files folder
    proj_dir=ExtAPI.DataModel.Project.ProjectDirectory
    user_dir=os.path.join(proj_dir,'user_files')
    
    # Read data to map
    # Example file is in mm, so convert from mm to m
    mapping_file=os.path.join(user_dir,'ExtData_Temp_Valve.txt')
    source_nodes,source_field=readDataToMap(mapping_file,1e-3)
    
    # Define mapping workflow
    # This will prepare the mapping between the source points and the targets
    filter_radius=10e-3
    
    op = dpf.operators.mapping.prepare_mapping_workflow() # operator instantiation
    op.inputs.input_support.Connect(source_nodes)
    op.inputs.output_support.Connect(dpf_mesh)
    op.inputs.filter_radius.Connect(filter_radius)
    mapping_workflow = op.outputs.mapping_workflow.GetData()
    
    # Now we can map the data
    # THe workflow is reused multiple times for various
    # source fields (here the variation is a scaling of the source field, so mapping is done only once)
    
    
    mapping_workflow.Connect('source',source_field) #Connect field to be mapped
    
    mapped_field=mapping_workflow.GetOutputAsField('target') # extract mapped value
    
    field_data=mapped_field.Data
    nids=mapped_field.ScopingIds
    
    # Temperatures are scaled based on time step
    for i in range(len(nids)):
        cmd='bf,{0},temp,{1}'.format(nids[i],field_data[i]*(1+(solver_data.CurrentStep-1)*.1))
        solver_input_file.WriteLine(cmd)