Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert CoAxialRotor class to MultiRotor #755

Open
rodrigomoliveira1 opened this issue Feb 12, 2021 · 7 comments
Open

Convert CoAxialRotor class to MultiRotor #755

rodrigomoliveira1 opened this issue Feb 12, 2021 · 7 comments
Assignees
Labels
enhancement New feature or request stale Issues with no activity for a long period

Comments

@rodrigomoliveira1
Copy link
Collaborator

The CoAxialRotor class constructs a series of shafts in a coaxial and parallel manner, limiting itself to positioning the shafts internally and externally.
Some configurations demands it not to be parallel of even coaxial, for example, compressors which have gear coupling between shafts.

CoAxialRotor class already has support for multiple shafts but isn't general enough. So, we could change its name to MultiRotor class and make some adaptations to suit these situations.
Anyway, there's still a need for allowing the user to set a speed relation between shafts, since CoAxialRotor just make the shafts to rotate at the same speed.

Another idea is to create a new element called GearLink (GearCouple, etc) which would provide gear coupling (stiffness and damping) between 2 nodes from different shafts, and would inherit from BearingElement.

@rodrigomoliveira1
Copy link
Collaborator Author

Some ideas:

  • MultiRotor class would take multiple Rotor objects and create a new object by adding some linkage between them.
  • MultiRotor class would inherit from Rotor class to make the same original methods available.
  • Plotting multiple rotors in a 2D configuration would be challenging. Instead, we could plot each rotor model individually and add it to a subplot.

@raphaeltimbo
Copy link
Collaborator

Some ideas:

  • MultiRotor class would take multiple Rotor objects and create a new object by adding some linkage between them.
  • MultiRotor class would inherit from Rotor class to make the same original methods available.
  • Plotting multiple rotors in a 2D configuration would be challenging. Instead, we could plot each rotor model individually and add it to a subplot.

Agreed. I think we can go in this direction.

Regarding the rotor speed, if we take multiple rotor objects, for the analysis we could have an API like:

import ross as rs

rotor1 = rs.Rotor(...)
rotor2 = rs.Rotor(...)

multirotor = rs.MultiRotor(rotor1, rotor2, links)

speed1 = 100
speed2 = 100
modal = multirotor.run_modal(speed=(speed1, speed2))

Here we would have to take in consideration the order in which we have instantiated the multirotor object and we would have to pass each rotor speed in the same order. In this case we would have more freedom defining each rotor speed, and if the user wants to have a speed relation, they can do speed2 = 2*speed1 for example.
Here, internally, to assemble the matrices, first we would have separate calls to each rotor M, C, K and G methods with their respective speed and then we would have the global matrices assembled considering their links.

@rodrigomoliveira1
Copy link
Collaborator Author

Taking 2 (or more) rotors and merging them requires renumbering the elements to make sure there'll be a continuous values for the elements, and set the degrees of freedom correctly.

However, once rotors are built, there's no way we can change the n values for each element, except for shaft elements. So, I need to add the same feature ShaftElement has to the other elements.

To make things shorter and more general, I'm adding two methods to Element class, so all the others inherit from it:

class Element(ABC):
    def __init__(self, n, tag=None):
        self._n = n
        self.tag = tag

    @property
    def n(self):
        return self._n

    @n.setter
    def n(self, value):
        self._n = value
        self.n_l = value
        if value is not None:
            self.n_r = value + 1

These methods will allows to manipulate the nodal location of each element and won't change the user experience at all. Although it seems a pretty simple way to get over this situation, these changes may require some change on rotors DataFrames, because we had a column df["n"], and with those changes, it will disappear, leaving only the df["_n"]

@raphaeltimbo
Copy link
Collaborator

raphaeltimbo commented Feb 17, 2021

Taking 2 (or more) rotors and merging them requires renumbering the elements to make sure there'll be a continuous values for the elements, and set the degrees of freedom correctly.

@rodrigomoliveira1, initially I wanted to avoid having to change the Element class just to have an extra method for this specific functionality. But if you think this modification improves the library as a whole, I think we could proceed with that modification.

I am only worried that we could break or make things more complex just to make this multirotor functionality work. In some cases I would suggest that we try to implement things by keeping the original rotors as they are and, if needed, we could make copies of these rotors and add attributes/methods to them after we create them.

@rodrigomoliveira1
Copy link
Collaborator Author

rodrigomoliveira1 commented Feb 18, 2021

I have suggested that because MultiRotor must have, at least, the same attributes than Rotor object to work properly. Having the same attributes, we avoid the need for changes in the main functions.

Even making copies of the input rotors, we'd still need to build those DataFrames with modified informations to the global assembly, so, when other functions refer to them, they should work without further issues.

The other option I see is copying the rotors' data and re-instantiate the elements to build a modified global assembly, but it probably would take a bit longer than just changing the n value.

The original rotors would not be changed at all in both cases.

@ross-bott
Copy link
Collaborator

Hi there!
I have marked this issue as stale because it has not had activity for 45 days.
Consider the following options:

  • If the issue refers to a large task, break it in smaller issues that can be solved in
    less than 45 days;
  • Label the issue as wontfix or wontfix for now and close it.

@ross-bott ross-bott added the stale Issues with no activity for a long period label Apr 6, 2021
@plevisse-naarea
Copy link

plevisse-naarea commented Sep 26, 2024

Hi,
I've been working on this for a bit :
I've defined a MultiRotor class which takes in a list of rotors and a list of links (defined in another specific class)
`
class MultiRotor(Rotor):

def __init__(
    self,
    rotors,
    links):
    ####################################################
    # Config attributes
    ####################################################

    ##################
    # Define links
    ##################
    self.links  =   links
    self.rotors =   rotors
    ####################################################
    #Check number of dofs for each 
    self.number_dof = np.all(np.isclose(rotors[0]._check_number_dof(),[rot._check_number_dof() for rot in rotors])) * 
          rotors[0]._check_number_dof()
    self.ndof       = np.sum([rot.ndof for rot in rotors])
    self._v0 = None  # used to call eigs`

The Links class contains the stiffnesses, gear ratio, shaft and node position for the connection :
class Link: def __init__( self, GearRatio, kxx, k_theta, node_1, shaft_1, node_2, shaft_2): self.GearRatio=GearRatio self.node_1 =node_1 self.node_2=node_2 self.shaft_1 = shaft_1 self.shaft_2 = shaft_2 self.kxx=kxx self.k_theta=k_theta

I can then assemble the mass and stiffness matrices by iterating on the shafts and creating a macro matrix :
`
def M(self, frequency=None):
"""Mass matrix for a multirotor.

    Returns
    -------
    M0 : np.ndarray
        Assembled Mass matrix for the multirotor.

    Examples
    --------
    """
    M0 = np.zeros((self.ndof, self.ndof))

    # if frequency is None, we assume the rotor does not have any elements
    # with frequency dependent mass matrices
    if frequency is None:
        frequency = 0

    idx=0
    for i,rot in enumerate(self.rotors):
        dofs = np.arange(idx,rot.ndof+idx)
        try:
            if i==0:
                M0[np.ix_(dofs, dofs)] += rot.M(frequency)
            else:
                M0[np.ix_(dofs, dofs)] += rot.M(frequency*self.links[i-1].GearRatio) #GearRatio is calculated with reference to the first shaft
        except TypeError:
            M0[np.ix_(dofs, dofs)] += rot.M()
        idx = rot.ndof+idx
    return M0`

(Note : this is still not 100% clean as the speed transfer function between the first shaft and the nth shaft is not very well defined, I need to work some more on this

The tricky part comes at the assembly of the A matrix and the connections between the nodes to ensure the conversion of speeds and torque : what I do is modify the K and C matrices to include the connection terms with stiffness and damping.
The speed conversion is done in this fashion :
K[idx + list_dof_1[5],idx + self.rotors[i].ndof + list_dof_2[5]] += -link.k_theta K[idx + self.rotors[i].ndof + list_dof_2[5],idx + list_dof_1[5]] += -link.k_theta K[idx + list_dof_1[5],idx + list_dof_1[5]] += link.k_theta / link.GearRatio K[idx + self.rotors[i].ndof + list_dof_2[5],idx + self.rotors[i].ndof + list_dof_2[5]] += link.k_theta * link.GearRatio

I can then assemble the A matrix

This gives proper results in torsion analysis.

Still need a bit of work to clean up the gear ratio vs number of shafts and node position and to get the post-processing tools up and ready to have the MultiRotor fit into the existing Results classes ; but it gives proper results for torsional analysis which was my # 1 objective

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request stale Issues with no activity for a long period
Projects
None yet
Development

No branches or pull requests

4 participants