Modules
MMS Module
dyn_sys
Started on Tue Feb 15 17:25:59 2022
@author: Vincent MAHE
Analyse systems of coupled nonlinear equations using the Method of Multiple Scales (MMS). This sub-module defines the dynamical system.
- class oscilate.MMS.dyn_sys.Dynamical_system(t, x, Eq, omegas, **kwargs)[source]
Bases:
objectThe dynamical system studied. See Dynamical systems of interest for a detailed description of the dynamical system.
- Parameters:
t (sympy.Symbol) – time \(t\).
x (sympy.Function or list of sympy.Function) – Unknown(s) of the problem.
Eq (sympy.Expr or list of sympy.Expr) – System’s equations without forcing, which can be defined separately (see parameters F and fF). Eq is the unforced system of equations describing the system’s dynamics.
omegas (sympy.Symbol or list of sympy.Symbol) – The natural frequency of each oscillator.
F (sympy.Symbol or 0, optional) – Forcing amplitude \(F\). Default is 0.
fF (sympy.Expr or list of sympy.Expr, optional) – For each oscillator, specify the coefficient multiplying the forcing terms in the equation. It can be used to define parametric forcing. Typically, if the forcing is \(x F \cos(\omega t)\), then
fF = x. Default is a list of 1, so the forcing is direct.
- class oscilate.MMS.dyn_sys.Forcing(F, fF)[source]
Bases:
objectDefine the forcing on the system as
A forcing amplitude F,
Forcing coefficients fF, used to introduce parametric forcing or simply weight the harmonic forcing.
For the \(i^\textrm{th}\) oscillator, denoting fF[i] as \(f_{F,i}(\boldsymbol{x}(t), \dot{\boldsymbol{x}}(t), \ddot{\boldsymbol{x}}(t))\), the forcing term on that oscillator is \(f_{F,i} F \cos(\omega t)\).
mms
Started on Tue Feb 15 17:25:59 2022
@author: Vincent MAHE
Analyse systems of coupled nonlinear equations using the Method of Multiple Scales (MMS). This sub-module defines the multiple scales system from the dynamical one, and the application of the MMS.
- oscilate.MMS.mms.Chain_rule_d2fdt2(f, tS, eps)[source]
Apply the chain rule to express second order time derivatives in terms of the time scales’ derivatives.
- Parameters:
f (sympy.Function) – Time scales-dependent function \(f(\boldsymbol{t})\).
tS (list) – Time scales \(\boldsymbol{t}^\intercal = [t_0, \cdots, t_{N_e}]\).
eps (sympy.Symbol) – Small parameter \(\epsilon\).
- Returns:
d2fdt2 – \(\mathrm{d}^2 f/ \mathrm{d}t^2\) expressed in terms of the time scales.
- Return type:
sympy.Function
Notes
Consider a time scales-dependent function \(f(t_0, t_1, ...)\), where \(t_0\) is the fast time and \(t_1, ...\) are the slow times. The Chain Rule is applied to give the expression of \(\mathrm{d}^2 f/ \mathrm{d}t^2\) in terms of the time scales.
- oscilate.MMS.mms.Chain_rule_dfdt(f, tS, eps)[source]
Apply the chain rule to express first order time derivatives in terms of the time scales’ derivatives.
- Parameters:
f (sympy.Function) – Time scales-dependent function \(f(\boldsymbol{t})\).
tS (list) – Time scales \(\boldsymbol{t}^\intercal = [t_0, \cdots, t_{N_e}]\).
eps (sympy.Symbol) – Small parameter \(\epsilon\).
- Returns:
dfdt – \(\mathrm{d} f/ \mathrm{d}t\) expressed in terms of the time scales.
- Return type:
sympy.Function
Notes
Consider a time scales-dependent function \(f(t_0, t_1, ...)\), where \(t_0\) is the fast time and \(t_1, ...\) are the slow times. The Chain Rule is applied to give the expression of \(\mathrm{d} f/ \mathrm{d}t\) in terms of the time scales.
- class oscilate.MMS.mms.Forcing_MMS(F, f_order, fF, forcing_term)[source]
Bases:
objectDefine the forcing on the system as
A forcing amplitude F
A scaling order f_order for the forcing
Forcing coefficients fF
Forcing terms (direct or parametric) forcing_term
- class oscilate.MMS.mms.Multiple_scales_system(dynamical_system, eps, Ne, omega_ref, sub_scaling, ratio_omegaMMS=1, eps_pow_0=0, **kwargs)[source]
Bases:
objectThe multiple scales system. See Application of the MMS for a detailed description of the dynamical system.
- Parameters:
dynamical_system (Dynamical_system) – The dynamical system.
eps (sympy.Symbol) – Small perturbation parameter \(\epsilon\).
Ne (int) – Truncation order of the asymptotic series and order of the slowest time scale.
omega_ref (sympy.Symbol) – Reference frequency \(\omega_{\textrm{ref}}\) of the MMS. Not necessarily the frequency around which the MMS is going to be applied, see ratio_omegaMMS.
sub_scaling (list of tuples) – Substitutions to do to scale the equations. Links small parameters to their scaled counterpart through \(\epsilon\).
ratio_omegaMMS (int or sympy.Rational, optional) –
Specify the frequency omegaMMS around which the MMS is going to be applied in terms of \(\omega_{\textrm{ref}}\). Denoting ratio_omegaMMS as \(r_{\textrm{MMS}}\), this means that
\[\omega_{\textrm{MMS}} = r_{\textrm{MMS}} \omega_{\textrm{ref}}.\]Use
ratio_omegaMMS=Rational(p,q)for\[q \omega_{\textrm{MMS}} = p \omega_{\textrm{ref}}\]to get better-looking results than the float \(p/q\). Default is 1.
eps_pow_0 (int, optional) –
Order of the leading order term in the asymptotic series of each oscillators’ response. For the \(i^{\textrm{th}}\) oscillator and denoting eps_pow_0 as \(\lambda_0\), this means that
\[x_i = \epsilon^{\lambda_0} x_{i,0} + \epsilon^{\lambda_0+1} x_{i,1} + \cdots.\]Default is 0.
ratio_omega_osc (list of int or sympy.Rational or None, optional) –
Specify the natural frequencies of the oscillators \(\omega_i\) in terms of the reference frequency \(\omega_{\textrm{ref}}\). Denoting
ratio_omega_osc[i]as \(r_i\), this means that\[\omega_i \approx r_i \omega_{\textrm{ref}}.\]Use
ratio_omega_osc[i]=Rational(p,q)for\[q \omega_{i} \approx p \omega_{\textrm{ref}}\]to get better-looking results than the float \(p/q\). Default is None for each oscillator, so the \(\omega_i\) are arbitrary and there are no internal resonances. Detuning can be introduced through the detunings keyword argument.
detunings (list of sympy.Symbol or int, optional) –
The detuning of each oscillator. Denoting
detunings[i]as \(\delta_i\), this means that\[\omega_i = r_i \omega_{\textrm{ref}} + \delta_i.\]Default is 0 for each oscillator.
Notes
Description of the method of multiple scales.
- apply_MMS(rewrite_polar=0)[source]
Apply the MMS.
- Parameters:
rewrite_polar (str, int or list of int, optional) – The orders at which the solutions will be rewritten in polar form. See
sol_x_polar().
Notes
The application of the MMS is operated by successively calling the following methods.
system_t0(): An equivalent system is written in terms of the fast time scale \(t_0\). This introduces the temporary unknowns \(\tilde{x}_{i,j}(t_0)\) and allows the use ofdsolve().sol_order_0(): Leading order solutions \(x_{i,0}(\boldsymbol{t})\) are defined.secular_analysis(): The leading order solutions are introduced in the equations and the secular terms at each order are identified. Cancelling those secular terms is a condition for bounded solutions. It leads to a system of modulation equations governing the slow time evolution of the complex amplitude of the homogeneous leading order solutions. Each equation takes the form\[\textrm{D}_{j} A_i(\boldsymbol{t}_s) = f_{A_i}^{(j)}(\boldsymbol{A}, t_1).\]After cancelling the secular terms the higher order equations are solved successively to express the higher order solutions \(x_{i,j}(\boldsymbol{t}),\; j>0\) in terms of the leading order ones.
autonomous_phases(): The phase coordinates are changed from \(\phi_i(\boldsymbol{t}_s)\) to \(\beta_i(\boldsymbol{t}_s)\) to cancel the slow time \(t_1\) in the secular terms. This will be used afterwards to obtain an autonomous system.modulation_equations(): The secular conditions are split into real and imaginary parts, polar coordinates are used and the autonomous phases are introduced, resulting in an autonomous system of modulation equations on polar coordinates. Equations come by two, one representing the amplitude modulation while the other represents the phase’s, such that\[\begin{split}\begin{cases} \textrm{D}_{j} a_i(\boldsymbol{t}_s) & = f_{a_i}^{(j)}(\boldsymbol{a}, \boldsymbol{\beta}), \\ a_i \textrm{D}_{j} \beta_i(\boldsymbol{t}_s) & = f_{\beta_i}^{(j)}(\boldsymbol{a}, \boldsymbol{\beta}). \end{cases}\end{split}\]This is the key result of the MMS. The modulations on each time scale can be combined to reintroduce the physical time, resulting in a system of the form
\[\begin{split}\begin{cases} \dfrac{\textrm{d}}{dt} a_i(t) & = f_{a_i}(\boldsymbol{a}, \boldsymbol{\beta}), \\ a_i \dfrac{\textrm{d}}{dt} \beta_i(t) & = f_{\beta_i}(\boldsymbol{a}, \boldsymbol{\beta}). \end{cases}\end{split}\]This is known as the reconstitution method.
sol_x_polar(): The leading and higher order solutions are rewritten in terms of polar coordinates using \(\cos\) and \(\sin\) functions.
- asymptotic_series(dynamical_system, eps_pow_0=0)[source]
Define the asymptotic series.
Notes
The series expansion for oscillator \(i\) (and for a leading order term \(\epsilon^0 = 1\)) takes the form (see Application of the MMS)
\[x_i(t) = x_{i,0}(t) + \epsilon x_{i,1}(t) + \epsilon^2 x_{i,2}(t) + \cdots + \epsilon^{N_e} x_{i,N_e}(t) + \mathcal{O}(\epsilon^{N_e+1}).\]On top of introducing the terms of the asymptotic series, this function prepares substitutions from
dof \(x_i(t)\) to temporary \(t\)-dependent asymptotic terms \(x_{i,j}(t)\), such that
\[x_i(t) = x_{i,0}(t) + \epsilon x_{i,1}(t) + \epsilon^2 x_{i,2}(t) + \cdots + \epsilon^{N_e} x_{i,N_e}(t),\]Temporary \(x_{i,j}(t)\) to the time scales-dependent terms \(x_{i,j}(\boldsymbol{t})\), such that
\[x_i(\boldsymbol{t}) = x_{i,0}(\boldsymbol{t}) + \epsilon x_{i,1}(\boldsymbol{t}) + \epsilon^2 x_{i,2}(\boldsymbol{t}) + \cdots + \epsilon^{N_e} x_{i,N_e}(\boldsymbol{t}).\]
- autonomous_phases()[source]
Define phase coordinates that render an autonomous system.
Notes
Define new phase coordinates \(\beta_i\) to transform nonautonomous equations into autonomous ones. The \(\beta_i\) are defined as
\[\beta_i = \frac{r_i}{r_{\textrm{MMS}}} \sigma t_1 - \phi_i,\]where we recall that \(\omega = r_{\textrm{MMS}} \omega_{\textrm{ref}} + \epsilon \sigma\) and \(\omega_{i,0} = r_i \omega_{\textrm{ref}}\). See details on this choice in Application of the MMS.
- compute_EqO(dynamical_system)[source]
Compute the system of equations for each oscillator at each order of \(\epsilon\). This system is described in Application of the MMS.
The output EqO is a list of lists:
The \(1^{\text{st}}\) level lists are associated to the equations for each oscillator,
The \(2^{\text{nd}}\) level lists are associated to the orders of \(\epsilon\) from the lowest to the highest order.
- Parameters:
dynamical_system (Dynamical_system) – The dynamical system.
- find_harmonics()[source]
Determine the harmonics contained in the MMS solutions.
- Returns:
harmonics – list of the harmonics appearing in the MMS solutions.
- Return type:
- forcing_MMS(dynamical_system)[source]
Rewrite the forcing terms.
- Parameters:
dynamical_system (Dynamical_system) – The dynamical system.
Notes
The initial forcing terms are
\[f_{F,i}(\boldsymbol{x}(t), \dot{\boldsymbol{x}}(t), \ddot{\boldsymbol{x}}(t)) F \cos(\omega t), \quad i=1,...,N.\]Rewritting them involves
Replacing the \(x_i(t)\) by their series expansions written in terms of time scales,
Scaling the forcing and the parameters in \(f_{F,i}\) if any,
Truncating terms whose order is larger than the largest order retained in the MMS,
Rewrite \(\cos(\omega t)\) as
\[\cos(\omega t) = \frac{1}{2} e^{\mathrm{j}(\omega_{\textrm{MMS}} + \epsilon \sigma)t} + cc = \frac{1}{2} e^{\mathrm{j}(\omega_{\textrm{MMS}}t_0 + \sigma t_1)} + cc.\]
- modulation_equations()[source]
Derive the modulation equations of the polar coordinates system.
Notes
Derive the modulation equations of the polar coordinates system (defined in
polar_coordinates()andautonomous_phases()) from the secular conditions. For oscillator \(i\), these are defined as\[\begin{split}\begin{cases} \dfrac{\textrm{d} a_i}{\textrm{d} t} & = f_{a_i}(\boldsymbol{a}, \boldsymbol{\beta}), \\ a_i \dfrac{\textrm{d} \beta_i}{\textrm{d} t} & = f_{\beta_i}(\boldsymbol{a}, \boldsymbol{\beta}), \end{cases}\end{split}\]where \(\boldsymbol{a}\) and \(\boldsymbol{\beta}\) are vectors containing the polar amplitudes and phases.
The aim here is to compute all the \(f_{a_i}\) and \(f_{\beta_i}\). This is done by:
Introducing polar coordinates in the secular terms
Splitting the real and imaginary parts of the (complex) secular terms
Using the autonomous phase coordinates
Collecting the terms governing the slow amplitude and phase dynamics.
- oscillators_frequencies()[source]
Gives the expression of every oscillator frequency in terms of the reference frequency, possibly with a detuning.
Notes
For the \(i^\textrm{th}\) oscillator, this leads to
\[\omega_i = r_i \omega_{\textrm{ref}} + \delta_i .\]An associated first-order natural frequency \(\omega_{i,0}\) is defined by neglecting the detuning \(\delta_i\), which is at least of order \(\epsilon\), resulting in
\[\omega_{i,0} = r_i \omega_{\textrm{ref}}.\]
- polar_coordinates()[source]
Define the polar coordinates.
Notes
Define polar coordinates such that, for oscillator \(i\), the complex amplitude of the homogeneous leading order solution is defined as
\[A_i(\boldsymbol{t}_s) = \frac{1}{2} a_i(\boldsymbol{t}_s) e^{\textrm{j} \phi_i(\boldsymbol{t}_s)},\]where \(a_i(\boldsymbol{t}_s)\) and \(\phi_i(\boldsymbol{t}_s)\) are the solution’s amplitude and phase, respectively.
- reconstitution()[source]
Use the reconstitution method to combine the modulation equations at each order. This reconstitution is based on the chain rule relation
\[\dfrac{\textrm{d}(\bullet)}{\textrm{d}t} = \sum_{i=0}^{N_e} \epsilon^{i} \mathrm{D}_i (\bullet) + \mathcal{O}(\epsilon^{N_e+1}).\]Note that some MMS approaches do not apply this reconstitution step.
- secular_analysis()[source]
Identify the secular terms in the MMS equations. This allows to:
Compute the modulation equations of the complex amplitudes \(A_i(\boldsymbol{t}_s)\), coming from the elimination of the secular terms,
Derive nonsecular MMS equations, i.e. MMS equations with the secular terms cancelled,
Use the nonsecular equations to express the higher order solutions \(x_{i,j}(\boldsymbol{t}),\; j>0\) in terms of the \(\boldsymbol{A}(\boldsymbol{t}_s)\).
- sol_higher_order(EqO_t0, xO_t0, io, ix)[source]
Compute the higher order solutions \(x_{i,j}(\boldsymbol{t}_s),\; j>0\).
- Parameters:
EqO_t0 (list of list of sympy.Expr) – The MMS equations at each order and for each oscillator written with \(t_0\) as the only independent variable.
xO_t0 (list of list of sympy.Function) – Oscillators’ response at each order written in terms of \(t_0\) only, \(\tilde{x}_{i,j}(t_0)\).
io (int) – The order of \(\epsilon\).
ix (int) – The dof number.
- sol_order_0()[source]
Compute the leading-order solutions for each oscillator.
Notes
For oscillator \(i\), the homogeneous solution takes the general form
\[x_{i,0}^{\textrm{h}}(\boldsymbol{t}) = A_i(\boldsymbol{t}_s) e^{\textrm{j} \omega_{i,0} t_0} + cc,\]where \(A_i(\boldsymbol{t}_s)\) is an unknown complex amplitude.
If the oscillator is subject to hard forcing (i.e. forcing appears at leading order), then the particular solution
\[x_{i,0}^{\textrm{p}}(t_0, t_1) = B_i e^{\textrm{j} \omega t} + cc = B_i e^{\textrm{j} (\omega_{\textrm{MMS}} t_0 + \sigma t_1)} + cc\]is also taken into account. \(B_i\) is a time-independent function of the forcing parameters.
- sol_x_polar(rewrite_polar=0)[source]
Write the solutions using the polar coordinates and \(\cos\) and \(\sin\) functions.
- Parameters:
rewrite_polar (str or int or list of int, optional) – The orders at which the solutions will be rewritten in polar form. If
"all", then all solution orders will be rewritten. If int, then only a single order will be rewritten. If list of int, then the listed orders will be rewritten. Default is 0, so only the leading order solution will be rewritten.
- system_t0()[source]
Rewrite the system with the fast time scale as the only independent variable.
Notes
This is a trick to use
dsolve(), which only accepts functions of 1 variable, to solve higher order equations. The higher order equations are rewritten in terms of temporary coordinates \(\tilde{x}_{i,j}(t_0)\) in place of \(x_{i,j}(\boldsymbol{t})\), with \(i,j\) denoting the oscillator number and \(\epsilon\) order, respectively. This is equivalent to temporary considering that \(\boldsymbol{A}(\boldsymbol{t}_s)\) does not depend on the slow times, which is of no consequence as there are no slow time derivatives appearing in the higher order equations at this stage. Indeed, they were either substituted using the complex modulation equations, or they disappeared when eliminating the secular terms.
- time_scales()[source]
Define the time scales.
Notes
The time scales are defined as (see Application of the MMS)
\[t_0 = t, \quad t_1 = \epsilon t, \quad \cdots, \quad t_{N_e} = \epsilon^{N_e} t.\]Substitutions from the physical time \(t\) to the time scales \(t_i, \; i=0, ..., N_e\) are also prepared. Note that \(t_0\) is refered-to as the fast time as it captures the oscillations. Other time scales are refered-to as slow time as they capture the modulations.
- class oscilate.MMS.mms.Substitutions_MMS(sub_t, sub_xO_t, sub_x, sub_scaling, sub_omega, sub_sigma)[source]
Bases:
objectSubstitutions used in the MMS.
- oscilate.MMS.mms.cartesian_to_polar(y, sub_polar, sub_phase=None)[source]
Rewrites an expression or a matrix y from cartesian to polar coordinates.
- Parameters:
y (sympy.Expr or sympy.Matrix) – A sympy expression or matrix written in cartesian coordinates.
sub_polar (list) – A list of substitutions to perform to go from cartesian to polar coordinates.
sub_phase (list, optional) – Additional substitutions to try and get rid of phases, so that only the amplitude remains in the expression. Default is None.
- Returns:
yp – The initial expression or matrix written in polar coordinates.
- Return type:
sympy.Expr or sympy.Matrix
- oscilate.MMS.mms.rescale(expr, mms)[source]
Rescales a scaled expression.
- Parameters:
expr (sympy.Expr) – An unscaled expression, i.e. an expression appearing at some order of \(\epsilon\).
mms (Multiple_scales_system) – The mms system, containing substitutions to scale an expression.
- Returns:
expr_scaled – The scaled expression.
- Return type:
sympy.Expr
- oscilate.MMS.mms.scale_parameters(param, scaling, eps)[source]
Scale parameters with the scaling parameter \(\epsilon\).
- Parameters:
- Returns:
param_scaled (list of sympy.Symbol and/or sympy.Function) – Scaled parameters.
sub_scaling (list of 2 lists of tuple) – Substitutions from scaled to unscaled parameters and vice-versa.
\(1^{\text{st}}\) list: The substitutions to do to introduce the scaled parameters in an expression.
\(2^{\text{nd}}\) list: The substitutions to do to reintroduce the unscaled parameters in a scaled expression.
Notes
For a given parameter \(p\) and a scaling order \(\lambda\), the associated scaled parameter \(\tilde{p}\) is
\[p = \epsilon^{\lambda} \tilde{p} .\]
steady_state
Started on Tue Feb 15 17:25:59 2022
@author: Vincent MAHE
Analyse systems of coupled nonlinear equations using the Method of Multiple Scales (MMS). This sub-module defines the steady state system from the multiple scales one, and the functions for steady state evaluation.
- class oscilate.MMS.steady_state.Coord_SS[source]
Bases:
objectThe coordinates used in the steady state analysis.
- class oscilate.MMS.steady_state.Forcing_SS(mms)[source]
Bases:
objectDefine the forcing on the system.
- class oscilate.MMS.steady_state.Sol_SS(ss, mms)[source]
Bases:
objectSolutions obtained when evaluating at steady state.
- class oscilate.MMS.steady_state.Stab_SS[source]
Bases:
objectStability analysis parameters and outputs.
- class oscilate.MMS.steady_state.Steady_state(mms)[source]
Bases:
objectSteady state analysis of the multiple scales system. See Evaluation at steady state for a detailed description of the dynamical system.
- Parameters:
mms (Multiple_scales_system) – The multiple scales system.
Notes
Description of the steady state analysis.
- Jacobian_cartesian()[source]
Compute the Jacobian of the modulation equations systems expressed in cartesian coordinates (see
stability_analysis()).- Returns:
J – Jacobian of the cartesian system.
- Return type:
sympy.Matrix
- Jacobian_polar()[source]
Compute the Jacobian of the modulation equations systems expressed in polar coordinates (see
stability_analysis()).- Returns:
J – Jacobian of the polar system.
- Return type:
sympy.Matrix
- additional_cartesian_substitutions(fp, fq)[source]
Reformulate the already-existing substitutions from polar to cartesian to try and substitute leftover polar terms.
- Parameters:
- Returns:
fp (list of sympy.Expr) – Evolution functions for the cartesian coordinates \(p_i\). Additional substitutions were performed to get rid of polar coordinates.
fq (list of sympy.Expr) – Evolution functions for the cartesian coordinates \(q_i\). Additional substitutions were performed to get rid of polar coordinates.
- bifurcation_curves(detJ, var_a=False, var_sig=True, solver=<function solve_poly2>)[source]
Compute bifurcation curves, defined by the simple bifurcation points of the slow time system obtained for any forcing frequency and amplitude.
- Parameters:
detJ (sympy.Expr) – The determinant of the matrix.
var_a (bool, optional) – Consider the \(i^{\textrm{th}}\) oscillator’s amplitude \(a_i\) as the variable and find the bifurcation curve as an expression for \(a_i\). detJ is rarely a quadratic polynomial in \(a_i\), so this can rarely be computed easily. Default is False.
var_sig (bool, optional) – Consider the detuning \(\sigma\) as the variable and find the bifurcation curve as an expression for \(\sigma\). detJ is often a quadratic polynomial in \(\sigma\), so this can often be computed. Default is True.
solver (function, optional) – The solver to use to compute the bifurcation curves. Available are solver called as solve(expr, x), which solve expr=0 for x.
solve()can be used but is sometimes slow. Default issolve_poly2().
- Returns:
bif_a (list) – The bifurcation curves for \(a_i^2\).
bif_sig (list) – The bifurcation curves for \(\sigma\).
Notes
Simple bifurcations are associated to real eigenvalues of the Jacobian matrix crossing the imaginary axis, hence passing through 0. As the determinant is the product of the eigenvalues, the zeros of the determinant give the bifurcation points of the system.
- cartesian_coordinates()[source]
Define cartesian coordinates from the polar ones.
Notes
The homogeneous leading order solution for oscillator \(i\) expressed in polar coordinates takes the form
\[\begin{split}\begin{split} x_{i,0}^{\textrm{h}}(t) & = a_i \cos\left(\frac{r_i}{r_{\textrm{MMS}}}\omega t - \beta_i \right), \\ & = a_i \cos(\beta_i) \cos\left(\frac{r_i}{r_{\textrm{MMS}}}\omega t\right) + a_i \sin(\beta_i) \sin\left(\frac{r_i}{r_{\textrm{MMS}}}\omega t\right) \end{split}\end{split}\]The polar coordinates are defined as
\[\begin{split}\begin{cases} p_i = a_i \cos (\beta_i), \\ q_i = a_i \sin (\beta_i), \end{cases}\end{split}\]such that the leading order solution can be written as
\[x_{i,0}^{\textrm{h}}(t) = p_i \cos\left(\frac{r_i}{r_{\textrm{MMS}}}\omega t\right) + q_i \sin\left(\frac{r_i}{r_{\textrm{MMS}}}\omega t\right).\]
- check_cartesian_substitutions(a, beta, fp, fq)[source]
Check if substitutions from polar to cartesian coordinates are complete.
- Parameters:
a (list of sympy.Symbol) – Amplitudes of the leading order solutions.
beta (list of sympy.Symbol) – Phases of the leading order solutions.
fp (list of sympy.Expr) – Evolution functions for the cartesian coordinates \(p_i\).
fq (list of sympy.Expr) – Evolution functions for the cartesian coordinates \(q_i\).
- Returns:
substitution_OK – True if substitutions are complete. False otherwise.
- Return type:
- eigenvalues(A, detA=None, trA=None)[source]
Computes the eigenvalues of a matrix \(\textrm{A}\).
- Parameters:
A (sympy.Matrix) – The matrix whose eigenvalues are to be computed.
detA (sympy.Expr) – Determinant of A. Default is None.
trA (sympy.Expr) – Trace of A. Default is None.
- Returns:
eigvals – The eigenvalues of \(\textrm{A}\).
- Return type:
- modulation_equations_SS(mms)[source]
Evaluate the modulation equations at steady state (polar system).
- modulation_equations_cartesian()[source]
Compute the modulation equations of the cartesian coordinates system.
Notes
Write the modulation equations using the cartesian coordinates (defined in
cartesian_coordinates()). For oscillator \(i\), this results in\[\begin{split}\begin{cases} \dfrac{\textrm{d} p_i}{\textrm{d} t} & = f_{p_i}(\boldsymbol{p}, \boldsymbol{q}), \\ \dfrac{\textrm{d} q_i}{\textrm{d} t} & = f_{q_i}(\boldsymbol{p}, \boldsymbol{q}), \end{cases}\end{split}\]where \(\boldsymbol{p}(t)\) and \(\boldsymbol{q}(t)\) are vectors containing the cartesian coordinates.
- polar_coordinates_SS(mms)[source]
Introduce time-independent amplitudes and phases (polar coordinates).
- solve_F()[source]
Solve the forced response in terms of the forcing amplitude \(F\). Returns \(F(a_i)\)
- solve_a()[source]
Solve the forced response in terms of the oscillator’s amplitude. For readability, the output actually returned is \(a_i^2(\sigma, F)\).
- solve_bbc(c=[], solve_dof=None)[source]
Find the backbone curve (bbc) of a given oscillator with the other oscillators’ amplitude set to 0.
- Parameters:
Notes
The backbone curve describes the frequency of free oscillations as a function of the oscillator’s amplitude. In the presence of small damping (as in the case in the MMS) the frequency of free oscillations is close from the resonance frequency. The backbone curve can therefore be interpreted as the backbone of the forced response.
The backbone curve of oscillator \(i\) typically takes the form
\[\omega_{\textrm{bbc}}^{(i)} = k\omega_{i} + f_{\textrm{bbc}}^{(i)} (a_i),\]where \(k=1,\; k<1,\; k>1\) are associated to direct, superharmonic and subharmonic responses, respectively.
- solve_forced(solve_dof=None)[source]
Solve the forced response of an oscillator.
- Parameters:
solve_dof (None or int, optional) – The oscillator to solve for. If None, no oscillator is solved for. Default is None.
Notes
Find the steady state solution for a given oscillator with the other oscillators’ amplitude set to 0.
To do so, one must choose an oscillator to chose for, say oscillator \(i\). Then, the following methods are called:
substitution_solve_dof(): Set the other oscillators’ amplitude to 0, i.e. \(a_j = 0 \; \forall j \neq i\).solve_phase(): express the oscillator’s phase \(\beta_i\) as a function of its amplitude \(a_i\).solve_sigma(): find the expression of \(\sigma(a_i)\).solve_a(): find the expression of \(a_i (\sigma, F)\).solve_F(): find the expression of \(F(a_i)\).
- solve_phase()[source]
Find solutions for the oscillator’s phase \(\beta_i\). The solutions actually returned are \(\sin(\beta_i)\) and \(\cos(\beta_i)\).
- solve_sigma()[source]
Solve the forced response in terms of the detuning \(\sigma\). Returns \(\sigma(a_i)\). It is recalled that \(\omega = \omega_{\textrm{MMS}} + \epsilon \sigma\).
- stability_analysis(coord='cartesian', rewrite_polar=False, eigenvalues=False, bifurcation_curves=False, trace_curves=False, analyse_blocks=False, kwargs_bif={})[source]
Evaluate the stability of a steady state solution. See Stability analysis for a detailed description of the dynamical system.
- Parameters:
coord (str, optional) – Either
"cartesian"or"polar". Specifies the coordinates to use for the stability analysis."cartesian"is recommended as it prevents divisions by 0, which occur when at least one of the oscillator has a 0 ampliutude. Default is"cartesian".rewrite_polar (bool, optional) – Rewrite the Jacobian’s determinant and trace in polar coordinates (if computed using cartesian ones). This is time consuming and the current back substitutions from cartesian to polar coordinates are not always sufficient. Default is False.
eigenvalues (bool, optional) – Compute the eigenvalues of the Jacobian. Default is False.
bifurcation_curves (bool, optional) – Compute the bifurcation curves. Default is False.
trace_curves (bool, optional) – Compute the trace curves, i.e. the zeros of the Jacobian’s trace. Default is False.
analyse_blocks (bool, optional) – Analyse the diagonal blocks of the Jacobian rather than the Jacobian itself. This is relevant if the Jacobian is block-diagonal.
kwargs_bif (dict, optional) – Passed to
bifurcation_curves()Default is dict().
- substitution_solve_dof(solve_dof)[source]
Set every oscillator amplitude to 0 except the one to solve for.
Notes
If one wants to solve for \(a_i\), then the system is evaluated for \(a_j=0, \; \forall j \neq i\).
- trace_curves(trJ, var_a=False, var_sig=True, solver=<function solve_poly2>)[source]
Compute curves capturing the variations of the trace of the Jacobian. For 2 by 2 Jacobians, a negative trace with a positive determinant indicates a stable response.
- Parameters:
trJ (sympy.Expr) – The trace of the matrix.
var_a (bool, optional) – Consider the \(i^{\textrm{th}}\) oscillator’s amplitude \(a_i\) as the variable and find the trace curve as an expression for \(a_i\). Default is False.
var_sig (bool, optional) – Consider the detuning \(\sigma\) as the variable and find the trace curve as an expression for \(\sigma\). Default is True.
solver (function, optional) – The solver to use to compute the trace curves. Available are solver called as solve(expr, x), which solve expr=0 for x.
solve()can be used but is sometimes slow. Default issolve_poly2().
- Returns:
tr_a (list) – The trace curves for \(a_i^2\).
tr_sig (list) – The trace curves for \(\sigma\).
visualisation
Started on Tue Feb 15 17:25:59 2022
@author: Vincent MAHE
Analyse systems of coupled nonlinear equations using the Method of Multiple Scales (MMS). This sub-module evaluates the symbolic expressions for given numerical parameters and allows to plot the resulting numerical results.
- oscilate.MMS.visualisation.numpise_ARC(mms, ss, dyn, param)[source]
Evaluate the amplitude-response curves at given numerical values. This transforms the sympy expressions to numpy arrays.
- Parameters:
mms (Multiple_scales_system) – The MMS object.
ss (Steady_state) – The MMS results evaluated at steady state.
dyn (Dynamical_system) – The initial dynamical system.
param (dict) –
A dictionnary whose values are tuples with 2 elements:
The sympy symbol of a parameter,
The numerical value(s) taken by that parameter.
The key of the amplitude vector must be
"a". The key of the angular frequency must be"omega".
- Returns:
ARC – The amplitude-response curves data.
- Return type:
- oscilate.MMS.visualisation.numpise_FRC(mms, ss, dyn, param, bbc=True, forced=True, bif=True)[source]
Evaluate the frequency-response and bifurcation curves at given numerical values. This transforms the sympy expressions to numpy arrays.
- Parameters:
mms (Multiple_scales_system) – The MMS object.
ss (Steady_state) – The MMS results evaluated at steady state.
dyn (Dynamical_system) – The initial dynamical system.
param (dict) –
A dictionary whose values are tuples with 2 elements:
The sympy symbol of a parameter,
The numerical value(s) taken by that parameter.
The key of the amplitude vector must be
"a". The key of the forcing amplitude must be"F".bbc (bool, optional) – Evaluate the backbone curve. Default is True.
forced (bool, optional) – Evaluate the forced response. Default is True.
bif (bool, optional) – Evaluate the bifurcation curves. Default is True.
- Returns:
FRC – The frequency-response curves data.
- Return type:
- oscilate.MMS.visualisation.numpise_F_ARC(mms, ss, param)[source]
Numpise the forced response’s forcing amplitude \(F\).
- Parameters:
mms (Multiple_scales_system)
ss (Steady_state)
param (dict) – See
sympy_to_numpy().
- Returns:
F – Numpised forced response’s forcing amplitude.
- Return type:
numpy.ndarray
- oscilate.MMS.visualisation.numpise_omega_FRC(mms, ss, param)[source]
Numpise the forced response’s frequency \(\omega\).
- Parameters:
mms (Multiple_scales_system)
ss (Steady_state)
param (dict) – See
sympy_to_numpy().
- Returns:
omega – Numpised forced response’s frequency.
- Return type:
numpy.ndarray
- oscilate.MMS.visualisation.numpise_omega_bbc(mms, ss, param)[source]
Numpise the backbone curve’s frequency \(\omega_{\textrm{bbc}}\).
- Parameters:
mms (Multiple_scales_system)
ss (Steady_state)
param (dict) – See
sympy_to_numpy().
- Returns:
omega_bbc – Numpised backbone curve’s frequency.
- Return type:
numpy.ndarray
- oscilate.MMS.visualisation.numpise_omega_bif(mms, ss, param)[source]
Numpise the bifurcation curves’ frequency \(\omega_{\textrm{bif}}\).
- Parameters:
mms (Multiple_scales_system)
ss (Steady_state)
param (dict) – See
sympy_to_numpy().
- Returns:
omega_bif – Numpised bifurcation curves’ frequency.
- Return type:
list of numpy.ndarray
- oscilate.MMS.visualisation.numpise_phase(mms, ss, dyn, param, omega, F)[source]
Numpise the phase \(\beta_i\).
- Parameters:
mms (Multiple_scales_system)
ss (Steady_state)
dyn (Dynamical_system)
param (dict) – See
sympy_to_numpy().omega (numpy.ndarray or list of numpy.ndarray) – The frequency array.
F (numpy.ndarray) – The forcing amplitude array.
- Returns:
phase – Numpised phase.
- Return type:
list of numpy.ndarray
- oscilate.MMS.visualisation.plot_ARC(ARC, **kwargs)[source]
Plots the amplitude-response curves (ARC), both forcing amplitude-amplitude and forcing amplitude-phase.
- Parameters:
ARC (dict) – Dictionary containing the amplitude response curves.
- Returns:
fig1 (Figure) – The amplitude plot \(a(F)\).
fig2 (Figure) – The phase plot \(\beta(F)\).
- oscilate.MMS.visualisation.plot_FRC(FRC, **kwargs)[source]
Plots the frequency response curves (FRC), both frequency-amplitude and frequency-phase. Also includes the stability information if given.
- Parameters:
FRC (dict) – Dictionary containing the frequency response curves and the bifurcation curves.
- Returns:
fig1 (Figure) – The amplitude plot \(a(\omega)\).
fig2 (Figure) – The phase plot \(\beta(\omega)\).
sympy_functions Module
Started on Wed Apr 9 13:39:41 2025
@author: Vincent MAHE
Sympy functions useful to the use of MMS functions.
- oscilate.sympy_functions.check_solvability(poly, x)[source]
Check the solvability of a polynomial \(p(x)\).
- Parameters:
poly (sympy.Expr) – The polynomial considered.
x (sympy.Symbol) – The variable to solve for.
- Returns:
bool – True is solvable, False otherwise.
- Return type:
bool,
- oscilate.sympy_functions.get_block_diagonal_indices(matrix, block_sizes)[source]
Generate a list of \((i, j)\) indices for all elements in the diagonal blocks of a block-diagonal matrix.
- oscilate.sympy_functions.get_exponent(expr, x)[source]
Get the exponent of \(x\) in an expression of the type \(\lambda x^n\) where \(\lambda\) is a constant while \(n\) is an integer or rational.
- Parameters:
expr (sympy.Expr) – The expression in which one wants to identify the exponent of x.
x (sympy.Symbol) – The variable whose exponent is to be known.
- oscilate.sympy_functions.is_block_diagonal(matrix, block_sizes)[source]
Check if a matrix is block-diagonal given block sizes.
- oscilate.sympy_functions.polynomial_terms(poly, x)[source]
Identify the terms of a polynomial.
- Parameters:
poly (sympy.Expr) – The polynomial considered.
x (sympy.Symbol) – The variable to solve for.
- Returns:
dic_x – The polynomial terms.
- Return type:
Notes
If the expression given for poly is of the form
\[p(x) = q(x) x^{-n},\]where the powers of \(x\) in \(q(x)\) are all superior or equal to \(0\), then an auxiliary polynomial
\[P(x) = \dfrac{p(x)}{x^{-n}}\]is constructed. It is the terms of that positive powers polynomial that are returned.
- oscilate.sympy_functions.solve_poly2(poly, x)[source]
Finds the roots of a polynomial of degree 2.
- Parameters:
poly (sympy.Expr) – polynomial whose roots are to be computed
x (sympy.Symbol) – Variable of the polynomial
- Returns:
x_sol – list containing the two roots of the polynomial
- Return type:
list of sympy.Expr
Notes
The polynomial of degree 2 takes the form
\[p(x) = a x^2 + bx + c.\]Note that \(b\) can be null but not \(a\) nor \(c\).
It is a workaround to using
solve()orsolveset(). These two work but can be very long when coefficients \(a,\; b,\; c\) are expressions involving many parameters. Note thatsolve()is significantly slower thansolveset().
- oscilate.sympy_functions.sub_deep(expr, sub)[source]
Performs deep substitutions of an expression.
- Parameters:
expr (sympy.Expr) – Expression on which substitutions are to be performed.
sub (list of tuples) – The substitutions to perform.
- Returns:
expr_sub – The expression with substitutions performed.
- Return type:
sympy.Expr
Notes
Deep substitutions are needed when a substitution involves terms that can still be substituted. For instance, one wants to substitute \(a_1\) and \(a_2\) by expressions, but \(a_1\) is actually a function of \(a_2\), so at least 2 substitutions are required.
- oscilate.sympy_functions.sympy_to_numpy(expr_sy, param)[source]
Transform a sympy expression into a numpy array.
- Parameters:
expr_sy (sympy.Expr) – A sympy expression.
param (dict) –
A dictionnary whose values are tuples with 2 elements:
The sympy symbol of a parameter
The numerical value(s) taken by that parameter
- Returns:
expr_np – The numerical values taken by the sympy expression evaluated.
- Return type:
numpy.ndarray