Exemple #1
0
def get_refshape_type(fem_doc_object):
    """ Return shape type the constraints references.

    Determine single shape type of references of *fem_doc_object* which must be
    a constraint (=have a *References* property). All references must be of the
    same type which is than returned as a string. A type can be "Vertex",
    "Edge", "Face" or "Solid".

    :param fem_doc_object:
     A constraint object with a *References* property.

    :returns:
     A string representing the shape type ("Vertex", "Edge", "Face" or
     "Solid"). If *fem_doc_object* isn't a constraint ``""`` is returned.

    :note:
     Undefined behaviour if the type of the references of one object are
     not all the same.

    :note:
     Undefined behaviour if constraint contains no references (empty list).
    """
    import femmesh.meshtools as FemMeshTools
    if hasattr(fem_doc_object, "References") and fem_doc_object.References:
        first_ref_obj = fem_doc_object.References[0]
        first_ref_shape = FemMeshTools.get_element(first_ref_obj[0],
                                                   first_ref_obj[1][0])
        st = first_ref_shape.ShapeType
        FreeCAD.Console.PrintMessage("References: {} in {}, {}\n".format(
            st, fem_doc_object.Name, fem_doc_object.Label))
        return st
    else:
        FreeCAD.Console.PrintMessage("References: empty in {}, {}\n".format(
            fem_doc_object.Name, fem_doc_object.Label))
        return ""
Exemple #2
0
 def select_clicked_reference_shape(self):
     self.setback_listobj_visibility()
     if self.sel_server:
         FreeCADGui.Selection.removeObserver(self.sel_server)
         self.sel_server = None
     if not self.sel_server:
         if not self.references:
             return
         currentItemName = str(self.list_References.currentItem().text())
         for ref in self.references:
             if self.get_item_text(ref) == currentItemName:
                 # print('found: shape: ' + ref[0].Name + ' element: ' + ref[1])
                 if not ref[0].ViewObject.Visibility:
                     self.obj_notvisible.append(ref[0])
                     ref[0].ViewObject.Visibility = True
                 FreeCADGui.Selection.clearSelection()
                 if ref[1].startswith('Solid') and (ref[0].Shape.ShapeType == 'Compound' or ref[0].Shape.ShapeType == 'CompSolid'):
                     # selection of Solids of Compounds or CompSolids is not possible, because a Solid is no Subelement
                     # since only Subelements can be selected, we're going to select all Faces of said Solids
                     solid = FemMeshTools.get_element(ref[0], ref[1])  # the method getElement(element) doesn't return Solid elements
                     if not solid:
                         return
                     faces = []
                     for fs in solid.Faces:
                         # find these faces in ref[0]
                         for i, fref in enumerate(ref[0].Shape.Faces):
                             if fs.isSame(fref):
                                 fref_elstring = 'Face' + str(i + 1)
                                 if fref_elstring not in faces:
                                     faces.append(fref_elstring)
                     for f in faces:
                         FreeCADGui.Selection.addSelection(ref[0], f)
                 else:
                     # Selection of all other element types is supported
                     FreeCADGui.Selection.addSelection(ref[0], ref[1])
 def select_clicked_reference_shape(self):
     self.setback_listobj_visibility()
     if self.sel_server:
         FreeCADGui.Selection.removeObserver(self.sel_server)
         self.sel_server = None
     if not self.sel_server:
         if not self.references:
             return
         currentItemName = str(self.list_References.currentItem().text())
         for ref in self.references:
             if self.get_item_text(ref) == currentItemName:
                 # print('found: shape: ' + ref[0].Name + ' element: ' + ref[1])
                 if not ref[0].ViewObject.Visibility:
                     self.obj_notvisible.append(ref[0])
                     ref[0].ViewObject.Visibility = True
                 FreeCADGui.Selection.clearSelection()
                 if ref[1].startswith('Solid') and (ref[0].Shape.ShapeType == 'Compound' or ref[0].Shape.ShapeType == 'CompSolid'):
                     # selection of Solids of Compounds or CompSolids is not possible, because a Solid is no Subelement
                     # since only Subelements can be selected, we gone select all Faces of such an Solids
                     solid = FemMeshTools.get_element(ref[0], ref[1])  # the method getElement(element) does not return Solid elements
                     if not solid:
                         return
                     faces = []
                     for fs in solid.Faces:
                         # find these faces in ref[0]
                         for i, fref in enumerate(ref[0].Shape.Faces):
                             if fs.isSame(fref):
                                 fref_elstring = 'Face' + str(i + 1)
                                 if fref_elstring not in faces:
                                     faces.append(fref_elstring)
                     for f in faces:
                         FreeCADGui.Selection.addSelection(ref[0], f)
                 else:
                     # Selection of all other element types is supported
                     FreeCADGui.Selection.addSelection(ref[0], ref[1])
 def has_equal_references_shape_types(self):
     import femmesh.meshtools as FemMeshTools
     ref_shty = ''
     for ref in self.references:
         r = FemMeshTools.get_element(ref[0], ref[1])  # the method getElement(element) does not return Solid elements
         # print('  ReferenceShape : ', r.ShapeType, ', ', ref[0].Name, ', ', ref[0].Label, ' --> ', ref[1])
         if not ref_shty:
             ref_shty = r.ShapeType
         if r.ShapeType != ref_shty:
             message = 'Multiple shape types are not allowed in the reference list.\n'
             FreeCAD.Console.PrintError(message)
             QMessageBox.critical(None, "Multiple ShapeTypes not allowed", message)
             return False
     return True
 def has_equal_references_shape_types(self):
     import femmesh.meshtools as FemMeshTools
     ref_shty = ''
     for ref in self.references:
         r = FemMeshTools.get_element(ref[0], ref[1])  # the method getElement(element) does not return Solid elements
         # print('  ReferenceShape : ', r.ShapeType, ', ', ref[0].Name, ', ', ref[0].Label, ' --> ', ref[1])
         if not ref_shty:
             ref_shty = r.ShapeType
         if r.ShapeType != ref_shty:
             message = 'Multiple shape types are not allowed in the reference list.\n'
             FreeCAD.Console.PrintError(message)
             QMessageBox.critical(None, "Multiple ShapeTypes not allowed", message)
             return False
     return True
Exemple #6
0
 def has_equal_references_shape_types(self, ref_shty=''):
     for ref in self.references:
         r = FemMeshTools.get_element(ref[0], ref[1])  # the method getElement(element) does not return Solid elements
         if not r:
             FreeCAD.Console.PrintError('Problem in retrieving element: {} \n'.format(ref[1]))
             continue
         # print('  ReferenceShape : ', r.ShapeType, ', ', ref[0].Name, ', ', ref[0].Label, ' --> ', ref[1])
         if not ref_shty:
             ref_shty = r.ShapeType
         if r.ShapeType != ref_shty:
             message = 'Multiple shape types are not allowed in the reference list.\n'
             FreeCAD.Console.PrintMessage(message)
             QtGui.QMessageBox.critical(None, "Multiple ShapeTypes not allowed", message)
             return False
     return True
 def has_equal_references_shape_types(self, ref_shty=''):
     for ref in self.references:
         r = FemMeshTools.get_element(ref[0], ref[1])  # the method getElement(element) does not return Solid elements
         if not r:
             FreeCAD.Console.PrintError('Problem in retrieving element: {} \n'.format(ref[1]))
             continue
         # print('  ReferenceShape : ', r.ShapeType, ', ', ref[0].Name, ', ', ref[0].Label, ' --> ', ref[1])
         if not ref_shty:
             ref_shty = r.ShapeType
         if r.ShapeType != ref_shty:
             message = 'Multiple shape types are not allowed in the reference list.\n'
             FreeCAD.Console.PrintMessage(message)
             QtGui.QMessageBox.critical(None, "Multiple ShapeTypes not allowed", message)
             return False
     return True
Exemple #8
0
def get_refshape_type(fem_doc_object):
    # returns the reference shape type
    # for force object:
    # in GUI defined frc_obj all frc_obj have at least one ref_shape and ref_shape have all the same shape type
    # for material object:
    # in GUI defined material_obj could have no RefShape and RefShapes could be different type
    # we're going to need the RefShapes to be the same type inside one fem_doc_object
    # TODO: check if all RefShapes inside the object really have the same type
    import femmesh.meshtools as FemMeshTools
    if hasattr(fem_doc_object, 'References') and fem_doc_object.References:
        first_ref_obj = fem_doc_object.References[0]
        first_ref_shape = FemMeshTools.get_element(first_ref_obj[0], first_ref_obj[1][0])
        st = first_ref_shape.ShapeType
        FreeCAD.Console.PrintMessage(fem_doc_object.Name + ' has ' + st + ' reference shapes.\n')
        return st
    else:
        FreeCAD.Console.PrintMessage(fem_doc_object.Name + ' has empty References.\n')
        return ''
Exemple #9
0
def get_refshape_type(fem_doc_object):
    # returns the reference shape type
    # for force object:
    # in GUI defined frc_obj all frc_obj have at leas one ref_shape and ref_shape have all the same shape type
    # for material object:
    # in GUI defined material_obj could have no RefShape and RefShapes could be different type
    # we're going to need the RefShapes to be the same type inside one fem_doc_object
    # TODO: check if all RefShapes inside the object really have the same type
    import femmesh.meshtools as FemMeshTools
    if hasattr(fem_doc_object, 'References') and fem_doc_object.References:
        first_ref_obj = fem_doc_object.References[0]
        first_ref_shape = FemMeshTools.get_element(first_ref_obj[0], first_ref_obj[1][0])
        st = first_ref_shape.ShapeType
        print(fem_doc_object.Name + ' has ' + st + ' reference shapes.')
        return st
    else:
        print(fem_doc_object.Name + ' has empty References.')
        return ''
Exemple #10
0
    def get_group_data(self):
        self.group_elements = {}
        # TODO solid, face, edge seam not work together, some print or make it work together
        # TODO handle groups for Edges and Vertexes

        # mesh groups and groups of analysis member
        if not self.mesh_obj.MeshGroupList:
            print('  No mesh group objects.')
        else:
            print('  Mesh group objects, we need to get the elements.')
            for mg in self.mesh_obj.MeshGroupList:
                new_group_elements = FemMeshTools.get_mesh_group_elements(
                    mg, self.part_obj)
                for ge in new_group_elements:
                    if ge not in self.group_elements:
                        self.group_elements[ge] = new_group_elements[ge]
                    else:
                        FreeCAD.Console.PrintError(
                            "  A group with this name exists already.\n")
        if self.analysis:
            print('  Group meshing.')
            new_group_elements = FemMeshTools.get_analysis_group_elements(
                self.analysis, self.part_obj)
            for ge in new_group_elements:
                if ge not in self.group_elements:
                    self.group_elements[ge] = new_group_elements[ge]
                else:
                    FreeCAD.Console.PrintError(
                        "  A group with this name exists already.\n")
        else:
            print('  No anlysis members for group meshing.')
        print('  {}'.format(self.group_elements))

        # mesh regions
        self.ele_length_map = {}  # { 'ElementString' : element length }
        self.ele_node_map = {}  # { 'ElementString' : [element nodes] }
        if not self.mesh_obj.MeshRegionList:
            print('  No mesh regions.')
        else:
            print('  Mesh regions, we need to get the elements.')
            if self.part_obj.Shape.ShapeType == 'Compound':
                # see http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&start=40#p149467 and http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&p=149520#p149520
                err = "GMSH could return unexpected meshes for a boolean split tools Compound. It is strongly recommended to extract the shape to mesh from the Compound and use this one."
                FreeCAD.Console.PrintError(err + "\n")
            for mr_obj in self.mesh_obj.MeshRegionList:
                if mr_obj.RelativeLength:
                    if mr_obj.References:
                        for sub in mr_obj.References:
                            # print(sub[0])  # Part the elements belongs to
                            # check if the shape of the mesh region is an element of the Part to mesh, if not try to find the element in the shape to mesh
                            search_ele_in_shape_to_mesh = False
                            shape = FreeCAD.ActiveDocument.getObject(
                                sub[0]).Shape
                            if not self.part_obj.Shape.isSame(shape):
                                search_ele_in_shape_to_mesh = True
                            elems = sub[1]
                            if search_ele_in_shape_to_mesh:
                                # we gone try to find the element it in the Shape to mesh and use the found element as elems
                                ele_shape = FemMeshTools.get_element(
                                    shape, elems
                                )  # the method getElement(element) does not return Solid elements
                                found_element = FemMeshTools.find_element_in_shape(
                                    self.part_obj.Shape, ele_shape)
                                if found_element:
                                    elems = found_element
                                else:
                                    FreeCAD.Console.PrintError(
                                        "One element of the meshregion " +
                                        mr_obj.Name +
                                        " could not be found in the Part to mesh. It will be ignored.\n"
                                    )
                            # print(elems)  # element
                            if elems not in self.ele_length_map:
                                # self.ele_length_map[elems] = Units.Quantity(mr_obj.CharacteristicLength).Value
                                mr_rellen = mr_obj.RelativeLength
                                if mr_rellen > 1.0:
                                    mr_rellen = 1.0
                                    FreeCAD.Console.PrintError(
                                        "The meshregion: " + mr_obj.Name +
                                        " should not use a relative length greater than unity.\n"
                                    )
                                elif mr_rellen < 0.01:
                                    mr_rellen = 0.01  # Relative length should not be less than 1/100 of base length
                                    FreeCAD.Console.PrintError(
                                        "The meshregion: " + mr_obj.Name +
                                        " should not use a relative length smaller than 0.01.\n"
                                    )

                                self.ele_length_map[
                                    elems] = mr_rellen * self.clmax
                            else:
                                FreeCAD.Console.PrintError(
                                    "The element " + elems +
                                    " of the meshregion " + mr_obj.Name +
                                    " has been added to another mesh region.\n"
                                )
                    else:
                        FreeCAD.Console.PrintError(
                            "The meshregion: " + mr_obj.Name +
                            " is not used to create the mesh because the reference list is empty.\n"
                        )
                else:
                    FreeCAD.Console.PrintError(
                        "The meshregion: " + mr_obj.Name +
                        " is not used to create the mesh because the CharacteristicLength is 0.0 mm.\n"
                    )
            for eleml in self.ele_length_map:
                print(eleml)
                ele_shape = FemMeshTools.get_element(
                    self.part_obj, eleml
                )  # the method getElement(element) does not return Solid elements
                ele_vertexes = FemMeshTools.get_vertexes_by_element(
                    self.part_obj.Shape, ele_shape)
                self.ele_node_map[eleml] = ele_vertexes
        print('  {}'.format(self.ele_length_map))
        print('  {}'.format(self.ele_node_map))
Exemple #11
0
    def get_region_data(self):
        """ Mesh regions """
        if self.mesh_obj.MeshUtility == "gmsh":
            # mesh regions
            self.ele_length_map = {}  # { 'ElementString' : element length }
            self.ele_node_map = {}  # { 'ElementString' : [element nodes] }
            if not self.mesh_obj.MeshRegionList:
                print('  No mesh regions.')
            else:
                print('  Mesh regions, we need to get the elements.')
                if self.part_obj.Shape.ShapeType == 'Compound':
                    # see http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&start=40#p149467 and http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&p=149520#p149520
                    err = "GMSH could return unexpected meshes for a boolean split tools Compound. It is strongly recommended to extract the shape to mesh from the Compound and use this one."
                    FreeCAD.Console.PrintError(err + "\n")
                for mr_obj in self.mesh_obj.MeshRegionList:
                    if mr_obj.RelativeLength:
                        if mr_obj.References:
                            for sub in mr_obj.References:
                                # check if the shape of the mesh region is an element of the Part to mesh, if not try to find the element in the shape to mesh
                                search_ele_in_shape_to_mesh = False
                                ref = FreeCAD.ActiveDocument.getObject(sub[0])
                                if not self.part_obj.Shape.isSame(ref.Shape):
                                    search_ele_in_shape_to_mesh = True
                                elems = sub[1]
                                if search_ele_in_shape_to_mesh:
                                    # Try to find the element in the Shape to mesh
                                    ele_shape = FemMeshTools.get_element(
                                        ref, elems
                                    )  # the method getElement(element) does not return Solid elements
                                    found_element = CfdTools.findElementInShape(
                                        self.part_obj.Shape, ele_shape)
                                    if found_element:
                                        elems = found_element
                                    else:
                                        FreeCAD.Console.PrintError(
                                            "One element of the meshregion " +
                                            mr_obj.Name +
                                            " could not be found in the Part to mesh. It will be ignored.\n"
                                        )
                                        elems = None
                                if elems:
                                    if elems not in self.ele_length_map:
                                        # self.ele_length_map[elems] = Units.Quantity(mr_obj.CharacteristicLength).Value
                                        mr_rellen = mr_obj.RelativeLength
                                        if mr_rellen > 1.0:
                                            mr_rellen = 1.0
                                            FreeCAD.Console.PrintError(
                                                "The meshregion: " +
                                                mr_obj.Name +
                                                " should not use a relative length greater than unity.\n"
                                            )
                                        elif mr_rellen < 0.01:
                                            mr_rellen = 0.01  # Relative length should not be less than 1/100 of base length
                                            FreeCAD.Console.PrintError(
                                                "The meshregion: " +
                                                mr_obj.Name +
                                                " should not use a relative length smaller than 0.01.\n"
                                            )
                                        self.ele_length_map[
                                            elems] = mr_rellen * self.clmax
                                    else:
                                        FreeCAD.Console.PrintError(
                                            "The element " + elems +
                                            " of the meshregion " +
                                            mr_obj.Name +
                                            " has been added to another mesh region.\n"
                                        )
                        else:
                            FreeCAD.Console.PrintError(
                                "The meshregion: " + mr_obj.Name +
                                " is not used to create the mesh because the reference list is empty.\n"
                            )
                    else:
                        FreeCAD.Console.PrintError(
                            "The meshregion: " + mr_obj.Name +
                            " is not used to create the mesh because the CharacteristicLength is 0.0 mm.\n"
                        )
                for eleml in self.ele_length_map:
                    ele_shape = FemMeshTools.get_element(
                        self.part_obj, eleml
                    )  # the method getElement(element) does not return Solid elements
                    ele_vertexes = FemMeshTools.get_vertexes_by_element(
                        self.part_obj.Shape, ele_shape)
                    self.ele_node_map[eleml] = ele_vertexes

        else:
            cf_settings = self.cf_settings
            cf_settings['MeshRegions'] = {}
            cf_settings['BoundaryLayers'] = {}
            cf_settings['InternalRegions'] = {}
            snappy_settings = self.snappy_settings
            snappy_settings['MeshRegions'] = {}
            snappy_settings['InternalRegions'] = {}

            from collections import defaultdict
            self.ele_meshpatch_map = defaultdict(list)
            if not self.mesh_obj.MeshRegionList:
                print('  No mesh regions.')
            else:
                print('  Mesh regions, we need to get the elements.')
                if "Boolean" in self.part_obj.Name:
                    err = "Cartesian meshes should not be generated for boolean split compounds."
                    FreeCAD.Console.PrintError(err + "\n")

                # Make list of list of all references for their corresponding mesh object
                if self.mesh_obj.MeshUtility == 'cfMesh':
                    region_face_lists = []
                    for mr_id, mr_obj in enumerate(
                            self.mesh_obj.MeshRegionList):
                        region_face_lists.append([])
                        if mr_obj.NumberLayers > 1 and not mr_obj.Internal:
                            refs = mr_obj.References
                            for r in refs:
                                region_face_lists[mr_id].append(r)
                    matched_faces = CfdTools.matchFacesToTargetShape(
                        region_face_lists, self.mesh_obj.Part.Shape)

                for mr_id, mr_obj in enumerate(self.mesh_obj.MeshRegionList):
                    try:
                        Internal = mr_obj.Internal
                        InternalRegion = mr_obj.InternalRegion
                    except AttributeError:
                        Internal = False
                        InternalRegion = {}

                    if mr_obj.RelativeLength:
                        # Store parameters per region
                        mr_rellen = mr_obj.RelativeLength
                        if mr_rellen > 1.0:
                            mr_rellen = 1.0
                            FreeCAD.Console.PrintError(
                                "The meshregion: {} should not use a relative length greater "
                                "than unity.\n".format(mr_obj.Name))
                        elif mr_rellen < 0.001:
                            mr_rellen = 0.001  # Relative length should not be less than 0.1% of base length
                            FreeCAD.Console.PrintError(
                                "The meshregion: {} should not use a relative length smaller "
                                "than 0.05.\n".format(mr_obj.Name))

                        tri_surface = ""
                        snappy_mesh_region_list = []
                        patch_list = []
                        for (si, sub) in enumerate(mr_obj.References):
                            elems = sub[1]
                            elt = FreeCAD.ActiveDocument.getObject(
                                sub[0]).Shape.getElement(elems)
                            if elt.ShapeType == 'Face':
                                facemesh = MeshPart.meshFromShape(
                                    elt,
                                    LinearDeflection=self.mesh_obj.
                                    STLLinearDeflection)

                                tri_surface += "solid {}{}{}\n".format(
                                    mr_obj.Name, sub[0], elems)
                                for face in facemesh.Facets:
                                    tri_surface += " facet normal 0 0 0\n"
                                    tri_surface += "  outer loop\n"
                                    for i in range(3):
                                        p = [
                                            i * self.scale
                                            for i in face.Points[i]
                                        ]
                                        tri_surface += "    vertex {} {} {}\n".format(
                                            p[0], p[1], p[2])
                                    tri_surface += "  endloop\n"
                                    tri_surface += " endfacet\n"
                                tri_surface += "solid {}{}{}\n".format(
                                    mr_obj.Name, sub[0], elems)

                                if self.mesh_obj.MeshUtility == 'snappyHexMesh' and mr_obj.Baffle:
                                    # Save baffle references or faces individually
                                    baffle = "{}{}{}".format(
                                        mr_obj.Name, sub[0], elems)
                                    fid = open(
                                        os.path.join(self.triSurfaceDir,
                                                     baffle + ".stl"), 'w')
                                    fid.write(tri_surface)
                                    fid.close()
                                    tri_surface = ""
                                    snappy_mesh_region_list.append(baffle)
                            else:
                                FreeCAD.Console.PrintError(
                                    "Cartesian meshes only support surface refinement.\n"
                                )

                        if self.mesh_obj.MeshUtility == 'cfMesh' or not mr_obj.Baffle:
                            fid = open(
                                os.path.join(self.triSurfaceDir,
                                             mr_obj.Name + '.stl'), 'w')
                            fid.write(tri_surface)
                            fid.close()

                        if self.mesh_obj.MeshUtility == 'cfMesh' and mr_obj.NumberLayers > 1 and not Internal:
                            for (i, mf) in enumerate(matched_faces):
                                for j in range(len(mf)):
                                    if mr_id == mf[j][0]:
                                        sfN = self.mesh_obj.ShapeFaceNames[i]
                                        self.ele_meshpatch_map[
                                            mr_obj.Name].append(sfN)
                                        patch_list.append(sfN)

                                        # Limit expansion ratio to greater than 1.0 and less than 1.2
                                        expratio = mr_obj.ExpansionRatio
                                        expratio = min(1.2, max(1.0, expratio))

                                        cf_settings['BoundaryLayers'][
                                            self.mesh_obj.
                                            ShapeFaceNames[i]] = {
                                                'NumberLayers':
                                                mr_obj.NumberLayers,
                                                'ExpansionRatio':
                                                expratio,
                                                'FirstLayerHeight':
                                                self.scale * Units.Quantity(
                                                    mr_obj.FirstLayerHeight).
                                                Value
                                            }

                        if self.mesh_obj.MeshUtility == 'cfMesh':
                            if not Internal:
                                cf_settings['MeshRegions'][mr_obj.Name] = {
                                    'RelativeLength':
                                    mr_rellen * self.clmax * self.scale,
                                    'RefinementThickness':
                                    self.scale * Units.Quantity(
                                        mr_obj.RefinementThickness).Value,
                                }
                            else:
                                cf_settings['InternalRegions'][mr_obj.Name] = {
                                    #"Internal": Internal,
                                    'RelativeLength':
                                    mr_rellen * self.clmax * self.scale,
                                    "InternalRegion":
                                    InternalRegion
                                }

                        elif self.mesh_obj.MeshUtility == 'snappyHexMesh':
                            if not Internal:
                                if not mr_obj.Baffle:
                                    snappy_mesh_region_list.append(mr_obj.Name)
                                for rL in range(len(snappy_mesh_region_list)):
                                    mrName = mr_obj.Name + snappy_mesh_region_list[
                                        rL]
                                    snappy_settings['MeshRegions'][mrName] = {
                                        'RegionName':
                                        snappy_mesh_region_list[rL],
                                        'RefinementLevel':
                                        mr_obj.RefinementLevel,
                                        'EdgeRefinementLevel':
                                        mr_obj.RegionEdgeRefinement,
                                        'MaxRefinementLevel':
                                        max(mr_obj.RefinementLevel,
                                            mr_obj.RegionEdgeRefinement),
                                        'Baffle':
                                        mr_obj.Baffle
                                    }
                            else:
                                minX = InternalRegion["Center"][
                                    "x"] - InternalRegion["BoxLengths"][
                                        "x"] / 2.0
                                maxX = InternalRegion["Center"][
                                    "x"] + InternalRegion["BoxLengths"][
                                        "x"] / 2.0
                                minY = InternalRegion["Center"][
                                    "y"] - InternalRegion["BoxLengths"][
                                        "y"] / 2.0
                                maxY = InternalRegion["Center"][
                                    "y"] + InternalRegion["BoxLengths"][
                                        "y"] / 2.0
                                minZ = InternalRegion["Center"][
                                    "z"] - InternalRegion["BoxLengths"][
                                        "z"] / 2.0
                                maxZ = InternalRegion["Center"][
                                    "z"] + InternalRegion["BoxLengths"][
                                        "z"] / 2.0
                                snappy_settings['InternalRegions'][
                                    mr_obj.Name] = {
                                        'RefinementLevel':
                                        mr_obj.RefinementLevel,
                                        "Type": InternalRegion["Type"],
                                        "Center": InternalRegion["Center"],
                                        "Radius":
                                        InternalRegion["SphereRadius"],
                                        "minX": minX,
                                        "maxX": maxX,
                                        "minY": minY,
                                        "maxY": maxY,
                                        "minZ": minZ,
                                        "maxZ": maxZ
                                    }

                    else:
                        FreeCAD.Console.PrintError(
                            "The meshregion: " + mr_obj.Name +
                            " is not used to create the mesh because the "
                            "CharacteristicLength is 0.0 mm or the reference list is empty.\n"
                        )
Exemple #12
0
    def processRefinements(self):
        """ Process mesh refinements """

        mr_objs = CfdTools.getMeshRefinementObjs(self.mesh_obj)

        if self.mesh_obj.MeshUtility == "gmsh":
            # mesh regions
            self.ele_length_map = {}  # { 'ElementString' : element length }
            self.ele_node_map = {}  # { 'ElementString' : [element nodes] }
            if not mr_objs:
                print('  No mesh refinements')
            else:
                print('  Mesh refinements found - getting elements')
                if self.part_obj.Shape.ShapeType == 'Compound':
                    # see http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&start=40#p149467 and http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&p=149520#p149520
                    err = "GMSH could return unexpected meshes for a boolean split tools Compound. It is strongly recommended to extract the shape to mesh from the Compound and use this one."
                    FreeCAD.Console.PrintError(err + "\n")
                for mr_obj in mr_objs:
                    if mr_obj.RelativeLength:
                        if mr_obj.References:
                            for sub in mr_obj.References:
                                # Check if the shape of the mesh region is an element of the Part to mesh;
                                # if not try to find the element in the shape to mesh
                                search_ele_in_shape_to_mesh = False
                                ref = FreeCAD.ActiveDocument.getObject(sub[0])
                                if not self.part_obj.Shape.isSame(ref.Shape):
                                    search_ele_in_shape_to_mesh = True
                                elems = sub[1]
                                if search_ele_in_shape_to_mesh:
                                    # Try to find the element in the Shape to mesh
                                    ele_shape = FemMeshTools.get_element(
                                        ref, elems
                                    )  # the method getElement(element) does not return Solid elements
                                    found_element = CfdTools.findElementInShape(
                                        self.part_obj.Shape, ele_shape)
                                    if found_element:
                                        elems = found_element
                                    else:
                                        FreeCAD.Console.PrintError(
                                            "One element of the meshregion " +
                                            mr_obj.Name +
                                            " could not be found in the Part to mesh. It will be ignored.\n"
                                        )
                                        elems = None
                                if elems:
                                    if elems not in self.ele_length_map:
                                        # self.ele_length_map[elems] = Units.Quantity(mr_obj.CharacteristicLength).Value
                                        mr_rellen = mr_obj.RelativeLength
                                        if mr_rellen > 1.0:
                                            mr_rellen = 1.0
                                            FreeCAD.Console.PrintError(
                                                "The meshregion: " +
                                                mr_obj.Name +
                                                " should not use a relative length greater than unity.\n"
                                            )
                                        elif mr_rellen < 0.01:
                                            mr_rellen = 0.01  # Relative length should not be less than 1/100 of base length
                                            FreeCAD.Console.PrintError(
                                                "The meshregion: " +
                                                mr_obj.Name +
                                                " should not use a relative length smaller than 0.01.\n"
                                            )
                                        self.ele_length_map[
                                            elems] = mr_rellen * self.clmax
                                    else:
                                        FreeCAD.Console.PrintError(
                                            "The element " + elems +
                                            " of the mesh refinement " +
                                            mr_obj.Name +
                                            " has been added to another mesh refinement.\n"
                                        )
                        else:
                            FreeCAD.Console.PrintError(
                                "The meshregion: " + mr_obj.Name +
                                " is not used to create the mesh because the reference list is empty.\n"
                            )
                    else:
                        FreeCAD.Console.PrintError(
                            "The meshregion: " + mr_obj.Name +
                            " is not used to create the mesh because the CharacteristicLength is 0.0 mm.\n"
                        )
                for eleml in self.ele_length_map:
                    ele_shape = FemMeshTools.get_element(
                        self.part_obj, eleml
                    )  # the method getElement(element) does not return Solid elements
                    ele_vertexes = FemMeshTools.get_vertexes_by_element(
                        self.part_obj.Shape, ele_shape)
                    self.ele_node_map[eleml] = ele_vertexes

        else:
            cf_settings = self.cf_settings
            cf_settings['MeshRegions'] = {}
            cf_settings['BoundaryLayers'] = {}
            cf_settings['InternalRegions'] = {}
            snappy_settings = self.snappy_settings
            snappy_settings['MeshRegions'] = {}
            snappy_settings['InternalRegions'] = {}

            from collections import defaultdict
            ele_meshpatch_map = defaultdict(list)
            if not mr_objs:
                print('  No mesh refinement')
            else:
                print('  Mesh refinements - getting the elements')
                if "Boolean" in self.part_obj.Name:
                    err = "Cartesian meshes should not be generated for boolean split compounds."
                    FreeCAD.Console.PrintError(err + "\n")

                # Make list of list of all references for their corresponding mesh object
                bl_matched_faces = []
                if self.mesh_obj.MeshUtility == 'cfMesh':
                    region_face_lists = []
                    for mr_id, mr_obj in enumerate(mr_objs):
                        region_face_lists.append([])
                        if mr_obj.NumberLayers > 1 and not mr_obj.Internal:
                            refs = mr_obj.References
                            for r in refs:
                                region_face_lists[mr_id].append(r)
                    CfdTools.cfdMessage("Matching refinement regions")
                    bl_matched_faces = CfdTools.matchFacesToTargetShape(
                        region_face_lists, self.mesh_obj.Part.Shape)

                for mr_id, mr_obj in enumerate(mr_objs):
                    Internal = mr_obj.Internal

                    if mr_obj.RelativeLength:
                        # Store parameters per region
                        mr_rellen = mr_obj.RelativeLength
                        if mr_rellen > 1.0:
                            mr_rellen = 1.0
                            FreeCAD.Console.PrintError(
                                "The meshregion: {} should not use a relative length greater "
                                "than unity.\n".format(mr_obj.Name))
                        elif mr_rellen < 0.001:
                            mr_rellen = 0.001  # Relative length should not be less than 0.1% of base length
                            FreeCAD.Console.PrintError(
                                "The meshregion: {} should not use a relative length smaller "
                                "than 0.001.\n".format(mr_obj.Name))

                        if not (self.mesh_obj.MeshUtility == 'snappyHexMesh'
                                and mr_obj.Baffle):
                            fid = open(
                                os.path.join(self.triSurfaceDir,
                                             mr_obj.Name + '.stl'), 'w')

                        snappy_mesh_region_list = []
                        patch_list = []
                        for (si, sub) in enumerate(mr_obj.References):
                            shape = FreeCAD.ActiveDocument.getObject(
                                sub[0]).Shape
                            elem = sub[1]

                            if self.mesh_obj.MeshUtility == 'snappyHexMesh' and mr_obj.Baffle:
                                # Save baffle references or faces individually
                                baffle = "{}{}{}".format(
                                    mr_obj.Name, sub[0], elem)
                                fid = open(
                                    os.path.join(self.triSurfaceDir,
                                                 baffle + ".stl"), 'w')
                                snappy_mesh_region_list.append(baffle)

                            if elem.startswith(
                                    'Solid'
                            ):  # getElement doesn't work with solids for some reason
                                elt = shape.Solids[int(elem.lstrip('Solid')) -
                                                   1]
                            else:
                                elt = shape.getElement(elem)
                            if elt.ShapeType == 'Face' or elt.ShapeType == 'Solid':
                                CfdTools.cfdMessage(
                                    "Triangulating part: {}:{} ...".format(
                                        FreeCAD.ActiveDocument.getObject(
                                            sub[0]).Label, sub[1]))
                                facemesh = MeshPart.meshFromShape(
                                    elt,
                                    LinearDeflection=self.mesh_obj.
                                    STLLinearDeflection)

                                CfdTools.cfdMessage(" writing to file\n")
                                fid.write("solid {}{}{}\n".format(
                                    mr_obj.Name, sub[0], elem))
                                for face in facemesh.Facets:
                                    fid.write(" facet normal 0 0 0\n")
                                    fid.write("  outer loop\n")
                                    for i in range(3):
                                        p = [
                                            i * self.scale
                                            for i in face.Points[i]
                                        ]
                                        fid.write(
                                            "    vertex {} {} {}\n".format(
                                                p[0], p[1], p[2]))
                                    fid.write("  endloop\n")
                                    fid.write(" endfacet\n")
                                fid.write("endsolid {}{}{}\n".format(
                                    mr_obj.Name, sub[0], elem))

                            if self.mesh_obj.MeshUtility == 'snappyHexMesh' and mr_obj.Baffle:
                                fid.close()

                        if not (self.mesh_obj.MeshUtility == 'snappyHexMesh'
                                and mr_obj.Baffle):
                            fid.close()

                        if self.mesh_obj.MeshUtility == 'cfMesh' and mr_obj.NumberLayers > 1 and not Internal:
                            for (i, mf) in enumerate(bl_matched_faces):
                                for j in range(len(mf)):
                                    if mr_id == mf[j][0]:
                                        sfN = self.mesh_obj.ShapeFaceNames[i]
                                        ele_meshpatch_map[mr_obj.Name].append(
                                            sfN)
                                        patch_list.append(sfN)

                                        # Limit expansion ratio to greater than 1.0 and less than 1.2
                                        expratio = mr_obj.ExpansionRatio
                                        expratio = min(1.2, max(1.0, expratio))

                                        cf_settings['BoundaryLayers'][
                                            self.mesh_obj.
                                            ShapeFaceNames[i]] = {
                                                'NumberLayers':
                                                mr_obj.NumberLayers,
                                                'ExpansionRatio':
                                                expratio,
                                                'FirstLayerHeight':
                                                self.scale * Units.Quantity(
                                                    mr_obj.FirstLayerHeight).
                                                Value
                                            }

                        if self.mesh_obj.MeshUtility == 'cfMesh':
                            if not Internal:
                                cf_settings['MeshRegions'][mr_obj.Name] = {
                                    'RelativeLength':
                                    mr_rellen * self.clmax * self.scale,
                                    'RefinementThickness':
                                    self.scale * Units.Quantity(
                                        mr_obj.RefinementThickness).Value,
                                }
                            else:
                                cf_settings['InternalRegions'][mr_obj.Name] = {
                                    'RelativeLength':
                                    mr_rellen * self.clmax * self.scale
                                }

                        elif self.mesh_obj.MeshUtility == 'snappyHexMesh':
                            refinement_level = CfdTools.relLenToRefinementLevel(
                                mr_obj.RelativeLength)
                            if not Internal:
                                if not mr_obj.Baffle:
                                    snappy_mesh_region_list.append(mr_obj.Name)
                                edge_level = CfdTools.relLenToRefinementLevel(
                                    mr_obj.RegionEdgeRefinement)
                                for rL in range(len(snappy_mesh_region_list)):
                                    mrName = mr_obj.Name + snappy_mesh_region_list[
                                        rL]
                                    snappy_settings['MeshRegions'][mrName] = {
                                        'RegionName':
                                        snappy_mesh_region_list[rL],
                                        'RefinementLevel':
                                        refinement_level,
                                        'EdgeRefinementLevel':
                                        edge_level,
                                        'MaxRefinementLevel':
                                        max(refinement_level, edge_level),
                                        'Baffle':
                                        mr_obj.Baffle
                                    }
                            else:
                                snappy_settings['InternalRegions'][
                                    mr_obj.Name] = {
                                        'RefinementLevel': refinement_level
                                    }

                    else:
                        FreeCAD.Console.PrintError(
                            "The meshregion: " + mr_obj.Name +
                            " is not used to create the mesh because the "
                            "CharacteristicLength is 0.0 mm or the reference list is empty.\n"
                        )
Exemple #13
0
 def get_region_data(self):
     # mesh regions
     self.ele_length_map = {}  # { 'ElementString' : element length }
     self.ele_node_map = {}  # { 'ElementString' : [element nodes] }
     if not self.mesh_obj.MeshRegionList:
         print('  No mesh regions.')
     else:
         print('  Mesh regions, we need to get the elements.')
         # by the use of MeshRegion object and a BooleanSplitCompound there could be problems with node numbers see
         # http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&start=40#p149467
         # http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&p=149520#p149520
         part = self.part_obj
         if self.mesh_obj.MeshRegionList:
             if part.Shape.ShapeType == "Compound" and hasattr(
                     part, "Proxy"
             ):  # other part obj might not have a Proxy, thus an exception would be raised
                 if (part.Proxy.Type == "FeatureBooleanFragments"
                         or part.Proxy.Type == "FeatureSlice"
                         or part.Proxy.Type == "FeatureXOR"):
                     error_message = "  The mesh to shape is a boolean split tools Compound and the mesh has mesh region list. GMSH could return unexpected meshes in such circumstances. It is strongly recommended to extract the shape to mesh from the Compound and use this one."
                     FreeCAD.Console.PrintError(error_message + "\n")
                     # TODO no gui popup because FreeCAD will be in a endless prind loop as long as the pop up is on --> my be find a better solution for either of both --> thus the pop up is in task panel
         for mr_obj in self.mesh_obj.MeshRegionList:
             # print(mr_obj.Name)
             # print(mr_obj.CharacteristicLength)
             # print(Units.Quantity(mr_obj.CharacteristicLength).Value)
             if mr_obj.CharacteristicLength:
                 if mr_obj.References:
                     for sub in mr_obj.References:
                         # print(sub[0])  # Part the elements belongs to
                         # check if the shape of the mesh region is an element of the Part to mesh, if not try to find the element in the shape to mesh
                         search_ele_in_shape_to_mesh = False
                         if not self.part_obj.Shape.isSame(sub[0].Shape):
                             # print("  One element of the meshregion " + mr_obj.Name + " is not an element of the Part to mesh.")
                             # print("  But we gone try to find it in the Shape to mesh :-)")
                             search_ele_in_shape_to_mesh = True
                         for elems in sub[1]:
                             # print(elems)  # elems --> element
                             if search_ele_in_shape_to_mesh:
                                 # we gone try to find the element it in the Shape to mesh and use the found element as elems
                                 ele_shape = FemMeshTools.get_element(
                                     sub[0], elems
                                 )  # the method getElement(element) does not return Solid elements
                                 found_element = FemMeshTools.find_element_in_shape(
                                     self.part_obj.Shape, ele_shape)
                                 if found_element:
                                     elems = found_element
                                 else:
                                     FreeCAD.Console.PrintError(
                                         "One element of the meshregion " +
                                         mr_obj.Name +
                                         " could not be found in the Part to mesh. It will be ignored.\n"
                                     )
                             # print(elems)  # element
                             if elems not in self.ele_length_map:
                                 self.ele_length_map[
                                     elems] = Units.Quantity(
                                         mr_obj.CharacteristicLength).Value
                             else:
                                 FreeCAD.Console.PrintError(
                                     "The element " + elems +
                                     " of the meshregion " + mr_obj.Name +
                                     " has been added to another mesh region.\n"
                                 )
                 else:
                     FreeCAD.Console.PrintError(
                         "The meshregion: " + mr_obj.Name +
                         " is not used to create the mesh because the reference list is empty.\n"
                     )
             else:
                 FreeCAD.Console.PrintError(
                     "The meshregion: " + mr_obj.Name +
                     " is not used to create the mesh because the CharacteristicLength is 0.0 mm.\n"
                 )
         for eleml in self.ele_length_map:
             ele_shape = FemMeshTools.get_element(
                 self.part_obj, eleml
             )  # the method getElement(element) does not return Solid elements
             ele_vertexes = FemMeshTools.get_vertexes_by_element(
                 self.part_obj.Shape, ele_shape)
             self.ele_node_map[eleml] = ele_vertexes
     print('  {}'.format(self.ele_length_map))
     print('  {}'.format(self.ele_node_map))
Exemple #14
0
    def get_boundary_layer_data(self):
        #Todo:  replace all Gmsh word in this functon
        # currently only one boundary layer setting object is allowed, but multiple boundary can be selected
        # Mesh.CharacteristicLengthMin, must be zero, or a value less than first inflation layer height
        self.bl_setting_list = [
        ]  # list of dict, each item map to MeshBoundaryLayer object
        self.bl_boundary_list = [
        ]  # to remove duplicated boundary edge or faces

        if not self.mesh_obj.MeshBoundaryLayerList:
            print('  No mesh boundary layer setting document object.')
        else:
            print('  Mesh boundary layers, we need to get the elements.')
            if self.part_obj.Shape.ShapeType == 'Compound':
                # see http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&start=40#p149467 and http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&p=149520#p149520
                err = "GMSH could return unexpected meshes for a boolean split tools Compound. It is strongly recommended to extract the shape to mesh from the Compound and use this one."
                FreeCAD.Console.PrintError(err + "\n")
            for mr_obj in self.mesh_obj.MeshBoundaryLayerList:
                if mr_obj.MinimumThickness and Units.Quantity(
                        mr_obj.MinimumThickness).Value > 0:
                    if mr_obj.References:
                        belem_list = []
                        for sub in mr_obj.References:
                            # print(sub[0])  # Part the elements belongs to
                            # check if the shape of the mesh boundary_layer is an element of the Part to mesh, if not try to find the element in the shape to mesh
                            search_ele_in_shape_to_mesh = False
                            if not self.part_obj.Shape.isSame(sub[0].Shape):
                                # print("  One element of the mesh boundary layer " + mr_obj.Name + " is not an element of the Part to mesh.")
                                # print("  But we going to find it in the Shape to mesh :-)")
                                search_ele_in_shape_to_mesh = True
                            for elems in sub[1]:
                                # print(elems)  # elems --> element
                                if search_ele_in_shape_to_mesh:
                                    # we try to find the element it in the Shape to mesh and use the found element as elems
                                    ele_shape = FemMeshTools.get_element(
                                        sub[0], elems
                                    )  # the method getElement(element) does not return Solid elements
                                    found_element = FemMeshTools.find_element_in_shape(
                                        self.part_obj.Shape, ele_shape)
                                    if found_element:  # also
                                        elems = found_element
                                    else:
                                        FreeCAD.Console.PrintError(
                                            "One element of the mesh boudary layer "
                                            + mr_obj.Name +
                                            " could not be found in the Part to mesh. It will be ignored.\n"
                                        )
                                # print(elems)  # element
                                if elems not in self.bl_boundary_list:
                                    # fetch settings in DocumentObject, fan setting is not implemented
                                    belem_list.append(elems)
                                    self.bl_boundary_list.append(elems)
                                else:
                                    FreeCAD.Console.PrintError(
                                        "The element " + elems +
                                        " of the mesh boundary layer " +
                                        mr_obj.Name +
                                        " has been added to another mesh  boudary layer.\n"
                                    )
                        setting = {}
                        setting['hwall_n'] = Units.Quantity(
                            mr_obj.MinimumThickness).Value
                        setting['ratio'] = mr_obj.GrowthRate
                        setting['thickness'] = sum([
                            setting['hwall_n'] * setting['ratio']**i
                            for i in range(mr_obj.NumberOfLayers)
                        ])
                        setting['hwall_t'] = setting[
                            'thickness']  # setting['hwall_n'] * 5 # tangetial cell dimension

                        # hfar: cell dimension outside boundary should be set later if some character length is set
                        if self.clmax > setting[
                                'thickness'] * 0.8 and self.clmax < setting[
                                    'thickness'] * 1.6:
                            setting['hfar'] = self.clmax
                        else:
                            setting['hfar'] = setting[
                                'thickness']  # set a value for safety, it may works as background mesh cell size
                        # from face name -> face id is done in geo file write up
                        #fan angle setup is not implemented yet
                        if self.dimension == '2':
                            setting['EdgesList'] = belem_list
                        elif self.dimension == '3':
                            setting['FacesList'] = belem_list
                        else:
                            FreeCAD.Console.PrintError(
                                "boundary layer is only  supported for 2D and 3D mesh"
                            )
                        self.bl_setting_list.append(setting)
                    else:
                        FreeCAD.Console.PrintError(
                            "The mesh boundary layer: " + mr_obj.Name +
                            " is not used to create the mesh because the reference list is empty.\n"
                        )
                else:
                    FreeCAD.Console.PrintError(
                        "The mesh boundary layer: " + mr_obj.Name +
                        " is not used to create the mesh because the min thickness is 0.0 mm.\n"
                    )
        print('  {}'.format(self.bl_setting_list))