SkillAgentSearch skills...

Luna.jl

Nonlinear optical pulse propagator

Install / Use

/learn @LupoLab/Luna.jl
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Luna.jl

DOI Stable

[!IMPORTANT]
To stay up-to-date with Luna.jl and learn about bugfixes and new features, subscribe to our mailing list.

Luna.jl is a flexible platform for the simulation of nonlinear optical dynamics—both in waveguides (such as optical fibres) and free-space geometries—using the unidirectional pulse propagation equation (UPPE) and its approximate forms, such as the commonly used generalised nonlinear Schrödinger equation (GNLSE). Some of the key features of Luna:

  • A variety of propagation geometries treated in a unified way:
    • Single-mode (mode-averaged) propagation in waveguides
    • Multi-mode propagation in waveguides with arbitrary (including non-symmetric) mode-shapes, full polarisation resolution, and intermodal coupling for arbitrary nonlinear polarisation terms
    • Waveguides with arbitrarily varying material properties and cross-sections (e.g. tapered fibres)
    • Free-space propagation with radial symmetry
    • Full (3+1)-dimensional free-space propagation
  • Both field-resolved and envelope propagation equations
  • A range of linear and nonlinear optical effects:
    • Modal dispersion and loss in waveguides
    • Optical Kerr effect (third-order nonlinearity)
    • Raman scattering in molecular gases or glasses
    • Strong-field photoionisation and plasma dynamics
  • A built-in interface for the running and processing of multi-dimensional parameter scans in serial or parallel
  • A standard library of plotting and processing functions, including calculation of spectrograms and beam properties

Luna is designed to be extensible: adding e.g. a new type of waveguide or a new nonlinear effect is straightforward, even without editing the main source code.

Luna was originally developed for modelling ultrafast pulse propagation in gas-filled hollow capillary fibres and hollow-core photonic crystal fibres. Therefore, such simulations have particularly good support. It is also excellent for modelling propagation in solid-core fibres.

Luna is written in the Julia programming language, chosen for its unique combination of readability, ease of use, and speed. If you want to use Luna but are new to Julia, see the relevant section of this README.

There are two ways of using Luna:

  1. A very simple high-level interface for the most heavily optimised applications of Luna: propagation in gas-filled hollow capillary fibres and hollow-core photonic crystal fibres (consisting of the function prop_capillary and some helper functions to create input pulses); or propagation of simple GNLSE simulations (consisting of the function prop_gnlse).
  2. A low-level interface which allows for full control and customisation of the simulation parameters, the use of custom waveguide modes and gas fills (including gas mixtures), and free-space propagation simulations.

For a short introduction on how to use the simple interface, see the Quickstart or GNLSE sections below. More information, including on the internals of Luna, can be found in the Documentation.

Installation

Luna requires Julia v1.9 or later, which can be obtained from here. In a Julia terminal, to install Luna simply enter the package manager with ] and run add Luna:

]
add Luna

This will install and precompile Luna and all its dependencies.

Quickstart

To run a simple simulation of ultrafast pulse propagation in a gas-filled hollow capillary fibre, you can use prop_capillary. As an example, take a 3-metre length of HCF with 125 μm core radius, filled with 1 bar of helium gas, and driving pulses centred at 800 nm wavelength with 120 μJ of energy and 10 fs duration. We consider a frequency grid which spans from 120 nm to 4 μm and a time window of 1 ps.

julia> using Luna
julia> output = prop_capillary(125e-6, 3, :He, 1; λ0=800e-9, energy=120e-6, τfwhm=10e-15, λlims=(150e-9, 4e-6), trange=1e-12)

The first time you run this code, you will see the precompilation message:

julia> using Luna
[ Info: Precompiling Luna [30eb0fb0-5147-11e9-3356-d75b018717ce]

This will take some time to complete (and you may see additional precompilation messages for the packages Luna depends on), but is only necessary once, unless you update Luna or edit the package source code. Since this is using the default options including FFT planning and caching of the PPT ionisation rate, you will also have to wait for those processes to finish. After the simulation finally runs (which for this example should take between 10 seconds and one minute), you will have the results stored in output:

julia> output = prop_capillary(125e-6, 3, :He, 1; λ0=800e-9, energy=120e-6, τfwhm=10e-15, λlims=(150e-9, 4e-6), trange=1e-12)
[...]
MemoryOutput["simulation_type", "dumps", "meta", "Eω", "grid", "stats", "z"]

You can access the results by indexing into output like a Dict, for example for the frequency-domain field :

julia> output["Eω"]
8193×201 Array{Complex{Float64},2}:
[...]

The shape of this array is (Nω x Nz) where is the number of frequency samples and Nz is the number of steps that were saved during the propagation. By default, prop_capillary will solve the full-field (carrier-resolved) UPPE. In this case, the numerical Fourier transforms are done using rfft, so the number of frequency samples is (Nt/2 + 1) with Nt the number of samples in the time domain.

Multi-mode propagation

prop_capillary accepts many keyword arguments (for a full list see the documentation) to customise the simulation parameters and input pulse. One of the most important is modes, which defines whether mode-averaged or multi-mode propagation is used, and which modes are included. By default, prop_capillary considers mode-averaged propagation in the fundamental (HE₁₁) mode of the capillary, which is fast and simple but less accurate, especially at high intensity when self-focusing and photoionisation play important roles in the propagation dynamics.

Mode-averaged propagation is activated using modes=:HE11 (the default) or replacing the :HE11 with a different mode designation (for mode-averaged propagation in a different mode). To run the same simulation as above with the first four modes (HE₁₁ to HE₁₄) of the capillary, set modes to 4 (this example also uses smaller time and frequency windows to make the simulation run a little faster):

julia> prop_capillary(125e-6, 3, :He, 1; λ0=800e-9, modes=4, energy=120e-6, τfwhm=10e-15, trange=400e-15, λlims=(150e-9, 4e-6))

The propagation will take much longer, and the output field now has shape (Nω x Nm x Nz) with Nm the number of modes:

julia> output_multimode["Eω"]
2049×4×201 Array{Complex{Float64},3}:
[...]

NOTE: Setting modes=:HE11 and modes=1 are not equivalent, except if only the Kerr effect is included in the simulation. The former uses mode-averaged propagation (treating all spatial dependence of the nonlinear polarisation the same as the Kerr effect) whereas the latter projects the spatially dependent nonlinear polarisation onto a single mode. This difference is especially important when photoionisation plays a major role.

Plotting results

More usefully, you can directly plot the propagation results using Plotting.prop_2D() (Plotting is imported at the same time as prop_capillary by the using Luna statement):

julia> Plotting.prop_2D(output)
PyPlot.Figure(PyObject <Figure size 2400x800 with 4 Axes>)

This should show a plot like this: Propagation example 1 You can also display the power spectrum at the input and output (and anywhere in between):

julia> Plotting.spec_1D(output, [0, 1.5, 3]; log10=true)
PyPlot.Figure(PyObject <Figure size 1700x1000 with 1 Axes>)

which will show this: Propagation example 2 Plotting functions accept many additional keyword arguments to quickly display relevant information. For example, you can show the bandpass-filtered UV pulse from the simulation using the bandpass argument:

julia> Plotting.time_1D(output, [2, 2.5, 3]; trange=(-10e-15, 30e-15), bandpass=(180e-9, 220e-9))
PyPlot.Figure(PyObject <Figure size 1700x1000 with 1 Axes>)

Propagation example 3

For multi-mode simulations, the plotting functions will display all modes individually by default. You can display the sum over modes instead using modes=:sum:

julia> Plotting.spec_1D(output_multimode; log10=true, modes=:sum)
PyPlot.Figure(PyObject <Figure size 1700x1000 with 1 Axes>)

Propagation example 4 (Compare this to the mode-averaged case above and note the important differences, e.g. the appearance of additional ultraviolet dispersive waves in higher-order modes.)

More plotting functions are available in the Plotting module, including for propagation statistics (Plotting.stats(output)) and spectrograms (Plotting.spectrogram())

Output processing

The Processing module contains many useful functions for more detailed processing and manual plotting, including:

  • Spectral energy density on frequency or wavelength axis with optional spectral resolution setting (Processing.getEω and Processing.getIω)
  • Time-domain fields and pulse envelopes with flexible frequency bandpass and linear (dispersive) propagation operators (Processing.getEt)
  • Ene
View on GitHub
GitHub Stars110
CategoryDevelopment
Updated13d ago
Forks41

Languages

Julia

Security Score

95/100

Audited on Mar 16, 2026

No findings