Beispiel #1
0
 def __init__(self, forces_model, report, pinted=False):
     # You can do this in 5 lines. But this is readable. Deal with it ¬¬,
     try:
         if isinstance(forces_model, dict):
             self.use = forces_model['use']
             if pinted:
                 self.P = forces_model['P']
                 self.V2 = forces_model['V2']
                 self.V3 = forces_model['V3']
                 self.M2 = forces_model['M2']
                 self.M3 = forces_model['M3']
                 self.T = forces_model['T']
             else:
                 self.P = Q(D(forces_model['P']), 'kN')
                 self.V2 = Q(D(forces_model['V2']), 'kN')
                 self.V3 = Q(D(forces_model['V3']), 'kN')
                 self.M2 = Q(D(forces_model['M2']), 'kN*m')
                 self.M3 = Q(D(forces_model['M3']), 'kN*m')
                 self.T = Q(D(forces_model['T']), 'kN*m')
         else:
             self.use = forces_model.use
             self.P = Q(forces_model.P, "kN")
             self.V2 = Q(forces_model.V2, "kN")
             self.V3 = Q(forces_model.V3, "kN")
             self.M2 = Q(forces_model.M2, "kN*m")
             self.M3 = Q(forces_model.M3, "kN*m")
             self.T = Q(forces_model.T, "kN*m")
         self.V = self.getV()
         self.M = self.getM()
         if report:
             self.reportSetup(report)
     except Exception as e:
         raise CalengCrash("Not a valid ForcesSet: " + str(e))
Beispiel #2
0
    def sum_to_this_uls(self, forces, report):
        """ This method returns resultant forces, suming self.uls_forces
            with the given as positional argument """
        try:
            top_V2 = self.top_uls * D(math.sin(self.top_ang))
            top_P = self.top_uls * D(math.cos(self.top_ang))
            bottom_V2 = -self.bottom_uls * D(math.sin(self.bottom_ang))
            bottom_P = self.bottom_uls * D(math.cos(self.top_ang))
            left_V3 = -self.left_uls * D(math.sin(self.left_ang))
            left_P = self.left_uls * D(math.cos(self.left_ang))
            right_V3 = self.right_uls * D(math.sin(self.right_ang))
            right_P = self.right_uls * D(math.cos(self.right_ang))

            P = forces.P + top_P + bottom_P + left_P + right_P
            V2 = forces.V2 + top_V2 + bottom_V2
            V3 = forces.V3 + left_V3 + right_V3
            # Future development: eccentricity in bracings. Will be needed to
            # update M2, M3 and T. For now this is enough.
            M2 = forces.M2
            M3 = forces.M3
            T = forces.T
            forces_dict = {
                'use': "TOTAL ULS",
                'P': P,
                'V2': V2,
                'V3': V3,
                'M2': M2,
                'M3': M3,
                'T': T,
            }
            uls_forces = ForcesSet(forces_dict, report, pinted=True)
        except Exception as e:
            raise CalengCrash("Can't compute composed ULS resultant forces: " +
                              str(e))
        return uls_forces
Beispiel #3
0
 def __init__(self, profile, dummy_bolted_plate, report):
     if profile.profile_type != "L":
         raise CalengCrash("Clip Angle must be a L Shaped Profile")
     self.profile_db_object = profile.get_mat_db_object()
     self.use = profile.use
     self.thickness = Q(self.profile_db_object.t, 'mm')
     self.locked_edges = []
     self.width = Q(self.profile_db_object.b, 'mm')
     self.length = Q(self.profile_db_object.h, 'mm')
     if self.width != self.length:
         # To avoid this crash, a lot of shit must be reviewed.
         # S006 soolver sets ec1 = ec3.
         # A second bolt array must be added... f**k a lot of things.
         raise CalengCrash("Only simmetric L Clip Angle alowed")
     solve_from_steel_mat(self, profile.material)
     self.setup_e(dummy_bolted_plate, report)
     if report:
         self.reportSetup(report)
Beispiel #4
0
 def bolt_the_flange(self, ba, bp, report):
     if self.profile_type == "H":
         pass
     elif self.profile_type == "U":
         pass
     else:
         raise CalengCrash("UNIMPLEMENTED BOLTED PROFILE "
                           "DIFFERENT FROM H OR U")
     self.bolted_flange = BoltedFlange(self, ba, bp, report)
Beispiel #5
0
    def getFv_Ed_max(self, forces, report):
        # Return if already computed
        hash_of_forces = hash(forces) + hash(self)
        if hash_of_forces in self.computed_Fv_Ed.keys():
            return self.computed_Fv_Ed.get(hash_of_forces)

        desc_string = "SHEAR BOLT ARRAY: COMPUTING MAX SHEAR AT BOLTS"\
                      " | {}".format(forces.use)
        report.addLine(101, 20, desc_string, "")
        desc_string = "In plane shear distribution"
        calc_string = "n = " + str(self.n)
        report.addLine(100, 20, desc_string, calc_string)

        # If only one bolt, cant be torsion. Or crash.
        if not Q(D(-1), "N*mm") < forces.T < Q(D(1), "N*mm"):
            if self.n == 1:
                raise CalengCrash("One single bolt can't"
                                  " resist torsion forces!!")
        # else (T = 0), we dont need to compute anything else.
        else:
            Fv_Ed = (forces.V / self.n).to("kN")
            desc_string = "Max shear (no torsion)"
            calc_string = "Fv_Ed = " + str(Fv_Ed)
            report.addLine(100, 20, desc_string, calc_string)
            self.computed_Fv_Ed[hash_of_forces] = Fv_Ed
            return Fv_Ed

        sum_A_d2 = Q(D(0), "mm**4")
        max_A_d = Q(D(0), "mm**3")

        # Distribution of shear: shear_share
        for b in self.get_bolt_matrix():
            if b[5] * self.bolt.A > max_A_d:
                max_A_d = b[5] * self.bolt.A
            sum_A_d2 += b[5]**2 * self.bolt.A
            desc_string = "Bolt " + str(b[0]) + ": row = " + str(b[1]) +\
                          ", col = " + str(b[2])
            calc_string = "d = " + str(b[5])
            report.addLine(100, 20, desc_string, calc_string)

        report.addLine(100, 20, "Total Inertia", "I = " + str(sum_A_d2))
        shear_share = max_A_d / sum_A_d2

        # Getting worst bolt Fv_Ed
        Fv_Ed_T = (forces.T * shear_share).to("kN")
        desc_string = "Max shear due to torsion"
        calc_string = "Fv_Ed_T = " + str(Fv_Ed_T)
        report.addLine(100, 20, desc_string, calc_string)

        Fv_Ed = (Fv_Ed_T + forces.V / self.n).to("kN")
        desc_string = "Max shear (including torsion)"
        calc_string = "Fv_Ed = " + str(Fv_Ed)
        report.addLine(100, 20, desc_string, calc_string)
        self.computed_Fv_Ed[hash_of_forces] = Fv_Ed
        return Fv_Ed
Beispiel #6
0
    def check(self, sls_forces, uls_forces, report):

        if sls_forces.P.magnitude != 0 or sls_forces.M.magnitude != 0 \
                or uls_forces.P.magnitude != 0 or uls_forces.M.magnitude != 0:
            raise CalengCrash("Not a ShearForcesSet provided"
                              " to ShearBoltArray.check()")
        else:
            Fv_Ed_max_sls = self.getFv_Ed_max(sls_forces, report)
            Fv_Ed_max_uls = self.getFv_Ed_max(uls_forces, report)
            bolt_check = self.bolt.check(Q(0, "kN"), Fv_Ed_max_sls, Q(0, "kN"),
                                         Fv_Ed_max_uls, report)
            # Its needed to return de check status
            return bolt_check
Beispiel #7
0
    def check(self, sls_forces, uls_forces, report):

        # If not shear forces, Crash.
        if sls_forces.T.magnitude != 0 or sls_forces.V.magnitude != 0 \
                or uls_forces.T.magnitude != 0 or uls_forces.V.magnitude != 0:
            raise CalengCrash("Not a FrontForcesSet provided"
                              " to TensionBoltArray.check()")

        else:
            Ft_Ed_max_sls = self.getFt_Ed_max(sls_forces, report)
            Ft_Ed_max_uls = self.getFt_Ed_max(uls_forces, report)
            bolt_check = self.bolt.check(Ft_Ed_max_sls, Q(0, "kN"),
                                         Ft_Ed_max_uls, Q(0, "kN"), report)
            return bolt_check
Beispiel #8
0
    def solveFromSize(self, size_model):
        if isinstance(size_model, int):
            size_model = BoltSizeList.objects.get(id=int(size_model))
        elif isinstance(size_model, str):
            size_model = BoltSizeList.objects.get(name=size_model)
        try:
            self.length = Q(size_model.length, "mm")
            self.diameter = Q(size_model.diameter, "mm")
            self.shaft_length = Q(size_model.shaft_length, "mm")
            self.A = Q(size_model.A, "mm**2")
            self.As = Q(size_model.As, "mm**2")
            self.dm = Q(size_model.dm, "mm")
            self.size_name = size_model.name

            if self.bolt_holes == "N":
                self.d0 = Q(size_model.hole, "mm")
            elif self.bolt_holes == "O":
                self.d0 = Q(size_model.os_hole, "mm")
            else:
                raise CalengCrash("Hole diameters are only defined for normal"
                                  " or oversized holes")
        except Exception as e:
            raise CalengCrash("Something happend when solving bolt parameters"
                              " from provided bolt size. Exc: " + str(e))
Beispiel #9
0
 def solveFromGrade(self, grade_model):
     if isinstance(grade_model, int):
         grade_model = BoltMaterialList.objects.get(id=int(grade_model))
     elif isinstance(grade_model, str):
         grade_model = BoltMaterialList.objects.get(name=grade_model)
     try:
         self.fub = Q(grade_model.fub, "MPa")
         self.fyb = Q(grade_model.fyb, "MPa")
         self.Ym2 = D(1.25)
         if self.fub.magnitude < 401:
             self.Ym2 = D(1.50)
         self.E = Q(grade_model.E, "MPa")
         self.grade_name = grade_model.name
     except Exception as e:
         raise CalengCrash("Something happend when solving bolt parameters"
                           " from provided bolt grade. Exc: " + str(e))
Beispiel #10
0
 def __init__(self, t, fyd, bolt, e, m1, m2, rp):
     self.type = "Corner T-Stub"
     self.thickness = t
     self.fyd = fyd
     self.bolt = bolt
     self.e = e
     self.m1 = m1
     self.m2 = m2
     self.m = m1
     self.n = min(e, D(1.25) * self.m)
     self.n1 = min(e, D(1.25) * m1)
     lambda1 = self.m1 / (self.m1 + self.e)
     lambda2 = self.m2 / (self.m1 + self.e)  # This is ok! don't change
     try:
         self.alfa = Q(D(get_alfa(lambda1.magnitude, lambda2.magnitude)))
     except Exception as e:
         raise CalengCrash("Could not set tstub alfa: " + str(e))
     self.leff = self.alfa * self.m
Beispiel #11
0
def solve_from_steel_mat(self, mat, report=None):
    try:
        if isinstance(mat, str):
            team = report.calc.user.profile.team
            q_object = Q_obj(team=team) | Q_obj(braced_builtin=True)
            steelmat = SteelMaterialList.objects.filter(q_object).get(name=mat)
        else:
            steelmat = mat
        self.fu = Q(D(steelmat.fu), "MPa")
        self.fy = Q(D(steelmat.fy), "MPa")
        self.Ym0 = D(1)  # TO FIX MAYBE FROM DB I DONT KNOW
        self.Ym1 = D(1)  # TO FIX MAYBE FROM DB I DONT KNOW
        self.Ym2 = D(1.25)  # SAME
        self.E = Q(D(steelmat.E), "MPa")
        self.G = Q(D(steelmat.E), "MPa")
        self.material_name = steelmat.name
    except Exception as e:
        raise CalengCrash("Something happened when solving steel materials"
                          " from provided material object. Exc: " + str(e))
Beispiel #12
0
    def rot90(self, axis, times, use, report):
        """ axis is an integer 1,2,3. Times is an integer representing
            the number of times to 90 degree rotate in the direction of
            the axis. The comboname is a string to represent this new
            forces set """
        forces = [self.P, self.V2, self.V3]
        moments = [self.T, self.M2, self.M3]

        for i in range(0, times):
            if axis == 1:
                forces = [forces[0], -forces[2], forces[1]]
                moments = [moments[0], -moments[2], moments[1]]
            elif axis == 2:
                forces = [forces[2], forces[1], -forces[0]]
                moments = [moments[2], moments[1], -moments[0]]
            elif axis == 3:
                forces = [-forces[1], forces[0], forces[2]]
                moments = [-moments[1], moments[0], moments[2]]
            else:
                forces = forces
                moments = moments
                raise CalengCrash("ForcesSet.rot90() needs an integer"
                                  " 1, 2 or 3.")

        if report:
            desc_string = "Generating rotated forces"
            report.addLine(100, 10, desc_string, use)

        # return rotated new object (all copied to avoid cagadas!)
        new_forces_set = copy(self)
        new_forces_set.P = copy(forces[0])
        new_forces_set.V2 = copy(forces[1])
        new_forces_set.V3 = copy(forces[2])
        new_forces_set.T = copy(moments[0])
        new_forces_set.M2 = copy(moments[1])
        new_forces_set.M3 = copy(moments[2])
        new_forces_set.V = new_forces_set.getV()
        new_forces_set.M = new_forces_set.getM()
        new_forces_set.use = use
        if report:
            new_forces_set.reportSetup(report)

        return new_forces_set
Beispiel #13
0
    def __init__(self, t, fyd, bolt, e, e_other, m, bp, w, leff, rp):
        if t.magnitude == 0:
            raise CalengCrash("Plate thickness cant be 0")
        self.type = "Simple T-Stub"
        self.thickness = t
        self.fyd = fyd
        self.e = e
        self.m = m
        self.bolt = bolt
        self.n = min(e, D(1.25) * m)
        self.leff = min(
            D(4) * m + D(1.25) * e,
            e_other + D(2) * m + D(0.625) * e,
            D(0.5) * bp,
            D(0.5) * w + D(2) * m + D(0.625) * e,
        )

        desc_string = "Single T Stub | Bolt " + str(bolt[0])
        calc_string = "e={},m={},n={},leff={}"\
                      .format(self.e, self.m, self.n, self.leff)
        rp.addLine(100, 30, desc_string, calc_string)
Beispiel #14
0
    def getFs_Rd(self, report):

        if not self.preloaded:
            raise CalengCrash("Can't get Fs_Rd in a snug tight bolt!")
        else:
            desc_string = "PRELOADED BOLT: SOLVING SLIP-RESISTANT CAPACITY"
            report.addLine(101, 20, desc_string, "")

            # solving
            Fs_Rd = (self.n * self.ks1 * self.mu * self.Fp_C /
                     self.Ym3).to("kN")

            # reporting
            desc_string = "Preloaded bolt parameters"
            calc_string = "μ = " + str(self.mu) + ", ks = " + str(self.ks1) +\
                          ", Fp_C = " + str(self.Fp_C)
            report.addLine(100, 20, desc_string, calc_string)
            desc_string = "Max Slip-Resistant per-bolt capacity"
            calc_string = "Fs_Rd = " + str(Fs_Rd)
            report.addLine(100, 20, desc_string, calc_string)

            return Fs_Rd
Beispiel #15
0
def get_dist_list(string):
    try:
        elements = string.split()
        dist_list = []
        for index, element in enumerate(elements):
            if "*" in element:
                times = element.split("*")[0]
                dist = element.split("*")[1]
                li = [dist] * int(times)
                dist_list.extend(li)
            else:
                dist_list.append(element)

        # Now we need to verify all data. A evil user can f**k us here
        # If something crashes we raise a message
        return_list = []
        for item in dist_list:
            return_list.append(Q(D(item), "mm"))
    except Exception as e:
        raise CalengCrash("Crashed when parsing tekla notation distances: " +
                          str(e))
    return return_list
Beispiel #16
0
 def __init__(self, model, report):
     try:
         if isinstance(model, dict):
             self.left_bracing = model['left_bracing']
             self.right_bracing = model['right_bracing']
             self.top_bracing = model['top_bracing']
             self.bottom_bracing = model['bottom_bracing']
             self.left_uls = Q(D(model['left_uls']), "kN")
             self.right_uls = Q(D(model['right_uls']), "kN")
             self.top_uls = Q(D(model['top_uls']), "kN")
             self.bottom_uls = Q(D(model['bottom_uls']), "kN")
             self.left_sls = Q(D(model['left_sls']), "kN")
             self.right_sls = Q(D(model['right_sls']), "kN")
             self.top_sls = Q(D(model['top_sls']), "kN")
             self.bottom_sls = Q(D(model['bottom_sls']), "kN")
             self.left_ang = Q(D(model['left_ang']), "degrees")
             self.right_ang = Q(D(model['right_ang']), "degrees")
             self.top_ang = Q(D(model['top_ang']), "degrees")
             self.bottom_ang = Q(D(model['bottom_ang']), "degrees")
         else:
             self.left_bracing = model.left_bracing
             self.right_bracing = model.right_bracing
             self.top_bracing = model.top_bracing
             self.bottom_bracing = model.bottom_bracing
             self.left_uls = Q(D(model.left_uls), "kN")
             self.right_uls = Q(D(model.right_uls), "kN")
             self.top_uls = Q(D(model.top_uls), "kN")
             self.bottom_uls = Q(D(model.bottom_uls), "kN")
             self.left_sls = Q(D(model.left_sls), "kN")
             self.right_sls = Q(D(model.right_sls), "kN")
             self.top_sls = Q(D(model.top_sls), "kN")
             self.bottom_sls = Q(D(model.bottom_sls), "kN")
             self.left_ang = Q(D(model.left_ang), "degrees")
             self.right_ang = Q(D(model.right_ang), "degrees")
             self.top_ang = Q(D(model.top_ang), "degrees")
             self.bottom_ang = Q(D(model.bottom_ang), "degrees")
         self.report_setup(report)
     except Exception as e:
         raise CalengCrash("Not a valid ExtraBracingForces: " + str(e))
Beispiel #17
0
def solve_from_polygons_legacy(plate, profile, position, bolt_array, report):
    """ Returns a list of tstub objects from given elements """

    # usefull stuff
    t = plate.thickness
    fyd = plate.fy / plate.Ym0
    bolts = bolt_array.get_bolt_matrix()
    tstub_list = []

    # Get the profile positioned polygon
    rotated_pol = profile.get_polygon(report)
    # rotated_pol = affinity.rotate(
    #     unpos_profile_pol,
    #     float(position.rotation.magnitude),
    #     origin=Point(0, 0))
    profile_pol = affinity.translate(rotated_pol,
                                     xoff=-float(position.g1.magnitude),
                                     yoff=-float(position.g2.magnitude))
    # Get the plate polygon
    plate_pol = plate.get_polygon(report)

    # Get the profile square boundary
    pb = profile_pol.bounds

    # Return void list if profile is 0 sized
    if len(pb) < 3:
        report.addLine(100, 30, "Empty profile. No TSTUB solved",
                       "MANUAL REVIEW REQUIRED")
        return []
    else:
        profile_boundary = Polygon((
            (pb[2], pb[3]),
            (pb[2], pb[1]),
            (pb[0], pb[1]),
            (pb[0], pb[3]),
        ))

    if plate_pol.disjoint(profile_pol):
        raise CalengCrash("Profile boundary is outside plate!")

    # Outside plate and inside plate different tstub types
    out_plate = plate_pol.difference(profile_boundary)

    out_bolts = []
    in_bolts = []

    # Bolt data: (i, row, col, x1, x2, d, A, As)
    for bolt in bolts:
        point = Point(bolt[3].magnitude, bolt[4].magnitude)
        if point.within(out_plate):
            out_bolts.append(bolt)
        elif point.within(profile_boundary):
            in_bolts.append(bolt)
        else:
            print("Quizas este justo en el contorno. no?")
            raise CalengCrash("Problem at tstubs.solve_from_polygons()")

    # If profile is a pipe, we create SimpleTstub objects as if it were a tube
    # +---------+ +---------+
    # | +  |  + | | 1  |  2 |   <- We choose the worst m distance (biggest)
    # |---- ----| |---- ----|      it may be in the 1 or 2 direction.
    # |         | |         |
    # |---- ----| |---- ----|
    # | +  |  + | | 3  |  4 |
    # +---------+ +---------+
    # TUBE is the same shit
    if profile.profile_type == "PIP" or profile.profile_type == "TUB":
        for bolt in out_bolts:
            point = Point(bolt[3].magnitude, bolt[4].magnitude)
            # e = Q(D(point.distance(plate_pol.exterior)), "mm")
            e = plate.e2_main
            e_other = plate.e1_main
            bp = plate.width
            w = np.max(bolt_array.p1)
            m = Q(D(point.distance(profile_pol)), "mm")
            leff1 = plate.width / bolt_array.n1
            leff2 = plate.length / bolt_array.n2
            leff = min(leff1, leff2)
            args = (t, fyd, bolt, e, e_other, m, bp, w, leff, report)
            tstub = SimpleTStub(*args)
            tstub_list.append(tstub)

    # If profile is an H, we create SimpleTStub objects for the outter bolts
    # but we need to create CornerTStub objects for bolts between flanges
    # These bolts are into "in_bolts" list
    # +-----------+ +-----------+
    # |  +     +  | | 1   |   2 |   <- We choose the worst m distance (biggest)
    # |  _______  | |----- -----|      it may be in the 1 or 2 direction.
    # |  +  |  +  | | 3   |   4 |   <- 3 and 4 are CornerTstubs
    # |  _______  | |----- -----|
    # |  +     +  | | 5   |   6 |
    # +-----------+ +-----------+

    # If profile is U: Same as H but with only one side with CornerTStubs
    # +-----------+ +-----------+
    # |  +     +  | | 1   |   2 |   <- We choose the worst m distance (biggest)
    # |     ____  | |----- -----|      it may be in the 1 or 2 direction.
    # |  +  |  +  | | 3   |   4 |   <- only 4 is a CornerTstubs
    # |     ____  | |----- -----|
    # |  +     +  | | 5   |   6 |
    # +-----------+ +-----------+

    # If profile is L, same as U but may be a bug.

    else:  # ELSE: Profile is H, U or L
        for bolt in out_bolts:
            point = Point(bolt[3].magnitude, bolt[4].magnitude)
            # e = Q(D(point.distance(plate_pol.exterior)), "mm")
            e = plate.e2_main
            e_other = plate.e1_main
            bp = plate.width
            w = np.max(bolt_array.p1)
            m = Q(D(point.distance(profile_pol)), "mm")
            leff1 = plate.width / bolt_array.n1
            leff2 = plate.length / bolt_array.n2
            leff = min(leff1, leff2)
            args = (t, fyd, bolt, e, e_other, m, bp, w, leff, report)
            tstub = SimpleTStub(*args)
            tstub_list.append(tstub)

        if profile.profile_type == "H":
            for bolt in in_bolts:
                point = Point(bolt[3].magnitude, bolt[4].magnitude)

                # Horizontal and vertical line from the point
                lpoint = affinity.translate(point, xoff=-1000)
                rpoint = affinity.translate(point, xoff=1000)
                dpoint = affinity.translate(point, yoff=-1000)
                upoint = affinity.translate(point, yoff=1000)
                horizontal_line = LineString([lpoint, rpoint])
                vertical_line = LineString([dpoint, upoint])

                # Points where the lines clashes with boundaries
                clash_h_pro = horizontal_line.intersection(
                    profile_pol.exterior)
                clash_v_pro = vertical_line.intersection(profile_pol.exterior)
                clash_h_plate = horizontal_line.intersection(
                    plate_pol.exterior)

                # Now, we need to find the closest point ¬¬'
                m1_adim = min(map(lambda x: point.distance(x), clash_h_pro))
                m2_adim = min(map(lambda x: point.distance(x), clash_v_pro))
                m1 = Q(D(m1_adim), "mm")
                m2 = Q(D(m2_adim), "mm")
                e_adim = min(map(lambda x: point.distance(x), clash_h_plate))
                e = Q(D(e_adim), "mm")
                tstub_list.append(CornerTStub(t, fyd, bolt, e, m1, m2, report))

        else:  # ELSE: Profile is U or L
            for bolt in in_bolts:
                point = Point(bolt[3].magnitude, bolt[4].magnitude)

    # Let's go up!
    return tstub_list
Beispiel #18
0
    def getFt_Ed_max_snug(self, forces, report):
        desc_string = "Snug-tight bolt group tension distribution"
        calc_string = "n = " + str(self.n)
        report.addLine(100, 20, desc_string, calc_string)

        if self.connected_plate is None:
            if forces.M2.magnitude != 0 and\
                    forces.M3.magnitude != 0:
                raise CalengCrash("TensionBoltArray needs a connected_plate"
                                  " if snug tight bolts.")
            else:
                return self.getFt_Ed_only_P(forces, report)

        if self.n2 == 1 and forces.M2.magnitude != 0:
            raise CalengCrash("Cant resist moments without lever arm")

        if self.connected_plate.length.magnitude == 0\
                or self.connected_plate.width.magnitude == 0:
            raise CalengCrash("Plate must have a width and length")

        # Get forces due to M2
        b = self.connected_plate.length
        h = self.connected_plate.width
        # Avoid 0 division
        p2_lev = self.p2_mean() if len(
            self.p2) > 0 else self.connected_plate.e2_main
        d = self.n1 * self.bolt.As / p2_lev
        c1 = (b - np.sqrt(d * b)) / (b - d) * h
        c = h - c1
        I2 = d * c**3 / 3 + b * c1**3 / 3
        desc_string = "Solving parameters for M2"
        report.addLine(100, 20, desc_string, "d = {}".format(str(d)))
        report.addLine(100, 20, "", "c1 = {}".format(str(c1)))
        report.addLine(100, 20, "", "c = {}".format(str(c)))
        report.addLine(100, 20, "", "I = {}".format(str(I2)))

        Ft_Ed_M2 = (forces.M2 * c * self.bolt.As / I2).to("kN")
        desc_string = "Max bolt tension due to joint M2"
        calc_string = "Ft_Ed_M2 = {}".format(str(Ft_Ed_M2))
        report.addLine(100, 20, desc_string, calc_string)

        if self.n1 == 1 and forces.M3.magnitude != 0:
            raise CalengCrash("Cant resist moments without lever arm")

        # Get forces due to M3
        b = self.connected_plate.width
        h = self.connected_plate.length
        # Avoid 0 division
        p1_lev = self.p1_mean() if len(
            self.p1) > 0 else self.connected_plate.e1_main
        d = self.n2 * self.bolt.As / p1_lev
        c1 = (b - np.sqrt(d * b)) / (b - d) * h
        c = h - c1
        I3 = d * c**3 / 3 + b * c1**3 / 3
        desc_string = "Solving parameters for M3"
        report.addLine(100, 20, desc_string, "d = {}".format(str(d)))
        report.addLine(100, 20, "", "c1 = {}".format(str(c1)))
        report.addLine(100, 20, "", "c = {}".format(str(c)))
        report.addLine(100, 20, "", "I = {}".format(str(I3)))

        Ft_Ed_M3 = (forces.M3 * c * self.bolt.As / I3).to("kN")
        desc_string = "Max bolt tension due to joint M3"
        calc_string = "Ft_Ed_M3 = {}".format(str(Ft_Ed_M3))
        report.addLine(100, 20, desc_string, calc_string)

        # Get forces due to P
        Ft_Ed_P = (forces.P / self.n).to("kN")
        desc_string = "Max bolt tension due to joint tension"
        calc_string = "Ft_Ed_P = {}".format(str(Ft_Ed_P))
        report.addLine(100, 20, desc_string, calc_string)

        # Returning solution
        Ft_Ed = Ft_Ed_P + Ft_Ed_M2 + Ft_Ed_M3
        desc_string = "Max bolt tension"
        calc_string = "Ft_Ed = " + str(Ft_Ed)
        report.addLine(100, 20, desc_string, calc_string)
        return Ft_Ed