photosurfactant 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- photosurfactant/__init__.py +1 -0
- photosurfactant/fourier.py +47 -0
- photosurfactant/intensity_functions.py +32 -0
- photosurfactant/parameters.py +219 -0
- photosurfactant/py.typed +0 -0
- photosurfactant/scripts/__init__.py +0 -0
- photosurfactant/scripts/plot_all.sh +19 -0
- photosurfactant/scripts/plot_error.py +75 -0
- photosurfactant/scripts/plot_first_order.py +506 -0
- photosurfactant/scripts/plot_leading_order.py +288 -0
- photosurfactant/scripts/plot_spectrum.py +146 -0
- photosurfactant/scripts/plot_sweep.py +234 -0
- photosurfactant/semi_analytic/__init__.py +3 -0
- photosurfactant/semi_analytic/first_order.py +540 -0
- photosurfactant/semi_analytic/leading_order.py +237 -0
- photosurfactant/semi_analytic/limits.py +240 -0
- photosurfactant/semi_analytic/utils.py +43 -0
- photosurfactant/utils/__init__.py +0 -0
- photosurfactant/utils/arg_parser.py +162 -0
- photosurfactant/utils/func_parser.py +10 -0
- photosurfactant-1.0.0.dist-info/METADATA +25 -0
- photosurfactant-1.0.0.dist-info/RECORD +24 -0
- photosurfactant-1.0.0.dist-info/WHEEL +4 -0
- photosurfactant-1.0.0.dist-info/entry_points.txt +6 -0
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
#! /usr/bin/env python
|
|
2
|
+
from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
from matplotlib import colors
|
|
6
|
+
|
|
7
|
+
from photosurfactant.fourier import convolution_coeff, fourier_series_coeff
|
|
8
|
+
from photosurfactant.intensity_functions import * # noqa: F401, F403
|
|
9
|
+
from photosurfactant.intensity_functions import mollifier
|
|
10
|
+
from photosurfactant.parameters import Parameters, PlottingParameters
|
|
11
|
+
from photosurfactant.semi_analytic.first_order import FirstOrder, Variables
|
|
12
|
+
from photosurfactant.semi_analytic.leading_order import LeadingOrder
|
|
13
|
+
from photosurfactant.utils.arg_parser import (
|
|
14
|
+
first_order_parser,
|
|
15
|
+
leading_order_parser,
|
|
16
|
+
parameter_parser,
|
|
17
|
+
plot_parser,
|
|
18
|
+
)
|
|
19
|
+
from photosurfactant.utils.func_parser import parse_func
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Figures:
|
|
23
|
+
"""Figures for the first order problem."""
|
|
24
|
+
|
|
25
|
+
def __init__(self, first: FirstOrder, plot_params: PlottingParameters):
|
|
26
|
+
"""Initialize the figures class."""
|
|
27
|
+
self.first = first
|
|
28
|
+
self.plot_params = plot_params
|
|
29
|
+
|
|
30
|
+
self.params = first.params
|
|
31
|
+
self.leading = first.leading
|
|
32
|
+
|
|
33
|
+
self.plt = plot_params.plt
|
|
34
|
+
|
|
35
|
+
self._initialize()
|
|
36
|
+
|
|
37
|
+
def _initialize(self):
|
|
38
|
+
self.xx = np.linspace(
|
|
39
|
+
-self.first.params.L, self.first.params.L, self.plot_params.grid_size
|
|
40
|
+
)
|
|
41
|
+
self.yy = np.linspace(0, 1, self.plot_params.grid_size)
|
|
42
|
+
|
|
43
|
+
self.ggamma_tr = self.first.Gamma_tr(self.xx)
|
|
44
|
+
self.ggamma_ci = self.first.Gamma_ci(self.xx)
|
|
45
|
+
self.ttension = (
|
|
46
|
+
-self.params.Ma
|
|
47
|
+
* (self.ggamma_tr + self.ggamma_ci)
|
|
48
|
+
/ (1 - self.leading.Gamma_tr - self.leading.Gamma_ci)
|
|
49
|
+
)
|
|
50
|
+
self.JJ_tr = self.first.J_tr(self.xx)
|
|
51
|
+
self.JJ_ci = self.first.J_ci(self.xx)
|
|
52
|
+
self.SS = self.first.S(self.xx)
|
|
53
|
+
self.ff = self.first.f(self.xx)
|
|
54
|
+
|
|
55
|
+
self.psii = np.array([self.first.psi(self.xx, y) for y in self.yy])
|
|
56
|
+
self.ppressure = np.array([self.first.p(self.xx, y) for y in self.yy])
|
|
57
|
+
self.uu = np.array([self.first.u(self.xx, y) for y in self.yy])
|
|
58
|
+
self.vv = np.array([self.first.w(self.xx, y) for y in self.yy])
|
|
59
|
+
self.cc_tr = np.array([self.first.c_tr(self.xx, y) for y in self.yy])
|
|
60
|
+
self.cc_ci = np.array([self.first.c_ci(self.xx, y) for y in self.yy])
|
|
61
|
+
|
|
62
|
+
self.label = self.plot_params.label
|
|
63
|
+
self.format = self.plot_params.format
|
|
64
|
+
|
|
65
|
+
def export_data(self, path: str):
|
|
66
|
+
"""Export data to a .csv file."""
|
|
67
|
+
np.savetxt(path + "xx.csv", self.xx, delimiter=",")
|
|
68
|
+
np.savetxt(path + "yy.csv", self.yy, delimiter=",")
|
|
69
|
+
np.savetxt(path + "ggamma_tr.csv", self.ggamma_tr, delimiter=",")
|
|
70
|
+
np.savetxt(path + "ggamma_ci.csv", self.ggamma_ci, delimiter=",")
|
|
71
|
+
np.savetxt(path + "ttension.csv", self.ttension, delimiter=",")
|
|
72
|
+
np.savetxt(path + "JJ_tr.csv", self.JJ_tr, delimiter=",")
|
|
73
|
+
np.savetxt(path + "JJ_ci.csv", self.JJ_ci, delimiter=",")
|
|
74
|
+
np.savetxt(path + "SS.csv", self.SS, delimiter=",")
|
|
75
|
+
np.savetxt(path + "ff.csv", self.ff, delimiter=",")
|
|
76
|
+
np.savetxt(path + "psii.csv", self.psii, delimiter=",")
|
|
77
|
+
np.savetxt(path + "ppressure.csv", self.ppressure, delimiter=",")
|
|
78
|
+
np.savetxt(path + "uu.csv", self.uu, delimiter=",")
|
|
79
|
+
np.savetxt(path + "vv.csv", self.vv, delimiter=",")
|
|
80
|
+
np.savetxt(path + "cc_tr.csv", self.cc_tr, delimiter=",")
|
|
81
|
+
np.savetxt(path + "cc_ci.csv", self.cc_ci, delimiter=",")
|
|
82
|
+
|
|
83
|
+
def plot_interfacial_velocity(self):
|
|
84
|
+
"""Plot the interfacial velocity."""
|
|
85
|
+
self.plt.figure(figsize=(6, 5))
|
|
86
|
+
self.plt.plot(self.xx, self.uu[-1, :], "k-")
|
|
87
|
+
self.plt.xlabel(r"$x$")
|
|
88
|
+
self.plt.ylabel(r"Interfacial Velocity ($u_1$)")
|
|
89
|
+
self.plt.grid()
|
|
90
|
+
self.plt.ticklabel_format(style="sci", axis="y", scilimits=(0, 0))
|
|
91
|
+
self.plt.tight_layout()
|
|
92
|
+
|
|
93
|
+
if self.plot_params.save:
|
|
94
|
+
self.plt.savefig(
|
|
95
|
+
self.plot_params.path
|
|
96
|
+
+ f"interfacial_velocity{self.label}.{self.format}",
|
|
97
|
+
bbox_inches="tight",
|
|
98
|
+
)
|
|
99
|
+
else:
|
|
100
|
+
self.plt.show()
|
|
101
|
+
|
|
102
|
+
def plot_streamplot(self):
|
|
103
|
+
"""Plot the streamlines and velocity field."""
|
|
104
|
+
self.plt.figure(figsize=(12, 4))
|
|
105
|
+
self.plt.streamplot(self.xx, self.yy, self.uu, self.vv, color="black")
|
|
106
|
+
self.plt.imshow(
|
|
107
|
+
np.sqrt(self.uu**2 + self.vv**2),
|
|
108
|
+
extent=[-self.params.L, self.params.L, 0, 1],
|
|
109
|
+
origin="lower",
|
|
110
|
+
aspect="auto",
|
|
111
|
+
cmap="Reds",
|
|
112
|
+
)
|
|
113
|
+
cbar = self.plt.colorbar(label=r"$\lVert \mathbf{u}_1 \rVert$")
|
|
114
|
+
cbar.formatter.set_powerlimits((0, 0))
|
|
115
|
+
cbar.formatter.set_useMathText(True)
|
|
116
|
+
self.plt.xlabel(r"$x$")
|
|
117
|
+
self.plt.ylabel(r"$z$")
|
|
118
|
+
self.plt.tight_layout()
|
|
119
|
+
|
|
120
|
+
if self.plot_params.save:
|
|
121
|
+
self.plt.savefig(
|
|
122
|
+
self.plot_params.path + f"streamplot{self.label}.{self.format}",
|
|
123
|
+
bbox_inches="tight",
|
|
124
|
+
)
|
|
125
|
+
else:
|
|
126
|
+
self.plt.show()
|
|
127
|
+
|
|
128
|
+
def plot_streamlines(self):
|
|
129
|
+
"""Plot the streamlines and velocity field."""
|
|
130
|
+
self.plt.figure(figsize=(12, 4))
|
|
131
|
+
self.plt.contour(self.xx, self.yy, self.psii, colors="black")
|
|
132
|
+
self.plt.imshow(
|
|
133
|
+
np.sqrt(self.uu**2 + self.vv**2),
|
|
134
|
+
extent=[-self.params.L, self.params.L, 0, 1],
|
|
135
|
+
origin="lower",
|
|
136
|
+
aspect="auto",
|
|
137
|
+
cmap="Reds",
|
|
138
|
+
)
|
|
139
|
+
cbar = self.plt.colorbar(label=r"$\lVert \mathbf{u}_1 \rVert$")
|
|
140
|
+
cbar.formatter.set_powerlimits((0, 0))
|
|
141
|
+
cbar.formatter.set_useMathText(True)
|
|
142
|
+
self.plt.xlabel(r"$x$")
|
|
143
|
+
self.plt.ylabel(r"$z$")
|
|
144
|
+
self.plt.tight_layout()
|
|
145
|
+
|
|
146
|
+
if self.plot_params.save:
|
|
147
|
+
self.plt.savefig(
|
|
148
|
+
self.plot_params.path + f"streamlines{self.label}.{self.format}",
|
|
149
|
+
bbox_inches="tight",
|
|
150
|
+
)
|
|
151
|
+
else:
|
|
152
|
+
self.plt.show()
|
|
153
|
+
|
|
154
|
+
def plot_concentration_crop(self, lims):
|
|
155
|
+
"""Plot the concentration field."""
|
|
156
|
+
_, axs = self.plt.subplots(1, 3, figsize=(12, 4), constrained_layout=True)
|
|
157
|
+
conc_fields = [self.cc_tr, self.cc_ci, self.cc_tr + self.cc_ci]
|
|
158
|
+
ax_labels = [
|
|
159
|
+
r"$c_{\mathrm{tr}, 1}$",
|
|
160
|
+
r"$c_{\mathrm{ci}, 1}$",
|
|
161
|
+
r"$c_{\mathrm{tot}, 1}$",
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
conc_lim = np.max(np.abs(conc_fields))
|
|
165
|
+
if self.plot_params.norm_scale == "linear":
|
|
166
|
+
norm = colors.CenteredNorm(vcenter=0.0, halfrange=conc_lim)
|
|
167
|
+
elif self.plot_params.norm_scale == "log":
|
|
168
|
+
norm = colors.SymLogNorm(
|
|
169
|
+
linthresh=1e-2 * conc_lim,
|
|
170
|
+
vmin=-conc_lim,
|
|
171
|
+
vmax=conc_lim,
|
|
172
|
+
)
|
|
173
|
+
else:
|
|
174
|
+
raise ValueError("Invalid norm scale.")
|
|
175
|
+
|
|
176
|
+
images = []
|
|
177
|
+
for ax, field, label in zip(axs.flat, conc_fields, ax_labels):
|
|
178
|
+
images.append(
|
|
179
|
+
ax.imshow(
|
|
180
|
+
field,
|
|
181
|
+
extent=[-self.params.L, self.params.L, 0, 1],
|
|
182
|
+
origin="lower",
|
|
183
|
+
aspect="auto",
|
|
184
|
+
cmap="coolwarm",
|
|
185
|
+
norm=norm,
|
|
186
|
+
)
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
ax.set_xlabel(r"$x$")
|
|
190
|
+
ax.set_ylabel(r"$z$")
|
|
191
|
+
ax.set_title(label)
|
|
192
|
+
ax.set_xlim(lims)
|
|
193
|
+
|
|
194
|
+
# Hide duplicate labels
|
|
195
|
+
for ax in axs.flat:
|
|
196
|
+
ax.label_outer()
|
|
197
|
+
|
|
198
|
+
cbar = self.plt.colorbar(
|
|
199
|
+
images[0], label="Concentration", ax=axs.ravel().tolist()
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
if self.plot_params.norm_scale == "linear":
|
|
203
|
+
cbar.formatter.set_powerlimits((0, 0))
|
|
204
|
+
cbar.formatter.set_useMathText(True)
|
|
205
|
+
|
|
206
|
+
if self.plot_params.save:
|
|
207
|
+
self.plt.savefig(
|
|
208
|
+
self.plot_params.path + f"concentration{self.label}.{self.format}",
|
|
209
|
+
bbox_inches="tight",
|
|
210
|
+
)
|
|
211
|
+
else:
|
|
212
|
+
self.plt.show()
|
|
213
|
+
|
|
214
|
+
def _plot_field(self, field, label, prefix=""):
|
|
215
|
+
"""Plot the field of a given scalar."""
|
|
216
|
+
if self.plot_params.norm_scale == "linear":
|
|
217
|
+
norm = colors.CenteredNorm()
|
|
218
|
+
elif self.plot_params.norm_scale == "log":
|
|
219
|
+
conc_lim = np.max(np.abs(field))
|
|
220
|
+
norm = colors.SymLogNorm(
|
|
221
|
+
linthresh=1e-2 * conc_lim,
|
|
222
|
+
vmin=-conc_lim,
|
|
223
|
+
vmax=conc_lim,
|
|
224
|
+
)
|
|
225
|
+
else:
|
|
226
|
+
raise ValueError("Invalid norm scale.")
|
|
227
|
+
|
|
228
|
+
self.plt.figure(figsize=(12, 4))
|
|
229
|
+
self.plt.imshow(
|
|
230
|
+
field,
|
|
231
|
+
extent=[-self.params.L, self.params.L, 0, 1],
|
|
232
|
+
origin="lower",
|
|
233
|
+
aspect="auto",
|
|
234
|
+
cmap="coolwarm",
|
|
235
|
+
norm=norm,
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
cbar = self.plt.colorbar(label=label)
|
|
239
|
+
|
|
240
|
+
if self.plot_params.norm_scale == "linear":
|
|
241
|
+
cbar.formatter.set_powerlimits((0, 0))
|
|
242
|
+
cbar.formatter.set_useMathText(True)
|
|
243
|
+
|
|
244
|
+
self.plt.xlabel(r"$x$")
|
|
245
|
+
self.plt.ylabel(r"$z$")
|
|
246
|
+
self.plt.tight_layout()
|
|
247
|
+
|
|
248
|
+
if self.plot_params.save:
|
|
249
|
+
self.plt.savefig(
|
|
250
|
+
self.plot_params.path + prefix + f"{self.label}.{self.format}",
|
|
251
|
+
bbox_inches="tight",
|
|
252
|
+
)
|
|
253
|
+
else:
|
|
254
|
+
self.plt.show()
|
|
255
|
+
|
|
256
|
+
def plot_pressure(self):
|
|
257
|
+
"""Plot the pressure field."""
|
|
258
|
+
self._plot_field(self.ppressure, r"$p_1$", "pressure")
|
|
259
|
+
|
|
260
|
+
def plot_concentration_tr(self):
|
|
261
|
+
"""Plot the concentration field of the trans surfactant."""
|
|
262
|
+
self._plot_field(self.cc_tr, r"$c_{\mathrm{tr}, 1}$", "concentration_tr")
|
|
263
|
+
|
|
264
|
+
def plot_concentration_ci(self):
|
|
265
|
+
"""Plot the concentration field of the cis surfactant."""
|
|
266
|
+
self._plot_field(self.cc_ci, r"$c_{\mathrm{ci}, 1}$", "concentration_ci")
|
|
267
|
+
|
|
268
|
+
def plot_concentration_tot(self):
|
|
269
|
+
"""Plot the total surfactant concentration field."""
|
|
270
|
+
self._plot_field(
|
|
271
|
+
self.cc_tr + self.cc_ci,
|
|
272
|
+
r"$c_{\mathrm{tot}, 1}$",
|
|
273
|
+
"concentration_tot",
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
def plot_surface_excess(self):
|
|
277
|
+
"""Plot the surface excess concentrations."""
|
|
278
|
+
self.plt.figure(figsize=(6, 5))
|
|
279
|
+
|
|
280
|
+
self.plt.plot(
|
|
281
|
+
self.xx,
|
|
282
|
+
self.ggamma_tr + self.ggamma_ci,
|
|
283
|
+
"k-",
|
|
284
|
+
label=r"$\Gamma_{\mathrm{tr}, 1} + \Gamma_{\mathrm{ci}, 1}$",
|
|
285
|
+
)
|
|
286
|
+
self.plt.plot(
|
|
287
|
+
self.xx, self.ggamma_tr, "r--", label=r"$\Gamma_{\mathrm{tr}, 1}$"
|
|
288
|
+
)
|
|
289
|
+
self.plt.plot(
|
|
290
|
+
self.xx, self.ggamma_ci, "b-.", label=r"$\Gamma_{\mathrm{ci}, 1}$"
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
self.plt.xlabel(r"$x$")
|
|
294
|
+
self.plt.ylabel("Surface Excess")
|
|
295
|
+
self.plt.legend(loc="lower right")
|
|
296
|
+
self.plt.grid()
|
|
297
|
+
self.plt.ticklabel_format(style="sci", axis="y", scilimits=(0, 0))
|
|
298
|
+
self.plt.tight_layout()
|
|
299
|
+
|
|
300
|
+
if self.plot_params.save:
|
|
301
|
+
self.plt.savefig(
|
|
302
|
+
self.plot_params.path + f"surface_excess{self.label}.{self.format}",
|
|
303
|
+
bbox_inches="tight",
|
|
304
|
+
)
|
|
305
|
+
else:
|
|
306
|
+
self.plt.show()
|
|
307
|
+
|
|
308
|
+
def plot_intensity(self):
|
|
309
|
+
"""Plot the light intensity."""
|
|
310
|
+
self.plt.figure(figsize=(6, 5))
|
|
311
|
+
|
|
312
|
+
self.plt.plot(self.xx, self.ff, "k-", label="Approx")
|
|
313
|
+
|
|
314
|
+
self.plt.xlabel(r"$x$")
|
|
315
|
+
self.plt.ylabel(r"$f_1$")
|
|
316
|
+
self.plt.ticklabel_format(style="sci", axis="y", scilimits=(0, 0))
|
|
317
|
+
self.plt.tight_layout()
|
|
318
|
+
|
|
319
|
+
if self.plot_params.save:
|
|
320
|
+
self.plt.savefig(
|
|
321
|
+
self.plot_params.path + f"intensity{self.label}.{self.format}",
|
|
322
|
+
bbox_inches="tight",
|
|
323
|
+
)
|
|
324
|
+
else:
|
|
325
|
+
self.plt.show()
|
|
326
|
+
|
|
327
|
+
def plot_intensity_slip_tension(self):
|
|
328
|
+
"""Plot the light intensity, interfacial slip velocity, and surface tension."""
|
|
329
|
+
_, ax1 = self.plt.subplots(figsize=(10, 4.5))
|
|
330
|
+
|
|
331
|
+
slip_plt = ax1.plot(self.xx, self.uu[-1, :], "k-", label=r"$u_1$")
|
|
332
|
+
ax1.set_xlabel(r"$x$")
|
|
333
|
+
ax1.set_ylabel(r"$u_1$")
|
|
334
|
+
ax1.ticklabel_format(style="sci", axis="y", scilimits=(0, 0))
|
|
335
|
+
|
|
336
|
+
ax2 = ax1.twinx()
|
|
337
|
+
|
|
338
|
+
tension_plt = ax2.plot(self.xx, self.ttension, "k--", label=r"$\gamma_1$")
|
|
339
|
+
ax2.set_ylabel(r"$\gamma_1$")
|
|
340
|
+
ax2.ticklabel_format(style="sci", axis="y", scilimits=(0, 0))
|
|
341
|
+
|
|
342
|
+
# Align and stretch axes (must occur before intensity plot)
|
|
343
|
+
offset, scale = 2, 0.5 # Relative location/scale of intensity
|
|
344
|
+
_, limit = ax1.get_ylim()
|
|
345
|
+
ax1.set_ylim(-limit, offset * limit)
|
|
346
|
+
_, limit = ax2.get_ylim()
|
|
347
|
+
ax2.set_ylim(-limit, offset * limit)
|
|
348
|
+
|
|
349
|
+
# Plot intensity on first axes scaled by slip velocity
|
|
350
|
+
max_u = np.max(self.uu[-1, :])
|
|
351
|
+
base, max_height = offset * max_u, scale * max_u
|
|
352
|
+
arrow_xx, arrow_ff = self.xx[::20], self.ff[::20]
|
|
353
|
+
ax1.quiver(
|
|
354
|
+
arrow_xx,
|
|
355
|
+
[base + 0.5 * max_height], # base of arrow
|
|
356
|
+
np.zeros_like(arrow_ff),
|
|
357
|
+
-(0.75 + arrow_ff), # arrow length (scaled by max_height)
|
|
358
|
+
scale=1 / max_height,
|
|
359
|
+
width=0.005,
|
|
360
|
+
scale_units="y",
|
|
361
|
+
color="b",
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
# Fix for having a single legend over multiple axes
|
|
365
|
+
plots = slip_plt + tension_plt
|
|
366
|
+
labels = [plot.get_label() for plot in plots]
|
|
367
|
+
ax1.legend(plots, labels, loc="lower right")
|
|
368
|
+
|
|
369
|
+
if self.plot_params.save:
|
|
370
|
+
self.plt.savefig(
|
|
371
|
+
self.plot_params.path
|
|
372
|
+
+ f"intensity_slip_tension{self.label}.{self.format}",
|
|
373
|
+
bbox_inches="tight",
|
|
374
|
+
)
|
|
375
|
+
else:
|
|
376
|
+
self.plt.show()
|
|
377
|
+
|
|
378
|
+
def plot_interface(self):
|
|
379
|
+
"""Plot the surface shape."""
|
|
380
|
+
self.plt.figure(figsize=(6, 5))
|
|
381
|
+
|
|
382
|
+
self.plt.plot(self.xx, self.SS, "k-", label="Approx")
|
|
383
|
+
|
|
384
|
+
self.plt.xlabel(r"$x$")
|
|
385
|
+
self.plt.ylabel(r"$S_1$")
|
|
386
|
+
self.plt.ticklabel_format(style="sci", axis="y", scilimits=(0, 0))
|
|
387
|
+
self.plt.tight_layout()
|
|
388
|
+
|
|
389
|
+
if self.plot_params.save:
|
|
390
|
+
self.plt.savefig(
|
|
391
|
+
self.plot_params.path + f"interface{self.label}.{self.format}",
|
|
392
|
+
bbox_inches="tight",
|
|
393
|
+
)
|
|
394
|
+
else:
|
|
395
|
+
self.plt.show()
|
|
396
|
+
|
|
397
|
+
def plot_surface_tension(self):
|
|
398
|
+
"""Plot the surface tension."""
|
|
399
|
+
self.plt.figure(figsize=(6, 5))
|
|
400
|
+
self.plt.plot(self.xx, self.ttension, "k-")
|
|
401
|
+
self.plt.xlabel(r"$x$")
|
|
402
|
+
self.plt.ylabel(r"Surface Tension ($\gamma_1$)")
|
|
403
|
+
self.plt.grid()
|
|
404
|
+
self.plt.ticklabel_format(style="sci", axis="y", scilimits=(0, 0))
|
|
405
|
+
self.plt.tight_layout()
|
|
406
|
+
|
|
407
|
+
if self.plot_params.save:
|
|
408
|
+
self.plt.savefig(
|
|
409
|
+
self.plot_params.path + f"tension{self.label}.{self.format}",
|
|
410
|
+
bbox_inches="tight",
|
|
411
|
+
)
|
|
412
|
+
else:
|
|
413
|
+
self.plt.show()
|
|
414
|
+
|
|
415
|
+
def plot_fluxes(self):
|
|
416
|
+
"""Plot the fluxes."""
|
|
417
|
+
self.plt.figure(figsize=(6, 5))
|
|
418
|
+
self.plt.plot(
|
|
419
|
+
self.xx,
|
|
420
|
+
self.JJ_tr + self.JJ_ci,
|
|
421
|
+
"k-",
|
|
422
|
+
label=r"$J_{\mathrm{tr}, 1} + J_{\mathrm{ci}, 1}$",
|
|
423
|
+
)
|
|
424
|
+
self.plt.plot(self.xx, self.JJ_tr, "r--", label=r"$J_{\mathrm{tr}, 1}$")
|
|
425
|
+
self.plt.plot(self.xx, self.JJ_ci, "b-.", label=r"$J_{\mathrm{ci}, 1}$")
|
|
426
|
+
self.plt.xlabel(r"$x$")
|
|
427
|
+
self.plt.ylabel("Kinetic Flux")
|
|
428
|
+
self.plt.legend(loc="lower right")
|
|
429
|
+
self.plt.grid()
|
|
430
|
+
self.plt.ticklabel_format(style="sci", axis="y", scilimits=(0, 0))
|
|
431
|
+
self.plt.tight_layout()
|
|
432
|
+
|
|
433
|
+
if self.plot_params.save:
|
|
434
|
+
self.plt.savefig(
|
|
435
|
+
self.plot_params.path + f"flux{self.label}.{self.format}",
|
|
436
|
+
bbox_inches="tight",
|
|
437
|
+
)
|
|
438
|
+
else:
|
|
439
|
+
self.plt.show()
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
def plot_first_order(): # noqa: D103
|
|
443
|
+
parser = ArgumentParser(
|
|
444
|
+
description="Plot the first order surfactant concentrations.",
|
|
445
|
+
formatter_class=ArgumentDefaultsHelpFormatter,
|
|
446
|
+
)
|
|
447
|
+
parameter_parser(parser)
|
|
448
|
+
plot_parser(parser)
|
|
449
|
+
leading_order_parser(parser)
|
|
450
|
+
first_order_parser(parser)
|
|
451
|
+
args = parser.parse_args()
|
|
452
|
+
|
|
453
|
+
params = Parameters.from_dict(vars(args))
|
|
454
|
+
plot_params = PlottingParameters.from_dict(vars(args))
|
|
455
|
+
|
|
456
|
+
root_index = args.root_index
|
|
457
|
+
func = parse_func(args.func)
|
|
458
|
+
problem = args.problem
|
|
459
|
+
|
|
460
|
+
# Calculate Fourier series coefficients
|
|
461
|
+
if args.mollify:
|
|
462
|
+
wavenumbers, func_coeffs = convolution_coeff(
|
|
463
|
+
lambda x: func(x, params),
|
|
464
|
+
mollifier(delta=args.delta), # noqa: F405
|
|
465
|
+
params.L,
|
|
466
|
+
plot_params.wave_count,
|
|
467
|
+
)
|
|
468
|
+
else:
|
|
469
|
+
wavenumbers, func_coeffs = fourier_series_coeff(
|
|
470
|
+
lambda x: func(x, params), params.L, plot_params.wave_count
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
# Solve leading order problem
|
|
474
|
+
leading = LeadingOrder(params, root_index)
|
|
475
|
+
|
|
476
|
+
# Solve first order problem
|
|
477
|
+
if problem == "forward":
|
|
478
|
+
constraint = lambda n: ( # noqa: E731
|
|
479
|
+
Variables.f,
|
|
480
|
+
func_coeffs[n],
|
|
481
|
+
)
|
|
482
|
+
elif problem == "inverse":
|
|
483
|
+
constraint = lambda n: ( # noqa: E731
|
|
484
|
+
(Variables.f, 0.0) if n == 0 else (Variables.S, func_coeffs[n])
|
|
485
|
+
)
|
|
486
|
+
|
|
487
|
+
first = FirstOrder(wavenumbers, params, leading)
|
|
488
|
+
first.solve(constraint)
|
|
489
|
+
|
|
490
|
+
# Plot figures
|
|
491
|
+
figures = Figures(first, plot_params)
|
|
492
|
+
|
|
493
|
+
figures.plot_streamplot()
|
|
494
|
+
figures.plot_streamlines()
|
|
495
|
+
figures.plot_pressure()
|
|
496
|
+
figures.plot_concentration_crop(lims=[-3.0, 3.0])
|
|
497
|
+
figures.plot_concentration_tr()
|
|
498
|
+
figures.plot_concentration_ci()
|
|
499
|
+
figures.plot_concentration_tot()
|
|
500
|
+
figures.plot_surface_excess()
|
|
501
|
+
figures.plot_surface_tension()
|
|
502
|
+
figures.plot_fluxes()
|
|
503
|
+
figures.plot_interfacial_velocity()
|
|
504
|
+
figures.plot_intensity()
|
|
505
|
+
figures.plot_intensity_slip_tension()
|
|
506
|
+
figures.plot_interface()
|