Ejemplo n.º 1
0
    def __add__(self, other: Element) -> Element:
        if self.id != other.id:
            raise FEMException("Wrong element:",
                               "only elements with the same id can be added.")
        el = copy.deepcopy(self)
        for unit in [
                "bending_moment",
                "shear_force",
                "deflection",
                "extension",
                "N_1",
                "N_2",
        ]:
            if getattr(el, unit) is None:
                setattr(el, unit, getattr(other, unit))
            else:
                setattr(el, unit, getattr(el, unit) + getattr(other, unit))
        el.max_deflection = (other.max_deflection if el.max_deflection is None
                             else max(el.max_deflection, other.max_deflection))

        el.node_map[self.node_id1] = el.node_1 + other.node_1
        el.node_map[self.node_id2] = el.node_2 + other.node_2
        el.node_map[self.node_id1].ux = el.node_1.ux + other.node_1.ux
        el.node_map[self.node_id1].uz = el.node_1.uz + other.node_1.uz
        el.node_map[self.node_id1].phi_y = el.node_1.phi_y + other.node_1.phi_y
        el.node_map[self.node_id2].ux = el.node_2.ux + other.node_2.ux
        el.node_map[self.node_id2].uz = el.node_2.uz + other.node_2.uz
        el.node_map[self.node_id2].phi_y = el.node_2.phi_y + other.node_2.phi_y
        return el
Ejemplo n.º 2
0
    def __add__(self, other):
        if self.id != other.id:
            raise FEMException('Wrong element:',
                               'only elements with the same id can be added.')
        el = copy.deepcopy(self)
        for unit in [
                'bending_moment', 'shear_force', 'deflection', 'extension',
                'N_1', 'N_2'
        ]:
            if getattr(el, unit) is None:
                setattr(el, unit, getattr(other, unit))
            else:
                setattr(el, unit, getattr(el, unit) + getattr(other, unit))
        el.max_deflection = other.max_deflection if el.max_deflection is None else \
            max(el.max_deflection, other.max_deflection)

        el.node_map[self.node_id1] = el.node_1 + other.node_1
        el.node_map[self.node_id2] = el.node_2 + other.node_2
        el.node_map[self.node_id1].ux = el.node_1.ux + other.node_1.ux
        el.node_map[self.node_id1].uz = el.node_1.uz + other.node_1.uz
        el.node_map[self.node_id1].phi_y = el.node_1.phi_y + other.node_1.phi_y
        el.node_map[self.node_id2].ux = el.node_2.ux + other.node_2.ux
        el.node_map[self.node_id2].uz = el.node_2.uz + other.node_2.uz
        el.node_map[self.node_id2].phi_y = el.node_2.phi_y + other.node_2.phi_y
        return el
Ejemplo n.º 3
0
    def all_q_load(self):
        if self.q_load is None:
            q = 0
        else:
            if self.q_direction == "x":
                q_factor = -sin(self.angle)
            elif self.q_direction == "y":
                q_factor = cos(self.angle)
            elif self.q_direction == "element" or self.q_direction is None:
                q_factor = 1
            elif self.q_direction is not None:
                raise FEMException('Wrong parameters',
                                   "q-loads direction is not set property. Please choose 'x', 'y', or 'element'")
            q = self.q_load * q_factor

        return q + self.dead_load * cos(self.angle)
Ejemplo n.º 4
0
    def all_q_load(self) -> float:
        if self.q_load is None:
            q = (0, 0)
        else:
            if self.q_direction == "x":
                q_factor = -sin(self.angle)
            elif self.q_direction == "y":
                q_factor = cos(self.angle)
            elif self.q_direction == "element" or self.q_direction is None:
                q_factor = 1
            elif self.q_direction is not None:
                raise FEMException(
                    "Wrong parameters",
                    "q-loads direction is not set property. Please choose 'x', 'y', or 'element'",
                )
            q = [i * q_factor for i in self.q_load]

        return [i + self.dead_load * cos(self.angle) for i in q]
Ejemplo n.º 5
0
 def all_q_load(self) -> Union[float, Sequence[float]]:
     q_factor = 0
     if self.q_load is None:
         q = self.dead_load * cos(self.angle)
     else:
         if self.q_direction == "x":
             q_factor = -sin(self.angle)
         elif self.q_direction == "y":
             q_factor = cos(self.angle)
         elif self.q_direction == "element" or self.q_direction is None:
             q_factor = 1
         elif self.q_direction is not None:
             raise FEMException(
                 "Wrong parameters",
                 "q-loads direction is not set property. Please choose 'x', 'y', or 'element'",
             )
         if isinstance(self.q_load, (float, int)):
             q = self.q_load * q_factor + self.dead_load * cos(self.angle)
         elif isinstance(self.q_load, list):
             q = [
                 q_l * q_factor + self.dead_load * cos(self.angle)
                 for q_l in self.q_load
             ]
     return q
Ejemplo n.º 6
0
    def solve(
        self,
        force_linear=False,
        verbosity=0,
        max_iter=200,
        geometrical_non_linear=False,
        **kwargs
    ):

        """
        Compute the results of current model.

        :param force_linear: (bool) Force a linear calculation. Even when the system has non linear nodes.
        :param verbosity: (int) 0. Log calculation outputs. 1. silence.
        :param max_iter: (int) Maximum allowed iterations.
        :param geometrical_non_linear: (bool) Calculate second order effects and determine the buckling factor.
        :return: (array) Displacements vector.


        Development **kwargs:
            :param naked: (bool) Whether or not to run the solve function without doing post processing.
            :param discretize_kwargs: When doing a geometric non linear analysis you can reduce or increase the number
                                      of elements created that are used for determining the buckling_factor
        """

        # kwargs: arguments for the iterative solver callers such as the _stiffness_adaptation method.
        #                naked (bool) Default = False, if True force lines won't be computed.

        if self.system_displacement_vector is None:
            system_components.assembly.process_supports(self)

        naked = kwargs.get("naked", False)

        if not naked:
            if not self.validate():
                if all(
                    ["general" in element.type for element in self.element_map.values()]
                ):
                    raise FEMException(
                        "StabilityError",
                        "The eigenvalues of the stiffness matrix are non zero, "
                        "which indicates a instable structure. "
                        "Check your support conditions",
                    )

        # (Re)set force vectors
        for el in self.element_map.values():
            el.reset()
        system_components.assembly.prep_matrix_forces(self)
        assert (
            self.system_force_vector is not None
        ), "There are no forces on the structure"

        if self.non_linear and not force_linear:
            return system_components.solver.stiffness_adaptation(
                self, verbosity, max_iter
            )

        system_components.assembly.assemble_system_matrix(self)
        if geometrical_non_linear:
            discretize_kwargs = kwargs.get("discretize_kwargs", None)
            self.buckling_factor = system_components.solver.geometrically_non_linear(
                self, verbosity, discretize_kwargs=discretize_kwargs
            )
            return self.system_displacement_vector

        system_components.assembly.process_conditions(self)

        # solution of the reduced system (reduced due to support conditions)
        reduced_displacement_vector = np.linalg.solve(
            self.reduced_system_matrix, self.reduced_force_vector
        )

        # add the solution of the reduced system in the complete system displacement vector
        self.system_displacement_vector = np.zeros(self.shape_system_matrix)
        np.put(
            self.system_displacement_vector,
            self._remainder_indexes,
            reduced_displacement_vector,
        )

        # determine the displacement vector of the elements
        for el in self.element_map.values():
            index_node_1 = (el.node_1.id - 1) * 3
            index_node_2 = (el.node_2.id - 1) * 3

            # node 1 ux, uz, phi
            el.element_displacement_vector[:3] = self.system_displacement_vector[
                index_node_1 : index_node_1 + 3
            ]
            # node 2 ux, uz, phi
            el.element_displacement_vector[3:] = self.system_displacement_vector[
                index_node_2 : index_node_2 + 3
            ]
            el.determine_force_vector()

        if not naked:
            # determining the node results in post processing class
            self.post_processor.node_results_elements()
            self.post_processor.node_results_system()
            self.post_processor.reaction_forces()
            self.post_processor.element_results()

            # check the values in the displacement vector for extreme values, indicating a flawed calculation
            assert np.any(self.system_displacement_vector < 1e6), (
                "The displacements of the structure exceed 1e6. "
                "Check your support conditions,"
                "or your elements Young's modulus"
            )

        return self.system_displacement_vector
Ejemplo n.º 7
0
    def add_multiple_elements(
        self,
        location,
        n=None,
        dl=None,
        EA=None,
        EI=None,
        g=0,
        mp=None,
        spring=None,
        **kwargs
    ):
        """
        Add multiple elements defined by the first and the last point.

        :param location: See 'add_element' method
        :param n: (int) Number of elements.
        :param dl: (flt) Distance between the elements nodes.
        :param EA: See 'add_element' method
        :param EI: See 'add_element' method
        :param g: See 'add_element' method
        :param mp: See 'add_element' method
        :param spring: See 'add_element' method

        **Keyword Args:**

        :param element_type: (str) See 'add_element' method
        :param first: (dict) Different arguments for the first element
        :param last: (dict) Different arguments for the last element
        :param steelsection: (str) Steel section name like IPE 300
        :param orient: (str) Steel section axis for moment of inertia - 'y' and 'z' possible
        :param b: (flt) Width of generic rectangle section
        :param h: (flt) Height of generic rectangle section
        :param d: (flt) Diameter of generic circle section
        :param sw: (boolean) If true self weight of section is considered as dead load
        :param E: (flt) Modulus of elasticity for section material
        :param gamma: (flt) Weight of section material per volume unit. [kN/m3] / [N/m3]s

            :Example:

            .. code-block:: python

                last={'EA': 1e3, 'mp': 290}

        :return: (list) Element IDs
        """

        first = kwargs.get("first", {})
        last = kwargs.get("last", {})
        element_type = kwargs.get("element_type", "general")

        for el in (first, last):
            if "EA" not in el:
                el["EA"] = EA
            if "EI" not in el:
                el["EI"] = EI
            if "g" not in el:
                el["g"] = g
            if "mp" not in el:
                el["mp"] = mp
            if "spring" not in el:
                el["spring"] = spring
            if "element_type" not in el:
                el["element_type"] = element_type

        point_1, point_2 = system_components.util.det_vertices(self, location)
        length = (point_2 - point_1).modulus()
        direction = (point_2 - point_1).unit()

        if type(n) == type(dl):
            raise FEMException(
                "Wrong parameters",
                "One, and only one, of n and dl should be passed as argument.",
            )
        elif n:
            dl = length / n

        point = point_1 + direction * dl
        elements = [
            self.add_element(
                (point_1, point),
                first["EA"],
                first["EI"],
                first["g"],
                first["mp"],
                first["spring"],
                element_type=first["element_type"],
                **kwargs
            )
        ]

        l = 2 * dl
        while l < length:
            point += direction * dl
            elements.append(
                self.add_element(
                    point, EA, EI, g, mp, spring, element_type=element_type, **kwargs
                )
            )
            l += dl

        elements.append(
            self.add_element(
                point_2,
                last["EA"],
                last["EI"],
                last["g"],
                last["mp"],
                last["spring"],
                element_type=last["element_type"],
                **kwargs
            )
        )
        return elements
Ejemplo n.º 8
0
def support_check(system, node_id):
    if system.node_map[node_id].hinge:
        raise FEMException(
            "Flawed inputs",
            "You cannot add a rotation-restraining support to a hinged node.",
        )
Ejemplo n.º 9
0
 def _support_check(self, node_id):
     if self.node_map[node_id].hinge:
         raise FEMException("Flawed inputs",
                            "You cannot add a support to a hinged node.")
Ejemplo n.º 10
0
    def add_multiple_elements(self,
                              location,
                              n=None,
                              dl=None,
                              EA=None,
                              EI=None,
                              g=0,
                              mp=None,
                              spring=None,
                              **kwargs):
        """
        Add multiple elements defined by the first and the last point.

        :param location: See 'add_element' method
        :param n: (int) Number of elements.
        :param dl: (flt) Distance between the elements nodes.
        :param EA: See 'add_element' method
        :param EI: See 'add_element' method
        :param g: See 'add_element' method
        :param mp: See 'add_element' method
        :param spring: See 'add_element' method

        **Keyword Args:**

        :param element_type: (str) See 'add_element' method
        :param first: (dict) Different arguments for the first element
        :param last: (dict) Different arguments for the last element

            :Example:

            .. code-block:: python

                last={'EA': 1e3, 'mp': 290}

        :return: (list) Element IDs
        """

        first = kwargs.get("first", {})
        last = kwargs.get("last", {})
        element_type = kwargs.get("element_type", "general")

        for el in (first, last):
            if "EA" not in el:
                el["EA"] = EA
            if "EI" not in el:
                el["EI"] = EI
            if "g" not in el:
                el["g"] = g
            if "mp" not in el:
                el["mp"] = mp
            if "spring" not in el:
                el["spring"] = spring
            if "element_type" not in el:
                el["element_type"] = element_type

        point_1, point_2 = self._det_vertices(location)
        length = (point_2 - point_1).modulus()
        direction = (point_2 - point_1).unit()

        if type(n) == type(dl):
            raise FEMException(
                "Wrong parameters",
                "One, and only one, of n and dl should be passed as argument.")
        elif n:
            dl = length / n

        point = point_1 + direction * dl
        elements = [
            self.add_element((point_1, point),
                             first["EA"],
                             first["EI"],
                             first["g"],
                             first["mp"],
                             first["spring"],
                             element_type=first["element_type"])
        ]

        l = 2 * dl
        while l < length:
            point += direction * dl
            elements.append(
                self.add_element(point,
                                 EA,
                                 EI,
                                 g,
                                 mp,
                                 spring,
                                 element_type=element_type))
            l += dl

        elements.append(
            self.add_element(point_2,
                             last["EA"],
                             last["EI"],
                             last["g"],
                             last["mp"],
                             last["spring"],
                             element_type=last["element_type"]))
        return elements