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

Dev sync ucs map #931

Merged
merged 32 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
059e8e0
Including gyroscopic effects in the UCS analysis
fernandarossi Nov 25, 2022
bab2764
Fixing error in comparison between two elements
fernandarossi Nov 25, 2022
afb8bea
Code formatted with black
fernandarossi Nov 28, 2022
a1e75ca
Add test to run_ucs synchronous
raphaeltimbo Nov 29, 2022
4d366b1
Merge branch 'ross-rotordynamics:master' into dev-sync_ucs_map
fernandarossi Jan 10, 2023
c6eb943
Correction of the UCS map
fernandarossi Jan 10, 2023
a242072
Updated code
fernandarossi Jan 11, 2023
c11ef05
Merge branch 'ross-rotordynamics:master' into dev-sync_ucs_map
fernandarossi Jan 31, 2023
a074b7e
UCS tests modified
fernandarossi Feb 6, 2023
b4c3166
Merge branch 'petrobras:master' into dev-sync_ucs_map
fernandarossi Mar 15, 2023
70c50dd
UCS tests update
fernandarossi Mar 15, 2023
1bcb8f9
Merge branch 'dev-sync_ucs_map' of github.com:fernandarossi/ross into…
fernandarossi Mar 15, 2023
2bac55d
UCS tests update
fernandarossi Mar 15, 2023
3fcd2da
Merge branch 'petrobras:master' into dev-sync_ucs_map
fernandarossi Mar 25, 2023
5b22e74
Code structure change
fernandarossi Mar 25, 2023
8933562
Disk element update
fernandarossi Mar 27, 2023
0a11c0c
Disk element update
fernandarossi Mar 28, 2023
bbef430
Merge branch 'petrobras:master' into dev-sync_ucs_map
fernandarossi May 2, 2023
e002574
Merge branch 'dev-sync_ucs_map' of github.com:fernandarossi/ross into…
fernandarossi May 15, 2023
0fbdf39
Branch restored
fernandarossi May 15, 2023
e4f0438
Corrections
fernandarossi May 15, 2023
799ab32
Merge branch 'petrobras:main' into dev-sync_ucs_map
fernandarossi May 31, 2023
b6bc2b6
Merge branch 'main' into dev-sync_ucs_map
Jul 3, 2023
ebdf759
Merge branch 'petrobras:main' into dev-sync_ucs_map
fernandarossi Jul 4, 2023
9a5bb5f
Merge branch 'petrobras:main' into dev-sync_ucs_map
fernandarossi Jul 15, 2023
5715135
Merge branch 'petrobras:main' into dev-sync_ucs_map
fernandarossi Sep 2, 2023
a5b4812
Merge branch 'petrobras:main' into dev-sync_ucs_map
fernandarossi Dec 11, 2023
f2a7376
Merge branch 'main' into dev-sync_ucs_map
Dec 21, 2023
32cffc7
Merge branch 'main' into dev-sync_ucs_map
Mar 14, 2024
8b76b9b
Test ucs rotor 9 fixed
fernandarossi Mar 21, 2024
a25381e
Merge branch 'main' into dev-sync_ucs_map
Apr 4, 2024
e69d577
Merge branch 'main' into dev-sync_ucs_map
Apr 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/references.bib
Original file line number Diff line number Diff line change
Expand Up @@ -720,3 +720,14 @@ @article{genta1988conical
journal = {Journal of Sound and Vibration},
doi = {10.1016/0022-460X(88)90342-2}
}

@article{rouch1980dynamic,
author = {Rouch, K. E. and Kao, J. S.},
title = {Dynamic Reduction in Rotor Dynamics by the Finite Element Method},
journal = {Journal of Mechanical Design},
volume = {102},
number = {2},
pages = {360-368},
year = {1980},
doi = {10.1115/1.3254752}
}
27 changes: 15 additions & 12 deletions ross/disk_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,18 +90,21 @@ def __eq__(self, other):
True
"""
false_number = 0
for i in self.__dict__:
try:
if np.allclose(self.__dict__[i], other.__dict__[i]):
pass
else:
false_number += 1

except TypeError:
if self.__dict__[i] == other.__dict__[i]:
pass
else:
false_number += 1
if "DiskElement" in other.__class__.__name__:
for i in self.__dict__:
try:
if np.allclose(self.__dict__[i], other.__dict__[i]):
pass
else:
false_number += 1

except TypeError:
if self.__dict__[i] == other.__dict__[i]:
pass
else:
false_number += 1
else:
false_number += 1

if false_number == 0:
return True
Expand Down
151 changes: 100 additions & 51 deletions ross/rotor_assembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@ def __eq__(self, other):
return False

@check_units
def run_modal(self, speed, num_modes=12, sparse=True):
def run_modal(self, speed, num_modes=12, sparse=True, synchronous=False):
"""Run modal analysis.

Method to calculate eigenvalues and eigvectors for a given rotor system.
Expand Down Expand Up @@ -615,6 +615,9 @@ def run_modal(self, speed, num_modes=12, sparse=True):
If False, scipy.linalg.eig() is used to calculate all the eigenvalues and
eigenvectors.
Default is True.
synchronous : bool, optional
If True a synchronous analysis is carried out according to :cite:`rouch1980dynamic`.
Default is False.

Returns
-------
Expand All @@ -638,7 +641,9 @@ def run_modal(self, speed, num_modes=12, sparse=True):
>>> mode2 = 1 # Second mode
>>> fig = modal.plot_mode_2d(mode2)
"""
evalues, evectors = self._eigen(speed, num_modes=num_modes, sparse=sparse)
evalues, evectors = self._eigen(
speed, num_modes=num_modes, sparse=sparse, synchronous=synchronous
)
wn_len = num_modes // 2
wn = (np.absolute(evalues))[:wn_len]
wd = (np.imag(evalues))[:wn_len]
Expand Down Expand Up @@ -887,9 +892,15 @@ def convergence(self, n_eigval=0, err_max=1e-02):

return results

def M(self, frequency=None):
def M(self, frequency=None, synchronous=False):
"""Mass matrix for an instance of a rotor.

Parameters
----------
synchronous : bool, optional
If True a synchronous analysis is carried out.
Default is False.

Returns
-------
M0 : np.ndarray
Expand All @@ -913,10 +924,44 @@ def M(self, frequency=None):

for elm in self.elements:
dofs = list(elm.dof_global_index.values())
try:
M0[np.ix_(dofs, dofs)] += elm.M(frequency)
except TypeError:
M0[np.ix_(dofs, dofs)] += elm.M()
if synchronous:
if elm in self.shaft_elements:
try:
M = elm.M(frequency)
except TypeError:
M = elm.M()
G = elm.G()
for i in range(8):
if i == 0 or i == 3 or i == 4 or i == 7:
M[i, 0] = M[i, 0] - G[i, 1]
M[i, 3] = M[i, 3] + G[i, 2]
M[i, 4] = M[i, 4] - G[i, 5]
M[i, 7] = M[i, 7] + G[i, 6]
else:
M[i, 1] = M[i, 1] + G[i, 0]
M[i, 2] = M[i, 2] - G[i, 3]
M[i, 5] = M[i, 5] + G[i, 4]
M[i, 6] = M[i, 6] - G[i, 7]
M0[np.ix_(dofs, dofs)] += M
elif elm in self.disk_elements:
try:
M = elm.M(frequency)
except TypeError:
M = elm.M()
G = elm.G()
M[2, 2] = M[2, 2] - G[2, 3]
M[3, 3] = M[3, 3] + G[3, 2]
M0[np.ix_(dofs, dofs)] += M
else:
try:
M0[np.ix_(dofs, dofs)] += elm.M(frequency)
except TypeError:
M0[np.ix_(dofs, dofs)] += elm.M()
else:
try:
M0[np.ix_(dofs, dofs)] += elm.M(frequency)
except TypeError:
M0[np.ix_(dofs, dofs)] += elm.M()

return M0

Expand Down Expand Up @@ -1053,7 +1098,7 @@ def G(self):

return G0

def A(self, speed=0, frequency=None):
def A(self, speed=0, frequency=None, synchronous=False):
"""State space matrix for an instance of a rotor.

Parameters
Expand All @@ -1063,6 +1108,9 @@ def A(self, speed=0, frequency=None):
Default is 0.
frequency : float, optional
Excitation frequency. Default is rotor speed.
synchronous : bool, optional
If True a synchronous analysis is carried out.
Default is False.

Returns
-------
Expand All @@ -1089,7 +1137,7 @@ def A(self, speed=0, frequency=None):
# fmt: off
A = np.vstack(
[np.hstack([Z, I]),
np.hstack([la.solve(-self.M(frequency), self.K(frequency)), la.solve(-self.M(frequency), (self.C(frequency) + self.G() * speed))])])
np.hstack([la.solve(-self.M(frequency, synchronous=synchronous), self.K(frequency)), la.solve(-self.M(frequency,synchronous=synchronous), (self.C(frequency) + self.G() * speed))])])
# fmt: on

return A
Expand Down Expand Up @@ -1240,7 +1288,14 @@ def _index(eigenvalues):

@check_units
def _eigen(
self, speed, num_modes=12, frequency=None, sorted_=True, A=None, sparse=True
self,
speed,
num_modes=12,
frequency=None,
sorted_=True,
A=None,
sparse=True,
synchronous=False,
):
"""Calculate eigenvalues and eigenvectors.

Expand All @@ -1264,6 +1319,9 @@ def _eigen(
sparse : bool, optional
If sparse, eigenvalues will be calculated with arpack.
Default is True.
synchronous : bool, optional
If True a synchronous analysis is carried out.
Default is False.

Returns
-------
Expand All @@ -1280,20 +1338,34 @@ def _eigen(
91.796...
"""
if A is None:
A = self.A(speed=speed, frequency=frequency)
A = self.A(speed=speed, frequency=frequency, synchronous=synchronous)

if sparse is True:
try:
evalues, evectors = las.eigs(
A, k=num_modes, sigma=0, ncv=2 * num_modes, which="LM", v0=self._v0
)
# store v0 as a linear combination of the previously
# calculated eigenvectors to use in the next call to eigs
self._v0 = np.real(sum(evectors.T))
except las.ArpackError:
evalues, evectors = la.eig(A)
else:
if synchronous:
evalues, evectors = la.eig(A)
idx = np.where(np.imag(evalues) != 0)[0]
evalues = evalues[idx]
evectors = evectors[:, idx]
idx = np.where(np.abs(np.real(evalues) / np.imag(evalues)) < 1000)[0]
evalues = evalues[idx]
evectors = evectors[:, idx]
else:
if sparse is True:
try:
evalues, evectors = las.eigs(
A,
k=num_modes,
sigma=0,
ncv=2 * num_modes,
which="LM",
v0=self._v0,
)
# store v0 as a linear combination of the previously
# calculated eigenvectors to use in the next call to eigs
self._v0 = np.real(sum(evectors.T))
except las.ArpackError:
evalues, evectors = la.eig(A)
else:
evalues, evectors = la.eig(A)

if sorted_ is False:
return evalues, evectors
Expand Down Expand Up @@ -2176,9 +2248,8 @@ def run_ucs(
Default is 16. In this case 4 modes are plotted, since for each pair
of eigenvalues calculated we have one wn, and we show only the
forward mode in the plots.
synchronous : bool
If True a synchronous analysis is carried out and the frequency of
the first forward model will be equal to the speed.
synchronous : bool, optional
If True a synchronous analysis is carried out.
Default is False.

Returns
Expand Down Expand Up @@ -2214,32 +2285,10 @@ def run_ucs(
for i, k in enumerate(stiffness_log):
bearings = [b.__class__(b.n, kxx=k, cxx=0) for b in bearings_elements]
rotor = self.__class__(self.shaft_elements, self.disk_elements, bearings)
speed = 0
if synchronous:

def wn_diff(x):
"""Function to evaluate difference between speed and
natural frequency for the first mode."""
modal = rotor.run_modal(speed=x, num_modes=num_modes)
# get first forward mode
if modal.whirl_direction()[0] == "Forward":
wn0 = modal.wn[0]
else:
wn0 = modal.wn[1]

return wn0 - x

speed = newton(wn_diff, 0)
modal = rotor.run_modal(speed=speed, num_modes=num_modes)

# if sync, select only forward modes
if synchronous:
rotor_wn[:, i] = modal.wn[modal.whirl_direction() == "Forward"]
# if not sync, with speed=0 whirl direction can be confusing, with
# two close modes being forward or backward, so we select one mode in
# each 2 modes.
else:
rotor_wn[:, i] = modal.wn[::2]
modal = rotor.run_modal(
speed=0, num_modes=num_modes, synchronous=synchronous
)
rotor_wn[:, i] = modal.wn[::2]

bearing0 = bearings_elements[0]

Expand Down
Loading
Loading