Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
pypk
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Aerospace and Mechanical Engineering
pypk
Commits
a049fe34
Commit
a049fe34
authored
10 months ago
by
Adrien Crovato
Browse files
Options
Downloads
Patches
Plain Diff
Add mode tracking. Add max iteration number for pk method. Bugfix.
parent
1de1eeaf
Branches
adri
Branches containing commit
No related tags found
Tags containing commit
1 merge request
!1
Vesion 1.1
Pipeline
#23932
failed
10 months ago
Changes
4
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
pypk/api_core.py
+1
-1
1 addition, 1 deletion
pypk/api_core.py
pypk/eigensolver.py
+27
-5
27 additions, 5 deletions
pypk/eigensolver.py
pypk/nipk.py
+12
-6
12 additions, 6 deletions
pypk/nipk.py
pypk/pk.py
+16
-18
16 additions, 18 deletions
pypk/pk.py
with
56 additions
and
30 deletions
pypk/api_core.py
+
1
−
1
View file @
a049fe34
...
...
@@ -41,7 +41,7 @@ def init_pypk(cfg):
agg
=
KSAggregator
(
cfg
[
'
rho_ks
'
])
# p-k method
if
cfg
[
'
method
'
]
==
'
pk
'
:
sol
=
Pk
(
name
,
flu
,
eig
,
agg
,
cfg
[
'
mach
'
],
cfg
[
'
k_ref
'
],
cfg
[
'
l_ref
'
],
cfg
[
'
vrb
'
],
cfg
[
'
n_modes
'
],
n_speed
,
tol
=
1e-3
)
sol
=
Pk
(
name
,
flu
,
eig
,
agg
,
cfg
[
'
mach
'
],
cfg
[
'
k_ref
'
],
cfg
[
'
l_ref
'
],
cfg
[
'
vrb
'
],
cfg
[
'
n_modes
'
],
n_speed
,
tol
=
1e-3
,
max_it
=
10
)
elif
cfg
[
'
method
'
]
==
'
nipk
'
:
sol
=
Nipk
(
name
,
flu
,
eig
,
agg
,
cfg
[
'
mach
'
],
cfg
[
'
k_ref
'
],
cfg
[
'
l_ref
'
],
cfg
[
'
vrb
'
],
cfg
[
'
n_modes
'
],
n_speed
)
else
:
...
...
This diff is collapsed.
Click to expand it.
pypk/eigensolver.py
+
27
−
5
View file @
a049fe34
...
...
@@ -25,22 +25,31 @@ class EigenSolver:
self
.
_n
=
n
# number of modes
self
.
_g
=
(
1
+
1j
*
g
)
# structural damping (complex proportional stiffness)
def
compute
(
self
,
rho
,
u
,
m
,
k
,
q
):
def
compute_natural
(
self
,
m
,
k
):
"""
Compute natural frequencies and mode shapes
m : mass matrix
k : stiffness matrix
"""
l
,
v
=
spla
.
eig
(
k
,
m
)
# det(-omega^2 * M + K) = 0
return
np
.
sqrt
(
np
.
real
(
l
)),
v
def
compute
(
self
,
rho
,
u
,
m
,
k
,
q
,
v0
=
None
):
"""
Compute eigenvalues and eigenvectors
rho : fuid density
u : freestream velocity
m : mass matrix
k : stiffness matrix
q : aerodynamic matrix
v0 : converged mode shapes from previous iteration (airspeed)
"""
p
,
v
=
spla
.
eig
(
self
.
_g
*
k
-
0.5
*
rho
*
u
**
2
*
q
,
-
u
**
2
/
self
.
_l
**
2
*
m
)
# det((p*u/l)^2*M + K - q_inf*Q) = 0
p
=
np
.
sqrt
(
p
)
# Sort
p
=
np
.
where
(
np
.
imag
(
p
)
<
0
,
-
p
,
p
)
# change sign of p if imag(p) < 0
srt
=
np
.
imag
(
p
).
argsort
()
# Normalize (optional since scipy does it
)
for
j
in
range
(
self
.
_n
)
:
v
[:,
j
]
/=
spla
.
n
or
m
(
v
[:,
j
]
)
if
v0
is
None
:
srt
=
np
.
imag
(
p
).
argsort
(
)
else
:
srt
=
self
.
_s
or
t
(
v
,
v0
)
return
p
[
srt
].
T
,
v
[:,
srt
]
def
compute_gradients
(
self
,
rho
,
u
,
m
,
k
,
q
,
p
,
v
,
dm
,
dk
,
dq
):
...
...
@@ -66,3 +75,16 @@ class EigenSolver:
b
[
-
1
,
0
]
=
0
x
=
spla
.
lu_solve
((
spla
.
lu_factor
(
a
)),
b
)
return
x
[
0
,
0
]
def
_sort
(
self
,
v
,
v0
):
"""
Sort current modes according to their correlation to previous modes
v : mode shapes from current iteration
v0 : converged mode shapes from previous iteration
"""
# Compute correlation matrix
mac
=
np
.
zeros
((
self
.
_n
,
self
.
_n
))
for
i
in
range
(
self
.
_n
):
for
j
in
range
(
self
.
_n
):
mac
[
i
,
j
]
=
np
.
linalg
.
norm
(
np
.
dot
(
v
[:,
i
],
np
.
conjugate
(
v0
[:,
j
])))
/
(
np
.
linalg
.
norm
(
v
[:,
i
])
*
np
.
linalg
.
norm
(
v0
[:,
j
]))
# Find maximum for each mode
return
np
.
argmax
(
mac
,
axis
=
0
)
This diff is collapsed.
Click to expand it.
pypk/nipk.py
+
12
−
6
View file @
a049fe34
...
...
@@ -33,21 +33,21 @@ class Nipk(Solution):
def
compute
(
self
):
"""
Compute frequencies and dampings
"""
omega_0
,
v_0
=
self
.
_eig
.
compute_natural
(
self
.
_m
,
self
.
_k
)
# natural frequencies and modes
self
.
rho
,
self
.
speed
=
self
.
_flu
.
compute
(
self
.
_mach
)
for
ivel
in
range
(
self
.
n_speed
):
# Compute eigenvalues at zero airspeed
if
self
.
speed
[
ivel
]
==
0
:
for
imod
in
range
(
self
.
n_modes
):
self
.
freq
[
ivel
,
imod
]
=
0.
self
.
freq
[
ivel
,
:]
=
omega_0
continue
# Compute eigenvalues for each reference reduced frequency
p_k
=
np
.
zeros
((
self
.
n_freqs
,
self
.
n_modes
),
dtype
=
complex
)
v_k
=
np
.
zeros
((
self
.
n_freqs
,
self
.
n_modes
,
self
.
n_modes
),
dtype
=
complex
)
for
ifrq
in
range
(
self
.
n_freqs
):
p_k
[
ifrq
,:],
v_k
[
ifrq
,:,:]
=
self
.
_eig
.
compute
(
self
.
rho
[
ivel
],
self
.
speed
[
ivel
],
self
.
_m
,
self
.
_k
,
self
.
_q
[
ifrq
,:,:])
p_k
[
ifrq
,:],
v_k
[
ifrq
,:,:]
=
self
.
_eig
.
compute
(
self
.
rho
[
ivel
],
self
.
speed
[
ivel
],
self
.
_m
,
self
.
_k
,
self
.
_q
[
ifrq
,:,:]
,
v_0
)
# Match reduced frequency by linear interpolation for each mode
for
imod
in
range
(
self
.
n_modes
):
delta
,
idx
=
self
.
__find_index
(
self
.
speed
[
ivel
],
p_k
[:,
imod
],
self
.
_kref
)
delta
,
idx
=
self
.
__find_index
(
self
.
speed
[
ivel
],
imod
,
p_k
[:,
imod
],
self
.
_kref
)
p_re
,
p_im
=
self
.
__interp
(
self
.
_kref
[
idx
],
delta
[
idx
],
p_k
[
idx
,
imod
])
# Compute frequency and damping
self
.
freq
[
ivel
,
imod
]
=
p_im
*
self
.
speed
[
ivel
]
/
self
.
_lref
/
(
2
*
np
.
pi
)
...
...
@@ -59,6 +59,11 @@ class Nipk(Solution):
self
.
_pk
[
ivel
,
imod
,
:]
=
p_k
[
idx
,
imod
]
self
.
_vk
[
ivel
,
imod
,
:,
:]
=
v_k
[
idx
,
:,
imod
]
self
.
_p
[
ivel
,
imod
]
=
p_re
+
1j
*
p_im
# Interpolate mode shapes for mode tracking
v_0
=
np
.
zeros
((
self
.
n_modes
,
self
.
n_modes
),
dtype
=
complex
)
for
imod
in
range
(
self
.
n_modes
):
a
=
(
self
.
_p
[
ivel
,
imod
].
imag
-
self
.
_kk
[
ivel
,
imod
,
0
])
/
(
self
.
_kk
[
ivel
,
imod
,
1
]
-
self
.
_kk
[
ivel
,
imod
,
0
])
v_0
[:,
imod
]
=
(
1
-
a
)
*
self
.
_vk
[
ivel
,
imod
,
0
,
:]
+
a
*
self
.
_vk
[
ivel
,
imod
,
1
,
:]
# Compute aggregated damping over modes then over dynamic pressures
self
.
_ksm
=
np
.
zeros
(
self
.
n_speed
)
for
i
in
range
(
self
.
n_speed
):
...
...
@@ -87,9 +92,10 @@ class Nipk(Solution):
dq
[
np
.
unravel_index
(
i
,
dq
.
shape
)]
=
1.
self
.
damp_qim
[
i
]
=
self
.
__compute_dg
(
z
,
z
,
zk
+
1j
*
dq
)
def
__find_index
(
self
,
u
,
p
,
k
):
def
__find_index
(
self
,
u
,
m
,
p
,
k
):
"""
Find the indices between which the frequency must be interpolated
u : freestream velocity
m : mode number
p : eigenvalue solutions
k : reference reduced frequencies
"""
...
...
@@ -109,7 +115,7 @@ class Nipk(Solution):
elif
ai
==
len
(
delta
)
-
1
:
idx
=
[
ai
-
1
,
ai
]
else
:
raise
RuntimeError
(
f
'
NIPK: could not match frequency for mode
{
i
}
at velocity
{
u
}
!
\n
'
)
raise
RuntimeError
(
f
'
NIPK: could not match frequency for mode
{
m
}
at velocity
{
u
}
!
\n
'
)
return
delta
,
idx
def
__interp
(
self
,
k
,
delta
,
p
):
...
...
This diff is collapsed.
Click to expand it.
pypk/pk.py
+
16
−
18
View file @
a049fe34
...
...
@@ -17,41 +17,48 @@
from
.solution
import
Solution
import
numpy
as
np
from
scipy
import
interpolate
import
scipy.linalg
as
spla
class
Pk
(
Solution
):
"""
Standard p-k method for flutter solution
"""
def
__init__
(
self
,
name
,
flu
,
eig
,
agg
,
mach
,
k_ref
,
l_ref
,
vrb
,
n_modes
,
n_speed
,
tol
=
1e-3
):
def
__init__
(
self
,
name
,
flu
,
eig
,
agg
,
mach
,
k_ref
,
l_ref
,
vrb
,
n_modes
,
n_speed
,
tol
=
1e-3
,
max_it
=
10
):
super
().
__init__
(
name
,
flu
,
eig
,
agg
,
mach
,
k_ref
,
l_ref
,
vrb
,
n_modes
,
n_speed
)
self
.
name
=
'
PK
'
# solver name
self
.
_tol
=
tol
# tolerance
self
.
_max_it
=
max_it
# maximum number of iterations
def
compute
(
self
):
"""
Compute frequencies and dampings
"""
omega
=
self
.
_
_sfreq
(
self
.
_m
,
self
.
_k
)
# natural frequencies
omega
_0
,
v_0
=
self
.
_
eig
.
compute_natural
(
self
.
_m
,
self
.
_k
)
# natural frequencies
and modes
self
.
rho
,
self
.
speed
=
self
.
_flu
.
compute
(
self
.
_mach
)
for
ivel
in
range
(
self
.
n_speed
):
# Compute eigenvalues at zero airspeed
if
self
.
speed
[
ivel
]
==
0
:
for
imod
in
range
(
self
.
n_modes
):
self
.
freq
[
ivel
,
imod
]
=
0.
self
.
freq
[
ivel
,
:]
=
omega_0
continue
v_tmp
=
np
.
zeros
((
self
.
n_modes
,
self
.
n_modes
),
dtype
=
complex
)
# temporary container for modes
for
imod
in
range
(
self
.
n_modes
):
k
=
omega
[
imod
]
*
self
.
_lref
/
self
.
speed
[
ivel
]
# guess reduced frequency
k
=
omega_0
[
imod
]
*
self
.
_lref
/
self
.
speed
[
ivel
]
# guess reduced frequency
it
=
0
while
True
:
# Interpolate loads and solve eigenvalue problem
# Interpolate loads and solve eigenvalue problem
q
=
self
.
__interp
(
k
,
self
.
_kref
,
self
.
_q
)
p
,
_
=
self
.
_eig
.
compute
(
self
.
rho
[
ivel
],
self
.
speed
[
ivel
],
self
.
_m
,
self
.
_k
,
q
)
p
,
v
=
self
.
_eig
.
compute
(
self
.
rho
[
ivel
],
self
.
speed
[
ivel
],
self
.
_m
,
self
.
_k
,
q
,
v_0
)
p
=
p
[
imod
]
# Check if reduced frequency is converged
if
abs
(
np
.
imag
(
p
)
-
k
)
<
self
.
_tol
:
if
abs
(
np
.
imag
(
p
)
-
k
)
<
self
.
_tol
or
it
==
self
.
_max_it
:
v_tmp
[:,
imod
]
=
v
[:,
imod
]
self
.
freq
[
ivel
,
imod
]
=
np
.
imag
(
p
)
*
self
.
speed
[
ivel
]
/
self
.
_lref
/
(
2
*
np
.
pi
)
self
.
damp
[
ivel
,
imod
]
=
np
.
real
(
p
)
/
np
.
imag
(
p
)
if
it
==
self
.
_max_it
:
print
(
f
'
PK: could not converge for mode
{
imod
}
at velocity
{
self
.
speed
[
ivel
]
}
, using k=
{
np
.
imag
(
p
)
}
with tolerance
{
abs
(
np
.
imag
(
p
)
-
k
)
}
.
'
)
break
else
:
k
=
np
.
imag
(
p
)
it
+=
1
# Update modes for mode tracking
v_0
=
v_tmp
# Compute aggregated damping over modes then over dynamic pressures
self
.
_ksm
=
np
.
zeros
(
self
.
n_speed
)
for
i
in
range
(
self
.
n_speed
):
...
...
@@ -63,15 +70,6 @@ class Pk(Solution):
"""
raise
NotImplementedError
()
def
__sfreq
(
self
,
m
,
k
):
"""
Compute the natural frequencies of the structural model
TODO: should it be given directly by the structural solver?
m : mass matrix
k : stiffness matrix
"""
om
,
_
=
spla
.
eig
(
k
,
m
)
# det(-omega^2 * M + K) = 0
return
np
.
sqrt
(
np
.
real
(
om
))
def
__interp
(
self
,
k
,
k_ref
,
q_ref
):
"""
Match the frequency and interpolate the eigenvalues and eigenvectors
k : interpolation reduced frequency
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment