diff --git a/src/Mod/Fem/femmesh/meshtools.py b/src/Mod/Fem/femmesh/meshtools.py index 7d6d59af38..dc178f81cb 100644 --- a/src/Mod/Fem/femmesh/meshtools.py +++ b/src/Mod/Fem/femmesh/meshtools.py @@ -1640,6 +1640,100 @@ def get_pressure_obj_faces_depreciated( return pressure_faces +# ***** contact faces **************************************************************************** +def get_contact_obj_faces( + femmesh, + femelement_table, + femnodes_ele_table, + femobj +): + # see comment on get_pressure_obj_faces_depreciated in the regard of getccxVolumesByFace() + + # sets are needed for each of the references separated + # BTW constraint tie works the same way AFAIK + # TODO it might be useful to introduce a Reference_master and Reference_slave attribute + + # groups makes no sense, since group would be needed for each contact face (master and slave) + + # slave is DEP1 and master is IND1 in input file + # first element face or ref_shape is slave, second is master + + # TODO above pre check in ccxtools + # TODO ref_shape_type should be Face + + slave_faces, master_faces = [], [] + + contact_obj = femobj["Object"] + if len(contact_obj.References) == 1 and len(contact_obj.References[0][1]) == 2: + # [(, ('Face7', 'Face3'))] + # refs are merged because they are on the same doc obj + # but only one element face for each contact face (Gui, TaskPael contact) + ref_obj = contact_obj.References[0][0] + ref_ele = contact_obj.References[0][1] + slave_ref = (ref_obj, (ref_ele[0],)) # the comma is needed! + master_ref = (ref_obj, (ref_ele[1],)) # the comma is needed! + elif ( + len(contact_obj.References) == 2 + and len(contact_obj.References[0][1]) == 1 + and len(contact_obj.References[1][1]) == 1 + ): + # [(, ('Face3',)), (, ('Face7',))] + # refs are on different objects + # but only one element face for each contact face (Gui, TaskPael contact) + slave_ref = contact_obj.References[0] + master_ref = contact_obj.References[1] + else: + FreeCAD.Console.PrintError( + "Not valid (example: only master or slave defined) " + "or not supported reference shape elements, contact face combination " + "(example: multiple element faces per master or slave\n" + ) + + FreeCAD.Console.PrintLog("Slave: {}, {}\n".format(slave_ref[0].Name, slave_ref)) + FreeCAD.Console.PrintLog("Master: {}, {}\n".format(master_ref[0].Name, master_ref)) + + if is_solid_femmesh(femmesh): + # get the nodes, sorted and duplicates removed + slaveface_nds = sorted(list(set(get_femnodes_by_refshape(femmesh, slave_ref)))) + masterface_nds = sorted(list(set(get_femnodes_by_refshape(femmesh, master_ref)))) + # FreeCAD.Console.PrintLog("slaveface_nds: {}\n".format(slaveface_nds)) + # FreeCAD.Console.PrintLog("masterface_nds: {}\n".format(slaveface_nds)) + + # fill the bit_pattern_dict and search for the faces + slave_bit_pattern_dict = get_bit_pattern_dict( + femelement_table, + femnodes_ele_table, + slaveface_nds + ) + master_bit_pattern_dict = get_bit_pattern_dict( + femelement_table, + femnodes_ele_table, + masterface_nds + ) + + # get the faces ids + slave_faces = get_ccxelement_faces_from_binary_search(slave_bit_pattern_dict) + master_faces = get_ccxelement_faces_from_binary_search(master_bit_pattern_dict) + + elif is_face_femmesh(femmesh): + slave_ref_shape = slave_ref[0].Shape.getElement(slave_ref[1][0]) + master_ref_shape = master_ref[0].Shape.getElement(master_ref[1][0]) + # get the faces ids + slave_face_ids = femmesh.getFacesByFace(slave_ref_shape) + master_face_ids = femmesh.getFacesByFace(master_ref_shape) + # build slave_faces and master_faces + # face 2 for tria6 element + # is it face 2 for all shell elements + for fid in slave_face_ids: + slave_faces.append([fid, 2]) + for fid in master_face_ids: + master_faces.append([fid, 2]) + + FreeCAD.Console.PrintLog("slave_faces: {}\n".format(slave_faces)) + FreeCAD.Console.PrintLog("master_faces: {}\n".format(master_faces)) + return [slave_faces, master_faces] + + # ************************************************************************************************ # ***** groups *********************************************************************************** def get_mesh_group_elements( diff --git a/src/Mod/Fem/femsolver/calculix/writer.py b/src/Mod/Fem/femsolver/calculix/writer.py index 86e0059d44..c10cfec075 100644 --- a/src/Mod/Fem/femsolver/calculix/writer.py +++ b/src/Mod/Fem/femsolver/calculix/writer.py @@ -587,7 +587,9 @@ class FemInputWriterCcx(writerbase.FemInputWriter): f.write(str(MPC_nodes[i]) + ",\n") def write_surfaces_constraints_contact(self, f): - # get surface nodes and write them to file + # get faces + self.get_constraints_contact_faces() + # write faces to file f.write("\n***********************************************************\n") f.write("** Surfaces for contact constraint\n") f.write("** written by {} function\n".format(sys._getframe().f_code.co_name)) @@ -595,43 +597,14 @@ class FemInputWriterCcx(writerbase.FemInputWriter): # femobj --> dict, FreeCAD document object is femobj["Object"] contact_obj = femobj["Object"] f.write("** " + contact_obj.Label + "\n") - cnt = 0 - for o, elem_tup in contact_obj.References: - for elem in elem_tup: - ref_shape = o.Shape.getElement(elem) - cnt = cnt + 1 - if ref_shape.ShapeType == "Face": - if cnt == 1: - name = "DEP" + contact_obj.Name - else: - name = "IND" + contact_obj.Name - f.write("*SURFACE, NAME=" + name + "\n") - - v = self.mesh_object.FemMesh.getccxVolumesByFace(ref_shape) - if len(v) > 0: - # volume elements found - FreeCAD.Console.PrintLog( - "{}, surface {}, {} touching volume elements found\n" - .format(contact_obj.Label, name, len(v)) - ) - for i in v: - f.write("{},S{}\n".format(i[0], i[1])) - else: - # try shell elements - v = self.mesh_object.FemMesh.getFacesByFace(ref_shape) - if len(v) > 0: - FreeCAD.Console.PrintLog( - "{}, surface {}, {} touching shell elements found\n" - .format(contact_obj.Label, name, len(v)) - ) - for i in v: - f.write("{},S2\n".format(i)) - else: - FreeCAD.Console.PrintError( - "{}, surface {}, Error: " - "Neither volume nor shell elements found!\n" - .format(contact_obj.Label, name) - ) + # slave DEP + f.write("*SURFACE, NAME=DEP{}\n".format(contact_obj.Name)) + for i in femobj["ContactSlaveFaces"]: + f.write("{},S{}\n".format(i[0], i[1])) + # master IND + f.write("*SURFACE, NAME=IND{}\n".format(contact_obj.Name)) + for i in femobj["ContactMasterFaces"]: + f.write("{},S{}\n".format(i[0], i[1])) def write_node_sets_constraints_transform(self, f): # get nodes diff --git a/src/Mod/Fem/femsolver/writerbase.py b/src/Mod/Fem/femsolver/writerbase.py index 1070f33044..e1ca9903e6 100644 --- a/src/Mod/Fem/femsolver/writerbase.py +++ b/src/Mod/Fem/femsolver/writerbase.py @@ -318,6 +318,32 @@ class FemInputWriter(): femobj["PressureFaces"] = [(some_string, pressure_faces)] FreeCAD.Console.PrintLog("{}\n".format(femobj["PressureFaces"])) + def get_constraints_contact_faces(self): + if not self.femnodes_mesh: + self.femnodes_mesh = self.femmesh.Nodes + if not self.femelement_table: + self.femelement_table = meshtools.get_femelement_table(self.femmesh) + if not self.femnodes_ele_table: + self.femnodes_ele_table = meshtools.get_femnodes_ele_table( + self.femnodes_mesh, + self.femelement_table + ) + + for femobj in self.contact_objects: + # femobj --> dict, FreeCAD document object is femobj["Object"] + print_obj_info(femobj["Object"]) + contact_slave_faces, contact_master_faces = meshtools.get_contact_obj_faces( + self.femmesh, + self.femelement_table, + self.femnodes_ele_table, femobj + ) + # [ele_id, ele_face_id], [ele_id, ele_face_id], ...] + # whereas the ele_face_id might be ccx specific + femobj["ContactSlaveFaces"] = contact_slave_faces + femobj["ContactMasterFaces"] = contact_master_faces + # FreeCAD.Console.PrintLog("{}\n".format(femobj["ContactSlaveFaces"])) + # FreeCAD.Console.PrintLog("{}\n".format(femobj["ContactMasterFaces"])) + def get_element_geometry2D_elements(self): # get element ids and write them into the objects FreeCAD.Console.PrintMessage("Shell thicknesses\n")