o
    *ήcT                     @   s.   d Z ddlmZ ddlmZ G dd dZdS )zB
This module can be used to solve problems related
to 2D Trusses.
    )Symbol)sympifyc                   @   s   e Zd ZdZdd Zedd Zedd Zedd	 Zed
d Z	edd Z
edd Zedd Zedd Zedd Zdd Zdd Zdd Zdd Zdd Zd d! Zd"d# Zd$d% Zd&d' Zd(d) Zd*S )+Trussa  
    A Truss is an assembly of members such as beams,
    connected by nodes, that create a rigid structure.
    In engineering, a truss is a structure that
    consists of two-force members only.

    Trusses are extremely important in engineering applications
    and can be seen in numerous real-world applications like bridges.

    Examples
    ========

    There is a Truss consisting of four nodes and five
    members connecting the nodes. A force P acts
    downward on the node D and there also exist pinned
    and roller joints on the nodes A and B respectively.

    .. image:: truss_example.png

    >>> from sympy.physics.continuum_mechanics.truss import Truss
    >>> t = Truss()
    >>> t.add_node("node_1", 0, 0)
    >>> t.add_node("node_2", 6, 0)
    >>> t.add_node("node_3", 2, 2)
    >>> t.add_node("node_4", 2, 0)
    >>> t.add_member("member_1", "node_1", "node_4")
    >>> t.add_member("member_2", "node_2", "node_4")
    >>> t.add_member("member_3", "node_1", "node_3")
    >>> t.add_member("member_4", "node_2", "node_3")
    >>> t.add_member("member_5", "node_3", "node_4")
    >>> t.apply_load("node_4", magnitude=10, direction=270)
    >>> t.apply_support("node_1", type="fixed")
    >>> t.apply_support("node_2", type="roller")
    c                 C   sF   g | _ i | _i | _i | _g | _g | _g | _g | _i | _i | _	i | _
dS )z'
        Initializes the class
        N)_nodes_members_loads	_supports_node_labels_node_positions_node_position_x_node_position_y_nodes_occupied_reaction_loads_internal_forcesself r   N/tmp/pip-target-vg8gfxp4/lib/python/sympy/physics/continuum_mechanics/truss.py__init__/   s   
zTruss.__init__c                 C      | j S )zL
        Returns the nodes of the truss along with their positions.
        )r   r   r   r   r   nodes?      zTruss.nodesc                 C   r   )z7
        Returns the node labels of the truss.
        )r	   r   r   r   r   node_labelsF   r   zTruss.node_labelsc                 C   r   )zB
        Returns the positions of the nodes of the truss.
        )r
   r   r   r   r   node_positionsM   r   zTruss.node_positionsc                 C   r   zW
        Returns the members of the truss along with the start and end points.
        )r   r   r   r   r   membersT   r   zTruss.membersc                 C   r   r   )_member_labelsr   r   r   r   member_labels[   r   zTruss.member_labelsc                 C   r   )z
        Returns the nodes with provided supports along with the kind of support provided i.e.
        pinned or roller.
        )r   r   r   r   r   supportsb   s   zTruss.supportsc                 C   r   )z8
        Returns the loads acting on the truss.
        )r   r   r   r   r   loadsj   r   zTruss.loadsc                 C   r   )z^
        Returns the reaction forces for all supports which are all initialized to 0.
        )r   r   r   r   r   reaction_loadsq   r   zTruss.reaction_loadsc                 C   r   )z]
        Returns the internal forces for all members which are all initialized to 0.
        )r   r   r   r   r   internal_forcesx   r   zTruss.internal_forcesc                 C   s   t |}t |}|| jv rtd|| jv r+|| jv r+| j|| j|kr+td| j|||f | j| | j||f | j| | j| dS )a  
        This method adds a node to the truss along with its name/label and its location.

        Parameters
        ==========
        label:  String or a Symbol
            The label for a node. It is the only way to identify a particular node.

        x: Sympifyable
            The x-coordinate of the position of the node.

        y: Sympifyable
            The y-coordinate of the position of the node.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.nodes
        [('A', 0, 0)]
        >>> t.add_node('B', 3, 0)
        >>> t.nodes
        [('A', 0, 0), ('B', 3, 0)]
        z!Node needs to have a unique labelz+A node already exists at the given positionN)	r   r	   
ValueErrorr   r   indexr   appendr
   )r   labelxyr   r   r   add_node   s   
,zTruss.add_nodec                 C   s
  t t| jD ]}| j| |kr| j| }| j| }q|| jvr$td| j }|D ]}|| j| d ks?|| j| d krCtdq+| j	
|||f | j
| | j
||f | j
| | j
| |t| jv rt| j| |t| jv r| j| dS dS )a%  
        This method removes a node from the truss.

        Parameters
        ==========
        label:  String or Symbol
            The label of the node to be removed.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.nodes
        [('A', 0, 0)]
        >>> t.add_node('B', 3, 0)
        >>> t.nodes
        [('A', 0, 0), ('B', 3, 0)]
        >>> t.remove_node('A')
        >>> t.nodes
        [('B', 3, 0)]
        z No such node exists in the trussr      z1The node given has members already attached to itN)rangelenr   r	   r   r   r"   r   copyr   remover
   listr   popr   )r   r%   ir&   r'   members_duplicatememberr   r   r   remove_node   s,   



$zTruss.remove_nodec                 C   s   || j vs|| j vs||krtd|t| jv rtd| jt||gr+td||g| j|< d| j||f< d| j||f< d| j|< dS )a  
        This method adds a member between any two nodes in the given truss.

        Parameters
        ==========
        label: String or Symbol
            The label for a member. It is the only way to identify a particular member.

        start: String or Symbol
            The label of the starting point/node of the member.

        end: String or Symbol
            The label of the ending point/node of the member.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.add_node('B', 3, 0)
        >>> t.add_node('C', 2, 2)
        >>> t.add_member('AB', 'A', 'B')
        >>> t.members
        {'AB': ['A', 'B']}
        z;The start and end points of the member must be unique nodesz9A member with the same label already exists for the trussz-A member already exists between the two nodesTr   N)r	   r"   r.   r   r   gettupler   )r   r%   startendr   r   r   
add_member   s   zTruss.add_memberc                 C   s   |t | jvrtd| jt| j| d | j| d g | jt| j| d | j| d g | j| | j| dS )a  
        This method removes a member from the given truss.

        Parameters
        ==========
        label: String or Symbol
            The label for the member to be removed.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.add_node('B', 3, 0)
        >>> t.add_node('C', 2, 2)
        >>> t.add_member('AB', 'A', 'B')
        >>> t.add_member('AC', 'A', 'C')
        >>> t.add_member('BC', 'B', 'C')
        >>> t.members
        {'AB': ['A', 'B'], 'AC': ['A', 'C'], 'BC': ['B', 'C']}
        >>> t.remove_member('AC')
        >>> t.members
        {'AB': ['A', 'B'], 'BC': ['B', 'C']}
        z"No such member exists in the Trussr   r)   N)r.   r   r"   r   r/   r5   r   )r   r%   r   r   r   remove_member  s   ((zTruss.remove_memberc              	   C   s  || j vr	td|| j v rtd| jD ]F}|d |kr\||d |d f| j| j||d |d f< || j | j |d < |d t| jv r\| j|d  | j|< | j|d  |t| jv r| j| dkrRdt| d t| jv rdt| d	 t| jv r| jdt| d  | jdt| d < | jdt| d	  | jdt| d	 < | jdt| d  | jdt| d	  | j	| | j	|< | j	| D ](}|d d
kr|d  t
dt| d	 8  < |d dkr| j	| |  nq| j	| D ]+}|d dkr+|d  t
dt| d 8  < |d dkr)| j	| |  nq| |t
dt| d d | |t
dt| d	 d
 | j	| nm| j| dkr| j	| | j	|< | j	| D ]+}|d d
kr|d  t
dt| d	 8  < |d dkr| j	| |  nqg| |t
dt| d	 d
 | j	| n|t| j	v r| j	| | j	|< | j	| t| jD ]}| j| d |d kr|| j| d< d| j|| j| d f< d| j| j| d |f< | jt|| j| d g | jt| j| d |g q| j| d |d krZ|| j| d< d| j| j| d |f< d| j|| j| d f< | jt| j| d |g | jt|| j| d g qqdS )a  
        This method changes the label of a node.

        Parameters
        ==========
        label: String or Symbol
            The label of the node for which the label has
            to be changed.

        new_label: String or Symbol
            The new label of the node.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.add_node('B', 3, 0)
        >>> t.nodes
        [('A', 0, 0), ('B', 3, 0)]
        >>> t.change_node_label('A', 'C')
        >>> t.nodes
        [('C', 0, 0), ('B', 3, 0)]
        z!No such node exists for the Trussz*A node with the given label already existsr   r)      pinnedR__x_yZ   rollerTN)r	   r"   r   r#   r.   r   r/   strr   r   r   r-   
apply_loadr   r   r5   )r   r%   	new_labelnodeloadr2   r   r   r   change_node_label'  s   

.4((   "zTruss.change_node_labelc                 C   s   |t | jvrtdt | j }|D ]+}||kr?| j| d | j| d g| j|< | j| | j| | j|< | j| qdS )aG  
        This method changes the label of a member.

        Parameters
        ==========
        label: String or Symbol
            The label of the member for which the label has
            to be changed.

        new_label: String or Symbol
            The new label of the member.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.add_node('B', 3, 0)
        >>> t.nodes
        [('A', 0, 0), ('B', 3, 0)]
        >>> t.change_node_label('A', 'C')
        >>> t.nodes
        [('C', 0, 0), ('B', 3, 0)]
        >>> t.add_member('BC', 'B', 'C')
        >>> t.members
        {'BC': ['B', 'C']}
        >>> t.change_member_label('BC', 'BC_new')
        >>> t.members
        {'BC_new': ['B', 'C']}
        z#No such member exists for the Trussr   r)   N)r.   r   r"   r,   r/   r   )r   r%   rC   r1   r2   r   r   r   change_member_label  s    "zTruss.change_member_labelc                 C   s\   t |}t |}|| jvrtd|t| jv r$| j| ||g dS ||gg| j|< dS )a  
        This method applies an external load at a particular node

        Parameters
        ==========
        location: String or Symbol
            Label of the Node at which load is applied.

        magnitude: Sympifyable
            Magnitude of the load applied. It must always be positive and any changes in
            the direction of the load are not reflected here.

        direction: Sympifyable
            The angle, in degrees, that the load vector makes with the horizontal
            in the counter-clockwise direction. It takes the values 0 to 360,
            inclusive.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> from sympy import symbols
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.add_node('B', 3, 0)
        >>> P = symbols('P')
        >>> t.apply_load('A', P, 90)
        >>> t.apply_load('A', P/2, 45)
        >>> t.apply_load('A', P/4, 90)
        >>> t.loads
        {'A': [[P, 90], [P/2, 45], [P/4, 90]]}
        z$Load must be applied at a known nodeN)r   r   r"   r.   r   r$   r   location	magnitude	directionr   r   r   rB     s   !
zTruss.apply_loadc                 C   sr   t |}t |}|| jvrtd||g| j| vrtd| j| ||g | j| g kr7| j| dS dS )a;  
        This method removes an already
        present external load at a particular node

        Parameters
        ==========
        location: String or Symbol
            Label of the Node at which load is applied and is to be removed.

        magnitude: Sympifyable
            Magnitude of the load applied.

        direction: Sympifyable
            The angle, in degrees, that the load vector makes with the horizontal
            in the counter-clockwise direction. It takes the values 0 to 360,
            inclusive.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> from sympy import symbols
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.add_node('B', 3, 0)
        >>> P = symbols('P')
        >>> t.apply_load('A', P, 90)
        >>> t.apply_load('A', P/2, 45)
        >>> t.apply_load('A', P/4, 90)
        >>> t.loads
        {'A': [[P, 90], [P/2, 45], [P/4, 90]]}
        >>> t.remove_load('A', P/4, 90)
        >>> t.loads
        {'A': [[P, 90], [P/2, 45]]}
        z&Load must be removed from a known nodezENo load of this magnitude and direction has been applied at this nodeN)r   r   r"   r   r-   r/   rH   r   r   r   remove_load  s   $
zTruss.remove_loadc                 C   s  || j vr	td|t| jvrG|dkr3| |tdt| d d | |tdt| d d nI|dkrF| |tdt| d d n5| j| dkrb|dkra| |tdt| d d n| j| dkr||dkr|| |tdt| d d || j|< d	S )
aH  
        This method adds a pinned or roller support at a particular node

        Parameters
        ==========

        location: String or Symbol
            Label of the Node at which support is added.

        type: String
            Type of the support being provided at the node.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.add_node('B', 3, 0)
        >>> t.apply_support('A', 'pinned')
        >>> t.supports
        {'A': 'pinned'}
        z%Support must be added on a known noder;   r<   r=   r   r>   r?   r@   N)r	   r"   r.   r   rB   r   rA   rL   )r   rI   typer   r   r   apply_support  s"   
 zTruss.apply_supportc                 C   s   || j vr	td|t| jvrtd| j| dkr:| |tdt| d d | |tdt| d d n| j| d	krP| |tdt| d d | j| d
S )a4  
        This method removes support from a particular node

        Parameters
        ==========

        location: String or Symbol
            Label of the Node at which support is to be removed.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.add_node('B', 3, 0)
        >>> t.apply_support('A', 'pinned')
        >>> t.supports
        {'A': 'pinned'}
        >>> t.remove_support('A')
        >>> t.supports
        {}
        z No such node exists in the Trussz+No support has been added to the given noder;   r<   r=   r   r>   r?   r@   N)r	   r"   r.   r   rL   r   rA   r/   )r   rI   r   r   r   remove_support5  s   
 zTruss.remove_supportN)__name__
__module____qualname____doc__r   propertyr   r   r   r   r   r   r   r    r!   r(   r3   r8   r9   rF   rG   rB   rL   rN   rO   r   r   r   r   r      s>    #








+/+#Y,-2*r   N)rS   sympy.core.symbolr   sympy.core.sympifyr   r   r   r   r   r   <module>   s    