Пример #1
0
def moment(ship, draft=None,
                 roll=Units.parseQuantity("0 deg"),
                 trim=Units.parseQuantity("0 deg")):
    """Compute the moment required to trim the ship 1cm

    Position arguments:
    ship -- Ship object (see createShip)

    Keyword arguments:
    draft -- Ship draft (Design ship draft by default)
    roll -- Roll angle (0 degrees by default)
    trim -- Trim angle (0 degrees by default)

    Returned value:
    Moment required to trim the ship 1cm. Such moment is positive if it cause a
    positive trim angle. The moment is expressed as a mass by a distance, not as
    a force by a distance
    """
    disp_orig, B_orig, _ = displacement(ship, draft, roll, trim)
    xcb_orig = Units.Quantity(B_orig.x, Units.Length)

    factor = 10.0
    x = 0.5 * ship.Length.getValueAs('cm').Value
    y = 1.0
    angle = math.atan2(y, x) * Units.Radian
    trim_new = trim + factor * angle
    disp_new, B_new, _ = displacement(ship, draft, roll, trim_new)
    xcb_new = Units.Quantity(B_new.x, Units.Length)

    mom0 = -disp_orig * xcb_orig
    mom1 = -disp_new * xcb_new
    return (mom1 - mom0) / factor
Пример #2
0
def solve(ship, weights, tanks, rolls, var_trim=True):
    """Compute the ship GZ stability curve

    Position arguments:
    ship -- Ship object
    weights -- List of weights to consider
    tanks -- List of tanks to consider (each one should be a tuple with the
    tank instance, the density of the fluid inside, and the filling level ratio)
    rolls -- List of roll angles

    Keyword arguments:
    var_trim -- True if the equilibrium trim should be computed for each roll
    angle, False if null trim angle can be used instead.

    Returned value:
    List of GZ curve points. Each point contains the GZ stability length, the
    equilibrium draft, and the equilibrium trim angle (0 deg if var_trim is
    False)
    """
    # Get the unloaded weight (ignoring the tanks for the moment).
    W = Units.parseQuantity("0 kg")
    mom_x = Units.parseQuantity("0 kg*m")
    mom_y = Units.parseQuantity("0 kg*m")
    mom_z = Units.parseQuantity("0 kg*m")
    for w in weights:
        W += w.Proxy.getMass(w)
        m = w.Proxy.getMoment(w)
        mom_x += m[0]
        mom_y += m[1]
        mom_z += m[2]
    COG = Vector(mom_x / W, mom_y / W, mom_z / W)
    W = W * G

    # Get the tanks weight
    TW = Units.parseQuantity("0 kg")
    VOLS = []
    for t in tanks:
        # t[0] = tank object
        # t[1] = load density
        # t[2] = filling level
        vol = t[0].Proxy.getVolume(t[0], t[2])
        VOLS.append(vol)
        TW += vol * t[1]
    TW = TW * G

    points = []
    for i,roll in enumerate(rolls):
        App.Console.PrintMessage("{0} / {1}\n".format(i + 1, len(rolls)))
        point = solve_point(W, COG, TW, VOLS,
                            ship, tanks, roll, var_trim)
        if point is None:
            return []
        points.append(point)

    return points
Пример #3
0
def floatingArea(ship, draft=None,
                       roll=Units.parseQuantity("0 deg"),
                       trim=Units.parseQuantity("0 deg")):
    """Compute the ship floating area

    Position arguments:
    ship -- Ship object (see createShip)

    Keyword arguments:
    draft -- Ship draft (Design ship draft by default)
    roll -- Roll angle (0 degrees by default)
    trim -- Trim angle (0 degrees by default)

    Returned values:
    area -- Ship floating area
    cf -- Floating area coefficient
    """
    if draft is None:
        draft = ship.Draft

    # We want to intersect the whole ship with the free surface, so in this case
    # we must not use the underwater side (or the tool will fail)
    shape, _ = placeShipShape(ship.Shape.copy(), draft, roll, trim)

    try:
        f = Part.Face(shape.slice(Vector(0,0,1), 0.0))
        area = Units.Quantity(f.Area, Units.Area)
    except Part.OCCError:
        msg = QtGui.QApplication.translate(
            "ship_console",
            "Part.OCCError: Floating area cannot be computed",
            None)
        App.Console.PrintError(msg + '\n')
        area = Units.Quantity(0.0, Units.Area)

    bbox = shape.BoundBox
    Area = (bbox.XMax - bbox.XMin) * (bbox.YMax - bbox.YMin)
    try:
        cf = area.Value / Area
    except ZeroDivisionError:
        msg = QtGui.QApplication.translate(
            "ship_console",
            "ZeroDivisionError: Null area found during the floating area"
            " computation!",
            None)
        App.Console.PrintError(msg + '\n')
        cf = 0.0

    return area, cf
Пример #4
0
def mainFrameCoeff(ship, draft=None):
    """Compute the main frame coefficient

    Position arguments:
    ship -- Ship object (see createShip)

    Keyword arguments:
    draft -- Ship draft (Design ship draft by default)

    Returned value:
    Ship main frame area coefficient
    """
    if draft is None:
        draft = ship.Draft

    shape, _ = placeShipShape(ship.Shape.copy(), draft,
                              Units.parseQuantity("0 deg"),
                              Units.parseQuantity("0 deg"))
    shape = getUnderwaterSide(shape)

    try:
        f = Part.Face(shape.slice(Vector(1,0,0), 0.0))
        area = f.Area
    except Part.OCCError:
        msg = QtGui.QApplication.translate(
            "ship_console",
            "Part.OCCError: Main frame area cannot be computed",
            None)
        App.Console.PrintError(msg + '\n')
        area = 0.0

    bbox = shape.BoundBox
    Area = (bbox.YMax - bbox.YMin) * (bbox.ZMax - bbox.ZMin)

    try:
        cm = area / Area
    except ZeroDivisionError:
        msg = QtGui.QApplication.translate(
            "ship_console",
            "ZeroDivisionError: Null area found during the main frame area"
            " coefficient computation!",
            None)
        App.Console.PrintError(msg + '\n')
        cm = 0.0

    return cm
Пример #5
0
    def accept(self):
        """Create the ship instance"""
        mw = self.getMainWindow()
        form = mw.findChild(QtGui.QWidget, "TaskPanel")
        form.ship = self.widget(QtGui.QComboBox, "Ship")
        form.weight = self.widget(QtGui.QLineEdit, "Weight")

        ship = self.ships[form.ship.currentIndex()]
        density = Units.parseQuantity(Locale.fromString(form.weight.text()))

        Tools.createWeight(self.shapes, ship, density)
        return True
Пример #6
0
def wettedArea(shape, draft, roll=Units.parseQuantity("0 deg"),
                             trim=Units.parseQuantity("0 deg")):
    """Compute the ship wetted area

    Position arguments:
    shape -- External faces of the ship hull
    draft -- Ship draft

    Keyword arguments:
    roll -- Roll angle (0 degrees by default)
    trim -- Trim angle (0 degrees by default)

    Returned value:
    The wetted area, i.e. The underwater side area
    """
    shape, _ = placeShipShape(shape.copy(), draft, roll, trim)
    shape = getUnderwaterSide(shape, force=False)

    area = 0.0
    for f in shape.Faces:
        area = area + f.Area
    return Units.Quantity(area, Units.Area)
Пример #7
0
def BMT(ship, draft=None, trim=Units.parseQuantity("0 deg")):
    """Calculate "ship Bouyance center" - "transversal metacenter" radius

    Position arguments:
    ship -- Ship object (see createShip)

    Keyword arguments:
    draft -- Ship draft (Design ship draft by default)
    trim -- Trim angle (0 degrees by default)

    Returned value:
    BMT radius
    """
    if draft is None:
        draft = ship.Draft

    roll = Units.parseQuantity("0 deg")
    _, B0, _ = displacement(ship, draft, roll, trim)


    nRoll = 2
    maxRoll = Units.parseQuantity("7 deg")

    BM = 0.0
    for i in range(nRoll):
        roll = (maxRoll / nRoll) * (i + 1)
        _, B1, _ = displacement(ship, draft, roll, trim)
        #     * M
        #    / \
        #   /   \  BM     ==|>   BM = (BB/2) / sin(alpha/2)
        #  /     \
        # *-------*
        #     BB
        BB = B1 - B0
        BB.x = 0.0
        # nRoll is actually representing the weight function
        BM += 0.5 * BB.Length / math.sin(math.radians(0.5 * roll)) / nRoll
    return Units.Quantity(BM, Units.Length)
Пример #8
0
def solve_point(W, COG, TW, VOLS, ship, tanks, roll, var_trim=True):
    """ Compute the ship GZ value.
    @param W Empty ship weight.
    @param COG Empty ship Center of mass.
    @param TW Tanks weights.
    @param VOLS List of tank volumes.
    @param tanks Considered tanks.
    @param roll Roll angle.
    @param var_trim True if the trim angle should be recomputed at each roll
    angle, False otherwise.
    @return GZ value, equilibrium draft, and equilibrium trim angle (0 if
    variable trim has not been requested)
    """    
    # Look for the equilibrium draft (and eventually the trim angle too)
    max_draft = Units.Quantity(ship.Shape.BoundBox.ZMax, Units.Length)
    draft = ship.Draft
    max_disp = Units.Quantity(ship.Shape.Volume, Units.Volume) * DENS * G
    if max_disp < W + TW:
        msg = QtGui.QApplication.translate(
            "ship_console",
            "Too much weight! The ship will never displace water enough",
            None)
        App.Console.PrintError(msg + ' ({} vs. {})\n'.format(
            (max_disp / G).UserString, ((W + TW) / G).UserString))
        return None

    trim = Units.parseQuantity("0 deg")
    for i in range(MAX_EQUILIBRIUM_ITERS):
        # Get the displacement, and the bouyance application point
        disp, B, _ = Hydrostatics.displacement(ship,
                                               draft,
                                               roll,
                                               trim)
        disp *= G

        # Add the tanks effect on the center of gravity
        mom_x = Units.Quantity(COG.x, Units.Length) * W
        mom_y = Units.Quantity(COG.y, Units.Length) * W
        mom_z = Units.Quantity(COG.z, Units.Length) * W
        for i,t in enumerate(tanks):
            tank_weight = VOLS[i] * t[1] * G
            tank_cog = t[0].Proxy.getCoG(t[0], VOLS[i], roll, trim)
            mom_x += Units.Quantity(tank_cog.x, Units.Length) * tank_weight
            mom_y += Units.Quantity(tank_cog.y, Units.Length) * tank_weight
            mom_z += Units.Quantity(tank_cog.z, Units.Length) * tank_weight
        cog_x = mom_x / (W + TW)
        cog_y = mom_y / (W + TW)
        cog_z = mom_z / (W + TW)
        # Compute the errors
        draft_error = -((disp - W - TW) / max_disp).Value
        R_x = cog_x - Units.Quantity(B.x, Units.Length)
        R_y = cog_y - Units.Quantity(B.y, Units.Length)
        R_z = cog_z - Units.Quantity(B.z, Units.Length)
        if not var_trim:
            trim_error = 0.0
        else:
            trim_error = -TRIM_RELAX_FACTOR * R_x / ship.Length

        # Check if we can tolerate the errors
        if abs(draft_error) < 0.01 and abs(trim_error) < 0.1:
            break

        # Get the new draft and trim
        draft += draft_error * max_draft
        trim += trim_error * Units.Degree

    # GZ should be provided in the Free surface oriented frame of reference
    c = math.cos(roll.getValueAs('rad'))
    s = math.sin(roll.getValueAs('rad'))
    return c * R_y - s * R_z, draft, trim
Пример #9
0
def areas(ship, n, draft=None,
                   roll=Units.parseQuantity("0 deg"),
                   trim=Units.parseQuantity("0 deg")):
    """Compute the ship transversal areas

    Position arguments:
    ship -- Ship object (see createShip)
    n -- Number of points to compute

    Keyword arguments:
    draft -- Ship draft (Design ship draft by default)
    roll -- Roll angle (0 degrees by default)
    trim -- Trim angle (0 degrees by default)

    Returned value:
    List of sections, each section contains 2 values, the x longitudinal
    coordinate, and the transversal area. If n < 2, an empty list will be
    returned.
    """
    if n < 2:
        return []

    if draft is None:
        draft = ship.Draft

    shape, _ = placeShipShape(ship.Shape.copy(), draft, roll, trim)
    shape = getUnderwaterSide(shape)

    # Sections distance computation
    bbox = shape.BoundBox
    xmin = bbox.XMin
    xmax = bbox.XMax
    dx = (xmax - xmin) / (n - 1.0)

    # Since we are computing the sections in the total length (not in the
    # length between perpendiculars), we can grant that the starting and
    # ending sections have null area
    areas = [(Units.Quantity(xmin, Units.Length),
              Units.Quantity(0.0, Units.Area))]
    # And since we just need to compute areas we will create boxes with its
    # front face at the desired transversal area position, computing the
    # common solid part, dividing it by faces, and getting only the desired
    # ones.
    App.Console.PrintMessage("Computing transversal areas...\n")
    App.Console.PrintMessage("Some Inventor representation errors can be"
                             " shown, please ignore them.\n")
    for i in range(1, n - 1):
        App.Console.PrintMessage("{0} / {1}\n".format(i, n - 2))
        x = xmin + i * dx
        try:
            f = Part.Face(shape.slice(Vector(1,0,0), x))
        except Part.OCCError:
            msg = QtGui.QApplication.translate(
                "ship_console",
                "Part.OCCError: Transversal area computation failed",
                None)
            App.Console.PrintError(msg + '\n')
            areas.append((Units.Quantity(x, Units.Length),
                          Units.Quantity(0.0, Units.Area)))
            continue
        # It is a valid face, so we can add this area
        areas.append((Units.Quantity(x, Units.Length),
                      Units.Quantity(f.Area, Units.Area)))
    # Last area is equal to zero (due to the total length usage)
    areas.append((Units.Quantity(xmax, Units.Length),
                  Units.Quantity(0.0, Units.Area)))
    App.Console.PrintMessage("Done!\n")
    return areas
Пример #10
0
    def get_boundary_layer_data(self):
        # mesh boundary layer
        # 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
        if not self.mesh_obj.MeshBoundaryLayerList:
            # print("  No mesh boundary layer setting document object.")
            pass
        else:
            Console.PrintMessage(
                "  Mesh boundary layers, we need to get the elements.\n")
            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.")
                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):
                                Console.PrintLog(
                                    "  One element of the mesh boundary layer {} is "
                                    "not an element of the Part to mesh.\n"
                                    "But we are going to try to find it in "
                                    "the Shape to mesh :-)\n".format(
                                        mr_obj.Name))
                                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
                                    # the method getElement(element) does not return Solid elements
                                    ele_shape = meshtools.get_element(
                                        sub[0], elems)
                                    found_element = meshtools.find_element_in_shape(
                                        self.part_obj.Shape, ele_shape)
                                    if found_element:  # also
                                        elems = found_element
                                    else:
                                        Console.PrintError(
                                            "One element of the mesh boundary layer {} could "
                                            "not be found in the Part to mesh. "
                                            "It will be ignored.\n".format(
                                                mr_obj.Name))
                                # 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:
                                    Console.PrintError(
                                        "The element {} of the mesh boundary "
                                        "layer {} has been added "
                                        "to another mesh boundary layer.\n".
                                        format(elems, mr_obj.Name))
                        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_n"] * 5 # tangential cell dimension
                        setting["hwall_t"] = setting["thickness"]

                        # 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:
                            # set a value for safety, it may works as background mesh cell size
                            setting["hfar"] = setting["thickness"]
                        # from face name -> face id is done in geo file write up
                        # TODO: fan angle setup is not implemented yet
                        if self.dimension == "2":
                            setting["EdgesList"] = belem_list
                        elif self.dimension == "3":
                            setting["FacesList"] = belem_list
                        else:
                            Console.PrintError(
                                "boundary layer is only supported for 2D and 3D mesh"
                            )
                        self.bl_setting_list.append(setting)
                    else:
                        Console.PrintError(
                            "The mesh boundary layer: {} is not used to create "
                            "the mesh because the reference list is empty.\n".
                            format(mr_obj.Name))
                else:
                    Console.PrintError(
                        "The mesh boundary layer: {} is not used to create "
                        "the mesh because the min thickness is 0.0 mm.\n".
                        format(mr_obj.Name))
            Console.PrintMessage("  {}\n".format(self.bl_setting_list))
Пример #11
0
def gz(lc, rolls, var_trim=True):
    """Compute the ship GZ stability curve

    Position arguments:
    lc -- Load condition spreadsheet
    rolls -- List of roll angles to compute

    Keyword arguments:
    var_trim -- True if the equilibrium trim should be computed for each roll
    angle, False if null trim angle can be used instead.

    Returned value:
    List of GZ curve points. Each point contains the GZ stability length, the
    equilibrium draft, and the equilibrium trim angle (0 deg if var_trim is
    False)
    """
    # B1 cell must be a ship
    # B2 cell must be the loading condition itself
    doc = lc.Document
    try:
        if lc not in doc.getObjectsByLabel(lc.get('B2')):
            return[]
        ships = doc.getObjectsByLabel(lc.get('B1'))
        if len(ships) != 1:
            if len(ships) == 0:
                msg = QtGui.QApplication.translate(
                    "ship_console",
                    "Wrong Ship label! (no instances labeled as"
                    "'{}' found)",
                    None)
                App.Console.PrintError(msg + '\n'.format(
                    lc.get('B1')))
            else:
                msg = QtGui.QApplication.translate(
                    "ship_console",
                    "Ambiguous Ship label! ({} instances labeled as"
                    "'{}' found)",
                    None)
                App.Console.PrintError(msg + '\n'.format(
                    len(ships),
                    lc.get('B1')))
            return[]
        ship = ships[0]
        if ship is None or not ship.PropertiesList.index("IsShip"):
            return[]
    except ValueError:
        return[]
    # Extract the weights and the tanks
    weights = []
    index = 6
    while True:
        try:
            ws = doc.getObjectsByLabel(lc.get('A{}'.format(index)))
        except ValueError:
            break
        index += 1
        if len(ws) != 1:
            if len(ws) == 0:
                msg = QtGui.QApplication.translate(
                    "ship_console",
                    "Wrong Weight label! (no instances labeled as"
                    "'{}' found)",
                    None)
                App.Console.PrintError(msg + '\n'.format(
                    lc.get('A{}'.format(index - 1))))
            else:
                msg = QtGui.QApplication.translate(
                    "ship_console",
                    "Ambiguous Weight label! ({} instances labeled as"
                    "'{}' found)",
                    None)
                App.Console.PrintError(msg + '\n'.format(
                    len(ws),
                    lc.get('A{}'.format(index - 1))))
            continue
        w = ws[0]
        try:
            if w is None or not w.PropertiesList.index("IsWeight"):
                msg = QtGui.QApplication.translate(
                    "ship_console",
                    "Invalid Weight! (the object labeled as"
                    "'{}' is not a weight)",
                    None)
                App.Console.PrintError(msg + '\n'.format(
                    len(ws),
                    lc.get('A{}'.format(index - 1))))
                continue
        except ValueError:
            continue
        weights.append(w)
    tanks = []
    index = 6
    while True:
        try:
            ts = doc.getObjectsByLabel(lc.get('C{}'.format(index)))
            dens = float(lc.get('D{}'.format(index)))
            level = float(lc.get('E{}'.format(index)))
            dens = Units.parseQuantity("{} kg/m^3".format(dens))
        except ValueError:
            break
        index += 1
        if len(ts) != 1:
            if len(ts) == 0:
                msg = QtGui.QApplication.translate(
                    "ship_console",
                    "Wrong Tank label! (no instances labeled as"
                    "'{}' found)",
                    None)
                App.Console.PrintError(msg + '\n'.format(
                    lc.get('C{}'.format(index - 1))))
            else:
                msg = QtGui.QApplication.translate(
                    "ship_console",
                    "Ambiguous Tank label! ({} instances labeled as"
                    "'{}' found)",
                    None)
                App.Console.PrintError(msg + '\n'.format(
                    len(ts),
                    lc.get('C{}'.format(index - 1))))
            continue
        t = ts[0]
        try:
            if t is None or not t.PropertiesList.index("IsTank"):
                msg = QtGui.QApplication.translate(
                    "ship_console",
                    "Invalid Tank! (the object labeled as"
                    "'{}' is not a tank)",
                    None)
                App.Console.PrintError(msg + '\n'.format(
                    len(ws),
                    lc.get('C{}'.format(index - 1))))
                continue
        except ValueError:
            continue
        tanks.append((t, dens, level))

    return solve(ship, weights, tanks, rolls, var_trim)
Пример #12
0
def getFromUi(value, unit, outputDim):
    quantity = Units.Quantity(str(value) + str(unit))
    return convert(quantity, outputDim)
Пример #13
0
 def get_region_data(self):
     # mesh regions
     if not self.mesh_obj.MeshRegionList:
         # print("  No mesh regions.")
         pass
     else:
         Console.PrintMessage(
             '  Mesh regions, we need to get the elements.\n')
         # 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:
             # other part obj might not have a Proxy, thus an exception would be raised
             if part.Shape.ShapeType == "Compound" and hasattr(
                     part, "Proxy"):
                 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.")
                     Console.PrintError(error_message + "\n")
                     # TODO: no gui popup because FreeCAD will be in a endless output loop
                     #       as long as the pop up is on --> maybe 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):
                             Console.PrintLog(
                                 "  One element of the meshregion {} is "
                                 "not an element of the Part to mesh.\n"
                                 "But we are going to try to find it in "
                                 "the Shape to mesh :-)\n".format(
                                     mr_obj.Name))
                             search_ele_in_shape_to_mesh = True
                         for elems in sub[1]:
                             # print(elems)  # elems --> element
                             if search_ele_in_shape_to_mesh:
                                 # we're going to try to find the element in the
                                 # Shape to mesh and use the found element as elems
                                 # the method getElement(element)
                                 # does not return Solid elements
                                 ele_shape = meshtools.get_element(
                                     sub[0], elems)
                                 found_element = meshtools.find_element_in_shape(
                                     self.part_obj.Shape, ele_shape)
                                 if found_element:
                                     elems = found_element
                                 else:
                                     Console.PrintError(
                                         "One element of the meshregion {} could not be found "
                                         "in the Part to mesh. It will be ignored.\n"
                                         .format(mr_obj.Name))
                             # print(elems)  # element
                             if elems not in self.ele_length_map:
                                 self.ele_length_map[
                                     elems] = Units.Quantity(
                                         mr_obj.CharacteristicLength).Value
                             else:
                                 Console.PrintError(
                                     "The element {} of the meshregion {} has "
                                     "been added to another mesh region.\n".
                                     format(elems, mr_obj.Name))
                 else:
                     Console.PrintError(
                         "The meshregion: {} is not used to create the mesh "
                         "because the reference list is empty.\n".format(
                             mr_obj.Name))
             else:
                 Console.PrintError(
                     "The meshregion: {} is not used to create the "
                     "mesh because the CharacteristicLength is 0.0 mm.\n".
                     format(mr_obj.Name))
         for eleml in self.ele_length_map:
             # the method getElement(element) does not return Solid elements
             ele_shape = meshtools.get_element(self.part_obj, eleml)
             ele_vertexes = meshtools.get_vertexes_by_element(
                 self.part_obj.Shape, ele_shape)
             self.ele_node_map[eleml] = ele_vertexes
         Console.PrintMessage("  {}\n".format(self.ele_length_map))
         Console.PrintMessage("  {}\n".format(self.ele_node_map))
Пример #14
0
 def check_material_keys(self):
     # FreeCAD units definition is at file end of src/Base/Unit.cpp
     if not self.material:
         FreeCAD.Console.PrintMessage(
             "For some reason all material data is empty!\n")
         self.material["Name"] = "NoName"
     if "Density" in self.material:
         if "Density" not in str(Units.Unit(self.material["Density"])):
             FreeCAD.Console.PrintMessage(
                 "Density in material data seems to have no unit "
                 "or a wrong unit (reset the value): {}\n".format(
                     self.material["Name"]))
             self.material["Density"] = "0 kg/m^3"
     else:
         FreeCAD.Console.PrintMessage("Density not found in {}\n".format(
             self.material["Name"]))
         self.material["Density"] = "0 kg/m^3"
     if self.obj.Category == "Solid":
         # mechanical properties
         if "YoungsModulus" in self.material:
             # unit type of YoungsModulus is Pressure
             if "Pressure" not in str(
                     Units.Unit(self.material["YoungsModulus"])):
                 FreeCAD.Console.PrintMessage(
                     "YoungsModulus in material data seems to have no unit "
                     "or a wrong unit (reset the value): {}\n".format(
                         self.material["Name"]))
                 self.material["YoungsModulus"] = "0 MPa"
         else:
             FreeCAD.Console.PrintMessage(
                 "YoungsModulus not found in {}\n".format(
                     self.material["Name"]))
             self.material["YoungsModulus"] = "0 MPa"
         if "PoissonRatio" in self.material:
             # PoissonRatio does not have a unit, but it is checked it there is no value at all
             try:
                 float(self.material["PoissonRatio"])
             except ValueError:
                 FreeCAD.Console.PrintMessage(
                     "PoissonRatio has wrong or no data (reset the value): {}\n"
                     .format(self.material["PoissonRatio"]))
                 self.material["PoissonRatio"] = "0"
         else:
             FreeCAD.Console.PrintMessage(
                 "PoissonRatio not found in {}\n".format(
                     self.material["Name"]))
             self.material["PoissonRatio"] = "0"
     if self.obj.Category == "Fluid":
         # Fluidic properties
         if "KinematicViscosity" in self.material:
             ki_vis = self.material["KinematicViscosity"]
             if "KinematicViscosity" not in str(Units.Unit(ki_vis)):
                 FreeCAD.Console.PrintMessage(
                     "KinematicViscosity in material data seems to have no unit "
                     "or a wrong unit (reset the value): {}\n".format(
                         self.material["Name"]))
                 self.material["KinematicViscosity"] = "0 m^2/s"
         else:
             FreeCAD.Console.PrintMessage(
                 "KinematicViscosity not found in {}\n".format(
                     self.material["Name"]))
             self.material["KinematicViscosity"] = "0 m^2/s"
         if "VolumetricThermalExpansionCoefficient" in self.material:
             # unit type VolumetricThermalExpansionCoefficient is ThermalExpansionCoefficient
             vol_ther_ex_co = self.material[
                 "VolumetricThermalExpansionCoefficient"]
             if "VolumetricThermalExpansionCoefficient" not in str(
                     Units.Unit(vol_ther_ex_co)):
                 FreeCAD.Console.PrintMessage(
                     "VolumetricThermalExpansionCoefficient in material data "
                     "seems to have no unit or a wrong unit (reset the value): {}\n"
                     .format(self.material["Name"]))
                 self.material[
                     "VolumetricThermalExpansionCoefficient"] = "0 m^3/m^3/K"
         else:
             FreeCAD.Console.PrintMessage(
                 "VolumetricThermalExpansionCoefficient not found in {}\n".
                 format(self.material["Name"]))
             self.material[
                 "VolumetricThermalExpansionCoefficient"] = "0 m^3/m^3/K"
     # Thermal properties
     if "ThermalConductivity" in self.material:
         if "ThermalConductivity" not in str(
                 Units.Unit(self.material["ThermalConductivity"])):
             FreeCAD.Console.PrintMessage(
                 "ThermalConductivity in material data seems to have no unit "
                 "or a wrong unit (reset the value): {}\n".format(
                     self.material["Name"]))
             self.material["ThermalConductivity"] = "0 W/m/K"
     else:
         FreeCAD.Console.PrintMessage(
             "ThermalConductivity not found in {}\n".format(
                 self.material["Name"]))
         self.material["ThermalConductivity"] = "0 W/m/K"
     if "ThermalExpansionCoefficient" in self.material:
         the_ex_co = self.material["ThermalExpansionCoefficient"]
         if "ThermalExpansionCoefficient" not in str(Units.Unit(the_ex_co)):
             FreeCAD.Console.PrintMessage(
                 "ThermalExpansionCoefficient in material data seems to have no unit "
                 "or a wrong unit (reset the value): {}\n".format(
                     self.material["Name"]))
             self.material["ThermalExpansionCoefficient"] = "0 um/m/K"
     else:
         FreeCAD.Console.PrintMessage(
             "ThermalExpansionCoefficient not found in {}\n".format(
                 self.material["Name"]))
         self.material["ThermalExpansionCoefficient"] = "0 um/m/K"
     if "SpecificHeat" in self.material:
         if "SpecificHeat" not in str(
                 Units.Unit(self.material["SpecificHeat"])):
             FreeCAD.Console.PrintMessage(
                 "SpecificHeat in material data seems to have no unit "
                 "or a wrong unit (reset the value): {}\n".format(
                     self.material["Name"]))
             self.material["SpecificHeat"] = "0 J/kg/K"
     else:
         FreeCAD.Console.PrintMessage(
             "SpecificHeat not found in {}\n".format(self.material["Name"]))
         self.material["SpecificHeat"] = "0 J/kg/K"
     FreeCAD.Console.PrintMessage("\n")
Пример #15
0
    def processRefinements(self):
        """ Process mesh refinements """
        mr_objs = CfdTools.getMeshRefinementObjs(self.mesh_obj)

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

        # Make list of all faces in meshed shape with original index
        mesh_face_list = list(
            zip(self.mesh_obj.Part.Shape.Faces,
                range(len(self.mesh_obj.Part.Shape.Faces))))

        # Make list of all boundary references
        CfdTools.cfdMessage("Matching boundary patches\n")
        boundary_face_list = []
        bc_group = None
        analysis_obj = CfdTools.getParentAnalysisObject(self.mesh_obj)
        if not analysis_obj:
            analysis_obj = CfdTools.getActiveAnalysis()
        if analysis_obj:
            bc_group = CfdTools.getCfdBoundaryGroup(analysis_obj)
        for bc_id, bc_obj in enumerate(bc_group):
            for ri, ref in enumerate(bc_obj.ShapeRefs):
                try:
                    bf = CfdTools.resolveReference(ref)
                except RuntimeError as re:
                    raise RuntimeError(
                        "Error processing boundary condition {}: {}".format(
                            bc_obj.Label, str(re)))
                for si, s in enumerate(bf):
                    boundary_face_list += [(sf, (bc_id, ri, si))
                                           for sf in s[0].Faces]

        # Match them up to faces in the main geometry
        bc_matched_faces = CfdTools.matchFaces(boundary_face_list,
                                               mesh_face_list)

        # Check for and filter duplicates
        bc_match_per_shape_face = [-1] * len(mesh_face_list)
        for k in range(len(bc_matched_faces)):
            match = bc_matched_faces[k][1]
            prev_k = bc_match_per_shape_face[match]
            if prev_k >= 0:
                nb, ri, si = bc_matched_faces[k][0]
                nb2, ri2, si2 = bc_matched_faces[prev_k][0]
                bc = bc_group[nb]
                bc2 = bc_group[nb2]
                CfdTools.cfdWarning(
                    "Boundary '{}' reference {}:{} also assigned as "
                    "boundary '{}' reference {}:{} - ignoring duplicate\n".
                    format(bc.Label, bc.ShapeRefs[ri][0].Name,
                           bc.ShapeRefs[ri][1][si], bc2.Label,
                           bc.ShapeRefs[ri][0].Name, bc.ShapeRefs[ri][1][si]))
            else:
                bc_match_per_shape_face[match] = k

        # Match relevant mesh regions to the shape being meshed: boundary layer mesh regions for cfMesh,
        # all surface mesh refinements for snappyHexMesh, and extrusion patches for all meshers.
        # For cfMesh, surface mesh refinements are written as separate surfaces so need not be matched
        CfdTools.cfdMessage("Matching mesh refinement regions\n")
        mr_face_list = []
        for mr_id, mr_obj in enumerate(mr_objs):
            if mr_obj.Extrusion or (
                    self.mesh_obj.MeshUtility == 'cfMesh'
                    and not mr_obj.Internal and mr_obj.NumberLayers > 0) or (
                        self.mesh_obj.MeshUtility == 'snappyHexMesh'
                        and not mr_obj.Internal):
                for ri, r in enumerate(mr_obj.ShapeRefs):
                    try:
                        bf = CfdTools.resolveReference(r)
                    except RuntimeError as re:
                        raise RuntimeError(
                            "Error processing mesh refinement {}: {}".format(
                                mr_obj.Label, str(re)))
                    for si, s in enumerate(bf):
                        mr_face_list += [(f, (mr_id, ri, si))
                                         for f in s[0].Faces]

        # Match them up to the primary geometry
        mr_matched_faces = CfdTools.matchFaces(mr_face_list, mesh_face_list)

        # Check for and filter duplicates
        mr_match_per_shape_face = [-1] * len(mesh_face_list)
        for k in range(len(mr_matched_faces)):
            match = mr_matched_faces[k][1]
            prev_k = mr_match_per_shape_face[match]
            if prev_k >= 0:
                nr, ri, si = mr_matched_faces[k][0]
                nr2, ri2, si2 = mr_matched_faces[prev_k][0]
                CfdTools.cfdWarning(
                    "Mesh refinement '{}' reference {}:{} also assigned as "
                    "mesh refinement '{}' reference {}:{} - ignoring duplicate\n"
                    .format(mr_objs[nr].Label,
                            mr_objs[nr].ShapeRefs[ri][0].Name,
                            mr_objs[nr].ShapeRefs[ri][1][si],
                            mr_objs[nr2].Label,
                            mr_objs[nr2].ShapeRefs[ri2][0].Name,
                            mr_objs[nr2].ShapeRefs[ri2][1][si2]))
            else:
                mr_match_per_shape_face[match] = k

        self.patch_faces = []
        self.patch_names = []
        for k in range(len(bc_group) + 1):
            self.patch_faces.append([])
            self.patch_names.append([])
            for l in range(len(mr_objs) + 1):
                self.patch_faces[k].append([])
                self.patch_names[k].append("patch_" + str(k) + "_" + str(l))
        for i in range(len(mesh_face_list)):
            k = bc_match_per_shape_face[i]
            l = mr_match_per_shape_face[i]
            nb = -1
            nr = -1
            if k >= 0:
                nb, bri, bsi = bc_matched_faces[k][0]
            if l >= 0:
                nr, rri, ssi = mr_matched_faces[l][0]
            self.patch_faces[nb + 1][nr + 1].append(i)

        # For gmsh, match mesh refinement with vertices in original mesh
        mr_matched_vertices = []
        if self.mesh_obj.MeshUtility == 'gmsh':
            # Make list of all vertices in meshed shape with original index
            mesh_vertices_list = list(
                zip(self.mesh_obj.Part.Shape.Vertexes,
                    range(len(self.mesh_obj.Part.Shape.Vertexes))))

            CfdTools.cfdMessage("Matching mesh refinements\n")
            mr_vertices_list = []
            for mr_id, mr_obj in enumerate(mr_objs):
                if not mr_obj.Internal:
                    for ri, r in enumerate(mr_obj.ShapeRefs):
                        try:
                            bf = CfdTools.resolveReference(r)
                        except RuntimeError as re:
                            raise RuntimeError(
                                "Error processing mesh refinement {}: {}".
                                format(mr_obj.Label, str(re)))
                        for si, s in enumerate(bf):
                            mr_vertices_list += [(v, (mr_id, ri, si))
                                                 for v in s[0].Vertexes]

            mr_matched_vertices = CfdTools.matchFaces(mr_vertices_list,
                                                      mesh_vertices_list)
            self.ele_length_map = {}
            self.ele_node_map = {}

        # For snappyHexMesh, also match surface mesh refinements to the boundary conditions, to identify boundary
        # conditions on supplementary geometry defined by the surface mesh refinements
        # Also matches baffles to surface mesh refinements
        bc_mr_matched_faces = []
        if self.mesh_obj.MeshUtility == 'snappyHexMesh':
            bc_mr_matched_faces = CfdTools.matchFaces(boundary_face_list,
                                                      mr_face_list)

        # Handle baffles
        for bc_id, bc_obj in enumerate(bc_group):
            if bc_obj.BoundaryType == 'baffle':
                baffle_matches = [
                    m for m in bc_mr_matched_faces if m[0][0] == bc_id
                ]
                mr_match_per_baffle_ref = []
                for r in bc_obj.ShapeRefs:
                    mr_match_per_baffle_ref += [[-1] * len(r[1])]
                for m in baffle_matches:
                    mr_match_per_baffle_ref[m[0][1]][m[0][2]] = m[1][0]
                # For each mesh region, the refs that are part of this baffle
                baffle_patch_refs = [[] for ri in range(len(mr_objs) + 1)]
                for ri, mr in enumerate(mr_match_per_baffle_ref):
                    for si, mri in enumerate(mr_match_per_baffle_ref[ri]):
                        baffle_patch_refs[mri + 1].append(
                            (bc_obj.ShapeRefs[ri][0],
                             (bc_obj.ShapeRefs[ri][1][si], )))

                # Write these geometries
                for ri, refs in enumerate(baffle_patch_refs):
                    try:
                        shape = CfdTools.makeShapeFromReferences(refs)
                    except RuntimeError as re:
                        raise RuntimeError(
                            "Error processing baffle {}: {}".format(
                                bc_obj.Label, str(re)))
                    solid_name = bc_obj.Name + "_" + str(ri)
                    if shape:
                        CfdTools.cfdMessage(
                            "Triangulating baffle {}, section {}\n".format(
                                bc_obj.Label, ri))
                        writeSurfaceMeshFromShape(shape, self.triSurfaceDir,
                                                  solid_name, self.mesh_obj)

                        if ri > 0:  # The parts of the baffle corresponding to a surface mesh region obj
                            mr_obj = mr_objs[ri - 1]
                            refinement_level = CfdTools.relLenToRefinementLevel(
                                mr_obj.RelativeLength)
                            edge_level = CfdTools.relLenToRefinementLevel(
                                mr_obj.RegionEdgeRefinement)
                        else:  # The parts of the baffle with no refinement obj
                            refinement_level = 0
                            edge_level = 0
                        snappy_settings['MeshRegions'][solid_name] = {
                            'RefinementLevel': refinement_level,
                            'EdgeRefinementLevel': edge_level,
                            'MaxRefinementLevel': max(refinement_level,
                                                      edge_level),
                            'Baffle': True
                        }

        for mr_id, mr_obj in enumerate(mr_objs):
            Internal = mr_obj.Internal
            mr_rellen = mr_obj.RelativeLength
            if mr_rellen > 1.0:
                mr_rellen = 1.0
                FreeCAD.Console.PrintError(
                    "The mesh refinement region '{}' 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 mesh refinement region '{}' should not use a relative length smaller "
                    "than 0.001.\n".format(mr_obj.Name))

            if self.mesh_obj.MeshUtility == 'gmsh':
                # Generate element maps for gmsh
                if not Internal:
                    mesh_vertex_idx = [
                        mf[1] for mf in mr_matched_vertices
                        if mf[0][0] == mr_id
                    ]
                    self.ele_length_map[mr_obj.Name] = mr_rellen * self.clmax
                    self.ele_node_map[mr_obj.Name] = mesh_vertex_idx
            else:
                # Find any matches with boundary conditions; mark those matching baffles for removal
                bc_matches = [
                    m for m in bc_mr_matched_faces if m[1][0] == mr_id
                ]
                bc_match_per_mr_ref = []
                for ri, r in enumerate(mr_obj.ShapeRefs):
                    bc_match_per_mr_ref.append([-1] * len(r[1]))
                for m in bc_matches:
                    bc_match_per_mr_ref[m[1][1]][m[1][2]] = -2 if bc_group[
                        m[0][0]].BoundaryType == 'baffle' else m[0][0]

                # Unmatch those in primary geometry
                main_geom_matches = [
                    m for m in mr_matched_faces if m[0][0] == mr_id
                ]
                for m in main_geom_matches:
                    bc_match_per_mr_ref[m[0][1]][m[0][2]] = -1

                # For each boundary, the refs that are part of this mesh region
                mr_patch_refs = [[] for ri in range(len(bc_group) + 1)]
                for ri, m in enumerate(bc_match_per_mr_ref):
                    for si, bci in enumerate(m):
                        if bci > -2:
                            mr_patch_refs[bci + 1].append(
                                (mr_obj.ShapeRefs[ri][0],
                                 (mr_obj.ShapeRefs[ri][1][si], )))

                # Loop over and write the sub-sections of this mesh object
                for bi in range(len(mr_patch_refs)):
                    if len(mr_patch_refs[bi]) and not mr_obj.Extrusion:
                        if bi == 0:
                            mr_patch_name = mr_obj.Name
                        else:
                            mr_patch_name = self.patch_names[bi][mr_id + 1]

                        CfdTools.cfdMessage(
                            "Triangulating mesh refinement region {}, section {}\n"
                            .format(mr_obj.Label, bi))

                        try:
                            shape = CfdTools.makeShapeFromReferences(
                                mr_patch_refs[bi])
                        except RuntimeError as re:
                            raise RuntimeError(
                                "Error processing mesh refinement region {}: {}"
                                .format(mr_obj.Label, str(re)))
                        if shape:
                            writeSurfaceMeshFromShape(shape,
                                                      self.triSurfaceDir,
                                                      mr_patch_name,
                                                      self.mesh_obj)

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

                        elif self.mesh_obj.MeshUtility == 'snappyHexMesh':
                            if not Internal:
                                edge_level = CfdTools.relLenToRefinementLevel(
                                    mr_obj.RegionEdgeRefinement)
                                snappy_settings['MeshRegions'][
                                    mr_patch_name] = {
                                        'RefinementLevel':
                                        refinement_level,
                                        'EdgeRefinementLevel':
                                        edge_level,
                                        'MaxRefinementLevel':
                                        max(refinement_level, edge_level),
                                        'Baffle':
                                        False
                                    }
                            else:
                                snappy_settings['InternalRegions'][
                                    mr_patch_name] = {
                                        'RefinementLevel': refinement_level
                                    }

            # In addition, for cfMesh and SnappyHesMesh, record matched boundary layer patches

            if (self.mesh_obj.MeshUtility == 'cfMesh' or self.mesh_obj.MeshUtility == 'snappyHexMesh') \
                    and mr_obj.NumberLayers > 0 and not Internal and not mr_obj.Extrusion:

                for k in range(len(self.patch_faces)):
                    if len(self.patch_faces[k][mr_id + 1]):
                        # 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))

                        if self.mesh_obj.MeshUtility == 'cfMesh':
                            cf_settings['BoundaryLayers'][self.patch_names[k][mr_id + 1]] = \
                            {
                                'NumberLayers': mr_obj.NumberLayers,
                                'ExpansionRatio': expratio,
                                'FirstLayerHeight': self.scale * Units.Quantity(mr_obj.FirstLayerHeight).Value
                            }
                        elif self.mesh_obj.MeshUtility == 'snappyHexMesh':
                            snappy_settings['BoundaryLayers'][self.patch_names[k][mr_id + 1]] = \
                            {
                                'NumberLayers': mr_obj.NumberLayers,
                                'ExpansionRatio': expratio,
                                # 'FinalLayerHeight': self.scale * Units.Quantity(mr_obj.FinalLayerHeight).Value
                            }
Пример #16
0
def parse(pathobj):
    # pylint: disable=global-statement
    global PRECISION
    global UNIT_FORMAT
    global UNIT_SPEED_FORMAT

    out = ""
    lastcommand = None

    precision_string = '.' + str(PRECISION) + 'f'

    # params = ['X','Y','Z','A','B','I','J','K','F','S'] #This list control the order of parameters
    params = ['X', 'Y', 'Z', 'A', 'B', 'I', 'J', 'F', 'S', 'T', 'Q', 'R', 'L']

    if hasattr(pathobj, "Group"):  # We have a compound or project.
        if OUTPUT_COMMENTS:
            out += linenumber() + "(compound: " + pathobj.Label + ")\n"
        for p in pathobj.Group:
            out += parse(p)
        return out
    else:  # parsing simple path

        if not hasattr(
                pathobj,
                "Path"):  # groups might contain non-path things like stock.
            return out

        if OUTPUT_COMMENTS:
            out += linenumber() + "(Path: " + pathobj.Label + ")\n"

        for c in pathobj.Path.Commands:
            outstring = []
            command = c.Name
            outstring.append(command)
            # if modal: only print the command if it is not the same as the last one
            if MODAL is True:
                if command == lastcommand:
                    outstring.pop(0)

            # Now add the remaining parameters in order
            for param in params:
                if param in c.Parameters:
                    if param == 'F':
                        speed = Units.Quantity(c.Parameters['F'],
                                               FreeCAD.Units.Velocity)
                        if speed.getValueAs(UNIT_SPEED_FORMAT) > 0.0:
                            outstring.append(param + format(
                                float(speed.getValueAs(UNIT_SPEED_FORMAT)),
                                precision_string))
                    elif param == 'S':
                        outstring.append(
                            param +
                            format(c.Parameters[param], precision_string))
                    elif param == 'T':
                        outstring.append(
                            param +
                            format(c.Parameters['T'], precision_string))
                    else:
                        pos = Units.Quantity(c.Parameters[param],
                                             FreeCAD.Units.Length)
                        outstring.append(
                            param + format(float(pos.getValueAs(UNIT_FORMAT)),
                                           precision_string))

            # store the latest command
            lastcommand = command

            # Check for Tool Change:
            if command == 'M6':
                if OUTPUT_COMMENTS:
                    out += linenumber() + "(begin toolchange)\n"
                for line in TOOL_CHANGE.splitlines(True):
                    out += linenumber() + line

            if command == "message":
                if OUTPUT_COMMENTS is False:
                    out = []
                else:
                    outstring.pop(0)  # remove the command

            # prepend a line number and append a newline
            if len(outstring) >= 1:
                if OUTPUT_LINE_NUMBERS:
                    outstring.insert(0, (linenumber()))

                # append the line to the final output
                for w in outstring:
                    out += w + COMMAND_SPACE
                out = out.strip() + "\n"

        return out
Пример #17
0
def DVBalloonTest():
    path = os.path.dirname(os.path.abspath(__file__))
    print('TDBalloon path: ' + path)
    templateFileSpec = path + '/TestTemplate.svg'

    FreeCAD.newDocument("TDBalloon")
    FreeCAD.setActiveDocument("TDBalloon")
    FreeCAD.ActiveDocument = FreeCAD.getDocument("TDBalloon")

    #make source feature
    box = FreeCAD.ActiveDocument.addObject("Part::Box", "Box")
    sphere = FreeCAD.ActiveDocument.addObject("Part::Sphere", "Sphere")

    #make a page
    page = FreeCAD.ActiveDocument.addObject('TechDraw::DrawPage', 'Page')
    FreeCAD.ActiveDocument.addObject('TechDraw::DrawSVGTemplate', 'Template')
    FreeCAD.ActiveDocument.Template.Template = templateFileSpec
    FreeCAD.ActiveDocument.Page.Template = FreeCAD.ActiveDocument.Template
    page.Scale = 5.0
    #    page.ViewObject.show()   # unit tests run in console mode

    #make Views
    view1 = FreeCAD.ActiveDocument.addObject('TechDraw::DrawViewPart', 'View')
    FreeCAD.ActiveDocument.View.Source = [FreeCAD.ActiveDocument.Box]
    rc = page.addView(view1)
    view1.X = Units.Quantity(30.0, Units.Length)
    view1.Y = Units.Quantity(150.0, Units.Length)
    view2 = FreeCAD.activeDocument().addObject('TechDraw::DrawViewPart',
                                               'View001')
    FreeCAD.activeDocument().View001.Source = [FreeCAD.activeDocument().Sphere]
    rc = page.addView(view2)
    view2.X = Units.Quantity(220.0, Units.Length)
    view2.Y = Units.Quantity(150.0, Units.Length)
    FreeCAD.ActiveDocument.recompute()

    print("Place balloon")
    balloon1 = FreeCAD.ActiveDocument.addObject('TechDraw::DrawViewBalloon',
                                                'Balloon1')
    balloon1.SourceView = view1
    balloon1.OriginIsSet = 1
    balloon1.OriginX = view1.X + Units.Quantity(20.0, Units.Length)
    balloon1.OriginY = view1.Y + Units.Quantity(20.0, Units.Length)
    balloon1.Text = "1"
    balloon1.Y = balloon1.OriginX + Units.Quantity(20.0, Units.Length)
    balloon1.X = balloon1.OriginY + Units.Quantity(20.0, Units.Length)

    print("adding balloon1 to page")
    rc = page.addView(balloon1)

    balloon2 = FreeCAD.ActiveDocument.addObject('TechDraw::DrawViewBalloon',
                                                'Balloon2')
    balloon2.SourceView = view2
    balloon2.OriginIsSet = 1
    balloon2.OriginX = view2.X + Units.Quantity(20.0, Units.Length)
    balloon2.OriginY = view2.Y + Units.Quantity(20.0, Units.Length)
    balloon2.Text = "2"
    balloon2.Y = balloon2.OriginX + Units.Quantity(20.0, Units.Length)
    balloon2.X = balloon2.OriginY + Units.Quantity(20.0, Units.Length)

    print("adding balloon2 to page")
    rc = page.addView(balloon2)

    FreeCAD.ActiveDocument.recompute()

    rc = False
    if ("Up-to-date" in balloon2.State) and ("Up-to-date" in balloon2.State):
        rc = True
    FreeCAD.closeDocument("TDBalloon")
    return rc
Пример #18
0
    def action(self, arg):
        """Handle the 3D scene events.

        This is installed as an EventCallback in the Inventor view.

        Parameters
        ----------
        arg: dict
            Dictionary with strings that indicates the type of event received
            from the 3D view.
        """
        import DraftGeomUtils
        plane = App.DraftWorkingPlane

        if arg["Type"] == "SoKeyboardEvent":
            if arg["Key"] == "ESCAPE":
                self.finish()
        elif arg["Type"] == "SoLocation2Event":  # mouse movement detection
            self.point, ctrlPoint, info = gui_tool_utils.getPoint(self, arg)
            # this is to make sure radius is what you see on screen
            if self.center and DraftVecUtils.dist(self.point, self.center) > 0:
                viewdelta = DraftVecUtils.project(self.point.sub(self.center),
                                                  plane.axis)
                if not DraftVecUtils.isNull(viewdelta):
                    self.point = self.point.add(viewdelta.negative())
            if self.step == 0:  # choose center
                if gui_tool_utils.hasMod(arg, gui_tool_utils.MODALT):
                    if not self.altdown:
                        self.altdown = True
                        self.ui.switchUi(True)
                    else:
                        if self.altdown:
                            self.altdown = False
                            self.ui.switchUi(False)
            elif self.step == 1:  # choose radius
                if len(self.tangents) == 2:
                    cir = DraftGeomUtils.circleFrom2tan1pt(
                        self.tangents[0], self.tangents[1], self.point)
                    _c = DraftGeomUtils.findClosestCircle(self.point, cir)
                    self.center = _c.Center
                    self.arctrack.setCenter(self.center)
                elif self.tangents and self.tanpoints:
                    cir = DraftGeomUtils.circleFrom1tan2pt(
                        self.tangents[0], self.tanpoints[0], self.point)
                    _c = DraftGeomUtils.findClosestCircle(self.point, cir)
                    self.center = _c.Center
                    self.arctrack.setCenter(self.center)
                if gui_tool_utils.hasMod(arg, gui_tool_utils.MODALT):
                    if not self.altdown:
                        self.altdown = True
                    if info:
                        ob = self.doc.getObject(info['Object'])
                        num = int(info['Component'].lstrip('Edge')) - 1
                        ed = ob.Shape.Edges[num]
                        if len(self.tangents) == 2:
                            cir = DraftGeomUtils.circleFrom3tan(
                                self.tangents[0], self.tangents[1], ed)
                            cl = DraftGeomUtils.findClosestCircle(
                                self.point, cir)
                            self.center = cl.Center
                            self.rad = cl.Radius
                            self.arctrack.setCenter(self.center)
                        else:
                            self.rad = self.center.add(
                                DraftGeomUtils.findDistance(
                                    self.center, ed).sub(self.center)).Length
                    else:
                        self.rad = DraftVecUtils.dist(self.point, self.center)
                else:
                    if self.altdown:
                        self.altdown = False
                    self.rad = DraftVecUtils.dist(self.point, self.center)
                self.ui.setRadiusValue(self.rad, "Length")
                self.arctrack.setRadius(self.rad)
                self.linetrack.p1(self.center)
                self.linetrack.p2(self.point)
                self.linetrack.on()
            elif (self.step == 2):  # choose first angle
                currentrad = DraftVecUtils.dist(self.point, self.center)
                if currentrad != 0:
                    angle = DraftVecUtils.angle(plane.u,
                                                self.point.sub(self.center),
                                                plane.axis)
                else:
                    angle = 0
                self.linetrack.p2(
                    DraftVecUtils.scaleTo(self.point.sub(self.center),
                                          self.rad).add(self.center))
                self.ui.setRadiusValue(math.degrees(angle), unit="Angle")
                self.firstangle = angle
            else:
                # choose second angle
                currentrad = DraftVecUtils.dist(self.point, self.center)
                if currentrad != 0:
                    angle = DraftVecUtils.angle(plane.u,
                                                self.point.sub(self.center),
                                                plane.axis)
                else:
                    angle = 0
                self.linetrack.p2(
                    DraftVecUtils.scaleTo(self.point.sub(self.center),
                                          self.rad).add(self.center))
                self.updateAngle(angle)
                self.ui.setRadiusValue(math.degrees(self.angle), unit="Angle")
                self.arctrack.setApertureAngle(self.angle)

            gui_tool_utils.redraw3DView()

        elif arg["Type"] == "SoMouseButtonEvent":  # mouse click
            if arg["State"] == "DOWN" and arg["Button"] == "BUTTON1":
                if self.point:
                    if self.step == 0:  # choose center
                        if not self.support:
                            gui_tool_utils.getSupport(arg)
                            (self.point, ctrlPoint,
                             info) = gui_tool_utils.getPoint(self, arg)
                        if gui_tool_utils.hasMod(arg, gui_tool_utils.MODALT):
                            snapped = self.view.getObjectInfo(
                                (arg["Position"][0], arg["Position"][1]))
                            if snapped:
                                ob = self.doc.getObject(snapped['Object'])
                                num = int(
                                    snapped['Component'].lstrip('Edge')) - 1
                                ed = ob.Shape.Edges[num]
                                self.tangents.append(ed)
                                if len(self.tangents) == 2:
                                    self.arctrack.on()
                                    self.ui.radiusUi()
                                    self.step = 1
                                    self.ui.setNextFocus()
                                    self.linetrack.on()
                                    _msg(translate("draft", "Pick radius"))
                        else:
                            if len(self.tangents) == 1:
                                self.tanpoints.append(self.point)
                            else:
                                self.center = self.point
                                self.node = [self.point]
                                self.arctrack.setCenter(self.center)
                                self.linetrack.p1(self.center)
                                self.linetrack.p2(
                                    self.view.getPoint(arg["Position"][0],
                                                       arg["Position"][1]))
                            self.arctrack.on()
                            self.ui.radiusUi()
                            self.step = 1
                            self.ui.setNextFocus()
                            self.linetrack.on()
                            _msg(translate("draft", "Pick radius"))
                            if self.planetrack:
                                self.planetrack.set(self.point)
                    elif self.step == 1:  # choose radius
                        if self.closedCircle:
                            self.drawArc()
                        else:
                            self.ui.labelRadius.setText(
                                translate("draft", "Start angle"))
                            self.ui.radiusValue.setToolTip(
                                translate("draft", "Start angle"))
                            self.ui.radiusValue.setText(
                                U.Quantity(0, U.Angle).UserString)
                            self.linetrack.p1(self.center)
                            self.linetrack.on()
                            self.step = 2
                            _msg(translate("draft", "Pick start angle"))
                    elif self.step == 2:  # choose first angle
                        self.ui.labelRadius.setText(
                            translate("draft", "Aperture angle"))
                        self.ui.radiusValue.setToolTip(
                            translate("draft", "Aperture angle"))
                        self.step = 3
                        # scale center->point vector for proper display
                        # u = DraftVecUtils.scaleTo(self.point.sub(self.center), self.rad) obsolete?
                        self.arctrack.setStartAngle(self.firstangle)
                        _msg(translate("draft", "Pick aperture"))
                    else:  # choose second angle
                        self.step = 4
                        self.drawArc()
Пример #19
0
    def processExtrusions(self):
        """ Find and process any extrusion objects """

        twoD_extrusion_objs = []
        other_extrusion_objs = []
        mesh_refinements = CfdTools.getMeshRefinementObjs(self.mesh_obj)
        self.extrusion_settings['ExtrusionsPresent'] = False
        self.extrusion_settings['ExtrudeTo2D'] = False
        self.extrusion_settings['Extrude2DPlanar'] = False
        for mr in mesh_refinements:
            if mr.Extrusion:
                self.extrusion_settings['ExtrusionsPresent'] = True
                if mr.ExtrusionType == '2DPlanar' or mr.ExtrusionType == '2DWedge':
                    twoD_extrusion_objs.append(mr)
                else:
                    other_extrusion_objs.append(mr)
                if mr.ExtrusionType == '2DPlanar':
                    self.extrusion_settings['Extrude2DPlanar'] = True

        if len(twoD_extrusion_objs) > 1:
            raise RuntimeError(
                "For 2D meshing, there must be exactly one 2D mesh extrusion object."
            )
        elif len(twoD_extrusion_objs) == 1:
            self.extrusion_settings['ExtrudeTo2D'] = True
        all_extrusion_objs = other_extrusion_objs + twoD_extrusion_objs  # Ensure 2D extrusion happens last

        self.extrusion_settings['Extrusions'] = []
        for extrusion_obj in all_extrusion_objs:
            extrusion_shape = extrusion_obj.Shape
            this_extrusion_settings = {}
            if len(extrusion_shape.Faces) == 0:
                raise RuntimeError("Extrusion object '{}' is empty.".format(
                    extrusion_obj.Label))

            this_extrusion_settings[
                'KeepExistingMesh'] = extrusion_obj.KeepExistingMesh
            if extrusion_obj.ExtrusionType == '2DPlanar' or extrusion_obj.ExtrusionType == '2DWedge':
                this_extrusion_settings['KeepExistingMesh'] = False
                all_faces_planar = True
                for faces in extrusion_shape.Faces:
                    if not isinstance(faces.Surface, Part.Plane):
                        all_faces_planar = False
                        break
                if not all_faces_planar:
                    raise RuntimeError(
                        "2D mesh extrusion surface must be a flat plane.")

            normal = extrusion_shape.Faces[0].Surface.Axis
            normal.multiply(1.0 / normal.Length)
            this_extrusion_settings['Normal'] = (normal.x, normal.y, normal.z)
            this_extrusion_settings[
                'ExtrusionType'] = extrusion_obj.ExtrusionType

            # Get the names of the faces being extruded
            mri = mesh_refinements.index(extrusion_obj)
            efl = []
            for l, ff in enumerate(self.patch_faces):
                f = ff[mri + 1]
                if len(f):
                    efl.append(self.patch_names[l][mri + 1])

            if not efl:
                raise RuntimeError(
                    "Extrusion patch for '{}' could not be found in the shape being meshed."
                    .format(extrusion_obj.Label))
            this_extrusion_settings['FrontFaceList'] = tuple(efl)
            this_extrusion_settings['BackFace'] = efl[0] + '_back'

            this_extrusion_settings[
                'Distance'] = extrusion_obj.ExtrusionThickness.getValueAs('m')
            this_extrusion_settings[
                'Angle'] = extrusion_obj.ExtrusionAngle.getValueAs('deg')
            this_extrusion_settings[
                'NumLayers'] = extrusion_obj.ExtrusionLayers
            this_extrusion_settings[
                'ExpansionRatio'] = extrusion_obj.ExtrusionRatio
            this_extrusion_settings['AxisPoint'] = \
                tuple(Units.Quantity(p, Units.Length).getValueAs('m') for p in extrusion_obj.ExtrusionAxisPoint)

            axis_direction = extrusion_obj.ExtrusionAxisDirection

            # Flip axis if necessary to go in same direction as patch normal (otherwise negative volume cells result)
            if len(extrusion_shape.Faces) > 0:
                in_plane_vector = extrusion_shape.Faces[
                    0].CenterOfMass - extrusion_obj.ExtrusionAxisPoint
                extrusion_normal = extrusion_obj.ExtrusionAxisDirection.cross(
                    in_plane_vector)
                face_normal = extrusion_shape.Faces[0].normalAt(0.5, 0.5)
                if extrusion_normal.dot(face_normal) < 0:
                    axis_direction = -axis_direction

            this_extrusion_settings['AxisDirection'] = tuple(
                d for d in axis_direction)
            self.extrusion_settings['Extrusions'].append(
                this_extrusion_settings)
Пример #20
0
    def writeMeshCase(self):
        """ Collect case settings, and finally build a runnable case. """
        CfdTools.cfdMessage(
            "Populating mesh dictionaries in folder {}\n".format(
                self.meshCaseDir))

        # cfMesh settings
        if self.mesh_obj.MeshUtility == "cfMesh":
            self.cf_settings['ClMax'] = self.clmax * self.scale
            if len(self.cf_settings['BoundaryLayers']) > 0:
                self.cf_settings['BoundaryLayerPresent'] = True
            else:
                self.cf_settings['BoundaryLayerPresent'] = False
            if len(self.cf_settings["InternalRegions"]) > 0:
                self.cf_settings['InternalRefinementRegionsPresent'] = True
            else:
                self.cf_settings['InternalRefinementRegionsPresent'] = False

        # SnappyHexMesh settings
        elif self.mesh_obj.MeshUtility == "snappyHexMesh":
            bound_box = self.part_obj.Shape.BoundBox
            bC = 5  # Number of background mesh buffer cells
            x_min = (bound_box.XMin - bC * self.clmax) * self.scale
            x_max = (bound_box.XMax + bC * self.clmax) * self.scale
            y_min = (bound_box.YMin - bC * self.clmax) * self.scale
            y_max = (bound_box.YMax + bC * self.clmax) * self.scale
            z_min = (bound_box.ZMin - bC * self.clmax) * self.scale
            z_max = (bound_box.ZMax + bC * self.clmax) * self.scale
            cells_x = int(math.ceil(bound_box.XLength / self.clmax) + 2 * bC)
            cells_y = int(math.ceil(bound_box.YLength / self.clmax) + 2 * bC)
            cells_z = int(math.ceil(bound_box.ZLength / self.clmax) + 2 * bC)

            snappy_settings = self.snappy_settings
            snappy_settings['BlockMesh'] = {
                "xMin": x_min,
                "xMax": x_max,
                "yMin": y_min,
                "yMax": y_max,
                "zMin": z_min,
                "zMax": z_max,
                "cellsX": cells_x,
                "cellsY": cells_y,
                "cellsZ": cells_z
            }

            if len(self.snappy_settings['BoundaryLayers']) > 0:
                self.snappy_settings['BoundaryLayerPresent'] = True
            else:
                self.snappy_settings['BoundaryLayerPresent'] = False

            if self.mesh_obj.ImplicitEdgeDetection:
                snappy_settings['ImplicitEdgeDetection'] = True
            else:
                snappy_settings['ImplicitEdgeDetection'] = False

            inside_x = Units.Quantity(
                self.mesh_obj.PointInMesh.get('x')).Value * self.scale
            inside_y = Units.Quantity(
                self.mesh_obj.PointInMesh.get('y')).Value * self.scale
            inside_z = Units.Quantity(
                self.mesh_obj.PointInMesh.get('z')).Value * self.scale

            shape_patch_names_list = []
            for k in range(len(self.patch_faces)):
                for j in range(len(self.patch_faces[k])):
                    if len(self.patch_faces[k][j]):
                        shape_patch_names_list.append(self.patch_names[k][j])

            snappy_settings['ShapePatchNames'] = tuple(shape_patch_names_list)
            snappy_settings[
                'EdgeRefinementLevel'] = CfdTools.relLenToRefinementLevel(
                    self.mesh_obj.EdgeRefinement)
            snappy_settings['PointInMesh'] = \
                {
                    "x": inside_x,
                    "y": inside_y,
                    "z": inside_z
                }
            snappy_settings[
                'CellsBetweenLevels'] = self.mesh_obj.CellsBetweenLevels

            if len(self.snappy_settings["InternalRegions"]) > 0:
                self.snappy_settings['InternalRefinementRegionsPresent'] = True
            else:
                self.snappy_settings[
                    'InternalRefinementRegionsPresent'] = False

        # GMSH settings
        elif self.mesh_obj.MeshUtility == "gmsh":
            exe = CfdTools.getGmshExecutable()
            self.gmsh_settings['Executable'] = CfdTools.translatePath(exe)
            self.gmsh_settings['HasLengthMap'] = False
            if self.ele_length_map:
                self.gmsh_settings['HasLengthMap'] = True
                self.gmsh_settings['LengthMap'] = self.ele_length_map
                self.gmsh_settings['NodeMap'] = {}
                for e in self.ele_length_map:
                    ele_nodes = (''.join(
                        (str(n + 1) + ', ')
                        for n in self.ele_node_map[e])).rstrip(', ')
                    self.gmsh_settings['NodeMap'][e] = ele_nodes
            self.gmsh_settings['ClMax'] = self.clmax
            self.gmsh_settings['ClMin'] = self.clmin
            sols = (''.join(
                (str(n + 1) + ', ')
                for n in range(len(self.mesh_obj.Part.Shape.Solids)))
                    ).rstrip(', ')
            self.gmsh_settings['Solids'] = sols
            self.gmsh_settings['BoundaryFaceMap'] = {}
            for k in range(len(self.patch_faces)):
                for l in range(len(self.patch_faces[k])):
                    patch_faces = self.patch_faces[k][l]
                    patch_name = self.patch_names[k][l]
                    if len(patch_faces):
                        self.gmsh_settings['BoundaryFaceMap'][
                            patch_name] = ', '.join(
                                str(fi + 1) for fi in patch_faces)

        # Perform initialisation here rather than __init__ in case of path changes
        self.template_path = os.path.join(CfdTools.getModulePath(), "Data",
                                          "Templates", "mesh")

        mesh_region_present = False
        if self.mesh_obj.MeshUtility == "cfMesh" and len(self.cf_settings['MeshRegions']) > 0 or \
           self.mesh_obj.MeshUtility == "snappyHexMesh" and len(self.snappy_settings['MeshRegions']) > 0:
            mesh_region_present = True

        self.settings = {
            'Name': self.part_obj.Name,
            'MeshPath': self.meshCaseDir,
            'FoamRuntime': CfdTools.getFoamRuntime(),
            'MeshUtility': self.mesh_obj.MeshUtility,
            'MeshRegionPresent': mesh_region_present,
            'CfSettings': self.cf_settings,
            'SnappySettings': self.snappy_settings,
            'GmshSettings': self.gmsh_settings,
            'ExtrusionSettings': self.extrusion_settings,
            'ConvertToDualMesh': self.mesh_obj.ConvertToDualMesh
        }
        if CfdTools.getFoamRuntime() != 'WindowsDocker':
            self.settings['TranslatedFoamPath'] = CfdTools.translatePath(
                CfdTools.getFoamDir())

        if self.mesh_obj.NumberOfProcesses <= 1:
            self.settings['ParallelMesh'] = False
            self.settings['NumberOfProcesses'] = 1
        else:
            self.settings['ParallelMesh'] = True
            self.settings[
                'NumberOfProcesses'] = self.mesh_obj.NumberOfProcesses
        self.settings['NumberOfThreads'] = self.mesh_obj.NumberOfThreads

        TemplateBuilder(self.meshCaseDir, self.template_path, self.settings)

        # Update Allmesh permission - will fail silently on Windows
        fname = os.path.join(self.meshCaseDir, "Allmesh")
        import stat
        s = os.stat(fname)
        os.chmod(fname, s.st_mode | stat.S_IEXEC)

        self.analysis.NeedsMeshRewrite = False
        CfdTools.cfdMessage(
            "Successfully wrote meshCase to folder {}\n".format(
                self.meshCaseDir))
Пример #21
0
    def writeMeshCase(self):
        """ Collect case settings, and finally build a runnable case. """
        CfdTools.cfdMessage(
            "Populating mesh dictionaries in folder {}\n".format(
                self.meshCaseDir))

        if self.mesh_obj.MeshUtility == "cfMesh":
            self.cf_settings['ClMax'] = self.clmax * self.scale

            if len(self.cf_settings['BoundaryLayers']) > 0:
                self.cf_settings['BoundaryLayerPresent'] = True
            else:
                self.cf_settings['BoundaryLayerPresent'] = False
            if len(self.cf_settings["InternalRegions"]) > 0:
                self.cf_settings['InternalRefinementRegionsPresent'] = True
            else:
                self.cf_settings['InternalRefinementRegionsPresent'] = False

        elif self.mesh_obj.MeshUtility == "snappyHexMesh":
            bound_box = self.part_obj.Shape.BoundBox
            bC = 5  # Number of background mesh buffer cells
            x_min = (bound_box.XMin - bC * self.clmax) * self.scale
            x_max = (bound_box.XMax + bC * self.clmax) * self.scale
            y_min = (bound_box.YMin - bC * self.clmax) * self.scale
            y_max = (bound_box.YMax + bC * self.clmax) * self.scale
            z_min = (bound_box.ZMin - bC * self.clmax) * self.scale
            z_max = (bound_box.ZMax + bC * self.clmax) * self.scale
            cells_x = int(math.ceil(bound_box.XLength / self.clmax) + 2 * bC)
            cells_y = int(math.ceil(bound_box.YLength / self.clmax) + 2 * bC)
            cells_z = int(math.ceil(bound_box.ZLength / self.clmax) + 2 * bC)

            snappy_settings = self.snappy_settings
            snappy_settings['BlockMesh'] = {
                "xMin": x_min,
                "xMax": x_max,
                "yMin": y_min,
                "yMax": y_max,
                "zMin": z_min,
                "zMax": z_max,
                "cellsX": cells_x,
                "cellsY": cells_y,
                "cellsZ": cells_z
            }

            inside_x = Units.Quantity(
                self.mesh_obj.PointInMesh.get('x')).Value * self.scale
            inside_y = Units.Quantity(
                self.mesh_obj.PointInMesh.get('y')).Value * self.scale
            inside_z = Units.Quantity(
                self.mesh_obj.PointInMesh.get('z')).Value * self.scale

            shape_face_names_list = []
            for i in self.mesh_obj.ShapeFaceNames:
                shape_face_names_list.append(i)
            snappy_settings['ShapeFaceNames'] = tuple(shape_face_names_list)
            snappy_settings[
                'EdgeRefinementLevel'] = CfdTools.relLenToRefinementLevel(
                    self.mesh_obj.EdgeRefinement)
            snappy_settings['PointInMesh'] = {
                "x": inside_x,
                "y": inside_y,
                "z": inside_z
            }
            snappy_settings[
                'CellsBetweenLevels'] = self.mesh_obj.CellsBetweenLevels
            if self.mesh_obj.NumberCores <= 1:
                self.mesh_obj.NumberCores = 1
                snappy_settings['ParallelMesh'] = False
            else:
                snappy_settings['ParallelMesh'] = True
            snappy_settings['NumberCores'] = self.mesh_obj.NumberCores

            if len(self.snappy_settings["InternalRegions"]) > 0:
                self.snappy_settings['InternalRefinementRegionsPresent'] = True
            else:
                self.snappy_settings[
                    'InternalRefinementRegionsPresent'] = False
        elif self.mesh_obj.MeshUtility == "gmsh":
            if platform.system() == "Windows":
                exe = os.path.join(FreeCAD.getHomePath(), 'bin', 'gmsh.exe')
            else:
                exe = subprocess.check_output(
                    ["which", "gmsh"], universal_newlines=True).rstrip('\n')
            self.gmsh_settings['Executable'] = CfdTools.translatePath(exe)
            self.gmsh_settings['ShapeFile'] = self.temp_file_shape
            self.gmsh_settings['HasLengthMap'] = False
            if self.ele_length_map:
                self.gmsh_settings['HasLengthMap'] = True
                self.gmsh_settings['LengthMap'] = self.ele_length_map
                self.gmsh_settings['NodeMap'] = {}
                for e in self.ele_length_map:
                    ele_nodes = (''.join(
                        (str(n + 1) + ', ')
                        for n in self.ele_node_map[e])).rstrip(', ')
                    self.gmsh_settings['NodeMap'][e] = ele_nodes
            self.gmsh_settings['ClMax'] = self.clmax
            self.gmsh_settings['ClMin'] = self.clmin
            sols = (''.join(
                (str(n + 1) + ', ')
                for n in range(len(self.mesh_obj.Part.Shape.Solids)))
                    ).rstrip(', ')
            self.gmsh_settings['Solids'] = sols
            self.gmsh_settings['BoundaryFaceMap'] = {}
            # Write one boundary per face
            for i in range(len(self.mesh_obj.Part.Shape.Faces)):
                self.gmsh_settings['BoundaryFaceMap']['face' + str(i)] = i + 1
            self.gmsh_settings['MeshFile'] = self.temp_file_mesh

        # Perform initialisation here rather than __init__ in case of path changes
        self.template_path = os.path.join(CfdTools.get_module_path(), "data",
                                          "defaultsMesh")

        mesh_region_present = False
        if self.mesh_obj.MeshUtility == "cfMesh" and len(self.cf_settings['MeshRegions']) > 0 or \
           self.mesh_obj.MeshUtility == "snappyHexMesh" and len(self.snappy_settings['MeshRegions']) > 0:
            mesh_region_present = True

        self.settings = {
            'Name': self.part_obj.Name,
            'MeshPath': self.meshCaseDir,
            'FoamRuntime': CfdTools.getFoamRuntime(),
            'TranslatedFoamPath':
            CfdTools.translatePath(CfdTools.getFoamDir()),
            'MeshUtility': self.mesh_obj.MeshUtility,
            'MeshRegionPresent': mesh_region_present,
            'CfSettings': self.cf_settings,
            'SnappySettings': self.snappy_settings,
            'GmshSettings': self.gmsh_settings,
            'TwoDSettings': self.two_d_settings
        }

        TemplateBuilder.TemplateBuilder(self.meshCaseDir, self.template_path,
                                        self.settings)

        # Update Allmesh permission - will fail silently on Windows
        fname = os.path.join(self.meshCaseDir, "Allmesh")
        import stat
        s = os.stat(fname)
        os.chmod(fname, s.st_mode | stat.S_IEXEC)

        CfdTools.cfdMessage(
            "Successfully wrote meshCase to folder {}\n".format(
                self.meshCaseDir))
Пример #22
0
def parse(pathobj):
    global DRILL_RETRACT_MODE
    global MOTION_MODE
    global CURRENT_X
    global CURRENT_Y
    global CURRENT_Z

    out = ''
    lastcommand = None
    precision_string = '.' + str(PRECISION) + 'f'

    params = [
        'X', 'Y', 'Z', 'A', 'B', 'C', 'U', 'V', 'W', 'I', 'J', 'K', 'F', 'S',
        'T', 'Q', 'R', 'L', 'P'
    ]

    if hasattr(pathobj, 'Group'):  # We have a compound or project.
        if OUTPUT_COMMENTS:
            out += linenumber() + '(Compound: ' + pathobj.Label + ')\n'
        for p in pathobj.Group:
            out += parse(p)
        return out

    else:  # Parsing simple path
        # groups might contain non-path things like stock.
        if not hasattr(pathobj, 'Path'):
            return out

        if OUTPUT_COMMENTS and OUTPUT_PATH:
            out += linenumber() + '(Path: ' + pathobj.Label + ')\n'

        for c in pathobj.Path.Commands:
            outlist = []
            command = c.Name
            outlist.append(command)
            # Debug:
            # print('pathobj.Path.Commands:', c)

            # If modal is True, delete duplicate commands:
            if MODAL:
                if command == lastcommand:
                    outlist.pop(0)

            # Add the remaining parameters in order:
            for param in params:
                if param in c.Parameters:
                    if param == 'F':
                        if command not in RAPID_MOVES:
                            feedRate = Units.Quantity(c.Parameters['F'],
                                                      FreeCAD.Units.Velocity)
                            if feedRate.getValueAs(UNIT_FEED_FORMAT) > 0.0:
                                outlist.append(param + format(
                                    float(feedRate.getValueAs(
                                        UNIT_FEED_FORMAT)), precision_string))
                    elif param == 'T':
                        outlist.append(param + str(int(c.Parameters[param])))

                    elif param in ['H', 'D', 'S', 'P', 'L']:
                        outlist.append(param + str(c.Parameters[param]))
                    elif param in ['A', 'B', 'C']:
                        outlist.append(
                            param +
                            format(c.Parameters[param], precision_string))
                    # [X, Y, Z, U, V, W, I, J, K, R, Q]
                    else:
                        pos = Units.Quantity(c.Parameters[param],
                                             FreeCAD.Units.Length)
                        outlist.append(
                            param + format(float(pos.getValueAs(UNIT_FORMAT)),
                                           precision_string))

            # Store the latest command:
            lastcommand = command

            # Capture the current position for subsequent calculations:
            if command in MOTION_COMMANDS:
                if 'X' in c.Parameters:
                    CURRENT_X = Units.Quantity(c.Parameters['X'],
                                               FreeCAD.Units.Length)
                if 'Y' in c.Parameters:
                    CURRENT_Y = Units.Quantity(c.Parameters['Y'],
                                               FreeCAD.Units.Length)
                if 'Z' in c.Parameters:
                    CURRENT_Z = Units.Quantity(c.Parameters['Z'],
                                               FreeCAD.Units.Length)

            if command in ('G98', 'G99'):
                DRILL_RETRACT_MODE = command

            if TRANSLATE_DRILL_CYCLES:
                if command in ('G81', 'G82', 'G83'):
                    out += drill_translate(outlist, command, c.Parameters)
                    # Erase the line just translated:
                    outlist = []

            if SPINDLE_WAIT > 0:
                if command in ('M3', 'M03', 'M4', 'M04'):
                    out += linenumber() + format_outlist(outlist) + '\n'
                    # RRF: P for milliseconds, S for seconds, change P to S
                    out += linenumber()
                    out += format_outlist(['G4', 'S%s' % SPINDLE_WAIT])
                    out += '\n'
                    outlist = []

            # Check for Tool Change:
            if command in ('M6', 'M06'):

                if OUTPUT_COMMENTS:
                    out += linenumber() + '(Begin toolchange)\n'

                if OUTPUT_TOOL_CHANGE:
                    for line in TOOL_CHANGE.splitlines(True):
                        out += linenumber() + line + '\n'
                    outlist[0] = ' '
                    outlist[-1] = ('T' + str(int(c.Parameters['T'])))

                if not OUTPUT_TOOL_CHANGE and OUTPUT_COMMENTS:
                    # next 2 lines could also be replaced by a single line as "outlist = []"
                    outlist[0] = ' '
                    outlist[-1] = ' '

                if not OUTPUT_TOOL_CHANGE and not OUTPUT_COMMENTS:
                    outlist = []

            if command == 'message':
                if OUTPUT_COMMENTS:
                    outlist.pop(0)  # remove the command
                else:
                    out = []

            if command in SUPPRESS_COMMANDS:
                outlist[0] = '(' + outlist[0]
                outlist[-1] = outlist[-1] + ')'

            # Remove embedded comments:
            if not OUTPUT_COMMENTS:
                tmplist = []
                list_index = 0
                while list_index < len(outlist):
                    left_index = outlist[list_index].find('(')
                    if left_index == -1:  # Not a comment
                        tmplist.append(outlist[list_index])
                    else:  # This line contains a comment, and possibly more
                        right_index = outlist[list_index].find(')')
                        comment_area = outlist[list_index][
                            left_index:right_index + 1]
                        line_minus_comment = outlist[list_index].replace(
                            comment_area, '').strip()
                        if line_minus_comment:
                            # Line contained more than just a comment
                            tmplist.append(line_minus_comment)
                    list_index += 1
                # Done removing comments
                outlist = tmplist

            # Prepend a line number and append a newline
            if len(outlist) >= 1:
                out += linenumber() + format_outlist(outlist) + '\n'

    return out
Пример #23
0
def parse(pathobj):
    out = ""
    lastcommand = None
    precision_string = '.' + str(PRECISION) + 'f'
    currLocation = {}  # keep track for no doubles

    # The params list control the order of parameters
    params = [
        'X', 'Y', 'Z', 'A', 'B', 'C', 'I', 'J', 'K', 'R', 'F', 'S', 'T', 'H',
        'L', 'Q'
    ]
    firstmove = Path.Command("G0", {"X": -1, "Y": -1, "Z": -1, "F": 0.0})
    currLocation.update(firstmove.Parameters)  # set First location Parameters

    if hasattr(pathobj, "Group"):
        # We have a compound or project.

        # if OUTPUT_COMMENTS:
        #    out += linenumber() + "(compound: " + pathobj.Label + ")\n"
        for p in pathobj.Group:
            out += parse(p)
        return out
    else:
        # parsing simple path

        # groups might contain non-path things like stock.
        if not hasattr(pathobj, "Path"):
            return out

        # if OUTPUT_COMMENTS:
        #    out += linenumber() + "(" + pathobj.Label + ")\n"

        for c in pathobj.Path.Commands:
            commandlist = [
            ]  # list of elements in the command, code and params.
            command = c.Name.strip()  # command M or G code or comment string
            commandlist.append(command)

            # if modal: only print the command if it is not the same as the last one
            if MODAL is True:
                if command == lastcommand:
                    commandlist.pop(0)

            if c.Name[0] == '(' and not OUTPUT_COMMENTS:  # command is a comment
                continue

            # Now add the remaining parameters in order
            for param in params:
                if param in c.Parameters:
                    if param == 'F' and (
                            currLocation[param] != c.Parameters[param]
                            or REPEAT_ARGUMENTS):
                        if c.Name not in ["G0", "G00"]:  # No F in G0
                            speed = Units.Quantity(c.Parameters['F'],
                                                   FreeCAD.Units.Velocity)
                            if speed.getValueAs(UNIT_SPEED_FORMAT) > 0.0:
                                commandlist.append(param + format(
                                    float(speed.getValueAs(UNIT_SPEED_FORMAT)),
                                    precision_string))
                        else:
                            continue
                    elif param == 'T':
                        commandlist.append(param + str(int(c.Parameters['T'])))
                    elif param == 'H':
                        commandlist.append(param + str(int(c.Parameters['H'])))
                    elif param == 'D':
                        commandlist.append(param + str(int(c.Parameters['D'])))
                    elif param == 'S':
                        commandlist.append(param + str(int(c.Parameters['S'])))
                    else:
                        if (not REPEAT_ARGUMENTS) and (
                                param
                                in currLocation) and (currLocation[param]
                                                      == c.Parameters[param]):
                            continue
                        else:
                            pos = Units.Quantity(c.Parameters[param],
                                                 FreeCAD.Units.Length)
                            commandlist.append(
                                param +
                                format(float(pos.getValueAs(UNIT_FORMAT)),
                                       precision_string))

            # store the latest command
            lastcommand = command
            currLocation.update(c.Parameters)

            # Check for Tool Change:
            if command == 'M6':
                for line in TOOL_CHANGE.splitlines(True):
                    out += linenumber() + line

                # add height offset
                if USE_TLO:
                    tool_height = '\nG43 H' + str(int(c.Parameters['T']))
                    commandlist.append(tool_height)

            if command == "message":
                if OUTPUT_COMMENTS is False:
                    out = []
                else:
                    commandlist.pop(0)  # remove the command

            # prepend a line number and append a newline
            if len(commandlist) >= 1:
                if OUTPUT_LINE_NUMBERS:
                    commandlist.insert(0, (linenumber()))

                # append the line to the final output
                for w in commandlist:
                    out += w.strip() + COMMAND_SPACE
                if (trace_gcode):
                    print("parse : >>{}".format(out))
                out = out.strip() + "\n"

        return out
Пример #24
0
def drill_translate(outlist, cmd, params):
    global DRILL_RETRACT_MODE
    global MOTION_MODE
    global CURRENT_X
    global CURRENT_Y
    global CURRENT_Z
    global UNITS
    global UNIT_FORMAT
    global UNIT_FEED_FORMAT

    class Drill:  # Using a class is necessary for the nested functions.
        gcode = ''

    strFormat = '.' + str(PRECISION) + 'f'

    if OUTPUT_COMMENTS:  # Comment the original command
        outlist[0] = '(' + outlist[0]
        outlist[-1] = outlist[-1] + ')'
        Drill.gcode += linenumber() + format_outlist(outlist) + '\n'

    # Cycle conversion only converts the cycles in the XY plane (G17).
    # --> ZX (G18) and YZ (G19) planes produce false gcode.
    drill_X = Units.Quantity(params['X'], FreeCAD.Units.Length)
    drill_Y = Units.Quantity(params['Y'], FreeCAD.Units.Length)
    drill_Z = Units.Quantity(params['Z'], FreeCAD.Units.Length)
    drill_R = Units.Quantity(params['R'], FreeCAD.Units.Length)
    drill_F = Units.Quantity(params['F'], FreeCAD.Units.Velocity)
    if cmd == 'G82':
        drill_DwellTime = params['P']
    elif cmd == 'G83':
        drill_Step = Units.Quantity(params['Q'], FreeCAD.Units.Length)

    # R less than Z is error
    if drill_R < drill_Z:
        Drill.gcode += linenumber() + '(drill cycle error: R less than Z )\n'
        return Drill.gcode

    # Z height to retract to when drill cycle is done:
    if DRILL_RETRACT_MODE == 'G98' and CURRENT_Z > drill_R:
        RETRACT_Z = CURRENT_Z
    else:
        RETRACT_Z = drill_R

    # Z motion nested functions:
    def rapid_Z_to(new_Z):
        Drill.gcode += linenumber() + 'G0 Z'
        Drill.gcode += format(float(new_Z.getValueAs(UNIT_FORMAT)),
                              strFormat) + '\n'

    def feed_Z_to(new_Z):
        Drill.gcode += linenumber() + 'G1 Z'
        Drill.gcode += format(float(new_Z.getValueAs(UNIT_FORMAT)),
                              strFormat) + ' F'
        Drill.gcode += format(float(drill_F.getValueAs(UNIT_FEED_FORMAT)),
                              '.2f') + '\n'

    # Make sure that Z is not below RETRACT_Z:
    if CURRENT_Z < RETRACT_Z:
        rapid_Z_to(RETRACT_Z)

    # Rapid to hole position XY:
    Drill.gcode += linenumber() + 'G0 X'
    Drill.gcode += format(float(drill_X.getValueAs(UNIT_FORMAT)),
                          strFormat) + ' Y'
    Drill.gcode += format(float(drill_Y.getValueAs(UNIT_FORMAT)),
                          strFormat) + '\n'

    # Rapid to R:
    rapid_Z_to(drill_R)

    # *************************************************************************
    # * Drill cycles:                                                         *
    # * G80 Cancel the drill cycle                                            *
    # * G81 Drill full depth in one pass                                      *
    # * G82 Drill full depth in one pass, and pause at the bottom             *
    # * G83 Drill in pecks, raising the drill to R height after each peck     *
    # * In preparation for a rapid to the next hole position:                 *
    # * G98 After the hole has been drilled, retract to the initial Z value   *
    # * G99 After the hole has been drilled, retract to R height              *
    # * Select G99 only if safe to move from hole to hole at the R height     *
    # *************************************************************************
    if cmd in ('G81', 'G82'):
        feed_Z_to(drill_Z)  # Drill hole in one step
        if cmd == 'G82':  # Dwell time delay at the bottom of the hole
            Drill.gcode += linenumber() + 'G4 S' + str(drill_DwellTime) + '\n'
            # RRF uses P for milliseconds, S for seconds, change P to S

    elif cmd == 'G83':  # Peck drill cycle:
        chip_Space = drill_Step * 0.5
        next_Stop_Z = drill_R - drill_Step
        while next_Stop_Z >= drill_Z:
            feed_Z_to(next_Stop_Z)  # Drill one peck of depth

            # Set next depth, next_Stop_Z is still at the current hole depth
            if (next_Stop_Z - drill_Step) >= drill_Z:
                # Rapid up to clear chips:
                rapid_Z_to(drill_R)
                # Rapid down to just above last peck depth:
                rapid_Z_to(next_Stop_Z + chip_Space)
                # Update next_Stop_Z to next depth:
                next_Stop_Z -= drill_Step
            elif next_Stop_Z == drill_Z:
                break  # Done
            else:  # More to drill, but less than drill_Step
                # Rapid up to clear chips:
                rapid_Z_to(drill_R)
                # Rapid down to just above last peck depth:
                rapid_Z_to(next_Stop_Z + chip_Space)
                # Dril remainder of the hole depth:
                feed_Z_to(drill_Z)
                break  # Done
    rapid_Z_to(RETRACT_Z)  # Done, retract the drill

    return Drill.gcode
Пример #25
0
 def check_prerequisites(self):
     from FreeCAD import Units
     message = ""
     # analysis
     if not self.analysis:
         message += "No active Analysis\n"
     if self.analysis_type not in self.known_analysis_types:
         message += "Unknown analysis type: {}\n".format(self.analysis_type)
     if not self.working_dir:
         message += "Working directory not set\n"
     import os
     if not (os.path.isdir(self.working_dir)):
         message += "Working directory \'{}\' doesn't exist.".format(
             self.working_dir)
     # solver
     if not self.solver:
         message += "No solver object defined in the analysis\n"
     else:
         if self.analysis_type == "frequency":
             if not hasattr(self.solver, "EigenmodeHighLimit"):
                 message += "Frequency analysis: Solver has no EigenmodeHighLimit.\n"
             elif not hasattr(self.solver, "EigenmodeLowLimit"):
                 message += "Frequency analysis: Solver has no EigenmodeLowLimit.\n"
             elif not hasattr(self.solver, "EigenmodesCount"):
                 message += "Frequency analysis: Solver has no EigenmodesCount.\n"
         if hasattr(self.solver, "MaterialNonlinearity"
                    ) and self.solver.MaterialNonlinearity == "nonlinear":
             if not self.materials_nonlinear:
                 message += "Solver is set to nonlinear materials, but there is no nonlinear material in the analysis.\n"
             if self.solver.SolverType == 'FemSolverCalculix' and self.solver.GeometricalNonlinearity != "nonlinear":
                 # nonlinear geometry --> should be set https://forum.freecadweb.org/viewtopic.php?f=18&t=23101&p=180489#p180489
                 message += "Solver CalculiX triggers nonlinear geometry for nonlinear material, thus it should to be set too.\n"
     # mesh
     if not self.mesh:
         message += "No mesh object defined in the analysis\n"
     if self.mesh:
         if self.mesh.FemMesh.VolumeCount == 0 and self.mesh.FemMesh.FaceCount > 0 and not self.shell_thicknesses:
             message += "FEM mesh has no volume elements, either define a shell thicknesses or provide a FEM mesh with volume elements.\n"
         if self.mesh.FemMesh.VolumeCount == 0 and self.mesh.FemMesh.FaceCount == 0 and self.mesh.FemMesh.EdgeCount > 0 and not self.beam_sections and not self.fluid_sections:
             message += "FEM mesh has no volume and no shell elements, either define a beam/fluid section or provide a FEM mesh with volume elements.\n"
         if self.mesh.FemMesh.VolumeCount == 0 and self.mesh.FemMesh.FaceCount == 0 and self.mesh.FemMesh.EdgeCount == 0:
             message += "FEM mesh has neither volume nor shell or edge elements. Provide a FEM mesh with elements!\n"
     # material linear and nonlinear
     if not self.materials_linear:
         message += "No material object defined in the analysis\n"
     has_no_references = False
     for m in self.materials_linear:
         if len(m['Object'].References) == 0:
             if has_no_references is True:
                 message += "More than one material has an empty references list (Only one empty references list is allowed!).\n"
             has_no_references = True
     mat_ref_shty = ''
     for m in self.materials_linear:
         ref_shty = get_refshape_type(m['Object'])
         if not mat_ref_shty:
             mat_ref_shty = ref_shty
         if mat_ref_shty and ref_shty and ref_shty != mat_ref_shty:  # mat_ref_shty could be empty in one material, only the not empty ones should have the same shape type
             message += 'Some material objects do not have the same reference shape type (all material objects must have the same reference shape type, at the moment).\n'
     for m in self.materials_linear:
         mat_map = m['Object'].Material
         mat_obj = m['Object']
         if mat_obj.Category == 'Solid':
             if 'YoungsModulus' in mat_map:
                 # print(Units.Quantity(mat_map['YoungsModulus']).Value)
                 if not Units.Quantity(mat_map['YoungsModulus']).Value:
                     message += "Value of YoungsModulus is set to 0.0.\n"
             else:
                 message += "No YoungsModulus defined for at least one material.\n"
             if 'PoissonRatio' not in mat_map:
                 message += "No PoissonRatio defined for at least one material.\n"  # PoissonRatio is allowed to be 0.0 (in ccx), but it should be set anyway.
         if self.analysis_type == "frequency" or self.selfweight_constraints:
             if 'Density' not in mat_map:
                 message += "No Density defined for at least one material.\n"
         if self.analysis_type == "thermomech":
             if 'ThermalConductivity' in mat_map:
                 if not Units.Quantity(
                         mat_map['ThermalConductivity']).Value:
                     message += "Value of ThermalConductivity is set to 0.0.\n"
             else:
                 message += "Thermomechanical analysis: No ThermalConductivity defined for at least one material.\n"
             if 'ThermalExpansionCoefficient' not in mat_map and mat_obj.Category == 'Solid':
                 message += "Thermomechanical analysis: No ThermalExpansionCoefficient defined for at least one material.\n"  # allowed to be 0.0 (in ccx)
             if 'SpecificHeat' not in mat_map:
                 message += "Thermomechanical analysis: No SpecificHeat defined for at least one material.\n"  # allowed to be 0.0 (in ccx)
     for m in self.materials_linear:
         has_nonlinear_material = False
         for nlm in self.materials_nonlinear:
             if nlm['Object'].LinearBaseMaterial == m['Object']:
                 if has_nonlinear_material is False:
                     has_nonlinear_material = True
                 else:
                     message += "At least two nonlinear materials use the same linear base material. Only one nonlinear material for each linear material allowed.\n"
     # which analysis needs which constraints
     # no check in the regard of loads existence (constraint force, pressure, self weight) is done because an analysis without loads at all is an valid analysis too
     if self.analysis_type == "static":
         if not (self.fixed_constraints or self.displacement_constraints):
             message += "Static analysis: Neither constraint fixed nor constraint displacement defined.\n"
     if self.analysis_type == "thermomech":
         if not self.initialtemperature_constraints:
             if not self.fluid_sections:
                 message += "Thermomechanical analysis: No initial temperature defined.\n"
         if len(self.initialtemperature_constraints) > 1:
             message += "Thermomechanical analysis: Only one initial temperature is allowed.\n"
     # constraints
     # fixed
     if self.fixed_constraints:
         for c in self.fixed_constraints:
             if len(c['Object'].References) == 0:
                 message += "At least one constraint fixed has an empty reference.\n"
     # displacement
     if self.displacement_constraints:
         for di in self.displacement_constraints:
             if len(di['Object'].References) == 0:
                 message += "At least one constraint displacement has an empty reference.\n"
     # plane rotation
     if self.planerotation_constraints:
         for c in self.planerotation_constraints:
             if len(c['Object'].References) == 0:
                 message += "At least one constraint plane rotation has an empty reference.\n"
     # contact
     if self.contact_constraints:
         for c in self.contact_constraints:
             if len(c['Object'].References) == 0:
                 message += "At least one constraint contact has an empty reference.\n"
     # transform
     if self.transform_constraints:
         for c in self.transform_constraints:
             if len(c['Object'].References) == 0:
                 message += "At least one constraint transform has an empty reference.\n"
     # pressure
     if self.pressure_constraints:
         for c in self.pressure_constraints:
             if len(c['Object'].References) == 0:
                 message += "At least one constraint pressure has an empty reference.\n"
     # force
     if self.force_constraints:
         for c in self.force_constraints:
             if len(c['Object'].References) == 0:
                 message += "At least one constraint force has an empty reference.\n"
     # temperature
     if self.temperature_constraints:
         for c in self.temperature_constraints:
             if len(c['Object'].References) == 0:
                 message += "At least one constraint temperature has an empty reference.\n"
     # heat flux
     if self.heatflux_constraints:
         for c in self.heatflux_constraints:
             if len(c['Object'].References) == 0:
                 message += "At least one constraint heat flux has an empty reference.\n"
     # beam section
     if self.beam_sections:
         if self.shell_thicknesses:
             # this needs to be checked only once either here or in shell_thicknesses
             message += "Beam Sections and shell thicknesses in one analysis is not supported at the moment.\n"
         if self.fluid_sections:
             # this needs to be checked only once either here or in shell_thicknesses
             message += "Beam Sections and Fluid Sections in one analysis is not supported at the moment.\n"
         has_no_references = False
         for b in self.beam_sections:
             if len(b['Object'].References) == 0:
                 if has_no_references is True:
                     message += "More than one beam section has an empty references list (Only one empty references list is allowed!).\n"
                 has_no_references = True
         if self.mesh:
             if self.mesh.FemMesh.FaceCount > 0 or self.mesh.FemMesh.VolumeCount > 0:
                 message += "Beam sections defined but FEM mesh has volume or shell elements.\n"
             if self.mesh.FemMesh.EdgeCount == 0:
                 message += "Beam sections defined but FEM mesh has no edge elements.\n"
     # shell thickness
     if self.shell_thicknesses:
         has_no_references = False
         for s in self.shell_thicknesses:
             if len(s['Object'].References) == 0:
                 if has_no_references is True:
                     message += "More than one shell thickness has an empty references list (Only one empty references list is allowed!).\n"
                 has_no_references = True
         if self.mesh:
             if self.mesh.FemMesh.VolumeCount > 0:
                 message += "Shell thicknesses defined but FEM mesh has volume elements.\n"
             if self.mesh.FemMesh.FaceCount == 0:
                 message += "Shell thicknesses defined but FEM mesh has no shell elements.\n"
     # fluid section
     if self.fluid_sections:
         if not self.selfweight_constraints:
             message += "A fluid network analysis requires self weight constraint to be applied"
         if self.analysis_type != "thermomech":
             message += "A fluid network analysis can only be done in a thermomech analysis"
         has_no_references = False
         for f in self.fluid_sections:
             if len(f['Object'].References) == 0:
                 if has_no_references is True:
                     message += "More than one fluid section has an empty references list (Only one empty references list is allowed!).\n"
                 has_no_references = True
         if self.mesh:
             if self.mesh.FemMesh.FaceCount > 0 or self.mesh.FemMesh.VolumeCount > 0:
                 message += "Fluid sections defined but FEM mesh has volume or shell elements.\n"
             if self.mesh.FemMesh.EdgeCount == 0:
                 message += "Fluid sections defined but FEM mesh has no edge elements.\n"
     return message
Пример #26
0
def parse(pathobj):
    global PRECISION
    global MODAL
    global OUTPUT_DOUBLES
    global UNIT_FORMAT
    global UNIT_SPEED_FORMAT

    out = ""
    lastcommand = None
    precision_string = '.' + str(PRECISION) + 'f'
    currLocation = {}  # keep track for no doubles

    # the order of parameters
    # linuxcnc doesn't want K properties on XY plane  Arcs need work.
    params = [
        'X', 'Y', 'Z', 'A', 'B', 'C', 'I', 'J', 'F', 'S', 'T', 'Q', 'R', 'L',
        'H', 'D', 'P'
    ]
    firstmove = Path.Command("G0", {"X": -1, "Y": -1, "Z": -1, "F": 0.0})
    currLocation.update(firstmove.Parameters)  # set First location Parameters

    if hasattr(pathobj, "Group"):  # We have a compound or project.
        # if OUTPUT_COMMENTS:
        #     out += linenumber() + "(compound: " + pathobj.Label + ")\n"
        for p in pathobj.Group:
            out += parse(p)
        return out
    else:  # parsing simple path

        # groups might contain non-path things like stock.
        if not hasattr(pathobj, "Path"):
            return out

        # if OUTPUT_COMMENTS:
        #     out += linenumber() + "(" + pathobj.Label + ")\n"

        for c in pathobj.Path.Commands:

            outstring = []
            command = c.Name
            outstring.append(command)

            # if modal: suppress the command if it is the same as the last one
            if MODAL is True:
                if command == lastcommand:
                    outstring.pop(0)

            if c.Name[0] == '(' and not OUTPUT_COMMENTS:  # command is a comment
                continue

            # Now add the remaining parameters in order
            for param in params:
                if param in c.Parameters:
                    if param == 'F' and (
                            currLocation[param] != c.Parameters[param]
                            or OUTPUT_DOUBLES):
                        if c.Name not in [
                                "G0", "G00"
                        ]:  # linuxcnc doesn't use rapid speeds
                            speed = Units.Quantity(c.Parameters['F'],
                                                   FreeCAD.Units.Velocity)
                            if speed.getValueAs(UNIT_SPEED_FORMAT) > 0.0:
                                outstring.append(param + format(
                                    float(speed.getValueAs(UNIT_SPEED_FORMAT)),
                                    precision_string))
                        else:
                            continue
                    elif param == 'T':
                        outstring.append(param + str(int(c.Parameters['T'])))
                    elif param == 'H':
                        outstring.append(param + str(int(c.Parameters['H'])))
                    elif param == 'D':
                        outstring.append(param + str(int(c.Parameters['D'])))
                    elif param == 'S':
                        outstring.append(param + str(int(c.Parameters['S'])))
                    else:
                        if (not OUTPUT_DOUBLES) and (
                                param
                                in currLocation) and (currLocation[param]
                                                      == c.Parameters[param]):
                            continue
                        else:
                            pos = Units.Quantity(c.Parameters[param],
                                                 FreeCAD.Units.Length)
                            outstring.append(
                                param +
                                format(float(pos.getValueAs(UNIT_FORMAT)),
                                       precision_string))

            # store the latest command
            lastcommand = command
            currLocation.update(c.Parameters)

            # Check for Tool Change:
            if command == 'M6':
                # if OUTPUT_COMMENTS:
                #     out += linenumber() + "(begin toolchange)\n"
                for line in TOOL_CHANGE.splitlines(True):
                    out += linenumber() + line

            if command == "message":
                if OUTPUT_COMMENTS is False:
                    out = []
                else:
                    outstring.pop(0)  # remove the command

            # prepend a line number and append a newline
            if len(outstring) >= 1:
                if OUTPUT_LINE_NUMBERS:
                    outstring.insert(0, (linenumber()))

                # append the line to the final output
                for w in outstring:
                    out += w + COMMAND_SPACE
                out = out.strip() + "\n"

        return out
Пример #27
0
def convert(quantityStr, unit):
    quantity = Units.Quantity(quantityStr)
    for key, setting in UNITS.items():
        unit = unit.replace(key, setting)
    return float(quantity.getValueAs(unit))
Пример #28
0
    def __init__(self):
        self.name = "Polar array"
        _log(_tr("Task panel:") + " {}".format(_tr(self.name)))

        # The .ui file must be loaded into an attribute
        # called `self.form` so that it is displayed in the task panel.
        ui_file = ":/ui/TaskPanel_PolarArray.ui"
        self.form = Gui.PySideUic.loadUi(ui_file)

        icon_name = "Draft_PolarArray"
        svg = ":/icons/" + icon_name
        pix = QtGui.QPixmap(svg)
        icon = QtGui.QIcon.fromTheme(icon_name, QtGui.QIcon(svg))
        self.form.setWindowIcon(icon)
        self.form.setWindowTitle(_tr(self.name))

        self.form.label_icon.setPixmap(pix.scaled(32, 32))

        # -------------------------------------------------------------------
        # Default values for the internal function,
        # and for the task panel interface
        start_angle = U.Quantity(360.0, App.Units.Angle)
        angle_unit = start_angle.getUserPreferred()[2]

        self.angle = start_angle.Value
        self.number = 5

        self.form.spinbox_angle.setProperty('rawValue', self.angle)
        self.form.spinbox_angle.setProperty('unit', angle_unit)

        self.form.spinbox_number.setValue(self.number)

        start_point = U.Quantity(0.0, App.Units.Length)
        length_unit = start_point.getUserPreferred()[2]

        self.center = App.Vector(start_point.Value, start_point.Value,
                                 start_point.Value)

        self.form.input_c_x.setProperty('rawValue', self.center.x)
        self.form.input_c_x.setProperty('unit', length_unit)
        self.form.input_c_y.setProperty('rawValue', self.center.y)
        self.form.input_c_y.setProperty('unit', length_unit)
        self.form.input_c_z.setProperty('rawValue', self.center.z)
        self.form.input_c_z.setProperty('unit', length_unit)

        self.fuse = utils.get_param("Draft_array_fuse", False)
        self.use_link = utils.get_param("Draft_array_Link", True)

        self.form.checkbox_fuse.setChecked(self.fuse)
        self.form.checkbox_link.setChecked(self.use_link)
        # -------------------------------------------------------------------

        # Some objects need to be selected before we can execute the function.
        self.selection = None

        # This is used to test the input of the internal function.
        # It should be changed to True before we can execute the function.
        self.valid_input = False

        self.set_widget_callbacks()

        self.tr_true = QT_TRANSLATE_NOOP("Draft", "True")
        self.tr_false = QT_TRANSLATE_NOOP("Draft", "False")

        # The mask is not used at the moment, but could be used in the future
        # by a callback to restrict the coordinates of the pointer.
        self.mask = ""
Пример #29
0
    def __init__(self, gmsh_mesh_obj, analysis=None):

        # mesh obj
        self.mesh_obj = gmsh_mesh_obj

        # analysis
        if analysis:
            self.analysis = analysis
        else:
            self.analysis = None

        # part to mesh
        self.part_obj = self.mesh_obj.Part

        # clmax, CharacteristicLengthMax: float, 0.0 = 1e+22
        self.clmax = Units.Quantity(
            self.mesh_obj.CharacteristicLengthMax).Value
        if self.clmax == 0.0:
            self.clmax = 1e+22

        # clmin, CharacteristicLengthMin: float
        self.clmin = Units.Quantity(
            self.mesh_obj.CharacteristicLengthMin).Value

        # geotol, GeometryTolerance: float, 0.0 = 1e-08
        self.geotol = self.mesh_obj.GeometryTolerance
        if self.geotol == 0.0:
            self.geotol = 1e-08

        # order
        # known_element_orders = ["1st", "2nd"]
        self.order = self.mesh_obj.ElementOrder
        if self.order == "1st":
            self.order = "1"
        elif self.order == "2nd":
            self.order = "2"
        else:
            Console.PrintError("Error in order\n")

        # dimension
        self.dimension = self.mesh_obj.ElementDimension

        # Algorithm2D
        algo2D = self.mesh_obj.Algorithm2D
        if algo2D == "Automatic":
            self.algorithm2D = "2"
        elif algo2D == "MeshAdapt":
            self.algorithm2D = "1"
        elif algo2D == "Delaunay":
            self.algorithm2D = "5"
        elif algo2D == "Frontal":
            self.algorithm2D = "6"
        elif algo2D == "BAMG":
            self.algorithm2D = "7"
        elif algo2D == "DelQuad":
            self.algorithm2D = "8"
        else:
            self.algorithm2D = "2"

        # Algorithm3D
        algo3D = self.mesh_obj.Algorithm3D
        if algo3D == "Automatic":
            self.algorithm3D = "1"
        elif algo3D == "Delaunay":
            self.algorithm3D = "1"
        elif algo3D == "New Delaunay":
            self.algorithm3D = "2"
        elif algo3D == "Frontal":
            self.algorithm3D = "4"
        elif algo3D == "Frontal Delaunay":
            self.algorithm3D = "5"
        elif algo3D == "Frontal Hex":
            self.algorithm3D = "6"
        elif algo3D == "MMG3D":
            self.algorithm3D = "7"
        elif algo3D == "R-tree":
            self.algorithm3D = "9"
        else:
            self.algorithm3D = "1"

        # mesh groups
        if self.mesh_obj.GroupsOfNodes is True:
            self.group_nodes_export = True
        else:
            self.group_nodes_export = False
        self.group_elements = {}

        # mesh regions
        self.ele_length_map = {}  # { "ElementString" : element length }
        self.ele_node_map = {}  # { "ElementString" : [element nodes] }

        # mesh boundary layer
        self.bl_setting_list = [
        ]  # list of dict, each item map to MeshBoundaryLayer object
        self.bl_boundary_list = [
        ]  # to remove duplicated boundary edge or faces

        # other initializations
        self.temp_file_geometry = ""
        self.temp_file_mesh = ""
        self.temp_file_geo = ""
        self.mesh_name = ""
        self.gmsh_bin = ""
        self.error = False
Пример #30
0
    def onChanged(self,vobj,prop):
        if prop in ["Text","Decimals","ShowUnit"]:
            if hasattr(self,"text1") and hasattr(self,"text2") and hasattr(vobj,"Text"):
                self.text1.string.deleteValues(0)
                self.text2.string.deleteValues(0)
                text1 = []
                text2 = []
                first = True
                for t in vobj.Text:
                    if t:
                        if hasattr(vobj.Object,"Area"):
                            from FreeCAD import Units
                            q = Units.Quantity(vobj.Object.Area,Units.Area).getUserPreferred()
                            qt = vobj.Object.Area/q[1]
                            if hasattr(vobj,"Decimals"):
                                if vobj.Decimals == 0:
                                    qt = str(int(qt))
                                else:
                                    f = "%."+str(abs(vobj.Decimals))+"f"
                                    qt = f % qt
                            else:
                                qt = str(qt)
                            if hasattr(vobj,"ShowUnit"):
                                if vobj.ShowUnit:
                                    qt = qt + q[2].replace("^2",u"\xb2") # square symbol
                            t = t.replace("$area",qt)
                        t = t.replace("$label",vobj.Object.Label)
                        if hasattr(vobj.Object,"Tag"):
                            t = t.replace("$tag",vobj.Object.Tag)
                        if hasattr(vobj.Object,"FinishFloor"):
                            t = t.replace("$floor",vobj.Object.FinishFloor)
                        if hasattr(vobj.Object,"FinishWalls"):
                            t = t.replace("$walls",vobj.Object.FinishWalls)
                        if hasattr(vobj.Object,"FinishCeiling"):
                            t = t.replace("$ceiling",vobj.Object.FinishCeiling)
                        if first:
                            text1.append(t.encode("utf8"))
                        else:
                            text2.append(t.encode("utf8"))
                    first = False
                if text1:
                    self.text1.string.setValues(text1)
                if text2:
                    self.text2.string.setValues(text2)

        elif prop == "FontName":
            if hasattr(self,"font") and hasattr(vobj,"FontName"):
                self.font.name = str(vobj.FontName)

        elif (prop == "FontSize"):
            if hasattr(self,"font") and hasattr(vobj,"FontSize"):
                self.font.size = vobj.FontSize.Value

        elif (prop == "FirstLine"):
            if hasattr(self,"header") and hasattr(vobj,"FontSize") and hasattr(vobj,"FirstLine"):
                scale = vobj.FirstLine.Value/vobj.FontSize.Value
                self.header.scaleFactor.setValue([scale,scale,scale])

        elif prop == "TextColor":
            if hasattr(self,"color") and hasattr(vobj,"TextColor"):
                c = vobj.TextColor
                self.color.rgb.setValue(c[0],c[1],c[2])

        elif prop == "TextPosition":
            if hasattr(self,"coords") and hasattr(self,"header") and hasattr(vobj,"TextPosition") and hasattr(vobj,"FirstLine"):
                pos = self.getTextPosition(vobj)
                self.coords.translation.setValue([pos.x,pos.y,pos.z])
                up = vobj.FirstLine.Value * vobj.LineSpacing
                self.header.translation.setValue([0,up,0])

        elif prop == "LineSpacing":
            if hasattr(self,"text1") and hasattr(self,"text2") and hasattr(vobj,"LineSpacing"):
                self.text1.spacing = vobj.LineSpacing
                self.text2.spacing = vobj.LineSpacing
                self.onChanged(vobj,"TextPosition")

        elif prop == "TextAlign":
            if hasattr(self,"text1") and hasattr(self,"text2") and hasattr(vobj,"TextAlign"):
                from pivy import coin
                if vobj.TextAlign == "Center":
                    self.text1.justification = coin.SoAsciiText.CENTER
                    self.text2.justification = coin.SoAsciiText.CENTER
                elif vobj.TextAlign == "Right":
                    self.text1.justification = coin.SoAsciiText.RIGHT
                    self.text2.justification = coin.SoAsciiText.RIGHT
                else:
                    self.text1.justification = coin.SoAsciiText.LEFT
                    self.text2.justification = coin.SoAsciiText.LEFT
                    
        elif prop == "Visibility":
            if vobj.Visibility:
                self.label.whichChild = 0
            else:
                self.label.whichChild = -1
Пример #31
0
#*                                                                         *
#***************************************************************************

import math
import FreeCAD as App
import FreeCADGui as Gui
from FreeCAD import Vector, Matrix, Placement
import Part
from FreeCAD import Units
import Instance as ShipInstance
import WeightInstance
import TankInstance
from shipHydrostatics import Tools as Hydrostatics


G = Units.parseQuantity("9.81 m/s^2")
MAX_EQUILIBRIUM_ITERS = 10
DENS = Units.parseQuantity("1025 kg/m^3")
TRIM_RELAX_FACTOR = 10.0


def solve(ship, weights, tanks, rolls, var_trim=True):
    """Compute the ship GZ stability curve

    Position arguments:
    ship -- Ship object
    weights -- List of weights to consider
    tanks -- List of tanks to consider (each one should be a tuple with the
    tank instance, the density of the fluid inside, and the filling level ratio)
    rolls -- List of roll angles
Пример #32
0
#*                                                                         *
#***************************************************************************

import math
import random
from FreeCAD import Vector, Rotation, Matrix, Placement
import Part
from FreeCAD import Units
import FreeCAD as App
import FreeCADGui as Gui
from PySide import QtGui, QtCore
from .. import Instance
from ..shipUtils import Math
from ..shipUtils import Units as USys

DENS = Units.parseQuantity("1025 kg/m^3")  # Salt water
COMMON_BOOLEAN_ITERATIONS = 10


def placeShipShape(shape, draft, roll, trim):
    """Move the ship shape such that the free surface matches with the plane
    z=0. The transformation will be applied on the input shape, so copy it
    before calling this method if it should be preserved.

    Position arguments:
    shape -- Ship shape
    draft -- Ship draft
    roll -- Roll angle
    trim -- Trim angle

    Returned values:
Пример #33
0
 def get_distances(self):
     """Get the distance parameters from the widgets."""
     r_d_str = self.form.spinbox_r_distance.text()
     tan_d_str = self.form.spinbox_tan_distance.text()
     return (U.Quantity(r_d_str).Value,
             U.Quantity(tan_d_str).Value)
Пример #34
0
    def process_output(self, text):
        log_lines = text.split('\n')
        prev_niter = self.niter
        for line in log_lines:
            line = line.rstrip()
            split = line.split()

            # Only record the first residual per outer iteration
            if line.startswith(u"Time = "):
                try:
                    time_val = float(line.lstrip(u"Time = "))
                except ValueError:
                    pass
                else:
                    self.prev_time = self.latest_time
                    self.latest_time = time_val
                    self.prev_num_outer_iters = self.latest_outer_iter
                    if self.latest_time > 0:
                        # Don't keep spurious time zero
                        self.latest_outer_iter = 0
                        self.niter += 1
                    self.in_forces_section = None
                    self.in_forcecoeffs_section = None

            if line.find(u"PIMPLE: iteration ") >= 0 or line.find(
                    u"pseudoTime: iteration ") >= 0:
                self.latest_outer_iter += 1
                # Don't increment counter on first outer iter as this was already done with time
                if self.latest_outer_iter > 1:
                    self.niter += 1

            if line.startswith(u"forces") and (line.endswith(u"write:")
                                               or line.endswith(u"execute:")):
                self.in_forces_section = split[1]
            if line.startswith(u"forceCoeffs") and (
                    line.endswith(u"write:") or line.endswith(u"execute:")):
                self.in_forcecoeffs_section = split[1]
            if not line.strip():
                # Blank line
                self.in_forces_section = None
                self.in_forcecoeffs_section = None

            # Add a point to the time axis for each outer iteration
            if self.niter > len(self.time):
                self.time.append(self.latest_time)
                if self.latest_outer_iter > 0:
                    # Outer-iteration case
                    # Create virtual times to space the residuals of the outer iterations nicely on the time graph
                    self.prev_num_outer_iters = max(self.prev_num_outer_iters,
                                                    self.latest_outer_iter)
                    for i in range(self.latest_outer_iter):
                        self.time[-(
                            self.latest_outer_iter - i)] = self.prev_time + (
                                self.latest_time - self.prev_time) * (
                                    (i + 1) / self.prev_num_outer_iters)

            if "Ux," in split and self.niter > len(self.UxResiduals):
                self.UxResiduals.append(float(split[7].split(',')[0]))
            if "Uy," in split and self.niter > len(self.UyResiduals):
                self.UyResiduals.append(float(split[7].split(',')[0]))
            if "Uz," in split and self.niter > len(self.UzResiduals):
                self.UzResiduals.append(float(split[7].split(',')[0]))
            if "p," in split and self.niter > len(self.pResiduals):
                self.pResiduals.append(float(split[7].split(',')[0]))
            if "p_rgh," in split and self.niter > len(self.pResiduals):
                self.pResiduals.append(float(split[7].split(',')[0]))
            if "h," in split and self.niter > len(self.EResiduals):
                self.EResiduals.append(float(split[7].split(',')[0]))
            # HiSA coupled residuals
            if "Residual:" in split and self.niter > len(self.rhoResiduals):
                self.rhoResiduals.append(float(split[4]))
                self.UxResiduals.append(float(split[5].lstrip('(')))
                self.UyResiduals.append(float(split[6]))
                self.UzResiduals.append(float(split[7].rstrip(')')))
                self.EResiduals.append(float(split[8]))
            if "k," in split and self.niter > len(self.kResiduals):
                self.kResiduals.append(float(split[7].split(',')[0]))
            if "epsilon," in split and self.niter > len(self.epsilonResiduals):
                self.epsilonResiduals.append(float(split[7].split(',')[0]))
            if "omega," in split and self.niter > len(self.omegaResiduals):
                self.omegaResiduals.append(float(split[7].split(',')[0]))
            if "nuTilda," in split and self.niter > len(self.nuTildaResiduals):
                self.nuTildaResiduals.append(float(split[7].split(',')[0]))
            if "gammaInt," in split and self.niter > len(
                    self.gammaIntResiduals):
                self.gammaIntResiduals.append(float(split[7].split(',')[0]))
            if "ReThetat," in split and self.niter > len(
                    self.ReThetatResiduals):
                self.ReThetatResiduals.append(float(split[7].split(',')[0]))

            # Force monitors
            if self.in_forces_section:
                f = self.forces[self.in_forces_section]
                if (("Pressure" in split) or
                    ("pressure"
                     in split)) and self.niter - 1 > len(f['pressureXForces']):
                    f['pressureXForces'].append(float(split[2].lstrip("(")))
                    f['pressureYForces'].append(float(split[3]))
                    f['pressureZForces'].append(float(split[4].rstrip(")")))
                if (("Viscous" in split) or
                    ("viscous"
                     in split)) and self.niter - 1 > len(f['viscousXForces']):
                    f['viscousXForces'].append(float(split[2].lstrip("(")))
                    f['viscousYForces'].append(float(split[3]))
                    f['viscousZForces'].append(float(split[4].rstrip(")")))

            # Force coefficient monitors
            if self.in_forcecoeffs_section:
                fc = self.force_coeffs[self.in_forcecoeffs_section]
                if "Cd" in split and self.niter - 1 > len(fc['cdCoeffs']):
                    fc['cdCoeffs'].append(float(split[2]))
                if "Cl" in split and self.niter - 1 > len(fc['clCoeffs']):
                    fc['clCoeffs'].append(float(split[2]))

        # Update plots
        if self.niter > 1 and self.niter > prev_niter:
            self.solver.Proxy.residual_plotter.updateValues(
                self.time,
                OrderedDict([('$\\rho$', self.rhoResiduals),
                             ('$U_x$', self.UxResiduals),
                             ('$U_y$', self.UyResiduals),
                             ('$U_z$', self.UzResiduals),
                             ('$p$', self.pResiduals),
                             ('$E$', self.EResiduals),
                             ('$k$', self.kResiduals),
                             ('$\\epsilon$', self.epsilonResiduals),
                             ('$\\tilde{\\nu}$', self.nuTildaResiduals),
                             ('$\\omega$', self.omegaResiduals),
                             ('$\\gamma$', self.gammaIntResiduals),
                             ('$Re_{\\theta}$', self.ReThetatResiduals)]))

            for fn in self.forces:
                f = self.forces[fn]
                self.solver.Proxy.forces_plotters[fn].updateValues(
                    self.time,
                    OrderedDict([('$Pressure_x$', f['pressureXForces']),
                                 ('$Pressure_y$', f['pressureYForces']),
                                 ('$Pressure_z$', f['pressureZForces']),
                                 ('$Viscous_x$', f['viscousXForces']),
                                 ('$Viscous_y$', f['viscousYForces']),
                                 ('$Viscous_z$', f['viscousZForces'])]))

            for fcn in self.force_coeffs:
                fc = self.force_coeffs[fcn]
                self.solver.Proxy.force_coeffs_plotters[fcn].updateValues(
                    self.time,
                    OrderedDict([('$C_D$', fc['cdCoeffs']),
                                 ('$C_L$', fc['clCoeffs'])]))

        # Probes
        for pn in self.probes:
            p = self.probes[pn]
            if p['file'] is None:
                working_dir = CfdTools.getOutputPath(self.analysis)
                case_name = self.solver.InputCaseName
                solver_dir = os.path.abspath(
                    os.path.join(working_dir, case_name))
                try:
                    f = open(
                        os.path.join(solver_dir, 'postProcessing', pn, '0',
                                     p['field']))
                    p['file'] = f
                except OSError:
                    pass
            if p['file']:
                ntimes = len(p['time'])
                is_vector = False

                for l in p['file'].readlines():
                    l = l.strip()
                    if len(l) and not l.startswith('#'):
                        s = l.split()
                        p['time'].append(float(s[0]))

                        if s[1].startswith('('):
                            is_vector = True
                        while len(p['values']) < len(s) - 1:
                            p['values'].append([])
                        for i in range(1, len(s)):
                            s[i] = s[i].lstrip('(').rstrip(')')
                            p['values'][i - 1].append(float(s[i]))

                if len(p['time']) > ntimes:
                    legends = []
                    for pi in p['points']:
                        points_str = '({}, {}, {}) m'.format(
                            *(Units.Quantity(pij, Units.Length).getValueAs('m')
                              for pij in (pi.x, pi.y, pi.z)))
                        if is_vector:
                            legends.append('{}$_x$ @ '.format(p['field']) +
                                           points_str)
                            legends.append('{}$_y$ @ '.format(p['field']) +
                                           points_str)
                            legends.append('{}$_z$ @ '.format(p['field']) +
                                           points_str)
                        else:
                            legends.append('${}$ @ '.format(p['field']) +
                                           points_str)
                    self.solver.Proxy.probes_plotters[pn].updateValues(
                        p['time'], OrderedDict(zip(legends, p['values'])))
Пример #35
0
#***************************************************************************

import math
import random
from FreeCAD import Vector, Rotation, Matrix, Placement
import Part
from FreeCAD import Units
import FreeCAD as App
import FreeCADGui as Gui
from PySide import QtGui, QtCore
import Instance
from shipUtils import Math
import shipUtils.Units as USys


DENS = Units.parseQuantity("1025 kg/m^3")  # Salt water
COMMON_BOOLEAN_ITERATIONS = 10


def placeShipShape(shape, draft, roll, trim):
    """Move the ship shape such that the free surface matches with the plane
    z=0. The transformation will be applied on the input shape, so copy it
    before calling this method if it should be preserved.

    Position arguments:
    shape -- Ship shape
    draft -- Ship draft
    roll -- Roll angle
    trim -- Trim angle

    Returned values:
Пример #36
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))
Пример #37
0
def displacement(ship, draft=None,
                       roll=Units.parseQuantity("0 deg"),
                       trim=Units.parseQuantity("0 deg")):
    """Compute the ship displacement

    Position arguments:
    ship -- Ship object (see createShip)

    Keyword arguments:
    draft -- Ship draft (Design ship draft by default)
    roll -- Roll angle (0 degrees by default)
    trim -- Trim angle (0 degrees by default)

    Returned values:
    disp -- The ship displacement (a density of the water of 1025 kg/m^3 is
    assumed)
    B -- Bouyance application point, i.e. Center of mass of the underwater side
    Cb -- Block coefficient

    The Bouyance center is referred to the original ship position.
    """
    if draft is None:
        draft = ship.Draft

    shape, base_z = placeShipShape(ship.Shape.copy(), draft, roll, trim)
    shape = getUnderwaterSide(shape)

    vol = 0.0
    cog = Vector()
    if len(shape.Solids) > 0:
        for solid in shape.Solids:
            vol += solid.Volume
            sCoG = solid.CenterOfMass
            cog.x = cog.x + sCoG.x * solid.Volume
            cog.y = cog.y + sCoG.y * solid.Volume
            cog.z = cog.z + sCoG.z * solid.Volume
        cog.x = cog.x / vol
        cog.y = cog.y / vol
        cog.z = cog.z / vol

    bbox = shape.BoundBox
    Vol = (bbox.XMax - bbox.XMin) * (bbox.YMax - bbox.YMin) * abs(bbox.ZMin)

    # Undo the transformations on the bouyance point
    B = Part.Point(Vector(cog.x, cog.y, cog.z))
    m = Matrix()
    m.move(Vector(0.0, 0.0, draft))
    m.move(Vector(-draft * math.sin(trim.getValueAs("rad")), 0.0, 0.0))
    m.rotateY(trim.getValueAs("rad"))
    m.move(Vector(0.0,
                  -draft * math.sin(roll.getValueAs("rad")),
                  base_z))
    m.rotateX(-roll.getValueAs("rad"))
    B.transform(m)

    try:
        cb = vol / Vol
    except ZeroDivisionError:
        msg = QtGui.QApplication.translate(
            "ship_console",
            "ZeroDivisionError: Null volume found during the displacement"
            " computation!",
            None)
        App.Console.PrintError(msg + '\n')
        cb = 0.0


    # Return the computed data
    return (DENS * Units.Quantity(vol, Units.Volume),
            Vector(B.X, B.Y, B.Z),
            cb)
Пример #38
0
def parse(pathobj):

    global DRILL_RETRACT_MODE
    global MOTION_MODE
    global CURRENT_X
    global CURRENT_Y
    global CURRENT_Z

    out = ""
    lastcommand = None
    precision_string = '.' + str(PRECISION) + 'f'

    params = [
        'X', 'Y', 'Z', 'A', 'B', 'C', 'U', 'V', 'W', 'I', 'J', 'K', 'F', 'S',
        'T', 'Q', 'R', 'L', 'P'
    ]

    if hasattr(pathobj, "Group"):  # We have a compound or project.
        if OUTPUT_COMMENTS:
            out += linenumber() + "(Compound: " + pathobj.Label + ")\n"
        for p in pathobj.Group:
            out += parse(p)
        return out

    else:  # parsing simple path
        if not hasattr(
                pathobj,
                "Path"):  # groups might contain non-path things like stock.
            return out

        if OUTPUT_COMMENTS:
            out += linenumber() + "(Path: " + pathobj.Label + ")\n"

        for c in pathobj.Path.Commands:
            outstring = []
            command = c.Name

            outstring.append(command)

            # if modal: only print the command if it is not the same as the last one
            if MODAL:
                if command == lastcommand:
                    outstring.pop(0)

            # Now add the remaining parameters in order
            for param in params:
                if param in c.Parameters:
                    if param == 'F':
                        if command not in RAPID_MOVES:
                            speed = Units.Quantity(c.Parameters['F'],
                                                   FreeCAD.Units.Velocity)
                            if speed.getValueAs(UNIT_SPEED_FORMAT) > 0.0:
                                outstring.append(param + format(
                                    float(speed.getValueAs(UNIT_SPEED_FORMAT)),
                                    precision_string))
                    elif param in ['T', 'H', 'D', 'S', 'P', 'L']:
                        outstring.append(param + str(c.Parameters[param]))
                    elif param in ['A', 'B', 'C']:
                        outstring.append(
                            param +
                            format(c.Parameters[param], precision_string))
                    else:  # [X, Y, Z, U, V, W, I, J, K, R, Q] (Conversion eventuelle mm/inches)
                        pos = Units.Quantity(c.Parameters[param],
                                             FreeCAD.Units.Length)
                        outstring.append(
                            param + format(float(pos.getValueAs(UNIT_FORMAT)),
                                           precision_string))

            # store the latest command
            lastcommand = command

            # Memorizes the current position for calculating the related movements and the withdrawal plan
            if command in MOTION_COMMANDS:
                if 'X' in c.Parameters:
                    CURRENT_X = Units.Quantity(c.Parameters['X'],
                                               FreeCAD.Units.Length)
                if 'Y' in c.Parameters:
                    CURRENT_Y = Units.Quantity(c.Parameters['Y'],
                                               FreeCAD.Units.Length)
                if 'Z' in c.Parameters:
                    CURRENT_Z = Units.Quantity(c.Parameters['Z'],
                                               FreeCAD.Units.Length)

            if command in ('G98', 'G99'):
                DRILL_RETRACT_MODE = command

            if command in ('G90', 'G91'):
                MOTION_MODE = command

            if TRANSLATE_DRILL_CYCLES:
                if command in ('G81', 'G82', 'G83'):
                    out += drill_translate(outstring, command, c.Parameters)
                    # Erase the line we just translated
                    outstring = []

            if SPINDLE_WAIT > 0:
                if command in ('M3', 'M03', 'M4', 'M04'):
                    out += linenumber() + format_outstring(outstring) + "\n"
                    out += linenumber() + format_outstring(
                        ['G4', 'P%s' % SPINDLE_WAIT]) + "\n"
                    outstring = []

            # Check for Tool Change:
            if command in ('M6', 'M06'):
                if OUTPUT_COMMENTS:
                    out += linenumber() + "(Begin toolchange)\n"
                if not OUTPUT_TOOL_CHANGE:
                    outstring.insert(0, "(")
                    outstring.append(")")
                else:
                    for line in TOOL_CHANGE.splitlines(True):
                        out += linenumber() + line

            if command == "message":
                if OUTPUT_COMMENTS is False:
                    out = []
                else:
                    outstring.pop(0)  # remove the command

            if command in SUPPRESS_COMMANDS:
                outstring.insert(0, "(")
                outstring.append(")")

            # prepend a line number and append a newline
            if len(outstring) >= 1:
                out += linenumber() + format_outstring(outstring) + "\n"

    return out
Пример #39
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"
                        )
Пример #40
0
def drill_translate(outstring, cmd, params):
    global DRILL_RETRACT_MODE
    global MOTION_MODE
    global CURRENT_X
    global CURRENT_Y
    global CURRENT_Z
    global UNITS
    global UNIT_FORMAT
    global UNIT_SPEED_FORMAT

    strFormat = '.' + str(PRECISION) + 'f'

    trBuff = ""

    if OUTPUT_COMMENTS:  # Comment the original command
        outstring[0] = "(" + outstring[0]
        outstring[-1] = outstring[-1] + ")"
        trBuff += linenumber() + format_outstring(outstring) + "\n"

    # cycle conversion
    # currently only cycles in XY are provided (G17)
    # other plains ZX (G18) and  YZ (G19) are not dealt with : Z drilling only.
    drill_X = Units.Quantity(params['X'], FreeCAD.Units.Length)
    drill_Y = Units.Quantity(params['Y'], FreeCAD.Units.Length)
    drill_Z = Units.Quantity(params['Z'], FreeCAD.Units.Length)
    RETRACT_Z = Units.Quantity(params['R'], FreeCAD.Units.Length)
    # R less than Z is error
    if RETRACT_Z < drill_Z:
        trBuff += linenumber() + "(drill cycle error: R less than Z )\n"
        return trBuff

    if MOTION_MODE == 'G91':  # G91 relative movements
        drill_X += CURRENT_X
        drill_Y += CURRENT_Y
        drill_Z += CURRENT_Z
        RETRACT_Z += CURRENT_Z

    if DRILL_RETRACT_MODE == 'G98' and CURRENT_Z >= RETRACT_Z:
        RETRACT_Z = CURRENT_Z

    # get the other parameters
    drill_Speed = Units.Quantity(params['F'], FreeCAD.Units.Velocity)
    if cmd == 'G83':
        drill_Step = Units.Quantity(params['Q'], FreeCAD.Units.Length)
        a_bit = drill_Step * 0.05  # NIST 3.5.16.4 G83 Cycle:  "current hole bottom, backed off a bit."
    elif cmd == 'G82':
        drill_DwellTime = params['P']

    # wrap this block to ensure machine MOTION_MODE is restored in case of error
    try:
        if MOTION_MODE == 'G91':
            trBuff += linenumber(
            ) + "G90\n"  # force absolute coordinates during cycles

        strG0_RETRACT_Z = 'G0 Z' + format(
            float(RETRACT_Z.getValueAs(UNIT_FORMAT)), strFormat) + "\n"
        strF_Drill_Speed = ' F' + format(
            float(drill_Speed.getValueAs(UNIT_SPEED_FORMAT)), '.2f') + "\n"

        # preliminary mouvement(s)
        if CURRENT_Z < RETRACT_Z:
            trBuff += linenumber() + strG0_RETRACT_Z
        trBuff += linenumber() + 'G0 X' + format(
            float(drill_X.getValueAs(UNIT_FORMAT)), strFormat) + ' Y' + format(
                float(drill_Y.getValueAs(UNIT_FORMAT)), strFormat) + "\n"
        if CURRENT_Z > RETRACT_Z:
            #    trBuff += linenumber() + 'G0 Z' + format(float(CURRENT_Z.getValueAs(UNIT_FORMAT)), strFormat) + "\n"  # not following NIST 3.5.16.1 Preliminary and In-Between Motion
            trBuff += linenumber() + strG0_RETRACT_Z
        last_Stop_Z = RETRACT_Z

        # drill moves
        if cmd in ('G81', 'G82'):
            trBuff += linenumber() + 'G1 Z' + format(
                float(drill_Z.getValueAs(UNIT_FORMAT)),
                strFormat) + strF_Drill_Speed
            # pause where applicable
            if cmd == 'G82':
                trBuff += linenumber() + 'G4 P' + str(drill_DwellTime) + "\n"
            trBuff += linenumber() + strG0_RETRACT_Z
        else:  # 'G83'
            if params['Q'] != 0:
                while 1:
                    if last_Stop_Z != RETRACT_Z:
                        clearance_depth = last_Stop_Z + a_bit
                        trBuff += linenumber() + 'G0 Z' + format(
                            float(clearance_depth.getValueAs(UNIT_FORMAT)),
                            strFormat) + "\n"
                    next_Stop_Z = last_Stop_Z - drill_Step
                    if next_Stop_Z > drill_Z:
                        trBuff += linenumber() + 'G1 Z' + format(
                            float(next_Stop_Z.getValueAs(UNIT_FORMAT)),
                            strFormat) + strF_Drill_Speed
                        trBuff += linenumber() + strG0_RETRACT_Z
                        last_Stop_Z = next_Stop_Z
                    else:
                        trBuff += linenumber() + 'G1 Z' + format(
                            float(drill_Z.getValueAs(UNIT_FORMAT)),
                            strFormat) + strF_Drill_Speed
                        trBuff += linenumber() + strG0_RETRACT_Z
                        break

    except Exception as e:
        pass

    if MOTION_MODE == 'G91':
        trBuff += linenumber() + 'G91'  # Restore if changed

    return trBuff
Пример #41
0
def areas(ship,
          n,
          draft=None,
          roll=Units.parseQuantity("0 deg"),
          trim=Units.parseQuantity("0 deg")):
    """Compute the ship transversal areas

    Position arguments:
    ship -- Ship object (see createShip)
    n -- Number of points to compute

    Keyword arguments:
    draft -- Ship draft (Design ship draft by default)
    roll -- Roll angle (0 degrees by default)
    trim -- Trim angle (0 degrees by default)

    Returned value:
    List of sections, each section contains 2 values, the x longitudinal
    coordinate, and the transversal area. If n < 2, an empty list will be
    returned.
    """
    if n < 2:
        return []

    if draft is None:
        draft = ship.Draft

    shape, _ = placeShipShape(ship.Shape.copy(), draft, roll, trim)
    shape = getUnderwaterSide(shape)

    # Sections distance computation
    bbox = shape.BoundBox
    xmin = bbox.XMin
    xmax = bbox.XMax
    dx = (xmax - xmin) / (n - 1.0)

    # Since we are computing the sections in the total length (not in the
    # length between perpendiculars), we can grant that the starting and
    # ending sections have null area
    areas = [(Units.Quantity(xmin,
                             Units.Length), Units.Quantity(0.0, Units.Area))]
    # And since we just need to compute areas we will create boxes with its
    # front face at the desired transversal area position, computing the
    # common solid part, dividing it by faces, and getting only the desired
    # ones.
    App.Console.PrintMessage("Computing transversal areas...\n")
    App.Console.PrintMessage("Some Inventor representation errors can be"
                             " shown, please ignore them.\n")
    for i in range(1, n - 1):
        App.Console.PrintMessage("{0} / {1}\n".format(i, n - 2))
        x = xmin + i * dx
        try:
            f = Part.Face(shape.slice(Vector(1, 0, 0), x))
        except Part.OCCError:
            msg = QtGui.QApplication.translate(
                "ship_console",
                "Part.OCCError: Transversal area computation failed", None)
            App.Console.PrintError(msg + '\n')
            areas.append((Units.Quantity(x, Units.Length),
                          Units.Quantity(0.0, Units.Area)))
            continue
        # It is a valid face, so we can add this area
        areas.append(
            (Units.Quantity(x,
                            Units.Length), Units.Quantity(f.Area, Units.Area)))
    # Last area is equal to zero (due to the total length usage)
    areas.append(
        (Units.Quantity(xmax, Units.Length), Units.Quantity(0.0, Units.Area)))
    App.Console.PrintMessage("Done!\n")
    return areas
Пример #42
0
 def getClmax(self):
     return Units.Quantity(self.clmax, Units.Length)
Пример #43
0
def displacement(ship,
                 draft=None,
                 roll=Units.parseQuantity("0 deg"),
                 trim=Units.parseQuantity("0 deg")):
    """Compute the ship displacement

    Position arguments:
    ship -- Ship object (see createShip)

    Keyword arguments:
    draft -- Ship draft (Design ship draft by default)
    roll -- Roll angle (0 degrees by default)
    trim -- Trim angle (0 degrees by default)

    Returned values:
    disp -- The ship displacement (a density of the water of 1025 kg/m^3 is
    assumed)
    B -- Bouyance application point, i.e. Center of mass of the underwater side
    Cb -- Block coefficient

    The Bouyance center is referred to the original ship position.
    """
    if draft is None:
        draft = ship.Draft

    shape, base_z = placeShipShape(ship.Shape.copy(), draft, roll, trim)
    shape = getUnderwaterSide(shape)

    vol = 0.0
    cog = Vector()
    if len(shape.Solids) > 0:
        for solid in shape.Solids:
            vol += solid.Volume
            sCoG = solid.CenterOfMass
            cog.x = cog.x + sCoG.x * solid.Volume
            cog.y = cog.y + sCoG.y * solid.Volume
            cog.z = cog.z + sCoG.z * solid.Volume
        cog.x = cog.x / vol
        cog.y = cog.y / vol
        cog.z = cog.z / vol

    bbox = shape.BoundBox
    Vol = (bbox.XMax - bbox.XMin) * (bbox.YMax - bbox.YMin) * abs(bbox.ZMin)

    # Undo the transformations on the bouyance point
    B = Part.Point(Vector(cog.x, cog.y, cog.z))
    m = Matrix()
    m.move(Vector(0.0, 0.0, draft))
    m.move(Vector(-draft * math.sin(trim.getValueAs("rad")), 0.0, 0.0))
    m.rotateY(trim.getValueAs("rad"))
    m.move(Vector(0.0, -draft * math.sin(roll.getValueAs("rad")), base_z))
    m.rotateX(-roll.getValueAs("rad"))
    B.transform(m)

    try:
        cb = vol / Vol
    except ZeroDivisionError:
        msg = QtGui.QApplication.translate(
            "ship_console",
            "ZeroDivisionError: Null volume found during the displacement"
            " computation!", None)
        App.Console.PrintError(msg + '\n')
        cb = 0.0

    # Return the computed data
    return (DENS * Units.Quantity(vol, Units.Volume), Vector(B.X, B.Y,
                                                             B.Z), cb)
Пример #44
0
    def accept(self):
        if not self.ship:
            return False
        if self.running:
            return
        self.save()

        mw = self.getMainWindow()
        form = mw.findChild(QtGui.QWidget, "TaskPanel")
        form.trim = self.widget(QtGui.QLineEdit, "Trim")
        form.minDraft = self.widget(QtGui.QLineEdit, "MinDraft")
        form.maxDraft = self.widget(QtGui.QLineEdit, "MaxDraft")
        form.nDraft = self.widget(QtGui.QSpinBox, "NDraft")

        trim = Units.parseQuantity(Locale.fromString(form.trim.text()))
        min_draft = Units.parseQuantity(Locale.fromString(form.minDraft.text()))
        max_draft = Units.parseQuantity(Locale.fromString(form.maxDraft.text()))
        n_draft = form.nDraft.value()

        draft = min_draft
        drafts = [draft]
        dDraft = (max_draft - min_draft) / (n_draft - 1)
        for i in range(1, n_draft):
            draft = draft + dDraft
            drafts.append(draft)

        # Get external faces
        self.loop = QtCore.QEventLoop()
        self.timer = QtCore.QTimer()
        self.timer.setSingleShot(True)
        QtCore.QObject.connect(self.timer,
                               QtCore.SIGNAL("timeout()"),
                               self.loop,
                               QtCore.SLOT("quit()"))
        self.running = True
        faces = self.externalFaces(self.ship.Shape)
        if not self.running:
            return False
        if len(faces) == 0:
            msg = QtGui.QApplication.translate(
                "ship_console",
                "Failure detecting external faces from the ship object",
                None)
            App.Console.PrintError(msg + '\n')
            return False
        faces = Part.makeShell(faces)

        # Get the hydrostatics
        msg = QtGui.QApplication.translate(
            "ship_console",
            "Computing hydrostatics",
            None)
        App.Console.PrintMessage(msg + '...\n')
        points = []
        for i in range(len(drafts)):
            App.Console.PrintMessage("\t{} / {}\n".format(i + 1, len(drafts)))
            draft = drafts[i]
            point = Tools.Point(self.ship,
                                faces,
                                draft,
                                trim)
            points.append(point)
            self.timer.start(0.0)
            self.loop.exec_()
            if(not self.running):
                break
        PlotAux.Plot(self.ship, trim, points)
        return True