POD and fft from pointclouds
We will now proceed to explain how to perform POD from point clouds. In this instance, we test only for POD in serial, as to perform in parallel, a parallel reader/writer is needed.
If you have saved information in hdf5 and have habilitated mpi4py compilation of it, then you could use this code in parallel.
Import general modules
[1]:
# Import required modules
from mpi4py import MPI #equivalent to the use of MPI_init() in C
import matplotlib.pyplot as plt
import numpy as np
import h5py
import sys
import os
# Get mpi info
comm = MPI.COMM_WORLD
# Hide the log for the notebook. Not recommended when running in clusters as it is better you see what happens
import os
os.environ["PYSEMTOOLS_HIDE_LOG"] = 'true'
Set up the input parameters
[2]:
file_sequence = [f"../4-interpolation/interpolated_fields{str(1+i).zfill(5)}.hdf5" for i in range(0, 48)]
pod_fields = ["u", "v", "w"]
mesh_fname = "../4-interpolation/points.hdf5"
mass_matrix_fname = "../4-interpolation/points.hdf5"
mass_matrix_key = "mass"
k = len(file_sequence)
p = len(file_sequence)
fft_axis = 1 # 0 for x, 1 for y, 2 for z (Depends on how the mesh was created)
Call the pysemtools routines
[3]:
# Import the pysemtools routines
from pysemtools.rom.fft_pod_wrappers import pod_fourier_1_homogenous_direction, physical_space
# Perform the POD with your input data
pod, ioh, _3d_bm_shape, number_of_frequencies, N_samples = pod_fourier_1_homogenous_direction(comm, file_sequence, pod_fields, mass_matrix_fname, mass_matrix_key, k, p, fft_axis)
/home/adperez/software/pySEMTools/pysemtools/rom/fft_pod_wrappers.py:365: ComplexWarning: Casting complex values to real discards the imaginary part
ioh[kappa].bm1sqrt[:, :] = np.copy(ioh[kappa].xi[:, :])
Write out data
Write out modes that you specify in physical space.
[4]:
from pysemtools.rom.fft_pod_wrappers import write_3dfield_to_file
# Load the mesh
with h5py.File(mesh_fname, 'r') as f:
x = f["x"][:]
y = f["y"][:]
z = f["z"][:]
# Write out 5 modes for the first 3 wavenumbers
write_3dfield_to_file("pod.vtk", x, y, z, pod, ioh, wavenumbers=[k for k in range(0, 3)], modes=[i for i in range(0, 5)], field_shape=_3d_bm_shape, fft_axis=fft_axis, field_names=pod_fields, N_samples=N_samples)
# Reconstruct all the snapshots for the first 3 wavenumbers and 5 modes
write_3dfield_to_file("pod.vtk", x, y, z, pod, ioh, wavenumbers=[k for k in range(1, 3)], modes=[i for i in range(0, 5)], field_shape=_3d_bm_shape, fft_axis=fft_axis, field_names=pod_fields, N_samples=N_samples, snapshots=[i for i in range(0, len(file_sequence))])
Writing ./pod_kappa_0_mode0.vtk
Writing ./pod_kappa_0_mode1.vtk
Writing ./pod_kappa_0_mode2.vtk
Writing ./pod_kappa_0_mode3.vtk
Writing ./pod_kappa_0_mode4.vtk
Writing ./pod_kappa_1_mode0.vtk
Writing ./pod_kappa_1_mode1.vtk
Writing ./pod_kappa_1_mode2.vtk
Writing ./pod_kappa_1_mode3.vtk
Writing ./pod_kappa_1_mode4.vtk
Writing ./pod_kappa_2_mode0.vtk
Writing ./pod_kappa_2_mode1.vtk
Writing ./pod_kappa_2_mode2.vtk
Writing ./pod_kappa_2_mode3.vtk
Writing ./pod_kappa_2_mode4.vtk
Writing ./pod_reconstructed_data_0
Writing ./pod_reconstructed_data_1
Writing ./pod_reconstructed_data_2
Writing ./pod_reconstructed_data_3
Writing ./pod_reconstructed_data_4
Writing ./pod_reconstructed_data_5
Writing ./pod_reconstructed_data_6
Writing ./pod_reconstructed_data_7
Writing ./pod_reconstructed_data_8
Writing ./pod_reconstructed_data_9
Writing ./pod_reconstructed_data_10
Writing ./pod_reconstructed_data_11
Writing ./pod_reconstructed_data_12
Writing ./pod_reconstructed_data_13
Writing ./pod_reconstructed_data_14
Writing ./pod_reconstructed_data_15
Writing ./pod_reconstructed_data_16
Writing ./pod_reconstructed_data_17
Writing ./pod_reconstructed_data_18
Writing ./pod_reconstructed_data_19
Writing ./pod_reconstructed_data_20
Writing ./pod_reconstructed_data_21
Writing ./pod_reconstructed_data_22
Writing ./pod_reconstructed_data_23
Writing ./pod_reconstructed_data_24
Writing ./pod_reconstructed_data_25
Writing ./pod_reconstructed_data_26
Writing ./pod_reconstructed_data_27
Writing ./pod_reconstructed_data_28
Writing ./pod_reconstructed_data_29
Writing ./pod_reconstructed_data_30
Writing ./pod_reconstructed_data_31
Writing ./pod_reconstructed_data_32
Writing ./pod_reconstructed_data_33
Writing ./pod_reconstructed_data_34
Writing ./pod_reconstructed_data_35
Writing ./pod_reconstructed_data_36
Writing ./pod_reconstructed_data_37
Writing ./pod_reconstructed_data_38
Writing ./pod_reconstructed_data_39
Writing ./pod_reconstructed_data_40
Writing ./pod_reconstructed_data_41
Writing ./pod_reconstructed_data_42
Writing ./pod_reconstructed_data_43
Writing ./pod_reconstructed_data_44
Writing ./pod_reconstructed_data_45
Writing ./pod_reconstructed_data_46
Writing ./pod_reconstructed_data_47
[5]:
from pysemtools.rom.fft_pod_wrappers import save_pod_state
# Save the POD state
save_pod_state("pod_state.hdf5", pod)
Use the helper function to reconstruct the snapshots.
Here you input the results you got. For this you must specify which snapshots to reconstruct the proper keyword. Then the wavenumbers and modes in each wavenumber to be used. At the moment, the support is only to reconstruct in the same modes in all chosen wavenumbers. This can be modified later quite easily by, for example, passing a directory with modes list, just as done for POD and IOH.
[6]:
phys = physical_space(pod, ioh, wavenumbers=[k for k in range(0, number_of_frequencies)], modes=[i for i in range(0, k)], field_shape=_3d_bm_shape, fft_axis=fft_axis, field_names=pod_fields, N_samples=N_samples, snapshots=[i for i in range(0, len(file_sequence))])
First check that the reconstruction of every snapshot matches and that the energy is kept in the time coefficients, not in the modes.
[7]:
# Load the mass matrix
with h5py.File(mass_matrix_fname, 'r') as f:
bm_v = f["mass"][:]
# Go through the snapshots in the file sequence
total_snapshot_energy = 0
for j, fname in enumerate(file_sequence):
print(f"Testing snapshot {j}: {fname}")
with h5py.File(fname, 'r') as f:
# Check one snapshot at a time
# Here one could also just use the phys that has been previously computed.
phys = physical_space(pod, ioh, wavenumbers=[k for k in range(0, number_of_frequencies)], modes=[i for i in range(0, k)], field_shape=_3d_bm_shape, fft_axis=fft_axis, field_names=pod_fields, N_samples=N_samples, snapshots=[j])
# Check if the reconstruction is accurate
for field in pod_fields:
passed = np.allclose(phys[j][field], f[field][:])
print(f"Field {field} passed: {passed}")
# Check if the energy was accurately captured
snapshot_energy = 0
for field in pod_fields:
snapshot_energy += np.sum(f[field][:]**2*bm_v)
total_snapshot_energy += snapshot_energy
reconstruction_energy = 0
for kappa in range(0, number_of_frequencies):
a_i = np.diag(pod[kappa].d_1t)@pod[kappa].vt_1t[:,j]
reconstruction_energy += np.sum(np.abs(a_i)**2)
print(f"Snapshot energy: {snapshot_energy}")
print(f"Reconstruction energy: {reconstruction_energy}")
print("=======================================")
# Check if the total energy is kept in the singular values
print(f"total snapshot energy: {total_snapshot_energy}")
total_pod_energy = 0
for kappa in range(0, number_of_frequencies):
total_pod_energy += np.sum(pod[kappa].d_1t**2)
print(f"Total POD energy: {total_pod_energy}")
print("=======================================")
Testing snapshot 0: ../4-interpolation/interpolated_fields00001.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 3.698958237844183e-05
Reconstruction energy: 3.6993163022397004e-05
=======================================
Testing snapshot 1: ../4-interpolation/interpolated_fields00002.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 3.8898814924962444e-05
Reconstruction energy: 3.8902239959461035e-05
=======================================
Testing snapshot 2: ../4-interpolation/interpolated_fields00003.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 4.153454569587408e-05
Reconstruction energy: 4.153817337208489e-05
=======================================
Testing snapshot 3: ../4-interpolation/interpolated_fields00004.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 4.4425076415412405e-05
Reconstruction energy: 4.442864337674737e-05
=======================================
Testing snapshot 4: ../4-interpolation/interpolated_fields00005.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 4.688317219673442e-05
Reconstruction energy: 4.688600091533262e-05
=======================================
Testing snapshot 5: ../4-interpolation/interpolated_fields00006.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 4.878401448156997e-05
Reconstruction energy: 4.878710853476647e-05
=======================================
Testing snapshot 6: ../4-interpolation/interpolated_fields00007.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 5.026805630070726e-05
Reconstruction energy: 5.027085874214742e-05
=======================================
Testing snapshot 7: ../4-interpolation/interpolated_fields00008.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 5.149475955390006e-05
Reconstruction energy: 5.1498217100047447e-05
=======================================
Testing snapshot 8: ../4-interpolation/interpolated_fields00009.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 5.237488647324383e-05
Reconstruction energy: 5.237815402427038e-05
=======================================
Testing snapshot 9: ../4-interpolation/interpolated_fields00010.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 5.263423351722945e-05
Reconstruction energy: 5.26386214147448e-05
=======================================
Testing snapshot 10: ../4-interpolation/interpolated_fields00011.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 5.187294605439943e-05
Reconstruction energy: 5.1878309034501663e-05
=======================================
Testing snapshot 11: ../4-interpolation/interpolated_fields00012.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 4.988241310699623e-05
Reconstruction energy: 4.988923186557772e-05
=======================================
Testing snapshot 12: ../4-interpolation/interpolated_fields00013.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 4.697643854683935e-05
Reconstruction energy: 4.698326450473892e-05
=======================================
Testing snapshot 13: ../4-interpolation/interpolated_fields00014.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 4.3863242905911426e-05
Reconstruction energy: 4.386992609602263e-05
=======================================
Testing snapshot 14: ../4-interpolation/interpolated_fields00015.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 4.04654975068024e-05
Reconstruction energy: 4.0472264813275435e-05
=======================================
Testing snapshot 15: ../4-interpolation/interpolated_fields00016.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 3.708331604360593e-05
Reconstruction energy: 3.708800095581567e-05
=======================================
Testing snapshot 16: ../4-interpolation/interpolated_fields00017.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 3.361937142993228e-05
Reconstruction energy: 3.3622823972522094e-05
=======================================
Testing snapshot 17: ../4-interpolation/interpolated_fields00018.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 3.042199960394419e-05
Reconstruction energy: 3.0424717509798353e-05
=======================================
Testing snapshot 18: ../4-interpolation/interpolated_fields00019.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.764625401122964e-05
Reconstruction energy: 2.764854026761965e-05
=======================================
Testing snapshot 19: ../4-interpolation/interpolated_fields00020.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.5278143358328515e-05
Reconstruction energy: 2.528007609408604e-05
=======================================
Testing snapshot 20: ../4-interpolation/interpolated_fields00021.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.3436562845034242e-05
Reconstruction energy: 2.3438276147769336e-05
=======================================
Testing snapshot 21: ../4-interpolation/interpolated_fields00022.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.2002654602291965e-05
Reconstruction energy: 2.2004310326422838e-05
=======================================
Testing snapshot 22: ../4-interpolation/interpolated_fields00023.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.0920245682595327e-05
Reconstruction energy: 2.09217571517706e-05
=======================================
Testing snapshot 23: ../4-interpolation/interpolated_fields00024.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.013654268431107e-05
Reconstruction energy: 2.0137912485458836e-05
=======================================
Testing snapshot 24: ../4-interpolation/interpolated_fields00025.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 1.9632578477660025e-05
Reconstruction energy: 1.9633680618611167e-05
=======================================
Testing snapshot 25: ../4-interpolation/interpolated_fields00026.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 1.933656650853822e-05
Reconstruction energy: 1.93375327210833e-05
=======================================
Testing snapshot 26: ../4-interpolation/interpolated_fields00027.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 1.9193896285463495e-05
Reconstruction energy: 1.919484401965993e-05
=======================================
Testing snapshot 27: ../4-interpolation/interpolated_fields00028.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 1.9209913696544347e-05
Reconstruction energy: 1.921084152200394e-05
=======================================
Testing snapshot 28: ../4-interpolation/interpolated_fields00029.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 1.9433633251162603e-05
Reconstruction energy: 1.9434414649136665e-05
=======================================
Testing snapshot 29: ../4-interpolation/interpolated_fields00030.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 1.9843626264053833e-05
Reconstruction energy: 1.9844286776115457e-05
=======================================
Testing snapshot 30: ../4-interpolation/interpolated_fields00031.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.0264037570696985e-05
Reconstruction energy: 2.0264694456842263e-05
=======================================
Testing snapshot 31: ../4-interpolation/interpolated_fields00032.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.061492121971811e-05
Reconstruction energy: 2.061561527274048e-05
=======================================
Testing snapshot 32: ../4-interpolation/interpolated_fields00033.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.0873392702196558e-05
Reconstruction energy: 2.0874141067124846e-05
=======================================
Testing snapshot 33: ../4-interpolation/interpolated_fields00034.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.100146581923816e-05
Reconstruction energy: 2.1002249619839244e-05
=======================================
Testing snapshot 34: ../4-interpolation/interpolated_fields00035.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.1002631484979843e-05
Reconstruction energy: 2.1003356850805536e-05
=======================================
Testing snapshot 35: ../4-interpolation/interpolated_fields00036.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.0926017391762055e-05
Reconstruction energy: 2.092671514261269e-05
=======================================
Testing snapshot 36: ../4-interpolation/interpolated_fields00037.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.0846074698639117e-05
Reconstruction energy: 2.0846812180790863e-05
=======================================
Testing snapshot 37: ../4-interpolation/interpolated_fields00038.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.0866571618859654e-05
Reconstruction energy: 2.086747072367675e-05
=======================================
Testing snapshot 38: ../4-interpolation/interpolated_fields00039.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.101439294141517e-05
Reconstruction energy: 2.1015443956099017e-05
=======================================
Testing snapshot 39: ../4-interpolation/interpolated_fields00040.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.1135889588706728e-05
Reconstruction energy: 2.1137121811861234e-05
=======================================
Testing snapshot 40: ../4-interpolation/interpolated_fields00041.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.1184459915354247e-05
Reconstruction energy: 2.1185893188943514e-05
=======================================
Testing snapshot 41: ../4-interpolation/interpolated_fields00042.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.1250999040067878e-05
Reconstruction energy: 2.1252544393961218e-05
=======================================
Testing snapshot 42: ../4-interpolation/interpolated_fields00043.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.1377532850036896e-05
Reconstruction energy: 2.1378960026407462e-05
=======================================
Testing snapshot 43: ../4-interpolation/interpolated_fields00044.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.1529543422705357e-05
Reconstruction energy: 2.153077292308808e-05
=======================================
Testing snapshot 44: ../4-interpolation/interpolated_fields00045.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.161399267113895e-05
Reconstruction energy: 2.1615112232324585e-05
=======================================
Testing snapshot 45: ../4-interpolation/interpolated_fields00046.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.1637133597399283e-05
Reconstruction energy: 2.163809363808384e-05
=======================================
Testing snapshot 46: ../4-interpolation/interpolated_fields00047.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.1440817225395135e-05
Reconstruction energy: 2.1441751635941706e-05
=======================================
Testing snapshot 47: ../4-interpolation/interpolated_fields00048.hdf5
Field u passed: True
Field v passed: True
Field w passed: True
Snapshot energy: 2.0948984478946528e-05
Reconstruction energy: 2.0949807869368654e-05
=======================================
total snapshot energy: 0.001434071843040977
Total POD energy: 0.0014341827489845003
=======================================
Then check if the left and right singular vectors are indeed orthogonal with respect to the others along the wavenumbers
[8]:
from pysemtools.rom.fft_pod_wrappers import degenerate_scaling
# Check the left singular vectors
all_passed = True
for kappa in range(0, number_of_frequencies):
kappa_i = 0
kappa_j = kappa_i # These are the modes for the fourier coefficients. Thus, they orthogonals in a wave number. The fourier modes are orthogonal among fourier modes
for i in range(0, k):
for j in range(0, k):
passed = True
scaled_mode_i = pod[kappa_i].u_1t[:,i]*ioh[kappa_i].bm1sqrt[:,0]*degenerate_scaling(kappa_i)
scaled_mode_j = pod[kappa_j].u_1t[:,j]*ioh[kappa_j].bm1sqrt[:,0]*degenerate_scaling(kappa_j)
norm = np.abs(scaled_mode_i.T@scaled_mode_j)
if (j==i) and (np.allclose(norm, 1)):
passed = True
elif (j!=i) and (np.allclose(norm, 0)):
passed = True
else:
passed = False
if not passed:
print(f"Mode {i} and mode {j} in wavenumber {kappa} are not orthogonal")
print(f"Norm: {norm}")
all_passed = False
break
print(f"The modes are orthogonal: {all_passed}")
# Check the right singular vectors
all_passed = True
for kappa in range(0, number_of_frequencies):
kappa_i = 0
kappa_j = kappa_i # These are the modes for the fourier coefficients. Thus, they orthogonals in a wave number. The fourier modes are orthogonal among fourier modes
for i in range(0, k):
for j in range(0, k):
passed = True
scaled_mode_i = pod[kappa_i].vt_1t[i,:]
scaled_mode_j = pod[kappa_j].vt_1t[j,:]
norm = np.abs(scaled_mode_i.T@scaled_mode_j)
if (j==i) and (np.allclose(norm, 1)):
passed = True
elif (j!=i) and (np.allclose(norm, 0)):
passed = True
else:
passed = False
if not passed:
print(f"Right singular vector {i} and right singular vector {j} in wavenumber {kappa} are not orthogonal")
print(f"Norm: {norm}")
all_passed = False
break
print(f"The right singular vectors are orthogonal: {all_passed}")
The modes are orthogonal: True
The right singular vectors are orthogonal: True
We have already written the data to vtk in previous steps. This means that you can readily use paraview or visit, for example.
However one can also plot the data in python. For this we use the pyvista module.
First we can get a dictionary with the reconstruction of the snapshots and also the modes in physical space.
[9]:
phys = physical_space(pod, ioh, wavenumbers=[k for k in range(0, number_of_frequencies)], modes=[i for i in range(0, k)], field_shape=_3d_bm_shape, fft_axis=fft_axis, field_names=pod_fields, N_samples=N_samples, snapshots=[i for i in range(0, len(file_sequence))])
phys_modes = physical_space(pod, ioh, wavenumbers=[k for k in range(0, number_of_frequencies)], modes=[i for i in range(0, k)], field_shape=_3d_bm_shape, fft_axis=fft_axis, field_names=pod_fields, N_samples=N_samples)
Then we can start plotting!
[11]:
import pyvista as pv
# Input parameters
kappa = 1
mode = 0
fields = ["u","v","w"]
isosurfaces = np.array([-8, 8])
# Create a structured mesh
mesh_1 = pv.StructuredGrid(x, y, z)
mesh_2 = pv.StructuredGrid(x, y, z)
# Add the field to the mesh
for field in fields:
values = phys_modes[kappa][mode][field]
mesh_1.point_data[field] = values.ravel(order='F')
values2 = phys_modes[kappa+1][mode][field]
mesh_2.point_data[field] = values2.ravel(order='F')
# Plot
pl = pv.Plotter(shape=(2, 3), window_size=[1920,1080]) # Size in pixels
pl.add_axes()
for i, field in enumerate(fields):
# Plot first row
pl.subplot(0, i)
# Obtain the isosurfaces
isos = mesh_1.contour(scalars = field, isosurfaces = isosurfaces)
pl.add_mesh(mesh_1.outline(), color="k")
pl.add_mesh(isos, opacity=1, cmap="coolwarm", scalar_bar_args={'title': f""})
# Change the settings a bit
pl.add_text(f"{field}: wavenumber {kappa} mode {mode}", font = "courier", font_size=10, position="upper_left")
# Plot second row
pl.subplot(1, i)
# Obtain the isosurfaces
isos = mesh_2.contour(scalars = field, isosurfaces = isosurfaces)
pl.add_mesh(mesh_2.outline(), color="k")
pl.add_mesh(isos, opacity=1, cmap="coolwarm", scalar_bar_args={'title': f""})
# Change the settings a bit
pl.add_text(f"{field}: wavenumber {kappa+1} mode {mode}", font = "courier", font_size=10, position="upper_left")
# Capture the plot as an image and show it (This is just to make the notebook render better on github)
from IPython.display import Image, display
image_path = "static_plot.png"
pl.screenshot(image_path)
pl.close()
display(Image(filename=image_path))
#pl.show()
