6. Canonical Transformations¶
A transformation of canonical variables \(T:({q},{p}) \rightarrow ({q}',{p}')\) that leaves Hamilton’s equations unaltered so that
is called a canonical transformation. Often the equations of motion encountered in celestial mechanics problems can be simplified by appropriately chosen canonical coordinate trasformations.
This documentation isn’t an introduction to canonical transformations, though there are several standard references, e.g., Goldstein’s Classical Mechanics.
6.1. The CanonicalTransformation
class¶
The class
CanonicalTransformation
provides a framework for composing and applying such transformations.
An instance of a
CanonicalTransformation
is initialized with a set of rules for transforming from old to new
variables and vice versa. These rules can be applied to any
expressions involving canonical variables by using the
old_to_new()
and
new_to_old()
methods. Additionally, the canonical transformation can be applied to
a Hamiltonian
instance in order to
produce a new Hamiltonian object that has the new variables as
canonical variables and with the Hamiltonian appropriately transformed.
As an example, we’ll apply a canonical transformation to simplify the toy Hamiltonian
First, we’ll set up a Hamiltonian
object to
represent this system
from celmech import CanonicalTransformation, Hamiltonian, PhaseSpaceState
import sympy as sp
import numpy as np
p1,p2,q1,q2 = sp.symbols("p(1:3),q(1:3)")
H = p1**2/2 + p2 + p2**4 + sp.cos(3*q1 + 2 * q2)
state=PhaseSpaceState([q1,q2,p1,p2],np.random.uniform(-0.5,0.5,4))
ham = Hamiltonian(H,{},state)
Next, we’ll build a canonical transformation to new variables \((Q_i,P_i)\) according to \(\mathbf{Q} = T\cdot \mathbf{q}\) and \(\mathbf{P} = (T^{-1})^\mathrm{T} \cdot \mathbf{p}\) for a matrix \(T\). We’ll construct our transformations so that \(Q_1 = 3q_1+2q_2\), the argument of the cosine term appearing in the original Hamiltonian and we’ll set \(Q_2 = q_2\).
We use the CanonicalTransformation
class method
from_linear_angle_transformation()
to produce a
CanonicalTransformation
instance
representing the desired transformation:
Tmtrx = [[3,2],[0,1]]
qp_old = ham.qp_vars
ct = CanonicalTransformation.from_linear_angle_transformation(qp_old,Tmtrx)
We examine the resulting transformation by expressing each old canonical variable in terms of new variables and vice versa
for variable in ct.old_qp_vars:
exprn = ct.old_to_new(variable)
display((variable,exprn))
for variable in ct.new_qp_vars:
exprn = ct.new_to_old(variable)
display((variable,exprn))
which produces the output
Now we’ll use our canonical transformation to generate a new Hamiltonian
with the
old_to_new_hamiltonian()
method:
kam = ct.old_to_new_hamiltonian(ham,do_reduction=True)
kam.H
The final line displays the transformed Hamiltonian in terms of the new variables:
After the transformation, the Hamiltonian does not depend on \(Q_2\), so the
corresponding momentum variable, \(P_2\), is conserved. By passing the
keyword argument do_reduction=True
, we have elected to generate a new
Hamiltonian in terms of the reduced phase space variables, \((Q_1,P_1)\) in
which the conserved quantity \(P_2\) appears as a parameter instead of a
dynamical variable.
The reduced Hamiltonian still keeps track the full set of phase space
variables, \((Q_1,Q_2,P_1,P_2)\), through the
full_qp
attribute.
This stores a dictionary-like representation where the variable symbols
serve as keys and their numerical values as the associated value
entries.
It is particularly useful to have access to these values in situations
where one wishes to carry out an integration or other calculation in the
reduced phase space reduced Hamiltonian, but express results in the
original phase space variables using the inverse canonical
transformation. However, as we will see below, the numerical value
stored for \(Q_2\) in full_qp
will NOT be updated according
to \(\frac{d}{dt}Q_2 = \frac{\partial}{\partial P_2}\) when the
system is integrated forward in time.
6.1.1. Common transformations¶
The CanonicalTransformation
class
provides a number of convenient class methods for initializing frequently used
canonical transformations.
The best way to get a feeling for these convenience functions is to see them applied to a real working problem: CanonicalTransformations.ipynb. A more advanced notebook using these functions is ResonantChain.ipynb.
The functions themselves include:
cartesian_to_polar()
implements a transformation taking user-specified canonical variable pairs \((q_i,p_i)\) to new variable pairs \((Q_i,P_i)=\left((\tan^{-1}(q_i/p_i),\frac{1}{2}(q_i^2+p_i^2)\right)\)polar_to_cartesian()
implements a transformation taking user-specified canonical variable pairs \((q_i,p_i)\) to new variable pairs \((Q_i,P_i)=\left(\sqrt{2p_i}\sin q_i,\sqrt{2p_i}\cos q_i\right)\)from_linear_angle_transformation()
produces the transformation \((\pmb{q},\pmb{p})\rightarrow(\pmb{Q},\pmb{P})\) given by\[\begin{eqnarray} \pmb{Q} = T \cdot \pmb{q} ~&;~ \pmb{P} = (T^{-1})^\mathrm{T} \cdot \pmb{p} \end{eqnarray}\]where \(T\) is a user-specified invertible matrix (useful for constructing new angles from linear combinations of old angles).
from_poincare_angles_matrix()
takes aPoincare
instance as input, along with an invertible matrix \(T\), and produces a transformation where the new canonical coordinates are linear combinations of the planets’ angular orbital elements given by \(\pmb{Q} = T\cdot (\lambda_1 ,..., \lambda_N,-\varpi_1,... ,-\varpi_N,-\Omega_1 ,..., -\Omega_N)\). This is useful for constructing new angles from combinations of old angles when only a small number of angle combinations appear in the Hamiltonian.from_type2_generating_function()
allows the user to specify a generating function \(F_2(\pmb{q},\pmb{P})\) (see, e.g., the Goldstein textbook reference above) producing a canonical transformation that satisfies the equations\[\begin{eqnarray} \mathbf{Q} = \nabla_{\mathbf{P}}F_2~&;~ \mathbf{p} = \nabla_{\mathbf{q}}F_2~. \end{eqnarray}\]rescale_transformation()
allows users to simulaneously rescale the Hamiltonian and canonical variables. This is useful for choosing physical scale/units for the problem at hand.Lambdas_to_delta_Lambdas()
transforms the \(\Lambda_i\) variables of aPoincare
instance to new variables \(\delta\Lambda_i=\Lambda_i - \Lambda_{i,0}\). Expanding around reference values of the $Lambda_i$ is often useful since the $Lambda_i$ are always nonzero, and the changes in their values are typically very small.
6.1.2. Reducing Degrees of Freedom¶
If the transformed Hamiltonian \(H' = H \circ T^{-1}\) is independent of one or more of the new canonical coordinate variables, \(q'_i\), then the corresponding new momentum variable, \(p'_i\) is a constant of motion. Finding transformations that elminate the dependence on one or more degrees of freedom allows one to consider a simpler, lower-dimensional Hamiltonian problem involving only those conjugate variable pairs, \((q'_i,p'_i)\), for which both variables appear explicitly in the Hamiltonian.
6.2. Lie Series Transformations¶
celmech
offers functionality for doing canonical perturbation theory
calculations through the
FirstOrderGeneratingFunction
class. We
give a brief overview of canonical perturbation theory before describing the
FirstOrderGeneratingFunction
class below.
6.2.1. Overview of Canonical Perturbation Theory¶
Constructing a Hamiltonian with a finite number of disturbing function terms implicitly assumes that an infinite number of other terms can be ignored because they are rapdily oscillating such that there average effect on the dynamics is negligible. In reality, these rapidly oscillating terms lead to rapid oscillations in the dynamical variables under study. The goal of canonical perturbation theory is to construct a near-identity canonical transformation to new dynamical variables governed by a Hamiltonian that no longer possesses these rapidly oscillating terms. Often, we will refer to the original variables that show rapid oscillations as osculating variables and the transformed variables for which these oscillations have been eliminated as mean variables. Lie series transformations provide a particularly elegant means by which to construct such a transformation. If the following discussion seems overly abstract, it may be helpful to reference the concrete example presented below.
A Lie series transformation is defined by its generating function, \(\chi(q',p')\), a function of canonical variables. The Lie transformation, \(f\rightarrow f'\) of a function \(f\), induced by a particular generating function \(\chi\), is defined as
where \({\cal L}_\chi= [\cdot,\chi]\) is the Lie derivative with respect to \(\chi\), i.e., the Poisson bracket of a function with \(\chi\).
Generally, the goal of applying a Lie transformation is to eliminate the dependence of a Hamiltonian on a set of variables up to a specific order in some small parameter. In other words, usually one seeks to transform a Hamiltonian of the form \(H = H_0(p) + \epsilon H_1(q,p) + \epsilon^2H_2(q,p) + ...\), such that
where, in the new, transformed variables, \((q',p')\), the Hamiltonian is integrable if one ignores terms of order \(\epsilon^N\) and smaller. In other words, \(p' = \exp[{\cal L}_{\chi(q,p)}]p\) is a conserved quantity up to order \(\epsilon^{N-1}\).
We’ll focus on constructing the transformation to first order in \(\epsilon\). If \(\chi\sim\mathcal{O}(\epsilon)\), then the transformed Hamiltonian is
Thus, we can eliminate the \(q'\) dependence of \(H'\) if \([H_0(p'),\chi(q',p')] = -H_1(q',p')\). Suppose we can express the perturbation Hamiltonian as a Fourier series in the variables \(q\):
Then the condition \([H_0(p'),\chi(q',p')] = -H_1(q',p')\) can be written as
where \(\mathbf{\omega}(p') = \nabla_{p'}H_0(p')\). This equation is readily solved by taking
however, in order for this solution to be valid, we must have \(\mathbf{k}\cdot\omega(p') \ne 0\). In other words, our transformation cannot be applied to resonant domains of phase space. Generally, resonances are dense in phase space, so our goal of eliminating any dependence on \(q'\) in the transformed Hamiltonian will not be possible. However we can still eliminate non-resonant harmonics from the transformed Hamiltonian if we only sum over \(\mathbf{k}\) values that are non-resonant in whatever region of phase-space we are interested in. More technically, if we are intersted in some domain of action space, \(D\), then we should exclude the set of \(\mathbf{k}\) vectors
and define our generating function as
- The sum above will generally include an inifinte number of \(k\) vectors.
However, the Fourier properties of smooth functions generally guarantee that
\(A_\mathbf{k}(p')\sim \exp(-|\mathbf{k}|_{1})\) where \(|\mathbf{k}|_{1}=\sum_i|k_i|\). If we’re interested in constructing a perturbation theory to first order in \(\epsilon\), then we only need to include a limited number of terms with \(|\mathbf{k}|_1 < k_\mathrm{max} \sim -\log\epsilon\).
6.2.2. The FirstOrderGeneratingFunction
class¶
celmech
provides the
FirstOrderGeneratingFunction
class for
applying Lie series transformations between osculating variables like those
integrated by via \(N\)-body simulations, which include every harmonic in
the interaction potential between planet pairs, and mean variables appropriate
for Hamiltonian models built with the
PoincareHamiltonian
class which typically include
only a small handful of harmonics from the interaction potential. celmech
.
The resulting transformations will apply corrections at first order in
planet-star mass ratio.
A FirstOrderGeneratingFunction
instance
provides a representation of a the generating function, \(\chi\), for a Lie
series transformation. The user builds up this function by specifying which
terms from the disturbing function the transformation should eliminate from
the full Hamiltonian at first order in planet masses. The interface for adding
disturbing function terms is very similar to the interface for adding terms to
a PoincareHamiltonian
object. (In fact, the
FirstOrderGeneratingFunction
is a special
sub-class of PoincareHamiltonian
that simple
overwrites the methods for adding disturbing function terms and adds some
additional functionality.)
6.2.2.1. An example¶
As usual, the most straightforward way to understand how this class works is by
way of example. Let’s suppose we want to study the secular dynamics of a pair
of planets near, but not in, a 3:2 MMR. We begin by setting up a rebound
simulation:
sim = rebound.Simulation()
sim.add(m=1)
sim.add(m=1e-5,P = 1, e=0.04)
sim.add(m=1e-5,P = (3/2) * ( 1 + .03), e=0.02,pomega = np.pi/2,l=0)
sim.move_to_com()
We’ll set up two corresponding PoincareHamiltonian
simulations, one modeling just the effect of secular terms (pham_sec
) and
one accounting for the effect of secular terms as well as the 3:2 MMR
(pham_full
):
pvars_sec, pvars_full = [Poincare.from_Simulation(sim) for _ in range(2)]
pham_sec = PoincareHamiltonian(pvars_sec)
pham_full = PoincareHamiltonian(pvars_full)
for pham in (pham_sec,pham_full):
pham.add_secular_terms(inclinations=False)
pham_full.add_MMR_terms(3,1)
Performing integrations with the two models and \(N\)-body, and plotting a comparison, we observe the following eccentricity behaviour:
All three models show the same overall long-term eccentricity trends but the
\(N\)-body model shows some short-term oscillations that comparison with
the pham_full
model reveals is mainly due to the effects of the 3:2
MMR. Next, we’ll capture these oscillations using a Lie series transformation.
6.2.2.2. Incorporating Lie transformations¶
Now we’ll redo our integration with the secular model while using the Lie
transformation methods and the
FirstOrderGeneratingFunction
class to
account for these oscillations. We’ll still be integrating our purely secular
equtions of motion but the application of the Lie series transformation will
allow us to approximate the effect of the 3:2 terms using a perturbative
approach. We’ll construct a first-order generating function
that eliminates the oscillating terms
H_3to2 = pham_full.H - pham_sec.H
H_3to2
We construct our desired transformation using:
from celmech.lie_transformations import FirstOrderGeneratingFunction
pchi = FirstOrderGeneratingFunction(pham_sec.state)
pchi.add_MMR_terms(3,1)
pchi.chi
This is precisely the generating function that eliminates the desired terms at
first order. We can even confirm the equation \([H_\mathrm{Kep},\chi] =
-H_{3:2}\), where \(H_{3:2}\) are the oscillating terms associated with the
3:2 MMR, using sympy
:
Hkep = PoincareHamiltonian(Poincare.from_Simulation(sim))
sp.simplify(pchi.Lie_deriv(Hkep.H) + H_3to2)
where the last line evaluates to 0. Now we do the integration:
N = 100
Tfin = 200
times = np.linspace(0,Tfin,N)
e_sec_mean,e_sec_osc = np.zeros((2,2,N))
for i,t in enumerate(times):
# convert initial osculating values to mean ones
pchi.osculating_to_mean()
pham_sec.integrate(t)
for j,p in enumerate(pham_sec.particles[1:]):
e_sec_mean[j,i] = pham_sec.particles[j+1].e
pchi.mean_to_osculating()
# convert mean back to
for j,p in enumerate(pham_sec.particles[1:]):
e_sec_osc[j,i] = pham_sec.particles[j+1].e
The calls to
osculating_to_mean()
and
mean_to_osculating()
convert the values of of the canonical variables stored by pham_sec.state
back and forth between the “primed” and “unprimed” values related by
\((q',p') = \exp[\mathcal{L}_{\chi}](q,p)\) so that e_sec_mean
will
store “mean” values that evolve according to the Hamiltonian pham_sec.H
while e_sec_osc
includes oscillations due to the 3:2 MMR terms. These
oscillations are computed analytically using the Lie transformation formalism.
Comparing our solutions for the osculating and mean eccentricities to the
results of our original integrations, we find
Now the ‘mean’ eccentricity variables track the overall trend and we’ve
eliminated the initial offset of these mean values by applying
osculating_to_mean
before commencing the integration. The
analytically-calculated correction from mean to osculating variables also match
nicely with the direct integration of both the Hamiltonian, pham_full
, as
well as direct \(N\)-body.
The mean eccentricity trends of our simple secular model acutally begins to diverge somewhat from the integration of the fuller Hamiltonian model, suggesting a small frequency difference in the secular frequencies between the two models. This small frequency difference arises from terms that are second order in mass. Normally such terms would be negligible, but they are amplified by a small denominator in this case because the system lies near the 3:2 MMR. Second-order in mass corrections and the effect of nearby MMRs are discussed in the Section ‘Corrections to Secular Dynamics Near Resonance’.
6.2.2.3. Complete Elimination of 0th Order Terms¶
In the example presented above, we used a Lie series transformation to eliminate two disturbing function harmonics with frequency \(3n_2 - 2n_1\) from the Hamiltonian by adding two corresponding terms to the generating function. When adding individual terms to the generating function in this fashion, we are typically limited in the number of terms we can practically eliminate from the transformed Hamiltonian. However, it is possible with the addition of a single term to the generating function to eliminate all harmonics of the synodic frequency, \(n_\mathrm{syn} = n_1 - n_2\), to zeroth order in eccentricities and inclinations. For circular, planar orbits, the interaction Hamiltonian is
where
The oscillating part of this interaction term can be eliminated at first order in planet masses with the generating function
where \(\bar{P}(\alpha) = \frac{1}{2\pi}\int_{-\pi}^{\pi}P(\psi,\alpha)d\psi\) is the mean value of \(P(\psi,\alpha)\). The integral over \(\psi\) can be expressed in closed form using elliptic functions as
where \(\mathbb{K}\) and \(F\) are complete and incomplete elliptic
integrals of the first kind, respectively. The term, \(\chi_0\) that
eliminates all zeroth order harmonics from the interaction Hamiltonian can be
added to the generating function represented by a
FirstOrderGeneratingFunction
instance
using the
add_zeroth_order_term()
method.
6.3. API¶
- class celmech.canonical_transformations.CanonicalTransformation(old_qp_vars, new_qp_vars, old_to_new_rule=None, new_to_old_rule=None, old_to_new_simplify=None, new_to_old_simplify=None, params={}, **kwargs)[source]¶
A class for representing canonical transformations.
An instance represents a transformation from old canonical variables, \((q,p)\) to new variables \((q',p')\).
- old_qp_vars¶
A list of symbols representing the old variables, \((q,p)\). The list should contain all coordinate variables, \(q\), followed by their conjugate momentum variables \(p\).
- Type
- new_qp_vars¶
A list of symbols representing the new variables, \((q',p')\). The list should contain all coordinate variables, \(q'\), followed by their conjugate momentum variables \(p'\).
- Type
- old_to_new_rule¶
A dictionary defining the substitution rules applied to transform from old canonical variables to new ones.
- Type
dictionary
- new_to_old_rule¶
A dictionary defining the substitution rules applied to transform from new canonical variables to old ones.
- Type
dictionary
- old_to_new_simplify¶
A function that will be applied to expressions when transforming from old to new variables.
- Type
function
- new_to_old_simplify¶
A function that will be applied to expression when transforming from new to old variables.
- Type
function
- params¶
A dictionary setting the numerical values of any parameters on which the transformation depends.
- Type
- H_scale¶
A factor by which the transformation rescales the Hamiltonian. This is used when applying transformations that simulatneously rescale the momenta and the Hamiltonian.
- Type
symbol or float
- classmethod Lambdas_to_delta_Lambdas(pham)[source]¶
Generate a canonical transformation applicable to a PoincareHamiltonian object, pham, that replaces the canonical momenta \(\Lambda_i\) conjugate to the mean longitudes \(\lambda_i\) with new momenta \(\delta\Lambda_i = \Lambda_i - \Lambda_{i,0}\).
- N_new_to_old(exprn)[source]¶
Same as
new_to_old()
but with numerical values replacing any symbolic parameters.
- N_old_to_new(exprn)[source]¶
Same as
old_to_new()
but with numerical values replacing any symbolic parameters.
- classmethod actions_to_delta_actions(old_qp_vars, actions, delta_actions, actions_ref, params={})[source]¶
Generate a canonical transformation applicable to a PoincareHamiltonian object, pham, that replaces the canonical momenta \(\Lambda_i\) conjugate to the mean longitudes \(\lambda_i\) with new momenta \(\delta\Lambda_i = \Lambda_i - \Lambda_{i,0}\).
- classmethod cartesian_to_polar(old_qp_vars, indices=None, polar_symbol_pairs=None, **kwargs)[source]¶
Initialize a canonical transformation that transforms a user-specified subset of conjugate coordinate-momentum pairs, \((q_i,p_i)\), to new ‘polar-style’ variable pairs
\[(Q_i,P_i) = \left(\tan^{-1}(q_i/p_i), \frac{1}{2}(q_i^2+p_i^2)\right)\]- Parameters
old_qp_vars (array-like) – The list of old canonical variables
indices (array-list) – List of integer indices of the coordinate-momentum pairs to be transformed.
polar_symbol_pairs (list, optional) – List of symbols to use for the new polar-style variables. Default symbols are \((Q_i,P_i)\) where the index i ranges over the number of variable pairs being transformed.
- Returns
The resulting transformation.
- Return type
.CanonicalTransformation
- classmethod composite(transformations, old_to_new_simplify=None, new_to_old_simplify=None)[source]¶
Create a canonical transformation as the composition of canonical transformations.
- Parameters
transformations (list of
CanonicalTransformation
) –List of transformations to compose. Transformations are composed in the order
\[T_N \circ T_{N-1}\circ ...\circ T_1 \circ T_0\]when passed the list \([T_0,T_1,...,]\).
- Return type
.CanonicalTransformation
- classmethod from_linear_angle_transformation(old_qp_vars, Tmtrx, old_cartesian_indices=[], new_cartesian_indices=[], **kwargs)[source]¶
Produces the transformation \((\pmb{q},\pmb{p})\rightarrow(\pmb{Q},\pmb{P})\) given by
\[\begin{eqnarray} \pmb{Q} = T \cdot \pmb{q} ~&;~ \pmb{P} = (T^{-1})^\mathrm{T} \cdot \pmb{p} \end{eqnarray}\]where \(T\) is a user-specified matrix.
- Parameters
old_qp_vars (list) – List of old variable symbols.
Tmtrx (array-like) – Matrix defining the canonical transformation.
old_cartesian_indicies (list) – List of indices specifying which old variables are cartesian-style pairs.
new_cartesian_indicies (list) – List of indices specify which new variables should be created as cartesian style pairs.
- Return type
.CanonicalTransformation
- classmethod from_poincare_angles_matrix(p_vars, Tmtrx, new_qp_pairs=None, **kwargs)[source]¶
Given an input
Poincare
instanace and an invertible matrix, \(T\), generate a transformation for which the new angle variables are given by\[\begin{split}\pmb{Q} = T \cdot \begin{pmatrix} \lambda_1 \\ \vdots \\ \lambda_N \\ \gamma_1 \\ \vdots \\ \gamma_N \\ q_1 \\ \vdots \\ q_N \end{pmatrix}~.\end{split}\]- Parameters
pvars (celmech.poincare.Poincare) – A Poincare instance with variables to which the resulting transformation will apply.
Tmtrx (ndarray, shape (N,N)) – An invertible matrix determining the new canonical angle variables as linear combinations of the planets’ orbital elements.
new_qp_pairs (list, optional) – A list of the symbols to use for the newly-generated coordinate-momentum pairs. List entries should be given in the form of 2-tuples containing a coordinate symbol followed by its conjugate momentum variable. If no list is supplied, the default symbols \((Q_i,P_i)\) will be used.
- Returns
The resulting transformation.
- Return type
.CanonicalTransformation
- classmethod from_type2_generating_function(F2func, old_qp_vars, new_qp_vars, **kwargs)[source]¶
Initialize a canonical transformation derived from a type 2 generating function. Given a set of old variables \((q,p)\), new variables, \((Q,P)\) and generating function \(F_2(q,P)\), the transformation rules are given by
\[\begin{split}p &=& \frac{\partial }{\partial q}F_2(q,P) \\ Q &=& \frac{\partial }{\partial P}F_2(q,P)\end{split}\]- Parameters
F2func (sympy expression) – The type 2 generating function
old_qp_vars (array-like) – The list of old canonical variables
new_qp_vars (array-like) – The list of new canonical variables
- Returns
The resulting transformation.
- Return type
.CanonicalTransformation
- new_to_old(exprn)[source]¶
Transform an expression in terms of new canonical variables to one in terms of old varialbes.
- Parameters
exprn (sympy expression) – The expression to transform.
- Returns
The transformed expression.
- Return type
sympy expression
- new_to_old_array(arr)[source]¶
Convert an array of new variable values to the corresponding values of old canonical variables.
- Parameters
arr (array-like) – Value of new variables
- Returns
new_arr – Array of old variable values.
- Return type
numpy.array
- old_to_new(exprn)[source]¶
Transform an expression in terms of old canonical variables to one in terms of new varialbes.
- Parameters
exprn (sympy expression) – The expression to transform
- Returns
The transformed expression.
- Return type
sympy expression
- old_to_new_array(arr)[source]¶
Convert an array of old variable values to the corresponding values of new canonical variables.
- Parameters
arr (array-like) – Value of old variables
- Returns
new_arr – Array of new variable values.
- Return type
numpy.array
- old_to_new_hamiltonian(ham, do_reduction=False)[source]¶
Apply canonical transformation to a
Hamiltonian
object, transforming the Hamiltonian and producing a new object with astate
attribute representing the phase space position in the new canonical variables.- Parameters
ham (celmech.hamiltonian.Hamiltonian) – The Hamiltonian object to which transformation is applied.
do_reduction (bool, optional) – If
True
, automatically reduce the number of degrees of freedom by detecting which canonical variables do not appear in the expression of the transformed Hamiltonian.
- Returns
new_ham – The transformed Hamiltonian.
- Return type
- classmethod polar_to_cartesian(old_qp_vars, indices=None, cartesian_symbol_pairs=None, **kwargs)[source]¶
Initialize a canonical transformation that transforms a user-specified subset of conjugate coordinate-momentum pairs, \((q_i,p_i)\), to new ‘cartesian-style’ variable pairs
\[(Q_i,P_i) = \left(\sqrt{2p_i}\sin q_i,\sqrt{2p_i}\cos q_i\right)\]- Parameters
old_qp_vars (array-like) – The list of old canonical variables
indices (array-list) – List of integer indices of the coordinate-momentum pairs to be transformed.
cartesian_symbol_pairs (list, optional) – List of symbols to use for the new cartesian-style variables. Default symbols are \((y_i,x_i)\) where the index i ranges over the number of variable pairs being transformed.
- Returns
The resulting transformation.
- Return type
.CanonicalTransformation
- classmethod rescale_transformation(qp_pairs, scale, cartesian_pairs=[], **kwargs)[source]¶
Get a canonical transformation that simulatneously rescales the Hamiltonian and canonical momenta by a common factor.
- Parameters
qp_pairs (list of 2-tuples) – Pairs of canonically conjugate variable symbols.
scale (symbol or real) – Re-scaling factor. The new momenta will be given by p’ = scale * p and the new Hamiltonian will be H’ = scale * H.
pairs (cartesian) – List of indices of Cartesian-style canonical pairs. These pairs will be recscaled such that (y’,x’) = sqrt(scale) * (y,x)
- class celmech.lie_transformations.FirstOrderGeneratingFunction(pvars)[source]¶
A class representing a generating function that maps from the ‘osculating’ canonical variables of the full \(N\)-body problem to ‘mean’ variables of an ‘averaged’ Hamiltonian or normal form.
The generating function is constructed to first order in planet-star mass ratios by specifying indivdual cosine terms to be eliminated from the full Hamiltonian.
This class is a sub-class of
celmech.poincare.PoincareHamiltonian
and disturbing function terms to be eliminated are added in the same manner that disturbing function terms can be added tocelmech.poincare.PoincareHamiltonian
.- chi¶
Symbolic expression for the generating function.
- Type
sympy expression
- N_chi¶
Symbolic expression for the generating function with numerical values of paramteters substituted where applicable.
- Type
sympy expression
- state¶
A set of Poincare variables to which transformations are applied.
- particles¶
List of
PoincareParticle
objects making up the system.- Type
- add_cosine_term(k_vec, max_order=None, l_max=0, nu_vecs=None, l_vecs=None, indexIn=1, indexOut=2, eccentricities=True, inclinations=True)[source]¶
Add a specific cosine term to the disturbing function up to an optional max_order in the eccentricities and inclinations.
- Parameters
k_vec (Tuple of 6 ints) – Coefficients (k1, k2, k3, k4, k5, k6) for a cosine term of the form cos(k1*lambdaOut + k2*lambdaIn + k3*pomegaIn + k4*pomegaOut + k5*OmegaIn + k6*OmegaOut) Note the ks must sum to zero, and by convention we write lambdaOut first, e.g., (3, -2, -1, 0, 0, 0) is cos(3*lambdaOut - 2*lambdaIn - pomega1)
max_order (int, optional) – Maximum order to go to in the (combined) eccentricities and inclinations. Can specify either max_order OR nu_vecs (see below), but not both (most users will use max_order). If neither are passed, max_order defaults to the leading order of the cosine term specified by k_vec.
l_max (int, optional) – Maximum degree of expansion in \(\delta = (\Lambda-\Lambda_0)/\Lambda_0\) to include in cosine coefficients. Default is 0. Can specify either l_max OR l_vecs (see below), but not both (most users will use l_max).
nu_vecs (List of 4-tuples, optional) – A list of the specific combinations of nu indices to include for the cosine term coefficient, e.g., [(0, 0, 0, 0), (1, 0, 0, 0), …] See paper and examples for definition and use. Can specify either max_order OR nu_vecs, but not both (max_order makes more sense for most use cases).
l_vecs (List of 2-tuples, optional) – A list of the specific combinations of l indices to include for the cosine term coefficient, e.g., [(0, 0), (1, 0), (2, 0), …] See paper and examples for definition and use. Can specify either l_max OR l_vecs, but not both (l_max makes more sense for most use cases). One use case for passing particular l_vecs is if one body is massless, so the other Lambda doesn’t vary (and doesn’t need expansion)
indexIn (int, optional) – Index of inner planet. Default 1.
indexOut (int, optional) – Index of outer planet. Default 2.
eccentricities (bool, optional) – By default, includes all eccentricity terms. Can set to False to exclude any eccentricity terms (e.g., fixed circular orbits).
inclinations (bool, optional) – By default, includes all inclination terms. Can set to False to exclude any inclination terms (e.g., co-planar systems).
- add_zeroth_order_term(indexIn=1, indexOut=2)[source]¶
Add generating function term that elimiates planet-planet interactions to 0th order in inclinations and eccentricities.
The added generating function term cancels the term
\[-\frac{Gm_im_j}{a_j}\left(\frac{1}{\sqrt{1+\alpha^2-2\cos(\lambda_j-\lambda_i)}} - \frac{1}{2}b_{1/2}^{(0)}(\alpha) -\frac{\cos(\lambda_j-\lambda_i)}{\sqrt{\alpha}} \right)\]from the Hamiltonian to first order in planet-star mass ratios.
- get_perturbative_solution(expression, free_variables=[], correction_only=False, lambdify=False, time_symbol=None)[source]¶
Calculate a solution for the time evolution of an expression using first-order perturbation theory.
- Parameters
expression (sympy expression) – Expression in terms of canonical variables for which to compute a perturbative solution.
free_variables (list, optional) – List of canonical variables to leave undetermined in the derived expression. By default, free_variables is empty and numerical values are substituted for all canonical variables
correction_only (bool, optional) – If True, only return the perturbative correction to the expression. I.e., if expression is \(f(q,p)\) then only return \([f(q,p),\chi(q,p)]\). Otherwise, return \(f(p,q) + [f(q,p),\chi(q,p)]. Default is \).
lambdify (bool, optional) – If True, return a function using sympy.lambdify. The list of arguments accepted by the returned function will the list free_variables, followed by the time at which to evaluate the expression.
time_symbol (sympy.Symbol, optional) – Symbol to use for denoting time. If no symbol is given, \(t\) is used.
- Returns
result – An expression for the solution as a function of time.
- Return type
sympy expression or function
- mean_to_osculating(**integrator_kwargs)[source]¶
Convert the
state
’s variables from osculating to mean canonical variables.
- mean_to_osculating_state_vector(y, approximate=True, **integrator_kwargs)[source]¶
Convert a state vector of canonical variables of mean variables used by a normal form to un-averaged variables of the full \(N\)-body Hamiltonian.
- Parameters
y (array-like) – State vector of ‘averaged’ canonical variables.
approximate (bool, optional) –
If True, Lie transformation is computed approximately to first order. In other words, the approximation
\[\exp[{\cal L}_{\chi}]f \approx f + \left[f,\chi \right]\]is used. Otherwise, the exact Lie transformation is computed numerically.
- Returns
yosc – State vector of osculating canonical variables.
- Return type
array-like
- osculating_to_mean(**integrator_kwargs)[source]¶
Convert the
state
’s variables from osculating to mean canonical variables.
- osculating_to_mean_state_vector(y, approximate=True, **integrator_kwargs)[source]¶
Convert a state vector of canonical variables of the the un-averaged \(N\)-body Hamiltonian to a state vector of mean variables used by a normal form.
- Parameters
y (array-like) – State vector of un-averaged variables.
approximate (bool, optional) –
If True, Lie transformation is computed approximately to first order. In other words, the approximation
\[\exp[{\cal L}_{\chi}]f \approx f + \left[f,\chi \right]\]False (is used. If) –
computed (the exact Lie transformation is) –
numerically. –
- Returns
ymean – State vector of transformed (averaged) variables.
- Return type
array-like