Visualization of spin-systems in QDYN

The nlevel_spin.f90 module offers a variety of tools for visualizing N-level spin states. Among these, you can visualize your state via the Wigner-spin function or the Husimi-Q-function. But it is also possible to trace your spin-coherent states over time.

As an example, we demonstrate these visualization tools on a example system and give some ideas on how to present the results in this tutorial.

First, we will show how to visualize spin-systems in QDYN via the spin-wigner function. As model system we will choose the Bose-Hubbard model from Kallush et al 2014 New J. Phys. 16 015008, (eq. (34)):

\begin{equation} \hat{H} = -2\Delta\hat{J}_x + U\hat{J}^2_z + 2u(t)\hat{J}_z, \end{equation}

where \(\Delta\) and \(U\) are postive parameters, and u(t) is the control pulse.

Note: We implement but don’t use the control pulse in this example! Feel free to play around with it!

In the following we will first set up the script.

[1]:
import copy
from pathlib import Path

import numpy as np
import qutip
import matplotlib.pyplot as plt
import colorsys
from mpl_toolkits.mplot3d import Axes3D

import qdyn.model
import qdyn.pulse
!make clean
[2]:
j=2*7+1

Implementing the model

First, we define a function which sets the Hamiltonian

[3]:
def get_Ham(
    j=2, delta=15, U=None  # use default value from paper
):
    if U is None:
        U = 2.0 * delta / j
    u = lambda t, args: 0

    Ham_0 = -2.0 * delta * qutip.operators.spin_Jx(j) + U * (
        qutip.operators.spin_Jz(j) ** 2.0
    )
    Ham_1 = 2.0 * qutip.operators.spin_Jz(j)
    return [Ham_0, [Ham_1, np.vectorize(u)]]

Then, we define a function which writes out all the necessary data to the runfolder which we choose to be “rf” as default

[4]:
def qdyn_model(
    Ham,
    qdyn_tlist,
    psi0,
    results_folder,
    print_time_needed = True,
    picture_dims=[500,250], # default in the program
    runfolder="rf",
    prop_method="cheby",
    **user_kwargs,
):
    """ Create qdyn-model

    """
    dt = (qdyn_tlist[0]) / (qdyn_tlist[1] - 1)
    tgrid = np.linspace(
        float(dt / 2),
        float(qdyn_tlist[0] - dt / 2),
        qdyn_tlist[1] - 1,
        dtype=np.float64,
    )
    model = qdyn.model.LevelModel()
    for H in Ham:
        if isinstance(H, list):
            model.add_ham(
                H[0],
                pulse=qdyn.pulse.Pulse(
                    tgrid,
                    amplitude=H[1](tgrid, None),
                    time_unit="iu",
                    ampl_unit="iu",
                    config_attribs={
                        'oct_shape': 'const',
                    },
                ),
                op_unit="iu",
            )
        else:
            model.add_ham(H, op_unit="iu")

    model.set_propagation(
        qdyn_tlist[0], qdyn_tlist[1], time_unit="iu", prop_method=prop_method
    )


    model.add_state(psi0, 'initial')
    user_variables = {}
    user_variables["phi_pixels"] = picture_dims[0]
    user_variables["theta_pixels"] = picture_dims[1]
    user_variables["results_folder"] = str(Path(runfolder)/results_folder)
    user_variables["print_time_needed"] = print_time_needed
    user_variables.update(user_kwargs)

    model.user_data = user_variables
    model.write_to_runfolder(str(runfolder))

    Path(user_variables["results_folder"]).mkdir(exist_ok=True)

Trajectory on the Bloch sphere

Set up everything

For the propagation we use a spin-coherent state at the north pole, \(\theta=0\), \(\phi=0\)

[5]:
psi0 = qutip.states.spin_coherent(j, 0, 0)

The tempral grid for qdyn is given as qdyn_tlist, which is a tuple (T, Nt). We will then propagate on a grid from 0 to T, with Nt timesteps

[6]:
qdyn_tlist = ( .1 , 100 ) #= ( T , Nt )

And finally we set up the model by using the routine above. We use a Hamiltonian without the squeezing term, i.e. U = 0.

[7]:
results_folder = Path("results_btraj")
[8]:
H = get_Ham(j,U=0)
qdyn_model(
    H, qdyn_tlist, psi0,
    results_folder=results_folder,
    plot_qfct = False,
    plot_wigner = False
)

Run the script

[9]:
!make
ifort -O2 -openmp -vec-report-0 -par-report-0 -openmp-report-0 -mkl=sequential -I`pwd` -I../../../../ -I/home/users/0000/uk060352/local/include  -L../../../../ -L/home/users/0000/uk060352/local/lib  -c -o prop_spin_sys.o prop_spin_sys.f90
ifort -O2 -openmp -vec-report-0 -par-report-0 -openmp-report-0 -mkl=sequential -I`pwd` -I../../../../ -I/home/users/0000/uk060352/local/include  -L../../../../ -L/home/users/0000/uk060352/local/lib  -o prop_spin_sys prop_spin_sys.o -lqdyn -ldfftpack -llbfgsb -larpack -lwigxjpf -lfastwigxj
[10]:
!./prop_spin_sys
*** Read config file rf/config ***
*** Done reading config file ***
*** Initializing system ***
  *** Initializing grid ***
  No explicit grid found in config file! Initializing grid as one dimensional 1x1 fake grid
    Initializing grid as 1D cartesian grid without mapping
      Number of grid points was set to nr = 1 for dimension dim = 1! Initializing dimension 1 as a 1x1 fake-grid...
  *** Initializing pulses ***
    1 pulses in config file
    Initializing pulse 1
      setting pulse shape as constant   1.00 in [   0.000E+00,   1.000E-01]
  *** Initializing dynamical generator ***
*** Done with initialization ***

 Obtaining the expectation values in the Bloch sphere:   1.553392410278320E-002
 s

Plot data in a graph

First, we plot the expectation values in a simple graph. Here, we see the temporal evolution of the expectation values \(\langle j_i \rangle\) for \(i=x,y,x\), and the spherical coordinated \(r\),\(\theta\) and \(\phi\). Note that the description of a n-level system by means of it’s expected position on the Bloch sphere is only meaningful, if the state is (close to) a spin-coherent state. The variable ovlp shows the overlap between the propagated state and the closest SCS which is, in this example, \(1\). That means that we follow the dynamics of a SCS on the surface of a generalised Bloch sphere.

[11]:
def plot_exp_values(dat_path, plot_path, plot=True):
    results_dat = sorted(dat_path.iterdir())
    r = np.loadtxt(results_dat[0])

    fig, ax = plt.subplots()
    leg = ['jx','jy','jz','r','theta','phi','ovlp']
    for i in range(1,len(r[0,:])):
        ax.plot(r[:,0],r[:,i],label=leg[i-1])
    ax.legend(ncol=7,mode="expand")

    ax.set_xlabel("ti")
    Path(plot_path).mkdir(parents=True, exist_ok=True)
    plt.savefig(Path(plot_path)/"bloch_exp_values.png", dpi=200)

    if plot:
        plt.show()
    plt.close(fig)

plot_exp_values("rf" / results_folder, "pictures")
../../_images/examples_visualizing_spin_systems_visualizing_spin_systems_in_qdyn_25_0.png

The data is easier to understand if we look at the dynamics on the Bloch sphere. The blue dots show the trajectory of the center of a SCS on the Bloch sphere.

[12]:
def plot_bloch_traj(dat_path, plot_path, plot=True):
    results_dat = sorted(dat_path.iterdir())
    r = np.loadtxt(results_dat[0])

    b = qutip.Bloch()
    b.view = [60,210]
    b.add_vectors([r[0,1],r[0,2],r[0,3]]) # initial state, green
    b.add_vectors([r[-1,1],r[-1,2],r[-1,3]]) # final state, orange
    b.add_points([r[:,1],r[:,2],r[:,3]])
    b.show()
    Path(plot_path).mkdir(parents=True, exist_ok=True)
    plt.savefig(Path(plot_path)/"bloch_traj.png", dpi=200)

plot_bloch_traj("rf" / results_folder, "pictures")
../../_images/examples_visualizing_spin_systems_visualizing_spin_systems_in_qdyn_27_0.png

Note: This cellfails for some versions of qutip and matplotlib. You can solve this by updating both (for example via pip install qutip matplotlib --upgrade).

Spin-Wigner and Q-function

If the state is not (close to) a SCS, the mean position of the state on the generalised Bloch sphere is not sufficient anymore and we move on to two more suitable visualisations: the Wigner function and the Q-function.

Set up everything

For the propagation we use a spin-coherent state at \(\theta=\pi/2\), \(\phi=\pi\)

[13]:
psi0 = qutip.states.spin_coherent(j, np.pi/2, np.pi)

The tempral grid for qdyn is given as qdyn_tlist, which is a tuple (T, Nt). We will then propagate on a grid from 0 to T, with Nt timesteps

[14]:
qdyn_tlist = ( .1 , 10 ) #= ( T , Nt )

And finally we set up the model by using the routine above. We use the default values for the Hamiltonian, i.e. the one with the squeezing term \(U\).

[15]:
results_folder = Path("results_qfct_wigner")
N_theta = 150
N_phi = 75
[16]:
H = get_Ham(j)
qdyn_model(
    H, qdyn_tlist, psi0,
    results_folder=results_folder,
    picture_dims = (N_theta, N_phi),
    exp_bloch = False
)

Run the script

[17]:
!make
make: 'prop_spin_sys' is up to date.
[18]:
!./prop_spin_sys
*** Read config file rf/config ***
*** Done reading config file ***
*** Initializing system ***
  *** Initializing grid ***
  No explicit grid found in config file! Initializing grid as one dimensional 1x1 fake grid
    Initializing grid as 1D cartesian grid without mapping
      Number of grid points was set to nr = 1 for dimension dim = 1! Initializing dimension 1 as a 1x1 fake-grid...
  *** Initializing pulses ***
    1 pulses in config file
    Initializing pulse 1
      setting pulse shape as constant   1.00 in [   0.000E+00,   1.000E-01]
  *** Initializing dynamical generator ***
*** Done with initialization ***

Initialising wigner symbols on 32 threads:
 Time needed for wigner  5.894494056701660E-002
 Time needed for wigner  3.347587585449219E-002
 Time needed for wigner  2.896595001220703E-002
 Time needed for wigner  2.896595001220703E-002
 Time needed for wigner  1.561212539672852E-002
 Time needed for wigner  1.571798324584961E-002
 Time needed for wigner  1.569819450378418E-002
 Time needed for wigner  1.557993888854980E-002
 Time needed for wigner  1.560711860656738E-002
 Time needed for wigner  1.557397842407227E-002
 Calculating and writing the spin-wigner function took:   0.274631977081299
 s
 Time needed for q-fct  0.153646945953369
 Time needed for q-fct  0.154102802276611
 Time needed for q-fct  0.153930902481079
 Time needed for q-fct  0.153733015060425
 Time needed for q-fct  0.153908014297485
 Time needed for q-fct  0.153897047042847
 Time needed for q-fct  0.153969049453735
 Time needed for q-fct  0.154065847396851
 Time needed for q-fct  0.189017772674561
 Time needed for q-fct  0.195749044418335
 Calculating and writing the q-function took:    1.63815498352051      s

Load data

First of all, we set a variable for the results folder, which we set earlier

[19]:
res_folder = "rf" / results_folder
results_dat = sorted(res_folder.iterdir())

The resulting data can now be loaded from the files by using numpy’s loadtxt function …

[20]:
r = np.loadtxt(results_dat[0])

… and plotted:

[21]:
fig, ax = plt.subplots()
ax.pcolormesh(r)
ax.axes.set_aspect('equal')
../../_images/examples_visualizing_spin_systems_visualizing_spin_systems_in_qdyn_48_0.png

Plotting everything

We will now load all the saved files and plot them. To save some work, we will first write a function, that first loads all the data and then plots it:

[22]:
def plot_surface(dat_path, plot_path, plot_inline=True):
    results_dat = sorted(dat_path.iterdir())
    results = []
    for dat_file in results_dat:
        results.append(np.loadtxt(dat_file))

    # get the number of files, the first half of them are the Q-functions and the other half the Wigner functions
    num_values = len(results)
    mid = int(num_values/2)-1

    # get the maximum value of all results for proper scaling
    # (it's a different one for the Q-function and the Wigner function)
    max_values = [np.amax(abs(np.array(results[0:mid]))),\
                  np.amax(abs(np.array(results)[mid+1,:]))]

    plot_path = Path(plot_path)
    if not plot_path.exists():
        plot_path.mkdir()

    for idx, res in enumerate(results):
        if idx <= mid:
            mode = 0
            idy = idx # index of the plot, starting from 0
            filename = "qfct_"+f"{idy:0>5}.png"
        else:
            mode = 1
            idy = idx - mid - 1 # index of the plot, starting from 0
            filename = "wigner_"+f"{idy:0>5}.png"
        fig, ax = plt.subplots()
        phi, theta = np.meshgrid(np.linspace(0,2*np.pi,res.shape[1]),np.linspace(0,1*np.pi,res.shape[0]))
        ax.pcolormesh(phi, theta, res, vmin = -max_values[mode], vmax = max_values[mode], cmap="bwr")
        ax.set_xlabel(r"$\phi$", usetex=True)
        ax.set_ylabel(r"$\theta$", usetex=True)
        ax.axes.set_aspect('equal')
        plt.savefig(Path(plot_path)/filename, dpi=200)
        if plot_inline:
            print(Path(plot_path)/filename)
            plt.show()
        plt.close(fig)


[23]:
%%capture
# `%%capture` suppresses the output and can be removed while playing around ;-)
plot_surface("rf" / results_folder, "pictures", plot_inline=True)

Plotting on a sphere

Instead of plotting a 2D plot, we can also visualise the state on a 3D sphere:

[24]:
def plot_sphere(dat_path, plot_path, plot_inline=True, plot_ids = []):
    results_dat = sorted(dat_path.iterdir())
    results = []
    for dat_file in results_dat:
        results.append(np.loadtxt(dat_file))

    # get the number of files, half of them are the Q-function and half the Wigner function
    num_values = len(results)
    mid = int(num_values/2)-1

    # get the maximum value of all results for proper scaling
    # (it's a different one for the Q-function and the Wigner function)
    max_values = [np.amax(abs(np.array(results[0:mid]))),\
                  np.amax(abs(np.array(results)[mid+1,:]))]

    plot_path = Path(plot_path)
    if not plot_path.exists():
        plot_path.mkdir()

    for idx, res in enumerate(results):
        # If plot_id is given, we only plot the file with index `plot_id`
        if plot_ids:
            if (idx not in plot_ids):
                continue

        if idx <= mid:
            # Q-function
            mode = 0
            idy = idx # index of the plot, starting from 0
            filename = "sph_qfct_"+f"{idy:0>5}.png"
            # normalise the Q-function to [0,1] using `scale`
            scale = max_values[mode] # because the values go from 0 to max_value
            shift = 0
            mycmap = copy.copy(plt.get_cmap("jet")) #non-divergent colormap
        else:
            # Wigner
            mode = 1
            idy = idx - mid - 1 # index of the plot, starting from 0
            filename = "sph_wigner_"+f"{idy:0>5}.png"
            # normalise the Wigner function to [0,1] using `scale` and `shift`
            scale = 2*max_values[mode]
            shift = 1/2
            mycmap = copy.copy(plt.get_cmap("coolwarm")) #divergent colormap

        fig = plt.figure(figsize=(5,5))
        ax = fig.add_subplot(111,projection="3d")

        phi = np.linspace(0,2*np.pi,res.shape[1])
        theta = np.linspace(0,1*np.pi,res.shape[0])
        n_phi = len(phi)
        n_theta = len(theta)

        # In order to draw gridlines, we add a colour below the current colormap
        mycmap.set_under('k')
        # draw a grid line every `ph_gs`/`th_gs` steps
        ph_gs = int(2*np.pi/6/(phi[2]-phi[1]))+1 # 60 degree
        th_gs = int(np.pi/6/(theta[2]-theta[1]))+1 # 30 degree

        x = np.outer(np.cos(phi), np.sin(theta))
        y = np.outer(np.sin(phi), np.sin(theta))
        z = np.outer(np.ones(np.size(phi)), np.cos(theta))

        ax.set_axis_off()
        ax.view_init(0, 180) # theta, phi

        inp = []
        for j in range(0, n_phi):
            for i in range(0, n_theta):
                val = res[i,j] / scale + shift
                # if theta and phi are on the gridlines, we set the value to -1
                # such that we draw the dark color of the grid lines,
                # but only if the value of the function is very small.
                # Like that, the grid lines will be underneath the actual plot.
                if ((j%ph_gs) < 0.01 and abs(val-shift) < 1E-1):
                    val = -1
                if ((i%th_gs) < 0.01 and abs(val-shift) < 1E-1):
                    val = -1
                inp.append([j, i, val])

        inp = np.array(inp)
        c = inp[:, 2].reshape((n_phi, n_theta))
        ax.plot_surface(x, y, z, rstride=1, cstride=1,
          cmap=mycmap, facecolors=mycmap(c), alpha=1, linewidth=0.1, antialiased=False, vmax=1, vmin=0
        )

        plt.savefig(Path(plot_path)/filename, dpi=200)
        if plot_inline:
            print(Path(plot_path)/filename)
            plt.show()
        plt.close(fig)
[25]:
plot_sphere("rf" / results_folder, "pictures", plot_ids=[0,9,10,19], plot_inline=False)

Video (2D)

In the end, we will create a video of the dynamics. For this we will reuse most of the functions from above. First of all, we increase the number of timesteps:

[26]:
qdyn_tlist = ( .24 , 240 ) #= ( T , Nt )

We also change the folder where to save the files and decrease the resolution a little (feel free play whith this)

[27]:
results_folder = Path("results_video")
N_theta = 300
N_phi = 150

… and finally set up the model and run the code:

[28]:
qdyn_model(
    H, qdyn_tlist, psi0,
    results_folder = results_folder,
    print_time_needed = False,
    picture_dims = (N_theta, N_phi),
    exp_bloch = False
)
[29]:
!./prop_spin_sys
*** Read config file rf/config ***
*** Done reading config file ***
*** Initializing system ***
  *** Initializing grid ***
  No explicit grid found in config file! Initializing grid as one dimensional 1x1 fake grid
    Initializing grid as 1D cartesian grid without mapping
      Number of grid points was set to nr = 1 for dimension dim = 1! Initializing dimension 1 as a 1x1 fake-grid...
  *** Initializing pulses ***
    1 pulses in config file
    Initializing pulse 1
      setting pulse shape as constant   1.00 in [   0.000E+00,   2.400E-01]
  *** Initializing dynamical generator ***
*** Done with initialization ***

Initialising wigner symbols on 32 threads:
 Calculating and writing the spin-wigner function took:    18.9903299808502
 s
 Calculating and writing the q-function took:    189.470355033875      s

Using the plot routine above, we plot the new results into another folder:

[30]:
%%capture
# `%%capture` suppresses the output and can be removed while playing around ;-)
plot_surface("rf" / results_folder, "pictures_video", plot_inline=False)

Compiling the video

Finally, we use ffmpeg to compile all plots into the videos qfct.mp4 and wigner.mp4, both located in the folder pictures_video.

[31]:
!ffmpeg -framerate 16 -i "pictures_video/qfct_%05d.png" -c:v libx264 -y pictures_video/qfct.mp4
ffmpeg version 3.4.6-0ubuntu0.18.04.1 Copyright (c) 2000-2019 the FFmpeg developers
  built with gcc 7 (Ubuntu 7.3.0-16ubuntu3)
  configuration: --prefix=/usr --extra-version=0ubuntu0.18.04.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librubberband --enable-librsvg --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264 --enable-shared
  libavutil      55. 78.100 / 55. 78.100
  libavcodec     57.107.100 / 57.107.100
  libavformat    57. 83.100 / 57. 83.100
  libavdevice    57. 10.100 / 57. 10.100
  libavfilter     6.107.100 /  6.107.100
  libavresample   3.  7.  0 /  3.  7.  0
  libswscale      4.  8.100 /  4.  8.100
  libswresample   2.  9.100 /  2.  9.100
  libpostproc    54.  7.100 / 54.  7.100
Input #0, image2, from 'pictures_video/qfct_%05d.png':
  Duration: 00:00:15.00, start: 0.000000, bitrate: N/A
    Stream #0:0: Video: png, rgba(pc), 1200x800 [SAR 7874:7874 DAR 3:2], 16 fps, 16 tbr, 16 tbn, 16 tbc
Stream mapping:
  Stream #0:0 -> #0:0 (png (native) -> h264 (libx264))
Press [q] to stop, [?] for help
[libx264 @ 0x55992192ee00] using SAR=1/1
[libx264 @ 0x55992192ee00] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX
[libx264 @ 0x55992192ee00] profile High 4:4:4 Predictive, level 3.2, 4:4:4 8-bit
[libx264 @ 0x55992192ee00] 264 - core 152 r2854 e9a5903 - H.264/MPEG-4 AVC codec - Copyleft 2003-2017 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x1:0x111 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=0 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=4 threads=25 lookahead_threads=4 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=16 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
Output #0, mp4, to 'pictures_video/qfct.mp4':
  Metadata:
    encoder         : Lavf57.83.100
    Stream #0:0: Video: h264 (libx264) (avc1 / 0x31637661), yuv444p, 1200x800 [SAR 1:1 DAR 3:2], q=-1--1, 16 fps, 16384 tbn, 16 tbc
    Metadata:
      encoder         : Lavc57.107.100 libx264
    Side data:
      cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1
frame=  240 fps=121 q=-1.0 Lsize=     178kB time=00:00:14.81 bitrate=  98.3kbits/s speed=7.49x
video:174kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 2.089669%
[libx264 @ 0x55992192ee00] frame I:1     Avg QP: 8.84  size:  5883
[libx264 @ 0x55992192ee00] frame P:60    Avg QP:12.97  size:  1361
[libx264 @ 0x55992192ee00] frame B:179   Avg QP:14.13  size:   503
[libx264 @ 0x55992192ee00] consecutive B-frames:  0.4%  0.0%  1.2% 98.3%
[libx264 @ 0x55992192ee00] mb I  I16..4: 96.7%  0.0%  3.3%
[libx264 @ 0x55992192ee00] mb P  I16..4:  5.5%  0.0%  0.1%  P16..4:  8.9%  1.8%  0.2%  0.0%  0.0%    skip:83.6%
[libx264 @ 0x55992192ee00] mb B  I16..4:  0.3%  0.0%  0.0%  B16..8:  8.9%  0.5%  0.0%  direct: 0.0%  skip:90.2%  L0:42.6% L1:56.7% BI: 0.8%
[libx264 @ 0x55992192ee00] coded y,u,v intra: 0.8% 0.0% 0.1% inter: 0.0% 0.0% 0.0%
[libx264 @ 0x55992192ee00] i16 v,h,dc,p: 38% 46%  5% 11%
[libx264 @ 0x55992192ee00] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 30% 29% 32%  1%  2%  2%  2%  1%  1%
[libx264 @ 0x55992192ee00] Weighted P-Frames: Y:0.0% UV:0.0%
[libx264 @ 0x55992192ee00] ref P L0: 64.1%  1.7% 18.2% 16.0%
[libx264 @ 0x55992192ee00] ref B L0: 89.0%  9.6%  1.5%
[libx264 @ 0x55992192ee00] ref B L1: 95.8%  4.2%
[libx264 @ 0x55992192ee00] kb/s:94.68
[32]:
!ffmpeg -framerate 16 -i "pictures_video/wigner_%05d.png" -c:v libx264 -y pictures_video/wigner.mp4
ffmpeg version 3.4.6-0ubuntu0.18.04.1 Copyright (c) 2000-2019 the FFmpeg developers
  built with gcc 7 (Ubuntu 7.3.0-16ubuntu3)
  configuration: --prefix=/usr --extra-version=0ubuntu0.18.04.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librubberband --enable-librsvg --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264 --enable-shared
  libavutil      55. 78.100 / 55. 78.100
  libavcodec     57.107.100 / 57.107.100
  libavformat    57. 83.100 / 57. 83.100
  libavdevice    57. 10.100 / 57. 10.100
  libavfilter     6.107.100 /  6.107.100
  libavresample   3.  7.  0 /  3.  7.  0
  libswscale      4.  8.100 /  4.  8.100
  libswresample   2.  9.100 /  2.  9.100
  libpostproc    54.  7.100 / 54.  7.100
Input #0, image2, from 'pictures_video/wigner_%05d.png':
  Duration: 00:00:15.00, start: 0.000000, bitrate: N/A
    Stream #0:0: Video: png, rgba(pc), 1200x800 [SAR 7874:7874 DAR 3:2], 16 fps, 16 tbr, 16 tbn, 16 tbc
Stream mapping:
  Stream #0:0 -> #0:0 (png (native) -> h264 (libx264))
Press [q] to stop, [?] for help
[libx264 @ 0x55a9600b5e00] using SAR=1/1
[libx264 @ 0x55a9600b5e00] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX
[libx264 @ 0x55a9600b5e00] profile High 4:4:4 Predictive, level 3.2, 4:4:4 8-bit
[libx264 @ 0x55a9600b5e00] 264 - core 152 r2854 e9a5903 - H.264/MPEG-4 AVC codec - Copyleft 2003-2017 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x1:0x111 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=0 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=4 threads=25 lookahead_threads=4 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=16 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
Output #0, mp4, to 'pictures_video/wigner.mp4':
  Metadata:
    encoder         : Lavf57.83.100
    Stream #0:0: Video: h264 (libx264) (avc1 / 0x31637661), yuv444p, 1200x800 [SAR 1:1 DAR 3:2], q=-1--1, 16 fps, 16384 tbn, 16 tbc
    Metadata:
      encoder         : Lavc57.107.100 libx264
    Side data:
      cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1
frame=  240 fps=120 q=-1.0 Lsize=     275kB time=00:00:14.81 bitrate= 152.3kbits/s speed= 7.4x
video:272kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 1.338302%
[libx264 @ 0x55a9600b5e00] frame I:1     Avg QP: 8.50  size:  5648
[libx264 @ 0x55a9600b5e00] frame P:60    Avg QP:14.16  size:  3430
[libx264 @ 0x55a9600b5e00] frame B:179   Avg QP:13.05  size:   369
[libx264 @ 0x55a9600b5e00] consecutive B-frames:  0.4%  0.0%  1.2% 98.3%
[libx264 @ 0x55a9600b5e00] mb I  I16..4: 96.4%  0.0%  3.6%
[libx264 @ 0x55a9600b5e00] mb P  I16..4:  4.2%  0.0%  0.5%  P16..4:  9.9%  4.5%  1.3%  0.0%  0.0%    skip:79.6%
[libx264 @ 0x55a9600b5e00] mb B  I16..4:  0.1%  0.0%  0.0%  B16..8:  8.3%  0.2%  0.0%  direct: 0.0%  skip:91.4%  L0:32.8% L1:66.1% BI: 1.1%
[libx264 @ 0x55a9600b5e00] coded y,u,v intra: 6.9% 2.1% 2.1% inter: 0.8% 0.2% 0.2%
[libx264 @ 0x55a9600b5e00] i16 v,h,dc,p: 52% 36%  5%  7%
[libx264 @ 0x55a9600b5e00] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 58% 14% 18%  2%  2%  2%  1%  2%  1%
[libx264 @ 0x55a9600b5e00] Weighted P-Frames: Y:0.0% UV:0.0%
[libx264 @ 0x55a9600b5e00] ref P L0: 63.9%  9.9% 16.0% 10.2%
[libx264 @ 0x55a9600b5e00] ref B L0: 89.1%  9.7%  1.2%
[libx264 @ 0x55a9600b5e00] ref B L1: 98.1%  1.9%
[libx264 @ 0x55a9600b5e00] kb/s:148.04