Tutorials

Comprehensive guides for common RSoft CAD workflows and advanced techniques.

Tutorial 1: Designing Your First Photonic Lantern

Overview

Learn to create a basic photonic lantern from scratch, including configuration, simulation, and analysis.

Step 1: Understanding the Configuration

from rsoft_cad.utils.config.modifier import load_config, modify_parameter

# Load and examine the default configuration
config = load_config("config/default_config.json")

# Key parameters to understand:
# - Num_Cores_Ring: Number of cores in the ring
# - Core_Diameter: Diameter of individual cores
# - Taper_Length: Length of the taper section
# - Taper_Factor: How much the structure tapers

Step 2: Create the Lantern

from rsoft_cad.lantern import PhotonicLantern

# Initialize the lantern
lantern = PhotonicLantern()

# Create with specific parameters
core_map = lantern.create_lantern(
    config=config,
    highest_mode="LP02",    # Maximum mode to support
    taper_factor=12,        # Taper ratio
    taper_length=45000,     # Taper length in microns
    savefile=True           # Save intermediate files
)

print(f"Created lantern with {len(core_map)} cores")

Step 3: Add Launch Conditions

# Add launch field at the input
lantern.add_launch_field(
    launch_type="LP01",     # Launch LP01 mode
    power=1.0,              # Normalized power
    position=(0, 0),        # Center position
    width=8.0               # Beam width
)

# Save the complete design
lantern.write("tutorial_lantern.ind")

Step 4: Run Simulation

from rsoft_cad.rsoft_simulations import run_simulation

# Execute BeamPROP simulation
result = run_simulation(
    design_filepath=lantern.design_filepath,
    design_filename=lantern.design_filename,
    sim_package="bsimw32",
    prefix_name="tutorial_sim",
    save_folder="tutorial_results"
)

if result.returncode == 0:
    print("Simulation completed successfully!")
else:
    print(f"Simulation failed: {result.stderr}")

Tutorial 2: Mode Selective Lantern Design

Overview

Design a mode selective lantern that efficiently couples specific LP modes.

Step 1: Mode Analysis

from rsoft_cad.utils.lp_modes import calculate_mode_cutoff
from rsoft_cad.constants import SINGLE_MODE_FIBERS

# Analyze mode properties for SMF-28 fiber
fiber_params = SINGLE_MODE_FIBERS["SMF-28"]
cutoff_freq = calculate_mode_cutoff(
    core_diameter=fiber_params["core_diameter"],
    numerical_aperture=fiber_params["numerical_aperture"],
    wavelength=1550  # nm
)

print(f"LP11 cutoff frequency: {cutoff_freq} THz")

Step 2: Create Mode Selective Lantern

from rsoft_cad.lantern import ModeSelectiveLantern

# Initialize mode selective lantern
mspl = ModeSelectiveLantern()

# Create with mode-specific parameters
core_map = mspl.create_lantern(
    highest_mode="LP11",        # Target mode
    launch_mode="LP01",         # Input mode
    taper_factor=8,             # Conservative taper
    taper_length=60000,         # Longer taper for mode selectivity
    mode_coupling_strength=0.1  # Weak coupling
)

# Add specific launch conditions for mode conversion
mspl.add_launch_field(
    launch_type="LP01",
    power=1.0,
    position=(0, 0)
)

mspl.write("mode_selective_lantern.ind")

Step 3: Optimization Loop

import numpy as np

# Optimize taper parameters
taper_factors = np.linspace(5, 15, 6)
coupling_efficiencies = []

for factor in taper_factors:
    # Create lantern with current parameters
    mspl = ModeSelectiveLantern()
    core_map = mspl.create_lantern(
        highest_mode="LP11",
        launch_mode="LP01",
        taper_factor=factor,
        taper_length=60000
    )
    
    # Run simulation
    result = run_simulation(
        mspl.design_filepath,
        mspl.design_filename,
        "bsimw32",
        f"opt_factor_{factor}"
    )
    
    # Extract coupling efficiency (simplified)
    if result.returncode == 0:
        efficiency = extract_coupling_efficiency(f"opt_factor_{factor}_monitor.dat")
        coupling_efficiencies.append(efficiency)
    else:
        coupling_efficiencies.append(0)

# Find optimal taper factor
optimal_factor = taper_factors[np.argmax(coupling_efficiencies)]
print(f"Optimal taper factor: {optimal_factor}")

Tutorial 3: Parameter Sweep Analysis

Overview

Systematically explore design parameters to find optimal configurations.

Step 1: Define Parameter Space

from rsoft_cad.beamprop import beamprop_tapered_lantern
import numpy as np
import pandas as pd

# Define parameter ranges
taper_lengths = np.linspace(20000, 80000, 13)
taper_factors = np.linspace(10, 20, 6)

# Create parameter grid
param_grid = [(tl, tf) for tl in taper_lengths for tf in taper_factors]
print(f"Total simulations: {len(param_grid)}")

Step 2: Execute Parameter Sweep

results = []

for i, (taper_length, taper_factor) in enumerate(param_grid):
    print(f"Running simulation {i+1}/{len(param_grid)}")
    
    # Run simulation with current parameters
    core_map = beamprop_tapered_lantern(
        expt_dir="param_sweep",
        opt_name=f"run_{i:03d}",
        taper_factor=taper_factor,
        taper_length=taper_length,
        highest_mode="LP02",
        launch_mode="LP01",
        result_files_prefix=f"sweep_{i:03d}"
    )
    
    # Store parameters and results
    results.append({
        'run_id': i,
        'taper_length': taper_length,
        'taper_factor': taper_factor,
        'num_cores': len(core_map)
    })

# Convert to DataFrame for analysis
df_results = pd.DataFrame(results)
df_results.to_csv("parameter_sweep_results.csv", index=False)

Step 3: Analyze and Visualize Results

from rsoft_cad.beamprop.beamprop_plot_util import plot_combined_monitor_files
import matplotlib.pyplot as plt

# Load and analyze monitor data
fig, ax, combined_df, final_values, summary, optimal_taper, optimal_value = plot_combined_monitor_files(
    "param_sweep/rsoft_data_files",
    save_plot=True,
    plot_filename="parameter_sweep_analysis"
)

# Create parameter sensitivity plot
fig, axes = plt.subplots(1, 2, figsize=(12, 5))

# Plot 1: Coupling efficiency vs taper length
for tf in taper_factors:
    mask = df_results['taper_factor'] == tf
    subset = df_results[mask]
    axes[0].plot(subset['taper_length'], subset['coupling_efficiency'], 
                label=f'TF={tf}', marker='o')

axes[0].set_xlabel('Taper Length (μm)')
axes[0].set_ylabel('Coupling Efficiency')
axes[0].legend()
axes[0].grid(True)

# Plot 2: Heatmap of parameter space
pivot_data = df_results.pivot('taper_factor', 'taper_length', 'coupling_efficiency')
im = axes[1].imshow(pivot_data, aspect='auto', cmap='viridis')
axes[1].set_xlabel('Taper Length')
axes[1].set_ylabel('Taper Factor')
plt.colorbar(im, ax=axes[1], label='Coupling Efficiency')

plt.tight_layout()
plt.savefig("parameter_sensitivity.png", dpi=300)
plt.show()

print(f"Optimal configuration: TL={optimal_taper}, Efficiency={optimal_value:.3f}")

Tutorial 4: Effective Index Analysis

Overview

Use FemSIM to analyze effective refractive indices and mode properties.

Step 1: Set Up FemSIM Simulation

from rsoft_cad.femsim import femsim_tapered_lantern

# Run FemSIM for effective index calculation
femsim_tapered_lantern(
    expt_dir="neff_analysis",
    taper_factor=15,
    taper_length=50000,
    num_points=150,          # Number of z-points
    num_grids=250,           # Grid resolution
    highest_mode="LP02",
    launch_mode="LP01"
)

Step 2: Process and Visualize Results

from rsoft_cad.femsim.visualisation import plot_combined_nef_files
from rsoft_cad.femsim.curve_fitting import fit_polynomial_to_data

# Load and plot effective index data
fig = plot_combined_nef_files(
    folder_path="neff_analysis/rsoft_data_files",
    plot_type="real",           # Plot real part of n_eff
    save_plot=True,
    max_indices=15,             # Plot first 15 modes
    remove_outliers=True,       # Clean data
    fit_data=True,              # Add polynomial fits
    colormap="plasma"
)

plt.title("Effective Index Evolution Along Taper")
plt.show()

Step 3: Mode Coupling Analysis

from rsoft_cad.femsim.data_processing import analyze_mode_coupling

# Analyze mode coupling from effective index data
coupling_data = analyze_mode_coupling(
    "neff_analysis/rsoft_data_files",
    mode_pairs=[("LP01", "LP11"), ("LP01", "LP21")],
    coupling_threshold=0.001
)

# Plot coupling evolution
fig, ax = plt.subplots(figsize=(10, 6))
for pair, data in coupling_data.items():
    ax.plot(data['z_position'], data['coupling_strength'], 
           label=f"{pair[0]}{pair[1]}", linewidth=2)

ax.set_xlabel('Z Position (μm)')
ax.set_ylabel('Coupling Strength')
ax.legend()
ax.grid(True, alpha=0.3)
plt.title("Mode Coupling Evolution")
plt.show()

Tutorial 5: Custom Taper Design

Overview

Create custom taper profiles for specialized applications.

Step 1: Define Custom Taper Function

from rsoft_cad.geometry.custom_taper import CustomTaper
import numpy as np

def exponential_taper(z, z_start, z_end, r_start, r_end, alpha=1.5):
    """Custom exponential taper profile"""
    if z < z_start or z > z_end:
        return r_start if z < z_start else r_end
    
    normalized_z = (z - z_start) / (z_end - z_start)
    return r_start * np.exp(-alpha * normalized_z) + r_end * (1 - np.exp(-alpha * normalized_z))

# Create custom taper
taper = CustomTaper(
    taper_function=exponential_taper,
    start_position=10000,
    end_position=60000,
    start_radius=25.0,
    end_radius=8.0
)

Step 2: Apply to Lantern Design

from rsoft_cad.lantern import PhotonicLantern

# Create lantern with custom taper
lantern = PhotonicLantern()
core_map = lantern.create_lantern(
    highest_mode="LP02",
    custom_taper=taper,        # Use custom taper
    taper_length=50000
)

# Visualize taper profile
z_positions = np.linspace(0, 70000, 1000)
radii = [taper.radius_at_position(z) for z in z_positions]

plt.figure(figsize=(10, 6))
plt.plot(z_positions, radii, linewidth=2)
plt.xlabel('Z Position (μm)')
plt.ylabel('Radius (μm)')
plt.title('Custom Exponential Taper Profile')
plt.grid(True, alpha=0.3)
plt.show()

lantern.write("custom_taper_lantern.ind")

Tutorial 6: Advanced Visualization

Overview

Create publication-quality plots and animations of your results.

Step 1: Field Distribution Plots

from rsoft_cad.utils.rsoft_file_plot import combined_field_plots

# Create comprehensive field plots
fig, axes = combined_field_plots(
    data_folder="simulation_results/",
    field_type="intensity",
    z_positions=[0, 25000, 50000],    # Specific z-positions
    colormap="hot",
    normalize=True,
    save_plots=True,
    plot_format="png",
    dpi=300
)

# Add custom annotations
for i, ax in enumerate(axes.flat):
    ax.set_title(f"Z = {[0, 25000, 50000][i]} μm")
    ax.grid(True, alpha=0.2)

plt.tight_layout()
plt.savefig("field_evolution.png", dpi=300, bbox_inches='tight')
plt.show()

Step 2: Animation of Field Propagation

import matplotlib.animation as animation

def create_propagation_animation(data_folder, output_filename="propagation.mp4"):
    # Load field data at multiple z-positions
    field_data = load_field_evolution(data_folder)
    
    fig, ax = plt.subplots(figsize=(8, 8))
    
    def animate(frame):
        ax.clear()
        z_pos = field_data['z_positions'][frame]
        field = field_data['fields'][frame]
        
        im = ax.imshow(field, cmap='hot', extent=[-50, 50, -50, 50])
        ax.set_title(f'Field Intensity at Z = {z_pos:.0f} μm')
        ax.set_xlabel('X (μm)')
        ax.set_ylabel('Y (μm)')
        
        return [im]
    
    # Create animation
    anim = animation.FuncAnimation(
        fig, animate, frames=len(field_data['z_positions']),
        interval=100, blit=False, repeat=True
    )
    
    # Save as video
    anim.save(output_filename, writer='ffmpeg', fps=10, dpi=150)
    plt.show()

# Create animation
create_propagation_animation("simulation_results/")

Next Steps

These tutorials cover the core workflows in RSoft CAD. For more advanced topics:

  • Explore the Examples section for real-world applications

  • Check the API Reference for detailed function documentation

  • Review the source code in the examples/ directory for additional patterns

Common Troubleshooting

Simulation Failures

  • Check RSoft installation and licensing

  • Verify input file format

  • Ensure sufficient computational resources

Memory Issues

  • Reduce grid resolution for large simulations

  • Use parameter chunking for large sweeps

  • Monitor system resources during execution

Convergence Problems

  • Adjust simulation parameters (step size, iterations)

  • Check boundary conditions

  • Verify mode definitions and launch conditions