Frontiers: HFE Droplet in Water#

This example corresponds to section 3.2 in our publication. In this example we compute the acoustic radiation force (ARF) on a HFE droplet suspended in water subjected to a plane standing wave. We compare the theories from King (1934), Yosioka & Kawasima (1955), and Gor’kov (1962).

As always we start off by importing the nececassry Python modules. For this example we are going to need the osaft library, and the third party packages NumPy and Matplotlib.

18 import numpy as np
19 from matplotlib import pyplot as plt
20
21 import osaft

The next step is to define the properties for our example, these include the material properties, the properties of the acoustic field and the radius of the particle. In the osaft library we are always assuming SI-units..

The wave type is set using the osaft.WaveType enum. Currently, there are two options: osaft.WaveType.STANDING and osaft.WaveType.TRAVELLING for a plane standing wave and a plane travelling wave, respectively.

35 # --------
36 # Geometry
37 # --------
38 # Radius
39 R_0 = 1e-6  # [m]
40
41 # -----------------
42 # Properties of HFE
43 # -----------------
44 # Speed of sound
45 c_hfe = 659  # [m/s]
46 # Density
47 rho_hfe = 1_621  # [kg/m^3]
48
49 # -------------------
50 # Properties of Water
51 # -------------------
52 # Speed of sound
53 c_w = 1_498  # [m/s]
54 # Density
55 rho_w = 997  # [kg/m^3]
56
57 # --------------------------------
58 # Properties of the Acoustic Field
59 # --------------------------------
60 # Frequency
61 f = 5e6  # [Hz]
62 # Pressure
63 p_0 = 1e5  # [Pa]
64 # Wave type
65 wave_type = osaft.WaveType.STANDING
66 # Position of the particle in the field
67 position = np.pi / 4  # [rad]

Once all properties are defined we can initialize the solution classes. In this example, we use the classes osaft.king1934.ARF(), osaft.yosioka1955.ARF(), and osaft.gorkov1962.ARF().

 75 # Theory of King
 76 king = osaft.king1934.ARF(
 77     f=f,
 78     R_0=R_0,
 79     rho_s=rho_hfe,
 80     rho_f=rho_w,
 81     c_f=c_w,
 82     p_0=p_0,
 83     wave_type=wave_type,
 84     position=position,
 85 )
 86
 87 # Theory of Yosioka
 88 yosioka = osaft.yosioka1955.ARF(
 89     f=f,
 90     R_0=R_0,
 91     rho_s=rho_hfe,
 92     c_s=c_hfe,
 93     rho_f=rho_w,
 94     c_f=c_w,
 95     p_0=p_0,
 96     wave_type=wave_type,
 97     position=position,
 98 )
 99
100 # Theory of Gor'kov
101 gorkov = osaft.gorkov1962.ARF(
102     f=f,
103     R_0=R_0,
104     rho_s=rho_hfe,
105     c_s=c_hfe,
106     rho_f=rho_w,
107     c_f=c_w,
108     p_0=p_0,
109     wave_type=wave_type,
110     position=position,
111 )

First, want to evaluate the compressibility of the droplet and the fluid and the scattering coefficients \(f_1\) and \(f_2\). All these quantities are properties of the solution classes and can easily be evaluated.

121 # Compressibility
122 print(f"{yosioka.scatterer.kappa_f = :.2e}")
123 print(f"{yosioka.fluid.kappa_f = :.2e}")
124
125 # Gor'kov scattering coefficients
126 print(f"{gorkov.f_1 = :.2f}")
127 print(f"{gorkov.f_2 = :.2f}")
yosioka.scatterer.kappa_f = 1.42e-09
yosioka.fluid.kappa_f = 4.47e-10
gorkov.f_1 = -2.18
gorkov.f_2 = 0.29

Next, we want to compare the ARF from the different theories in the small particle limit. To plot the ARF we need to initialize an osaft.ARFPlot() instance. With the method add_solutions() we can add our models to the instance. With set_abscissa() we define the attribute that we want to plot the ARF against. Here we select the radius R_0. Finally, osaft.ARFPlot.plot_solutions() will generate the plot. plot_solutions() returns two Matplotlib objects, a Figure and an Axes object. These can be used to further manipulate the plot and to save it. To display the plot we need to call plt.show()

143 arf_plot = osaft.ARFPlot()
144
145 # Add solutions to be plotted
146 arf_plot.add_solutions(gorkov, yosioka, king)
147
148 # Define independent plotting variable (in this case the radius)
149 arf_plot.set_abscissa(np.linspace(1e-6, 15e-6, 300), "R_0")
150 fig, ax = arf_plot.plot_solutions()
151
152 # Setting the axis labels and the title
153 ax.set_xlabel(r"$R \, \mathrm{[m]}$")
154 ax.set_title(r"$\mathrm{(a)} \quad R \ll  \lambda$")
155
156 plt.show()
$\mathrm{(a)} \quad R \ll  \lambda$
/home/docs/checkouts/readthedocs.org/user_builds/osaft/checkouts/stable/osaft/plotting/datacontainers/arf_datacontainer.py:56: AssumptionWarning: Theory might not be valid anymore!
  self._arf = self._compute_arf_single_process(attr_name, values)

Note

It is only possible to plot the ARF against properties that wrap an underlying PassiveVariable, i.e. an input parameter of the model. You can get a list of all input variables using the method input_variables().

166 print(f"{gorkov.input_variables() = }")
167 print(f"{yosioka.input_variables() = }")
168 print(f"{king.input_variables() = }")
gorkov.input_variables() = ['position', 'p_0', 'wave_type', 'rho_s', 'c_s', 'rho_f', 'c_f', 'R_0', 'f']
yosioka.input_variables() = ['small_particle', 'bubble_solution', 'position', 'p_0', 'wave_type', 'rho_s', 'c_s', 'rho_f', 'c_f', 'R_0', 'f', 'N_max']
king.input_variables() = ['small_particle_limit', 'position', 'p_0', 'wave_type', 'rho_s', 'rho_f', 'c_f', 'R_0', 'f', 'N_max']

We redo our ARF plot, but this time the particle size is ranging from 1e-6 to 120e-6 meters.

174 # Plot
175 arf_plot.set_abscissa(np.linspace(1e-6, 120e-6, 300), "R_0")
176 fig, ax = arf_plot.plot_solutions()
177
178 # Additional Matplotlib commands for the publication
179 ax.set_xlabel(r"$R \, \mathrm{[m]}$")
180 ax.set_title(r"$\mathrm{(b)} \quad R \sim  \lambda$")
181 plt.show()
$\mathrm{(b)} \quad R \sim  \lambda$
/home/docs/checkouts/readthedocs.org/user_builds/osaft/checkouts/stable/osaft/plotting/datacontainers/arf_datacontainer.py:56: AssumptionWarning: Theory might not be valid anymore!
  self._arf = self._compute_arf_single_process(attr_name, values)

Lastly, we want to plot the mode shapes of the particle. We can do this using the osaft.ParticleWireframePlot() class. To plot a specific model we have to pass this model when initializing ParticleWireframePlot. We can also pass a value for the scale_factor. The displacements in the mode shape plot are exaggerated, the scale_factor is the ratio between the maximal displacement and the particle radius in the exaggerated plot.

In our example we plot the mode shape for three different radii. Again, we call plt.show() to display the plot.

196 # Creating a figure with subplots
197 fig, axes = plt.subplots(
198     1,
199     3,
200     figsize=(9, 2.5),
201     gridspec_kw={
202         "width_ratios": [1, 1, 1],
203     },
204 )
205
206 # List of radii
207 radii = [1e-6, 30e-6, 90e-6]
208
209 # We loop through the three radii and the three subplots
210 for radius, ax in zip(radii, axes):
211
212     # During each loop we change the radius in the model
213     yosioka.R_0 = radius
214
215     # We plot the wireframe plot in the respect
216     wireframe_plot = osaft.ParticleWireframePlot(yosioka, scale_factor=0.1)
217     wireframe_plot.plot(ax=ax)
218
219     # Making the plot prettier
220     um_r = int(yosioka.R_0 * 1e6)
221     ax.axis(False)
222     ax.set_aspect(1)
223     ax.set_title(rf"$R_0 = {{{um_r}}}\mathrm{{\mu m}}$")
224
225 fig.tight_layout()
226 plt.show()
$R_0 = {1}\mathrm{\mu m}$, $R_0 = {30}\mathrm{\mu m}$, $R_0 = {90}\mathrm{\mu m}$

Total running time of the script: ( 0 minutes 4.854 seconds)

Estimated memory usage: 9 MB

Gallery generated by Sphinx-Gallery