11.4. Generating a movie of eigendynamics

Eigendynamics, i.e. the exponential growth of a perturbation with a potential oscillation can be nicely visualized in a movie. To that end, we can generate a sequence of images with an eigenperturbation that grows (and oscillates) like \(exp(\lambda t)\). As an example of such a movie, refer to Section 10.3.2, where the azimuthal instability of a bubble is investigated. Here, due to the azimuthal instability, it is effectively a three-dimensional scenario which is even harder to visualize in any other way.

Example of the eigendynamics of the rising bubble case.

We first start by importing the problem class from rising_bubble.py and define a conventional plotter class. We don’t have to do anything regarding the eigendynamics here. This plotter can therefore be also used for the base state, as done in the previous examples.

from rising_bubble import *
from pyoomph.output.plotting import MatplotlibPlotter

# Define a plotter as usual. We don't have to care about the eigendynamics here
class RisingBubblePlotter(MatplotlibPlotter):
    def define_plot(self):
        pr=cast("RisingBubbleProblem",self.get_problem())
        self.set_view(-3*pr.R,-5*pr.R,3*pr.R,2*pr.R)
        cb_v=self.add_colorbar("velocity",cmap="viridis",position="top right")
        self.add_plot("domain/velocity",colorbar=cb_v,transform=[None,"mirror_x"])
        self.add_plot("domain/velocity",mode="streamlines",transform=[None,"mirror_x"])
        self.add_plot("domain/interface",transform=[None,"mirror_x"])

We can then just find a stationary solution, solve (and refine) the eigensolution:

with RisingBubbleProblem() as problem:
    # Same as before in the rising bubble problem, except that we just solve at Bo=4
    problem.set_c_compiler("system").optimize_for_max_speed()
    problem.set_eigensolver("slepc").use_mumps()
    problem.setup_for_stability_analysis(azimuthal_stability=True,analytic_hessian=False)
    problem.Mo=6.2e-7
    problem.Bo.value=4
    m=1
    lambd=0.1+0.67j

    problem.run(10,startstep=0.1,outstep=False,temporal_error=1)
    problem.solve(max_newton_iterations=20,spatial_adapt=4)
    problem.solve_eigenproblem(1,azimuthal_m=m,shift=lambd,target=lambd)
    problem.refine_eigenfunction(use_startvector=True)

    # Create an animation of the eigenfunction using the RisingBubblePlotter class
    problem.create_eigendynamics_animation("eigenanim",RisingBubblePlotter(),max_amplitude=1,numperiods=4,numouts=4*25)

The final call of the method create_eigendynamics_animation() does the following: It creates a subdirectory (here eigenanim) in the output directory. It used the plotter class shipped as argument to perform plots. However, it won’t plot the base state, but it will perturb the base state by a perturbation with the eigenfunction which grows (and oscillates) over time like \(exp(\lambda t)\). We can specify the maximum amplitude, from which the initial amplitude is calculated. Note that the total amplitude is given by the amplitude of the eigenfunction times the growing amplitude. Therefore, it also depends on the way we implemented process_eigenvectors() in rising_bubble.py. We can specify the number of periods to consider. In case the eigenvalue is real, i.e. no oscillation amplitude given, this time is given by \(2\pi/|\lambda|\). For complex eigenvalues, the period is the reasonable choice \(2\pi/|\mathrm{Im}(\lambda)|\). The amount of output steps then controls the time step.

Once done, you can assemble all generated images to a movie. It is noteworthy that for azimuthal instabilities, the transform "mirror_x" will also invert the eigenperturbation on the left part of the plot in a reasonable way.

If you do not want to create a movie, but e.g. a sequence of images for a static document, consider adding fileext="pdf" to the constructor of the plotter class.