Skip to content

Commit d069c02

Browse files
committed
added LE example
1 parent 5d80569 commit d069c02

File tree

3 files changed

+314
-0
lines changed

3 files changed

+314
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
"""main_LE_HONSE_v1.py
2+
3+
This script demonstrates the linear stability analysis for a higher-order
4+
nonlinear Schrödinger equation with quartic propagation constant, discussed in
5+
[1]_. The example reproduces the linear eigenspectrum (LE) of the generalized
6+
dispersion Kerr soliton in Sect. 8 and Fig. 9 of Ref. [2]_. This example is
7+
discussed as SWtools use-case in [3]_.
8+
9+
References
10+
----------
11+
12+
.. [1] O. Melchert, A. Demircan, "Optical Solitary Wavelets",
13+
https://doi.org/10.48550/arXiv.2410.06867.
14+
15+
.. [2] K. K. K. Tam, T. J. Alexander, A. Blanco-Redondo, C. M. de Sterke,
16+
Generalized dispersion Kerr solitons, Phys. Rev. A 101 (2020) 043822,
17+
https://doi.org/10.1103/PhysRevA.101.043822.
18+
19+
.. [3] O. Melchert, A. Demircan, https://doi.org/10.48550/arXiv.2504.10623.
20+
21+
.. codeauthor:: Oliver Melchert <melchert@iqo.uni-hannover.de>
22+
"""
23+
import numpy as np
24+
from SWtools import SRM, LE_HONSE, LE_dump
25+
26+
# -- SET UP DOMAIN AND MODEL
27+
xi = np.linspace(-25, 25, 2**10)
28+
c2, c3, c4 = 0.35, 0., -0.04167
29+
kap = 1.
30+
31+
# -- DETERMINE SW SOLUTION
32+
NEVP = SRM(xi, (0,c2,c3,c4), lambda I, xi: I)
33+
NEVP.solve(np.exp(-xi**2/2), kap)
34+
35+
# -- PERFORM LSA
36+
res = LE_HONSE(xi, NEVP.U, kap, (c2,c3,c4))
37+
38+
# -- POSTPROCESS RESULTS
39+
LE_dump(*res)
40+
Lam_max, Lam, f, g = res
41+
res = {
42+
'xi': xi,
43+
'U': NEVP.U,
44+
'betas': [c2,c3,c4],
45+
'kap': kap,
46+
'Lam_max': Lam_max,
47+
'Lam': Lam,
48+
'f': f,
49+
'g': g
50+
}
51+
np.savez_compressed('res_LE_HONSE.npz', **res)
221 KB
Loading
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
"""main_fig_stability_v1.py
2+
3+
Module implementing a figure with the description:
4+
5+
Linear stability analysis for the solitary waves of a higher-order nonlinear
6+
Schrödinger equation with quartic dispersion.
7+
%
8+
(a) Solitary wave with wavenumber $\kappa$.
9+
%
10+
(b) Zero-eigenvalue modes (stars) and internal modes (diamonds).
11+
Continuous-wave spectrum is shaded gray.
12+
%
13+
(c) Small-amplitude mode $f$ of the fundamental internal mode, and,
14+
%
15+
(d) corresponding mode $g$.
16+
17+
.. codeauthor:: Oliver Melchert <melchert@iqo.uni-hannover.de>
18+
"""
19+
import sys
20+
import os
21+
import numpy as np
22+
import matplotlib as mpl
23+
import matplotlib.pyplot as plt
24+
from matplotlib.gridspec import GridSpec, GridSpecFromSubplotSpec
25+
26+
27+
def save_fig(fig_name='test', fig_format='png'):
28+
dir_name = os.path.dirname(fig_name)
29+
os.makedirs(dir_name,exist_ok=True)
30+
if fig_format == 'png':
31+
plt.savefig(fig_name+'.png', format='png', dpi=600)
32+
elif fig_format == 'pdf':
33+
plt.savefig(fig_name+'.pdf', format='pdf', dpi=600)
34+
elif fig_format == 'svg':
35+
plt.savefig(fig_name+'.svg', format='svg', dpi=600)
36+
else:
37+
plt.show()
38+
39+
40+
def set_style(fig_width=3.25, aspect_ratio = 0.6):
41+
42+
fig_height = aspect_ratio*fig_width
43+
44+
params = {
45+
'figure.figsize': (fig_width,fig_height),
46+
'legend.fontsize': 6,
47+
'legend.frameon': False,
48+
'axes.labelsize': 7,
49+
'axes.linewidth': 1.,
50+
'axes.linewidth': 0.8,
51+
'xtick.labelsize' :7,
52+
'ytick.labelsize': 7,
53+
'mathtext.fontset': 'stixsans',
54+
'mathtext.rm': 'serif',
55+
'mathtext.bf': 'serif:bold',
56+
'mathtext.it': 'serif:italic',
57+
'mathtext.sf': 'sans\\-serif',
58+
'font.size': 7,
59+
'font.family': 'serif',
60+
'font.serif': "Helvetica",
61+
}
62+
mpl.rcParams.update(params)
63+
64+
65+
def main_figure(res, o_name = './fig_v1'):
66+
67+
o_format = 'png'
68+
69+
def subfig_label(ax, label):
70+
pos = ax.get_position()
71+
fig.text(
72+
pos.x0,
73+
pos.y1,
74+
label,
75+
color="white",
76+
backgroundcolor="k",
77+
bbox=dict(facecolor="k", edgecolor="none", boxstyle="square,pad=0.1"),
78+
verticalalignment="top",
79+
horizontalalignment="left",
80+
)
81+
82+
set_style(3.5, 0.66)
83+
fig = plt.figure()
84+
plt.subplots_adjust(left = 0.1, bottom = 0.11, right = 0.99, top = 0.98, wspace=1.3)
85+
gs00 = GridSpec(nrows = 1, ncols = 1)
86+
87+
gsA = GridSpecFromSubplotSpec(4, 5, subplot_spec=gs00[0,0], wspace=1.5, hspace=0.2)
88+
ax0 = fig.add_subplot(gsA[:, 2])
89+
90+
gsB = GridSpecFromSubplotSpec(2, 1, subplot_spec=gsA[:,3:], wspace=0.075, hspace=0.05)
91+
ax1 = fig.add_subplot(gsB[0, 0])
92+
ax2 = fig.add_subplot(gsB[1, 0])
93+
sf1 = [ax1,ax2]
94+
95+
gsC = GridSpecFromSubplotSpec(1, 1, subplot_spec=gsA[:,:2], wspace=0.075, hspace=0.075)
96+
ax3 = fig.add_subplot(gsC[0, 0])
97+
98+
99+
# -- SUBFIGURE CONTENT ----------------------------------------------------
100+
subfig_a(fig, ax3, res)
101+
subfig_b(fig, ax0, res)
102+
subfig_cd(fig, sf1, res)
103+
104+
subfig_label(ax3,r"(a)")
105+
subfig_label(ax0,r"(b)")
106+
subfig_label(ax1,r"(c)")
107+
subfig_label(ax2,r"(d)")
108+
109+
# -- GENERATE FIGURE ------------------------------------------------------
110+
save_fig(fig_name=o_name, fig_format=o_format )
111+
112+
113+
def marker_style(LamR, LamI):
114+
115+
my_col, my_marker, my_size = 'k', 'o', 4
116+
mfc, mew = 'k',1
117+
118+
if np.abs(LamR) < 0.02 and np.abs(LamI) < 0.01:
119+
my_col, my_marker, my_size = 'limegreen', '*', 6
120+
mfc, mew = 'limegreen', 0
121+
elif np.abs(LamR) > 0.02 and np.abs(LamI) < 0.01:
122+
my_col, my_marker, my_size = 'magenta', 'd', 4
123+
mfc, mew = 'white', 1
124+
elif np.abs(LamI) > 0.01:
125+
my_col, my_marker, my_size = 'C0', 'd', 4
126+
mfc, mew = 'C0', 1
127+
128+
return my_col, my_marker, my_size, mfc, mew
129+
130+
131+
def subfig_a(fig, ax, res):
132+
133+
t = res['xi']
134+
U = res['U']
135+
kap = res['kap']
136+
137+
def my_label(ax, label):
138+
pos = ax.get_position()
139+
fig.text(
140+
pos.x0+0.01,
141+
pos.y0+0.01,
142+
label,
143+
color="k",
144+
verticalalignment="bottom",
145+
horizontalalignment="left",
146+
)
147+
148+
my_yLims = lambda y: (1.2*np.min(np.real(y)),1.2*np.max(np.real(y)))
149+
150+
ax.axhline(0, color='k', lw=0.75)
151+
ax.plot(t, np.real(U), color="C0", lw=1, label=r'${\mathrm{Re}}[U]$')
152+
ax.plot(t, np.imag(U), color="C0", dashes=[2,1], lw=1, label=r'${\mathrm{Im}}[U]$')
153+
ax.set_ylim(my_yLims(U))
154+
ax.set_ylabel(r"Solution $U(\xi)$")
155+
ax.tick_params(axis="x", length=2.0, pad=1)
156+
ax.tick_params(axis="y", length=2.0, pad=1)
157+
ax.set_xlabel(r"Coordinate $\xi$", labelpad=1)
158+
159+
ax.legend(
160+
ncol=1,
161+
loc='upper right',
162+
handlelength=0.8,
163+
columnspacing=1.,
164+
handletextpad=0.5
165+
)
166+
167+
#my_label(ax, "$\kappa = %4.3lf$"%(kap))
168+
ax.yaxis.set_label_coords(-0.25,0.5)
169+
170+
171+
def subfig_b(fig, ax, res):
172+
kap = res['kap']
173+
Lam = res['Lam']
174+
Lam_max = res['Lam_max']
175+
f = res['f']
176+
g = res['g']
177+
178+
ax.axhline(0,color='k', lw=0.5)
179+
ax.axvline(0,color='k', lw=0.5)
180+
for i in range(Lam.size):
181+
LamR, LamI = np.real(Lam[i]), np.imag(Lam[i])
182+
my_col, my_marker, my_size, mfc, mew = marker_style(LamR, LamI)
183+
ax.plot([LamR], [LamI], color=my_col, marker = my_marker, markersize=my_size, mfc=mfc, mew=mew)
184+
185+
ax.axhline(Lam_max, color='k', dashes=[1,1])
186+
ax.axhline(-Lam_max, color='k', dashes=[1,1])
187+
188+
ax.axhspan(Lam_max,1.5*Lam_max, color='silver')
189+
ax.axhspan(-Lam_max,-1.5*Lam_max, color='silver')
190+
191+
y_lim = (-1.2*Lam_max, 1.2*Lam_max)
192+
ax.tick_params(axis="y", length=2.0, pad=1)
193+
ax.set_ylim(y_lim)
194+
ax.set_ylabel(r"$\rm{Im}[\Lambda]$")
195+
196+
x_lim = (-1.5,1.5)
197+
ax.set_xlim(x_lim)
198+
ax.tick_params(axis="x", length=2.0, pad=1, top=False)
199+
ax.set_xlabel(r"$\rm{Re}[\Lambda]$", labelpad=1)
200+
201+
ax.yaxis.set_label_coords(-.9,0.5)
202+
203+
204+
def subfig_cd(fig, axs, res):
205+
206+
ax1, ax2 = axs
207+
208+
t = res['xi']
209+
Lam = res['Lam']
210+
f_ = res['f']
211+
g_ = res['g']
212+
213+
my_yLims = lambda y: (1.2*np.min(np.real(y)),1.4*np.max(np.real(y)))
214+
215+
idx = np.argmin(np.where(np.abs(np.imag(Lam))>0.02, np.abs(np.imag(Lam)) , np.inf))
216+
217+
LamR, LamI = np.real(Lam[idx]), np.imag(Lam[idx])
218+
f, g = f_[idx], g_[idx]
219+
220+
my_col, my_marker, my_size, mfc, mew = marker_style(LamR, LamI)
221+
222+
ax1.axhline(0, color='k', lw=0.75)
223+
ax1.plot(t, np.real(f), color=my_col, lw=1, label=r'${\mathrm{Re}}[f]$')
224+
ax1.plot(t, np.imag(f), color=my_col, dashes=[2,1], lw=1, label=r'${\mathrm{Im}}[f]$')
225+
ax1.set_ylim(my_yLims(f))
226+
ax1.set_ylabel(r"Mode $f$")
227+
#ax1.set_ylabel(r"Mode $f$ (${\rm{Im}}[\Lambda] = %4.3lf$)"%(LamI))
228+
ax1.tick_params(axis="x", length=2.0, pad=1, labelbottom=False)
229+
ax1.tick_params(axis="y", length=2.0, pad=1)
230+
231+
ax1.legend(
232+
ncol=2,
233+
handlelength=0.8,
234+
columnspacing=0.75,
235+
handletextpad=0.5,
236+
loc = (0.15,0.85)
237+
)
238+
239+
ax2.axhline(0, color='k', lw=0.75)
240+
ax2.plot(t, np.real(g), color=my_col, lw=1, label=r'${\mathrm{Re}}[g]$')
241+
ax2.plot(t, np.imag(g), color=my_col, dashes=[2,1], lw=1, label=r'${\mathrm{Im}}[g]$')
242+
ax2.set_ylim(my_yLims(g))
243+
ax2.set_ylabel(r"Mode $g$")
244+
#ax2.set_ylabel(r"Mode $g$ (${\rm{Im}}[\Lambda] = %4.3lf$)"%(LamI))
245+
ax2.tick_params(axis="x", length=2.0, pad=1)
246+
ax2.tick_params(axis="y", length=2.0, pad=1)
247+
ax2.set_xlabel(r"Coordinate $\xi$", labelpad=1)
248+
249+
ax2.legend(
250+
ncol=2,
251+
handlelength=0.8,
252+
columnspacing=0.75,
253+
handletextpad=0.5,
254+
loc = (0.15,0.85)
255+
)
256+
257+
ax1.yaxis.set_label_coords(-0.3,0.5)
258+
ax2.yaxis.set_label_coords(-0.3,0.5)
259+
260+
261+
if __name__=="__main__":
262+
res = np.load('../res_LE_HONSE.npz')
263+
main_figure(res, o_name = './fig_HONSE_stability')

0 commit comments

Comments
 (0)